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.FontMetrics;
30 import java.awt.Rectangle;
31 import java.io.BufferedReader;
32 import java.io.ByteArrayInputStream;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.io.OutputStreamWriter;
41 import java.io.PrintWriter;
42 import java.lang.reflect.InvocationTargetException;
43 import java.math.BigInteger;
44 import java.net.MalformedURLException;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.BitSet;
49 import java.util.Collections;
50 import java.util.Enumeration;
51 import java.util.GregorianCalendar;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Hashtable;
55 import java.util.IdentityHashMap;
56 import java.util.Iterator;
57 import java.util.LinkedHashMap;
58 import java.util.List;
59 import java.util.Locale;
61 import java.util.Map.Entry;
63 import java.util.Vector;
64 import java.util.jar.JarEntry;
65 import java.util.jar.JarInputStream;
66 import java.util.jar.JarOutputStream;
68 import javax.swing.JInternalFrame;
69 import javax.swing.SwingUtilities;
70 import javax.xml.bind.JAXBContext;
71 import javax.xml.bind.JAXBElement;
72 import javax.xml.bind.Marshaller;
73 import javax.xml.datatype.DatatypeConfigurationException;
74 import javax.xml.datatype.DatatypeFactory;
75 import javax.xml.datatype.XMLGregorianCalendar;
76 import javax.xml.stream.XMLInputFactory;
77 import javax.xml.stream.XMLStreamReader;
79 import jalview.analysis.Conservation;
80 import jalview.analysis.PCA;
81 import jalview.analysis.scoremodels.ScoreModels;
82 import jalview.analysis.scoremodels.SimilarityParams;
83 import jalview.api.FeatureColourI;
84 import jalview.api.ViewStyleI;
85 import jalview.api.analysis.ScoreModelI;
86 import jalview.api.analysis.SimilarityParamsI;
87 import jalview.api.structures.JalviewStructureDisplayI;
88 import jalview.bin.Cache;
89 import jalview.bin.Console;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.ContactMatrix;
95 import jalview.datamodel.ContactMatrixI;
96 import jalview.datamodel.DBRefEntry;
97 import jalview.datamodel.GeneLocus;
98 import jalview.datamodel.GraphLine;
99 import jalview.datamodel.GroupSet;
100 import jalview.datamodel.PDBEntry;
101 import jalview.datamodel.Point;
102 import jalview.datamodel.RnaViewerModel;
103 import jalview.datamodel.SequenceFeature;
104 import jalview.datamodel.SequenceGroup;
105 import jalview.datamodel.SequenceI;
106 import jalview.datamodel.StructureViewerModel;
107 import jalview.datamodel.StructureViewerModel.StructureData;
108 import jalview.datamodel.features.FeatureMatcher;
109 import jalview.datamodel.features.FeatureMatcherI;
110 import jalview.datamodel.features.FeatureMatcherSet;
111 import jalview.datamodel.features.FeatureMatcherSetI;
112 import jalview.ext.varna.RnaModel;
113 import jalview.gui.AlignFrame;
114 import jalview.gui.AlignViewport;
115 import jalview.gui.AlignmentPanel;
116 import jalview.gui.AppVarna;
117 import jalview.gui.Desktop;
118 import jalview.gui.JvOptionPane;
119 import jalview.gui.OOMWarning;
120 import jalview.gui.OverviewPanel;
121 import jalview.gui.PCAPanel;
122 import jalview.gui.PaintRefresher;
123 import jalview.gui.SplitFrame;
124 import jalview.gui.StructureViewer;
125 import jalview.gui.StructureViewer.ViewerType;
126 import jalview.gui.StructureViewerBase;
127 import jalview.gui.TreePanel;
128 import jalview.io.BackupFiles;
129 import jalview.io.DataSourceType;
130 import jalview.io.FileFormat;
131 import jalview.io.NewickFile;
132 import jalview.math.Matrix;
133 import jalview.math.MatrixI;
134 import jalview.renderer.ResidueShaderI;
135 import jalview.schemes.AnnotationColourGradient;
136 import jalview.schemes.ColourSchemeI;
137 import jalview.schemes.ColourSchemeProperty;
138 import jalview.schemes.FeatureColour;
139 import jalview.schemes.ResidueProperties;
140 import jalview.schemes.UserColourScheme;
141 import jalview.structure.StructureSelectionManager;
142 import jalview.structures.models.AAStructureBindingModel;
143 import jalview.util.Format;
144 import jalview.util.HttpUtils;
145 import jalview.util.MessageManager;
146 import jalview.util.Platform;
147 import jalview.util.StringUtils;
148 import jalview.util.jarInputStreamProvider;
149 import jalview.util.matcher.Condition;
150 import jalview.viewmodel.AlignmentViewport;
151 import jalview.viewmodel.PCAModel;
152 import jalview.viewmodel.ViewportRanges;
153 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
154 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
155 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
156 import jalview.ws.datamodel.MappableContactMatrixI;
157 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
158 import jalview.ws.jws2.Jws2Discoverer;
159 import jalview.ws.jws2.dm.AAConSettings;
160 import jalview.ws.jws2.jabaws2.Jws2Instance;
161 import jalview.ws.params.ArgumentI;
162 import jalview.ws.params.AutoCalcSetting;
163 import jalview.ws.params.WsParamSetI;
164 import jalview.xml.binding.jalview.AlcodonFrame;
165 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
166 import jalview.xml.binding.jalview.Annotation;
167 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
168 import jalview.xml.binding.jalview.AnnotationColourScheme;
169 import jalview.xml.binding.jalview.AnnotationElement;
170 import jalview.xml.binding.jalview.DoubleMatrix;
171 import jalview.xml.binding.jalview.DoubleVector;
172 import jalview.xml.binding.jalview.Feature;
173 import jalview.xml.binding.jalview.Feature.OtherData;
174 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
175 import jalview.xml.binding.jalview.FilterBy;
176 import jalview.xml.binding.jalview.JalviewModel;
177 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
178 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
179 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
180 import jalview.xml.binding.jalview.JalviewModel.JGroup;
181 import jalview.xml.binding.jalview.JalviewModel.JSeq;
182 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
183 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
184 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
186 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
187 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
188 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
189 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
191 import jalview.xml.binding.jalview.JalviewModel.Tree;
192 import jalview.xml.binding.jalview.JalviewModel.UserColours;
193 import jalview.xml.binding.jalview.JalviewModel.Viewport;
194 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
195 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
196 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
197 import jalview.xml.binding.jalview.JalviewUserColours;
198 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
199 import jalview.xml.binding.jalview.MapListType;
200 import jalview.xml.binding.jalview.MapListType.MapListFrom;
201 import jalview.xml.binding.jalview.MapListType.MapListTo;
202 import jalview.xml.binding.jalview.Mapping;
203 import jalview.xml.binding.jalview.MatrixType;
204 import jalview.xml.binding.jalview.NoValueColour;
205 import jalview.xml.binding.jalview.ObjectFactory;
206 import jalview.xml.binding.jalview.PcaDataType;
207 import jalview.xml.binding.jalview.Pdbentry.Property;
208 import jalview.xml.binding.jalview.Sequence;
209 import jalview.xml.binding.jalview.Sequence.DBRef;
210 import jalview.xml.binding.jalview.SequenceSet;
211 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
212 import jalview.xml.binding.jalview.ThresholdType;
213 import jalview.xml.binding.jalview.VAMSAS;
216 * Write out the current jalview desktop state as a Jalview XML stream.
218 * Note: the vamsas objects referred to here are primitive versions of the
219 * VAMSAS project schema elements - they are not the same and most likely never
223 * @version $Revision: 1.134 $
225 public class Jalview2XML
228 // BH 2018 we add the .jvp binary extension to J2S so that
229 // it will declare that binary when we do the file save from the browser
233 Platform.addJ2SBinaryType(".jvp?");
236 private static final String VIEWER_PREFIX = "viewer_";
238 private static final String RNA_PREFIX = "rna_";
240 private static final String UTF_8 = "UTF-8";
243 * used in decision if quit confirmation should be issued
245 private static boolean stateSavedUpToDate = false;
248 * prefix for recovering datasets for alignments with multiple views where
249 * non-existent dataset IDs were written for some views
251 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
253 // use this with nextCounter() to make unique names for entities
254 private int counter = 0;
257 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
258 * of sequence objects are created.
260 IdentityHashMap<SequenceI, String> seqsToIds = null;
263 * jalview XML Sequence ID to jalview sequence object reference (both dataset
264 * and alignment sequences. Populated as XML reps of sequence objects are
267 Map<String, SequenceI> seqRefIds = null;
269 Map<String, SequenceI> incompleteSeqs = null;
271 List<SeqFref> frefedSequence = null;
273 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
276 * Map of reconstructed AlignFrame objects that appear to have come from
277 * SplitFrame objects (have a dna/protein complement view).
279 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
282 * Map from displayed rna structure models to their saved session state jar
285 private Map<RnaModel, String> rnaSessions = new HashMap<>();
288 * map from contact matrices to their XML ids
290 private Map<ContactMatrixI,String> contactMatrices = new HashMap<>();
291 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
294 * A helper method for safely using the value of an optional attribute that
295 * may be null if not present in the XML. Answers the boolean value, or false
301 public static boolean safeBoolean(Boolean b)
303 return b == null ? false : b.booleanValue();
307 * A helper method for safely using the value of an optional attribute that
308 * may be null if not present in the XML. Answers the integer value, or zero
314 public static int safeInt(Integer i)
316 return i == null ? 0 : i.intValue();
320 * A helper method for safely using the value of an optional attribute that
321 * may be null if not present in the XML. Answers the float value, or zero if
327 public static float safeFloat(Float f)
329 return f == null ? 0f : f.floatValue();
333 * create/return unique hash string for sq
336 * @return new or existing unique string for sq
338 String seqHash(SequenceI sq)
340 if (seqsToIds == null)
344 if (seqsToIds.containsKey(sq))
346 return seqsToIds.get(sq);
350 // create sequential key
351 String key = "sq" + (seqsToIds.size() + 1);
352 key = makeHashCode(sq, key); // check we don't have an external reference
354 seqsToIds.put(sq, key);
361 if (seqsToIds == null)
363 seqsToIds = new IdentityHashMap<>();
365 if (seqRefIds == null)
367 seqRefIds = new HashMap<>();
369 if (incompleteSeqs == null)
371 incompleteSeqs = new HashMap<>();
373 if (frefedSequence == null)
375 frefedSequence = new ArrayList<>();
383 public Jalview2XML(boolean raiseGUI)
385 this.raiseGUI = raiseGUI;
389 * base class for resolving forward references to sequences by their ID
394 abstract class SeqFref
400 public SeqFref(String _sref, String type)
406 public String getSref()
411 public SequenceI getSrefSeq()
413 return seqRefIds.get(sref);
416 public boolean isResolvable()
418 return seqRefIds.get(sref) != null;
421 public SequenceI getSrefDatasetSeq()
423 SequenceI sq = seqRefIds.get(sref);
426 while (sq.getDatasetSequence() != null)
428 sq = sq.getDatasetSequence();
435 * @return true if the forward reference was fully resolved
437 abstract boolean resolve();
440 public String toString()
442 return type + " reference to " + sref;
447 * create forward reference for a mapping
453 public SeqFref newMappingRef(final String sref,
454 final jalview.datamodel.Mapping _jmap)
456 SeqFref fref = new SeqFref(sref, "Mapping")
458 public jalview.datamodel.Mapping jmap = _jmap;
463 SequenceI seq = getSrefDatasetSeq();
475 public SeqFref newAlcodMapRef(final String sref,
476 final AlignedCodonFrame _cf,
477 final jalview.datamodel.Mapping _jmap)
480 SeqFref fref = new SeqFref(sref, "Codon Frame")
482 AlignedCodonFrame cf = _cf;
484 public jalview.datamodel.Mapping mp = _jmap;
487 public boolean isResolvable()
489 return super.isResolvable() && mp.getTo() != null;
495 SequenceI seq = getSrefDatasetSeq();
500 cf.addMap(seq, mp.getTo(), mp.getMap());
507 public void resolveFrefedSequences()
509 Iterator<SeqFref> nextFref = frefedSequence.iterator();
510 int toresolve = frefedSequence.size();
511 int unresolved = 0, failedtoresolve = 0;
512 while (nextFref.hasNext())
514 SeqFref ref = nextFref.next();
515 if (ref.isResolvable())
527 } catch (Exception x)
530 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
543 System.err.println("Jalview Project Import: There were " + unresolved
544 + " forward references left unresolved on the stack.");
546 if (failedtoresolve > 0)
548 System.err.println("SERIOUS! " + failedtoresolve
549 + " resolvable forward references failed to resolve.");
551 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
554 "Jalview Project Import: There are " + incompleteSeqs.size()
555 + " sequences which may have incomplete metadata.");
556 if (incompleteSeqs.size() < 10)
558 for (SequenceI s : incompleteSeqs.values())
560 System.err.println(s.toString());
566 "Too many to report. Skipping output of incomplete sequences.");
572 * This maintains a map of viewports, the key being the seqSetId. Important to
573 * set historyItem and redoList for multiple views
575 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
577 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
579 String uniqueSetSuffix = "";
582 * List of pdbfiles added to Jar
584 List<String> pdbfiles = null;
586 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
587 public void saveState(File statefile)
589 FileOutputStream fos = null;
594 fos = new FileOutputStream(statefile);
596 JarOutputStream jout = new JarOutputStream(fos);
600 } catch (Exception e)
602 Console.error("Couln't write Jalview state to " + statefile, e);
603 // TODO: inform user of the problem - they need to know if their data was
605 if (errorMessage == null)
607 errorMessage = "Did't write Jalview Archive to output file '"
608 + statefile + "' - See console error log for details";
612 errorMessage += "(Didn't write Jalview Archive to output file '"
623 } catch (IOException e)
633 * Writes a jalview project archive to the given Jar output stream.
637 public void saveState(JarOutputStream jout)
639 AlignFrame[] frames = Desktop.getAlignFrames();
641 setStateSavedUpToDate(true);
643 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
645 int n = debugDelaySave;
649 Console.debug("***** debugging save sleep " + i + "/" + n);
653 } catch (InterruptedException e)
655 // TODO Auto-generated catch block
666 saveAllFrames(Arrays.asList(frames), jout);
670 * core method for storing state for a set of AlignFrames.
673 * - frames involving all data to be exported (including containing
676 * - project output stream
678 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
680 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
683 * ensure cached data is clear before starting
685 // todo tidy up seqRefIds, seqsToIds initialisation / reset
687 splitFrameCandidates.clear();
692 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
693 // //////////////////////////////////////////////////
695 List<String> shortNames = new ArrayList<>();
696 List<String> viewIds = new ArrayList<>();
699 for (int i = frames.size() - 1; i > -1; i--)
701 AlignFrame af = frames.get(i);
703 if (skipList != null && skipList
704 .containsKey(af.getViewport().getSequenceSetId()))
709 String shortName = makeFilename(af, shortNames);
711 int apSize = af.getAlignPanels().size();
713 for (int ap = 0; ap < apSize; ap++)
715 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
717 String fileName = apSize == 1 ? shortName : ap + shortName;
718 if (!fileName.endsWith(".xml"))
720 fileName = fileName + ".xml";
723 saveState(apanel, fileName, jout, viewIds);
725 String dssid = getDatasetIdRef(
726 af.getViewport().getAlignment().getDataset());
727 if (!dsses.containsKey(dssid))
729 dsses.put(dssid, af);
734 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
740 } catch (Exception foo)
744 } catch (Exception ex)
746 // TODO: inform user of the problem - they need to know if their data was
748 if (errorMessage == null)
750 errorMessage = "Couldn't write Jalview Archive - see error output for details";
752 ex.printStackTrace();
757 * Generates a distinct file name, based on the title of the AlignFrame, by
758 * appending _n for increasing n until an unused name is generated. The new
759 * name (without its extension) is added to the list.
763 * @return the generated name, with .xml extension
765 protected String makeFilename(AlignFrame af, List<String> namesUsed)
767 String shortName = af.getTitle();
769 if (shortName.indexOf(File.separatorChar) > -1)
771 shortName = shortName
772 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
777 while (namesUsed.contains(shortName))
779 if (shortName.endsWith("_" + (count - 1)))
781 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
784 shortName = shortName.concat("_" + count);
788 namesUsed.add(shortName);
790 if (!shortName.endsWith(".xml"))
792 shortName = shortName + ".xml";
797 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
798 public boolean saveAlignment(AlignFrame af, String jarFile,
803 // create backupfiles object and get new temp filename destination
804 boolean doBackup = BackupFiles.getEnabled();
805 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
806 FileOutputStream fos = new FileOutputStream(
807 doBackup ? backupfiles.getTempFilePath() : jarFile);
809 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
811 int n = debugDelaySave;
815 Console.debug("***** debugging save sleep " + i + "/" + n);
819 } catch (InterruptedException e)
821 // TODO Auto-generated catch block
828 JarOutputStream jout = new JarOutputStream(fos);
829 List<AlignFrame> frames = new ArrayList<>();
831 // resolve splitframes
832 if (af.getViewport().getCodingComplement() != null)
834 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
840 saveAllFrames(frames, jout);
844 } catch (Exception foo)
848 boolean success = true;
852 backupfiles.setWriteSuccess(success);
853 success = backupfiles.rollBackupsAndRenameTempFile();
857 } catch (Exception ex)
859 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
860 ex.printStackTrace();
865 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
866 String fileName, JarOutputStream jout)
869 for (String dssids : dsses.keySet())
871 AlignFrame _af = dsses.get(dssids);
872 String jfileName = fileName + " Dataset for " + _af.getTitle();
873 if (!jfileName.endsWith(".xml"))
875 jfileName = jfileName + ".xml";
877 saveState(_af.alignPanel, jfileName, true, jout, null);
882 * create a JalviewModel from an alignment view and marshall it to a
886 * panel to create jalview model for
888 * name of alignment panel written to output stream
895 public JalviewModel saveState(AlignmentPanel ap, String fileName,
896 JarOutputStream jout, List<String> viewIds)
898 return saveState(ap, fileName, false, jout, viewIds);
902 * create a JalviewModel from an alignment view and marshall it to a
906 * panel to create jalview model for
908 * name of alignment panel written to output stream
910 * when true, only write the dataset for the alignment, not the data
911 * associated with the view.
917 public JalviewModel saveState(AlignmentPanel ap, String fileName,
918 boolean storeDS, JarOutputStream jout, List<String> viewIds)
922 viewIds = new ArrayList<>();
927 List<UserColourScheme> userColours = new ArrayList<>();
929 AlignViewport av = ap.av;
930 ViewportRanges vpRanges = av.getRanges();
932 final ObjectFactory objectFactory = new ObjectFactory();
933 JalviewModel object = objectFactory.createJalviewModel();
934 object.setVamsasModel(new VAMSAS());
936 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
939 GregorianCalendar c = new GregorianCalendar();
940 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
941 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
942 object.setCreationDate(now);
943 } catch (DatatypeConfigurationException e)
945 System.err.println("error writing date: " + e.toString());
947 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
950 * rjal is full height alignment, jal is actual alignment with full metadata
951 * but excludes hidden sequences.
953 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
955 if (av.hasHiddenRows())
957 rjal = jal.getHiddenSequences().getFullAlignment();
960 SequenceSet vamsasSet = new SequenceSet();
962 // JalviewModelSequence jms = new JalviewModelSequence();
964 vamsasSet.setGapChar(jal.getGapCharacter() + "");
966 if (jal.getDataset() != null)
968 // dataset id is the dataset's hashcode
969 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
972 // switch jal and the dataset
973 jal = jal.getDataset();
977 if (jal.getProperties() != null)
979 Enumeration en = jal.getProperties().keys();
980 while (en.hasMoreElements())
982 String key = en.nextElement().toString();
983 SequenceSetProperties ssp = new SequenceSetProperties();
985 ssp.setValue(jal.getProperties().get(key).toString());
986 // vamsasSet.addSequenceSetProperties(ssp);
987 vamsasSet.getSequenceSetProperties().add(ssp);
992 Set<String> calcIdSet = new HashSet<>();
993 // record the set of vamsas sequence XML POJO we create.
994 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
996 for (final SequenceI jds : rjal.getSequences())
998 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
999 : jds.getDatasetSequence();
1000 String id = seqHash(jds);
1001 if (vamsasSetIds.get(id) == null)
1003 if (seqRefIds.get(id) != null && !storeDS)
1005 // This happens for two reasons: 1. multiple views are being
1007 // 2. the hashCode has collided with another sequence's code. This
1009 // HAPPEN! (PF00072.15.stk does this)
1010 // JBPNote: Uncomment to debug writing out of files that do not read
1011 // back in due to ArrayOutOfBoundExceptions.
1012 // System.err.println("vamsasSeq backref: "+id+"");
1013 // System.err.println(jds.getName()+"
1014 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1015 // System.err.println("Hashcode: "+seqHash(jds));
1016 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1017 // System.err.println(rsq.getName()+"
1018 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1019 // System.err.println("Hashcode: "+seqHash(rsq));
1023 vamsasSeq = createVamsasSequence(id, jds);
1024 // vamsasSet.addSequence(vamsasSeq);
1025 vamsasSet.getSequence().add(vamsasSeq);
1026 vamsasSetIds.put(id, vamsasSeq);
1027 seqRefIds.put(id, jds);
1031 jseq.setStart(jds.getStart());
1032 jseq.setEnd(jds.getEnd());
1033 jseq.setColour(av.getSequenceColour(jds).getRGB());
1035 jseq.setId(id); // jseq id should be a string not a number
1038 // Store any sequences this sequence represents
1039 if (av.hasHiddenRows())
1041 // use rjal, contains the full height alignment
1043 av.getAlignment().getHiddenSequences().isHidden(jds));
1045 if (av.isHiddenRepSequence(jds))
1047 jalview.datamodel.SequenceI[] reps = av
1048 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1050 for (int h = 0; h < reps.length; h++)
1054 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1055 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1060 // mark sequence as reference - if it is the reference for this view
1061 if (jal.hasSeqrep())
1063 jseq.setViewreference(jds == jal.getSeqrep());
1067 // TODO: omit sequence features from each alignment view's XML dump if we
1068 // are storing dataset
1069 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1070 for (SequenceFeature sf : sfs)
1072 // Features features = new Features();
1073 Feature features = new Feature();
1075 features.setBegin(sf.getBegin());
1076 features.setEnd(sf.getEnd());
1077 features.setDescription(sf.getDescription());
1078 features.setType(sf.getType());
1079 features.setFeatureGroup(sf.getFeatureGroup());
1080 features.setScore(sf.getScore());
1081 if (sf.links != null)
1083 for (int l = 0; l < sf.links.size(); l++)
1085 OtherData keyValue = new OtherData();
1086 keyValue.setKey("LINK_" + l);
1087 keyValue.setValue(sf.links.elementAt(l).toString());
1088 // features.addOtherData(keyValue);
1089 features.getOtherData().add(keyValue);
1092 if (sf.otherDetails != null)
1095 * save feature attributes, which may be simple strings or
1096 * map valued (have sub-attributes)
1098 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1100 String key = entry.getKey();
1101 Object value = entry.getValue();
1102 if (value instanceof Map<?, ?>)
1104 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1107 OtherData otherData = new OtherData();
1108 otherData.setKey(key);
1109 otherData.setKey2(subAttribute.getKey());
1110 otherData.setValue(subAttribute.getValue().toString());
1111 // features.addOtherData(otherData);
1112 features.getOtherData().add(otherData);
1117 OtherData otherData = new OtherData();
1118 otherData.setKey(key);
1119 otherData.setValue(value.toString());
1120 // features.addOtherData(otherData);
1121 features.getOtherData().add(otherData);
1126 // jseq.addFeatures(features);
1127 jseq.getFeatures().add(features);
1130 if (jdatasq.getAllPDBEntries() != null)
1132 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1133 while (en.hasMoreElements())
1135 Pdbids pdb = new Pdbids();
1136 jalview.datamodel.PDBEntry entry = en.nextElement();
1138 String pdbId = entry.getId();
1140 pdb.setType(entry.getType());
1143 * Store any structure views associated with this sequence. This
1144 * section copes with duplicate entries in the project, so a dataset
1145 * only view *should* be coped with sensibly.
1147 // This must have been loaded, is it still visible?
1148 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1149 String matchedFile = null;
1150 for (int f = frames.length - 1; f > -1; f--)
1152 if (frames[f] instanceof StructureViewerBase)
1154 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1155 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1156 viewIds, matchedFile, viewFrame);
1158 * Only store each structure viewer's state once in the project
1159 * jar. First time through only (storeDS==false)
1161 String viewId = viewFrame.getViewId();
1162 String viewerType = viewFrame.getViewerType().toString();
1163 if (!storeDS && !viewIds.contains(viewId))
1165 viewIds.add(viewId);
1166 File viewerState = viewFrame.saveSession();
1167 if (viewerState != null)
1169 copyFileToJar(jout, viewerState.getPath(),
1170 getViewerJarEntryName(viewId), viewerType);
1175 "Failed to save viewer state for " + viewerType);
1181 if (matchedFile != null || entry.getFile() != null)
1183 if (entry.getFile() != null)
1186 matchedFile = entry.getFile();
1188 pdb.setFile(matchedFile); // entry.getFile());
1189 if (pdbfiles == null)
1191 pdbfiles = new ArrayList<>();
1194 if (!pdbfiles.contains(pdbId))
1196 pdbfiles.add(pdbId);
1197 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1201 Enumeration<String> props = entry.getProperties();
1202 if (props.hasMoreElements())
1204 // PdbentryItem item = new PdbentryItem();
1205 while (props.hasMoreElements())
1207 Property prop = new Property();
1208 String key = props.nextElement();
1210 prop.setValue(entry.getProperty(key).toString());
1211 // item.addProperty(prop);
1212 pdb.getProperty().add(prop);
1214 // pdb.addPdbentryItem(item);
1217 // jseq.addPdbids(pdb);
1218 jseq.getPdbids().add(pdb);
1222 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1224 // jms.addJSeq(jseq);
1225 object.getJSeq().add(jseq);
1228 if (!storeDS && av.hasHiddenRows())
1230 jal = av.getAlignment();
1234 if (storeDS && jal.getCodonFrames() != null)
1236 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1237 for (AlignedCodonFrame acf : jac)
1239 AlcodonFrame alc = new AlcodonFrame();
1240 if (acf.getProtMappings() != null
1241 && acf.getProtMappings().length > 0)
1243 boolean hasMap = false;
1244 SequenceI[] dnas = acf.getdnaSeqs();
1245 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1246 for (int m = 0; m < pmaps.length; m++)
1248 AlcodMap alcmap = new AlcodMap();
1249 alcmap.setDnasq(seqHash(dnas[m]));
1251 createVamsasMapping(pmaps[m], dnas[m], null, false));
1252 // alc.addAlcodMap(alcmap);
1253 alc.getAlcodMap().add(alcmap);
1258 // vamsasSet.addAlcodonFrame(alc);
1259 vamsasSet.getAlcodonFrame().add(alc);
1262 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1264 // AlcodonFrame alc = new AlcodonFrame();
1265 // vamsasSet.addAlcodonFrame(alc);
1266 // for (int p = 0; p < acf.aaWidth; p++)
1268 // Alcodon cmap = new Alcodon();
1269 // if (acf.codons[p] != null)
1271 // // Null codons indicate a gapped column in the translated peptide
1273 // cmap.setPos1(acf.codons[p][0]);
1274 // cmap.setPos2(acf.codons[p][1]);
1275 // cmap.setPos3(acf.codons[p][2]);
1277 // alc.addAlcodon(cmap);
1279 // if (acf.getProtMappings() != null
1280 // && acf.getProtMappings().length > 0)
1282 // SequenceI[] dnas = acf.getdnaSeqs();
1283 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1284 // for (int m = 0; m < pmaps.length; m++)
1286 // AlcodMap alcmap = new AlcodMap();
1287 // alcmap.setDnasq(seqHash(dnas[m]));
1288 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1290 // alc.addAlcodMap(alcmap);
1297 // /////////////////////////////////
1298 if (!storeDS && av.getCurrentTree() != null)
1300 // FIND ANY ASSOCIATED TREES
1301 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1302 if (Desktop.desktop != null)
1304 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1306 for (int t = 0; t < frames.length; t++)
1308 if (frames[t] instanceof TreePanel)
1310 TreePanel tp = (TreePanel) frames[t];
1312 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1314 JalviewModel.Tree tree = new JalviewModel.Tree();
1315 tree.setTitle(tp.getTitle());
1316 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1317 tree.setNewick(tp.getTree().print());
1318 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1320 tree.setFitToWindow(tp.fitToWindow.getState());
1321 tree.setFontName(tp.getTreeFont().getName());
1322 tree.setFontSize(tp.getTreeFont().getSize());
1323 tree.setFontStyle(tp.getTreeFont().getStyle());
1324 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1326 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1327 tree.setShowDistances(tp.distanceMenu.getState());
1329 tree.setHeight(tp.getHeight());
1330 tree.setWidth(tp.getWidth());
1331 tree.setXpos(tp.getX());
1332 tree.setYpos(tp.getY());
1333 tree.setId(makeHashCode(tp, null));
1334 tree.setLinkToAllViews(
1335 tp.getTreeCanvas().isApplyToAllViews());
1338 if (tp.isColumnWise())
1340 tree.setColumnWise(true);
1341 String annId = tp.getAssocAnnotation().annotationId;
1342 tree.setColumnReference(annId);
1344 // jms.addTree(tree);
1345 object.getTree().add(tree);
1355 if (!storeDS && Desktop.desktop != null)
1357 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1359 if (frame instanceof PCAPanel)
1361 PCAPanel panel = (PCAPanel) frame;
1362 if (panel.getAlignViewport().getAlignment() == jal)
1364 savePCA(panel, object);
1372 * store forward refs from an annotationRow to any groups
1374 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1377 for (SequenceI sq : jal.getSequences())
1379 // Store annotation on dataset sequences only
1380 AlignmentAnnotation[] aa = sq.getAnnotation();
1381 if (aa != null && aa.length > 0)
1383 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1390 if (jal.getAlignmentAnnotation() != null)
1392 // Store the annotation shown on the alignment.
1393 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1394 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1399 if (jal.getGroups() != null)
1401 JGroup[] groups = new JGroup[jal.getGroups().size()];
1403 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1405 JGroup jGroup = new JGroup();
1406 groups[++i] = jGroup;
1408 jGroup.setStart(sg.getStartRes());
1409 jGroup.setEnd(sg.getEndRes());
1410 jGroup.setName(sg.getName());
1411 if (groupRefs.containsKey(sg))
1413 // group has references so set its ID field
1414 jGroup.setId(groupRefs.get(sg));
1416 ColourSchemeI colourScheme = sg.getColourScheme();
1417 if (colourScheme != null)
1419 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1420 if (groupColourScheme.conservationApplied())
1422 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1424 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1426 jGroup.setColour(setUserColourScheme(colourScheme,
1427 userColours, object));
1431 jGroup.setColour(colourScheme.getSchemeName());
1434 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1436 jGroup.setColour("AnnotationColourGradient");
1437 jGroup.setAnnotationColours(constructAnnotationColours(
1438 (jalview.schemes.AnnotationColourGradient) colourScheme,
1439 userColours, object));
1441 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1444 setUserColourScheme(colourScheme, userColours, object));
1448 jGroup.setColour(colourScheme.getSchemeName());
1451 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1454 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1455 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1456 jGroup.setDisplayText(sg.getDisplayText());
1457 jGroup.setColourText(sg.getColourText());
1458 jGroup.setTextCol1(sg.textColour.getRGB());
1459 jGroup.setTextCol2(sg.textColour2.getRGB());
1460 jGroup.setTextColThreshold(sg.thresholdTextColour);
1461 jGroup.setShowUnconserved(sg.getShowNonconserved());
1462 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1463 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1464 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1465 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1466 for (SequenceI seq : sg.getSequences())
1468 // jGroup.addSeq(seqHash(seq));
1469 jGroup.getSeq().add(seqHash(seq));
1473 // jms.setJGroup(groups);
1475 for (JGroup grp : groups)
1477 object.getJGroup().add(grp);
1482 // /////////SAVE VIEWPORT
1483 Viewport view = new Viewport();
1484 view.setTitle(ap.alignFrame.getTitle());
1485 view.setSequenceSetId(
1486 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1487 view.setId(av.getViewId());
1488 if (av.getCodingComplement() != null)
1490 view.setComplementId(av.getCodingComplement().getViewId());
1492 view.setViewName(av.getViewName());
1493 view.setGatheredViews(av.isGatherViewsHere());
1495 Rectangle size = ap.av.getExplodedGeometry();
1496 Rectangle position = size;
1499 size = ap.alignFrame.getBounds();
1500 if (av.getCodingComplement() != null)
1502 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1510 view.setXpos(position.x);
1511 view.setYpos(position.y);
1513 view.setWidth(size.width);
1514 view.setHeight(size.height);
1516 view.setStartRes(vpRanges.getStartRes());
1517 view.setStartSeq(vpRanges.getStartSeq());
1519 OverviewPanel ov = ap.getOverviewPanel();
1522 Overview overview = new Overview();
1523 overview.setTitle(ov.getTitle());
1524 Rectangle bounds = ov.getFrameBounds();
1525 overview.setXpos(bounds.x);
1526 overview.setYpos(bounds.y);
1527 overview.setWidth(bounds.width);
1528 overview.setHeight(bounds.height);
1529 overview.setShowHidden(ov.isShowHiddenRegions());
1530 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1531 overview.setResidueColour(
1532 ov.getCanvas().getResidueColour().getRGB());
1533 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1534 view.setOverview(overview);
1536 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1538 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1539 userColours, object));
1542 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1544 AnnotationColourScheme ac = constructAnnotationColours(
1545 (jalview.schemes.AnnotationColourGradient) av
1546 .getGlobalColourScheme(),
1547 userColours, object);
1549 view.setAnnotationColours(ac);
1550 view.setBgColour("AnnotationColourGradient");
1554 view.setBgColour(ColourSchemeProperty
1555 .getColourName(av.getGlobalColourScheme()));
1558 ResidueShaderI vcs = av.getResidueShading();
1559 ColourSchemeI cs = av.getGlobalColourScheme();
1563 if (vcs.conservationApplied())
1565 view.setConsThreshold(vcs.getConservationInc());
1566 if (cs instanceof jalview.schemes.UserColourScheme)
1568 view.setBgColour(setUserColourScheme(cs, userColours, object));
1571 view.setPidThreshold(vcs.getThreshold());
1574 view.setConservationSelected(av.getConservationSelected());
1575 view.setPidSelected(av.getAbovePIDThreshold());
1576 view.setCharHeight(av.getCharHeight());
1577 view.setCharWidth(av.getCharWidth());
1578 final Font font = av.getFont();
1579 view.setFontName(font.getName());
1580 view.setFontSize(font.getSize());
1581 view.setFontStyle(font.getStyle());
1582 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1583 view.setRenderGaps(av.isRenderGaps());
1584 view.setShowAnnotation(av.isShowAnnotation());
1585 view.setShowBoxes(av.getShowBoxes());
1586 view.setShowColourText(av.getColourText());
1587 view.setShowFullId(av.getShowJVSuffix());
1588 view.setRightAlignIds(av.isRightAlignIds());
1589 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1590 view.setShowText(av.getShowText());
1591 view.setShowUnconserved(av.getShowUnconserved());
1592 view.setWrapAlignment(av.getWrapAlignment());
1593 view.setTextCol1(av.getTextColour().getRGB());
1594 view.setTextCol2(av.getTextColour2().getRGB());
1595 view.setTextColThreshold(av.getThresholdTextColour());
1596 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1597 view.setShowSequenceLogo(av.isShowSequenceLogo());
1598 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1599 view.setShowGroupConsensus(av.isShowGroupConsensus());
1600 view.setShowGroupConservation(av.isShowGroupConservation());
1601 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1602 view.setShowDbRefTooltip(av.isShowDBRefs());
1603 view.setFollowHighlight(av.isFollowHighlight());
1604 view.setFollowSelection(av.followSelection);
1605 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1606 view.setShowComplementFeatures(av.isShowComplementFeatures());
1607 view.setShowComplementFeaturesOnTop(
1608 av.isShowComplementFeaturesOnTop());
1609 if (av.getFeaturesDisplayed() != null)
1611 FeatureSettings fs = new FeatureSettings();
1613 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1614 .getFeatureRenderer();
1615 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1617 Vector<String> settingsAdded = new Vector<>();
1618 if (renderOrder != null)
1620 for (String featureType : renderOrder)
1622 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1623 setting.setType(featureType);
1626 * save any filter for the feature type
1628 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1631 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1633 FeatureMatcherI firstFilter = filters.next();
1634 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1635 filters, filter.isAnded()));
1639 * save colour scheme for the feature type
1641 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1642 if (!fcol.isSimpleColour())
1644 setting.setColour(fcol.getMaxColour().getRGB());
1645 setting.setMincolour(fcol.getMinColour().getRGB());
1646 setting.setMin(fcol.getMin());
1647 setting.setMax(fcol.getMax());
1648 setting.setColourByLabel(fcol.isColourByLabel());
1649 if (fcol.isColourByAttribute())
1651 String[] attName = fcol.getAttributeName();
1652 setting.getAttributeName().add(attName[0]);
1653 if (attName.length > 1)
1655 setting.getAttributeName().add(attName[1]);
1658 setting.setAutoScale(fcol.isAutoScaled());
1659 setting.setThreshold(fcol.getThreshold());
1660 Color noColour = fcol.getNoColour();
1661 if (noColour == null)
1663 setting.setNoValueColour(NoValueColour.NONE);
1665 else if (noColour.equals(fcol.getMaxColour()))
1667 setting.setNoValueColour(NoValueColour.MAX);
1671 setting.setNoValueColour(NoValueColour.MIN);
1673 // -1 = No threshold, 0 = Below, 1 = Above
1674 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1675 : (fcol.isBelowThreshold() ? 0 : -1));
1679 setting.setColour(fcol.getColour().getRGB());
1683 av.getFeaturesDisplayed().isVisible(featureType));
1684 float rorder = fr.getOrder(featureType);
1687 setting.setOrder(rorder);
1689 /// fs.addSetting(setting);
1690 fs.getSetting().add(setting);
1691 settingsAdded.addElement(featureType);
1695 // is groups actually supposed to be a map here ?
1696 Iterator<String> en = fr.getFeatureGroups().iterator();
1697 Vector<String> groupsAdded = new Vector<>();
1698 while (en.hasNext())
1700 String grp = en.next();
1701 if (groupsAdded.contains(grp))
1705 Group g = new Group();
1707 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1710 fs.getGroup().add(g);
1711 groupsAdded.addElement(grp);
1713 // jms.setFeatureSettings(fs);
1714 object.setFeatureSettings(fs);
1717 if (av.hasHiddenColumns())
1719 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1720 .getHiddenColumns();
1724 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1728 Iterator<int[]> hiddenRegions = hidden.iterator();
1729 while (hiddenRegions.hasNext())
1731 int[] region = hiddenRegions.next();
1732 HiddenColumns hc = new HiddenColumns();
1733 hc.setStart(region[0]);
1734 hc.setEnd(region[1]);
1735 // view.addHiddenColumns(hc);
1736 view.getHiddenColumns().add(hc);
1740 if (calcIdSet.size() > 0)
1742 for (String calcId : calcIdSet)
1744 if (calcId.trim().length() > 0)
1746 CalcIdParam cidp = createCalcIdParam(calcId, av);
1747 // Some calcIds have no parameters.
1750 // view.addCalcIdParam(cidp);
1751 view.getCalcIdParam().add(cidp);
1757 // jms.addViewport(view);
1758 object.getViewport().add(view);
1760 // object.setJalviewModelSequence(jms);
1761 // object.getVamsasModel().addSequenceSet(vamsasSet);
1762 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1764 if (jout != null && fileName != null)
1766 // We may not want to write the object to disk,
1767 // eg we can copy the alignViewport to a new view object
1768 // using save and then load
1771 fileName = fileName.replace('\\', '/');
1772 System.out.println("Writing jar entry " + fileName);
1773 JarEntry entry = new JarEntry(fileName);
1774 jout.putNextEntry(entry);
1775 PrintWriter pout = new PrintWriter(
1776 new OutputStreamWriter(jout, UTF_8));
1777 JAXBContext jaxbContext = JAXBContext
1778 .newInstance(JalviewModel.class);
1779 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1781 // output pretty printed
1782 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1783 jaxbMarshaller.marshal(
1784 new ObjectFactory().createJalviewModel(object), pout);
1786 // jaxbMarshaller.marshal(object, pout);
1787 // marshaller.marshal(object);
1790 } catch (Exception ex)
1792 // TODO: raise error in GUI if marshalling failed.
1793 System.err.println("Error writing Jalview project");
1794 ex.printStackTrace();
1801 * Writes PCA viewer attributes and computed values to an XML model object and
1802 * adds it to the JalviewModel. Any exceptions are reported by logging.
1804 protected void savePCA(PCAPanel panel, JalviewModel object)
1808 PcaViewer viewer = new PcaViewer();
1809 viewer.setHeight(panel.getHeight());
1810 viewer.setWidth(panel.getWidth());
1811 viewer.setXpos(panel.getX());
1812 viewer.setYpos(panel.getY());
1813 viewer.setTitle(panel.getTitle());
1814 PCAModel pcaModel = panel.getPcaModel();
1815 viewer.setScoreModelName(pcaModel.getScoreModelName());
1816 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1817 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1818 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1820 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1821 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1822 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1823 SeqPointMin spmin = new SeqPointMin();
1824 spmin.setXPos(spMin[0]);
1825 spmin.setYPos(spMin[1]);
1826 spmin.setZPos(spMin[2]);
1827 viewer.setSeqPointMin(spmin);
1828 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1829 SeqPointMax spmax = new SeqPointMax();
1830 spmax.setXPos(spMax[0]);
1831 spmax.setYPos(spMax[1]);
1832 spmax.setZPos(spMax[2]);
1833 viewer.setSeqPointMax(spmax);
1834 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1835 viewer.setLinkToAllViews(
1836 panel.getRotatableCanvas().isApplyToAllViews());
1837 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1838 viewer.setIncludeGaps(sp.includeGaps());
1839 viewer.setMatchGaps(sp.matchGaps());
1840 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1841 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1844 * sequence points on display
1846 for (jalview.datamodel.SequencePoint spt : pcaModel
1847 .getSequencePoints())
1849 SequencePoint point = new SequencePoint();
1850 point.setSequenceRef(seqHash(spt.getSequence()));
1851 point.setXPos(spt.coord.x);
1852 point.setYPos(spt.coord.y);
1853 point.setZPos(spt.coord.z);
1854 viewer.getSequencePoint().add(point);
1858 * (end points of) axes on display
1860 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1863 Axis axis = new Axis();
1867 viewer.getAxis().add(axis);
1871 * raw PCA data (note we are not restoring PCA inputs here -
1872 * alignment view, score model, similarity parameters)
1874 PcaDataType data = new PcaDataType();
1875 viewer.setPcaData(data);
1876 PCA pca = pcaModel.getPcaData();
1878 DoubleMatrix pm = new DoubleMatrix();
1879 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1880 data.setPairwiseMatrix(pm);
1882 DoubleMatrix tm = new DoubleMatrix();
1883 saveDoubleMatrix(pca.getTridiagonal(), tm);
1884 data.setTridiagonalMatrix(tm);
1886 DoubleMatrix eigenMatrix = new DoubleMatrix();
1887 data.setEigenMatrix(eigenMatrix);
1888 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1890 object.getPcaViewer().add(viewer);
1891 } catch (Throwable t)
1893 Console.error("Error saving PCA: " + t.getMessage());
1898 * Stores values from a matrix into an XML element, including (if present) the
1903 * @see #loadDoubleMatrix(DoubleMatrix)
1905 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1907 xmlMatrix.setRows(m.height());
1908 xmlMatrix.setColumns(m.width());
1909 for (int i = 0; i < m.height(); i++)
1911 DoubleVector row = new DoubleVector();
1912 for (int j = 0; j < m.width(); j++)
1914 row.getV().add(m.getValue(i, j));
1916 xmlMatrix.getRow().add(row);
1918 if (m.getD() != null)
1920 DoubleVector dVector = new DoubleVector();
1921 for (double d : m.getD())
1923 dVector.getV().add(d);
1925 xmlMatrix.setD(dVector);
1927 if (m.getE() != null)
1929 DoubleVector eVector = new DoubleVector();
1930 for (double e : m.getE())
1932 eVector.getV().add(e);
1934 xmlMatrix.setE(eVector);
1939 * Loads XML matrix data into a new Matrix object, including the D and/or E
1940 * vectors (if present)
1944 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1946 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1948 int rows = mData.getRows();
1949 double[][] vals = new double[rows][];
1951 for (int i = 0; i < rows; i++)
1953 List<Double> dVector = mData.getRow().get(i).getV();
1954 vals[i] = new double[dVector.size()];
1956 for (Double d : dVector)
1962 MatrixI m = new Matrix(vals);
1964 if (mData.getD() != null)
1966 List<Double> dVector = mData.getD().getV();
1967 double[] vec = new double[dVector.size()];
1969 for (Double d : dVector)
1975 if (mData.getE() != null)
1977 List<Double> dVector = mData.getE().getV();
1978 double[] vec = new double[dVector.size()];
1980 for (Double d : dVector)
1991 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1992 * for each viewer, with
1994 * <li>viewer geometry (position, size, split pane divider location)</li>
1995 * <li>index of the selected structure in the viewer (currently shows gapped
1997 * <li>the id of the annotation holding RNA secondary structure</li>
1998 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2000 * Varna viewer state is also written out (in native Varna XML) to separate
2001 * project jar entries. A separate entry is written for each RNA structure
2002 * displayed, with the naming convention
2004 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2012 * @param storeDataset
2014 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2015 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2016 boolean storeDataset)
2018 if (Desktop.desktop == null)
2022 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2023 for (int f = frames.length - 1; f > -1; f--)
2025 if (frames[f] instanceof AppVarna)
2027 AppVarna varna = (AppVarna) frames[f];
2029 * link the sequence to every viewer that is showing it and is linked to
2030 * its alignment panel
2032 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2034 String viewId = varna.getViewId();
2035 RnaViewer rna = new RnaViewer();
2036 rna.setViewId(viewId);
2037 rna.setTitle(varna.getTitle());
2038 rna.setXpos(varna.getX());
2039 rna.setYpos(varna.getY());
2040 rna.setWidth(varna.getWidth());
2041 rna.setHeight(varna.getHeight());
2042 rna.setDividerLocation(varna.getDividerLocation());
2043 rna.setSelectedRna(varna.getSelectedIndex());
2044 // jseq.addRnaViewer(rna);
2045 jseq.getRnaViewer().add(rna);
2048 * Store each Varna panel's state once in the project per sequence.
2049 * First time through only (storeDataset==false)
2051 // boolean storeSessions = false;
2052 // String sequenceViewId = viewId + seqsToIds.get(jds);
2053 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2055 // viewIds.add(sequenceViewId);
2056 // storeSessions = true;
2058 for (RnaModel model : varna.getModels())
2060 if (model.seq == jds)
2063 * VARNA saves each view (sequence or alignment secondary
2064 * structure, gapped or trimmed) as a separate XML file
2066 String jarEntryName = rnaSessions.get(model);
2067 if (jarEntryName == null)
2070 String varnaStateFile = varna.getStateInfo(model.rna);
2071 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2072 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2073 rnaSessions.put(model, jarEntryName);
2075 SecondaryStructure ss = new SecondaryStructure();
2076 String annotationId = varna.getAnnotation(jds).annotationId;
2077 ss.setAnnotationId(annotationId);
2078 ss.setViewerState(jarEntryName);
2079 ss.setGapped(model.gapped);
2080 ss.setTitle(model.title);
2081 // rna.addSecondaryStructure(ss);
2082 rna.getSecondaryStructure().add(ss);
2091 * Copy the contents of a file to a new entry added to the output jar
2095 * @param jarEntryName
2097 * additional identifying info to log to the console
2099 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2100 String jarEntryName, String msg)
2102 try (InputStream is = new FileInputStream(infilePath))
2104 File file = new File(infilePath);
2105 if (file.exists() && jout != null)
2108 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2109 jout.putNextEntry(new JarEntry(jarEntryName));
2112 // dis = new DataInputStream(new FileInputStream(file));
2113 // byte[] data = new byte[(int) file.length()];
2114 // dis.readFully(data);
2115 // writeJarEntry(jout, jarEntryName, data);
2117 } catch (Exception ex)
2119 ex.printStackTrace();
2124 * Copies input to output, in 4K buffers; handles any data (text or binary)
2128 * @throws IOException
2130 protected void copyAll(InputStream in, OutputStream out)
2133 byte[] buffer = new byte[4096];
2135 while ((bytesRead = in.read(buffer)) != -1)
2137 out.write(buffer, 0, bytesRead);
2142 * Save the state of a structure viewer
2147 * the archive XML element under which to save the state
2150 * @param matchedFile
2154 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2155 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2156 String matchedFile, StructureViewerBase viewFrame)
2158 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2161 * Look for any bindings for this viewer to the PDB file of interest
2162 * (including part matches excluding chain id)
2164 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2166 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2167 final String pdbId = pdbentry.getId();
2168 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2169 && entry.getId().toLowerCase(Locale.ROOT)
2170 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2173 * not interested in a binding to a different PDB entry here
2177 if (matchedFile == null)
2179 matchedFile = pdbentry.getFile();
2181 else if (!matchedFile.equals(pdbentry.getFile()))
2184 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2185 + pdbentry.getFile());
2189 // can get at it if the ID
2190 // match is ambiguous (e.g.
2193 for (int smap = 0; smap < viewFrame.getBinding()
2194 .getSequence()[peid].length; smap++)
2196 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2197 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2199 StructureState state = new StructureState();
2200 state.setVisible(true);
2201 state.setXpos(viewFrame.getX());
2202 state.setYpos(viewFrame.getY());
2203 state.setWidth(viewFrame.getWidth());
2204 state.setHeight(viewFrame.getHeight());
2205 final String viewId = viewFrame.getViewId();
2206 state.setViewId(viewId);
2207 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2208 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2209 state.setColourByJmol(viewFrame.isColouredByViewer());
2210 state.setType(viewFrame.getViewerType().toString());
2211 // pdb.addStructureState(state);
2212 pdb.getStructureState().add(state);
2220 * Populates the AnnotationColourScheme xml for save. This captures the
2221 * settings of the options in the 'Colour by Annotation' dialog.
2224 * @param userColours
2228 private AnnotationColourScheme constructAnnotationColours(
2229 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2232 AnnotationColourScheme ac = new AnnotationColourScheme();
2233 ac.setAboveThreshold(acg.getAboveThreshold());
2234 ac.setThreshold(acg.getAnnotationThreshold());
2235 // 2.10.2 save annotationId (unique) not annotation label
2236 ac.setAnnotation(acg.getAnnotation().annotationId);
2237 if (acg.getBaseColour() instanceof UserColourScheme)
2240 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2245 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2248 ac.setMaxColour(acg.getMaxColour().getRGB());
2249 ac.setMinColour(acg.getMinColour().getRGB());
2250 ac.setPerSequence(acg.isSeqAssociated());
2251 ac.setPredefinedColours(acg.isPredefinedColours());
2255 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2256 IdentityHashMap<SequenceGroup, String> groupRefs,
2257 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2258 SequenceSet vamsasSet)
2261 for (int i = 0; i < aa.length; i++)
2263 Annotation an = new Annotation();
2265 AlignmentAnnotation annotation = aa[i];
2266 if (annotation.annotationId != null)
2268 annotationIds.put(annotation.annotationId, annotation);
2271 an.setId(annotation.annotationId);
2273 an.setVisible(annotation.visible);
2275 an.setDescription(annotation.description);
2277 if (annotation.sequenceRef != null)
2279 // 2.9 JAL-1781 xref on sequence id rather than name
2280 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2282 if (annotation.groupRef != null)
2284 String groupIdr = groupRefs.get(annotation.groupRef);
2285 if (groupIdr == null)
2287 // make a locally unique String
2288 groupRefs.put(annotation.groupRef,
2289 groupIdr = ("" + System.currentTimeMillis()
2290 + annotation.groupRef.getName()
2291 + groupRefs.size()));
2293 an.setGroupRef(groupIdr.toString());
2296 // store all visualization attributes for annotation
2297 an.setGraphHeight(annotation.graphHeight);
2298 an.setCentreColLabels(annotation.centreColLabels);
2299 an.setScaleColLabels(annotation.scaleColLabel);
2300 an.setShowAllColLabels(annotation.showAllColLabels);
2301 an.setBelowAlignment(annotation.belowAlignment);
2303 if (annotation.graph > 0)
2306 an.setGraphType(annotation.graph);
2307 an.setGraphGroup(annotation.graphGroup);
2308 if (annotation.getThreshold() != null)
2310 ThresholdLine line = new ThresholdLine();
2311 line.setLabel(annotation.getThreshold().label);
2312 line.setValue(annotation.getThreshold().value);
2313 line.setColour(annotation.getThreshold().colour.getRGB());
2314 an.setThresholdLine(line);
2316 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2318 if (annotation.sequenceRef.getContactMaps() != null)
2320 ContactMatrixI cm = annotation.sequenceRef
2321 .getContactMatrixFor(annotation);
2324 storeMatrixFor(vamsasSet, an,annotation, cm);
2334 an.setLabel(annotation.label);
2336 if (annotation == av.getAlignmentQualityAnnot()
2337 || annotation == av.getAlignmentConservationAnnotation()
2338 || annotation == av.getAlignmentConsensusAnnotation()
2339 || annotation.autoCalculated)
2341 // new way of indicating autocalculated annotation -
2342 an.setAutoCalculated(annotation.autoCalculated);
2344 if (annotation.hasScore())
2346 an.setScore(annotation.getScore());
2349 if (annotation.getCalcId() != null)
2351 calcIdSet.add(annotation.getCalcId());
2352 an.setCalcId(annotation.getCalcId());
2354 if (annotation.hasProperties())
2356 for (String pr : annotation.getProperties())
2358 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2360 prop.setValue(annotation.getProperty(pr));
2361 an.getProperty().add(prop);
2365 AnnotationElement ae;
2366 if (annotation.annotations != null)
2368 an.setScoreOnly(false);
2369 for (int a = 0; a < annotation.annotations.length; a++)
2371 if ((annotation == null) || (annotation.annotations[a] == null))
2376 ae = new AnnotationElement();
2377 if (annotation.annotations[a].description != null)
2379 ae.setDescription(annotation.annotations[a].description);
2381 if (annotation.annotations[a].displayCharacter != null)
2383 ae.setDisplayCharacter(
2384 annotation.annotations[a].displayCharacter);
2387 if (!Float.isNaN(annotation.annotations[a].value))
2389 ae.setValue(annotation.annotations[a].value);
2393 if (annotation.annotations[a].secondaryStructure > ' ')
2395 ae.setSecondaryStructure(
2396 annotation.annotations[a].secondaryStructure + "");
2399 if (annotation.annotations[a].colour != null
2400 && annotation.annotations[a].colour != java.awt.Color.black)
2402 ae.setColour(annotation.annotations[a].colour.getRGB());
2405 // an.addAnnotationElement(ae);
2406 an.getAnnotationElement().add(ae);
2407 if (annotation.autoCalculated)
2409 // only write one non-null entry into the annotation row -
2410 // sufficient to get the visualization attributes necessary to
2418 an.setScoreOnly(true);
2420 if (!storeDS || (storeDS && !annotation.autoCalculated))
2422 // skip autocalculated annotation - these are only provided for
2424 // vamsasSet.addAnnotation(an);
2425 vamsasSet.getAnnotation().add(an);
2431 private void storeMatrixFor(SequenceSet root, Annotation an, AlignmentAnnotation annotation, ContactMatrixI cm)
2433 String cmId = contactMatrices.get(cm);
2434 MatrixType xmlmat=null;
2437 xmlmat = new MatrixType();
2438 xmlmat.setType(cm.getType());
2439 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2440 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2441 // consider using an opaque to/from -> allow instance to control
2442 // its representation ?
2443 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2446 for (BitSet gp : cm.getGroups())
2448 xmlmat.getGroups().add(stringifyBitset(gp));
2453 // provenance object for tree ?
2454 xmlmat.getNewick().add(cm.getNewick());
2455 xmlmat.setTreeMethod(cm.getTreeMethod());
2457 if (cm.hasCutHeight())
2459 xmlmat.setCutHeight(cm.getCutHeight());
2461 xmlmat.setId(makeHashCode(cm, cm.get));
2462 root.getMatrices().add(xmlmat);
2467 // set/get properties
2468 if (cm instanceof MappableContactMatrixI)
2470 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2471 .getMapFor(annotation.sequenceRef);
2474 MapListType mp = new MapListType();
2475 List<int[]> r = mlst.getFromRanges();
2476 for (int[] range : r)
2478 MapListFrom mfrom = new MapListFrom();
2479 mfrom.setStart(range[0]);
2480 mfrom.setEnd(range[1]);
2481 // mp.addMapListFrom(mfrom);
2482 mp.getMapListFrom().add(mfrom);
2484 r = mlst.getToRanges();
2485 for (int[] range : r)
2487 MapListTo mto = new MapListTo();
2488 mto.setStart(range[0]);
2489 mto.setEnd(range[1]);
2490 // mp.addMapListTo(mto);
2491 mp.getMapListTo().add(mto);
2494 BigInteger.valueOf(mlst.getFromRatio()));
2495 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2496 xmlmat.setMapping(mp);
2500 an.getContactmatrix().add(xmlmat);
2503 private String stringifyBitset(BitSet gp)
2505 StringBuilder sb = new StringBuilder();
2506 for (long val : gp.toLongArray())
2508 if (sb.length() > 0)
2514 return sb.toString();
2517 private BitSet deStringifyBitset(String stringified)
2519 if ("".equals(stringified) || stringified == null)
2521 return new BitSet();
2523 String[] longvals = stringified.split(",");
2524 long[] newlongvals = new long[longvals.length];
2525 for (int lv = 0; lv < longvals.length; lv++)
2529 newlongvals[lv] = Long.valueOf(longvals[lv]);
2530 } catch (Exception x)
2532 errorMessage += "Couldn't destringify bitset from: '" + stringified
2534 newlongvals[lv] = 0;
2537 return BitSet.valueOf(newlongvals);
2540 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2542 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2543 if (settings != null)
2545 CalcIdParam vCalcIdParam = new CalcIdParam();
2546 vCalcIdParam.setCalcId(calcId);
2547 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2548 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2549 // generic URI allowing a third party to resolve another instance of the
2550 // service used for this calculation
2551 for (String url : settings.getServiceURLs())
2553 // vCalcIdParam.addServiceURL(urls);
2554 vCalcIdParam.getServiceURL().add(url);
2556 vCalcIdParam.setVersion("1.0");
2557 if (settings.getPreset() != null)
2559 WsParamSetI setting = settings.getPreset();
2560 vCalcIdParam.setName(setting.getName());
2561 vCalcIdParam.setDescription(setting.getDescription());
2565 vCalcIdParam.setName("");
2566 vCalcIdParam.setDescription("Last used parameters");
2568 // need to be able to recover 1) settings 2) user-defined presets or
2569 // recreate settings from preset 3) predefined settings provided by
2570 // service - or settings that can be transferred (or discarded)
2571 vCalcIdParam.setParameters(
2572 settings.getWsParamFile().replace("\n", "|\\n|"));
2573 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2574 // todo - decide if updateImmediately is needed for any projects.
2576 return vCalcIdParam;
2581 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2584 if (calcIdParam.getVersion().equals("1.0"))
2586 final String[] calcIds = calcIdParam.getServiceURL()
2587 .toArray(new String[0]);
2588 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2589 .getPreferredServiceFor(calcIds);
2590 if (service != null)
2592 WsParamSetI parmSet = null;
2595 parmSet = service.getParamStore().parseServiceParameterFile(
2596 calcIdParam.getName(), calcIdParam.getDescription(),
2598 calcIdParam.getParameters().replace("|\\n|", "\n"));
2599 } catch (IOException x)
2601 Console.warn("Couldn't parse parameter data for "
2602 + calcIdParam.getCalcId(), x);
2605 List<ArgumentI> argList = null;
2606 if (calcIdParam.getName().length() > 0)
2608 parmSet = service.getParamStore()
2609 .getPreset(calcIdParam.getName());
2610 if (parmSet != null)
2612 // TODO : check we have a good match with settings in AACon -
2613 // otherwise we'll need to create a new preset
2618 argList = parmSet.getArguments();
2621 AAConSettings settings = new AAConSettings(
2622 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2623 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2624 calcIdParam.isNeedsUpdate());
2630 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2634 throw new Error(MessageManager.formatMessage(
2635 "error.unsupported_version_calcIdparam", new Object[]
2636 { calcIdParam.toString() }));
2640 * External mapping between jalview objects and objects yielding a valid and
2641 * unique object ID string. This is null for normal Jalview project IO, but
2642 * non-null when a jalview project is being read or written as part of a
2645 IdentityHashMap jv2vobj = null;
2648 * Construct a unique ID for jvobj using either existing bindings or if none
2649 * exist, the result of the hashcode call for the object.
2652 * jalview data object
2653 * @return unique ID for referring to jvobj
2655 private String makeHashCode(Object jvobj, String altCode)
2657 if (jv2vobj != null)
2659 Object id = jv2vobj.get(jvobj);
2662 return id.toString();
2664 // check string ID mappings
2665 if (jvids2vobj != null && jvobj instanceof String)
2667 id = jvids2vobj.get(jvobj);
2671 return id.toString();
2673 // give up and warn that something has gone wrong
2675 "Cannot find ID for object in external mapping : " + jvobj);
2681 * return local jalview object mapped to ID, if it exists
2685 * @return null or object bound to idcode
2687 private Object retrieveExistingObj(String idcode)
2689 if (idcode != null && vobj2jv != null)
2691 return vobj2jv.get(idcode);
2697 * binding from ID strings from external mapping table to jalview data model
2700 private Hashtable vobj2jv;
2702 private Sequence createVamsasSequence(String id, SequenceI jds)
2704 return createVamsasSequence(true, id, jds, null);
2707 private Sequence createVamsasSequence(boolean recurse, String id,
2708 SequenceI jds, SequenceI parentseq)
2710 Sequence vamsasSeq = new Sequence();
2711 vamsasSeq.setId(id);
2712 vamsasSeq.setName(jds.getName());
2713 vamsasSeq.setSequence(jds.getSequenceAsString());
2714 vamsasSeq.setDescription(jds.getDescription());
2715 List<DBRefEntry> dbrefs = null;
2716 if (jds.getDatasetSequence() != null)
2718 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2722 // seqId==dsseqid so we can tell which sequences really are
2723 // dataset sequences only
2724 vamsasSeq.setDsseqid(id);
2725 dbrefs = jds.getDBRefs();
2726 if (parentseq == null)
2733 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2737 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2739 DBRef dbref = new DBRef();
2740 DBRefEntry ref = dbrefs.get(d);
2741 dbref.setSource(ref.getSource());
2742 dbref.setVersion(ref.getVersion());
2743 dbref.setAccessionId(ref.getAccessionId());
2744 dbref.setCanonical(ref.isCanonical());
2745 if (ref instanceof GeneLocus)
2747 dbref.setLocus(true);
2751 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2753 dbref.setMapping(mp);
2755 vamsasSeq.getDBRef().add(dbref);
2761 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2762 SequenceI parentseq, SequenceI jds, boolean recurse)
2765 if (jmp.getMap() != null)
2769 jalview.util.MapList mlst = jmp.getMap();
2770 List<int[]> r = mlst.getFromRanges();
2771 for (int[] range : r)
2773 MapListFrom mfrom = new MapListFrom();
2774 mfrom.setStart(range[0]);
2775 mfrom.setEnd(range[1]);
2776 // mp.addMapListFrom(mfrom);
2777 mp.getMapListFrom().add(mfrom);
2779 r = mlst.getToRanges();
2780 for (int[] range : r)
2782 MapListTo mto = new MapListTo();
2783 mto.setStart(range[0]);
2784 mto.setEnd(range[1]);
2785 // mp.addMapListTo(mto);
2786 mp.getMapListTo().add(mto);
2788 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2789 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2790 if (jmp.getTo() != null)
2792 // MappingChoice mpc = new MappingChoice();
2794 // check/create ID for the sequence referenced by getTo()
2797 SequenceI ps = null;
2798 if (parentseq != jmp.getTo()
2799 && parentseq.getDatasetSequence() != jmp.getTo())
2801 // chaining dbref rather than a handshaking one
2802 jmpid = seqHash(ps = jmp.getTo());
2806 jmpid = seqHash(ps = parentseq);
2808 // mpc.setDseqFor(jmpid);
2809 mp.setDseqFor(jmpid);
2810 if (!seqRefIds.containsKey(jmpid))
2812 Console.debug("creatign new DseqFor ID");
2813 seqRefIds.put(jmpid, ps);
2817 Console.debug("reusing DseqFor ID");
2820 // mp.setMappingChoice(mpc);
2826 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2827 List<UserColourScheme> userColours, JalviewModel jm)
2830 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2831 boolean newucs = false;
2832 if (!userColours.contains(ucs))
2834 userColours.add(ucs);
2837 id = "ucs" + userColours.indexOf(ucs);
2840 // actually create the scheme's entry in the XML model
2841 java.awt.Color[] colours = ucs.getColours();
2842 UserColours uc = new UserColours();
2843 // UserColourScheme jbucs = new UserColourScheme();
2844 JalviewUserColours jbucs = new JalviewUserColours();
2846 for (int i = 0; i < colours.length; i++)
2848 Colour col = new Colour();
2849 col.setName(ResidueProperties.aa[i]);
2850 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2851 // jbucs.addColour(col);
2852 jbucs.getColour().add(col);
2854 if (ucs.getLowerCaseColours() != null)
2856 colours = ucs.getLowerCaseColours();
2857 for (int i = 0; i < colours.length; i++)
2859 Colour col = new Colour();
2860 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2861 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2862 // jbucs.addColour(col);
2863 jbucs.getColour().add(col);
2868 uc.setUserColourScheme(jbucs);
2869 // jm.addUserColours(uc);
2870 jm.getUserColours().add(uc);
2876 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2879 List<UserColours> uc = jm.getUserColours();
2880 UserColours colours = null;
2882 for (int i = 0; i < uc.length; i++)
2884 if (uc[i].getId().equals(id))
2891 for (UserColours c : uc)
2893 if (c.getId().equals(id))
2900 java.awt.Color[] newColours = new java.awt.Color[24];
2902 for (int i = 0; i < 24; i++)
2904 newColours[i] = new java.awt.Color(Integer.parseInt(
2905 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2906 colours.getUserColourScheme().getColour().get(i).getRGB(),
2910 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2913 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2915 newColours = new java.awt.Color[23];
2916 for (int i = 0; i < 23; i++)
2918 newColours[i] = new java.awt.Color(
2919 Integer.parseInt(colours.getUserColourScheme().getColour()
2920 .get(i + 24).getRGB(), 16));
2922 ucs.setLowerCaseColours(newColours);
2929 * contains last error message (if any) encountered by XML loader.
2931 String errorMessage = null;
2934 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2935 * exceptions are raised during project XML parsing
2937 public boolean attemptversion1parse = false;
2940 * Load a jalview project archive from a jar file
2943 * - HTTP URL or filename
2945 public AlignFrame loadJalviewAlign(final Object file)
2948 jalview.gui.AlignFrame af = null;
2952 // create list to store references for any new Jmol viewers created
2953 newStructureViewers = new Vector<>();
2954 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2955 // Workaround is to make sure caller implements the JarInputStreamProvider
2957 // so we can re-open the jar input stream for each entry.
2959 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2960 af = loadJalviewAlign(jprovider);
2963 af.setMenusForViewport();
2965 } catch (MalformedURLException e)
2967 errorMessage = "Invalid URL format for '" + file + "'";
2973 SwingUtilities.invokeAndWait(new Runnable()
2978 setLoadingFinishedForNewStructureViewers();
2981 } catch (Exception x)
2983 System.err.println("Error loading alignment: " + x.getMessage());
2989 @SuppressWarnings("unused")
2990 private jarInputStreamProvider createjarInputStreamProvider(
2991 final Object ofile) throws MalformedURLException
2994 // BH 2018 allow for bytes already attached to File object
2997 String file = (ofile instanceof File
2998 ? ((File) ofile).getCanonicalPath()
2999 : ofile.toString());
3000 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3003 errorMessage = null;
3004 uniqueSetSuffix = null;
3006 viewportsAdded.clear();
3007 frefedSequence = null;
3009 if (HttpUtils.startsWithHttpOrHttps(file))
3011 url = new URL(file);
3013 final URL _url = url;
3014 return new jarInputStreamProvider()
3018 public JarInputStream getJarInputStream() throws IOException
3022 // System.out.println("Jalview2XML: opening byte jarInputStream for
3023 // bytes.length=" + bytes.length);
3024 return new JarInputStream(new ByteArrayInputStream(bytes));
3028 // System.out.println("Jalview2XML: opening url jarInputStream for "
3030 return new JarInputStream(_url.openStream());
3034 // System.out.println("Jalview2XML: opening file jarInputStream for
3036 return new JarInputStream(new FileInputStream(file));
3041 public String getFilename()
3046 } catch (IOException e)
3048 e.printStackTrace();
3054 * Recover jalview session from a jalview project archive. Caller may
3055 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3056 * themselves. Any null fields will be initialised with default values,
3057 * non-null fields are left alone.
3062 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3064 errorMessage = null;
3065 if (uniqueSetSuffix == null)
3067 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3069 if (seqRefIds == null)
3073 AlignFrame af = null, _af = null;
3074 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3075 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3076 final String file = jprovider.getFilename();
3079 JarInputStream jin = null;
3080 JarEntry jarentry = null;
3085 jin = jprovider.getJarInputStream();
3086 for (int i = 0; i < entryCount; i++)
3088 jarentry = jin.getNextJarEntry();
3091 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3093 JAXBContext jc = JAXBContext
3094 .newInstance("jalview.xml.binding.jalview");
3095 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3096 .createXMLStreamReader(jin);
3097 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3098 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3099 JalviewModel.class);
3100 JalviewModel object = jbe.getValue();
3102 if (true) // !skipViewport(object))
3104 _af = loadFromObject(object, file, true, jprovider);
3105 if (_af != null && object.getViewport().size() > 0)
3106 // getJalviewModelSequence().getViewportCount() > 0)
3110 // store a reference to the first view
3113 if (_af.getViewport().isGatherViewsHere())
3115 // if this is a gathered view, keep its reference since
3116 // after gathering views, only this frame will remain
3118 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3121 // Save dataset to register mappings once all resolved
3122 importedDatasets.put(
3123 af.getViewport().getAlignment().getDataset(),
3124 af.getViewport().getAlignment().getDataset());
3129 else if (jarentry != null)
3131 // Some other file here.
3134 } while (jarentry != null);
3136 resolveFrefedSequences();
3137 } catch (IOException ex)
3139 ex.printStackTrace();
3140 errorMessage = "Couldn't locate Jalview XML file : " + file;
3142 "Exception whilst loading jalview XML file : " + ex + "\n");
3143 } catch (Exception ex)
3145 System.err.println("Parsing as Jalview Version 2 file failed.");
3146 ex.printStackTrace(System.err);
3147 if (attemptversion1parse)
3149 // used to attempt to parse as V1 castor-generated xml
3151 if (Desktop.instance != null)
3153 Desktop.instance.stopLoading();
3157 System.out.println("Successfully loaded archive file");
3160 ex.printStackTrace();
3163 "Exception whilst loading jalview XML file : " + ex + "\n");
3164 } catch (OutOfMemoryError e)
3166 // Don't use the OOM Window here
3167 errorMessage = "Out of memory loading jalview XML file";
3168 System.err.println("Out of memory whilst loading jalview XML file");
3169 e.printStackTrace();
3173 * Regather multiple views (with the same sequence set id) to the frame (if
3174 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3175 * views instead of separate frames. Note this doesn't restore a state where
3176 * some expanded views in turn have tabbed views - the last "first tab" read
3177 * in will play the role of gatherer for all.
3179 for (AlignFrame fr : gatherToThisFrame.values())
3181 Desktop.instance.gatherViews(fr);
3184 restoreSplitFrames();
3185 for (AlignmentI ds : importedDatasets.keySet())
3187 if (ds.getCodonFrames() != null)
3189 StructureSelectionManager
3190 .getStructureSelectionManager(Desktop.instance)
3191 .registerMappings(ds.getCodonFrames());
3194 if (errorMessage != null)
3199 if (Desktop.instance != null)
3201 Desktop.instance.stopLoading();
3208 * Try to reconstruct and display SplitFrame windows, where each contains
3209 * complementary dna and protein alignments. Done by pairing up AlignFrame
3210 * objects (created earlier) which have complementary viewport ids associated.
3212 protected void restoreSplitFrames()
3214 List<SplitFrame> gatherTo = new ArrayList<>();
3215 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3216 Map<String, AlignFrame> dna = new HashMap<>();
3219 * Identify the DNA alignments
3221 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3224 AlignFrame af = candidate.getValue();
3225 if (af.getViewport().getAlignment().isNucleotide())
3227 dna.put(candidate.getKey().getId(), af);
3232 * Try to match up the protein complements
3234 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3237 AlignFrame af = candidate.getValue();
3238 if (!af.getViewport().getAlignment().isNucleotide())
3240 String complementId = candidate.getKey().getComplementId();
3241 // only non-null complements should be in the Map
3242 if (complementId != null && dna.containsKey(complementId))
3244 final AlignFrame dnaFrame = dna.get(complementId);
3245 SplitFrame sf = createSplitFrame(dnaFrame, af);
3246 addedToSplitFrames.add(dnaFrame);
3247 addedToSplitFrames.add(af);
3248 dnaFrame.setMenusForViewport();
3249 af.setMenusForViewport();
3250 if (af.getViewport().isGatherViewsHere())
3259 * Open any that we failed to pair up (which shouldn't happen!) as
3260 * standalone AlignFrame's.
3262 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3265 AlignFrame af = candidate.getValue();
3266 if (!addedToSplitFrames.contains(af))
3268 Viewport view = candidate.getKey();
3269 Desktop.addInternalFrame(af, view.getTitle(),
3270 safeInt(view.getWidth()), safeInt(view.getHeight()));
3271 af.setMenusForViewport();
3272 System.err.println("Failed to restore view " + view.getTitle()
3273 + " to split frame");
3278 * Gather back into tabbed views as flagged.
3280 for (SplitFrame sf : gatherTo)
3282 Desktop.instance.gatherViews(sf);
3285 splitFrameCandidates.clear();
3289 * Construct and display one SplitFrame holding DNA and protein alignments.
3292 * @param proteinFrame
3295 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3296 AlignFrame proteinFrame)
3298 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3299 String title = MessageManager.getString("label.linked_view_title");
3300 int width = (int) dnaFrame.getBounds().getWidth();
3301 int height = (int) (dnaFrame.getBounds().getHeight()
3302 + proteinFrame.getBounds().getHeight() + 50);
3305 * SplitFrame location is saved to both enclosed frames
3307 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3308 Desktop.addInternalFrame(splitFrame, title, width, height);
3311 * And compute cDNA consensus (couldn't do earlier with consensus as
3312 * mappings were not yet present)
3314 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3320 * check errorMessage for a valid error message and raise an error box in the
3321 * GUI or write the current errorMessage to stderr and then clear the error
3324 protected void reportErrors()
3326 reportErrors(false);
3329 protected void reportErrors(final boolean saving)
3331 if (errorMessage != null)
3333 final String finalErrorMessage = errorMessage;
3336 javax.swing.SwingUtilities.invokeLater(new Runnable()
3341 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3343 "Error " + (saving ? "saving" : "loading")
3345 JvOptionPane.WARNING_MESSAGE);
3351 System.err.println("Problem loading Jalview file: " + errorMessage);
3354 errorMessage = null;
3357 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3360 * when set, local views will be updated from view stored in JalviewXML
3361 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3362 * sync if this is set to true.
3364 private final boolean updateLocalViews = false;
3367 * Returns the path to a temporary file holding the PDB file for the given PDB
3368 * id. The first time of asking, searches for a file of that name in the
3369 * Jalview project jar, and copies it to a new temporary file. Any repeat
3370 * requests just return the path to the file previously created.
3376 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3379 if (alreadyLoadedPDB.containsKey(pdbId))
3381 return alreadyLoadedPDB.get(pdbId).toString();
3384 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3386 if (tempFile != null)
3388 alreadyLoadedPDB.put(pdbId, tempFile);
3394 * Copies the jar entry of given name to a new temporary file and returns the
3395 * path to the file, or null if the entry is not found.
3398 * @param jarEntryName
3400 * a prefix for the temporary file name, must be at least three
3402 * @param suffixModel
3403 * null or original file - so new file can be given the same suffix
3407 protected String copyJarEntry(jarInputStreamProvider jprovider,
3408 String jarEntryName, String prefix, String suffixModel)
3410 String suffix = ".tmp";
3411 if (suffixModel == null)
3413 suffixModel = jarEntryName;
3415 int sfpos = suffixModel.lastIndexOf(".");
3416 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3418 suffix = "." + suffixModel.substring(sfpos + 1);
3421 try (JarInputStream jin = jprovider.getJarInputStream())
3423 JarEntry entry = null;
3426 entry = jin.getNextJarEntry();
3427 } while (entry != null && !entry.getName().equals(jarEntryName));
3431 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3432 File outFile = File.createTempFile(prefix, suffix);
3433 outFile.deleteOnExit();
3434 try (OutputStream os = new FileOutputStream(outFile))
3438 String t = outFile.getAbsolutePath();
3444 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3446 } catch (Exception ex)
3448 ex.printStackTrace();
3454 private class JvAnnotRow
3456 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3463 * persisted version of annotation row from which to take vis properties
3465 public jalview.datamodel.AlignmentAnnotation template;
3468 * original position of the annotation row in the alignment
3474 * Load alignment frame from jalview XML DOM object
3476 * @param jalviewModel
3479 * filename source string
3480 * @param loadTreesAndStructures
3481 * when false only create Viewport
3483 * data source provider
3484 * @return alignment frame created from view stored in DOM
3486 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3487 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3489 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3491 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3493 // JalviewModelSequence jms = object.getJalviewModelSequence();
3495 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3497 Viewport view = (jalviewModel.getViewport().size() > 0)
3498 ? jalviewModel.getViewport().get(0)
3501 // ////////////////////////////////
3502 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3505 // If we just load in the same jar file again, the sequenceSetId
3506 // will be the same, and we end up with multiple references
3507 // to the same sequenceSet. We must modify this id on load
3508 // so that each load of the file gives a unique id
3511 * used to resolve correct alignment dataset for alignments with multiple
3514 String uniqueSeqSetId = null;
3515 String viewId = null;
3518 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3519 viewId = (view.getId() == null ? null
3520 : view.getId() + uniqueSetSuffix);
3523 // ////////////////////////////////
3526 List<SequenceI> hiddenSeqs = null;
3528 List<SequenceI> tmpseqs = new ArrayList<>();
3530 boolean multipleView = false;
3531 SequenceI referenceseqForView = null;
3532 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3533 List<JSeq> jseqs = jalviewModel.getJSeq();
3534 int vi = 0; // counter in vamsasSeq array
3535 for (int i = 0; i < jseqs.size(); i++)
3537 JSeq jseq = jseqs.get(i);
3538 String seqId = jseq.getId();
3540 SequenceI tmpSeq = seqRefIds.get(seqId);
3543 if (!incompleteSeqs.containsKey(seqId))
3545 // may not need this check, but keep it for at least 2.9,1 release
3546 if (tmpSeq.getStart() != jseq.getStart()
3547 || tmpSeq.getEnd() != jseq.getEnd())
3549 System.err.println(String.format(
3550 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3551 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3552 jseq.getStart(), jseq.getEnd()));
3557 incompleteSeqs.remove(seqId);
3559 if (vamsasSeqs.size() > vi
3560 && vamsasSeqs.get(vi).getId().equals(seqId))
3562 // most likely we are reading a dataset XML document so
3563 // update from vamsasSeq section of XML for this sequence
3564 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3565 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3566 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3571 // reading multiple views, so vamsasSeq set is a subset of JSeq
3572 multipleView = true;
3574 tmpSeq.setStart(jseq.getStart());
3575 tmpSeq.setEnd(jseq.getEnd());
3576 tmpseqs.add(tmpSeq);
3580 Sequence vamsasSeq = vamsasSeqs.get(vi);
3581 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3582 vamsasSeq.getSequence());
3583 tmpSeq.setDescription(vamsasSeq.getDescription());
3584 tmpSeq.setStart(jseq.getStart());
3585 tmpSeq.setEnd(jseq.getEnd());
3586 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3587 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3588 tmpseqs.add(tmpSeq);
3592 if (safeBoolean(jseq.isViewreference()))
3594 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3597 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3599 if (hiddenSeqs == null)
3601 hiddenSeqs = new ArrayList<>();
3604 hiddenSeqs.add(tmpSeq);
3609 // Create the alignment object from the sequence set
3610 // ///////////////////////////////
3611 SequenceI[] orderedSeqs = tmpseqs
3612 .toArray(new SequenceI[tmpseqs.size()]);
3614 AlignmentI al = null;
3615 // so we must create or recover the dataset alignment before going further
3616 // ///////////////////////////////
3617 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3619 // older jalview projects do not have a dataset - so creat alignment and
3621 al = new Alignment(orderedSeqs);
3622 al.setDataset(null);
3626 boolean isdsal = jalviewModel.getViewport().isEmpty();
3629 // we are importing a dataset record, so
3630 // recover reference to an alignment already materialsed as dataset
3631 al = getDatasetFor(vamsasSet.getDatasetId());
3635 // materialse the alignment
3636 al = new Alignment(orderedSeqs);
3640 addDatasetRef(vamsasSet.getDatasetId(), al);
3643 // finally, verify all data in vamsasSet is actually present in al
3644 // passing on flag indicating if it is actually a stored dataset
3645 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3648 if (referenceseqForView != null)
3650 al.setSeqrep(referenceseqForView);
3652 // / Add the alignment properties
3653 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3655 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3657 al.setProperty(ssp.getKey(), ssp.getValue());
3660 // ///////////////////////////////
3662 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3665 // load sequence features, database references and any associated PDB
3666 // structures for the alignment
3668 // prior to 2.10, this part would only be executed the first time a
3669 // sequence was encountered, but not afterwards.
3670 // now, for 2.10 projects, this is also done if the xml doc includes
3671 // dataset sequences not actually present in any particular view.
3673 for (int i = 0; i < vamsasSeqs.size(); i++)
3675 JSeq jseq = jseqs.get(i);
3676 if (jseq.getFeatures().size() > 0)
3678 List<Feature> features = jseq.getFeatures();
3679 for (int f = 0; f < features.size(); f++)
3681 Feature feat = features.get(f);
3682 SequenceFeature sf = new SequenceFeature(feat.getType(),
3683 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3684 safeFloat(feat.getScore()), feat.getFeatureGroup());
3685 sf.setStatus(feat.getStatus());
3688 * load any feature attributes - include map-valued attributes
3690 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3691 for (int od = 0; od < feat.getOtherData().size(); od++)
3693 OtherData keyValue = feat.getOtherData().get(od);
3694 String attributeName = keyValue.getKey();
3695 String attributeValue = keyValue.getValue();
3696 if (attributeName.startsWith("LINK"))
3698 sf.addLink(attributeValue);
3702 String subAttribute = keyValue.getKey2();
3703 if (subAttribute == null)
3705 // simple string-valued attribute
3706 sf.setValue(attributeName, attributeValue);
3710 // attribute 'key' has sub-attribute 'key2'
3711 if (!mapAttributes.containsKey(attributeName))
3713 mapAttributes.put(attributeName, new HashMap<>());
3715 mapAttributes.get(attributeName).put(subAttribute,
3720 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3723 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3726 // adds feature to datasequence's feature set (since Jalview 2.10)
3727 al.getSequenceAt(i).addSequenceFeature(sf);
3730 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3732 // adds dbrefs to datasequence's set (since Jalview 2.10)
3734 al.getSequenceAt(i).getDatasetSequence() == null
3735 ? al.getSequenceAt(i)
3736 : al.getSequenceAt(i).getDatasetSequence(),
3739 if (jseq.getPdbids().size() > 0)
3741 List<Pdbids> ids = jseq.getPdbids();
3742 for (int p = 0; p < ids.size(); p++)
3744 Pdbids pdbid = ids.get(p);
3745 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3746 entry.setId(pdbid.getId());
3747 if (pdbid.getType() != null)
3749 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3751 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3755 entry.setType(PDBEntry.Type.FILE);
3758 // jprovider is null when executing 'New View'
3759 if (pdbid.getFile() != null && jprovider != null)
3761 if (!pdbloaded.containsKey(pdbid.getFile()))
3763 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3768 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3772 if (pdbid.getPdbentryItem() != null)
3774 for (PdbentryItem item : pdbid.getPdbentryItem())
3776 for (Property pr : item.getProperty())
3778 entry.setProperty(pr.getName(), pr.getValue());
3783 for (Property prop : pdbid.getProperty())
3785 entry.setProperty(prop.getName(), prop.getValue());
3787 StructureSelectionManager
3788 .getStructureSelectionManager(Desktop.instance)
3789 .registerPDBEntry(entry);
3790 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3791 if (al.getSequenceAt(i).getDatasetSequence() != null)
3793 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3797 al.getSequenceAt(i).addPDBId(entry);
3802 } // end !multipleview
3804 // ///////////////////////////////
3805 // LOAD SEQUENCE MAPPINGS
3807 if (vamsasSet.getAlcodonFrame().size() > 0)
3809 // TODO Potentially this should only be done once for all views of an
3811 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3812 for (int i = 0; i < alc.size(); i++)
3814 AlignedCodonFrame cf = new AlignedCodonFrame();
3815 if (alc.get(i).getAlcodMap().size() > 0)
3817 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3818 for (int m = 0; m < maps.size(); m++)
3820 AlcodMap map = maps.get(m);
3821 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3823 jalview.datamodel.Mapping mapping = null;
3824 // attach to dna sequence reference.
3825 if (map.getMapping() != null)
3827 mapping = addMapping(map.getMapping());
3828 if (dnaseq != null && mapping.getTo() != null)
3830 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3836 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3840 al.addCodonFrame(cf);
3845 // ////////////////////////////////
3847 List<JvAnnotRow> autoAlan = new ArrayList<>();
3850 * store any annotations which forward reference a group's ID
3852 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3854 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3856 List<Annotation> an = vamsasSet.getAnnotation();
3858 for (int i = 0; i < an.size(); i++)
3860 Annotation annotation = an.get(i);
3863 * test if annotation is automatically calculated for this view only
3865 boolean autoForView = false;
3866 if (annotation.getLabel().equals("Quality")
3867 || annotation.getLabel().equals("Conservation")
3868 || annotation.getLabel().equals("Consensus"))
3870 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3872 // JAXB has no has() test; schema defaults value to false
3873 // if (!annotation.hasAutoCalculated())
3875 // annotation.setAutoCalculated(true);
3878 if (autoForView || annotation.isAutoCalculated())
3880 // remove ID - we don't recover annotation from other views for
3881 // view-specific annotation
3882 annotation.setId(null);
3885 // set visibility for other annotation in this view
3886 String annotationId = annotation.getId();
3887 if (annotationId != null && annotationIds.containsKey(annotationId))
3889 AlignmentAnnotation jda = annotationIds.get(annotationId);
3890 // in principle Visible should always be true for annotation displayed
3891 // in multiple views
3892 if (annotation.isVisible() != null)
3894 jda.visible = annotation.isVisible();
3897 al.addAnnotation(jda);
3901 // Construct new annotation from model.
3902 List<AnnotationElement> ae = annotation.getAnnotationElement();
3903 jalview.datamodel.Annotation[] anot = null;
3904 java.awt.Color firstColour = null;
3906 if (!annotation.isScoreOnly())
3908 anot = new jalview.datamodel.Annotation[al.getWidth()];
3909 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3911 AnnotationElement annElement = ae.get(aa);
3912 anpos = annElement.getPosition();
3914 if (anpos >= anot.length)
3919 float value = safeFloat(annElement.getValue());
3920 anot[anpos] = new jalview.datamodel.Annotation(
3921 annElement.getDisplayCharacter(),
3922 annElement.getDescription(),
3923 (annElement.getSecondaryStructure() == null
3924 || annElement.getSecondaryStructure()
3928 .getSecondaryStructure()
3931 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3932 if (firstColour == null)
3934 firstColour = anot[anpos].colour;
3938 jalview.datamodel.AlignmentAnnotation jaa = null;
3940 if (annotation.isGraph())
3942 float llim = 0, hlim = 0;
3943 // if (autoForView || an[i].isAutoCalculated()) {
3946 jaa = new jalview.datamodel.AlignmentAnnotation(
3947 annotation.getLabel(), annotation.getDescription(), anot,
3948 llim, hlim, safeInt(annotation.getGraphType()));
3950 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3951 jaa._linecolour = firstColour;
3952 if (annotation.getThresholdLine() != null)
3954 jaa.setThreshold(new jalview.datamodel.GraphLine(
3955 safeFloat(annotation.getThresholdLine().getValue()),
3956 annotation.getThresholdLine().getLabel(),
3957 new java.awt.Color(safeInt(
3958 annotation.getThresholdLine().getColour()))));
3960 if (autoForView || annotation.isAutoCalculated())
3962 // Hardwire the symbol display line to ensure that labels for
3963 // histograms are displayed
3969 jaa = new jalview.datamodel.AlignmentAnnotation(
3970 annotation.getLabel(), annotation.getDescription(), anot);
3971 jaa._linecolour = firstColour;
3973 // register new annotation
3974 if (annotation.getId() != null)
3976 annotationIds.put(annotation.getId(), jaa);
3977 jaa.annotationId = annotation.getId();
3979 // recover sequence association
3980 String sequenceRef = annotation.getSequenceRef();
3981 if (sequenceRef != null)
3983 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3984 SequenceI sequence = seqRefIds.get(sequenceRef);
3985 if (sequence == null)
3987 // in pre-2.9 projects sequence ref is to sequence name
3988 sequence = al.findName(sequenceRef);
3990 if (sequence != null)
3992 jaa.createSequenceMapping(sequence, 1, true);
3993 sequence.addAlignmentAnnotation(jaa);
3996 // and make a note of any group association
3997 if (annotation.getGroupRef() != null
3998 && annotation.getGroupRef().length() > 0)
4000 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4001 .get(annotation.getGroupRef());
4004 aal = new ArrayList<>();
4005 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4010 if (annotation.getScore() != null)
4012 jaa.setScore(annotation.getScore().doubleValue());
4014 if (annotation.isVisible() != null)
4016 jaa.visible = annotation.isVisible().booleanValue();
4019 if (annotation.isCentreColLabels() != null)
4021 jaa.centreColLabels = annotation.isCentreColLabels()
4025 if (annotation.isScaleColLabels() != null)
4027 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4029 if (annotation.isAutoCalculated())
4031 // newer files have an 'autoCalculated' flag and store calculation
4032 // state in viewport properties
4033 jaa.autoCalculated = true; // means annotation will be marked for
4034 // update at end of load.
4036 if (annotation.getGraphHeight() != null)
4038 jaa.graphHeight = annotation.getGraphHeight().intValue();
4040 jaa.belowAlignment = annotation.isBelowAlignment();
4041 jaa.setCalcId(annotation.getCalcId());
4042 if (annotation.getProperty().size() > 0)
4044 for (jalview.xml.binding.jalview.Property prop : annotation
4047 jaa.setProperty(prop.getName(), prop.getValue());
4050 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4052 if (annotation.getContactmatrix() != null
4053 && annotation.getContactmatrix().size() > 0)
4055 for (MatrixType xmlmat : annotation.getContactmatrix())
4057 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4059 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4061 Console.error("Can't handle non square PAE Matrices");
4065 float[][] elements = ContactMatrix
4066 .fromFloatStringToContacts(xmlmat.getElements(),
4067 xmlmat.getCols().intValue(),
4068 xmlmat.getRows().intValue());
4069 jalview.util.MapList mapping = null;
4070 if (xmlmat.getMapping() != null)
4072 MapListType m = xmlmat.getMapping();
4073 // Mapping m = dr.getMapping();
4074 int fr[] = new int[m.getMapListFrom().size() * 2];
4075 Iterator<MapListFrom> from = m.getMapListFrom()
4076 .iterator();// enumerateMapListFrom();
4077 for (int _i = 0; from.hasNext(); _i += 2)
4079 MapListFrom mf = from.next();
4080 fr[_i] = mf.getStart();
4081 fr[_i + 1] = mf.getEnd();
4083 int fto[] = new int[m.getMapListTo().size() * 2];
4084 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4085 for (int _i = 0; to.hasNext(); _i += 2)
4087 MapListTo mf = to.next();
4088 fto[_i] = mf.getStart();
4089 fto[_i + 1] = mf.getEnd();
4092 mapping = new jalview.util.MapList(fr, fto,
4093 m.getMapFromUnit().intValue(),
4094 m.getMapToUnit().intValue());
4096 List<BitSet> newgroups = new ArrayList<BitSet>();
4097 if (xmlmat.getGroups().size() > 0)
4099 for (String sgroup : xmlmat.getGroups())
4101 newgroups.add(deStringifyBitset(sgroup));
4104 String nwk = xmlmat.getNewick().size() > 0
4105 ? xmlmat.getNewick().get(0)
4107 if (xmlmat.getNewick().size() > 1)
4110 "Ignoring additional clusterings for contact matrix");
4112 String treeMethod = xmlmat.getTreeMethod();
4113 double thresh = xmlmat.getCutHeight() != null
4114 ? xmlmat.getCutHeight()
4116 GroupSet grpset = new GroupSet();
4117 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4118 PAEContactMatrix newpae = new PAEContactMatrix(
4119 jaa.sequenceRef, mapping, elements, grpset);
4120 jaa.sequenceRef.addContactListFor(jaa, newpae);
4125 Console.error("Ignoring CONTACT_MAP annotation with type "
4126 + xmlmat.getType());
4132 if (jaa.autoCalculated)
4134 autoAlan.add(new JvAnnotRow(i, jaa));
4137 // if (!autoForView)
4139 // add autocalculated group annotation and any user created annotation
4141 al.addAnnotation(jaa);
4145 // ///////////////////////
4147 // Create alignment markup and styles for this view
4148 if (jalviewModel.getJGroup().size() > 0)
4150 List<JGroup> groups = jalviewModel.getJGroup();
4151 boolean addAnnotSchemeGroup = false;
4152 for (int i = 0; i < groups.size(); i++)
4154 JGroup jGroup = groups.get(i);
4155 ColourSchemeI cs = null;
4156 if (jGroup.getColour() != null)
4158 if (jGroup.getColour().startsWith("ucs"))
4160 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4162 else if (jGroup.getColour().equals("AnnotationColourGradient")
4163 && jGroup.getAnnotationColours() != null)
4165 addAnnotSchemeGroup = true;
4169 cs = ColourSchemeProperty.getColourScheme(null, al,
4170 jGroup.getColour());
4173 int pidThreshold = safeInt(jGroup.getPidThreshold());
4175 Vector<SequenceI> seqs = new Vector<>();
4177 for (int s = 0; s < jGroup.getSeq().size(); s++)
4179 String seqId = jGroup.getSeq().get(s);
4180 SequenceI ts = seqRefIds.get(seqId);
4184 seqs.addElement(ts);
4188 if (seqs.size() < 1)
4193 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4194 safeBoolean(jGroup.isDisplayBoxes()),
4195 safeBoolean(jGroup.isDisplayText()),
4196 safeBoolean(jGroup.isColourText()),
4197 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4198 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4199 sg.getGroupColourScheme()
4200 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4201 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4203 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4204 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4205 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4206 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4207 // attributes with a default in the schema are never null
4208 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4209 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4210 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4211 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4212 if (jGroup.getConsThreshold() != null
4213 && jGroup.getConsThreshold().intValue() != 0)
4215 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4218 c.verdict(false, 25);
4219 sg.cs.setConservation(c);
4222 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4224 // re-instate unique group/annotation row reference
4225 List<AlignmentAnnotation> jaal = groupAnnotRefs
4226 .get(jGroup.getId());
4229 for (AlignmentAnnotation jaa : jaal)
4232 if (jaa.autoCalculated)
4234 // match up and try to set group autocalc alignment row for this
4236 if (jaa.label.startsWith("Consensus for "))
4238 sg.setConsensus(jaa);
4240 // match up and try to set group autocalc alignment row for this
4242 if (jaa.label.startsWith("Conservation for "))
4244 sg.setConservationRow(jaa);
4251 if (addAnnotSchemeGroup)
4253 // reconstruct the annotation colourscheme
4255 constructAnnotationColour(jGroup.getAnnotationColours(),
4256 null, al, jalviewModel, false));
4262 // only dataset in this model, so just return.
4265 // ///////////////////////////////
4268 AlignFrame af = null;
4269 AlignViewport av = null;
4270 // now check to see if we really need to create a new viewport.
4271 if (multipleView && viewportsAdded.size() == 0)
4273 // We recovered an alignment for which a viewport already exists.
4274 // TODO: fix up any settings necessary for overlaying stored state onto
4275 // state recovered from another document. (may not be necessary).
4276 // we may need a binding from a viewport in memory to one recovered from
4278 // and then recover its containing af to allow the settings to be applied.
4279 // TODO: fix for vamsas demo
4281 "About to recover a viewport for existing alignment: Sequence set ID is "
4283 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4284 if (seqsetobj != null)
4286 if (seqsetobj instanceof String)
4288 uniqueSeqSetId = (String) seqsetobj;
4290 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4296 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4302 * indicate that annotation colours are applied across all groups (pre
4303 * Jalview 2.8.1 behaviour)
4305 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4306 jalviewModel.getVersion());
4308 AlignmentPanel ap = null;
4309 boolean isnewview = true;
4312 // Check to see if this alignment already has a view id == viewId
4313 jalview.gui.AlignmentPanel views[] = Desktop
4314 .getAlignmentPanels(uniqueSeqSetId);
4315 if (views != null && views.length > 0)
4317 for (int v = 0; v < views.length; v++)
4319 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4321 // recover the existing alignpanel, alignframe, viewport
4322 af = views[v].alignFrame;
4325 // TODO: could even skip resetting view settings if we don't want to
4326 // change the local settings from other jalview processes
4335 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4336 uniqueSeqSetId, viewId, autoAlan);
4337 av = af.getViewport();
4342 * Load any trees, PDB structures and viewers, Overview
4344 * Not done if flag is false (when this method is used for New View)
4346 if (loadTreesAndStructures)
4348 loadTrees(jalviewModel, view, af, av, ap);
4349 loadPCAViewers(jalviewModel, ap);
4350 loadPDBStructures(jprovider, jseqs, af, ap);
4351 loadRnaViewers(jprovider, jseqs, ap);
4352 loadOverview(view, jalviewModel.getVersion(), af);
4354 // and finally return.
4359 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4360 * and geometry as saved
4365 protected void loadOverview(Viewport view, String version, AlignFrame af)
4367 if (!isVersionStringLaterThan("2.11.3", version)
4368 && view.getOverview() == null)
4373 * first close any Overview that was opened automatically
4374 * (if so configured in Preferences) so that the view is
4375 * restored in the same state as saved
4377 af.alignPanel.closeOverviewPanel();
4379 Overview overview = view.getOverview();
4380 if (overview != null)
4382 OverviewPanel overviewPanel = af
4383 .openOverviewPanel(overview.isShowHidden());
4384 overviewPanel.setTitle(overview.getTitle());
4385 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4386 overview.getWidth(), overview.getHeight());
4387 Color gap = new Color(overview.getGapColour());
4388 Color residue = new Color(overview.getResidueColour());
4389 Color hidden = new Color(overview.getHiddenColour());
4390 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4395 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4396 * panel is restored from separate jar entries, two (gapped and trimmed) per
4397 * sequence and secondary structure.
4399 * Currently each viewer shows just one sequence and structure (gapped and
4400 * trimmed), however this method is designed to support multiple sequences or
4401 * structures in viewers if wanted in future.
4407 private void loadRnaViewers(jarInputStreamProvider jprovider,
4408 List<JSeq> jseqs, AlignmentPanel ap)
4411 * scan the sequences for references to viewers; create each one the first
4412 * time it is referenced, add Rna models to existing viewers
4414 for (JSeq jseq : jseqs)
4416 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4418 RnaViewer viewer = jseq.getRnaViewer().get(i);
4419 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4422 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4424 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4425 SequenceI seq = seqRefIds.get(jseq.getId());
4426 AlignmentAnnotation ann = this.annotationIds
4427 .get(ss.getAnnotationId());
4430 * add the structure to the Varna display (with session state copied
4431 * from the jar to a temporary file)
4433 boolean gapped = safeBoolean(ss.isGapped());
4434 String rnaTitle = ss.getTitle();
4435 String sessionState = ss.getViewerState();
4436 String tempStateFile = copyJarEntry(jprovider, sessionState,
4438 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4439 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4441 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4447 * Locate and return an already instantiated matching AppVarna, or create one
4451 * @param viewIdSuffix
4455 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4456 String viewIdSuffix, AlignmentPanel ap)
4459 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4460 * if load is repeated
4462 String postLoadId = viewer.getViewId() + viewIdSuffix;
4463 for (JInternalFrame frame : getAllFrames())
4465 if (frame instanceof AppVarna)
4467 AppVarna varna = (AppVarna) frame;
4468 if (postLoadId.equals(varna.getViewId()))
4470 // this viewer is already instantiated
4471 // could in future here add ap as another 'parent' of the
4472 // AppVarna window; currently just 1-to-many
4479 * viewer not found - make it
4481 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4482 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4483 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4484 safeInt(viewer.getDividerLocation()));
4485 AppVarna varna = new AppVarna(model, ap);
4491 * Load any saved trees
4499 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4500 AlignViewport av, AlignmentPanel ap)
4502 // TODO result of automated refactoring - are all these parameters needed?
4505 for (int t = 0; t < jm.getTree().size(); t++)
4508 Tree tree = jm.getTree().get(t);
4510 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4513 if (tree.isColumnWise())
4515 AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds
4516 .get(tree.getColumnReference());
4520 "Null alignment annotation when restoring columnwise tree");
4522 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4523 tree.getTitle(), safeInt(tree.getWidth()),
4524 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4525 safeInt(tree.getYpos()));
4530 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4531 tree.getTitle(), safeInt(tree.getWidth()),
4532 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4533 safeInt(tree.getYpos()));
4535 if (tree.getId() != null)
4537 // perhaps bind the tree id to something ?
4542 // update local tree attributes ?
4543 // TODO: should check if tp has been manipulated by user - if so its
4544 // settings shouldn't be modified
4545 tp.setTitle(tree.getTitle());
4546 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4547 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4548 safeInt(tree.getHeight())));
4549 tp.setViewport(av); // af.viewport;
4550 // TODO: verify 'associate with all views' works still
4551 tp.getTreeCanvas().setViewport(av); // af.viewport;
4552 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4554 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4558 "There was a problem recovering stored Newick tree: \n"
4559 + tree.getNewick());
4563 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4564 tp.fitToWindow_actionPerformed(null);
4566 if (tree.getFontName() != null)
4569 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4570 safeInt(tree.getFontSize())));
4575 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4576 safeInt(view.getFontSize())));
4579 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4580 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4581 tp.showDistances(safeBoolean(tree.isShowDistances()));
4583 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4585 if (safeBoolean(tree.isCurrentTree()))
4587 af.getViewport().setCurrentTree(tp.getTree());
4591 } catch (Exception ex)
4593 ex.printStackTrace();
4598 * Load and link any saved structure viewers.
4605 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4606 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4609 * Run through all PDB ids on the alignment, and collect mappings between
4610 * distinct view ids and all sequences referring to that view.
4612 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4614 for (int i = 0; i < jseqs.size(); i++)
4616 JSeq jseq = jseqs.get(i);
4617 if (jseq.getPdbids().size() > 0)
4619 List<Pdbids> ids = jseq.getPdbids();
4620 for (int p = 0; p < ids.size(); p++)
4622 Pdbids pdbid = ids.get(p);
4623 final int structureStateCount = pdbid.getStructureState().size();
4624 for (int s = 0; s < structureStateCount; s++)
4626 // check to see if we haven't already created this structure view
4627 final StructureState structureState = pdbid.getStructureState()
4629 String sviewid = (structureState.getViewId() == null) ? null
4630 : structureState.getViewId() + uniqueSetSuffix;
4631 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4632 // Originally : pdbid.getFile()
4633 // : TODO: verify external PDB file recovery still works in normal
4634 // jalview project load
4636 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4637 jpdb.setId(pdbid.getId());
4639 int x = safeInt(structureState.getXpos());
4640 int y = safeInt(structureState.getYpos());
4641 int width = safeInt(structureState.getWidth());
4642 int height = safeInt(structureState.getHeight());
4644 // Probably don't need to do this anymore...
4645 // Desktop.desktop.getComponentAt(x, y);
4646 // TODO: NOW: check that this recovers the PDB file correctly.
4647 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4649 jalview.datamodel.SequenceI seq = seqRefIds
4650 .get(jseq.getId() + "");
4651 if (sviewid == null)
4653 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4656 if (!structureViewers.containsKey(sviewid))
4658 String viewerType = structureState.getType();
4659 if (viewerType == null) // pre Jalview 2.9
4661 viewerType = ViewerType.JMOL.toString();
4663 structureViewers.put(sviewid,
4664 new StructureViewerModel(x, y, width, height, false,
4665 false, true, structureState.getViewId(),
4667 // Legacy pre-2.7 conversion JAL-823 :
4668 // do not assume any view has to be linked for colour by
4672 // assemble String[] { pdb files }, String[] { id for each
4673 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4674 // seqs_file 2}, boolean[] {
4675 // linkAlignPanel,superposeWithAlignpanel}} from hash
4676 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4677 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4678 || structureState.isAlignwithAlignPanel());
4681 * Default colour by linked panel to false if not specified (e.g.
4682 * for pre-2.7 projects)
4684 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4685 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4686 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4689 * Default colour by viewer to true if not specified (e.g. for
4692 boolean colourByViewer = jmoldat.isColourByViewer();
4693 colourByViewer &= structureState.isColourByJmol();
4694 jmoldat.setColourByViewer(colourByViewer);
4696 if (jmoldat.getStateData().length() < structureState.getValue()
4697 /*Content()*/.length())
4699 jmoldat.setStateData(structureState.getValue());// Content());
4701 if (pdbid.getFile() != null)
4703 File mapkey = new File(pdbid.getFile());
4704 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4705 if (seqstrmaps == null)
4707 jmoldat.getFileData().put(mapkey,
4708 seqstrmaps = jmoldat.new StructureData(pdbFile,
4711 if (!seqstrmaps.getSeqList().contains(seq))
4713 seqstrmaps.getSeqList().add(seq);
4719 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");
4720 Console.warn(errorMessage);
4726 // Instantiate the associated structure views
4727 for (Entry<String, StructureViewerModel> entry : structureViewers
4732 createOrLinkStructureViewer(entry, af, ap, jprovider);
4733 } catch (Exception e)
4736 "Error loading structure viewer: " + e.getMessage());
4737 // failed - try the next one
4749 protected void createOrLinkStructureViewer(
4750 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4751 AlignmentPanel ap, jarInputStreamProvider jprovider)
4753 final StructureViewerModel stateData = viewerData.getValue();
4756 * Search for any viewer windows already open from other alignment views
4757 * that exactly match the stored structure state
4759 StructureViewerBase comp = findMatchingViewer(viewerData);
4763 linkStructureViewer(ap, comp, stateData);
4767 String type = stateData.getType();
4770 ViewerType viewerType = ViewerType.valueOf(type);
4771 createStructureViewer(viewerType, viewerData, af, jprovider);
4772 } catch (IllegalArgumentException | NullPointerException e)
4774 // TODO JAL-3619 show error dialog / offer an alternative viewer
4775 Console.error("Invalid structure viewer type: " + type);
4780 * Generates a name for the entry in the project jar file to hold state
4781 * information for a structure viewer
4786 protected String getViewerJarEntryName(String viewId)
4788 return VIEWER_PREFIX + viewId;
4792 * Returns any open frame that matches given structure viewer data. The match
4793 * is based on the unique viewId, or (for older project versions) the frame's
4799 protected StructureViewerBase findMatchingViewer(
4800 Entry<String, StructureViewerModel> viewerData)
4802 final String sviewid = viewerData.getKey();
4803 final StructureViewerModel svattrib = viewerData.getValue();
4804 StructureViewerBase comp = null;
4805 JInternalFrame[] frames = getAllFrames();
4806 for (JInternalFrame frame : frames)
4808 if (frame instanceof StructureViewerBase)
4811 * Post jalview 2.4 schema includes structure view id
4813 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4816 comp = (StructureViewerBase) frame;
4817 break; // break added in 2.9
4820 * Otherwise test for matching position and size of viewer frame
4822 else if (frame.getX() == svattrib.getX()
4823 && frame.getY() == svattrib.getY()
4824 && frame.getHeight() == svattrib.getHeight()
4825 && frame.getWidth() == svattrib.getWidth())
4827 comp = (StructureViewerBase) frame;
4828 // no break in faint hope of an exact match on viewId
4836 * Link an AlignmentPanel to an existing structure viewer.
4841 * @param useinViewerSuperpos
4842 * @param usetoColourbyseq
4843 * @param viewerColouring
4845 protected void linkStructureViewer(AlignmentPanel ap,
4846 StructureViewerBase viewer, StructureViewerModel stateData)
4848 // NOTE: if the jalview project is part of a shared session then
4849 // view synchronization should/could be done here.
4851 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4852 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4853 final boolean viewerColouring = stateData.isColourByViewer();
4854 Map<File, StructureData> oldFiles = stateData.getFileData();
4857 * Add mapping for sequences in this view to an already open viewer
4859 final AAStructureBindingModel binding = viewer.getBinding();
4860 for (File id : oldFiles.keySet())
4862 // add this and any other pdb files that should be present in the
4864 StructureData filedat = oldFiles.get(id);
4865 String pdbFile = filedat.getFilePath();
4866 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4867 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4869 binding.addSequenceForStructFile(pdbFile, seq);
4871 // and add the AlignmentPanel's reference to the view panel
4872 viewer.addAlignmentPanel(ap);
4873 if (useinViewerSuperpos)
4875 viewer.useAlignmentPanelForSuperposition(ap);
4879 viewer.excludeAlignmentPanelForSuperposition(ap);
4881 if (usetoColourbyseq)
4883 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4887 viewer.excludeAlignmentPanelForColourbyseq(ap);
4892 * Get all frames within the Desktop.
4896 protected JInternalFrame[] getAllFrames()
4898 JInternalFrame[] frames = null;
4899 // TODO is this necessary - is it safe - risk of hanging?
4904 frames = Desktop.desktop.getAllFrames();
4905 } catch (ArrayIndexOutOfBoundsException e)
4907 // occasional No such child exceptions are thrown here...
4911 } catch (InterruptedException f)
4915 } while (frames == null);
4920 * Answers true if 'version' is equal to or later than 'supported', where each
4921 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4922 * changes. Development and test values for 'version' are leniently treated
4926 * - minimum version we are comparing against
4928 * - version of data being processsed
4929 * @return true if version is equal to or later than supported
4931 public static boolean isVersionStringLaterThan(String supported,
4934 if (supported == null || version == null
4935 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4936 || version.equalsIgnoreCase("Test")
4937 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4939 System.err.println("Assuming project file with "
4940 + (version == null ? "null" : version)
4941 + " is compatible with Jalview version " + supported);
4946 return StringUtils.compareVersions(version, supported, "b") >= 0;
4950 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4952 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4954 if (newStructureViewers != null)
4956 sview.getBinding().setFinishedLoadingFromArchive(false);
4957 newStructureViewers.add(sview);
4961 protected void setLoadingFinishedForNewStructureViewers()
4963 if (newStructureViewers != null)
4965 for (JalviewStructureDisplayI sview : newStructureViewers)
4967 sview.getBinding().setFinishedLoadingFromArchive(true);
4969 newStructureViewers.clear();
4970 newStructureViewers = null;
4974 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4975 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4976 Viewport view, String uniqueSeqSetId, String viewId,
4977 List<JvAnnotRow> autoAlan)
4979 AlignFrame af = null;
4980 af = new AlignFrame(al, safeInt(view.getWidth()),
4981 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4985 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4986 // System.out.println("Jalview2XML AF " + e);
4987 // super.processKeyEvent(e);
4994 af.setFileName(file, FileFormat.Jalview);
4996 final AlignViewport viewport = af.getViewport();
4997 for (int i = 0; i < JSEQ.size(); i++)
4999 int colour = safeInt(JSEQ.get(i).getColour());
5000 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5006 viewport.setColourByReferenceSeq(true);
5007 viewport.setDisplayReferenceSeq(true);
5010 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5012 if (view.getSequenceSetId() != null)
5014 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5016 viewport.setSequenceSetId(uniqueSeqSetId);
5019 // propagate shared settings to this new view
5020 viewport.setHistoryList(av.getHistoryList());
5021 viewport.setRedoList(av.getRedoList());
5025 viewportsAdded.put(uniqueSeqSetId, viewport);
5027 // TODO: check if this method can be called repeatedly without
5028 // side-effects if alignpanel already registered.
5029 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5031 // apply Hidden regions to view.
5032 if (hiddenSeqs != null)
5034 for (int s = 0; s < JSEQ.size(); s++)
5036 SequenceGroup hidden = new SequenceGroup();
5037 boolean isRepresentative = false;
5038 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5040 isRepresentative = true;
5041 SequenceI sequenceToHide = al
5042 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5043 hidden.addSequence(sequenceToHide, false);
5044 // remove from hiddenSeqs list so we don't try to hide it twice
5045 hiddenSeqs.remove(sequenceToHide);
5047 if (isRepresentative)
5049 SequenceI representativeSequence = al.getSequenceAt(s);
5050 hidden.addSequence(representativeSequence, false);
5051 viewport.hideRepSequences(representativeSequence, hidden);
5055 SequenceI[] hseqs = hiddenSeqs
5056 .toArray(new SequenceI[hiddenSeqs.size()]);
5057 viewport.hideSequence(hseqs);
5060 // recover view properties and display parameters
5062 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5063 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5064 final int pidThreshold = safeInt(view.getPidThreshold());
5065 viewport.setThreshold(pidThreshold);
5067 viewport.setColourText(safeBoolean(view.isShowColourText()));
5069 viewport.setConservationSelected(
5070 safeBoolean(view.isConservationSelected()));
5071 viewport.setIncrement(safeInt(view.getConsThreshold()));
5072 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5073 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5075 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5076 safeInt(view.getFontSize())),
5077 (view.getCharWidth() != null) ? false : true);
5078 if (view.getCharWidth() != null)
5080 viewport.setCharWidth(view.getCharWidth());
5081 viewport.setCharHeight(view.getCharHeight());
5083 ViewStyleI vs = viewport.getViewStyle();
5084 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5085 viewport.setViewStyle(vs);
5086 // TODO: allow custom charWidth/Heights to be restored by updating them
5087 // after setting font - which means set above to false
5088 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5089 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5090 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5092 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5094 viewport.setShowText(safeBoolean(view.isShowText()));
5096 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5097 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5098 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5099 viewport.setShowUnconserved(view.isShowUnconserved());
5100 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5102 if (view.getViewName() != null)
5104 viewport.setViewName(view.getViewName());
5105 af.setInitialTabVisible();
5107 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5108 safeInt(view.getWidth()), safeInt(view.getHeight()));
5109 // startSeq set in af.alignPanel.updateLayout below
5110 af.alignPanel.updateLayout();
5111 ColourSchemeI cs = null;
5112 // apply colourschemes
5113 if (view.getBgColour() != null)
5115 if (view.getBgColour().startsWith("ucs"))
5117 cs = getUserColourScheme(jm, view.getBgColour());
5119 else if (view.getBgColour().startsWith("Annotation"))
5121 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5122 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5129 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5130 view.getBgColour());
5135 * turn off 'alignment colour applies to all groups'
5136 * while restoring global colour scheme
5138 viewport.setColourAppliesToAllGroups(false);
5139 viewport.setGlobalColourScheme(cs);
5140 viewport.getResidueShading().setThreshold(pidThreshold,
5141 view.isIgnoreGapsinConsensus());
5142 viewport.getResidueShading()
5143 .setConsensus(viewport.getSequenceConsensusHash());
5144 if (safeBoolean(view.isConservationSelected()) && cs != null)
5146 viewport.getResidueShading()
5147 .setConservationInc(safeInt(view.getConsThreshold()));
5149 af.changeColour(cs);
5150 viewport.setColourAppliesToAllGroups(true);
5152 viewport.setShowSequenceFeatures(
5153 safeBoolean(view.isShowSequenceFeatures()));
5155 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5156 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5157 viewport.setFollowHighlight(view.isFollowHighlight());
5158 viewport.followSelection = view.isFollowSelection();
5159 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5160 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5161 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5162 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5163 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5164 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5165 viewport.setShowGroupConservation(view.isShowGroupConservation());
5166 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5167 viewport.setShowComplementFeaturesOnTop(
5168 view.isShowComplementFeaturesOnTop());
5170 // recover feature settings
5171 if (jm.getFeatureSettings() != null)
5173 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5174 .getFeatureRenderer();
5175 FeaturesDisplayed fdi;
5176 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5177 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5179 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5180 Map<String, Float> featureOrder = new Hashtable<>();
5182 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5185 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5186 String featureType = setting.getType();
5189 * restore feature filters (if any)
5191 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5193 if (filters != null)
5195 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5197 if (!filter.isEmpty())
5199 fr.setFeatureFilter(featureType, filter);
5204 * restore feature colour scheme
5206 Color maxColour = new Color(setting.getColour());
5207 if (setting.getMincolour() != null)
5210 * minColour is always set unless a simple colour
5211 * (including for colour by label though it doesn't use it)
5213 Color minColour = new Color(setting.getMincolour().intValue());
5214 Color noValueColour = minColour;
5215 NoValueColour noColour = setting.getNoValueColour();
5216 if (noColour == NoValueColour.NONE)
5218 noValueColour = null;
5220 else if (noColour == NoValueColour.MAX)
5222 noValueColour = maxColour;
5224 float min = safeFloat(safeFloat(setting.getMin()));
5225 float max = setting.getMax() == null ? 1f
5226 : setting.getMax().floatValue();
5227 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5228 maxColour, noValueColour, min, max);
5229 if (setting.getAttributeName().size() > 0)
5231 gc.setAttributeName(setting.getAttributeName().toArray(
5232 new String[setting.getAttributeName().size()]));
5234 if (setting.getThreshold() != null)
5236 gc.setThreshold(setting.getThreshold().floatValue());
5237 int threshstate = safeInt(setting.getThreshstate());
5238 // -1 = None, 0 = Below, 1 = Above threshold
5239 if (threshstate == 0)
5241 gc.setBelowThreshold(true);
5243 else if (threshstate == 1)
5245 gc.setAboveThreshold(true);
5248 gc.setAutoScaled(true); // default
5249 if (setting.isAutoScale() != null)
5251 gc.setAutoScaled(setting.isAutoScale());
5253 if (setting.isColourByLabel() != null)
5255 gc.setColourByLabel(setting.isColourByLabel());
5257 // and put in the feature colour table.
5258 featureColours.put(featureType, gc);
5262 featureColours.put(featureType, new FeatureColour(maxColour));
5264 renderOrder[fs] = featureType;
5265 if (setting.getOrder() != null)
5267 featureOrder.put(featureType, setting.getOrder().floatValue());
5271 featureOrder.put(featureType, Float.valueOf(
5272 fs / jm.getFeatureSettings().getSetting().size()));
5274 if (safeBoolean(setting.isDisplay()))
5276 fdi.setVisible(featureType);
5279 Map<String, Boolean> fgtable = new Hashtable<>();
5280 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5282 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5283 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5285 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5286 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5287 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5288 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5289 fgtable, featureColours, 1.0f, featureOrder);
5290 fr.transferSettings(frs);
5293 if (view.getHiddenColumns().size() > 0)
5295 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5297 final HiddenColumns hc = view.getHiddenColumns().get(c);
5298 viewport.hideColumns(safeInt(hc.getStart()),
5299 safeInt(hc.getEnd()) /* +1 */);
5302 if (view.getCalcIdParam() != null)
5304 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5306 if (calcIdParam != null)
5308 if (recoverCalcIdParam(calcIdParam, viewport))
5313 Console.warn("Couldn't recover parameters for "
5314 + calcIdParam.getCalcId());
5319 af.setMenusFromViewport(viewport);
5320 af.setTitle(view.getTitle());
5321 // TODO: we don't need to do this if the viewport is aready visible.
5323 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5324 * has a 'cdna/protein complement' view, in which case save it in order to
5325 * populate a SplitFrame once all views have been read in.
5327 String complementaryViewId = view.getComplementId();
5328 if (complementaryViewId == null)
5330 Desktop.addInternalFrame(af, view.getTitle(),
5331 safeInt(view.getWidth()), safeInt(view.getHeight()));
5332 // recompute any autoannotation
5333 af.alignPanel.updateAnnotation(false, true);
5334 reorderAutoannotation(af, al, autoAlan);
5335 af.alignPanel.alignmentChanged();
5339 splitFrameCandidates.put(view, af);
5346 * Reads saved data to restore Colour by Annotation settings
5348 * @param viewAnnColour
5352 * @param checkGroupAnnColour
5355 private ColourSchemeI constructAnnotationColour(
5356 AnnotationColourScheme viewAnnColour, AlignFrame af,
5357 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5359 boolean propagateAnnColour = false;
5360 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5362 if (checkGroupAnnColour && al.getGroups() != null
5363 && al.getGroups().size() > 0)
5365 // pre 2.8.1 behaviour
5366 // check to see if we should transfer annotation colours
5367 propagateAnnColour = true;
5368 for (SequenceGroup sg : al.getGroups())
5370 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5372 propagateAnnColour = false;
5378 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5380 String annotationId = viewAnnColour.getAnnotation();
5381 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5384 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5386 if (matchedAnnotation == null
5387 && annAlignment.getAlignmentAnnotation() != null)
5389 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5392 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5394 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5399 if (matchedAnnotation == null)
5401 System.err.println("Failed to match annotation colour scheme for "
5405 // belt-and-braces create a threshold line if the
5406 // colourscheme needs one but the matchedAnnotation doesn't have one
5407 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5408 && matchedAnnotation.getThreshold() == null)
5410 matchedAnnotation.setThreshold(
5411 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5412 "Threshold", Color.black));
5415 AnnotationColourGradient cs = null;
5416 if (viewAnnColour.getColourScheme().equals("None"))
5418 cs = new AnnotationColourGradient(matchedAnnotation,
5419 new Color(safeInt(viewAnnColour.getMinColour())),
5420 new Color(safeInt(viewAnnColour.getMaxColour())),
5421 safeInt(viewAnnColour.getAboveThreshold()));
5423 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5425 cs = new AnnotationColourGradient(matchedAnnotation,
5426 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5427 safeInt(viewAnnColour.getAboveThreshold()));
5431 cs = new AnnotationColourGradient(matchedAnnotation,
5432 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5433 viewAnnColour.getColourScheme()),
5434 safeInt(viewAnnColour.getAboveThreshold()));
5437 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5438 boolean useOriginalColours = safeBoolean(
5439 viewAnnColour.isPredefinedColours());
5440 cs.setSeqAssociated(perSequenceOnly);
5441 cs.setPredefinedColours(useOriginalColours);
5443 if (propagateAnnColour && al.getGroups() != null)
5445 // Also use these settings for all the groups
5446 for (int g = 0; g < al.getGroups().size(); g++)
5448 SequenceGroup sg = al.getGroups().get(g);
5449 if (sg.getGroupColourScheme() == null)
5454 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5455 matchedAnnotation, sg.getColourScheme(),
5456 safeInt(viewAnnColour.getAboveThreshold()));
5457 sg.setColourScheme(groupScheme);
5458 groupScheme.setSeqAssociated(perSequenceOnly);
5459 groupScheme.setPredefinedColours(useOriginalColours);
5465 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5466 List<JvAnnotRow> autoAlan)
5468 // copy over visualization settings for autocalculated annotation in the
5470 if (al.getAlignmentAnnotation() != null)
5473 * Kludge for magic autoannotation names (see JAL-811)
5475 String[] magicNames = new String[] { "Consensus", "Quality",
5477 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5478 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5479 for (String nm : magicNames)
5481 visan.put(nm, nullAnnot);
5483 for (JvAnnotRow auan : autoAlan)
5485 visan.put(auan.template.label
5486 + (auan.template.getCalcId() == null ? ""
5487 : "\t" + auan.template.getCalcId()),
5490 int hSize = al.getAlignmentAnnotation().length;
5491 List<JvAnnotRow> reorder = new ArrayList<>();
5492 // work through any autoCalculated annotation already on the view
5493 // removing it if it should be placed in a different location on the
5494 // annotation panel.
5495 List<String> remains = new ArrayList<>(visan.keySet());
5496 for (int h = 0; h < hSize; h++)
5498 jalview.datamodel.AlignmentAnnotation jalan = al
5499 .getAlignmentAnnotation()[h];
5500 if (jalan.autoCalculated)
5503 JvAnnotRow valan = visan.get(k = jalan.label);
5504 if (jalan.getCalcId() != null)
5506 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5511 // delete the auto calculated row from the alignment
5512 al.deleteAnnotation(jalan, false);
5516 if (valan != nullAnnot)
5518 if (jalan != valan.template)
5520 // newly created autoannotation row instance
5521 // so keep a reference to the visible annotation row
5522 // and copy over all relevant attributes
5523 if (valan.template.graphHeight >= 0)
5526 jalan.graphHeight = valan.template.graphHeight;
5528 jalan.visible = valan.template.visible;
5530 reorder.add(new JvAnnotRow(valan.order, jalan));
5535 // Add any (possibly stale) autocalculated rows that were not appended to
5536 // the view during construction
5537 for (String other : remains)
5539 JvAnnotRow othera = visan.get(other);
5540 if (othera != nullAnnot && othera.template.getCalcId() != null
5541 && othera.template.getCalcId().length() > 0)
5543 reorder.add(othera);
5546 // now put the automatic annotation in its correct place
5547 int s = 0, srt[] = new int[reorder.size()];
5548 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5549 for (JvAnnotRow jvar : reorder)
5552 srt[s++] = jvar.order;
5555 jalview.util.QuickSort.sort(srt, rws);
5556 // and re-insert the annotation at its correct position
5557 for (JvAnnotRow jvar : rws)
5559 al.addAnnotation(jvar.template, jvar.order);
5561 af.alignPanel.adjustAnnotationHeight();
5565 Hashtable skipList = null;
5568 * TODO remove this method
5571 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5572 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5573 * throw new Error("Implementation Error. No skipList defined for this
5574 * Jalview2XML instance."); } return (AlignFrame)
5575 * skipList.get(view.getSequenceSetId()); }
5579 * Check if the Jalview view contained in object should be skipped or not.
5582 * @return true if view's sequenceSetId is a key in skipList
5584 private boolean skipViewport(JalviewModel object)
5586 if (skipList == null)
5590 String id = object.getViewport().get(0).getSequenceSetId();
5591 if (skipList.containsKey(id))
5593 Console.debug("Skipping seuqence set id " + id);
5599 public void addToSkipList(AlignFrame af)
5601 if (skipList == null)
5603 skipList = new Hashtable();
5605 skipList.put(af.getViewport().getSequenceSetId(), af);
5608 public void clearSkipList()
5610 if (skipList != null)
5617 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5618 boolean ignoreUnrefed, String uniqueSeqSetId)
5620 jalview.datamodel.AlignmentI ds = getDatasetFor(
5621 vamsasSet.getDatasetId());
5622 AlignmentI xtant_ds = ds;
5623 if (xtant_ds == null)
5625 // good chance we are about to create a new dataset, but check if we've
5626 // seen some of the dataset sequence IDs before.
5627 // TODO: skip this check if we are working with project generated by
5628 // version 2.11 or later
5629 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5630 if (xtant_ds != null)
5633 addDatasetRef(vamsasSet.getDatasetId(), ds);
5636 Vector<SequenceI> dseqs = null;
5639 // recovering an alignment View
5640 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5641 if (seqSetDS != null)
5643 if (ds != null && ds != seqSetDS)
5646 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5647 + " - CDS/Protein crossreference data may be lost");
5648 if (xtant_ds != null)
5650 // This can only happen if the unique sequence set ID was bound to a
5651 // dataset that did not contain any of the sequences in the view
5652 // currently being restored.
5654 "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.");
5658 addDatasetRef(vamsasSet.getDatasetId(), ds);
5663 // try even harder to restore dataset
5664 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5665 // create a list of new dataset sequences
5666 dseqs = new Vector<>();
5668 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5670 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5671 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5673 // create a new dataset
5676 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5677 dseqs.copyInto(dsseqs);
5678 ds = new jalview.datamodel.Alignment(dsseqs);
5679 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5680 + " for alignment " + System.identityHashCode(al));
5681 addDatasetRef(vamsasSet.getDatasetId(), ds);
5683 // set the dataset for the newly imported alignment.
5684 if (al.getDataset() == null && !ignoreUnrefed)
5687 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5688 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5690 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5694 * XML dataset sequence ID to materialised dataset reference
5696 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5699 * @return the first materialised dataset reference containing a dataset
5700 * sequence referenced in the given view
5702 * - sequences from the view
5704 AlignmentI checkIfHasDataset(List<Sequence> list)
5706 for (Sequence restoredSeq : list)
5708 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5709 if (datasetFor != null)
5718 * Register ds as the containing dataset for the dataset sequences referenced
5719 * by sequences in list
5722 * - sequences in a view
5725 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5727 for (Sequence restoredSeq : list)
5729 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5730 if (prevDS != null && prevDS != ds)
5732 Console.warn("Dataset sequence appears in many datasets: "
5733 + restoredSeq.getDsseqid());
5734 // TODO: try to merge!
5742 * sequence definition to create/merge dataset sequence for
5746 * vector to add new dataset sequence to
5747 * @param ignoreUnrefed
5748 * - when true, don't create new sequences from vamsasSeq if it's id
5749 * doesn't already have an asssociated Jalview sequence.
5751 * - used to reorder the sequence in the alignment according to the
5752 * vamsasSeq array ordering, to preserve ordering of dataset
5754 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5755 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5758 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5760 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5761 boolean reorder = false;
5762 SequenceI dsq = null;
5763 if (sq != null && sq.getDatasetSequence() != null)
5765 dsq = sq.getDatasetSequence();
5771 if (sq == null && ignoreUnrefed)
5775 String sqid = vamsasSeq.getDsseqid();
5778 // need to create or add a new dataset sequence reference to this sequence
5781 dsq = seqRefIds.get(sqid);
5786 // make a new dataset sequence
5787 dsq = sq.createDatasetSequence();
5790 // make up a new dataset reference for this sequence
5791 sqid = seqHash(dsq);
5793 dsq.setVamsasId(uniqueSetSuffix + sqid);
5794 seqRefIds.put(sqid, dsq);
5799 dseqs.addElement(dsq);
5804 ds.addSequence(dsq);
5810 { // make this dataset sequence sq's dataset sequence
5811 sq.setDatasetSequence(dsq);
5812 // and update the current dataset alignment
5817 if (!dseqs.contains(dsq))
5824 if (ds.findIndex(dsq) < 0)
5826 ds.addSequence(dsq);
5833 // TODO: refactor this as a merge dataset sequence function
5834 // now check that sq (the dataset sequence) sequence really is the union of
5835 // all references to it
5836 // boolean pre = sq.getStart() < dsq.getStart();
5837 // boolean post = sq.getEnd() > dsq.getEnd();
5841 // StringBuffer sb = new StringBuffer();
5842 String newres = jalview.analysis.AlignSeq.extractGaps(
5843 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5844 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5845 && newres.length() > dsq.getLength())
5847 // Update with the longer sequence.
5851 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5852 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5853 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5854 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5856 dsq.setSequence(newres);
5858 // TODO: merges will never happen if we 'know' we have the real dataset
5859 // sequence - this should be detected when id==dssid
5861 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5862 // + (pre ? "prepended" : "") + " "
5863 // + (post ? "appended" : ""));
5868 // sequence refs are identical. We may need to update the existing dataset
5869 // alignment with this one, though.
5870 if (ds != null && dseqs == null)
5872 int opos = ds.findIndex(dsq);
5873 SequenceI tseq = null;
5874 if (opos != -1 && vseqpos != opos)
5876 // remove from old position
5877 ds.deleteSequence(dsq);
5879 if (vseqpos < ds.getHeight())
5881 if (vseqpos != opos)
5883 // save sequence at destination position
5884 tseq = ds.getSequenceAt(vseqpos);
5885 ds.replaceSequenceAt(vseqpos, dsq);
5886 ds.addSequence(tseq);
5891 ds.addSequence(dsq);
5898 * TODO use AlignmentI here and in related methods - needs
5899 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5901 Hashtable<String, AlignmentI> datasetIds = null;
5903 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5905 private AlignmentI getDatasetFor(String datasetId)
5907 if (datasetIds == null)
5909 datasetIds = new Hashtable<>();
5912 if (datasetIds.containsKey(datasetId))
5914 return datasetIds.get(datasetId);
5919 private void addDatasetRef(String datasetId, AlignmentI dataset)
5921 if (datasetIds == null)
5923 datasetIds = new Hashtable<>();
5925 datasetIds.put(datasetId, dataset);
5929 * make a new dataset ID for this jalview dataset alignment
5934 private String getDatasetIdRef(AlignmentI dataset)
5936 if (dataset.getDataset() != null)
5939 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5941 String datasetId = makeHashCode(dataset, null);
5942 if (datasetId == null)
5944 // make a new datasetId and record it
5945 if (dataset2Ids == null)
5947 dataset2Ids = new IdentityHashMap<>();
5951 datasetId = dataset2Ids.get(dataset);
5953 if (datasetId == null)
5955 datasetId = "ds" + dataset2Ids.size() + 1;
5956 dataset2Ids.put(dataset, datasetId);
5963 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5964 * constructed as a special subclass GeneLocus.
5966 * @param datasetSequence
5969 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5971 for (int d = 0; d < sequence.getDBRef().size(); d++)
5973 DBRef dr = sequence.getDBRef().get(d);
5977 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5978 dr.getAccessionId());
5982 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5983 dr.getAccessionId());
5985 if (dr.getMapping() != null)
5987 entry.setMap(addMapping(dr.getMapping()));
5989 entry.setCanonical(dr.isCanonical());
5990 datasetSequence.addDBRef(entry);
5994 private jalview.datamodel.Mapping addMapping(Mapping m)
5996 SequenceI dsto = null;
5997 // Mapping m = dr.getMapping();
5998 int fr[] = new int[m.getMapListFrom().size() * 2];
5999 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6000 for (int _i = 0; from.hasNext(); _i += 2)
6002 MapListFrom mf = from.next();
6003 fr[_i] = mf.getStart();
6004 fr[_i + 1] = mf.getEnd();
6006 int fto[] = new int[m.getMapListTo().size() * 2];
6007 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6008 for (int _i = 0; to.hasNext(); _i += 2)
6010 MapListTo mf = to.next();
6011 fto[_i] = mf.getStart();
6012 fto[_i + 1] = mf.getEnd();
6014 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6015 fto, m.getMapFromUnit().intValue(),
6016 m.getMapToUnit().intValue());
6019 * (optional) choice of dseqFor or Sequence
6021 if (m.getDseqFor() != null)
6023 String dsfor = m.getDseqFor();
6024 if (seqRefIds.containsKey(dsfor))
6029 jmap.setTo(seqRefIds.get(dsfor));
6033 frefedSequence.add(newMappingRef(dsfor, jmap));
6036 else if (m.getSequence() != null)
6039 * local sequence definition
6041 Sequence ms = m.getSequence();
6042 SequenceI djs = null;
6043 String sqid = ms.getDsseqid();
6044 if (sqid != null && sqid.length() > 0)
6047 * recover dataset sequence
6049 djs = seqRefIds.get(sqid);
6054 "Warning - making up dataset sequence id for DbRef sequence map reference");
6055 sqid = ((Object) ms).toString(); // make up a new hascode for
6056 // undefined dataset sequence hash
6057 // (unlikely to happen)
6063 * make a new dataset sequence and add it to refIds hash
6065 djs = new jalview.datamodel.Sequence(ms.getName(),
6067 djs.setStart(jmap.getMap().getToLowest());
6068 djs.setEnd(jmap.getMap().getToHighest());
6069 djs.setVamsasId(uniqueSetSuffix + sqid);
6071 incompleteSeqs.put(sqid, djs);
6072 seqRefIds.put(sqid, djs);
6075 Console.debug("about to recurse on addDBRefs.");
6084 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6085 * view as XML (but not to file), and then reloading it
6090 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6093 JalviewModel jm = saveState(ap, null, null, null);
6096 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6097 ap.getAlignment().getDataset());
6099 uniqueSetSuffix = "";
6100 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6101 jm.getViewport().get(0).setId(null);
6102 // we don't overwrite the view we just copied
6104 if (this.frefedSequence == null)
6106 frefedSequence = new Vector<>();
6109 viewportsAdded.clear();
6111 AlignFrame af = loadFromObject(jm, null, false, null);
6112 af.getAlignPanels().clear();
6113 af.closeMenuItem_actionPerformed(true);
6116 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6117 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6118 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6119 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6120 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6123 return af.alignPanel;
6126 private Hashtable jvids2vobj;
6129 * set the object to ID mapping tables used to write/recover objects and XML
6130 * ID strings for the jalview project. If external tables are provided then
6131 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6132 * object goes out of scope. - also populates the datasetIds hashtable with
6133 * alignment objects containing dataset sequences
6136 * Map from ID strings to jalview datamodel
6138 * Map from jalview datamodel to ID strings
6142 public void setObjectMappingTables(Hashtable vobj2jv,
6143 IdentityHashMap jv2vobj)
6145 this.jv2vobj = jv2vobj;
6146 this.vobj2jv = vobj2jv;
6147 Iterator ds = jv2vobj.keySet().iterator();
6149 while (ds.hasNext())
6151 Object jvobj = ds.next();
6152 id = jv2vobj.get(jvobj).toString();
6153 if (jvobj instanceof jalview.datamodel.Alignment)
6155 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6157 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6160 else if (jvobj instanceof jalview.datamodel.Sequence)
6162 // register sequence object so the XML parser can recover it.
6163 if (seqRefIds == null)
6165 seqRefIds = new HashMap<>();
6167 if (seqsToIds == null)
6169 seqsToIds = new IdentityHashMap<>();
6171 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6172 seqsToIds.put((SequenceI) jvobj, id);
6174 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6177 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6178 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6179 if (jvann.annotationId == null)
6181 jvann.annotationId = anid;
6183 if (!jvann.annotationId.equals(anid))
6185 // TODO verify that this is the correct behaviour
6186 Console.warn("Overriding Annotation ID for " + anid
6187 + " from different id : " + jvann.annotationId);
6188 jvann.annotationId = anid;
6191 else if (jvobj instanceof String)
6193 if (jvids2vobj == null)
6195 jvids2vobj = new Hashtable();
6196 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6201 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6207 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6208 * objects created from the project archive. If string is null (default for
6209 * construction) then suffix will be set automatically.
6213 public void setUniqueSetSuffix(String string)
6215 uniqueSetSuffix = string;
6220 * uses skipList2 as the skipList for skipping views on sequence sets
6221 * associated with keys in the skipList
6225 public void setSkipList(Hashtable skipList2)
6227 skipList = skipList2;
6231 * Reads the jar entry of given name and returns its contents, or null if the
6232 * entry is not found.
6235 * @param jarEntryName
6238 protected String readJarEntry(jarInputStreamProvider jprovider,
6239 String jarEntryName)
6241 String result = null;
6242 BufferedReader in = null;
6247 * Reopen the jar input stream and traverse its entries to find a matching
6250 JarInputStream jin = jprovider.getJarInputStream();
6251 JarEntry entry = null;
6254 entry = jin.getNextJarEntry();
6255 } while (entry != null && !entry.getName().equals(jarEntryName));
6259 StringBuilder out = new StringBuilder(256);
6260 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6263 while ((data = in.readLine()) != null)
6267 result = out.toString();
6272 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6274 } catch (Exception ex)
6276 ex.printStackTrace();
6284 } catch (IOException e)
6295 * Returns an incrementing counter (0, 1, 2...)
6299 private synchronized int nextCounter()
6305 * Loads any saved PCA viewers
6310 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6314 List<PcaViewer> pcaviewers = model.getPcaViewer();
6315 for (PcaViewer viewer : pcaviewers)
6317 String modelName = viewer.getScoreModelName();
6318 SimilarityParamsI params = new SimilarityParams(
6319 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6320 viewer.isIncludeGaps(),
6321 viewer.isDenominateByShortestLength());
6324 * create the panel (without computing the PCA)
6326 PCAPanel panel = new PCAPanel(ap, modelName, params);
6328 panel.setTitle(viewer.getTitle());
6329 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6330 viewer.getWidth(), viewer.getHeight()));
6332 boolean showLabels = viewer.isShowLabels();
6333 panel.setShowLabels(showLabels);
6334 panel.getRotatableCanvas().setShowLabels(showLabels);
6335 panel.getRotatableCanvas()
6336 .setBgColour(new Color(viewer.getBgColour()));
6337 panel.getRotatableCanvas()
6338 .setApplyToAllViews(viewer.isLinkToAllViews());
6341 * load PCA output data
6343 ScoreModelI scoreModel = ScoreModels.getInstance()
6344 .getScoreModel(modelName, ap);
6345 PCA pca = new PCA(null, scoreModel, params);
6346 PcaDataType pcaData = viewer.getPcaData();
6348 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6349 pca.setPairwiseScores(pairwise);
6351 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6352 pca.setTridiagonal(triDiag);
6354 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6355 pca.setEigenmatrix(result);
6357 panel.getPcaModel().setPCA(pca);
6360 * we haven't saved the input data! (JAL-2647 to do)
6362 panel.setInputData(null);
6365 * add the sequence points for the PCA display
6367 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6368 for (SequencePoint sp : viewer.getSequencePoint())
6370 String seqId = sp.getSequenceRef();
6371 SequenceI seq = seqRefIds.get(seqId);
6374 throw new IllegalStateException(
6375 "Unmatched seqref for PCA: " + seqId);
6377 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6378 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6380 seqPoints.add(seqPoint);
6382 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6385 * set min-max ranges and scale after setPoints (which recomputes them)
6387 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6388 SeqPointMin spMin = viewer.getSeqPointMin();
6389 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6391 SeqPointMax spMax = viewer.getSeqPointMax();
6392 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6394 panel.getRotatableCanvas().setSeqMinMax(min, max);
6396 // todo: hold points list in PCAModel only
6397 panel.getPcaModel().setSequencePoints(seqPoints);
6399 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6400 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6401 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6403 // is this duplication needed?
6404 panel.setTop(seqPoints.size() - 1);
6405 panel.getPcaModel().setTop(seqPoints.size() - 1);
6408 * add the axes' end points for the display
6410 for (int i = 0; i < 3; i++)
6412 Axis axis = viewer.getAxis().get(i);
6413 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6414 axis.getXPos(), axis.getYPos(), axis.getZPos());
6417 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6418 "label.calc_title", "PCA", modelName), 475, 450);
6420 } catch (Exception ex)
6422 Console.error("Error loading PCA: " + ex.toString());
6427 * Creates a new structure viewer window
6434 protected void createStructureViewer(ViewerType viewerType,
6435 final Entry<String, StructureViewerModel> viewerData,
6436 AlignFrame af, jarInputStreamProvider jprovider)
6438 final StructureViewerModel viewerModel = viewerData.getValue();
6439 String sessionFilePath = null;
6441 if (viewerType == ViewerType.JMOL)
6443 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6447 String viewerJarEntryName = getViewerJarEntryName(
6448 viewerModel.getViewId());
6449 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6450 "viewerSession", ".tmp");
6452 final String sessionPath = sessionFilePath;
6453 final String sviewid = viewerData.getKey();
6456 SwingUtilities.invokeAndWait(new Runnable()
6461 JalviewStructureDisplayI sview = null;
6464 sview = StructureViewer.createView(viewerType, af.alignPanel,
6465 viewerModel, sessionPath, sviewid);
6466 addNewStructureViewer(sview);
6467 } catch (OutOfMemoryError ex)
6469 new OOMWarning("Restoring structure view for " + viewerType,
6470 (OutOfMemoryError) ex.getCause());
6471 if (sview != null && sview.isVisible())
6473 sview.closeViewer(false);
6474 sview.setVisible(false);
6480 } catch (InvocationTargetException | InterruptedException ex)
6482 Console.warn("Unexpected error when opening " + viewerType
6483 + " structure viewer", ex);
6488 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6489 * the path of the file. "load file" commands are rewritten to change the
6490 * original PDB file names to those created as the Jalview project is loaded.
6496 private String rewriteJmolSession(StructureViewerModel svattrib,
6497 jarInputStreamProvider jprovider)
6499 String state = svattrib.getStateData(); // Jalview < 2.9
6500 if (state == null || state.isEmpty()) // Jalview >= 2.9
6502 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6503 state = readJarEntry(jprovider, jarEntryName);
6505 // TODO or simpler? for each key in oldFiles,
6506 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6507 // (allowing for different path escapings)
6508 StringBuilder rewritten = new StringBuilder(state.length());
6509 int cp = 0, ncp, ecp;
6510 Map<File, StructureData> oldFiles = svattrib.getFileData();
6511 while ((ncp = state.indexOf("load ", cp)) > -1)
6515 // look for next filename in load statement
6516 rewritten.append(state.substring(cp,
6517 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6518 String oldfilenam = state.substring(ncp,
6519 ecp = state.indexOf("\"", ncp));
6520 // recover the new mapping data for this old filename
6521 // have to normalize filename - since Jmol and jalview do
6522 // filename translation differently.
6523 StructureData filedat = oldFiles.get(new File(oldfilenam));
6524 if (filedat == null)
6526 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6527 filedat = oldFiles.get(new File(reformatedOldFilename));
6529 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6530 rewritten.append("\"");
6531 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6532 // look for next file statement.
6533 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6537 // just append rest of state
6538 rewritten.append(state.substring(cp));
6542 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6543 rewritten = new StringBuilder(state);
6544 rewritten.append("; load append ");
6545 for (File id : oldFiles.keySet())
6547 // add pdb files that should be present in the viewer
6548 StructureData filedat = oldFiles.get(id);
6549 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6551 rewritten.append(";");
6554 if (rewritten.length() == 0)
6558 final String history = "history = ";
6559 int historyIndex = rewritten.indexOf(history);
6560 if (historyIndex > -1)
6563 * change "history = [true|false];" to "history = [1|0];"
6565 historyIndex += history.length();
6566 String val = rewritten.substring(historyIndex, historyIndex + 5);
6567 if (val.startsWith("true"))
6569 rewritten.replace(historyIndex, historyIndex + 4, "1");
6571 else if (val.startsWith("false"))
6573 rewritten.replace(historyIndex, historyIndex + 5, "0");
6579 File tmp = File.createTempFile("viewerSession", ".tmp");
6580 try (OutputStream os = new FileOutputStream(tmp))
6582 InputStream is = new ByteArrayInputStream(
6583 rewritten.toString().getBytes());
6585 return tmp.getAbsolutePath();
6587 } catch (IOException e)
6589 Console.error("Error restoring Jmol session: " + e.toString());
6595 * Populates an XML model of the feature colour scheme for one feature type
6597 * @param featureType
6601 public static Colour marshalColour(String featureType,
6602 FeatureColourI fcol)
6604 Colour col = new Colour();
6605 if (fcol.isSimpleColour())
6607 col.setRGB(Format.getHexString(fcol.getColour()));
6611 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6612 col.setMin(fcol.getMin());
6613 col.setMax(fcol.getMax());
6614 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6615 col.setAutoScale(fcol.isAutoScaled());
6616 col.setThreshold(fcol.getThreshold());
6617 col.setColourByLabel(fcol.isColourByLabel());
6618 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6619 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6620 : ThresholdType.NONE));
6621 if (fcol.isColourByAttribute())
6623 final String[] attName = fcol.getAttributeName();
6624 col.getAttributeName().add(attName[0]);
6625 if (attName.length > 1)
6627 col.getAttributeName().add(attName[1]);
6630 Color noColour = fcol.getNoColour();
6631 if (noColour == null)
6633 col.setNoValueColour(NoValueColour.NONE);
6635 else if (noColour == fcol.getMaxColour())
6637 col.setNoValueColour(NoValueColour.MAX);
6641 col.setNoValueColour(NoValueColour.MIN);
6644 col.setName(featureType);
6649 * Populates an XML model of the feature filter(s) for one feature type
6651 * @param firstMatcher
6652 * the first (or only) match condition)
6654 * remaining match conditions (if any)
6656 * if true, conditions are and-ed, else or-ed
6658 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6659 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6662 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6664 if (filters.hasNext())
6669 CompoundMatcher compound = new CompoundMatcher();
6670 compound.setAnd(and);
6671 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6672 firstMatcher, Collections.emptyIterator(), and);
6673 // compound.addMatcherSet(matcher1);
6674 compound.getMatcherSet().add(matcher1);
6675 FeatureMatcherI nextMatcher = filters.next();
6676 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6677 nextMatcher, filters, and);
6678 // compound.addMatcherSet(matcher2);
6679 compound.getMatcherSet().add(matcher2);
6680 result.setCompoundMatcher(compound);
6685 * single condition matcher
6687 // MatchCondition matcherModel = new MatchCondition();
6688 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6689 matcherModel.setCondition(
6690 firstMatcher.getMatcher().getCondition().getStableName());
6691 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6692 if (firstMatcher.isByAttribute())
6694 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6695 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6696 String[] attName = firstMatcher.getAttribute();
6697 matcherModel.getAttributeName().add(attName[0]); // attribute
6698 if (attName.length > 1)
6700 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6703 else if (firstMatcher.isByLabel())
6705 matcherModel.setBy(FilterBy.BY_LABEL);
6707 else if (firstMatcher.isByScore())
6709 matcherModel.setBy(FilterBy.BY_SCORE);
6711 result.setMatchCondition(matcherModel);
6718 * Loads one XML model of a feature filter to a Jalview object
6720 * @param featureType
6721 * @param matcherSetModel
6724 public static FeatureMatcherSetI parseFilter(String featureType,
6725 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6727 FeatureMatcherSetI result = new FeatureMatcherSet();
6730 parseFilterConditions(result, matcherSetModel, true);
6731 } catch (IllegalStateException e)
6733 // mixing AND and OR conditions perhaps
6735 String.format("Error reading filter conditions for '%s': %s",
6736 featureType, e.getMessage()));
6737 // return as much as was parsed up to the error
6744 * Adds feature match conditions to matcherSet as unmarshalled from XML
6745 * (possibly recursively for compound conditions)
6748 * @param matcherSetModel
6750 * if true, multiple conditions are AND-ed, else they are OR-ed
6751 * @throws IllegalStateException
6752 * if AND and OR conditions are mixed
6754 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6755 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6758 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6759 .getMatchCondition();
6765 FilterBy filterBy = mc.getBy();
6766 Condition cond = Condition.fromString(mc.getCondition());
6767 String pattern = mc.getValue();
6768 FeatureMatcherI matchCondition = null;
6769 if (filterBy == FilterBy.BY_LABEL)
6771 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6773 else if (filterBy == FilterBy.BY_SCORE)
6775 matchCondition = FeatureMatcher.byScore(cond, pattern);
6778 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6780 final List<String> attributeName = mc.getAttributeName();
6781 String[] attNames = attributeName
6782 .toArray(new String[attributeName.size()]);
6783 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6788 * note this throws IllegalStateException if AND-ing to a
6789 * previously OR-ed compound condition, or vice versa
6793 matcherSet.and(matchCondition);
6797 matcherSet.or(matchCondition);
6803 * compound condition
6805 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6806 .getCompoundMatcher().getMatcherSet();
6807 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6808 if (matchers.size() == 2)
6810 parseFilterConditions(matcherSet, matchers.get(0), anded);
6811 parseFilterConditions(matcherSet, matchers.get(1), anded);
6815 System.err.println("Malformed compound filter condition");
6821 * Loads one XML model of a feature colour to a Jalview object
6823 * @param colourModel
6826 public static FeatureColourI parseColour(Colour colourModel)
6828 FeatureColourI colour = null;
6830 if (colourModel.getMax() != null)
6832 Color mincol = null;
6833 Color maxcol = null;
6834 Color noValueColour = null;
6838 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6839 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6840 } catch (Exception e)
6842 Console.warn("Couldn't parse out graduated feature color.", e);
6845 NoValueColour noCol = colourModel.getNoValueColour();
6846 if (noCol == NoValueColour.MIN)
6848 noValueColour = mincol;
6850 else if (noCol == NoValueColour.MAX)
6852 noValueColour = maxcol;
6855 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6856 safeFloat(colourModel.getMin()),
6857 safeFloat(colourModel.getMax()));
6858 final List<String> attributeName = colourModel.getAttributeName();
6859 String[] attributes = attributeName
6860 .toArray(new String[attributeName.size()]);
6861 if (attributes != null && attributes.length > 0)
6863 colour.setAttributeName(attributes);
6865 if (colourModel.isAutoScale() != null)
6867 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6869 if (colourModel.isColourByLabel() != null)
6871 colour.setColourByLabel(
6872 colourModel.isColourByLabel().booleanValue());
6874 if (colourModel.getThreshold() != null)
6876 colour.setThreshold(colourModel.getThreshold().floatValue());
6878 ThresholdType ttyp = colourModel.getThreshType();
6879 if (ttyp == ThresholdType.ABOVE)
6881 colour.setAboveThreshold(true);
6883 else if (ttyp == ThresholdType.BELOW)
6885 colour.setBelowThreshold(true);
6890 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6891 colour = new FeatureColour(color);
6897 public static void setStateSavedUpToDate(boolean s)
6899 Console.debug("Setting overall stateSavedUpToDate to " + s);
6900 stateSavedUpToDate = s;
6903 public static boolean stateSavedUpToDate()
6905 Console.debug("Returning overall stateSavedUpToDate value: "
6906 + stateSavedUpToDate);
6907 return stateSavedUpToDate;
6910 public static boolean allSavedUpToDate()
6912 if (stateSavedUpToDate()) // nothing happened since last project save
6915 AlignFrame[] frames = Desktop.getAlignFrames();
6918 for (int i = 0; i < frames.length; i++)
6920 if (frames[i] == null)
6922 if (!frames[i].getViewport().savedUpToDate())
6923 return false; // at least one alignment is not individually saved
6929 // used for debugging and tests
6930 private static int debugDelaySave = 20;
6932 public static void setDebugDelaySave(int n)