2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.BitSet;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Hashtable;
54 import java.util.IdentityHashMap;
55 import java.util.Iterator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Locale;
60 import java.util.Map.Entry;
62 import java.util.Vector;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarInputStream;
65 import java.util.jar.JarOutputStream;
67 import javax.swing.JInternalFrame;
68 import javax.swing.SwingUtilities;
69 import javax.xml.bind.JAXBContext;
70 import javax.xml.bind.JAXBElement;
71 import javax.xml.bind.Marshaller;
72 import javax.xml.datatype.DatatypeConfigurationException;
73 import javax.xml.datatype.DatatypeFactory;
74 import javax.xml.datatype.XMLGregorianCalendar;
75 import javax.xml.stream.XMLInputFactory;
76 import javax.xml.stream.XMLStreamReader;
78 import jalview.analysis.Conservation;
79 import jalview.analysis.PCA;
80 import jalview.analysis.scoremodels.ScoreModels;
81 import jalview.analysis.scoremodels.SimilarityParams;
82 import jalview.api.FeatureColourI;
83 import jalview.api.ViewStyleI;
84 import jalview.api.analysis.ScoreModelI;
85 import jalview.api.analysis.SimilarityParamsI;
86 import jalview.api.structures.JalviewStructureDisplayI;
87 import jalview.bin.Cache;
88 import jalview.bin.Console;
89 import jalview.bin.Jalview;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.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 * A helper method for safely using the value of an optional attribute that
289 * may be null if not present in the XML. Answers the boolean value, or false
295 public static boolean safeBoolean(Boolean b)
297 return b == null ? false : b.booleanValue();
301 * A helper method for safely using the value of an optional attribute that
302 * may be null if not present in the XML. Answers the integer value, or zero
308 public static int safeInt(Integer i)
310 return i == null ? 0 : i.intValue();
314 * A helper method for safely using the value of an optional attribute that
315 * may be null if not present in the XML. Answers the float value, or zero if
321 public static float safeFloat(Float f)
323 return f == null ? 0f : f.floatValue();
327 * create/return unique hash string for sq
330 * @return new or existing unique string for sq
332 String seqHash(SequenceI sq)
334 if (seqsToIds == null)
338 if (seqsToIds.containsKey(sq))
340 return seqsToIds.get(sq);
344 // create sequential key
345 String key = "sq" + (seqsToIds.size() + 1);
346 key = makeHashCode(sq, key); // check we don't have an external reference
348 seqsToIds.put(sq, key);
355 if (seqsToIds == null)
357 seqsToIds = new IdentityHashMap<>();
359 if (seqRefIds == null)
361 seqRefIds = new HashMap<>();
363 if (incompleteSeqs == null)
365 incompleteSeqs = new HashMap<>();
367 if (frefedSequence == null)
369 frefedSequence = new ArrayList<>();
377 public Jalview2XML(boolean raiseGUI)
379 this.raiseGUI = raiseGUI;
383 * base class for resolving forward references to sequences by their ID
388 abstract class SeqFref
394 public SeqFref(String _sref, String type)
400 public String getSref()
405 public SequenceI getSrefSeq()
407 return seqRefIds.get(sref);
410 public boolean isResolvable()
412 return seqRefIds.get(sref) != null;
415 public SequenceI getSrefDatasetSeq()
417 SequenceI sq = seqRefIds.get(sref);
420 while (sq.getDatasetSequence() != null)
422 sq = sq.getDatasetSequence();
429 * @return true if the forward reference was fully resolved
431 abstract boolean resolve();
434 public String toString()
436 return type + " reference to " + sref;
441 * create forward reference for a mapping
447 public SeqFref newMappingRef(final String sref,
448 final jalview.datamodel.Mapping _jmap)
450 SeqFref fref = new SeqFref(sref, "Mapping")
452 public jalview.datamodel.Mapping jmap = _jmap;
457 SequenceI seq = getSrefDatasetSeq();
469 public SeqFref newAlcodMapRef(final String sref,
470 final AlignedCodonFrame _cf,
471 final jalview.datamodel.Mapping _jmap)
474 SeqFref fref = new SeqFref(sref, "Codon Frame")
476 AlignedCodonFrame cf = _cf;
478 public jalview.datamodel.Mapping mp = _jmap;
481 public boolean isResolvable()
483 return super.isResolvable() && mp.getTo() != null;
489 SequenceI seq = getSrefDatasetSeq();
494 cf.addMap(seq, mp.getTo(), mp.getMap());
501 public void resolveFrefedSequences()
503 Iterator<SeqFref> nextFref = frefedSequence.iterator();
504 int toresolve = frefedSequence.size();
505 int unresolved = 0, failedtoresolve = 0;
506 while (nextFref.hasNext())
508 SeqFref ref = nextFref.next();
509 if (ref.isResolvable())
521 } catch (Exception x)
523 jalview.bin.Console.errPrintln(
524 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
537 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
539 + " forward references left unresolved on the stack.");
541 if (failedtoresolve > 0)
543 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
544 + " resolvable forward references failed to resolve.");
546 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
548 jalview.bin.Console.errPrintln(
549 "Jalview Project Import: There are " + incompleteSeqs.size()
550 + " sequences which may have incomplete metadata.");
551 if (incompleteSeqs.size() < 10)
553 for (SequenceI s : incompleteSeqs.values())
555 jalview.bin.Console.errPrintln(s.toString());
560 jalview.bin.Console.errPrintln(
561 "Too many to report. Skipping output of incomplete sequences.");
567 * This maintains a map of viewports, the key being the seqSetId. Important to
568 * set historyItem and redoList for multiple views
570 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
572 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
574 String uniqueSetSuffix = "";
577 * List of pdbfiles added to Jar
579 List<String> pdbfiles = null;
581 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
582 public void saveState(File statefile)
584 FileOutputStream fos = null;
589 fos = new FileOutputStream(statefile);
591 JarOutputStream jout = new JarOutputStream(fos);
595 } catch (Exception e)
597 Console.error("Couln't write Jalview state to " + statefile, e);
598 // TODO: inform user of the problem - they need to know if their data was
600 if (errorMessage == null)
602 errorMessage = "Did't write Jalview Archive to output file '"
603 + statefile + "' - See console error log for details";
607 errorMessage += "(Didn't write Jalview Archive to output file '"
618 } catch (IOException e)
628 * Writes a jalview project archive to the given Jar output stream.
632 public void saveState(JarOutputStream jout)
634 AlignFrame[] frames = Desktop.getAlignFrames();
636 setStateSavedUpToDate(true);
638 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
640 int n = debugDelaySave;
644 Console.debug("***** debugging save sleep " + i + "/" + n);
648 } catch (InterruptedException e)
650 // TODO Auto-generated catch block
661 saveAllFrames(Arrays.asList(frames), jout);
665 * core method for storing state for a set of AlignFrames.
668 * - frames involving all data to be exported (including containing
671 * - project output stream
673 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
675 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
678 * ensure cached data is clear before starting
680 // todo tidy up seqRefIds, seqsToIds initialisation / reset
682 splitFrameCandidates.clear();
687 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
688 // //////////////////////////////////////////////////
690 List<String> shortNames = new ArrayList<>();
691 List<String> viewIds = new ArrayList<>();
694 for (int i = frames.size() - 1; i > -1; i--)
696 AlignFrame af = frames.get(i);
698 if (skipList != null && skipList
699 .containsKey(af.getViewport().getSequenceSetId()))
704 String shortName = makeFilename(af, shortNames);
706 int apSize = af.getAlignPanels().size();
708 for (int ap = 0; ap < apSize; ap++)
710 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
712 String fileName = apSize == 1 ? shortName : ap + shortName;
713 if (!fileName.endsWith(".xml"))
715 fileName = fileName + ".xml";
718 saveState(apanel, fileName, jout, viewIds);
720 String dssid = getDatasetIdRef(
721 af.getViewport().getAlignment().getDataset());
722 if (!dsses.containsKey(dssid))
724 dsses.put(dssid, af);
729 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
735 } catch (Exception foo)
739 } catch (Exception ex)
741 // TODO: inform user of the problem - they need to know if their data was
743 if (errorMessage == null)
745 errorMessage = "Couldn't write Jalview Archive - see error output for details";
747 ex.printStackTrace();
752 * Generates a distinct file name, based on the title of the AlignFrame, by
753 * appending _n for increasing n until an unused name is generated. The new
754 * name (without its extension) is added to the list.
758 * @return the generated name, with .xml extension
760 protected String makeFilename(AlignFrame af, List<String> namesUsed)
762 String shortName = af.getTitle();
764 if (shortName.indexOf(File.separatorChar) > -1)
766 shortName = shortName
767 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
772 while (namesUsed.contains(shortName))
774 if (shortName.endsWith("_" + (count - 1)))
776 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
779 shortName = shortName.concat("_" + count);
783 namesUsed.add(shortName);
785 if (!shortName.endsWith(".xml"))
787 shortName = shortName + ".xml";
792 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
793 public boolean saveAlignment(AlignFrame af, String jarFile,
798 // create backupfiles object and get new temp filename destination
799 boolean doBackup = BackupFiles.getEnabled();
800 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
801 FileOutputStream fos = new FileOutputStream(
802 doBackup ? backupfiles.getTempFilePath() : jarFile);
804 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
806 int n = debugDelaySave;
810 Console.debug("***** debugging save sleep " + i + "/" + n);
814 } catch (InterruptedException e)
816 // TODO Auto-generated catch block
823 JarOutputStream jout = new JarOutputStream(fos);
824 List<AlignFrame> frames = new ArrayList<>();
826 // resolve splitframes
827 if (af.getViewport().getCodingComplement() != null)
829 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
835 saveAllFrames(frames, jout);
839 } catch (Exception foo)
843 boolean success = true;
847 backupfiles.setWriteSuccess(success);
848 success = backupfiles.rollBackupsAndRenameTempFile();
852 } catch (Exception ex)
854 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
855 ex.printStackTrace();
860 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
861 String fileName, JarOutputStream jout)
864 for (String dssids : dsses.keySet())
866 AlignFrame _af = dsses.get(dssids);
867 String jfileName = fileName + " Dataset for " + _af.getTitle();
868 if (!jfileName.endsWith(".xml"))
870 jfileName = jfileName + ".xml";
872 saveState(_af.alignPanel, jfileName, true, jout, null);
877 * create a JalviewModel from an alignment view and marshall it to a
881 * panel to create jalview model for
883 * name of alignment panel written to output stream
890 public JalviewModel saveState(AlignmentPanel ap, String fileName,
891 JarOutputStream jout, List<String> viewIds)
893 return saveState(ap, fileName, false, jout, viewIds);
897 * create a JalviewModel from an alignment view and marshall it to a
901 * panel to create jalview model for
903 * name of alignment panel written to output stream
905 * when true, only write the dataset for the alignment, not the data
906 * associated with the view.
912 public JalviewModel saveState(AlignmentPanel ap, String fileName,
913 boolean storeDS, JarOutputStream jout, List<String> viewIds)
917 viewIds = new ArrayList<>();
922 List<UserColourScheme> userColours = new ArrayList<>();
924 AlignViewport av = ap.av;
925 ViewportRanges vpRanges = av.getRanges();
927 final ObjectFactory objectFactory = new ObjectFactory();
928 JalviewModel object = objectFactory.createJalviewModel();
929 object.setVamsasModel(new VAMSAS());
931 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
934 GregorianCalendar c = new GregorianCalendar();
935 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
936 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
937 object.setCreationDate(now);
938 } catch (DatatypeConfigurationException e)
940 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
942 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
945 * rjal is full height alignment, jal is actual alignment with full metadata
946 * but excludes hidden sequences.
948 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
950 if (av.hasHiddenRows())
952 rjal = jal.getHiddenSequences().getFullAlignment();
955 SequenceSet vamsasSet = new SequenceSet();
957 // JalviewModelSequence jms = new JalviewModelSequence();
959 vamsasSet.setGapChar(jal.getGapCharacter() + "");
961 if (jal.getDataset() != null)
963 // dataset id is the dataset's hashcode
964 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
967 // switch jal and the dataset
968 jal = jal.getDataset();
972 if (jal.getProperties() != null)
974 Enumeration en = jal.getProperties().keys();
975 while (en.hasMoreElements())
977 String key = en.nextElement().toString();
978 SequenceSetProperties ssp = new SequenceSetProperties();
980 ssp.setValue(jal.getProperties().get(key).toString());
981 // vamsasSet.addSequenceSetProperties(ssp);
982 vamsasSet.getSequenceSetProperties().add(ssp);
987 Set<String> calcIdSet = new HashSet<>();
988 // record the set of vamsas sequence XML POJO we create.
989 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
991 for (final SequenceI jds : rjal.getSequences())
993 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
994 : jds.getDatasetSequence();
995 String id = seqHash(jds);
996 if (vamsasSetIds.get(id) == null)
998 if (seqRefIds.get(id) != null && !storeDS)
1000 // This happens for two reasons: 1. multiple views are being
1002 // 2. the hashCode has collided with another sequence's code. This
1004 // HAPPEN! (PF00072.15.stk does this)
1005 // JBPNote: Uncomment to debug writing out of files that do not read
1006 // back in due to ArrayOutOfBoundExceptions.
1007 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1008 // jalview.bin.Console.errPrintln(jds.getName()+"
1009 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1010 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1011 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1012 // jalview.bin.Console.errPrintln(rsq.getName()+"
1013 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1014 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1018 vamsasSeq = createVamsasSequence(id, jds);
1019 // vamsasSet.addSequence(vamsasSeq);
1020 vamsasSet.getSequence().add(vamsasSeq);
1021 vamsasSetIds.put(id, vamsasSeq);
1022 seqRefIds.put(id, jds);
1026 jseq.setStart(jds.getStart());
1027 jseq.setEnd(jds.getEnd());
1028 jseq.setColour(av.getSequenceColour(jds).getRGB());
1030 jseq.setId(id); // jseq id should be a string not a number
1033 // Store any sequences this sequence represents
1034 if (av.hasHiddenRows())
1036 // use rjal, contains the full height alignment
1038 av.getAlignment().getHiddenSequences().isHidden(jds));
1040 if (av.isHiddenRepSequence(jds))
1042 jalview.datamodel.SequenceI[] reps = av
1043 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1045 for (int h = 0; h < reps.length; h++)
1049 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1050 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1055 // mark sequence as reference - if it is the reference for this view
1056 if (jal.hasSeqrep())
1058 jseq.setViewreference(jds == jal.getSeqrep());
1062 // TODO: omit sequence features from each alignment view's XML dump if we
1063 // are storing dataset
1064 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1065 for (SequenceFeature sf : sfs)
1067 // Features features = new Features();
1068 Feature features = new Feature();
1070 features.setBegin(sf.getBegin());
1071 features.setEnd(sf.getEnd());
1072 features.setDescription(sf.getDescription());
1073 features.setType(sf.getType());
1074 features.setFeatureGroup(sf.getFeatureGroup());
1075 features.setScore(sf.getScore());
1076 if (sf.links != null)
1078 for (int l = 0; l < sf.links.size(); l++)
1080 OtherData keyValue = new OtherData();
1081 keyValue.setKey("LINK_" + l);
1082 keyValue.setValue(sf.links.elementAt(l).toString());
1083 // features.addOtherData(keyValue);
1084 features.getOtherData().add(keyValue);
1087 if (sf.otherDetails != null)
1090 * save feature attributes, which may be simple strings or
1091 * map valued (have sub-attributes)
1093 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1095 String key = entry.getKey();
1096 Object value = entry.getValue();
1097 if (value instanceof Map<?, ?>)
1099 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1102 OtherData otherData = new OtherData();
1103 otherData.setKey(key);
1104 otherData.setKey2(subAttribute.getKey());
1105 otherData.setValue(subAttribute.getValue().toString());
1106 // features.addOtherData(otherData);
1107 features.getOtherData().add(otherData);
1112 OtherData otherData = new OtherData();
1113 otherData.setKey(key);
1114 otherData.setValue(value.toString());
1115 // features.addOtherData(otherData);
1116 features.getOtherData().add(otherData);
1121 // jseq.addFeatures(features);
1122 jseq.getFeatures().add(features);
1125 if (jdatasq.getAllPDBEntries() != null)
1127 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1128 while (en.hasMoreElements())
1130 Pdbids pdb = new Pdbids();
1131 jalview.datamodel.PDBEntry entry = en.nextElement();
1133 String pdbId = entry.getId();
1135 pdb.setType(entry.getType());
1138 * Store any structure views associated with this sequence. This
1139 * section copes with duplicate entries in the project, so a dataset
1140 * only view *should* be coped with sensibly.
1142 // This must have been loaded, is it still visible?
1143 JInternalFrame[] frames = null;
1144 if (Desktop.desktop != null)
1146 frames = Desktop.desktop.getAllFrames();
1148 else if (Jalview.isHeadlessMode()
1149 && Jalview.getInstance().getCommands() != null)
1157 String matchedFile = null;
1160 for (int f = frames.length - 1; f > -1; f--)
1162 if (frames[f] instanceof StructureViewerBase)
1164 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1165 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1166 viewIds, matchedFile, viewFrame);
1168 * Only store each structure viewer's state once in the project
1169 * jar. First time through only (storeDS==false)
1171 String viewId = viewFrame.getViewId();
1172 String viewerType = viewFrame.getViewerType().toString();
1173 if (!storeDS && !viewIds.contains(viewId))
1175 viewIds.add(viewId);
1176 File viewerState = viewFrame.saveSession();
1177 if (viewerState != null)
1179 copyFileToJar(jout, viewerState.getPath(),
1180 getViewerJarEntryName(viewId), viewerType);
1184 Console.error("Failed to save viewer state for "
1192 if (matchedFile != null || entry.getFile() != null)
1194 if (entry.getFile() != null)
1197 matchedFile = entry.getFile();
1199 pdb.setFile(matchedFile); // entry.getFile());
1200 if (pdbfiles == null)
1202 pdbfiles = new ArrayList<>();
1205 if (!pdbfiles.contains(pdbId))
1207 pdbfiles.add(pdbId);
1208 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1212 Enumeration<String> props = entry.getProperties();
1213 if (props.hasMoreElements())
1215 // PdbentryItem item = new PdbentryItem();
1216 while (props.hasMoreElements())
1218 Property prop = new Property();
1219 String key = props.nextElement();
1221 prop.setValue(entry.getProperty(key).toString());
1222 // item.addProperty(prop);
1223 pdb.getProperty().add(prop);
1225 // pdb.addPdbentryItem(item);
1228 // jseq.addPdbids(pdb);
1229 jseq.getPdbids().add(pdb);
1233 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1235 // jms.addJSeq(jseq);
1236 object.getJSeq().add(jseq);
1239 if (!storeDS && av.hasHiddenRows())
1241 jal = av.getAlignment();
1245 if (storeDS && jal.getCodonFrames() != null)
1247 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1248 for (AlignedCodonFrame acf : jac)
1250 AlcodonFrame alc = new AlcodonFrame();
1251 if (acf.getProtMappings() != null
1252 && acf.getProtMappings().length > 0)
1254 boolean hasMap = false;
1255 SequenceI[] dnas = acf.getdnaSeqs();
1256 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1257 for (int m = 0; m < pmaps.length; m++)
1259 AlcodMap alcmap = new AlcodMap();
1260 alcmap.setDnasq(seqHash(dnas[m]));
1262 createVamsasMapping(pmaps[m], dnas[m], null, false));
1263 // alc.addAlcodMap(alcmap);
1264 alc.getAlcodMap().add(alcmap);
1269 // vamsasSet.addAlcodonFrame(alc);
1270 vamsasSet.getAlcodonFrame().add(alc);
1273 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1275 // AlcodonFrame alc = new AlcodonFrame();
1276 // vamsasSet.addAlcodonFrame(alc);
1277 // for (int p = 0; p < acf.aaWidth; p++)
1279 // Alcodon cmap = new Alcodon();
1280 // if (acf.codons[p] != null)
1282 // // Null codons indicate a gapped column in the translated peptide
1284 // cmap.setPos1(acf.codons[p][0]);
1285 // cmap.setPos2(acf.codons[p][1]);
1286 // cmap.setPos3(acf.codons[p][2]);
1288 // alc.addAlcodon(cmap);
1290 // if (acf.getProtMappings() != null
1291 // && acf.getProtMappings().length > 0)
1293 // SequenceI[] dnas = acf.getdnaSeqs();
1294 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1295 // for (int m = 0; m < pmaps.length; m++)
1297 // AlcodMap alcmap = new AlcodMap();
1298 // alcmap.setDnasq(seqHash(dnas[m]));
1299 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1301 // alc.addAlcodMap(alcmap);
1308 // /////////////////////////////////
1309 if (!storeDS && av.getCurrentTree() != null)
1311 // FIND ANY ASSOCIATED TREES
1312 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1313 if (Desktop.desktop != null)
1315 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1317 for (int t = 0; t < frames.length; t++)
1319 if (frames[t] instanceof TreePanel)
1321 TreePanel tp = (TreePanel) frames[t];
1323 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1325 JalviewModel.Tree tree = new JalviewModel.Tree();
1326 tree.setTitle(tp.getTitle());
1327 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1328 tree.setNewick(tp.getTree().print());
1329 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1331 tree.setFitToWindow(tp.fitToWindow.getState());
1332 tree.setFontName(tp.getTreeFont().getName());
1333 tree.setFontSize(tp.getTreeFont().getSize());
1334 tree.setFontStyle(tp.getTreeFont().getStyle());
1335 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1337 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1338 tree.setShowDistances(tp.distanceMenu.getState());
1340 tree.setHeight(tp.getHeight());
1341 tree.setWidth(tp.getWidth());
1342 tree.setXpos(tp.getX());
1343 tree.setYpos(tp.getY());
1344 tree.setId(makeHashCode(tp, null));
1345 tree.setLinkToAllViews(
1346 tp.getTreeCanvas().isApplyToAllViews());
1349 if (tp.isColumnWise())
1351 tree.setColumnWise(true);
1352 String annId = tp.getAssocAnnotation().annotationId;
1353 tree.setColumnReference(annId);
1355 // jms.addTree(tree);
1356 object.getTree().add(tree);
1366 if (!storeDS && Desktop.desktop != null)
1368 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1370 if (frame instanceof PCAPanel)
1372 PCAPanel panel = (PCAPanel) frame;
1373 if (panel.getAlignViewport().getAlignment() == jal)
1375 savePCA(panel, object);
1383 * store forward refs from an annotationRow to any groups
1385 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1388 for (SequenceI sq : jal.getSequences())
1390 // Store annotation on dataset sequences only
1391 AlignmentAnnotation[] aa = sq.getAnnotation();
1392 if (aa != null && aa.length > 0)
1394 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1401 if (jal.getAlignmentAnnotation() != null)
1403 // Store the annotation shown on the alignment.
1404 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1405 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1410 if (jal.getGroups() != null)
1412 JGroup[] groups = new JGroup[jal.getGroups().size()];
1414 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1416 JGroup jGroup = new JGroup();
1417 groups[++i] = jGroup;
1419 jGroup.setStart(sg.getStartRes());
1420 jGroup.setEnd(sg.getEndRes());
1421 jGroup.setName(sg.getName());
1422 if (groupRefs.containsKey(sg))
1424 // group has references so set its ID field
1425 jGroup.setId(groupRefs.get(sg));
1427 ColourSchemeI colourScheme = sg.getColourScheme();
1428 if (colourScheme != null)
1430 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1431 if (groupColourScheme.conservationApplied())
1433 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1435 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1437 jGroup.setColour(setUserColourScheme(colourScheme,
1438 userColours, object));
1442 jGroup.setColour(colourScheme.getSchemeName());
1445 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1447 jGroup.setColour("AnnotationColourGradient");
1448 jGroup.setAnnotationColours(constructAnnotationColours(
1449 (jalview.schemes.AnnotationColourGradient) colourScheme,
1450 userColours, object));
1452 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1455 setUserColourScheme(colourScheme, userColours, object));
1459 jGroup.setColour(colourScheme.getSchemeName());
1462 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1465 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1466 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1467 jGroup.setDisplayText(sg.getDisplayText());
1468 jGroup.setColourText(sg.getColourText());
1469 jGroup.setTextCol1(sg.textColour.getRGB());
1470 jGroup.setTextCol2(sg.textColour2.getRGB());
1471 jGroup.setTextColThreshold(sg.thresholdTextColour);
1472 jGroup.setShowUnconserved(sg.getShowNonconserved());
1473 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1474 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1475 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1476 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1477 for (SequenceI seq : sg.getSequences())
1479 // jGroup.addSeq(seqHash(seq));
1480 jGroup.getSeq().add(seqHash(seq));
1484 // jms.setJGroup(groups);
1486 for (JGroup grp : groups)
1488 object.getJGroup().add(grp);
1493 // /////////SAVE VIEWPORT
1494 Viewport view = new Viewport();
1495 view.setTitle(ap.alignFrame.getTitle());
1496 view.setSequenceSetId(
1497 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1498 view.setId(av.getViewId());
1499 if (av.getCodingComplement() != null)
1501 view.setComplementId(av.getCodingComplement().getViewId());
1503 view.setViewName(av.getViewName());
1504 view.setGatheredViews(av.isGatherViewsHere());
1506 Rectangle size = ap.av.getExplodedGeometry();
1507 Rectangle position = size;
1510 size = ap.alignFrame.getBounds();
1511 if (av.getCodingComplement() != null)
1513 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1521 view.setXpos(position.x);
1522 view.setYpos(position.y);
1524 view.setWidth(size.width);
1525 view.setHeight(size.height);
1527 view.setStartRes(vpRanges.getStartRes());
1528 view.setStartSeq(vpRanges.getStartSeq());
1530 OverviewPanel ov = ap.getOverviewPanel();
1533 Overview overview = new Overview();
1534 overview.setTitle(ov.getTitle());
1535 Rectangle bounds = ov.getFrameBounds();
1536 overview.setXpos(bounds.x);
1537 overview.setYpos(bounds.y);
1538 overview.setWidth(bounds.width);
1539 overview.setHeight(bounds.height);
1540 overview.setShowHidden(ov.isShowHiddenRegions());
1541 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1542 overview.setResidueColour(
1543 ov.getCanvas().getResidueColour().getRGB());
1544 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1545 view.setOverview(overview);
1547 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1549 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1550 userColours, object));
1553 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1555 AnnotationColourScheme ac = constructAnnotationColours(
1556 (jalview.schemes.AnnotationColourGradient) av
1557 .getGlobalColourScheme(),
1558 userColours, object);
1560 view.setAnnotationColours(ac);
1561 view.setBgColour("AnnotationColourGradient");
1565 view.setBgColour(ColourSchemeProperty
1566 .getColourName(av.getGlobalColourScheme()));
1569 ResidueShaderI vcs = av.getResidueShading();
1570 ColourSchemeI cs = av.getGlobalColourScheme();
1574 if (vcs.conservationApplied())
1576 view.setConsThreshold(vcs.getConservationInc());
1577 if (cs instanceof jalview.schemes.UserColourScheme)
1579 view.setBgColour(setUserColourScheme(cs, userColours, object));
1582 view.setPidThreshold(vcs.getThreshold());
1585 view.setConservationSelected(av.getConservationSelected());
1586 view.setPidSelected(av.getAbovePIDThreshold());
1587 view.setCharHeight(av.getCharHeight());
1588 view.setCharWidth(av.getCharWidth());
1589 final Font font = av.getFont();
1590 view.setFontName(font.getName());
1591 view.setFontSize(font.getSize());
1592 view.setFontStyle(font.getStyle());
1593 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1594 view.setRenderGaps(av.isRenderGaps());
1595 view.setShowAnnotation(av.isShowAnnotation());
1596 view.setShowBoxes(av.getShowBoxes());
1597 view.setShowColourText(av.getColourText());
1598 view.setShowFullId(av.getShowJVSuffix());
1599 view.setRightAlignIds(av.isRightAlignIds());
1600 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1601 view.setShowText(av.getShowText());
1602 view.setShowUnconserved(av.getShowUnconserved());
1603 view.setWrapAlignment(av.getWrapAlignment());
1604 view.setTextCol1(av.getTextColour().getRGB());
1605 view.setTextCol2(av.getTextColour2().getRGB());
1606 view.setTextColThreshold(av.getThresholdTextColour());
1607 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1608 view.setShowSequenceLogo(av.isShowSequenceLogo());
1609 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1610 view.setShowGroupConsensus(av.isShowGroupConsensus());
1611 view.setShowGroupConservation(av.isShowGroupConservation());
1612 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1613 view.setShowDbRefTooltip(av.isShowDBRefs());
1614 view.setFollowHighlight(av.isFollowHighlight());
1615 view.setFollowSelection(av.followSelection);
1616 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1617 view.setShowComplementFeatures(av.isShowComplementFeatures());
1618 view.setShowComplementFeaturesOnTop(
1619 av.isShowComplementFeaturesOnTop());
1620 if (av.getFeaturesDisplayed() != null)
1622 FeatureSettings fs = new FeatureSettings();
1624 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1625 .getFeatureRenderer();
1626 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1628 Vector<String> settingsAdded = new Vector<>();
1629 if (renderOrder != null)
1631 for (String featureType : renderOrder)
1633 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1634 setting.setType(featureType);
1637 * save any filter for the feature type
1639 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1642 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1644 FeatureMatcherI firstFilter = filters.next();
1645 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1646 filters, filter.isAnded()));
1650 * save colour scheme for the feature type
1652 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1653 if (!fcol.isSimpleColour())
1655 setting.setColour(fcol.getMaxColour().getRGB());
1656 setting.setMincolour(fcol.getMinColour().getRGB());
1657 setting.setMin(fcol.getMin());
1658 setting.setMax(fcol.getMax());
1659 setting.setColourByLabel(fcol.isColourByLabel());
1660 if (fcol.isColourByAttribute())
1662 String[] attName = fcol.getAttributeName();
1663 setting.getAttributeName().add(attName[0]);
1664 if (attName.length > 1)
1666 setting.getAttributeName().add(attName[1]);
1669 setting.setAutoScale(fcol.isAutoScaled());
1670 setting.setThreshold(fcol.getThreshold());
1671 Color noColour = fcol.getNoColour();
1672 if (noColour == null)
1674 setting.setNoValueColour(NoValueColour.NONE);
1676 else if (noColour.equals(fcol.getMaxColour()))
1678 setting.setNoValueColour(NoValueColour.MAX);
1682 setting.setNoValueColour(NoValueColour.MIN);
1684 // -1 = No threshold, 0 = Below, 1 = Above
1685 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1686 : (fcol.isBelowThreshold() ? 0 : -1));
1690 setting.setColour(fcol.getColour().getRGB());
1694 av.getFeaturesDisplayed().isVisible(featureType));
1695 float rorder = fr.getOrder(featureType);
1698 setting.setOrder(rorder);
1700 /// fs.addSetting(setting);
1701 fs.getSetting().add(setting);
1702 settingsAdded.addElement(featureType);
1706 // is groups actually supposed to be a map here ?
1707 Iterator<String> en = fr.getFeatureGroups().iterator();
1708 Vector<String> groupsAdded = new Vector<>();
1709 while (en.hasNext())
1711 String grp = en.next();
1712 if (groupsAdded.contains(grp))
1716 Group g = new Group();
1718 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1721 fs.getGroup().add(g);
1722 groupsAdded.addElement(grp);
1724 // jms.setFeatureSettings(fs);
1725 object.setFeatureSettings(fs);
1728 if (av.hasHiddenColumns())
1730 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1731 .getHiddenColumns();
1735 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1739 Iterator<int[]> hiddenRegions = hidden.iterator();
1740 while (hiddenRegions.hasNext())
1742 int[] region = hiddenRegions.next();
1743 HiddenColumns hc = new HiddenColumns();
1744 hc.setStart(region[0]);
1745 hc.setEnd(region[1]);
1746 // view.addHiddenColumns(hc);
1747 view.getHiddenColumns().add(hc);
1751 if (calcIdSet.size() > 0)
1753 for (String calcId : calcIdSet)
1755 if (calcId.trim().length() > 0)
1757 CalcIdParam cidp = createCalcIdParam(calcId, av);
1758 // Some calcIds have no parameters.
1761 // view.addCalcIdParam(cidp);
1762 view.getCalcIdParam().add(cidp);
1768 // jms.addViewport(view);
1769 object.getViewport().add(view);
1771 // object.setJalviewModelSequence(jms);
1772 // object.getVamsasModel().addSequenceSet(vamsasSet);
1773 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1775 if (jout != null && fileName != null)
1777 // We may not want to write the object to disk,
1778 // eg we can copy the alignViewport to a new view object
1779 // using save and then load
1782 fileName = fileName.replace('\\', '/');
1783 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1784 JarEntry entry = new JarEntry(fileName);
1785 jout.putNextEntry(entry);
1786 PrintWriter pout = new PrintWriter(
1787 new OutputStreamWriter(jout, UTF_8));
1788 JAXBContext jaxbContext = JAXBContext
1789 .newInstance(JalviewModel.class);
1790 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1792 // output pretty printed
1793 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1794 jaxbMarshaller.marshal(
1795 new ObjectFactory().createJalviewModel(object), pout);
1797 // jaxbMarshaller.marshal(object, pout);
1798 // marshaller.marshal(object);
1801 } catch (Exception ex)
1803 // TODO: raise error in GUI if marshalling failed.
1804 jalview.bin.Console.errPrintln("Error writing Jalview project");
1805 ex.printStackTrace();
1812 * Writes PCA viewer attributes and computed values to an XML model object and
1813 * adds it to the JalviewModel. Any exceptions are reported by logging.
1815 protected void savePCA(PCAPanel panel, JalviewModel object)
1819 PcaViewer viewer = new PcaViewer();
1820 viewer.setHeight(panel.getHeight());
1821 viewer.setWidth(panel.getWidth());
1822 viewer.setXpos(panel.getX());
1823 viewer.setYpos(panel.getY());
1824 viewer.setTitle(panel.getTitle());
1825 PCAModel pcaModel = panel.getPcaModel();
1826 viewer.setScoreModelName(pcaModel.getScoreModelName());
1827 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1828 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1829 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1831 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1832 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1833 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1834 SeqPointMin spmin = new SeqPointMin();
1835 spmin.setXPos(spMin[0]);
1836 spmin.setYPos(spMin[1]);
1837 spmin.setZPos(spMin[2]);
1838 viewer.setSeqPointMin(spmin);
1839 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1840 SeqPointMax spmax = new SeqPointMax();
1841 spmax.setXPos(spMax[0]);
1842 spmax.setYPos(spMax[1]);
1843 spmax.setZPos(spMax[2]);
1844 viewer.setSeqPointMax(spmax);
1845 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1846 viewer.setLinkToAllViews(
1847 panel.getRotatableCanvas().isApplyToAllViews());
1848 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1849 viewer.setIncludeGaps(sp.includeGaps());
1850 viewer.setMatchGaps(sp.matchGaps());
1851 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1852 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1855 * sequence points on display
1857 for (jalview.datamodel.SequencePoint spt : pcaModel
1858 .getSequencePoints())
1860 SequencePoint point = new SequencePoint();
1861 point.setSequenceRef(seqHash(spt.getSequence()));
1862 point.setXPos(spt.coord.x);
1863 point.setYPos(spt.coord.y);
1864 point.setZPos(spt.coord.z);
1865 viewer.getSequencePoint().add(point);
1869 * (end points of) axes on display
1871 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1874 Axis axis = new Axis();
1878 viewer.getAxis().add(axis);
1882 * raw PCA data (note we are not restoring PCA inputs here -
1883 * alignment view, score model, similarity parameters)
1885 PcaDataType data = new PcaDataType();
1886 viewer.setPcaData(data);
1887 PCA pca = pcaModel.getPcaData();
1889 DoubleMatrix pm = new DoubleMatrix();
1890 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1891 data.setPairwiseMatrix(pm);
1893 DoubleMatrix tm = new DoubleMatrix();
1894 saveDoubleMatrix(pca.getTridiagonal(), tm);
1895 data.setTridiagonalMatrix(tm);
1897 DoubleMatrix eigenMatrix = new DoubleMatrix();
1898 data.setEigenMatrix(eigenMatrix);
1899 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1901 object.getPcaViewer().add(viewer);
1902 } catch (Throwable t)
1904 Console.error("Error saving PCA: " + t.getMessage());
1909 * Stores values from a matrix into an XML element, including (if present) the
1914 * @see #loadDoubleMatrix(DoubleMatrix)
1916 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1918 xmlMatrix.setRows(m.height());
1919 xmlMatrix.setColumns(m.width());
1920 for (int i = 0; i < m.height(); i++)
1922 DoubleVector row = new DoubleVector();
1923 for (int j = 0; j < m.width(); j++)
1925 row.getV().add(m.getValue(i, j));
1927 xmlMatrix.getRow().add(row);
1929 if (m.getD() != null)
1931 DoubleVector dVector = new DoubleVector();
1932 for (double d : m.getD())
1934 dVector.getV().add(d);
1936 xmlMatrix.setD(dVector);
1938 if (m.getE() != null)
1940 DoubleVector eVector = new DoubleVector();
1941 for (double e : m.getE())
1943 eVector.getV().add(e);
1945 xmlMatrix.setE(eVector);
1950 * Loads XML matrix data into a new Matrix object, including the D and/or E
1951 * vectors (if present)
1955 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1957 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1959 int rows = mData.getRows();
1960 double[][] vals = new double[rows][];
1962 for (int i = 0; i < rows; i++)
1964 List<Double> dVector = mData.getRow().get(i).getV();
1965 vals[i] = new double[dVector.size()];
1967 for (Double d : dVector)
1973 MatrixI m = new Matrix(vals);
1975 if (mData.getD() != null)
1977 List<Double> dVector = mData.getD().getV();
1978 double[] vec = new double[dVector.size()];
1980 for (Double d : dVector)
1986 if (mData.getE() != null)
1988 List<Double> dVector = mData.getE().getV();
1989 double[] vec = new double[dVector.size()];
1991 for (Double d : dVector)
2002 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2003 * for each viewer, with
2005 * <li>viewer geometry (position, size, split pane divider location)</li>
2006 * <li>index of the selected structure in the viewer (currently shows gapped
2008 * <li>the id of the annotation holding RNA secondary structure</li>
2009 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2011 * Varna viewer state is also written out (in native Varna XML) to separate
2012 * project jar entries. A separate entry is written for each RNA structure
2013 * displayed, with the naming convention
2015 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2023 * @param storeDataset
2025 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2026 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2027 boolean storeDataset)
2029 if (Desktop.desktop == null)
2033 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2034 for (int f = frames.length - 1; f > -1; f--)
2036 if (frames[f] instanceof AppVarna)
2038 AppVarna varna = (AppVarna) frames[f];
2040 * link the sequence to every viewer that is showing it and is linked to
2041 * its alignment panel
2043 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2045 String viewId = varna.getViewId();
2046 RnaViewer rna = new RnaViewer();
2047 rna.setViewId(viewId);
2048 rna.setTitle(varna.getTitle());
2049 rna.setXpos(varna.getX());
2050 rna.setYpos(varna.getY());
2051 rna.setWidth(varna.getWidth());
2052 rna.setHeight(varna.getHeight());
2053 rna.setDividerLocation(varna.getDividerLocation());
2054 rna.setSelectedRna(varna.getSelectedIndex());
2055 // jseq.addRnaViewer(rna);
2056 jseq.getRnaViewer().add(rna);
2059 * Store each Varna panel's state once in the project per sequence.
2060 * First time through only (storeDataset==false)
2062 // boolean storeSessions = false;
2063 // String sequenceViewId = viewId + seqsToIds.get(jds);
2064 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2066 // viewIds.add(sequenceViewId);
2067 // storeSessions = true;
2069 for (RnaModel model : varna.getModels())
2071 if (model.seq == jds)
2074 * VARNA saves each view (sequence or alignment secondary
2075 * structure, gapped or trimmed) as a separate XML file
2077 String jarEntryName = rnaSessions.get(model);
2078 if (jarEntryName == null)
2081 String varnaStateFile = varna.getStateInfo(model.rna);
2082 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2083 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2084 rnaSessions.put(model, jarEntryName);
2086 SecondaryStructure ss = new SecondaryStructure();
2087 String annotationId = varna.getAnnotation(jds).annotationId;
2088 ss.setAnnotationId(annotationId);
2089 ss.setViewerState(jarEntryName);
2090 ss.setGapped(model.gapped);
2091 ss.setTitle(model.title);
2092 // rna.addSecondaryStructure(ss);
2093 rna.getSecondaryStructure().add(ss);
2102 * Copy the contents of a file to a new entry added to the output jar
2106 * @param jarEntryName
2108 * additional identifying info to log to the console
2110 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2111 String jarEntryName, String msg)
2113 try (InputStream is = new FileInputStream(infilePath))
2115 File file = new File(infilePath);
2116 if (file.exists() && jout != null)
2118 jalview.bin.Console.outPrintln(
2119 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2120 jout.putNextEntry(new JarEntry(jarEntryName));
2123 // dis = new DataInputStream(new FileInputStream(file));
2124 // byte[] data = new byte[(int) file.length()];
2125 // dis.readFully(data);
2126 // writeJarEntry(jout, jarEntryName, data);
2128 } catch (Exception ex)
2130 ex.printStackTrace();
2135 * Copies input to output, in 4K buffers; handles any data (text or binary)
2139 * @throws IOException
2141 protected void copyAll(InputStream in, OutputStream out)
2144 byte[] buffer = new byte[4096];
2146 while ((bytesRead = in.read(buffer)) != -1)
2148 out.write(buffer, 0, bytesRead);
2153 * Save the state of a structure viewer
2158 * the archive XML element under which to save the state
2161 * @param matchedFile
2165 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2166 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2167 String matchedFile, StructureViewerBase viewFrame)
2169 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2172 * Look for any bindings for this viewer to the PDB file of interest
2173 * (including part matches excluding chain id)
2175 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2177 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2178 final String pdbId = pdbentry.getId();
2179 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2180 && entry.getId().toLowerCase(Locale.ROOT)
2181 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2184 * not interested in a binding to a different PDB entry here
2188 if (matchedFile == null)
2190 matchedFile = pdbentry.getFile();
2192 else if (!matchedFile.equals(pdbentry.getFile()))
2195 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2196 + pdbentry.getFile());
2200 // can get at it if the ID
2201 // match is ambiguous (e.g.
2204 for (int smap = 0; smap < viewFrame.getBinding()
2205 .getSequence()[peid].length; smap++)
2207 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2208 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2210 StructureState state = new StructureState();
2211 state.setVisible(true);
2212 state.setXpos(viewFrame.getX());
2213 state.setYpos(viewFrame.getY());
2214 state.setWidth(viewFrame.getWidth());
2215 state.setHeight(viewFrame.getHeight());
2216 final String viewId = viewFrame.getViewId();
2217 state.setViewId(viewId);
2218 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2219 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2220 state.setColourByJmol(viewFrame.isColouredByViewer());
2221 state.setType(viewFrame.getViewerType().toString());
2222 // pdb.addStructureState(state);
2223 pdb.getStructureState().add(state);
2231 * Populates the AnnotationColourScheme xml for save. This captures the
2232 * settings of the options in the 'Colour by Annotation' dialog.
2235 * @param userColours
2239 private AnnotationColourScheme constructAnnotationColours(
2240 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2243 AnnotationColourScheme ac = new AnnotationColourScheme();
2244 ac.setAboveThreshold(acg.getAboveThreshold());
2245 ac.setThreshold(acg.getAnnotationThreshold());
2246 // 2.10.2 save annotationId (unique) not annotation label
2247 ac.setAnnotation(acg.getAnnotation().annotationId);
2248 if (acg.getBaseColour() instanceof UserColourScheme)
2251 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2256 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2259 ac.setMaxColour(acg.getMaxColour().getRGB());
2260 ac.setMinColour(acg.getMinColour().getRGB());
2261 ac.setPerSequence(acg.isSeqAssociated());
2262 ac.setPredefinedColours(acg.isPredefinedColours());
2266 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2267 IdentityHashMap<SequenceGroup, String> groupRefs,
2268 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2269 SequenceSet vamsasSet)
2272 for (int i = 0; i < aa.length; i++)
2274 Annotation an = new Annotation();
2276 AlignmentAnnotation annotation = aa[i];
2277 if (annotation.annotationId != null)
2279 annotationIds.put(annotation.annotationId, annotation);
2282 an.setId(annotation.annotationId);
2284 an.setVisible(annotation.visible);
2286 an.setDescription(annotation.description);
2288 if (annotation.sequenceRef != null)
2290 // 2.9 JAL-1781 xref on sequence id rather than name
2291 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2293 if (annotation.groupRef != null)
2295 String groupIdr = groupRefs.get(annotation.groupRef);
2296 if (groupIdr == null)
2298 // make a locally unique String
2299 groupRefs.put(annotation.groupRef,
2300 groupIdr = ("" + System.currentTimeMillis()
2301 + annotation.groupRef.getName()
2302 + groupRefs.size()));
2304 an.setGroupRef(groupIdr.toString());
2307 // store all visualization attributes for annotation
2308 an.setGraphHeight(annotation.graphHeight);
2309 an.setCentreColLabels(annotation.centreColLabels);
2310 an.setScaleColLabels(annotation.scaleColLabel);
2311 an.setShowAllColLabels(annotation.showAllColLabels);
2312 an.setBelowAlignment(annotation.belowAlignment);
2314 if (annotation.graph > 0)
2317 an.setGraphType(annotation.graph);
2318 an.setGraphGroup(annotation.graphGroup);
2319 if (annotation.getThreshold() != null)
2321 ThresholdLine line = new ThresholdLine();
2322 line.setLabel(annotation.getThreshold().label);
2323 line.setValue(annotation.getThreshold().value);
2324 line.setColour(annotation.getThreshold().colour.getRGB());
2325 an.setThresholdLine(line);
2327 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2329 if (annotation.sequenceRef.getContactMaps() != null)
2331 ContactMatrixI cm = annotation.sequenceRef
2332 .getContactMatrixFor(annotation);
2335 MatrixType xmlmat = new MatrixType();
2336 xmlmat.setType(cm.getType());
2337 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2338 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2339 // consider using an opaque to/from -> allow instance to control
2340 // its representation ?
2341 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2344 for (BitSet gp : cm.getGroups())
2346 xmlmat.getGroups().add(stringifyBitset(gp));
2351 // provenance object for tree ?
2352 xmlmat.getNewick().add(cm.getNewick());
2353 xmlmat.setTreeMethod(cm.getTreeMethod());
2355 if (cm.hasCutHeight())
2357 xmlmat.setCutHeight(cm.getCutHeight());
2359 // set/get properties
2360 if (cm instanceof MappableContactMatrixI)
2362 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2363 .getMapFor(annotation.sequenceRef);
2366 MapListType mp = new MapListType();
2367 List<int[]> r = mlst.getFromRanges();
2368 for (int[] range : r)
2370 MapListFrom mfrom = new MapListFrom();
2371 mfrom.setStart(range[0]);
2372 mfrom.setEnd(range[1]);
2373 // mp.addMapListFrom(mfrom);
2374 mp.getMapListFrom().add(mfrom);
2376 r = mlst.getToRanges();
2377 for (int[] range : r)
2379 MapListTo mto = new MapListTo();
2380 mto.setStart(range[0]);
2381 mto.setEnd(range[1]);
2382 // mp.addMapListTo(mto);
2383 mp.getMapListTo().add(mto);
2386 BigInteger.valueOf(mlst.getFromRatio()));
2387 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2388 xmlmat.setMapping(mp);
2392 an.getContactmatrix().add(xmlmat);
2402 an.setLabel(annotation.label);
2404 if (annotation == av.getAlignmentQualityAnnot()
2405 || annotation == av.getAlignmentConservationAnnotation()
2406 || annotation == av.getAlignmentConsensusAnnotation()
2407 || annotation.autoCalculated)
2409 // new way of indicating autocalculated annotation -
2410 an.setAutoCalculated(annotation.autoCalculated);
2412 if (annotation.hasScore())
2414 an.setScore(annotation.getScore());
2417 if (annotation.getCalcId() != null)
2419 calcIdSet.add(annotation.getCalcId());
2420 an.setCalcId(annotation.getCalcId());
2422 if (annotation.hasProperties())
2424 for (String pr : annotation.getProperties())
2426 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2428 prop.setValue(annotation.getProperty(pr));
2429 an.getProperty().add(prop);
2433 AnnotationElement ae;
2434 if (annotation.annotations != null)
2436 an.setScoreOnly(false);
2437 for (int a = 0; a < annotation.annotations.length; a++)
2439 if ((annotation == null) || (annotation.annotations[a] == null))
2444 ae = new AnnotationElement();
2445 if (annotation.annotations[a].description != null)
2447 ae.setDescription(annotation.annotations[a].description);
2449 if (annotation.annotations[a].displayCharacter != null)
2451 ae.setDisplayCharacter(
2452 annotation.annotations[a].displayCharacter);
2455 if (!Float.isNaN(annotation.annotations[a].value))
2457 ae.setValue(annotation.annotations[a].value);
2461 if (annotation.annotations[a].secondaryStructure > ' ')
2463 ae.setSecondaryStructure(
2464 annotation.annotations[a].secondaryStructure + "");
2467 if (annotation.annotations[a].colour != null
2468 && annotation.annotations[a].colour != java.awt.Color.black)
2470 ae.setColour(annotation.annotations[a].colour.getRGB());
2473 // an.addAnnotationElement(ae);
2474 an.getAnnotationElement().add(ae);
2475 if (annotation.autoCalculated)
2477 // only write one non-null entry into the annotation row -
2478 // sufficient to get the visualization attributes necessary to
2486 an.setScoreOnly(true);
2488 if (!storeDS || (storeDS && !annotation.autoCalculated))
2490 // skip autocalculated annotation - these are only provided for
2492 // vamsasSet.addAnnotation(an);
2493 vamsasSet.getAnnotation().add(an);
2499 private String stringifyBitset(BitSet gp)
2501 StringBuilder sb = new StringBuilder();
2502 for (long val : gp.toLongArray())
2504 if (sb.length() > 0)
2510 return sb.toString();
2513 private BitSet deStringifyBitset(String stringified)
2515 if ("".equals(stringified) || stringified == null)
2517 return new BitSet();
2519 String[] longvals = stringified.split(",");
2520 long[] newlongvals = new long[longvals.length];
2521 for (int lv = 0; lv < longvals.length; lv++)
2525 newlongvals[lv] = Long.valueOf(longvals[lv]);
2526 } catch (Exception x)
2528 errorMessage += "Couldn't destringify bitset from: '" + stringified
2530 newlongvals[lv] = 0;
2533 return BitSet.valueOf(newlongvals);
2537 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2539 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2540 if (settings != null)
2542 CalcIdParam vCalcIdParam = new CalcIdParam();
2543 vCalcIdParam.setCalcId(calcId);
2544 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2545 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2546 // generic URI allowing a third party to resolve another instance of the
2547 // service used for this calculation
2548 for (String url : settings.getServiceURLs())
2550 // vCalcIdParam.addServiceURL(urls);
2551 vCalcIdParam.getServiceURL().add(url);
2553 vCalcIdParam.setVersion("1.0");
2554 if (settings.getPreset() != null)
2556 WsParamSetI setting = settings.getPreset();
2557 vCalcIdParam.setName(setting.getName());
2558 vCalcIdParam.setDescription(setting.getDescription());
2562 vCalcIdParam.setName("");
2563 vCalcIdParam.setDescription("Last used parameters");
2565 // need to be able to recover 1) settings 2) user-defined presets or
2566 // recreate settings from preset 3) predefined settings provided by
2567 // service - or settings that can be transferred (or discarded)
2568 vCalcIdParam.setParameters(
2569 settings.getWsParamFile().replace("\n", "|\\n|"));
2570 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2571 // todo - decide if updateImmediately is needed for any projects.
2573 return vCalcIdParam;
2578 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2581 if (calcIdParam.getVersion().equals("1.0"))
2583 final String[] calcIds = calcIdParam.getServiceURL()
2584 .toArray(new String[0]);
2585 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2586 .getPreferredServiceFor(calcIds);
2587 if (service != null)
2589 WsParamSetI parmSet = null;
2592 parmSet = service.getParamStore().parseServiceParameterFile(
2593 calcIdParam.getName(), calcIdParam.getDescription(),
2595 calcIdParam.getParameters().replace("|\\n|", "\n"));
2596 } catch (IOException x)
2598 Console.warn("Couldn't parse parameter data for "
2599 + calcIdParam.getCalcId(), x);
2602 List<ArgumentI> argList = null;
2603 if (calcIdParam.getName().length() > 0)
2605 parmSet = service.getParamStore()
2606 .getPreset(calcIdParam.getName());
2607 if (parmSet != null)
2609 // TODO : check we have a good match with settings in AACon -
2610 // otherwise we'll need to create a new preset
2615 argList = parmSet.getArguments();
2618 AAConSettings settings = new AAConSettings(
2619 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2620 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2621 calcIdParam.isNeedsUpdate());
2627 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2631 throw new Error(MessageManager.formatMessage(
2632 "error.unsupported_version_calcIdparam", new Object[]
2633 { calcIdParam.toString() }));
2637 * External mapping between jalview objects and objects yielding a valid and
2638 * unique object ID string. This is null for normal Jalview project IO, but
2639 * non-null when a jalview project is being read or written as part of a
2642 IdentityHashMap jv2vobj = null;
2645 * Construct a unique ID for jvobj using either existing bindings or if none
2646 * exist, the result of the hashcode call for the object.
2649 * jalview data object
2650 * @return unique ID for referring to jvobj
2652 private String makeHashCode(Object jvobj, String altCode)
2654 if (jv2vobj != null)
2656 Object id = jv2vobj.get(jvobj);
2659 return id.toString();
2661 // check string ID mappings
2662 if (jvids2vobj != null && jvobj instanceof String)
2664 id = jvids2vobj.get(jvobj);
2668 return id.toString();
2670 // give up and warn that something has gone wrong
2672 "Cannot find ID for object in external mapping : " + jvobj);
2678 * return local jalview object mapped to ID, if it exists
2682 * @return null or object bound to idcode
2684 private Object retrieveExistingObj(String idcode)
2686 if (idcode != null && vobj2jv != null)
2688 return vobj2jv.get(idcode);
2694 * binding from ID strings from external mapping table to jalview data model
2697 private Hashtable vobj2jv;
2699 private Sequence createVamsasSequence(String id, SequenceI jds)
2701 return createVamsasSequence(true, id, jds, null);
2704 private Sequence createVamsasSequence(boolean recurse, String id,
2705 SequenceI jds, SequenceI parentseq)
2707 Sequence vamsasSeq = new Sequence();
2708 vamsasSeq.setId(id);
2709 vamsasSeq.setName(jds.getName());
2710 vamsasSeq.setSequence(jds.getSequenceAsString());
2711 vamsasSeq.setDescription(jds.getDescription());
2712 List<DBRefEntry> dbrefs = null;
2713 if (jds.getDatasetSequence() != null)
2715 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2719 // seqId==dsseqid so we can tell which sequences really are
2720 // dataset sequences only
2721 vamsasSeq.setDsseqid(id);
2722 dbrefs = jds.getDBRefs();
2723 if (parentseq == null)
2730 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2734 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2736 DBRef dbref = new DBRef();
2737 DBRefEntry ref = dbrefs.get(d);
2738 dbref.setSource(ref.getSource());
2739 dbref.setVersion(ref.getVersion());
2740 dbref.setAccessionId(ref.getAccessionId());
2741 dbref.setCanonical(ref.isCanonical());
2742 if (ref instanceof GeneLocus)
2744 dbref.setLocus(true);
2748 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2750 dbref.setMapping(mp);
2752 vamsasSeq.getDBRef().add(dbref);
2758 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2759 SequenceI parentseq, SequenceI jds, boolean recurse)
2762 if (jmp.getMap() != null)
2766 jalview.util.MapList mlst = jmp.getMap();
2767 List<int[]> r = mlst.getFromRanges();
2768 for (int[] range : r)
2770 MapListFrom mfrom = new MapListFrom();
2771 mfrom.setStart(range[0]);
2772 mfrom.setEnd(range[1]);
2773 // mp.addMapListFrom(mfrom);
2774 mp.getMapListFrom().add(mfrom);
2776 r = mlst.getToRanges();
2777 for (int[] range : r)
2779 MapListTo mto = new MapListTo();
2780 mto.setStart(range[0]);
2781 mto.setEnd(range[1]);
2782 // mp.addMapListTo(mto);
2783 mp.getMapListTo().add(mto);
2785 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2786 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2787 if (jmp.getTo() != null)
2789 // MappingChoice mpc = new MappingChoice();
2791 // check/create ID for the sequence referenced by getTo()
2794 SequenceI ps = null;
2795 if (parentseq != jmp.getTo()
2796 && parentseq.getDatasetSequence() != jmp.getTo())
2798 // chaining dbref rather than a handshaking one
2799 jmpid = seqHash(ps = jmp.getTo());
2803 jmpid = seqHash(ps = parentseq);
2805 // mpc.setDseqFor(jmpid);
2806 mp.setDseqFor(jmpid);
2807 if (!seqRefIds.containsKey(jmpid))
2809 Console.debug("creatign new DseqFor ID");
2810 seqRefIds.put(jmpid, ps);
2814 Console.debug("reusing DseqFor ID");
2817 // mp.setMappingChoice(mpc);
2823 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2824 List<UserColourScheme> userColours, JalviewModel jm)
2827 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2828 boolean newucs = false;
2829 if (!userColours.contains(ucs))
2831 userColours.add(ucs);
2834 id = "ucs" + userColours.indexOf(ucs);
2837 // actually create the scheme's entry in the XML model
2838 java.awt.Color[] colours = ucs.getColours();
2839 UserColours uc = new UserColours();
2840 // UserColourScheme jbucs = new UserColourScheme();
2841 JalviewUserColours jbucs = new JalviewUserColours();
2843 for (int i = 0; i < colours.length; i++)
2845 Colour col = new Colour();
2846 col.setName(ResidueProperties.aa[i]);
2847 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2848 // jbucs.addColour(col);
2849 jbucs.getColour().add(col);
2851 if (ucs.getLowerCaseColours() != null)
2853 colours = ucs.getLowerCaseColours();
2854 for (int i = 0; i < colours.length; i++)
2856 Colour col = new Colour();
2857 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2858 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2859 // jbucs.addColour(col);
2860 jbucs.getColour().add(col);
2865 uc.setUserColourScheme(jbucs);
2866 // jm.addUserColours(uc);
2867 jm.getUserColours().add(uc);
2873 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2876 List<UserColours> uc = jm.getUserColours();
2877 UserColours colours = null;
2879 for (int i = 0; i < uc.length; i++)
2881 if (uc[i].getId().equals(id))
2888 for (UserColours c : uc)
2890 if (c.getId().equals(id))
2897 java.awt.Color[] newColours = new java.awt.Color[24];
2899 for (int i = 0; i < 24; i++)
2901 newColours[i] = new java.awt.Color(Integer.parseInt(
2902 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2903 colours.getUserColourScheme().getColour().get(i).getRGB(),
2907 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2910 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2912 newColours = new java.awt.Color[23];
2913 for (int i = 0; i < 23; i++)
2915 newColours[i] = new java.awt.Color(
2916 Integer.parseInt(colours.getUserColourScheme().getColour()
2917 .get(i + 24).getRGB(), 16));
2919 ucs.setLowerCaseColours(newColours);
2926 * contains last error message (if any) encountered by XML loader.
2928 String errorMessage = null;
2931 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2932 * exceptions are raised during project XML parsing
2934 public boolean attemptversion1parse = false;
2937 * Load a jalview project archive from a jar file
2940 * - HTTP URL or filename
2942 public AlignFrame loadJalviewAlign(final Object file)
2945 jalview.gui.AlignFrame af = null;
2949 // create list to store references for any new Jmol viewers created
2950 newStructureViewers = new Vector<>();
2951 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2952 // Workaround is to make sure caller implements the JarInputStreamProvider
2954 // so we can re-open the jar input stream for each entry.
2956 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2957 af = loadJalviewAlign(jprovider);
2960 af.setMenusForViewport();
2962 } catch (MalformedURLException e)
2964 errorMessage = "Invalid URL format for '" + file + "'";
2970 SwingUtilities.invokeAndWait(new Runnable()
2975 setLoadingFinishedForNewStructureViewers();
2978 } catch (Exception x)
2981 .errPrintln("Error loading alignment: " + x.getMessage());
2987 @SuppressWarnings("unused")
2988 private jarInputStreamProvider createjarInputStreamProvider(
2989 final Object ofile) throws MalformedURLException
2992 // BH 2018 allow for bytes already attached to File object
2995 String file = (ofile instanceof File
2996 ? ((File) ofile).getCanonicalPath()
2997 : ofile.toString());
2998 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3001 errorMessage = null;
3002 uniqueSetSuffix = null;
3004 viewportsAdded.clear();
3005 frefedSequence = null;
3007 if (HttpUtils.startsWithHttpOrHttps(file))
3009 url = new URL(file);
3011 final URL _url = url;
3012 return new jarInputStreamProvider()
3016 public JarInputStream getJarInputStream() throws IOException
3020 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3021 // jarInputStream for
3022 // bytes.length=" + bytes.length);
3023 return new JarInputStream(new ByteArrayInputStream(bytes));
3027 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3028 // jarInputStream for "
3030 return new JarInputStream(_url.openStream());
3034 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3035 // jarInputStream for
3037 return new JarInputStream(new FileInputStream(file));
3042 public String getFilename()
3047 } catch (IOException e)
3049 e.printStackTrace();
3055 * Recover jalview session from a jalview project archive. Caller may
3056 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3057 * themselves. Any null fields will be initialised with default values,
3058 * non-null fields are left alone.
3063 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3065 errorMessage = null;
3066 if (uniqueSetSuffix == null)
3068 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3070 if (seqRefIds == null)
3074 AlignFrame af = null, _af = null;
3075 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3076 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3077 final String file = jprovider.getFilename();
3080 JarInputStream jin = null;
3081 JarEntry jarentry = null;
3086 jin = jprovider.getJarInputStream();
3087 for (int i = 0; i < entryCount; i++)
3089 jarentry = jin.getNextJarEntry();
3092 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3094 JAXBContext jc = JAXBContext
3095 .newInstance("jalview.xml.binding.jalview");
3096 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3097 .createXMLStreamReader(jin);
3098 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3099 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3100 JalviewModel.class);
3101 JalviewModel object = jbe.getValue();
3103 if (true) // !skipViewport(object))
3105 _af = loadFromObject(object, file, true, jprovider);
3106 if (_af != null && object.getViewport().size() > 0)
3107 // getJalviewModelSequence().getViewportCount() > 0)
3111 // store a reference to the first view
3114 if (_af.getViewport().isGatherViewsHere())
3116 // if this is a gathered view, keep its reference since
3117 // after gathering views, only this frame will remain
3119 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3122 // Save dataset to register mappings once all resolved
3123 importedDatasets.put(
3124 af.getViewport().getAlignment().getDataset(),
3125 af.getViewport().getAlignment().getDataset());
3130 else if (jarentry != null)
3132 // Some other file here.
3135 } while (jarentry != null);
3137 resolveFrefedSequences();
3138 } catch (IOException ex)
3140 ex.printStackTrace();
3141 errorMessage = "Couldn't locate Jalview XML file : " + file;
3142 jalview.bin.Console.errPrintln(
3143 "Exception whilst loading jalview XML file : " + ex + "\n");
3144 } catch (Exception ex)
3147 .errPrintln("Parsing as Jalview Version 2 file failed.");
3148 ex.printStackTrace(System.err);
3149 if (attemptversion1parse)
3151 // used to attempt to parse as V1 castor-generated xml
3153 if (Desktop.instance != null)
3155 Desktop.instance.stopLoading();
3159 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3162 ex.printStackTrace();
3164 jalview.bin.Console.errPrintln(
3165 "Exception whilst loading jalview XML file : " + ex + "\n");
3166 } catch (OutOfMemoryError e)
3168 // Don't use the OOM Window here
3169 errorMessage = "Out of memory loading jalview XML file";
3171 .errPrintln("Out of memory whilst loading jalview XML file");
3172 e.printStackTrace();
3176 * Regather multiple views (with the same sequence set id) to the frame (if
3177 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3178 * views instead of separate frames. Note this doesn't restore a state where
3179 * some expanded views in turn have tabbed views - the last "first tab" read
3180 * in will play the role of gatherer for all.
3182 for (AlignFrame fr : gatherToThisFrame.values())
3184 Desktop.instance.gatherViews(fr);
3187 restoreSplitFrames();
3188 for (AlignmentI ds : importedDatasets.keySet())
3190 if (ds.getCodonFrames() != null)
3192 StructureSelectionManager
3193 .getStructureSelectionManager(Desktop.instance)
3194 .registerMappings(ds.getCodonFrames());
3197 if (errorMessage != null)
3202 if (Desktop.instance != null)
3204 Desktop.instance.stopLoading();
3211 * Try to reconstruct and display SplitFrame windows, where each contains
3212 * complementary dna and protein alignments. Done by pairing up AlignFrame
3213 * objects (created earlier) which have complementary viewport ids associated.
3215 protected void restoreSplitFrames()
3217 List<SplitFrame> gatherTo = new ArrayList<>();
3218 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3219 Map<String, AlignFrame> dna = new HashMap<>();
3222 * Identify the DNA alignments
3224 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3227 AlignFrame af = candidate.getValue();
3228 if (af.getViewport().getAlignment().isNucleotide())
3230 dna.put(candidate.getKey().getId(), af);
3235 * Try to match up the protein complements
3237 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3240 AlignFrame af = candidate.getValue();
3241 if (!af.getViewport().getAlignment().isNucleotide())
3243 String complementId = candidate.getKey().getComplementId();
3244 // only non-null complements should be in the Map
3245 if (complementId != null && dna.containsKey(complementId))
3247 final AlignFrame dnaFrame = dna.get(complementId);
3248 SplitFrame sf = createSplitFrame(dnaFrame, af);
3249 addedToSplitFrames.add(dnaFrame);
3250 addedToSplitFrames.add(af);
3251 dnaFrame.setMenusForViewport();
3252 af.setMenusForViewport();
3253 if (af.getViewport().isGatherViewsHere())
3262 * Open any that we failed to pair up (which shouldn't happen!) as
3263 * standalone AlignFrame's.
3265 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3268 AlignFrame af = candidate.getValue();
3269 if (!addedToSplitFrames.contains(af))
3271 Viewport view = candidate.getKey();
3272 Desktop.addInternalFrame(af, view.getTitle(),
3273 safeInt(view.getWidth()), safeInt(view.getHeight()));
3274 af.setMenusForViewport();
3275 jalview.bin.Console.errPrintln("Failed to restore view "
3276 + view.getTitle() + " to split frame");
3281 * Gather back into tabbed views as flagged.
3283 for (SplitFrame sf : gatherTo)
3285 Desktop.instance.gatherViews(sf);
3288 splitFrameCandidates.clear();
3292 * Construct and display one SplitFrame holding DNA and protein alignments.
3295 * @param proteinFrame
3298 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3299 AlignFrame proteinFrame)
3301 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3302 String title = MessageManager.getString("label.linked_view_title");
3303 int width = (int) dnaFrame.getBounds().getWidth();
3304 int height = (int) (dnaFrame.getBounds().getHeight()
3305 + proteinFrame.getBounds().getHeight() + 50);
3308 * SplitFrame location is saved to both enclosed frames
3310 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3311 Desktop.addInternalFrame(splitFrame, title, width, height);
3314 * And compute cDNA consensus (couldn't do earlier with consensus as
3315 * mappings were not yet present)
3317 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3323 * check errorMessage for a valid error message and raise an error box in the
3324 * GUI or write the current errorMessage to stderr and then clear the error
3327 protected void reportErrors()
3329 reportErrors(false);
3332 protected void reportErrors(final boolean saving)
3334 if (errorMessage != null)
3336 final String finalErrorMessage = errorMessage;
3339 javax.swing.SwingUtilities.invokeLater(new Runnable()
3344 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3346 "Error " + (saving ? "saving" : "loading")
3348 JvOptionPane.WARNING_MESSAGE);
3354 jalview.bin.Console.errPrintln(
3355 "Problem loading Jalview file: " + errorMessage);
3358 errorMessage = null;
3361 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3364 * when set, local views will be updated from view stored in JalviewXML
3365 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3366 * sync if this is set to true.
3368 private final boolean updateLocalViews = false;
3371 * Returns the path to a temporary file holding the PDB file for the given PDB
3372 * id. The first time of asking, searches for a file of that name in the
3373 * Jalview project jar, and copies it to a new temporary file. Any repeat
3374 * requests just return the path to the file previously created.
3380 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3383 if (alreadyLoadedPDB.containsKey(pdbId))
3385 return alreadyLoadedPDB.get(pdbId).toString();
3388 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3390 if (tempFile != null)
3392 alreadyLoadedPDB.put(pdbId, tempFile);
3398 * Copies the jar entry of given name to a new temporary file and returns the
3399 * path to the file, or null if the entry is not found.
3402 * @param jarEntryName
3404 * a prefix for the temporary file name, must be at least three
3406 * @param suffixModel
3407 * null or original file - so new file can be given the same suffix
3411 protected String copyJarEntry(jarInputStreamProvider jprovider,
3412 String jarEntryName, String prefix, String suffixModel)
3414 String suffix = ".tmp";
3415 if (suffixModel == null)
3417 suffixModel = jarEntryName;
3419 int sfpos = suffixModel.lastIndexOf(".");
3420 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3422 suffix = "." + suffixModel.substring(sfpos + 1);
3425 try (JarInputStream jin = jprovider.getJarInputStream())
3427 JarEntry entry = null;
3430 entry = jin.getNextJarEntry();
3431 } while (entry != null && !entry.getName().equals(jarEntryName));
3435 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3436 File outFile = File.createTempFile(prefix, suffix);
3437 outFile.deleteOnExit();
3438 try (OutputStream os = new FileOutputStream(outFile))
3442 String t = outFile.getAbsolutePath();
3448 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3450 } catch (Exception ex)
3452 ex.printStackTrace();
3458 private class JvAnnotRow
3460 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3467 * persisted version of annotation row from which to take vis properties
3469 public jalview.datamodel.AlignmentAnnotation template;
3472 * original position of the annotation row in the alignment
3478 * Load alignment frame from jalview XML DOM object
3480 * @param jalviewModel
3483 * filename source string
3484 * @param loadTreesAndStructures
3485 * when false only create Viewport
3487 * data source provider
3488 * @return alignment frame created from view stored in DOM
3490 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3491 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3493 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3495 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3497 // JalviewModelSequence jms = object.getJalviewModelSequence();
3499 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3501 Viewport view = (jalviewModel.getViewport().size() > 0)
3502 ? jalviewModel.getViewport().get(0)
3505 // ////////////////////////////////
3506 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3509 // If we just load in the same jar file again, the sequenceSetId
3510 // will be the same, and we end up with multiple references
3511 // to the same sequenceSet. We must modify this id on load
3512 // so that each load of the file gives a unique id
3515 * used to resolve correct alignment dataset for alignments with multiple
3518 String uniqueSeqSetId = null;
3519 String viewId = null;
3522 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3523 viewId = (view.getId() == null ? null
3524 : view.getId() + uniqueSetSuffix);
3527 // ////////////////////////////////
3530 List<SequenceI> hiddenSeqs = null;
3532 List<SequenceI> tmpseqs = new ArrayList<>();
3534 boolean multipleView = false;
3535 SequenceI referenceseqForView = null;
3536 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3537 List<JSeq> jseqs = jalviewModel.getJSeq();
3538 int vi = 0; // counter in vamsasSeq array
3539 for (int i = 0; i < jseqs.size(); i++)
3541 JSeq jseq = jseqs.get(i);
3542 String seqId = jseq.getId();
3544 SequenceI tmpSeq = seqRefIds.get(seqId);
3547 if (!incompleteSeqs.containsKey(seqId))
3549 // may not need this check, but keep it for at least 2.9,1 release
3550 if (tmpSeq.getStart() != jseq.getStart()
3551 || tmpSeq.getEnd() != jseq.getEnd())
3553 jalview.bin.Console.errPrintln(String.format(
3554 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3555 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3556 jseq.getStart(), jseq.getEnd()));
3561 incompleteSeqs.remove(seqId);
3563 if (vamsasSeqs.size() > vi
3564 && vamsasSeqs.get(vi).getId().equals(seqId))
3566 // most likely we are reading a dataset XML document so
3567 // update from vamsasSeq section of XML for this sequence
3568 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3569 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3570 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3575 // reading multiple views, so vamsasSeq set is a subset of JSeq
3576 multipleView = true;
3578 tmpSeq.setStart(jseq.getStart());
3579 tmpSeq.setEnd(jseq.getEnd());
3580 tmpseqs.add(tmpSeq);
3584 Sequence vamsasSeq = vamsasSeqs.get(vi);
3585 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3586 vamsasSeq.getSequence());
3587 tmpSeq.setDescription(vamsasSeq.getDescription());
3588 tmpSeq.setStart(jseq.getStart());
3589 tmpSeq.setEnd(jseq.getEnd());
3590 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3591 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3592 tmpseqs.add(tmpSeq);
3596 if (safeBoolean(jseq.isViewreference()))
3598 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3601 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3603 if (hiddenSeqs == null)
3605 hiddenSeqs = new ArrayList<>();
3608 hiddenSeqs.add(tmpSeq);
3613 // Create the alignment object from the sequence set
3614 // ///////////////////////////////
3615 SequenceI[] orderedSeqs = tmpseqs
3616 .toArray(new SequenceI[tmpseqs.size()]);
3618 AlignmentI al = null;
3619 // so we must create or recover the dataset alignment before going further
3620 // ///////////////////////////////
3621 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3623 // older jalview projects do not have a dataset - so creat alignment and
3625 al = new Alignment(orderedSeqs);
3626 al.setDataset(null);
3630 boolean isdsal = jalviewModel.getViewport().isEmpty();
3633 // we are importing a dataset record, so
3634 // recover reference to an alignment already materialsed as dataset
3635 al = getDatasetFor(vamsasSet.getDatasetId());
3639 // materialse the alignment
3640 al = new Alignment(orderedSeqs);
3644 addDatasetRef(vamsasSet.getDatasetId(), al);
3647 // finally, verify all data in vamsasSet is actually present in al
3648 // passing on flag indicating if it is actually a stored dataset
3649 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3652 if (referenceseqForView != null)
3654 al.setSeqrep(referenceseqForView);
3656 // / Add the alignment properties
3657 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3659 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3661 al.setProperty(ssp.getKey(), ssp.getValue());
3664 // ///////////////////////////////
3666 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3669 // load sequence features, database references and any associated PDB
3670 // structures for the alignment
3672 // prior to 2.10, this part would only be executed the first time a
3673 // sequence was encountered, but not afterwards.
3674 // now, for 2.10 projects, this is also done if the xml doc includes
3675 // dataset sequences not actually present in any particular view.
3677 for (int i = 0; i < vamsasSeqs.size(); i++)
3679 JSeq jseq = jseqs.get(i);
3680 if (jseq.getFeatures().size() > 0)
3682 List<Feature> features = jseq.getFeatures();
3683 for (int f = 0; f < features.size(); f++)
3685 Feature feat = features.get(f);
3686 SequenceFeature sf = new SequenceFeature(feat.getType(),
3687 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3688 safeFloat(feat.getScore()), feat.getFeatureGroup());
3689 sf.setStatus(feat.getStatus());
3692 * load any feature attributes - include map-valued attributes
3694 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3695 for (int od = 0; od < feat.getOtherData().size(); od++)
3697 OtherData keyValue = feat.getOtherData().get(od);
3698 String attributeName = keyValue.getKey();
3699 String attributeValue = keyValue.getValue();
3700 if (attributeName.startsWith("LINK"))
3702 sf.addLink(attributeValue);
3706 String subAttribute = keyValue.getKey2();
3707 if (subAttribute == null)
3709 // simple string-valued attribute
3710 sf.setValue(attributeName, attributeValue);
3714 // attribute 'key' has sub-attribute 'key2'
3715 if (!mapAttributes.containsKey(attributeName))
3717 mapAttributes.put(attributeName, new HashMap<>());
3719 mapAttributes.get(attributeName).put(subAttribute,
3724 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3727 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3730 // adds feature to datasequence's feature set (since Jalview 2.10)
3731 al.getSequenceAt(i).addSequenceFeature(sf);
3734 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3736 // adds dbrefs to datasequence's set (since Jalview 2.10)
3738 al.getSequenceAt(i).getDatasetSequence() == null
3739 ? al.getSequenceAt(i)
3740 : al.getSequenceAt(i).getDatasetSequence(),
3743 if (jseq.getPdbids().size() > 0)
3745 List<Pdbids> ids = jseq.getPdbids();
3746 for (int p = 0; p < ids.size(); p++)
3748 Pdbids pdbid = ids.get(p);
3749 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3750 entry.setId(pdbid.getId());
3751 if (pdbid.getType() != null)
3753 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3755 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3759 entry.setType(PDBEntry.Type.FILE);
3762 // jprovider is null when executing 'New View'
3763 if (pdbid.getFile() != null && jprovider != null)
3765 if (!pdbloaded.containsKey(pdbid.getFile()))
3767 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3772 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3776 if (pdbid.getPdbentryItem() != null)
3778 for (PdbentryItem item : pdbid.getPdbentryItem())
3780 for (Property pr : item.getProperty())
3782 entry.setProperty(pr.getName(), pr.getValue());
3787 for (Property prop : pdbid.getProperty())
3789 entry.setProperty(prop.getName(), prop.getValue());
3791 StructureSelectionManager
3792 .getStructureSelectionManager(Desktop.instance)
3793 .registerPDBEntry(entry);
3794 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3795 if (al.getSequenceAt(i).getDatasetSequence() != null)
3797 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3801 al.getSequenceAt(i).addPDBId(entry);
3806 } // end !multipleview
3808 // ///////////////////////////////
3809 // LOAD SEQUENCE MAPPINGS
3811 if (vamsasSet.getAlcodonFrame().size() > 0)
3813 // TODO Potentially this should only be done once for all views of an
3815 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3816 for (int i = 0; i < alc.size(); i++)
3818 AlignedCodonFrame cf = new AlignedCodonFrame();
3819 if (alc.get(i).getAlcodMap().size() > 0)
3821 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3822 for (int m = 0; m < maps.size(); m++)
3824 AlcodMap map = maps.get(m);
3825 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3827 jalview.datamodel.Mapping mapping = null;
3828 // attach to dna sequence reference.
3829 if (map.getMapping() != null)
3831 mapping = addMapping(map.getMapping());
3832 if (dnaseq != null && mapping.getTo() != null)
3834 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3840 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3844 al.addCodonFrame(cf);
3849 // ////////////////////////////////
3851 List<JvAnnotRow> autoAlan = new ArrayList<>();
3854 * store any annotations which forward reference a group's ID
3856 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3858 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3860 List<Annotation> an = vamsasSet.getAnnotation();
3862 for (int i = 0; i < an.size(); i++)
3864 Annotation annotation = an.get(i);
3867 * test if annotation is automatically calculated for this view only
3869 boolean autoForView = false;
3870 if (annotation.getLabel().equals("Quality")
3871 || annotation.getLabel().equals("Conservation")
3872 || annotation.getLabel().equals("Consensus"))
3874 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3876 // JAXB has no has() test; schema defaults value to false
3877 // if (!annotation.hasAutoCalculated())
3879 // annotation.setAutoCalculated(true);
3882 if (autoForView || annotation.isAutoCalculated())
3884 // remove ID - we don't recover annotation from other views for
3885 // view-specific annotation
3886 annotation.setId(null);
3889 // set visibility for other annotation in this view
3890 String annotationId = annotation.getId();
3891 if (annotationId != null && annotationIds.containsKey(annotationId))
3893 AlignmentAnnotation jda = annotationIds.get(annotationId);
3894 // in principle Visible should always be true for annotation displayed
3895 // in multiple views
3896 if (annotation.isVisible() != null)
3898 jda.visible = annotation.isVisible();
3901 al.addAnnotation(jda);
3905 // Construct new annotation from model.
3906 List<AnnotationElement> ae = annotation.getAnnotationElement();
3907 jalview.datamodel.Annotation[] anot = null;
3908 java.awt.Color firstColour = null;
3910 if (!annotation.isScoreOnly())
3912 anot = new jalview.datamodel.Annotation[al.getWidth()];
3913 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3915 AnnotationElement annElement = ae.get(aa);
3916 anpos = annElement.getPosition();
3918 if (anpos >= anot.length)
3923 float value = safeFloat(annElement.getValue());
3924 anot[anpos] = new jalview.datamodel.Annotation(
3925 annElement.getDisplayCharacter(),
3926 annElement.getDescription(),
3927 (annElement.getSecondaryStructure() == null
3928 || annElement.getSecondaryStructure()
3932 .getSecondaryStructure()
3935 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3936 if (firstColour == null)
3938 firstColour = anot[anpos].colour;
3942 jalview.datamodel.AlignmentAnnotation jaa = null;
3944 if (annotation.isGraph())
3946 float llim = 0, hlim = 0;
3947 // if (autoForView || an[i].isAutoCalculated()) {
3950 jaa = new jalview.datamodel.AlignmentAnnotation(
3951 annotation.getLabel(), annotation.getDescription(), anot,
3952 llim, hlim, safeInt(annotation.getGraphType()));
3954 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3955 jaa._linecolour = firstColour;
3956 if (annotation.getThresholdLine() != null)
3958 jaa.setThreshold(new jalview.datamodel.GraphLine(
3959 safeFloat(annotation.getThresholdLine().getValue()),
3960 annotation.getThresholdLine().getLabel(),
3961 new java.awt.Color(safeInt(
3962 annotation.getThresholdLine().getColour()))));
3964 if (autoForView || annotation.isAutoCalculated())
3966 // Hardwire the symbol display line to ensure that labels for
3967 // histograms are displayed
3973 jaa = new jalview.datamodel.AlignmentAnnotation(
3974 annotation.getLabel(), annotation.getDescription(), anot);
3975 jaa._linecolour = firstColour;
3977 // register new annotation
3978 if (annotation.getId() != null)
3980 annotationIds.put(annotation.getId(), jaa);
3981 jaa.annotationId = annotation.getId();
3983 // recover sequence association
3984 String sequenceRef = annotation.getSequenceRef();
3985 if (sequenceRef != null)
3987 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3988 SequenceI sequence = seqRefIds.get(sequenceRef);
3989 if (sequence == null)
3991 // in pre-2.9 projects sequence ref is to sequence name
3992 sequence = al.findName(sequenceRef);
3994 if (sequence != null)
3996 jaa.createSequenceMapping(sequence, 1, true);
3997 sequence.addAlignmentAnnotation(jaa);
4000 // and make a note of any group association
4001 if (annotation.getGroupRef() != null
4002 && annotation.getGroupRef().length() > 0)
4004 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4005 .get(annotation.getGroupRef());
4008 aal = new ArrayList<>();
4009 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4014 if (annotation.getScore() != null)
4016 jaa.setScore(annotation.getScore().doubleValue());
4018 if (annotation.isVisible() != null)
4020 jaa.visible = annotation.isVisible().booleanValue();
4023 if (annotation.isCentreColLabels() != null)
4025 jaa.centreColLabels = annotation.isCentreColLabels()
4029 if (annotation.isScaleColLabels() != null)
4031 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4033 if (annotation.isAutoCalculated())
4035 // newer files have an 'autoCalculated' flag and store calculation
4036 // state in viewport properties
4037 jaa.autoCalculated = true; // means annotation will be marked for
4038 // update at end of load.
4040 if (annotation.getGraphHeight() != null)
4042 jaa.graphHeight = annotation.getGraphHeight().intValue();
4044 jaa.belowAlignment = annotation.isBelowAlignment();
4045 jaa.setCalcId(annotation.getCalcId());
4046 if (annotation.getProperty().size() > 0)
4048 for (jalview.xml.binding.jalview.Property prop : annotation
4051 jaa.setProperty(prop.getName(), prop.getValue());
4054 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4056 if (annotation.getContactmatrix() != null
4057 && annotation.getContactmatrix().size() > 0)
4059 for (MatrixType xmlmat : annotation.getContactmatrix())
4061 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4063 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4065 Console.error("Can't handle non square PAE Matrices");
4069 float[][] elements = ContactMatrix
4070 .fromFloatStringToContacts(xmlmat.getElements(),
4071 xmlmat.getCols().intValue(),
4072 xmlmat.getRows().intValue());
4073 jalview.util.MapList mapping = null;
4074 if (xmlmat.getMapping() != null)
4076 MapListType m = xmlmat.getMapping();
4077 // Mapping m = dr.getMapping();
4078 int fr[] = new int[m.getMapListFrom().size() * 2];
4079 Iterator<MapListFrom> from = m.getMapListFrom()
4080 .iterator();// enumerateMapListFrom();
4081 for (int _i = 0; from.hasNext(); _i += 2)
4083 MapListFrom mf = from.next();
4084 fr[_i] = mf.getStart();
4085 fr[_i + 1] = mf.getEnd();
4087 int fto[] = new int[m.getMapListTo().size() * 2];
4088 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4089 for (int _i = 0; to.hasNext(); _i += 2)
4091 MapListTo mf = to.next();
4092 fto[_i] = mf.getStart();
4093 fto[_i + 1] = mf.getEnd();
4096 mapping = new jalview.util.MapList(fr, fto,
4097 m.getMapFromUnit().intValue(),
4098 m.getMapToUnit().intValue());
4100 List<BitSet> newgroups = new ArrayList<BitSet>();
4101 if (xmlmat.getGroups().size() > 0)
4103 for (String sgroup : xmlmat.getGroups())
4105 newgroups.add(deStringifyBitset(sgroup));
4108 String nwk = xmlmat.getNewick().size() > 0
4109 ? xmlmat.getNewick().get(0)
4111 if (xmlmat.getNewick().size() > 1)
4114 "Ignoring additional clusterings for contact matrix");
4116 String treeMethod = xmlmat.getTreeMethod();
4117 double thresh = xmlmat.getCutHeight() != null
4118 ? xmlmat.getCutHeight()
4120 GroupSet grpset = new GroupSet();
4121 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4122 PAEContactMatrix newpae = new PAEContactMatrix(
4123 jaa.sequenceRef, mapping, elements, grpset);
4124 jaa.sequenceRef.addContactListFor(jaa, newpae);
4129 Console.error("Ignoring CONTACT_MAP annotation with type "
4130 + xmlmat.getType());
4136 if (jaa.autoCalculated)
4138 autoAlan.add(new JvAnnotRow(i, jaa));
4141 // if (!autoForView)
4143 // add autocalculated group annotation and any user created annotation
4145 al.addAnnotation(jaa);
4149 // ///////////////////////
4151 // Create alignment markup and styles for this view
4152 if (jalviewModel.getJGroup().size() > 0)
4154 List<JGroup> groups = jalviewModel.getJGroup();
4155 boolean addAnnotSchemeGroup = false;
4156 for (int i = 0; i < groups.size(); i++)
4158 JGroup jGroup = groups.get(i);
4159 ColourSchemeI cs = null;
4160 if (jGroup.getColour() != null)
4162 if (jGroup.getColour().startsWith("ucs"))
4164 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4166 else if (jGroup.getColour().equals("AnnotationColourGradient")
4167 && jGroup.getAnnotationColours() != null)
4169 addAnnotSchemeGroup = true;
4173 cs = ColourSchemeProperty.getColourScheme(null, al,
4174 jGroup.getColour());
4177 int pidThreshold = safeInt(jGroup.getPidThreshold());
4179 Vector<SequenceI> seqs = new Vector<>();
4181 for (int s = 0; s < jGroup.getSeq().size(); s++)
4183 String seqId = jGroup.getSeq().get(s);
4184 SequenceI ts = seqRefIds.get(seqId);
4188 seqs.addElement(ts);
4192 if (seqs.size() < 1)
4197 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4198 safeBoolean(jGroup.isDisplayBoxes()),
4199 safeBoolean(jGroup.isDisplayText()),
4200 safeBoolean(jGroup.isColourText()),
4201 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4202 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4203 sg.getGroupColourScheme()
4204 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4205 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4207 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4208 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4209 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4210 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4211 // attributes with a default in the schema are never null
4212 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4213 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4214 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4215 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4216 if (jGroup.getConsThreshold() != null
4217 && jGroup.getConsThreshold().intValue() != 0)
4219 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4222 c.verdict(false, 25);
4223 sg.cs.setConservation(c);
4226 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4228 // re-instate unique group/annotation row reference
4229 List<AlignmentAnnotation> jaal = groupAnnotRefs
4230 .get(jGroup.getId());
4233 for (AlignmentAnnotation jaa : jaal)
4236 if (jaa.autoCalculated)
4238 // match up and try to set group autocalc alignment row for this
4240 if (jaa.label.startsWith("Consensus for "))
4242 sg.setConsensus(jaa);
4244 // match up and try to set group autocalc alignment row for this
4246 if (jaa.label.startsWith("Conservation for "))
4248 sg.setConservationRow(jaa);
4255 if (addAnnotSchemeGroup)
4257 // reconstruct the annotation colourscheme
4259 constructAnnotationColour(jGroup.getAnnotationColours(),
4260 null, al, jalviewModel, false));
4266 // only dataset in this model, so just return.
4269 // ///////////////////////////////
4272 AlignFrame af = null;
4273 AlignViewport av = null;
4274 // now check to see if we really need to create a new viewport.
4275 if (multipleView && viewportsAdded.size() == 0)
4277 // We recovered an alignment for which a viewport already exists.
4278 // TODO: fix up any settings necessary for overlaying stored state onto
4279 // state recovered from another document. (may not be necessary).
4280 // we may need a binding from a viewport in memory to one recovered from
4282 // and then recover its containing af to allow the settings to be applied.
4283 // TODO: fix for vamsas demo
4284 jalview.bin.Console.errPrintln(
4285 "About to recover a viewport for existing alignment: Sequence set ID is "
4287 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4288 if (seqsetobj != null)
4290 if (seqsetobj instanceof String)
4292 uniqueSeqSetId = (String) seqsetobj;
4293 jalview.bin.Console.errPrintln(
4294 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4299 jalview.bin.Console.errPrintln(
4300 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4306 * indicate that annotation colours are applied across all groups (pre
4307 * Jalview 2.8.1 behaviour)
4309 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4310 jalviewModel.getVersion());
4312 AlignmentPanel ap = null;
4313 boolean isnewview = true;
4316 // Check to see if this alignment already has a view id == viewId
4317 jalview.gui.AlignmentPanel views[] = Desktop
4318 .getAlignmentPanels(uniqueSeqSetId);
4319 if (views != null && views.length > 0)
4321 for (int v = 0; v < views.length; v++)
4323 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4325 // recover the existing alignpanel, alignframe, viewport
4326 af = views[v].alignFrame;
4329 // TODO: could even skip resetting view settings if we don't want to
4330 // change the local settings from other jalview processes
4339 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4340 uniqueSeqSetId, viewId, autoAlan);
4341 av = af.getViewport();
4346 * Load any trees, PDB structures and viewers, Overview
4348 * Not done if flag is false (when this method is used for New View)
4350 if (loadTreesAndStructures)
4352 loadTrees(jalviewModel, view, af, av, ap);
4353 loadPCAViewers(jalviewModel, ap);
4354 loadPDBStructures(jprovider, jseqs, af, ap);
4355 loadRnaViewers(jprovider, jseqs, ap);
4356 loadOverview(view, jalviewModel.getVersion(), af);
4358 // and finally return.
4363 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4364 * and geometry as saved
4369 protected void loadOverview(Viewport view, String version, AlignFrame af)
4371 if (!isVersionStringLaterThan("2.11.3", version)
4372 && view.getOverview() == null)
4377 * first close any Overview that was opened automatically
4378 * (if so configured in Preferences) so that the view is
4379 * restored in the same state as saved
4381 af.alignPanel.closeOverviewPanel();
4383 Overview overview = view.getOverview();
4384 if (overview != null)
4386 OverviewPanel overviewPanel = af
4387 .openOverviewPanel(overview.isShowHidden());
4388 overviewPanel.setTitle(overview.getTitle());
4389 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4390 overview.getWidth(), overview.getHeight());
4391 Color gap = new Color(overview.getGapColour());
4392 Color residue = new Color(overview.getResidueColour());
4393 Color hidden = new Color(overview.getHiddenColour());
4394 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4399 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4400 * panel is restored from separate jar entries, two (gapped and trimmed) per
4401 * sequence and secondary structure.
4403 * Currently each viewer shows just one sequence and structure (gapped and
4404 * trimmed), however this method is designed to support multiple sequences or
4405 * structures in viewers if wanted in future.
4411 private void loadRnaViewers(jarInputStreamProvider jprovider,
4412 List<JSeq> jseqs, AlignmentPanel ap)
4415 * scan the sequences for references to viewers; create each one the first
4416 * time it is referenced, add Rna models to existing viewers
4418 for (JSeq jseq : jseqs)
4420 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4422 RnaViewer viewer = jseq.getRnaViewer().get(i);
4423 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4426 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4428 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4429 SequenceI seq = seqRefIds.get(jseq.getId());
4430 AlignmentAnnotation ann = this.annotationIds
4431 .get(ss.getAnnotationId());
4434 * add the structure to the Varna display (with session state copied
4435 * from the jar to a temporary file)
4437 boolean gapped = safeBoolean(ss.isGapped());
4438 String rnaTitle = ss.getTitle();
4439 String sessionState = ss.getViewerState();
4440 String tempStateFile = copyJarEntry(jprovider, sessionState,
4442 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4443 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4445 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4451 * Locate and return an already instantiated matching AppVarna, or create one
4455 * @param viewIdSuffix
4459 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4460 String viewIdSuffix, AlignmentPanel ap)
4463 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4464 * if load is repeated
4466 String postLoadId = viewer.getViewId() + viewIdSuffix;
4467 for (JInternalFrame frame : getAllFrames())
4469 if (frame instanceof AppVarna)
4471 AppVarna varna = (AppVarna) frame;
4472 if (postLoadId.equals(varna.getViewId()))
4474 // this viewer is already instantiated
4475 // could in future here add ap as another 'parent' of the
4476 // AppVarna window; currently just 1-to-many
4483 * viewer not found - make it
4485 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4486 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4487 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4488 safeInt(viewer.getDividerLocation()));
4489 AppVarna varna = new AppVarna(model, ap);
4495 * Load any saved trees
4503 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4504 AlignViewport av, AlignmentPanel ap)
4506 // TODO result of automated refactoring - are all these parameters needed?
4509 for (int t = 0; t < jm.getTree().size(); t++)
4512 Tree tree = jm.getTree().get(t);
4514 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4517 if (tree.isColumnWise())
4519 AlignmentAnnotation aa = annotationIds
4520 .get(tree.getColumnReference());
4524 "Null alignment annotation when restoring columnwise tree");
4526 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4527 tree.getTitle(), safeInt(tree.getWidth()),
4528 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4529 safeInt(tree.getYpos()));
4534 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4535 tree.getTitle(), safeInt(tree.getWidth()),
4536 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4537 safeInt(tree.getYpos()));
4539 if (tree.getId() != null)
4541 // perhaps bind the tree id to something ?
4546 // update local tree attributes ?
4547 // TODO: should check if tp has been manipulated by user - if so its
4548 // settings shouldn't be modified
4549 tp.setTitle(tree.getTitle());
4550 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4551 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4552 safeInt(tree.getHeight())));
4553 tp.setViewport(av); // af.viewport;
4554 // TODO: verify 'associate with all views' works still
4555 tp.getTreeCanvas().setViewport(av); // af.viewport;
4556 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4558 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4562 "There was a problem recovering stored Newick tree: \n"
4563 + tree.getNewick());
4567 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4568 tp.fitToWindow_actionPerformed(null);
4570 if (tree.getFontName() != null)
4573 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4574 safeInt(tree.getFontSize())));
4579 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4580 safeInt(view.getFontSize())));
4583 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4584 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4585 tp.showDistances(safeBoolean(tree.isShowDistances()));
4587 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4589 if (safeBoolean(tree.isCurrentTree()))
4591 af.getViewport().setCurrentTree(tp.getTree());
4595 } catch (Exception ex)
4597 ex.printStackTrace();
4602 * Load and link any saved structure viewers.
4609 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4610 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4613 * Run through all PDB ids on the alignment, and collect mappings between
4614 * distinct view ids and all sequences referring to that view.
4616 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4618 for (int i = 0; i < jseqs.size(); i++)
4620 JSeq jseq = jseqs.get(i);
4621 if (jseq.getPdbids().size() > 0)
4623 List<Pdbids> ids = jseq.getPdbids();
4624 for (int p = 0; p < ids.size(); p++)
4626 Pdbids pdbid = ids.get(p);
4627 final int structureStateCount = pdbid.getStructureState().size();
4628 for (int s = 0; s < structureStateCount; s++)
4630 // check to see if we haven't already created this structure view
4631 final StructureState structureState = pdbid.getStructureState()
4633 String sviewid = (structureState.getViewId() == null) ? null
4634 : structureState.getViewId() + uniqueSetSuffix;
4635 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4636 // Originally : pdbid.getFile()
4637 // : TODO: verify external PDB file recovery still works in normal
4638 // jalview project load
4640 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4641 jpdb.setId(pdbid.getId());
4643 int x = safeInt(structureState.getXpos());
4644 int y = safeInt(structureState.getYpos());
4645 int width = safeInt(structureState.getWidth());
4646 int height = safeInt(structureState.getHeight());
4648 // Probably don't need to do this anymore...
4649 // Desktop.desktop.getComponentAt(x, y);
4650 // TODO: NOW: check that this recovers the PDB file correctly.
4651 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4653 jalview.datamodel.SequenceI seq = seqRefIds
4654 .get(jseq.getId() + "");
4655 if (sviewid == null)
4657 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4660 if (!structureViewers.containsKey(sviewid))
4662 String viewerType = structureState.getType();
4663 if (viewerType == null) // pre Jalview 2.9
4665 viewerType = ViewerType.JMOL.toString();
4667 structureViewers.put(sviewid,
4668 new StructureViewerModel(x, y, width, height, false,
4669 false, true, structureState.getViewId(),
4671 // Legacy pre-2.7 conversion JAL-823 :
4672 // do not assume any view has to be linked for colour by
4676 // assemble String[] { pdb files }, String[] { id for each
4677 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4678 // seqs_file 2}, boolean[] {
4679 // linkAlignPanel,superposeWithAlignpanel}} from hash
4680 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4681 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4682 || structureState.isAlignwithAlignPanel());
4685 * Default colour by linked panel to false if not specified (e.g.
4686 * for pre-2.7 projects)
4688 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4689 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4690 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4693 * Default colour by viewer to true if not specified (e.g. for
4696 boolean colourByViewer = jmoldat.isColourByViewer();
4697 colourByViewer &= structureState.isColourByJmol();
4698 jmoldat.setColourByViewer(colourByViewer);
4700 if (jmoldat.getStateData().length() < structureState.getValue()
4701 /*Content()*/.length())
4703 jmoldat.setStateData(structureState.getValue());// Content());
4705 if (pdbid.getFile() != null)
4707 File mapkey = new File(pdbid.getFile());
4708 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4709 if (seqstrmaps == null)
4711 jmoldat.getFileData().put(mapkey,
4712 seqstrmaps = jmoldat.new StructureData(pdbFile,
4715 if (!seqstrmaps.getSeqList().contains(seq))
4717 seqstrmaps.getSeqList().add(seq);
4723 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");
4724 Console.warn(errorMessage);
4730 // Instantiate the associated structure views
4731 for (Entry<String, StructureViewerModel> entry : structureViewers
4736 createOrLinkStructureViewer(entry, af, ap, jprovider);
4737 } catch (Exception e)
4739 jalview.bin.Console.errPrintln(
4740 "Error loading structure viewer: " + e.getMessage());
4741 // failed - try the next one
4753 protected void createOrLinkStructureViewer(
4754 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4755 AlignmentPanel ap, jarInputStreamProvider jprovider)
4757 final StructureViewerModel stateData = viewerData.getValue();
4760 * Search for any viewer windows already open from other alignment views
4761 * that exactly match the stored structure state
4763 StructureViewerBase comp = findMatchingViewer(viewerData);
4767 linkStructureViewer(ap, comp, stateData);
4771 String type = stateData.getType();
4774 ViewerType viewerType = ViewerType.valueOf(type);
4775 createStructureViewer(viewerType, viewerData, af, jprovider);
4776 } catch (IllegalArgumentException | NullPointerException e)
4778 // TODO JAL-3619 show error dialog / offer an alternative viewer
4779 Console.error("Invalid structure viewer type: " + type);
4784 * Generates a name for the entry in the project jar file to hold state
4785 * information for a structure viewer
4790 protected String getViewerJarEntryName(String viewId)
4792 return VIEWER_PREFIX + viewId;
4796 * Returns any open frame that matches given structure viewer data. The match
4797 * is based on the unique viewId, or (for older project versions) the frame's
4803 protected StructureViewerBase findMatchingViewer(
4804 Entry<String, StructureViewerModel> viewerData)
4806 final String sviewid = viewerData.getKey();
4807 final StructureViewerModel svattrib = viewerData.getValue();
4808 StructureViewerBase comp = null;
4809 JInternalFrame[] frames = getAllFrames();
4810 for (JInternalFrame frame : frames)
4812 if (frame instanceof StructureViewerBase)
4815 * Post jalview 2.4 schema includes structure view id
4817 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4820 comp = (StructureViewerBase) frame;
4821 break; // break added in 2.9
4824 * Otherwise test for matching position and size of viewer frame
4826 else if (frame.getX() == svattrib.getX()
4827 && frame.getY() == svattrib.getY()
4828 && frame.getHeight() == svattrib.getHeight()
4829 && frame.getWidth() == svattrib.getWidth())
4831 comp = (StructureViewerBase) frame;
4832 // no break in faint hope of an exact match on viewId
4840 * Link an AlignmentPanel to an existing structure viewer.
4845 * @param useinViewerSuperpos
4846 * @param usetoColourbyseq
4847 * @param viewerColouring
4849 protected void linkStructureViewer(AlignmentPanel ap,
4850 StructureViewerBase viewer, StructureViewerModel stateData)
4852 // NOTE: if the jalview project is part of a shared session then
4853 // view synchronization should/could be done here.
4855 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4856 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4857 final boolean viewerColouring = stateData.isColourByViewer();
4858 Map<File, StructureData> oldFiles = stateData.getFileData();
4861 * Add mapping for sequences in this view to an already open viewer
4863 final AAStructureBindingModel binding = viewer.getBinding();
4864 for (File id : oldFiles.keySet())
4866 // add this and any other pdb files that should be present in the
4868 StructureData filedat = oldFiles.get(id);
4869 String pdbFile = filedat.getFilePath();
4870 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4871 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4873 binding.addSequenceForStructFile(pdbFile, seq);
4875 // and add the AlignmentPanel's reference to the view panel
4876 viewer.addAlignmentPanel(ap);
4877 if (useinViewerSuperpos)
4879 viewer.useAlignmentPanelForSuperposition(ap);
4883 viewer.excludeAlignmentPanelForSuperposition(ap);
4885 if (usetoColourbyseq)
4887 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4891 viewer.excludeAlignmentPanelForColourbyseq(ap);
4896 * Get all frames within the Desktop.
4900 protected JInternalFrame[] getAllFrames()
4902 JInternalFrame[] frames = null;
4903 // TODO is this necessary - is it safe - risk of hanging?
4908 frames = Desktop.desktop.getAllFrames();
4909 } catch (ArrayIndexOutOfBoundsException e)
4911 // occasional No such child exceptions are thrown here...
4915 } catch (InterruptedException f)
4919 } while (frames == null);
4924 * Answers true if 'version' is equal to or later than 'supported', where each
4925 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4926 * changes. Development and test values for 'version' are leniently treated
4930 * - minimum version we are comparing against
4932 * - version of data being processsed
4933 * @return true if version is equal to or later than supported
4935 public static boolean isVersionStringLaterThan(String supported,
4938 if (supported == null || version == null
4939 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4940 || version.equalsIgnoreCase("Test")
4941 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4943 jalview.bin.Console.errPrintln("Assuming project file with "
4944 + (version == null ? "null" : version)
4945 + " is compatible with Jalview version " + supported);
4950 return StringUtils.compareVersions(version, supported, "b") >= 0;
4954 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4956 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4958 if (newStructureViewers != null)
4960 sview.getBinding().setFinishedLoadingFromArchive(false);
4961 newStructureViewers.add(sview);
4965 protected void setLoadingFinishedForNewStructureViewers()
4967 if (newStructureViewers != null)
4969 for (JalviewStructureDisplayI sview : newStructureViewers)
4971 sview.getBinding().setFinishedLoadingFromArchive(true);
4973 newStructureViewers.clear();
4974 newStructureViewers = null;
4978 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4979 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4980 Viewport view, String uniqueSeqSetId, String viewId,
4981 List<JvAnnotRow> autoAlan)
4983 AlignFrame af = null;
4984 af = new AlignFrame(al, safeInt(view.getWidth()),
4985 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4989 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4990 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
4991 // super.processKeyEvent(e);
4998 af.setFileName(file, FileFormat.Jalview);
5000 final AlignViewport viewport = af.getViewport();
5001 for (int i = 0; i < JSEQ.size(); i++)
5003 int colour = safeInt(JSEQ.get(i).getColour());
5004 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5010 viewport.setColourByReferenceSeq(true);
5011 viewport.setDisplayReferenceSeq(true);
5014 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5016 if (view.getSequenceSetId() != null)
5018 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5020 viewport.setSequenceSetId(uniqueSeqSetId);
5023 // propagate shared settings to this new view
5024 viewport.setHistoryList(av.getHistoryList());
5025 viewport.setRedoList(av.getRedoList());
5029 viewportsAdded.put(uniqueSeqSetId, viewport);
5031 // TODO: check if this method can be called repeatedly without
5032 // side-effects if alignpanel already registered.
5033 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5035 // apply Hidden regions to view.
5036 if (hiddenSeqs != null)
5038 for (int s = 0; s < JSEQ.size(); s++)
5040 SequenceGroup hidden = new SequenceGroup();
5041 boolean isRepresentative = false;
5042 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5044 isRepresentative = true;
5045 SequenceI sequenceToHide = al
5046 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5047 hidden.addSequence(sequenceToHide, false);
5048 // remove from hiddenSeqs list so we don't try to hide it twice
5049 hiddenSeqs.remove(sequenceToHide);
5051 if (isRepresentative)
5053 SequenceI representativeSequence = al.getSequenceAt(s);
5054 hidden.addSequence(representativeSequence, false);
5055 viewport.hideRepSequences(representativeSequence, hidden);
5059 SequenceI[] hseqs = hiddenSeqs
5060 .toArray(new SequenceI[hiddenSeqs.size()]);
5061 viewport.hideSequence(hseqs);
5064 // recover view properties and display parameters
5066 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5067 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5068 final int pidThreshold = safeInt(view.getPidThreshold());
5069 viewport.setThreshold(pidThreshold);
5071 viewport.setColourText(safeBoolean(view.isShowColourText()));
5073 viewport.setConservationSelected(
5074 safeBoolean(view.isConservationSelected()));
5075 viewport.setIncrement(safeInt(view.getConsThreshold()));
5076 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5077 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5079 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5080 safeInt(view.getFontSize())),
5081 (view.getCharWidth() != null) ? false : true);
5082 if (view.getCharWidth() != null)
5084 viewport.setCharWidth(view.getCharWidth());
5085 viewport.setCharHeight(view.getCharHeight());
5087 ViewStyleI vs = viewport.getViewStyle();
5088 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5089 viewport.setViewStyle(vs);
5090 // TODO: allow custom charWidth/Heights to be restored by updating them
5091 // after setting font - which means set above to false
5092 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5093 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5094 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5096 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5098 viewport.setShowText(safeBoolean(view.isShowText()));
5100 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5101 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5102 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5103 viewport.setShowUnconserved(view.isShowUnconserved());
5104 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5106 if (view.getViewName() != null)
5108 viewport.setViewName(view.getViewName());
5109 af.setInitialTabVisible();
5111 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5112 safeInt(view.getWidth()), safeInt(view.getHeight()));
5113 // startSeq set in af.alignPanel.updateLayout below
5114 af.alignPanel.updateLayout();
5115 ColourSchemeI cs = null;
5116 // apply colourschemes
5117 if (view.getBgColour() != null)
5119 if (view.getBgColour().startsWith("ucs"))
5121 cs = getUserColourScheme(jm, view.getBgColour());
5123 else if (view.getBgColour().startsWith("Annotation"))
5125 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5126 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5133 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5134 view.getBgColour());
5139 * turn off 'alignment colour applies to all groups'
5140 * while restoring global colour scheme
5142 viewport.setColourAppliesToAllGroups(false);
5143 viewport.setGlobalColourScheme(cs);
5144 viewport.getResidueShading().setThreshold(pidThreshold,
5145 view.isIgnoreGapsinConsensus());
5146 viewport.getResidueShading()
5147 .setConsensus(viewport.getSequenceConsensusHash());
5148 if (safeBoolean(view.isConservationSelected()) && cs != null)
5150 viewport.getResidueShading()
5151 .setConservationInc(safeInt(view.getConsThreshold()));
5153 af.changeColour(cs);
5154 viewport.setColourAppliesToAllGroups(true);
5156 viewport.setShowSequenceFeatures(
5157 safeBoolean(view.isShowSequenceFeatures()));
5159 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5160 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5161 viewport.setFollowHighlight(view.isFollowHighlight());
5162 viewport.followSelection = view.isFollowSelection();
5163 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5164 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5165 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5166 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5167 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5168 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5169 viewport.setShowGroupConservation(view.isShowGroupConservation());
5170 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5171 viewport.setShowComplementFeaturesOnTop(
5172 view.isShowComplementFeaturesOnTop());
5174 // recover feature settings
5175 if (jm.getFeatureSettings() != null)
5177 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5178 .getFeatureRenderer();
5179 FeaturesDisplayed fdi;
5180 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5181 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5183 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5184 Map<String, Float> featureOrder = new Hashtable<>();
5186 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5189 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5190 String featureType = setting.getType();
5193 * restore feature filters (if any)
5195 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5197 if (filters != null)
5199 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5201 if (!filter.isEmpty())
5203 fr.setFeatureFilter(featureType, filter);
5208 * restore feature colour scheme
5210 Color maxColour = new Color(setting.getColour());
5211 if (setting.getMincolour() != null)
5214 * minColour is always set unless a simple colour
5215 * (including for colour by label though it doesn't use it)
5217 Color minColour = new Color(setting.getMincolour().intValue());
5218 Color noValueColour = minColour;
5219 NoValueColour noColour = setting.getNoValueColour();
5220 if (noColour == NoValueColour.NONE)
5222 noValueColour = null;
5224 else if (noColour == NoValueColour.MAX)
5226 noValueColour = maxColour;
5228 float min = safeFloat(safeFloat(setting.getMin()));
5229 float max = setting.getMax() == null ? 1f
5230 : setting.getMax().floatValue();
5231 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5232 maxColour, noValueColour, min, max);
5233 if (setting.getAttributeName().size() > 0)
5235 gc.setAttributeName(setting.getAttributeName().toArray(
5236 new String[setting.getAttributeName().size()]));
5238 if (setting.getThreshold() != null)
5240 gc.setThreshold(setting.getThreshold().floatValue());
5241 int threshstate = safeInt(setting.getThreshstate());
5242 // -1 = None, 0 = Below, 1 = Above threshold
5243 if (threshstate == 0)
5245 gc.setBelowThreshold(true);
5247 else if (threshstate == 1)
5249 gc.setAboveThreshold(true);
5252 gc.setAutoScaled(true); // default
5253 if (setting.isAutoScale() != null)
5255 gc.setAutoScaled(setting.isAutoScale());
5257 if (setting.isColourByLabel() != null)
5259 gc.setColourByLabel(setting.isColourByLabel());
5261 // and put in the feature colour table.
5262 featureColours.put(featureType, gc);
5266 featureColours.put(featureType, new FeatureColour(maxColour));
5268 renderOrder[fs] = featureType;
5269 if (setting.getOrder() != null)
5271 featureOrder.put(featureType, setting.getOrder().floatValue());
5275 featureOrder.put(featureType, Float.valueOf(
5276 fs / jm.getFeatureSettings().getSetting().size()));
5278 if (safeBoolean(setting.isDisplay()))
5280 fdi.setVisible(featureType);
5283 Map<String, Boolean> fgtable = new Hashtable<>();
5284 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5286 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5287 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5289 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5290 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5291 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5292 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5293 fgtable, featureColours, 1.0f, featureOrder);
5294 fr.transferSettings(frs);
5297 if (view.getHiddenColumns().size() > 0)
5299 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5301 final HiddenColumns hc = view.getHiddenColumns().get(c);
5302 viewport.hideColumns(safeInt(hc.getStart()),
5303 safeInt(hc.getEnd()) /* +1 */);
5306 if (view.getCalcIdParam() != null)
5308 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5310 if (calcIdParam != null)
5312 if (recoverCalcIdParam(calcIdParam, viewport))
5317 Console.warn("Couldn't recover parameters for "
5318 + calcIdParam.getCalcId());
5323 af.setMenusFromViewport(viewport);
5324 af.setTitle(view.getTitle());
5325 // TODO: we don't need to do this if the viewport is aready visible.
5327 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5328 * has a 'cdna/protein complement' view, in which case save it in order to
5329 * populate a SplitFrame once all views have been read in.
5331 String complementaryViewId = view.getComplementId();
5332 if (complementaryViewId == null)
5334 Desktop.addInternalFrame(af, view.getTitle(),
5335 safeInt(view.getWidth()), safeInt(view.getHeight()));
5336 // recompute any autoannotation
5337 af.alignPanel.updateAnnotation(false, true);
5338 reorderAutoannotation(af, al, autoAlan);
5339 af.alignPanel.alignmentChanged();
5343 splitFrameCandidates.put(view, af);
5350 * Reads saved data to restore Colour by Annotation settings
5352 * @param viewAnnColour
5356 * @param checkGroupAnnColour
5359 private ColourSchemeI constructAnnotationColour(
5360 AnnotationColourScheme viewAnnColour, AlignFrame af,
5361 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5363 boolean propagateAnnColour = false;
5364 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5366 if (checkGroupAnnColour && al.getGroups() != null
5367 && al.getGroups().size() > 0)
5369 // pre 2.8.1 behaviour
5370 // check to see if we should transfer annotation colours
5371 propagateAnnColour = true;
5372 for (SequenceGroup sg : al.getGroups())
5374 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5376 propagateAnnColour = false;
5382 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5384 String annotationId = viewAnnColour.getAnnotation();
5385 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5388 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5390 if (matchedAnnotation == null
5391 && annAlignment.getAlignmentAnnotation() != null)
5393 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5396 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5398 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5403 if (matchedAnnotation == null)
5406 .errPrintln("Failed to match annotation colour scheme for "
5410 // belt-and-braces create a threshold line if the
5411 // colourscheme needs one but the matchedAnnotation doesn't have one
5412 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5413 && matchedAnnotation.getThreshold() == null)
5415 matchedAnnotation.setThreshold(
5416 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5417 "Threshold", Color.black));
5420 AnnotationColourGradient cs = null;
5421 if (viewAnnColour.getColourScheme().equals("None"))
5423 cs = new AnnotationColourGradient(matchedAnnotation,
5424 new Color(safeInt(viewAnnColour.getMinColour())),
5425 new Color(safeInt(viewAnnColour.getMaxColour())),
5426 safeInt(viewAnnColour.getAboveThreshold()));
5428 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5430 cs = new AnnotationColourGradient(matchedAnnotation,
5431 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5432 safeInt(viewAnnColour.getAboveThreshold()));
5436 cs = new AnnotationColourGradient(matchedAnnotation,
5437 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5438 viewAnnColour.getColourScheme()),
5439 safeInt(viewAnnColour.getAboveThreshold()));
5442 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5443 boolean useOriginalColours = safeBoolean(
5444 viewAnnColour.isPredefinedColours());
5445 cs.setSeqAssociated(perSequenceOnly);
5446 cs.setPredefinedColours(useOriginalColours);
5448 if (propagateAnnColour && al.getGroups() != null)
5450 // Also use these settings for all the groups
5451 for (int g = 0; g < al.getGroups().size(); g++)
5453 SequenceGroup sg = al.getGroups().get(g);
5454 if (sg.getGroupColourScheme() == null)
5459 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5460 matchedAnnotation, sg.getColourScheme(),
5461 safeInt(viewAnnColour.getAboveThreshold()));
5462 sg.setColourScheme(groupScheme);
5463 groupScheme.setSeqAssociated(perSequenceOnly);
5464 groupScheme.setPredefinedColours(useOriginalColours);
5470 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5471 List<JvAnnotRow> autoAlan)
5473 // copy over visualization settings for autocalculated annotation in the
5475 if (al.getAlignmentAnnotation() != null)
5478 * Kludge for magic autoannotation names (see JAL-811)
5480 String[] magicNames = new String[] { "Consensus", "Quality",
5482 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5483 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5484 for (String nm : magicNames)
5486 visan.put(nm, nullAnnot);
5488 for (JvAnnotRow auan : autoAlan)
5490 visan.put(auan.template.label
5491 + (auan.template.getCalcId() == null ? ""
5492 : "\t" + auan.template.getCalcId()),
5495 int hSize = al.getAlignmentAnnotation().length;
5496 List<JvAnnotRow> reorder = new ArrayList<>();
5497 // work through any autoCalculated annotation already on the view
5498 // removing it if it should be placed in a different location on the
5499 // annotation panel.
5500 List<String> remains = new ArrayList<>(visan.keySet());
5501 for (int h = 0; h < hSize; h++)
5503 jalview.datamodel.AlignmentAnnotation jalan = al
5504 .getAlignmentAnnotation()[h];
5505 if (jalan.autoCalculated)
5508 JvAnnotRow valan = visan.get(k = jalan.label);
5509 if (jalan.getCalcId() != null)
5511 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5516 // delete the auto calculated row from the alignment
5517 al.deleteAnnotation(jalan, false);
5521 if (valan != nullAnnot)
5523 if (jalan != valan.template)
5525 // newly created autoannotation row instance
5526 // so keep a reference to the visible annotation row
5527 // and copy over all relevant attributes
5528 if (valan.template.graphHeight >= 0)
5531 jalan.graphHeight = valan.template.graphHeight;
5533 jalan.visible = valan.template.visible;
5535 reorder.add(new JvAnnotRow(valan.order, jalan));
5540 // Add any (possibly stale) autocalculated rows that were not appended to
5541 // the view during construction
5542 for (String other : remains)
5544 JvAnnotRow othera = visan.get(other);
5545 if (othera != nullAnnot && othera.template.getCalcId() != null
5546 && othera.template.getCalcId().length() > 0)
5548 reorder.add(othera);
5551 // now put the automatic annotation in its correct place
5552 int s = 0, srt[] = new int[reorder.size()];
5553 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5554 for (JvAnnotRow jvar : reorder)
5557 srt[s++] = jvar.order;
5560 jalview.util.QuickSort.sort(srt, rws);
5561 // and re-insert the annotation at its correct position
5562 for (JvAnnotRow jvar : rws)
5564 al.addAnnotation(jvar.template, jvar.order);
5566 af.alignPanel.adjustAnnotationHeight();
5570 Hashtable skipList = null;
5573 * TODO remove this method
5576 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5577 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5578 * throw new Error("Implementation Error. No skipList defined for this
5579 * Jalview2XML instance."); } return (AlignFrame)
5580 * skipList.get(view.getSequenceSetId()); }
5584 * Check if the Jalview view contained in object should be skipped or not.
5587 * @return true if view's sequenceSetId is a key in skipList
5589 private boolean skipViewport(JalviewModel object)
5591 if (skipList == null)
5595 String id = object.getViewport().get(0).getSequenceSetId();
5596 if (skipList.containsKey(id))
5598 Console.debug("Skipping seuqence set id " + id);
5604 public void addToSkipList(AlignFrame af)
5606 if (skipList == null)
5608 skipList = new Hashtable();
5610 skipList.put(af.getViewport().getSequenceSetId(), af);
5613 public void clearSkipList()
5615 if (skipList != null)
5622 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5623 boolean ignoreUnrefed, String uniqueSeqSetId)
5625 jalview.datamodel.AlignmentI ds = getDatasetFor(
5626 vamsasSet.getDatasetId());
5627 AlignmentI xtant_ds = ds;
5628 if (xtant_ds == null)
5630 // good chance we are about to create a new dataset, but check if we've
5631 // seen some of the dataset sequence IDs before.
5632 // TODO: skip this check if we are working with project generated by
5633 // version 2.11 or later
5634 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5635 if (xtant_ds != null)
5638 addDatasetRef(vamsasSet.getDatasetId(), ds);
5641 Vector<SequenceI> dseqs = null;
5644 // recovering an alignment View
5645 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5646 if (seqSetDS != null)
5648 if (ds != null && ds != seqSetDS)
5651 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5652 + " - CDS/Protein crossreference data may be lost");
5653 if (xtant_ds != null)
5655 // This can only happen if the unique sequence set ID was bound to a
5656 // dataset that did not contain any of the sequences in the view
5657 // currently being restored.
5659 "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.");
5663 addDatasetRef(vamsasSet.getDatasetId(), ds);
5668 // try even harder to restore dataset
5669 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5670 // create a list of new dataset sequences
5671 dseqs = new Vector<>();
5673 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5675 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5676 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5678 // create a new dataset
5681 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5682 dseqs.copyInto(dsseqs);
5683 ds = new jalview.datamodel.Alignment(dsseqs);
5684 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5685 + " for alignment " + System.identityHashCode(al));
5686 addDatasetRef(vamsasSet.getDatasetId(), ds);
5688 // set the dataset for the newly imported alignment.
5689 if (al.getDataset() == null && !ignoreUnrefed)
5692 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5693 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5695 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5699 * XML dataset sequence ID to materialised dataset reference
5701 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5704 * @return the first materialised dataset reference containing a dataset
5705 * sequence referenced in the given view
5707 * - sequences from the view
5709 AlignmentI checkIfHasDataset(List<Sequence> list)
5711 for (Sequence restoredSeq : list)
5713 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5714 if (datasetFor != null)
5723 * Register ds as the containing dataset for the dataset sequences referenced
5724 * by sequences in list
5727 * - sequences in a view
5730 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5732 for (Sequence restoredSeq : list)
5734 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5735 if (prevDS != null && prevDS != ds)
5737 Console.warn("Dataset sequence appears in many datasets: "
5738 + restoredSeq.getDsseqid());
5739 // TODO: try to merge!
5747 * sequence definition to create/merge dataset sequence for
5751 * vector to add new dataset sequence to
5752 * @param ignoreUnrefed
5753 * - when true, don't create new sequences from vamsasSeq if it's id
5754 * doesn't already have an asssociated Jalview sequence.
5756 * - used to reorder the sequence in the alignment according to the
5757 * vamsasSeq array ordering, to preserve ordering of dataset
5759 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5760 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5763 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5765 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5766 boolean reorder = false;
5767 SequenceI dsq = null;
5768 if (sq != null && sq.getDatasetSequence() != null)
5770 dsq = sq.getDatasetSequence();
5776 if (sq == null && ignoreUnrefed)
5780 String sqid = vamsasSeq.getDsseqid();
5783 // need to create or add a new dataset sequence reference to this sequence
5786 dsq = seqRefIds.get(sqid);
5791 // make a new dataset sequence
5792 dsq = sq.createDatasetSequence();
5795 // make up a new dataset reference for this sequence
5796 sqid = seqHash(dsq);
5798 dsq.setVamsasId(uniqueSetSuffix + sqid);
5799 seqRefIds.put(sqid, dsq);
5804 dseqs.addElement(dsq);
5809 ds.addSequence(dsq);
5815 { // make this dataset sequence sq's dataset sequence
5816 sq.setDatasetSequence(dsq);
5817 // and update the current dataset alignment
5822 if (!dseqs.contains(dsq))
5829 if (ds.findIndex(dsq) < 0)
5831 ds.addSequence(dsq);
5838 // TODO: refactor this as a merge dataset sequence function
5839 // now check that sq (the dataset sequence) sequence really is the union of
5840 // all references to it
5841 // boolean pre = sq.getStart() < dsq.getStart();
5842 // boolean post = sq.getEnd() > dsq.getEnd();
5846 // StringBuffer sb = new StringBuffer();
5847 String newres = jalview.analysis.AlignSeq.extractGaps(
5848 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5849 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5850 && newres.length() > dsq.getLength())
5852 // Update with the longer sequence.
5856 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5857 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5858 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5859 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5861 dsq.setSequence(newres);
5863 // TODO: merges will never happen if we 'know' we have the real dataset
5864 // sequence - this should be detected when id==dssid
5865 jalview.bin.Console.errPrintln(
5866 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5867 // + (pre ? "prepended" : "") + " "
5868 // + (post ? "appended" : ""));
5873 // sequence refs are identical. We may need to update the existing dataset
5874 // alignment with this one, though.
5875 if (ds != null && dseqs == null)
5877 int opos = ds.findIndex(dsq);
5878 SequenceI tseq = null;
5879 if (opos != -1 && vseqpos != opos)
5881 // remove from old position
5882 ds.deleteSequence(dsq);
5884 if (vseqpos < ds.getHeight())
5886 if (vseqpos != opos)
5888 // save sequence at destination position
5889 tseq = ds.getSequenceAt(vseqpos);
5890 ds.replaceSequenceAt(vseqpos, dsq);
5891 ds.addSequence(tseq);
5896 ds.addSequence(dsq);
5903 * TODO use AlignmentI here and in related methods - needs
5904 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5906 Hashtable<String, AlignmentI> datasetIds = null;
5908 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5910 private AlignmentI getDatasetFor(String datasetId)
5912 if (datasetIds == null)
5914 datasetIds = new Hashtable<>();
5917 if (datasetIds.containsKey(datasetId))
5919 return datasetIds.get(datasetId);
5924 private void addDatasetRef(String datasetId, AlignmentI dataset)
5926 if (datasetIds == null)
5928 datasetIds = new Hashtable<>();
5930 datasetIds.put(datasetId, dataset);
5934 * make a new dataset ID for this jalview dataset alignment
5939 private String getDatasetIdRef(AlignmentI dataset)
5941 if (dataset.getDataset() != null)
5944 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5946 String datasetId = makeHashCode(dataset, null);
5947 if (datasetId == null)
5949 // make a new datasetId and record it
5950 if (dataset2Ids == null)
5952 dataset2Ids = new IdentityHashMap<>();
5956 datasetId = dataset2Ids.get(dataset);
5958 if (datasetId == null)
5960 datasetId = "ds" + dataset2Ids.size() + 1;
5961 dataset2Ids.put(dataset, datasetId);
5968 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5969 * constructed as a special subclass GeneLocus.
5971 * @param datasetSequence
5974 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5976 for (int d = 0; d < sequence.getDBRef().size(); d++)
5978 DBRef dr = sequence.getDBRef().get(d);
5982 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5983 dr.getAccessionId());
5987 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5988 dr.getAccessionId());
5990 if (dr.getMapping() != null)
5992 entry.setMap(addMapping(dr.getMapping()));
5994 entry.setCanonical(dr.isCanonical());
5995 datasetSequence.addDBRef(entry);
5999 private jalview.datamodel.Mapping addMapping(Mapping m)
6001 SequenceI dsto = null;
6002 // Mapping m = dr.getMapping();
6003 int fr[] = new int[m.getMapListFrom().size() * 2];
6004 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6005 for (int _i = 0; from.hasNext(); _i += 2)
6007 MapListFrom mf = from.next();
6008 fr[_i] = mf.getStart();
6009 fr[_i + 1] = mf.getEnd();
6011 int fto[] = new int[m.getMapListTo().size() * 2];
6012 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6013 for (int _i = 0; to.hasNext(); _i += 2)
6015 MapListTo mf = to.next();
6016 fto[_i] = mf.getStart();
6017 fto[_i + 1] = mf.getEnd();
6019 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6020 fto, m.getMapFromUnit().intValue(),
6021 m.getMapToUnit().intValue());
6024 * (optional) choice of dseqFor or Sequence
6026 if (m.getDseqFor() != null)
6028 String dsfor = m.getDseqFor();
6029 if (seqRefIds.containsKey(dsfor))
6034 jmap.setTo(seqRefIds.get(dsfor));
6038 frefedSequence.add(newMappingRef(dsfor, jmap));
6041 else if (m.getSequence() != null)
6044 * local sequence definition
6046 Sequence ms = m.getSequence();
6047 SequenceI djs = null;
6048 String sqid = ms.getDsseqid();
6049 if (sqid != null && sqid.length() > 0)
6052 * recover dataset sequence
6054 djs = seqRefIds.get(sqid);
6058 jalview.bin.Console.errPrintln(
6059 "Warning - making up dataset sequence id for DbRef sequence map reference");
6060 sqid = ((Object) ms).toString(); // make up a new hascode for
6061 // undefined dataset sequence hash
6062 // (unlikely to happen)
6068 * make a new dataset sequence and add it to refIds hash
6070 djs = new jalview.datamodel.Sequence(ms.getName(),
6072 djs.setStart(jmap.getMap().getToLowest());
6073 djs.setEnd(jmap.getMap().getToHighest());
6074 djs.setVamsasId(uniqueSetSuffix + sqid);
6076 incompleteSeqs.put(sqid, djs);
6077 seqRefIds.put(sqid, djs);
6080 Console.debug("about to recurse on addDBRefs.");
6089 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6090 * view as XML (but not to file), and then reloading it
6095 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6098 JalviewModel jm = saveState(ap, null, null, null);
6101 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6102 ap.getAlignment().getDataset());
6104 uniqueSetSuffix = "";
6105 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6106 jm.getViewport().get(0).setId(null);
6107 // we don't overwrite the view we just copied
6109 if (this.frefedSequence == null)
6111 frefedSequence = new Vector<>();
6114 viewportsAdded.clear();
6116 AlignFrame af = loadFromObject(jm, null, false, null);
6117 af.getAlignPanels().clear();
6118 af.closeMenuItem_actionPerformed(true);
6121 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6122 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6123 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6124 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6125 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6128 return af.alignPanel;
6131 private Hashtable jvids2vobj;
6134 * set the object to ID mapping tables used to write/recover objects and XML
6135 * ID strings for the jalview project. If external tables are provided then
6136 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6137 * object goes out of scope. - also populates the datasetIds hashtable with
6138 * alignment objects containing dataset sequences
6141 * Map from ID strings to jalview datamodel
6143 * Map from jalview datamodel to ID strings
6147 public void setObjectMappingTables(Hashtable vobj2jv,
6148 IdentityHashMap jv2vobj)
6150 this.jv2vobj = jv2vobj;
6151 this.vobj2jv = vobj2jv;
6152 Iterator ds = jv2vobj.keySet().iterator();
6154 while (ds.hasNext())
6156 Object jvobj = ds.next();
6157 id = jv2vobj.get(jvobj).toString();
6158 if (jvobj instanceof jalview.datamodel.Alignment)
6160 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6162 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6165 else if (jvobj instanceof jalview.datamodel.Sequence)
6167 // register sequence object so the XML parser can recover it.
6168 if (seqRefIds == null)
6170 seqRefIds = new HashMap<>();
6172 if (seqsToIds == null)
6174 seqsToIds = new IdentityHashMap<>();
6176 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6177 seqsToIds.put((SequenceI) jvobj, id);
6179 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6182 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6183 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6184 if (jvann.annotationId == null)
6186 jvann.annotationId = anid;
6188 if (!jvann.annotationId.equals(anid))
6190 // TODO verify that this is the correct behaviour
6191 Console.warn("Overriding Annotation ID for " + anid
6192 + " from different id : " + jvann.annotationId);
6193 jvann.annotationId = anid;
6196 else if (jvobj instanceof String)
6198 if (jvids2vobj == null)
6200 jvids2vobj = new Hashtable();
6201 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6206 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6212 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6213 * objects created from the project archive. If string is null (default for
6214 * construction) then suffix will be set automatically.
6218 public void setUniqueSetSuffix(String string)
6220 uniqueSetSuffix = string;
6225 * uses skipList2 as the skipList for skipping views on sequence sets
6226 * associated with keys in the skipList
6230 public void setSkipList(Hashtable skipList2)
6232 skipList = skipList2;
6236 * Reads the jar entry of given name and returns its contents, or null if the
6237 * entry is not found.
6240 * @param jarEntryName
6243 protected String readJarEntry(jarInputStreamProvider jprovider,
6244 String jarEntryName)
6246 String result = null;
6247 BufferedReader in = null;
6252 * Reopen the jar input stream and traverse its entries to find a matching
6255 JarInputStream jin = jprovider.getJarInputStream();
6256 JarEntry entry = null;
6259 entry = jin.getNextJarEntry();
6260 } while (entry != null && !entry.getName().equals(jarEntryName));
6264 StringBuilder out = new StringBuilder(256);
6265 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6268 while ((data = in.readLine()) != null)
6272 result = out.toString();
6277 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6279 } catch (Exception ex)
6281 ex.printStackTrace();
6289 } catch (IOException e)
6300 * Returns an incrementing counter (0, 1, 2...)
6304 private synchronized int nextCounter()
6310 * Loads any saved PCA viewers
6315 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6319 List<PcaViewer> pcaviewers = model.getPcaViewer();
6320 for (PcaViewer viewer : pcaviewers)
6322 String modelName = viewer.getScoreModelName();
6323 SimilarityParamsI params = new SimilarityParams(
6324 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6325 viewer.isIncludeGaps(),
6326 viewer.isDenominateByShortestLength());
6329 * create the panel (without computing the PCA)
6331 PCAPanel panel = new PCAPanel(ap, modelName, params);
6333 panel.setTitle(viewer.getTitle());
6334 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6335 viewer.getWidth(), viewer.getHeight()));
6337 boolean showLabels = viewer.isShowLabels();
6338 panel.setShowLabels(showLabels);
6339 panel.getRotatableCanvas().setShowLabels(showLabels);
6340 panel.getRotatableCanvas()
6341 .setBgColour(new Color(viewer.getBgColour()));
6342 panel.getRotatableCanvas()
6343 .setApplyToAllViews(viewer.isLinkToAllViews());
6346 * load PCA output data
6348 ScoreModelI scoreModel = ScoreModels.getInstance()
6349 .getScoreModel(modelName, ap);
6350 PCA pca = new PCA(null, scoreModel, params);
6351 PcaDataType pcaData = viewer.getPcaData();
6353 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6354 pca.setPairwiseScores(pairwise);
6356 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6357 pca.setTridiagonal(triDiag);
6359 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6360 pca.setEigenmatrix(result);
6362 panel.getPcaModel().setPCA(pca);
6365 * we haven't saved the input data! (JAL-2647 to do)
6367 panel.setInputData(null);
6370 * add the sequence points for the PCA display
6372 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6373 for (SequencePoint sp : viewer.getSequencePoint())
6375 String seqId = sp.getSequenceRef();
6376 SequenceI seq = seqRefIds.get(seqId);
6379 throw new IllegalStateException(
6380 "Unmatched seqref for PCA: " + seqId);
6382 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6383 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6385 seqPoints.add(seqPoint);
6387 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6390 * set min-max ranges and scale after setPoints (which recomputes them)
6392 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6393 SeqPointMin spMin = viewer.getSeqPointMin();
6394 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6396 SeqPointMax spMax = viewer.getSeqPointMax();
6397 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6399 panel.getRotatableCanvas().setSeqMinMax(min, max);
6401 // todo: hold points list in PCAModel only
6402 panel.getPcaModel().setSequencePoints(seqPoints);
6404 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6405 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6406 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6408 // is this duplication needed?
6409 panel.setTop(seqPoints.size() - 1);
6410 panel.getPcaModel().setTop(seqPoints.size() - 1);
6413 * add the axes' end points for the display
6415 for (int i = 0; i < 3; i++)
6417 Axis axis = viewer.getAxis().get(i);
6418 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6419 axis.getXPos(), axis.getYPos(), axis.getZPos());
6422 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6423 "label.calc_title", "PCA", modelName), 475, 450);
6425 } catch (Exception ex)
6427 Console.error("Error loading PCA: " + ex.toString());
6432 * Creates a new structure viewer window
6439 protected void createStructureViewer(ViewerType viewerType,
6440 final Entry<String, StructureViewerModel> viewerData,
6441 AlignFrame af, jarInputStreamProvider jprovider)
6443 final StructureViewerModel viewerModel = viewerData.getValue();
6444 String sessionFilePath = null;
6446 if (viewerType == ViewerType.JMOL)
6448 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6452 String viewerJarEntryName = getViewerJarEntryName(
6453 viewerModel.getViewId());
6454 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6455 "viewerSession", ".tmp");
6457 final String sessionPath = sessionFilePath;
6458 final String sviewid = viewerData.getKey();
6461 SwingUtilities.invokeAndWait(new Runnable()
6466 JalviewStructureDisplayI sview = null;
6469 sview = StructureViewer.createView(viewerType, af.alignPanel,
6470 viewerModel, sessionPath, sviewid);
6471 addNewStructureViewer(sview);
6472 } catch (OutOfMemoryError ex)
6474 new OOMWarning("Restoring structure view for " + viewerType,
6475 (OutOfMemoryError) ex.getCause());
6476 if (sview != null && sview.isVisible())
6478 sview.closeViewer(false);
6479 sview.setVisible(false);
6485 } catch (InvocationTargetException | InterruptedException ex)
6487 Console.warn("Unexpected error when opening " + viewerType
6488 + " structure viewer", ex);
6493 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6494 * the path of the file. "load file" commands are rewritten to change the
6495 * original PDB file names to those created as the Jalview project is loaded.
6501 private String rewriteJmolSession(StructureViewerModel svattrib,
6502 jarInputStreamProvider jprovider)
6504 String state = svattrib.getStateData(); // Jalview < 2.9
6505 if (state == null || state.isEmpty()) // Jalview >= 2.9
6507 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6508 state = readJarEntry(jprovider, jarEntryName);
6510 // TODO or simpler? for each key in oldFiles,
6511 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6512 // (allowing for different path escapings)
6513 StringBuilder rewritten = new StringBuilder(state.length());
6514 int cp = 0, ncp, ecp;
6515 Map<File, StructureData> oldFiles = svattrib.getFileData();
6516 while ((ncp = state.indexOf("load ", cp)) > -1)
6520 // look for next filename in load statement
6521 rewritten.append(state.substring(cp,
6522 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6523 String oldfilenam = state.substring(ncp,
6524 ecp = state.indexOf("\"", ncp));
6525 // recover the new mapping data for this old filename
6526 // have to normalize filename - since Jmol and jalview do
6527 // filename translation differently.
6528 StructureData filedat = oldFiles.get(new File(oldfilenam));
6529 if (filedat == null)
6531 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6532 filedat = oldFiles.get(new File(reformatedOldFilename));
6534 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6535 rewritten.append("\"");
6536 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6537 // look for next file statement.
6538 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6542 // just append rest of state
6543 rewritten.append(state.substring(cp));
6547 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6548 rewritten = new StringBuilder(state);
6549 rewritten.append("; load append ");
6550 for (File id : oldFiles.keySet())
6552 // add pdb files that should be present in the viewer
6553 StructureData filedat = oldFiles.get(id);
6554 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6556 rewritten.append(";");
6559 if (rewritten.length() == 0)
6563 final String history = "history = ";
6564 int historyIndex = rewritten.indexOf(history);
6565 if (historyIndex > -1)
6568 * change "history = [true|false];" to "history = [1|0];"
6570 historyIndex += history.length();
6571 String val = rewritten.substring(historyIndex, historyIndex + 5);
6572 if (val.startsWith("true"))
6574 rewritten.replace(historyIndex, historyIndex + 4, "1");
6576 else if (val.startsWith("false"))
6578 rewritten.replace(historyIndex, historyIndex + 5, "0");
6584 File tmp = File.createTempFile("viewerSession", ".tmp");
6585 try (OutputStream os = new FileOutputStream(tmp))
6587 InputStream is = new ByteArrayInputStream(
6588 rewritten.toString().getBytes());
6590 return tmp.getAbsolutePath();
6592 } catch (IOException e)
6594 Console.error("Error restoring Jmol session: " + e.toString());
6600 * Populates an XML model of the feature colour scheme for one feature type
6602 * @param featureType
6606 public static Colour marshalColour(String featureType,
6607 FeatureColourI fcol)
6609 Colour col = new Colour();
6610 if (fcol.isSimpleColour())
6612 col.setRGB(Format.getHexString(fcol.getColour()));
6616 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6617 col.setMin(fcol.getMin());
6618 col.setMax(fcol.getMax());
6619 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6620 col.setAutoScale(fcol.isAutoScaled());
6621 col.setThreshold(fcol.getThreshold());
6622 col.setColourByLabel(fcol.isColourByLabel());
6623 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6624 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6625 : ThresholdType.NONE));
6626 if (fcol.isColourByAttribute())
6628 final String[] attName = fcol.getAttributeName();
6629 col.getAttributeName().add(attName[0]);
6630 if (attName.length > 1)
6632 col.getAttributeName().add(attName[1]);
6635 Color noColour = fcol.getNoColour();
6636 if (noColour == null)
6638 col.setNoValueColour(NoValueColour.NONE);
6640 else if (noColour == fcol.getMaxColour())
6642 col.setNoValueColour(NoValueColour.MAX);
6646 col.setNoValueColour(NoValueColour.MIN);
6649 col.setName(featureType);
6654 * Populates an XML model of the feature filter(s) for one feature type
6656 * @param firstMatcher
6657 * the first (or only) match condition)
6659 * remaining match conditions (if any)
6661 * if true, conditions are and-ed, else or-ed
6663 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6664 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6667 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6669 if (filters.hasNext())
6674 CompoundMatcher compound = new CompoundMatcher();
6675 compound.setAnd(and);
6676 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6677 firstMatcher, Collections.emptyIterator(), and);
6678 // compound.addMatcherSet(matcher1);
6679 compound.getMatcherSet().add(matcher1);
6680 FeatureMatcherI nextMatcher = filters.next();
6681 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6682 nextMatcher, filters, and);
6683 // compound.addMatcherSet(matcher2);
6684 compound.getMatcherSet().add(matcher2);
6685 result.setCompoundMatcher(compound);
6690 * single condition matcher
6692 // MatchCondition matcherModel = new MatchCondition();
6693 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6694 matcherModel.setCondition(
6695 firstMatcher.getMatcher().getCondition().getStableName());
6696 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6697 if (firstMatcher.isByAttribute())
6699 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6700 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6701 String[] attName = firstMatcher.getAttribute();
6702 matcherModel.getAttributeName().add(attName[0]); // attribute
6703 if (attName.length > 1)
6705 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6708 else if (firstMatcher.isByLabel())
6710 matcherModel.setBy(FilterBy.BY_LABEL);
6712 else if (firstMatcher.isByScore())
6714 matcherModel.setBy(FilterBy.BY_SCORE);
6716 result.setMatchCondition(matcherModel);
6723 * Loads one XML model of a feature filter to a Jalview object
6725 * @param featureType
6726 * @param matcherSetModel
6729 public static FeatureMatcherSetI parseFilter(String featureType,
6730 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6732 FeatureMatcherSetI result = new FeatureMatcherSet();
6735 parseFilterConditions(result, matcherSetModel, true);
6736 } catch (IllegalStateException e)
6738 // mixing AND and OR conditions perhaps
6739 jalview.bin.Console.errPrintln(
6740 String.format("Error reading filter conditions for '%s': %s",
6741 featureType, e.getMessage()));
6742 // return as much as was parsed up to the error
6749 * Adds feature match conditions to matcherSet as unmarshalled from XML
6750 * (possibly recursively for compound conditions)
6753 * @param matcherSetModel
6755 * if true, multiple conditions are AND-ed, else they are OR-ed
6756 * @throws IllegalStateException
6757 * if AND and OR conditions are mixed
6759 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6760 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6763 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6764 .getMatchCondition();
6770 FilterBy filterBy = mc.getBy();
6771 Condition cond = Condition.fromString(mc.getCondition());
6772 String pattern = mc.getValue();
6773 FeatureMatcherI matchCondition = null;
6774 if (filterBy == FilterBy.BY_LABEL)
6776 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6778 else if (filterBy == FilterBy.BY_SCORE)
6780 matchCondition = FeatureMatcher.byScore(cond, pattern);
6783 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6785 final List<String> attributeName = mc.getAttributeName();
6786 String[] attNames = attributeName
6787 .toArray(new String[attributeName.size()]);
6788 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6793 * note this throws IllegalStateException if AND-ing to a
6794 * previously OR-ed compound condition, or vice versa
6798 matcherSet.and(matchCondition);
6802 matcherSet.or(matchCondition);
6808 * compound condition
6810 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6811 .getCompoundMatcher().getMatcherSet();
6812 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6813 if (matchers.size() == 2)
6815 parseFilterConditions(matcherSet, matchers.get(0), anded);
6816 parseFilterConditions(matcherSet, matchers.get(1), anded);
6821 .errPrintln("Malformed compound filter condition");
6827 * Loads one XML model of a feature colour to a Jalview object
6829 * @param colourModel
6832 public static FeatureColourI parseColour(Colour colourModel)
6834 FeatureColourI colour = null;
6836 if (colourModel.getMax() != null)
6838 Color mincol = null;
6839 Color maxcol = null;
6840 Color noValueColour = null;
6844 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6845 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6846 } catch (Exception e)
6848 Console.warn("Couldn't parse out graduated feature color.", e);
6851 NoValueColour noCol = colourModel.getNoValueColour();
6852 if (noCol == NoValueColour.MIN)
6854 noValueColour = mincol;
6856 else if (noCol == NoValueColour.MAX)
6858 noValueColour = maxcol;
6861 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6862 safeFloat(colourModel.getMin()),
6863 safeFloat(colourModel.getMax()));
6864 final List<String> attributeName = colourModel.getAttributeName();
6865 String[] attributes = attributeName
6866 .toArray(new String[attributeName.size()]);
6867 if (attributes != null && attributes.length > 0)
6869 colour.setAttributeName(attributes);
6871 if (colourModel.isAutoScale() != null)
6873 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6875 if (colourModel.isColourByLabel() != null)
6877 colour.setColourByLabel(
6878 colourModel.isColourByLabel().booleanValue());
6880 if (colourModel.getThreshold() != null)
6882 colour.setThreshold(colourModel.getThreshold().floatValue());
6884 ThresholdType ttyp = colourModel.getThreshType();
6885 if (ttyp == ThresholdType.ABOVE)
6887 colour.setAboveThreshold(true);
6889 else if (ttyp == ThresholdType.BELOW)
6891 colour.setBelowThreshold(true);
6896 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6897 colour = new FeatureColour(color);
6903 public static void setStateSavedUpToDate(boolean s)
6905 Console.debug("Setting overall stateSavedUpToDate to " + s);
6906 stateSavedUpToDate = s;
6909 public static boolean stateSavedUpToDate()
6911 Console.debug("Returning overall stateSavedUpToDate value: "
6912 + stateSavedUpToDate);
6913 return stateSavedUpToDate;
6916 public static boolean allSavedUpToDate()
6918 if (stateSavedUpToDate()) // nothing happened since last project save
6921 AlignFrame[] frames = Desktop.getAlignFrames();
6924 for (int i = 0; i < frames.length; i++)
6926 if (frames[i] == null)
6928 if (!frames[i].getViewport().savedUpToDate())
6929 return false; // at least one alignment is not individually saved
6935 // used for debugging and tests
6936 private static int debugDelaySave = 20;
6938 public static void setDebugDelaySave(int n)