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 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1144 if (Desktop.desktop != null)
1146 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1149 for (JInternalFrame jif : jifs)
1151 if (jif instanceof JalviewStructureDisplayI)
1153 viewFrames.add((JalviewStructureDisplayI) jif);
1158 else if (Jalview.isHeadlessMode()
1159 && Jalview.getInstance().getCommands() != null)
1162 StructureViewerBase.getAllStructureViewerBases());
1165 String matchedFile = null;
1166 for (JalviewStructureDisplayI viewFrame : viewFrames)
1168 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1169 matchedFile, viewFrame);
1171 * Only store each structure viewer's state once in the project
1172 * jar. First time through only (storeDS==false)
1174 String viewId = viewFrame.getViewId();
1175 String viewerType = viewFrame.getViewerType().toString();
1176 if (!storeDS && !viewIds.contains(viewId))
1178 viewIds.add(viewId);
1179 File viewerState = viewFrame.saveSession();
1180 if (viewerState != null)
1182 copyFileToJar(jout, viewerState.getPath(),
1183 getViewerJarEntryName(viewId), viewerType);
1188 "Failed to save viewer state for " + viewerType);
1193 if (matchedFile != null || entry.getFile() != null)
1195 if (entry.getFile() != null)
1198 matchedFile = entry.getFile();
1200 pdb.setFile(matchedFile); // entry.getFile());
1201 if (pdbfiles == null)
1203 pdbfiles = new ArrayList<>();
1206 if (!pdbfiles.contains(pdbId))
1208 pdbfiles.add(pdbId);
1209 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1213 Enumeration<String> props = entry.getProperties();
1214 if (props.hasMoreElements())
1216 // PdbentryItem item = new PdbentryItem();
1217 while (props.hasMoreElements())
1219 Property prop = new Property();
1220 String key = props.nextElement();
1222 prop.setValue(entry.getProperty(key).toString());
1223 // item.addProperty(prop);
1224 pdb.getProperty().add(prop);
1226 // pdb.addPdbentryItem(item);
1229 // jseq.addPdbids(pdb);
1230 jseq.getPdbids().add(pdb);
1234 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1236 // jms.addJSeq(jseq);
1237 object.getJSeq().add(jseq);
1240 if (!storeDS && av.hasHiddenRows())
1242 jal = av.getAlignment();
1246 if (storeDS && jal.getCodonFrames() != null)
1248 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1249 for (AlignedCodonFrame acf : jac)
1251 AlcodonFrame alc = new AlcodonFrame();
1252 if (acf.getProtMappings() != null
1253 && acf.getProtMappings().length > 0)
1255 boolean hasMap = false;
1256 SequenceI[] dnas = acf.getdnaSeqs();
1257 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1258 for (int m = 0; m < pmaps.length; m++)
1260 AlcodMap alcmap = new AlcodMap();
1261 alcmap.setDnasq(seqHash(dnas[m]));
1263 createVamsasMapping(pmaps[m], dnas[m], null, false));
1264 // alc.addAlcodMap(alcmap);
1265 alc.getAlcodMap().add(alcmap);
1270 // vamsasSet.addAlcodonFrame(alc);
1271 vamsasSet.getAlcodonFrame().add(alc);
1274 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1276 // AlcodonFrame alc = new AlcodonFrame();
1277 // vamsasSet.addAlcodonFrame(alc);
1278 // for (int p = 0; p < acf.aaWidth; p++)
1280 // Alcodon cmap = new Alcodon();
1281 // if (acf.codons[p] != null)
1283 // // Null codons indicate a gapped column in the translated peptide
1285 // cmap.setPos1(acf.codons[p][0]);
1286 // cmap.setPos2(acf.codons[p][1]);
1287 // cmap.setPos3(acf.codons[p][2]);
1289 // alc.addAlcodon(cmap);
1291 // if (acf.getProtMappings() != null
1292 // && acf.getProtMappings().length > 0)
1294 // SequenceI[] dnas = acf.getdnaSeqs();
1295 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1296 // for (int m = 0; m < pmaps.length; m++)
1298 // AlcodMap alcmap = new AlcodMap();
1299 // alcmap.setDnasq(seqHash(dnas[m]));
1300 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1302 // alc.addAlcodMap(alcmap);
1309 // /////////////////////////////////
1310 if (!storeDS && av.getCurrentTree() != null)
1312 // FIND ANY ASSOCIATED TREES
1313 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1314 if (Desktop.desktop != null)
1316 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1318 for (int t = 0; t < frames.length; t++)
1320 if (frames[t] instanceof TreePanel)
1322 TreePanel tp = (TreePanel) frames[t];
1324 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1326 JalviewModel.Tree tree = new JalviewModel.Tree();
1327 tree.setTitle(tp.getTitle());
1328 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1329 tree.setNewick(tp.getTree().print());
1330 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1332 tree.setFitToWindow(tp.fitToWindow.getState());
1333 tree.setFontName(tp.getTreeFont().getName());
1334 tree.setFontSize(tp.getTreeFont().getSize());
1335 tree.setFontStyle(tp.getTreeFont().getStyle());
1336 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1338 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1339 tree.setShowDistances(tp.distanceMenu.getState());
1341 tree.setHeight(tp.getHeight());
1342 tree.setWidth(tp.getWidth());
1343 tree.setXpos(tp.getX());
1344 tree.setYpos(tp.getY());
1345 tree.setId(makeHashCode(tp, null));
1346 tree.setLinkToAllViews(
1347 tp.getTreeCanvas().isApplyToAllViews());
1350 if (tp.isColumnWise())
1352 tree.setColumnWise(true);
1353 String annId = tp.getAssocAnnotation().annotationId;
1354 tree.setColumnReference(annId);
1356 // jms.addTree(tree);
1357 object.getTree().add(tree);
1367 if (!storeDS && Desktop.desktop != null)
1369 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1371 if (frame instanceof PCAPanel)
1373 PCAPanel panel = (PCAPanel) frame;
1374 if (panel.getAlignViewport().getAlignment() == jal)
1376 savePCA(panel, object);
1384 * store forward refs from an annotationRow to any groups
1386 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1389 for (SequenceI sq : jal.getSequences())
1391 // Store annotation on dataset sequences only
1392 AlignmentAnnotation[] aa = sq.getAnnotation();
1393 if (aa != null && aa.length > 0)
1395 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1402 if (jal.getAlignmentAnnotation() != null)
1404 // Store the annotation shown on the alignment.
1405 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1406 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1411 if (jal.getGroups() != null)
1413 JGroup[] groups = new JGroup[jal.getGroups().size()];
1415 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1417 JGroup jGroup = new JGroup();
1418 groups[++i] = jGroup;
1420 jGroup.setStart(sg.getStartRes());
1421 jGroup.setEnd(sg.getEndRes());
1422 jGroup.setName(sg.getName());
1423 if (groupRefs.containsKey(sg))
1425 // group has references so set its ID field
1426 jGroup.setId(groupRefs.get(sg));
1428 ColourSchemeI colourScheme = sg.getColourScheme();
1429 if (colourScheme != null)
1431 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1432 if (groupColourScheme.conservationApplied())
1434 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1436 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1438 jGroup.setColour(setUserColourScheme(colourScheme,
1439 userColours, object));
1443 jGroup.setColour(colourScheme.getSchemeName());
1446 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1448 jGroup.setColour("AnnotationColourGradient");
1449 jGroup.setAnnotationColours(constructAnnotationColours(
1450 (jalview.schemes.AnnotationColourGradient) colourScheme,
1451 userColours, object));
1453 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1456 setUserColourScheme(colourScheme, userColours, object));
1460 jGroup.setColour(colourScheme.getSchemeName());
1463 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1466 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1467 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1468 jGroup.setDisplayText(sg.getDisplayText());
1469 jGroup.setColourText(sg.getColourText());
1470 jGroup.setTextCol1(sg.textColour.getRGB());
1471 jGroup.setTextCol2(sg.textColour2.getRGB());
1472 jGroup.setTextColThreshold(sg.thresholdTextColour);
1473 jGroup.setShowUnconserved(sg.getShowNonconserved());
1474 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1475 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1476 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1477 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1478 for (SequenceI seq : sg.getSequences())
1480 // jGroup.addSeq(seqHash(seq));
1481 jGroup.getSeq().add(seqHash(seq));
1485 // jms.setJGroup(groups);
1487 for (JGroup grp : groups)
1489 object.getJGroup().add(grp);
1494 // /////////SAVE VIEWPORT
1495 Viewport view = new Viewport();
1496 view.setTitle(ap.alignFrame.getTitle());
1497 view.setSequenceSetId(
1498 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1499 view.setId(av.getViewId());
1500 if (av.getCodingComplement() != null)
1502 view.setComplementId(av.getCodingComplement().getViewId());
1504 view.setViewName(av.getViewName());
1505 view.setGatheredViews(av.isGatherViewsHere());
1507 Rectangle size = ap.av.getExplodedGeometry();
1508 Rectangle position = size;
1511 size = ap.alignFrame.getBounds();
1512 if (av.getCodingComplement() != null)
1514 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1522 view.setXpos(position.x);
1523 view.setYpos(position.y);
1525 view.setWidth(size.width);
1526 view.setHeight(size.height);
1528 view.setStartRes(vpRanges.getStartRes());
1529 view.setStartSeq(vpRanges.getStartSeq());
1531 OverviewPanel ov = ap.getOverviewPanel();
1534 Overview overview = new Overview();
1535 overview.setTitle(ov.getTitle());
1536 Rectangle bounds = ov.getFrameBounds();
1537 overview.setXpos(bounds.x);
1538 overview.setYpos(bounds.y);
1539 overview.setWidth(bounds.width);
1540 overview.setHeight(bounds.height);
1541 overview.setShowHidden(ov.isShowHiddenRegions());
1542 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1543 overview.setResidueColour(
1544 ov.getCanvas().getResidueColour().getRGB());
1545 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1546 view.setOverview(overview);
1548 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1550 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1551 userColours, object));
1554 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1556 AnnotationColourScheme ac = constructAnnotationColours(
1557 (jalview.schemes.AnnotationColourGradient) av
1558 .getGlobalColourScheme(),
1559 userColours, object);
1561 view.setAnnotationColours(ac);
1562 view.setBgColour("AnnotationColourGradient");
1566 view.setBgColour(ColourSchemeProperty
1567 .getColourName(av.getGlobalColourScheme()));
1570 ResidueShaderI vcs = av.getResidueShading();
1571 ColourSchemeI cs = av.getGlobalColourScheme();
1575 if (vcs.conservationApplied())
1577 view.setConsThreshold(vcs.getConservationInc());
1578 if (cs instanceof jalview.schemes.UserColourScheme)
1580 view.setBgColour(setUserColourScheme(cs, userColours, object));
1583 view.setPidThreshold(vcs.getThreshold());
1586 view.setConservationSelected(av.getConservationSelected());
1587 view.setPidSelected(av.getAbovePIDThreshold());
1588 view.setCharHeight(av.getCharHeight());
1589 view.setCharWidth(av.getCharWidth());
1590 final Font font = av.getFont();
1591 view.setFontName(font.getName());
1592 view.setFontSize(font.getSize());
1593 view.setFontStyle(font.getStyle());
1594 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1595 view.setRenderGaps(av.isRenderGaps());
1596 view.setShowAnnotation(av.isShowAnnotation());
1597 view.setShowBoxes(av.getShowBoxes());
1598 view.setShowColourText(av.getColourText());
1599 view.setShowFullId(av.getShowJVSuffix());
1600 view.setRightAlignIds(av.isRightAlignIds());
1601 view.setIdWidth(av.getIdWidth());
1602 view.setIdWidthManuallyAdjusted(ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1604 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1605 view.setShowText(av.getShowText());
1606 view.setShowUnconserved(av.getShowUnconserved());
1607 view.setWrapAlignment(av.getWrapAlignment());
1608 view.setTextCol1(av.getTextColour().getRGB());
1609 view.setTextCol2(av.getTextColour2().getRGB());
1610 view.setTextColThreshold(av.getThresholdTextColour());
1611 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1612 view.setShowSequenceLogo(av.isShowSequenceLogo());
1613 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1614 view.setShowGroupConsensus(av.isShowGroupConsensus());
1615 view.setShowGroupConservation(av.isShowGroupConservation());
1616 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1617 view.setShowDbRefTooltip(av.isShowDBRefs());
1618 view.setFollowHighlight(av.isFollowHighlight());
1619 view.setFollowSelection(av.followSelection);
1620 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1621 view.setShowComplementFeatures(av.isShowComplementFeatures());
1622 view.setShowComplementFeaturesOnTop(
1623 av.isShowComplementFeaturesOnTop());
1624 if (av.getFeaturesDisplayed() != null)
1626 FeatureSettings fs = new FeatureSettings();
1628 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1629 .getFeatureRenderer();
1630 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1632 Vector<String> settingsAdded = new Vector<>();
1633 if (renderOrder != null)
1635 for (String featureType : renderOrder)
1637 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1638 setting.setType(featureType);
1641 * save any filter for the feature type
1643 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1646 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1648 FeatureMatcherI firstFilter = filters.next();
1649 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1650 filters, filter.isAnded()));
1654 * save colour scheme for the feature type
1656 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1657 if (!fcol.isSimpleColour())
1659 setting.setColour(fcol.getMaxColour().getRGB());
1660 setting.setMincolour(fcol.getMinColour().getRGB());
1661 setting.setMin(fcol.getMin());
1662 setting.setMax(fcol.getMax());
1663 setting.setColourByLabel(fcol.isColourByLabel());
1664 if (fcol.isColourByAttribute())
1666 String[] attName = fcol.getAttributeName();
1667 setting.getAttributeName().add(attName[0]);
1668 if (attName.length > 1)
1670 setting.getAttributeName().add(attName[1]);
1673 setting.setAutoScale(fcol.isAutoScaled());
1674 setting.setThreshold(fcol.getThreshold());
1675 Color noColour = fcol.getNoColour();
1676 if (noColour == null)
1678 setting.setNoValueColour(NoValueColour.NONE);
1680 else if (noColour.equals(fcol.getMaxColour()))
1682 setting.setNoValueColour(NoValueColour.MAX);
1686 setting.setNoValueColour(NoValueColour.MIN);
1688 // -1 = No threshold, 0 = Below, 1 = Above
1689 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1690 : (fcol.isBelowThreshold() ? 0 : -1));
1694 setting.setColour(fcol.getColour().getRGB());
1698 av.getFeaturesDisplayed().isVisible(featureType));
1699 float rorder = fr.getOrder(featureType);
1702 setting.setOrder(rorder);
1704 /// fs.addSetting(setting);
1705 fs.getSetting().add(setting);
1706 settingsAdded.addElement(featureType);
1710 // is groups actually supposed to be a map here ?
1711 Iterator<String> en = fr.getFeatureGroups().iterator();
1712 Vector<String> groupsAdded = new Vector<>();
1713 while (en.hasNext())
1715 String grp = en.next();
1716 if (groupsAdded.contains(grp))
1720 Group g = new Group();
1722 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1725 fs.getGroup().add(g);
1726 groupsAdded.addElement(grp);
1728 // jms.setFeatureSettings(fs);
1729 object.setFeatureSettings(fs);
1732 if (av.hasHiddenColumns())
1734 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1735 .getHiddenColumns();
1739 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1743 Iterator<int[]> hiddenRegions = hidden.iterator();
1744 while (hiddenRegions.hasNext())
1746 int[] region = hiddenRegions.next();
1747 HiddenColumns hc = new HiddenColumns();
1748 hc.setStart(region[0]);
1749 hc.setEnd(region[1]);
1750 // view.addHiddenColumns(hc);
1751 view.getHiddenColumns().add(hc);
1755 if (calcIdSet.size() > 0)
1757 for (String calcId : calcIdSet)
1759 if (calcId.trim().length() > 0)
1761 CalcIdParam cidp = createCalcIdParam(calcId, av);
1762 // Some calcIds have no parameters.
1765 // view.addCalcIdParam(cidp);
1766 view.getCalcIdParam().add(cidp);
1772 // jms.addViewport(view);
1773 object.getViewport().add(view);
1775 // object.setJalviewModelSequence(jms);
1776 // object.getVamsasModel().addSequenceSet(vamsasSet);
1777 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1779 if (jout != null && fileName != null)
1781 // We may not want to write the object to disk,
1782 // eg we can copy the alignViewport to a new view object
1783 // using save and then load
1786 fileName = fileName.replace('\\', '/');
1787 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1788 JarEntry entry = new JarEntry(fileName);
1789 jout.putNextEntry(entry);
1790 PrintWriter pout = new PrintWriter(
1791 new OutputStreamWriter(jout, UTF_8));
1792 JAXBContext jaxbContext = JAXBContext
1793 .newInstance(JalviewModel.class);
1794 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1796 // output pretty printed
1797 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1798 jaxbMarshaller.marshal(
1799 new ObjectFactory().createJalviewModel(object), pout);
1801 // jaxbMarshaller.marshal(object, pout);
1802 // marshaller.marshal(object);
1805 } catch (Exception ex)
1807 // TODO: raise error in GUI if marshalling failed.
1808 jalview.bin.Console.errPrintln("Error writing Jalview project");
1809 ex.printStackTrace();
1816 * Writes PCA viewer attributes and computed values to an XML model object and
1817 * adds it to the JalviewModel. Any exceptions are reported by logging.
1819 protected void savePCA(PCAPanel panel, JalviewModel object)
1823 PcaViewer viewer = new PcaViewer();
1824 viewer.setHeight(panel.getHeight());
1825 viewer.setWidth(panel.getWidth());
1826 viewer.setXpos(panel.getX());
1827 viewer.setYpos(panel.getY());
1828 viewer.setTitle(panel.getTitle());
1829 PCAModel pcaModel = panel.getPcaModel();
1830 viewer.setScoreModelName(pcaModel.getScoreModelName());
1831 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1832 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1833 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1835 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1836 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1837 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1838 SeqPointMin spmin = new SeqPointMin();
1839 spmin.setXPos(spMin[0]);
1840 spmin.setYPos(spMin[1]);
1841 spmin.setZPos(spMin[2]);
1842 viewer.setSeqPointMin(spmin);
1843 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1844 SeqPointMax spmax = new SeqPointMax();
1845 spmax.setXPos(spMax[0]);
1846 spmax.setYPos(spMax[1]);
1847 spmax.setZPos(spMax[2]);
1848 viewer.setSeqPointMax(spmax);
1849 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1850 viewer.setLinkToAllViews(
1851 panel.getRotatableCanvas().isApplyToAllViews());
1852 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1853 viewer.setIncludeGaps(sp.includeGaps());
1854 viewer.setMatchGaps(sp.matchGaps());
1855 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1856 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1859 * sequence points on display
1861 for (jalview.datamodel.SequencePoint spt : pcaModel
1862 .getSequencePoints())
1864 SequencePoint point = new SequencePoint();
1865 point.setSequenceRef(seqHash(spt.getSequence()));
1866 point.setXPos(spt.coord.x);
1867 point.setYPos(spt.coord.y);
1868 point.setZPos(spt.coord.z);
1869 viewer.getSequencePoint().add(point);
1873 * (end points of) axes on display
1875 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1878 Axis axis = new Axis();
1882 viewer.getAxis().add(axis);
1886 * raw PCA data (note we are not restoring PCA inputs here -
1887 * alignment view, score model, similarity parameters)
1889 PcaDataType data = new PcaDataType();
1890 viewer.setPcaData(data);
1891 PCA pca = pcaModel.getPcaData();
1893 DoubleMatrix pm = new DoubleMatrix();
1894 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1895 data.setPairwiseMatrix(pm);
1897 DoubleMatrix tm = new DoubleMatrix();
1898 saveDoubleMatrix(pca.getTridiagonal(), tm);
1899 data.setTridiagonalMatrix(tm);
1901 DoubleMatrix eigenMatrix = new DoubleMatrix();
1902 data.setEigenMatrix(eigenMatrix);
1903 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1905 object.getPcaViewer().add(viewer);
1906 } catch (Throwable t)
1908 Console.error("Error saving PCA: " + t.getMessage());
1913 * Stores values from a matrix into an XML element, including (if present) the
1918 * @see #loadDoubleMatrix(DoubleMatrix)
1920 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1922 xmlMatrix.setRows(m.height());
1923 xmlMatrix.setColumns(m.width());
1924 for (int i = 0; i < m.height(); i++)
1926 DoubleVector row = new DoubleVector();
1927 for (int j = 0; j < m.width(); j++)
1929 row.getV().add(m.getValue(i, j));
1931 xmlMatrix.getRow().add(row);
1933 if (m.getD() != null)
1935 DoubleVector dVector = new DoubleVector();
1936 for (double d : m.getD())
1938 dVector.getV().add(d);
1940 xmlMatrix.setD(dVector);
1942 if (m.getE() != null)
1944 DoubleVector eVector = new DoubleVector();
1945 for (double e : m.getE())
1947 eVector.getV().add(e);
1949 xmlMatrix.setE(eVector);
1954 * Loads XML matrix data into a new Matrix object, including the D and/or E
1955 * vectors (if present)
1959 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1961 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1963 int rows = mData.getRows();
1964 double[][] vals = new double[rows][];
1966 for (int i = 0; i < rows; i++)
1968 List<Double> dVector = mData.getRow().get(i).getV();
1969 vals[i] = new double[dVector.size()];
1971 for (Double d : dVector)
1977 MatrixI m = new Matrix(vals);
1979 if (mData.getD() != null)
1981 List<Double> dVector = mData.getD().getV();
1982 double[] vec = new double[dVector.size()];
1984 for (Double d : dVector)
1990 if (mData.getE() != null)
1992 List<Double> dVector = mData.getE().getV();
1993 double[] vec = new double[dVector.size()];
1995 for (Double d : dVector)
2006 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2007 * for each viewer, with
2009 * <li>viewer geometry (position, size, split pane divider location)</li>
2010 * <li>index of the selected structure in the viewer (currently shows gapped
2012 * <li>the id of the annotation holding RNA secondary structure</li>
2013 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2015 * Varna viewer state is also written out (in native Varna XML) to separate
2016 * project jar entries. A separate entry is written for each RNA structure
2017 * displayed, with the naming convention
2019 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2027 * @param storeDataset
2029 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2030 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2031 boolean storeDataset)
2033 if (Desktop.desktop == null)
2037 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2038 for (int f = frames.length - 1; f > -1; f--)
2040 if (frames[f] instanceof AppVarna)
2042 AppVarna varna = (AppVarna) frames[f];
2044 * link the sequence to every viewer that is showing it and is linked to
2045 * its alignment panel
2047 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2049 String viewId = varna.getViewId();
2050 RnaViewer rna = new RnaViewer();
2051 rna.setViewId(viewId);
2052 rna.setTitle(varna.getTitle());
2053 rna.setXpos(varna.getX());
2054 rna.setYpos(varna.getY());
2055 rna.setWidth(varna.getWidth());
2056 rna.setHeight(varna.getHeight());
2057 rna.setDividerLocation(varna.getDividerLocation());
2058 rna.setSelectedRna(varna.getSelectedIndex());
2059 // jseq.addRnaViewer(rna);
2060 jseq.getRnaViewer().add(rna);
2063 * Store each Varna panel's state once in the project per sequence.
2064 * First time through only (storeDataset==false)
2066 // boolean storeSessions = false;
2067 // String sequenceViewId = viewId + seqsToIds.get(jds);
2068 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2070 // viewIds.add(sequenceViewId);
2071 // storeSessions = true;
2073 for (RnaModel model : varna.getModels())
2075 if (model.seq == jds)
2078 * VARNA saves each view (sequence or alignment secondary
2079 * structure, gapped or trimmed) as a separate XML file
2081 String jarEntryName = rnaSessions.get(model);
2082 if (jarEntryName == null)
2085 String varnaStateFile = varna.getStateInfo(model.rna);
2086 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2087 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2088 rnaSessions.put(model, jarEntryName);
2090 SecondaryStructure ss = new SecondaryStructure();
2091 String annotationId = varna.getAnnotation(jds).annotationId;
2092 ss.setAnnotationId(annotationId);
2093 ss.setViewerState(jarEntryName);
2094 ss.setGapped(model.gapped);
2095 ss.setTitle(model.title);
2096 // rna.addSecondaryStructure(ss);
2097 rna.getSecondaryStructure().add(ss);
2106 * Copy the contents of a file to a new entry added to the output jar
2110 * @param jarEntryName
2112 * additional identifying info to log to the console
2114 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2115 String jarEntryName, String msg)
2117 try (InputStream is = new FileInputStream(infilePath))
2119 File file = new File(infilePath);
2120 if (file.exists() && jout != null)
2122 jalview.bin.Console.outPrintln(
2123 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2124 jout.putNextEntry(new JarEntry(jarEntryName));
2127 // dis = new DataInputStream(new FileInputStream(file));
2128 // byte[] data = new byte[(int) file.length()];
2129 // dis.readFully(data);
2130 // writeJarEntry(jout, jarEntryName, data);
2132 } catch (Exception ex)
2134 ex.printStackTrace();
2139 * Copies input to output, in 4K buffers; handles any data (text or binary)
2143 * @throws IOException
2145 protected void copyAll(InputStream in, OutputStream out)
2148 byte[] buffer = new byte[4096];
2150 while ((bytesRead = in.read(buffer)) != -1)
2152 out.write(buffer, 0, bytesRead);
2157 * Save the state of a structure viewer
2162 * the archive XML element under which to save the state
2165 * @param matchedFile
2169 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2170 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2171 String matchedFile, JalviewStructureDisplayI viewFrame)
2173 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2176 * Look for any bindings for this viewer to the PDB file of interest
2177 * (including part matches excluding chain id)
2179 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2181 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2182 final String pdbId = pdbentry.getId();
2183 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2184 && entry.getId().toLowerCase(Locale.ROOT)
2185 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2188 * not interested in a binding to a different PDB entry here
2192 if (matchedFile == null)
2194 matchedFile = pdbentry.getFile();
2196 else if (!matchedFile.equals(pdbentry.getFile()))
2199 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2200 + pdbentry.getFile());
2204 // can get at it if the ID
2205 // match is ambiguous (e.g.
2208 for (int smap = 0; smap < viewFrame.getBinding()
2209 .getSequence()[peid].length; smap++)
2211 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2212 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2214 StructureState state = new StructureState();
2215 state.setVisible(true);
2216 state.setXpos(viewFrame.getY());
2217 state.setYpos(viewFrame.getY());
2218 state.setWidth(viewFrame.getWidth());
2219 state.setHeight(viewFrame.getHeight());
2220 final String viewId = viewFrame.getViewId();
2221 state.setViewId(viewId);
2222 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2223 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2224 state.setColourByJmol(viewFrame.isColouredByViewer());
2225 state.setType(viewFrame.getViewerType().toString());
2226 // pdb.addStructureState(state);
2227 pdb.getStructureState().add(state);
2235 * Populates the AnnotationColourScheme xml for save. This captures the
2236 * settings of the options in the 'Colour by Annotation' dialog.
2239 * @param userColours
2243 private AnnotationColourScheme constructAnnotationColours(
2244 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2247 AnnotationColourScheme ac = new AnnotationColourScheme();
2248 ac.setAboveThreshold(acg.getAboveThreshold());
2249 ac.setThreshold(acg.getAnnotationThreshold());
2250 // 2.10.2 save annotationId (unique) not annotation label
2251 ac.setAnnotation(acg.getAnnotation().annotationId);
2252 if (acg.getBaseColour() instanceof UserColourScheme)
2255 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2260 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2263 ac.setMaxColour(acg.getMaxColour().getRGB());
2264 ac.setMinColour(acg.getMinColour().getRGB());
2265 ac.setPerSequence(acg.isSeqAssociated());
2266 ac.setPredefinedColours(acg.isPredefinedColours());
2270 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2271 IdentityHashMap<SequenceGroup, String> groupRefs,
2272 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2273 SequenceSet vamsasSet)
2276 for (int i = 0; i < aa.length; i++)
2278 Annotation an = new Annotation();
2280 AlignmentAnnotation annotation = aa[i];
2281 if (annotation.annotationId != null)
2283 annotationIds.put(annotation.annotationId, annotation);
2286 an.setId(annotation.annotationId);
2288 an.setVisible(annotation.visible);
2290 an.setDescription(annotation.description);
2292 if (annotation.sequenceRef != null)
2294 // 2.9 JAL-1781 xref on sequence id rather than name
2295 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2297 if (annotation.groupRef != null)
2299 String groupIdr = groupRefs.get(annotation.groupRef);
2300 if (groupIdr == null)
2302 // make a locally unique String
2303 groupRefs.put(annotation.groupRef,
2304 groupIdr = ("" + System.currentTimeMillis()
2305 + annotation.groupRef.getName()
2306 + groupRefs.size()));
2308 an.setGroupRef(groupIdr.toString());
2311 // store all visualization attributes for annotation
2312 an.setGraphHeight(annotation.graphHeight);
2313 an.setCentreColLabels(annotation.centreColLabels);
2314 an.setScaleColLabels(annotation.scaleColLabel);
2315 an.setShowAllColLabels(annotation.showAllColLabels);
2316 an.setBelowAlignment(annotation.belowAlignment);
2318 if (annotation.graph > 0)
2321 an.setGraphType(annotation.graph);
2322 an.setGraphGroup(annotation.graphGroup);
2323 if (annotation.getThreshold() != null)
2325 ThresholdLine line = new ThresholdLine();
2326 line.setLabel(annotation.getThreshold().label);
2327 line.setValue(annotation.getThreshold().value);
2328 line.setColour(annotation.getThreshold().colour.getRGB());
2329 an.setThresholdLine(line);
2331 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2333 if (annotation.sequenceRef.getContactMaps() != null)
2335 ContactMatrixI cm = annotation.sequenceRef
2336 .getContactMatrixFor(annotation);
2339 MatrixType xmlmat = new MatrixType();
2340 xmlmat.setType(cm.getType());
2341 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2342 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2343 // consider using an opaque to/from -> allow instance to control
2344 // its representation ?
2345 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2348 for (BitSet gp : cm.getGroups())
2350 xmlmat.getGroups().add(stringifyBitset(gp));
2355 // provenance object for tree ?
2356 xmlmat.getNewick().add(cm.getNewick());
2357 xmlmat.setTreeMethod(cm.getTreeMethod());
2359 if (cm.hasCutHeight())
2361 xmlmat.setCutHeight(cm.getCutHeight());
2363 // set/get properties
2364 if (cm instanceof MappableContactMatrixI)
2366 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2367 .getMapFor(annotation.sequenceRef);
2370 MapListType mp = new MapListType();
2371 List<int[]> r = mlst.getFromRanges();
2372 for (int[] range : r)
2374 MapListFrom mfrom = new MapListFrom();
2375 mfrom.setStart(range[0]);
2376 mfrom.setEnd(range[1]);
2377 // mp.addMapListFrom(mfrom);
2378 mp.getMapListFrom().add(mfrom);
2380 r = mlst.getToRanges();
2381 for (int[] range : r)
2383 MapListTo mto = new MapListTo();
2384 mto.setStart(range[0]);
2385 mto.setEnd(range[1]);
2386 // mp.addMapListTo(mto);
2387 mp.getMapListTo().add(mto);
2390 BigInteger.valueOf(mlst.getFromRatio()));
2391 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2392 xmlmat.setMapping(mp);
2396 an.getContactmatrix().add(xmlmat);
2406 an.setLabel(annotation.label);
2408 if (annotation == av.getAlignmentQualityAnnot()
2409 || annotation == av.getAlignmentConservationAnnotation()
2410 || annotation == av.getAlignmentConsensusAnnotation()
2411 || annotation.autoCalculated)
2413 // new way of indicating autocalculated annotation -
2414 an.setAutoCalculated(annotation.autoCalculated);
2416 if (annotation.hasScore())
2418 an.setScore(annotation.getScore());
2421 if (annotation.getCalcId() != null)
2423 calcIdSet.add(annotation.getCalcId());
2424 an.setCalcId(annotation.getCalcId());
2426 if (annotation.hasProperties())
2428 for (String pr : annotation.getProperties())
2430 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2432 prop.setValue(annotation.getProperty(pr));
2433 an.getProperty().add(prop);
2437 AnnotationElement ae;
2438 if (annotation.annotations != null)
2440 an.setScoreOnly(false);
2441 for (int a = 0; a < annotation.annotations.length; a++)
2443 if ((annotation == null) || (annotation.annotations[a] == null))
2448 ae = new AnnotationElement();
2449 if (annotation.annotations[a].description != null)
2451 ae.setDescription(annotation.annotations[a].description);
2453 if (annotation.annotations[a].displayCharacter != null)
2455 ae.setDisplayCharacter(
2456 annotation.annotations[a].displayCharacter);
2459 if (!Float.isNaN(annotation.annotations[a].value))
2461 ae.setValue(annotation.annotations[a].value);
2465 if (annotation.annotations[a].secondaryStructure > ' ')
2467 ae.setSecondaryStructure(
2468 annotation.annotations[a].secondaryStructure + "");
2471 if (annotation.annotations[a].colour != null
2472 && annotation.annotations[a].colour != java.awt.Color.black)
2474 ae.setColour(annotation.annotations[a].colour.getRGB());
2477 // an.addAnnotationElement(ae);
2478 an.getAnnotationElement().add(ae);
2479 if (annotation.autoCalculated)
2481 // only write one non-null entry into the annotation row -
2482 // sufficient to get the visualization attributes necessary to
2490 an.setScoreOnly(true);
2492 if (!storeDS || (storeDS && !annotation.autoCalculated))
2494 // skip autocalculated annotation - these are only provided for
2496 // vamsasSet.addAnnotation(an);
2497 vamsasSet.getAnnotation().add(an);
2503 private String stringifyBitset(BitSet gp)
2505 StringBuilder sb = new StringBuilder();
2506 for (long val : gp.toLongArray())
2508 if (sb.length() > 0)
2514 return sb.toString();
2517 private BitSet deStringifyBitset(String stringified)
2519 if ("".equals(stringified) || stringified == null)
2521 return new BitSet();
2523 String[] longvals = stringified.split(",");
2524 long[] newlongvals = new long[longvals.length];
2525 for (int lv = 0; lv < longvals.length; lv++)
2529 newlongvals[lv] = Long.valueOf(longvals[lv]);
2530 } catch (Exception x)
2532 errorMessage += "Couldn't destringify bitset from: '" + stringified
2534 newlongvals[lv] = 0;
2537 return BitSet.valueOf(newlongvals);
2541 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2543 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2544 if (settings != null)
2546 CalcIdParam vCalcIdParam = new CalcIdParam();
2547 vCalcIdParam.setCalcId(calcId);
2548 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2549 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2550 // generic URI allowing a third party to resolve another instance of the
2551 // service used for this calculation
2552 for (String url : settings.getServiceURLs())
2554 // vCalcIdParam.addServiceURL(urls);
2555 vCalcIdParam.getServiceURL().add(url);
2557 vCalcIdParam.setVersion("1.0");
2558 if (settings.getPreset() != null)
2560 WsParamSetI setting = settings.getPreset();
2561 vCalcIdParam.setName(setting.getName());
2562 vCalcIdParam.setDescription(setting.getDescription());
2566 vCalcIdParam.setName("");
2567 vCalcIdParam.setDescription("Last used parameters");
2569 // need to be able to recover 1) settings 2) user-defined presets or
2570 // recreate settings from preset 3) predefined settings provided by
2571 // service - or settings that can be transferred (or discarded)
2572 vCalcIdParam.setParameters(
2573 settings.getWsParamFile().replace("\n", "|\\n|"));
2574 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2575 // todo - decide if updateImmediately is needed for any projects.
2577 return vCalcIdParam;
2582 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2585 if (calcIdParam.getVersion().equals("1.0"))
2587 final String[] calcIds = calcIdParam.getServiceURL()
2588 .toArray(new String[0]);
2589 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2590 .getPreferredServiceFor(calcIds);
2591 if (service != null)
2593 WsParamSetI parmSet = null;
2596 parmSet = service.getParamStore().parseServiceParameterFile(
2597 calcIdParam.getName(), calcIdParam.getDescription(),
2599 calcIdParam.getParameters().replace("|\\n|", "\n"));
2600 } catch (IOException x)
2602 Console.warn("Couldn't parse parameter data for "
2603 + calcIdParam.getCalcId(), x);
2606 List<ArgumentI> argList = null;
2607 if (calcIdParam.getName().length() > 0)
2609 parmSet = service.getParamStore()
2610 .getPreset(calcIdParam.getName());
2611 if (parmSet != null)
2613 // TODO : check we have a good match with settings in AACon -
2614 // otherwise we'll need to create a new preset
2619 argList = parmSet.getArguments();
2622 AAConSettings settings = new AAConSettings(
2623 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2624 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2625 calcIdParam.isNeedsUpdate());
2631 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2635 throw new Error(MessageManager.formatMessage(
2636 "error.unsupported_version_calcIdparam", new Object[]
2637 { calcIdParam.toString() }));
2641 * External mapping between jalview objects and objects yielding a valid and
2642 * unique object ID string. This is null for normal Jalview project IO, but
2643 * non-null when a jalview project is being read or written as part of a
2646 IdentityHashMap jv2vobj = null;
2649 * Construct a unique ID for jvobj using either existing bindings or if none
2650 * exist, the result of the hashcode call for the object.
2653 * jalview data object
2654 * @return unique ID for referring to jvobj
2656 private String makeHashCode(Object jvobj, String altCode)
2658 if (jv2vobj != null)
2660 Object id = jv2vobj.get(jvobj);
2663 return id.toString();
2665 // check string ID mappings
2666 if (jvids2vobj != null && jvobj instanceof String)
2668 id = jvids2vobj.get(jvobj);
2672 return id.toString();
2674 // give up and warn that something has gone wrong
2676 "Cannot find ID for object in external mapping : " + jvobj);
2682 * return local jalview object mapped to ID, if it exists
2686 * @return null or object bound to idcode
2688 private Object retrieveExistingObj(String idcode)
2690 if (idcode != null && vobj2jv != null)
2692 return vobj2jv.get(idcode);
2698 * binding from ID strings from external mapping table to jalview data model
2701 private Hashtable vobj2jv;
2703 private Sequence createVamsasSequence(String id, SequenceI jds)
2705 return createVamsasSequence(true, id, jds, null);
2708 private Sequence createVamsasSequence(boolean recurse, String id,
2709 SequenceI jds, SequenceI parentseq)
2711 Sequence vamsasSeq = new Sequence();
2712 vamsasSeq.setId(id);
2713 vamsasSeq.setName(jds.getName());
2714 vamsasSeq.setSequence(jds.getSequenceAsString());
2715 vamsasSeq.setDescription(jds.getDescription());
2716 List<DBRefEntry> dbrefs = null;
2717 if (jds.getDatasetSequence() != null)
2719 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2723 // seqId==dsseqid so we can tell which sequences really are
2724 // dataset sequences only
2725 vamsasSeq.setDsseqid(id);
2726 dbrefs = jds.getDBRefs();
2727 if (parentseq == null)
2734 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2738 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2740 DBRef dbref = new DBRef();
2741 DBRefEntry ref = dbrefs.get(d);
2742 dbref.setSource(ref.getSource());
2743 dbref.setVersion(ref.getVersion());
2744 dbref.setAccessionId(ref.getAccessionId());
2745 dbref.setCanonical(ref.isCanonical());
2746 if (ref instanceof GeneLocus)
2748 dbref.setLocus(true);
2752 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2754 dbref.setMapping(mp);
2756 vamsasSeq.getDBRef().add(dbref);
2762 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2763 SequenceI parentseq, SequenceI jds, boolean recurse)
2766 if (jmp.getMap() != null)
2770 jalview.util.MapList mlst = jmp.getMap();
2771 List<int[]> r = mlst.getFromRanges();
2772 for (int[] range : r)
2774 MapListFrom mfrom = new MapListFrom();
2775 mfrom.setStart(range[0]);
2776 mfrom.setEnd(range[1]);
2777 // mp.addMapListFrom(mfrom);
2778 mp.getMapListFrom().add(mfrom);
2780 r = mlst.getToRanges();
2781 for (int[] range : r)
2783 MapListTo mto = new MapListTo();
2784 mto.setStart(range[0]);
2785 mto.setEnd(range[1]);
2786 // mp.addMapListTo(mto);
2787 mp.getMapListTo().add(mto);
2789 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2790 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2791 if (jmp.getTo() != null)
2793 // MappingChoice mpc = new MappingChoice();
2795 // check/create ID for the sequence referenced by getTo()
2798 SequenceI ps = null;
2799 if (parentseq != jmp.getTo()
2800 && parentseq.getDatasetSequence() != jmp.getTo())
2802 // chaining dbref rather than a handshaking one
2803 jmpid = seqHash(ps = jmp.getTo());
2807 jmpid = seqHash(ps = parentseq);
2809 // mpc.setDseqFor(jmpid);
2810 mp.setDseqFor(jmpid);
2811 if (!seqRefIds.containsKey(jmpid))
2813 Console.debug("creatign new DseqFor ID");
2814 seqRefIds.put(jmpid, ps);
2818 Console.debug("reusing DseqFor ID");
2821 // mp.setMappingChoice(mpc);
2827 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2828 List<UserColourScheme> userColours, JalviewModel jm)
2831 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2832 boolean newucs = false;
2833 if (!userColours.contains(ucs))
2835 userColours.add(ucs);
2838 id = "ucs" + userColours.indexOf(ucs);
2841 // actually create the scheme's entry in the XML model
2842 java.awt.Color[] colours = ucs.getColours();
2843 UserColours uc = new UserColours();
2844 // UserColourScheme jbucs = new UserColourScheme();
2845 JalviewUserColours jbucs = new JalviewUserColours();
2847 for (int i = 0; i < colours.length; i++)
2849 Colour col = new Colour();
2850 col.setName(ResidueProperties.aa[i]);
2851 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2852 // jbucs.addColour(col);
2853 jbucs.getColour().add(col);
2855 if (ucs.getLowerCaseColours() != null)
2857 colours = ucs.getLowerCaseColours();
2858 for (int i = 0; i < colours.length; i++)
2860 Colour col = new Colour();
2861 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2862 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2863 // jbucs.addColour(col);
2864 jbucs.getColour().add(col);
2869 uc.setUserColourScheme(jbucs);
2870 // jm.addUserColours(uc);
2871 jm.getUserColours().add(uc);
2877 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2880 List<UserColours> uc = jm.getUserColours();
2881 UserColours colours = null;
2883 for (int i = 0; i < uc.length; i++)
2885 if (uc[i].getId().equals(id))
2892 for (UserColours c : uc)
2894 if (c.getId().equals(id))
2901 java.awt.Color[] newColours = new java.awt.Color[24];
2903 for (int i = 0; i < 24; i++)
2905 newColours[i] = new java.awt.Color(Integer.parseInt(
2906 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2907 colours.getUserColourScheme().getColour().get(i).getRGB(),
2911 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2914 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2916 newColours = new java.awt.Color[23];
2917 for (int i = 0; i < 23; i++)
2919 newColours[i] = new java.awt.Color(
2920 Integer.parseInt(colours.getUserColourScheme().getColour()
2921 .get(i + 24).getRGB(), 16));
2923 ucs.setLowerCaseColours(newColours);
2930 * contains last error message (if any) encountered by XML loader.
2932 String errorMessage = null;
2935 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2936 * exceptions are raised during project XML parsing
2938 public boolean attemptversion1parse = false;
2941 * Load a jalview project archive from a jar file
2944 * - HTTP URL or filename
2946 public AlignFrame loadJalviewAlign(final Object file)
2949 jalview.gui.AlignFrame af = null;
2953 // create list to store references for any new Jmol viewers created
2954 newStructureViewers = new Vector<>();
2955 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2956 // Workaround is to make sure caller implements the JarInputStreamProvider
2958 // so we can re-open the jar input stream for each entry.
2960 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2961 af = loadJalviewAlign(jprovider);
2964 af.setMenusForViewport();
2966 } catch (MalformedURLException e)
2968 errorMessage = "Invalid URL format for '" + file + "'";
2974 SwingUtilities.invokeAndWait(new Runnable()
2979 setLoadingFinishedForNewStructureViewers();
2982 } catch (Exception x)
2985 .errPrintln("Error loading alignment: " + x.getMessage());
2991 @SuppressWarnings("unused")
2992 private jarInputStreamProvider createjarInputStreamProvider(
2993 final Object ofile) throws MalformedURLException
2996 // BH 2018 allow for bytes already attached to File object
2999 String file = (ofile instanceof File
3000 ? ((File) ofile).getCanonicalPath()
3001 : ofile.toString());
3002 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3005 errorMessage = null;
3006 uniqueSetSuffix = null;
3008 viewportsAdded.clear();
3009 frefedSequence = null;
3011 if (HttpUtils.startsWithHttpOrHttps(file))
3013 url = new URL(file);
3015 final URL _url = url;
3016 return new jarInputStreamProvider()
3020 public JarInputStream getJarInputStream() throws IOException
3024 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3025 // jarInputStream for
3026 // bytes.length=" + bytes.length);
3027 return new JarInputStream(new ByteArrayInputStream(bytes));
3031 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3032 // jarInputStream for "
3034 return new JarInputStream(_url.openStream());
3038 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3039 // jarInputStream for
3041 return new JarInputStream(new FileInputStream(file));
3046 public String getFilename()
3051 } catch (IOException e)
3053 e.printStackTrace();
3059 * Recover jalview session from a jalview project archive. Caller may
3060 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3061 * themselves. Any null fields will be initialised with default values,
3062 * non-null fields are left alone.
3067 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3069 errorMessage = null;
3070 if (uniqueSetSuffix == null)
3072 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3074 if (seqRefIds == null)
3078 AlignFrame af = null, _af = null;
3079 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3080 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3081 final String file = jprovider.getFilename();
3084 JarInputStream jin = null;
3085 JarEntry jarentry = null;
3090 jin = jprovider.getJarInputStream();
3091 for (int i = 0; i < entryCount; i++)
3093 jarentry = jin.getNextJarEntry();
3096 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3098 JAXBContext jc = JAXBContext
3099 .newInstance("jalview.xml.binding.jalview");
3100 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3101 .createXMLStreamReader(jin);
3102 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3103 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3104 JalviewModel.class);
3105 JalviewModel object = jbe.getValue();
3107 if (true) // !skipViewport(object))
3109 _af = loadFromObject(object, file, true, jprovider);
3110 if (_af != null && object.getViewport().size() > 0)
3111 // getJalviewModelSequence().getViewportCount() > 0)
3115 // store a reference to the first view
3118 if (_af.getViewport().isGatherViewsHere())
3120 // if this is a gathered view, keep its reference since
3121 // after gathering views, only this frame will remain
3123 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3126 // Save dataset to register mappings once all resolved
3127 importedDatasets.put(
3128 af.getViewport().getAlignment().getDataset(),
3129 af.getViewport().getAlignment().getDataset());
3134 else if (jarentry != null)
3136 // Some other file here.
3139 } while (jarentry != null);
3141 resolveFrefedSequences();
3142 } catch (IOException ex)
3144 ex.printStackTrace();
3145 errorMessage = "Couldn't locate Jalview XML file : " + file;
3146 jalview.bin.Console.errPrintln(
3147 "Exception whilst loading jalview XML file : " + ex + "\n");
3148 } catch (Exception ex)
3151 .errPrintln("Parsing as Jalview Version 2 file failed.");
3152 ex.printStackTrace(System.err);
3153 if (attemptversion1parse)
3155 // used to attempt to parse as V1 castor-generated xml
3157 if (Desktop.instance != null)
3159 Desktop.instance.stopLoading();
3163 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3166 ex.printStackTrace();
3168 jalview.bin.Console.errPrintln(
3169 "Exception whilst loading jalview XML file : " + ex + "\n");
3170 } catch (OutOfMemoryError e)
3172 // Don't use the OOM Window here
3173 errorMessage = "Out of memory loading jalview XML file";
3175 .errPrintln("Out of memory whilst loading jalview XML file");
3176 e.printStackTrace();
3180 * Regather multiple views (with the same sequence set id) to the frame (if
3181 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3182 * views instead of separate frames. Note this doesn't restore a state where
3183 * some expanded views in turn have tabbed views - the last "first tab" read
3184 * in will play the role of gatherer for all.
3186 for (AlignFrame fr : gatherToThisFrame.values())
3188 Desktop.instance.gatherViews(fr);
3191 restoreSplitFrames();
3192 for (AlignmentI ds : importedDatasets.keySet())
3194 if (ds.getCodonFrames() != null)
3196 StructureSelectionManager
3197 .getStructureSelectionManager(Desktop.instance)
3198 .registerMappings(ds.getCodonFrames());
3201 if (errorMessage != null)
3206 if (Desktop.instance != null)
3208 Desktop.instance.stopLoading();
3215 * Try to reconstruct and display SplitFrame windows, where each contains
3216 * complementary dna and protein alignments. Done by pairing up AlignFrame
3217 * objects (created earlier) which have complementary viewport ids associated.
3219 protected void restoreSplitFrames()
3221 List<SplitFrame> gatherTo = new ArrayList<>();
3222 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3223 Map<String, AlignFrame> dna = new HashMap<>();
3226 * Identify the DNA alignments
3228 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3231 AlignFrame af = candidate.getValue();
3232 if (af.getViewport().getAlignment().isNucleotide())
3234 dna.put(candidate.getKey().getId(), af);
3239 * Try to match up the protein complements
3241 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3244 AlignFrame af = candidate.getValue();
3245 if (!af.getViewport().getAlignment().isNucleotide())
3247 String complementId = candidate.getKey().getComplementId();
3248 // only non-null complements should be in the Map
3249 if (complementId != null && dna.containsKey(complementId))
3251 final AlignFrame dnaFrame = dna.get(complementId);
3252 SplitFrame sf = createSplitFrame(dnaFrame, af);
3253 addedToSplitFrames.add(dnaFrame);
3254 addedToSplitFrames.add(af);
3255 dnaFrame.setMenusForViewport();
3256 af.setMenusForViewport();
3257 if (af.getViewport().isGatherViewsHere())
3266 * Open any that we failed to pair up (which shouldn't happen!) as
3267 * standalone AlignFrame's.
3269 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3272 AlignFrame af = candidate.getValue();
3273 if (!addedToSplitFrames.contains(af))
3275 Viewport view = candidate.getKey();
3276 Desktop.addInternalFrame(af, view.getTitle(),
3277 safeInt(view.getWidth()), safeInt(view.getHeight()));
3278 af.setMenusForViewport();
3279 jalview.bin.Console.errPrintln("Failed to restore view "
3280 + view.getTitle() + " to split frame");
3285 * Gather back into tabbed views as flagged.
3287 for (SplitFrame sf : gatherTo)
3289 Desktop.instance.gatherViews(sf);
3292 splitFrameCandidates.clear();
3296 * Construct and display one SplitFrame holding DNA and protein alignments.
3299 * @param proteinFrame
3302 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3303 AlignFrame proteinFrame)
3305 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3306 String title = MessageManager.getString("label.linked_view_title");
3307 int width = (int) dnaFrame.getBounds().getWidth();
3308 int height = (int) (dnaFrame.getBounds().getHeight()
3309 + proteinFrame.getBounds().getHeight() + 50);
3312 * SplitFrame location is saved to both enclosed frames
3314 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3315 Desktop.addInternalFrame(splitFrame, title, width, height);
3318 * And compute cDNA consensus (couldn't do earlier with consensus as
3319 * mappings were not yet present)
3321 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3327 * check errorMessage for a valid error message and raise an error box in the
3328 * GUI or write the current errorMessage to stderr and then clear the error
3331 protected void reportErrors()
3333 reportErrors(false);
3336 protected void reportErrors(final boolean saving)
3338 if (errorMessage != null)
3340 final String finalErrorMessage = errorMessage;
3343 javax.swing.SwingUtilities.invokeLater(new Runnable()
3348 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3350 "Error " + (saving ? "saving" : "loading")
3352 JvOptionPane.WARNING_MESSAGE);
3358 jalview.bin.Console.errPrintln(
3359 "Problem loading Jalview file: " + errorMessage);
3362 errorMessage = null;
3365 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3368 * when set, local views will be updated from view stored in JalviewXML
3369 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3370 * sync if this is set to true.
3372 private final boolean updateLocalViews = false;
3375 * Returns the path to a temporary file holding the PDB file for the given PDB
3376 * id. The first time of asking, searches for a file of that name in the
3377 * Jalview project jar, and copies it to a new temporary file. Any repeat
3378 * requests just return the path to the file previously created.
3384 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3387 if (alreadyLoadedPDB.containsKey(pdbId))
3389 return alreadyLoadedPDB.get(pdbId).toString();
3392 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3394 if (tempFile != null)
3396 alreadyLoadedPDB.put(pdbId, tempFile);
3402 * Copies the jar entry of given name to a new temporary file and returns the
3403 * path to the file, or null if the entry is not found.
3406 * @param jarEntryName
3408 * a prefix for the temporary file name, must be at least three
3410 * @param suffixModel
3411 * null or original file - so new file can be given the same suffix
3415 protected String copyJarEntry(jarInputStreamProvider jprovider,
3416 String jarEntryName, String prefix, String suffixModel)
3418 String suffix = ".tmp";
3419 if (suffixModel == null)
3421 suffixModel = jarEntryName;
3423 int sfpos = suffixModel.lastIndexOf(".");
3424 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3426 suffix = "." + suffixModel.substring(sfpos + 1);
3429 try (JarInputStream jin = jprovider.getJarInputStream())
3431 JarEntry entry = null;
3434 entry = jin.getNextJarEntry();
3435 } while (entry != null && !entry.getName().equals(jarEntryName));
3439 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3440 File outFile = File.createTempFile(prefix, suffix);
3441 outFile.deleteOnExit();
3442 try (OutputStream os = new FileOutputStream(outFile))
3446 String t = outFile.getAbsolutePath();
3452 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3454 } catch (Exception ex)
3456 ex.printStackTrace();
3462 private class JvAnnotRow
3464 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3471 * persisted version of annotation row from which to take vis properties
3473 public jalview.datamodel.AlignmentAnnotation template;
3476 * original position of the annotation row in the alignment
3482 * Load alignment frame from jalview XML DOM object
3484 * @param jalviewModel
3487 * filename source string
3488 * @param loadTreesAndStructures
3489 * when false only create Viewport
3491 * data source provider
3492 * @return alignment frame created from view stored in DOM
3494 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3495 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3497 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3499 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3501 // JalviewModelSequence jms = object.getJalviewModelSequence();
3503 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3505 Viewport view = (jalviewModel.getViewport().size() > 0)
3506 ? jalviewModel.getViewport().get(0)
3509 // ////////////////////////////////
3510 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3513 // If we just load in the same jar file again, the sequenceSetId
3514 // will be the same, and we end up with multiple references
3515 // to the same sequenceSet. We must modify this id on load
3516 // so that each load of the file gives a unique id
3519 * used to resolve correct alignment dataset for alignments with multiple
3522 String uniqueSeqSetId = null;
3523 String viewId = null;
3526 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3527 viewId = (view.getId() == null ? null
3528 : view.getId() + uniqueSetSuffix);
3531 // ////////////////////////////////
3534 List<SequenceI> hiddenSeqs = null;
3536 List<SequenceI> tmpseqs = new ArrayList<>();
3538 boolean multipleView = false;
3539 SequenceI referenceseqForView = null;
3540 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3541 List<JSeq> jseqs = jalviewModel.getJSeq();
3542 int vi = 0; // counter in vamsasSeq array
3543 for (int i = 0; i < jseqs.size(); i++)
3545 JSeq jseq = jseqs.get(i);
3546 String seqId = jseq.getId();
3548 SequenceI tmpSeq = seqRefIds.get(seqId);
3551 if (!incompleteSeqs.containsKey(seqId))
3553 // may not need this check, but keep it for at least 2.9,1 release
3554 if (tmpSeq.getStart() != jseq.getStart()
3555 || tmpSeq.getEnd() != jseq.getEnd())
3557 jalview.bin.Console.errPrintln(String.format(
3558 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3559 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3560 jseq.getStart(), jseq.getEnd()));
3565 incompleteSeqs.remove(seqId);
3567 if (vamsasSeqs.size() > vi
3568 && vamsasSeqs.get(vi).getId().equals(seqId))
3570 // most likely we are reading a dataset XML document so
3571 // update from vamsasSeq section of XML for this sequence
3572 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3573 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3574 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3579 // reading multiple views, so vamsasSeq set is a subset of JSeq
3580 multipleView = true;
3582 tmpSeq.setStart(jseq.getStart());
3583 tmpSeq.setEnd(jseq.getEnd());
3584 tmpseqs.add(tmpSeq);
3588 Sequence vamsasSeq = vamsasSeqs.get(vi);
3589 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3590 vamsasSeq.getSequence());
3591 tmpSeq.setDescription(vamsasSeq.getDescription());
3592 tmpSeq.setStart(jseq.getStart());
3593 tmpSeq.setEnd(jseq.getEnd());
3594 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3595 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3596 tmpseqs.add(tmpSeq);
3600 if (safeBoolean(jseq.isViewreference()))
3602 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3605 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3607 if (hiddenSeqs == null)
3609 hiddenSeqs = new ArrayList<>();
3612 hiddenSeqs.add(tmpSeq);
3617 // Create the alignment object from the sequence set
3618 // ///////////////////////////////
3619 SequenceI[] orderedSeqs = tmpseqs
3620 .toArray(new SequenceI[tmpseqs.size()]);
3622 AlignmentI al = null;
3623 // so we must create or recover the dataset alignment before going further
3624 // ///////////////////////////////
3625 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3627 // older jalview projects do not have a dataset - so creat alignment and
3629 al = new Alignment(orderedSeqs);
3630 al.setDataset(null);
3634 boolean isdsal = jalviewModel.getViewport().isEmpty();
3637 // we are importing a dataset record, so
3638 // recover reference to an alignment already materialsed as dataset
3639 al = getDatasetFor(vamsasSet.getDatasetId());
3643 // materialse the alignment
3644 al = new Alignment(orderedSeqs);
3648 addDatasetRef(vamsasSet.getDatasetId(), al);
3651 // finally, verify all data in vamsasSet is actually present in al
3652 // passing on flag indicating if it is actually a stored dataset
3653 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3656 if (referenceseqForView != null)
3658 al.setSeqrep(referenceseqForView);
3660 // / Add the alignment properties
3661 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3663 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3665 al.setProperty(ssp.getKey(), ssp.getValue());
3668 // ///////////////////////////////
3670 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3673 // load sequence features, database references and any associated PDB
3674 // structures for the alignment
3676 // prior to 2.10, this part would only be executed the first time a
3677 // sequence was encountered, but not afterwards.
3678 // now, for 2.10 projects, this is also done if the xml doc includes
3679 // dataset sequences not actually present in any particular view.
3681 for (int i = 0; i < vamsasSeqs.size(); i++)
3683 JSeq jseq = jseqs.get(i);
3684 if (jseq.getFeatures().size() > 0)
3686 List<Feature> features = jseq.getFeatures();
3687 for (int f = 0; f < features.size(); f++)
3689 Feature feat = features.get(f);
3690 SequenceFeature sf = new SequenceFeature(feat.getType(),
3691 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3692 safeFloat(feat.getScore()), feat.getFeatureGroup());
3693 sf.setStatus(feat.getStatus());
3696 * load any feature attributes - include map-valued attributes
3698 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3699 for (int od = 0; od < feat.getOtherData().size(); od++)
3701 OtherData keyValue = feat.getOtherData().get(od);
3702 String attributeName = keyValue.getKey();
3703 String attributeValue = keyValue.getValue();
3704 if (attributeName.startsWith("LINK"))
3706 sf.addLink(attributeValue);
3710 String subAttribute = keyValue.getKey2();
3711 if (subAttribute == null)
3713 // simple string-valued attribute
3714 sf.setValue(attributeName, attributeValue);
3718 // attribute 'key' has sub-attribute 'key2'
3719 if (!mapAttributes.containsKey(attributeName))
3721 mapAttributes.put(attributeName, new HashMap<>());
3723 mapAttributes.get(attributeName).put(subAttribute,
3728 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3731 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3734 // adds feature to datasequence's feature set (since Jalview 2.10)
3735 al.getSequenceAt(i).addSequenceFeature(sf);
3738 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3740 // adds dbrefs to datasequence's set (since Jalview 2.10)
3742 al.getSequenceAt(i).getDatasetSequence() == null
3743 ? al.getSequenceAt(i)
3744 : al.getSequenceAt(i).getDatasetSequence(),
3747 if (jseq.getPdbids().size() > 0)
3749 List<Pdbids> ids = jseq.getPdbids();
3750 for (int p = 0; p < ids.size(); p++)
3752 Pdbids pdbid = ids.get(p);
3753 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3754 entry.setId(pdbid.getId());
3755 if (pdbid.getType() != null)
3757 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3759 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3763 entry.setType(PDBEntry.Type.FILE);
3766 // jprovider is null when executing 'New View'
3767 if (pdbid.getFile() != null && jprovider != null)
3769 if (!pdbloaded.containsKey(pdbid.getFile()))
3771 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3776 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3780 if (pdbid.getPdbentryItem() != null)
3782 for (PdbentryItem item : pdbid.getPdbentryItem())
3784 for (Property pr : item.getProperty())
3786 entry.setProperty(pr.getName(), pr.getValue());
3791 for (Property prop : pdbid.getProperty())
3793 entry.setProperty(prop.getName(), prop.getValue());
3795 StructureSelectionManager
3796 .getStructureSelectionManager(Desktop.instance)
3797 .registerPDBEntry(entry);
3798 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3799 if (al.getSequenceAt(i).getDatasetSequence() != null)
3801 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3805 al.getSequenceAt(i).addPDBId(entry);
3810 } // end !multipleview
3812 // ///////////////////////////////
3813 // LOAD SEQUENCE MAPPINGS
3815 if (vamsasSet.getAlcodonFrame().size() > 0)
3817 // TODO Potentially this should only be done once for all views of an
3819 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3820 for (int i = 0; i < alc.size(); i++)
3822 AlignedCodonFrame cf = new AlignedCodonFrame();
3823 if (alc.get(i).getAlcodMap().size() > 0)
3825 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3826 for (int m = 0; m < maps.size(); m++)
3828 AlcodMap map = maps.get(m);
3829 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3831 jalview.datamodel.Mapping mapping = null;
3832 // attach to dna sequence reference.
3833 if (map.getMapping() != null)
3835 mapping = addMapping(map.getMapping());
3836 if (dnaseq != null && mapping.getTo() != null)
3838 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3844 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3848 al.addCodonFrame(cf);
3853 // ////////////////////////////////
3855 List<JvAnnotRow> autoAlan = new ArrayList<>();
3858 * store any annotations which forward reference a group's ID
3860 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3862 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3864 List<Annotation> an = vamsasSet.getAnnotation();
3866 for (int i = 0; i < an.size(); i++)
3868 Annotation annotation = an.get(i);
3871 * test if annotation is automatically calculated for this view only
3873 boolean autoForView = false;
3874 if (annotation.getLabel().equals("Quality")
3875 || annotation.getLabel().equals("Conservation")
3876 || annotation.getLabel().equals("Consensus"))
3878 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3880 // JAXB has no has() test; schema defaults value to false
3881 // if (!annotation.hasAutoCalculated())
3883 // annotation.setAutoCalculated(true);
3886 if (autoForView || annotation.isAutoCalculated())
3888 // remove ID - we don't recover annotation from other views for
3889 // view-specific annotation
3890 annotation.setId(null);
3893 // set visibility for other annotation in this view
3894 String annotationId = annotation.getId();
3895 if (annotationId != null && annotationIds.containsKey(annotationId))
3897 AlignmentAnnotation jda = annotationIds.get(annotationId);
3898 // in principle Visible should always be true for annotation displayed
3899 // in multiple views
3900 if (annotation.isVisible() != null)
3902 jda.visible = annotation.isVisible();
3905 al.addAnnotation(jda);
3909 // Construct new annotation from model.
3910 List<AnnotationElement> ae = annotation.getAnnotationElement();
3911 jalview.datamodel.Annotation[] anot = null;
3912 java.awt.Color firstColour = null;
3914 if (!annotation.isScoreOnly())
3916 anot = new jalview.datamodel.Annotation[al.getWidth()];
3917 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3919 AnnotationElement annElement = ae.get(aa);
3920 anpos = annElement.getPosition();
3922 if (anpos >= anot.length)
3927 float value = safeFloat(annElement.getValue());
3928 anot[anpos] = new jalview.datamodel.Annotation(
3929 annElement.getDisplayCharacter(),
3930 annElement.getDescription(),
3931 (annElement.getSecondaryStructure() == null
3932 || annElement.getSecondaryStructure()
3936 .getSecondaryStructure()
3939 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3940 if (firstColour == null)
3942 firstColour = anot[anpos].colour;
3946 jalview.datamodel.AlignmentAnnotation jaa = null;
3948 if (annotation.isGraph())
3950 float llim = 0, hlim = 0;
3951 // if (autoForView || an[i].isAutoCalculated()) {
3954 jaa = new jalview.datamodel.AlignmentAnnotation(
3955 annotation.getLabel(), annotation.getDescription(), anot,
3956 llim, hlim, safeInt(annotation.getGraphType()));
3958 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3959 jaa._linecolour = firstColour;
3960 if (annotation.getThresholdLine() != null)
3962 jaa.setThreshold(new jalview.datamodel.GraphLine(
3963 safeFloat(annotation.getThresholdLine().getValue()),
3964 annotation.getThresholdLine().getLabel(),
3965 new java.awt.Color(safeInt(
3966 annotation.getThresholdLine().getColour()))));
3968 if (autoForView || annotation.isAutoCalculated())
3970 // Hardwire the symbol display line to ensure that labels for
3971 // histograms are displayed
3977 jaa = new jalview.datamodel.AlignmentAnnotation(
3978 annotation.getLabel(), annotation.getDescription(), anot);
3979 jaa._linecolour = firstColour;
3981 // register new annotation
3982 if (annotation.getId() != null)
3984 annotationIds.put(annotation.getId(), jaa);
3985 jaa.annotationId = annotation.getId();
3987 // recover sequence association
3988 String sequenceRef = annotation.getSequenceRef();
3989 if (sequenceRef != null)
3991 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3992 SequenceI sequence = seqRefIds.get(sequenceRef);
3993 if (sequence == null)
3995 // in pre-2.9 projects sequence ref is to sequence name
3996 sequence = al.findName(sequenceRef);
3998 if (sequence != null)
4000 jaa.createSequenceMapping(sequence, 1, true);
4001 sequence.addAlignmentAnnotation(jaa);
4004 // and make a note of any group association
4005 if (annotation.getGroupRef() != null
4006 && annotation.getGroupRef().length() > 0)
4008 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4009 .get(annotation.getGroupRef());
4012 aal = new ArrayList<>();
4013 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4018 if (annotation.getScore() != null)
4020 jaa.setScore(annotation.getScore().doubleValue());
4022 if (annotation.isVisible() != null)
4024 jaa.visible = annotation.isVisible().booleanValue();
4027 if (annotation.isCentreColLabels() != null)
4029 jaa.centreColLabels = annotation.isCentreColLabels()
4033 if (annotation.isScaleColLabels() != null)
4035 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4037 if (annotation.isAutoCalculated())
4039 // newer files have an 'autoCalculated' flag and store calculation
4040 // state in viewport properties
4041 jaa.autoCalculated = true; // means annotation will be marked for
4042 // update at end of load.
4044 if (annotation.getGraphHeight() != null)
4046 jaa.graphHeight = annotation.getGraphHeight().intValue();
4048 jaa.belowAlignment = annotation.isBelowAlignment();
4049 jaa.setCalcId(annotation.getCalcId());
4050 if (annotation.getProperty().size() > 0)
4052 for (jalview.xml.binding.jalview.Property prop : annotation
4055 jaa.setProperty(prop.getName(), prop.getValue());
4058 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4060 if (annotation.getContactmatrix() != null
4061 && annotation.getContactmatrix().size() > 0)
4063 for (MatrixType xmlmat : annotation.getContactmatrix())
4065 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4067 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4069 Console.error("Can't handle non square PAE Matrices");
4073 float[][] elements = ContactMatrix
4074 .fromFloatStringToContacts(xmlmat.getElements(),
4075 xmlmat.getCols().intValue(),
4076 xmlmat.getRows().intValue());
4077 jalview.util.MapList mapping = null;
4078 if (xmlmat.getMapping() != null)
4080 MapListType m = xmlmat.getMapping();
4081 // Mapping m = dr.getMapping();
4082 int fr[] = new int[m.getMapListFrom().size() * 2];
4083 Iterator<MapListFrom> from = m.getMapListFrom()
4084 .iterator();// enumerateMapListFrom();
4085 for (int _i = 0; from.hasNext(); _i += 2)
4087 MapListFrom mf = from.next();
4088 fr[_i] = mf.getStart();
4089 fr[_i + 1] = mf.getEnd();
4091 int fto[] = new int[m.getMapListTo().size() * 2];
4092 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4093 for (int _i = 0; to.hasNext(); _i += 2)
4095 MapListTo mf = to.next();
4096 fto[_i] = mf.getStart();
4097 fto[_i + 1] = mf.getEnd();
4100 mapping = new jalview.util.MapList(fr, fto,
4101 m.getMapFromUnit().intValue(),
4102 m.getMapToUnit().intValue());
4104 List<BitSet> newgroups = new ArrayList<BitSet>();
4105 if (xmlmat.getGroups().size() > 0)
4107 for (String sgroup : xmlmat.getGroups())
4109 newgroups.add(deStringifyBitset(sgroup));
4112 String nwk = xmlmat.getNewick().size() > 0
4113 ? xmlmat.getNewick().get(0)
4115 if (xmlmat.getNewick().size() > 1)
4118 "Ignoring additional clusterings for contact matrix");
4120 String treeMethod = xmlmat.getTreeMethod();
4121 double thresh = xmlmat.getCutHeight() != null
4122 ? xmlmat.getCutHeight()
4124 GroupSet grpset = new GroupSet();
4125 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4126 PAEContactMatrix newpae = new PAEContactMatrix(
4127 jaa.sequenceRef, mapping, elements, grpset);
4128 jaa.sequenceRef.addContactListFor(jaa, newpae);
4133 Console.error("Ignoring CONTACT_MAP annotation with type "
4134 + xmlmat.getType());
4140 if (jaa.autoCalculated)
4142 autoAlan.add(new JvAnnotRow(i, jaa));
4145 // if (!autoForView)
4147 // add autocalculated group annotation and any user created annotation
4149 al.addAnnotation(jaa);
4153 // ///////////////////////
4155 // Create alignment markup and styles for this view
4156 if (jalviewModel.getJGroup().size() > 0)
4158 List<JGroup> groups = jalviewModel.getJGroup();
4159 boolean addAnnotSchemeGroup = false;
4160 for (int i = 0; i < groups.size(); i++)
4162 JGroup jGroup = groups.get(i);
4163 ColourSchemeI cs = null;
4164 if (jGroup.getColour() != null)
4166 if (jGroup.getColour().startsWith("ucs"))
4168 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4170 else if (jGroup.getColour().equals("AnnotationColourGradient")
4171 && jGroup.getAnnotationColours() != null)
4173 addAnnotSchemeGroup = true;
4177 cs = ColourSchemeProperty.getColourScheme(null, al,
4178 jGroup.getColour());
4181 int pidThreshold = safeInt(jGroup.getPidThreshold());
4183 Vector<SequenceI> seqs = new Vector<>();
4185 for (int s = 0; s < jGroup.getSeq().size(); s++)
4187 String seqId = jGroup.getSeq().get(s);
4188 SequenceI ts = seqRefIds.get(seqId);
4192 seqs.addElement(ts);
4196 if (seqs.size() < 1)
4201 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4202 safeBoolean(jGroup.isDisplayBoxes()),
4203 safeBoolean(jGroup.isDisplayText()),
4204 safeBoolean(jGroup.isColourText()),
4205 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4206 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4207 sg.getGroupColourScheme()
4208 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4209 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4211 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4212 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4213 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4214 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4215 // attributes with a default in the schema are never null
4216 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4217 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4218 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4219 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4220 if (jGroup.getConsThreshold() != null
4221 && jGroup.getConsThreshold().intValue() != 0)
4223 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4226 c.verdict(false, 25);
4227 sg.cs.setConservation(c);
4230 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4232 // re-instate unique group/annotation row reference
4233 List<AlignmentAnnotation> jaal = groupAnnotRefs
4234 .get(jGroup.getId());
4237 for (AlignmentAnnotation jaa : jaal)
4240 if (jaa.autoCalculated)
4242 // match up and try to set group autocalc alignment row for this
4244 if (jaa.label.startsWith("Consensus for "))
4246 sg.setConsensus(jaa);
4248 // match up and try to set group autocalc alignment row for this
4250 if (jaa.label.startsWith("Conservation for "))
4252 sg.setConservationRow(jaa);
4259 if (addAnnotSchemeGroup)
4261 // reconstruct the annotation colourscheme
4263 constructAnnotationColour(jGroup.getAnnotationColours(),
4264 null, al, jalviewModel, false));
4270 // only dataset in this model, so just return.
4273 // ///////////////////////////////
4276 AlignFrame af = null;
4277 AlignViewport av = null;
4278 // now check to see if we really need to create a new viewport.
4279 if (multipleView && viewportsAdded.size() == 0)
4281 // We recovered an alignment for which a viewport already exists.
4282 // TODO: fix up any settings necessary for overlaying stored state onto
4283 // state recovered from another document. (may not be necessary).
4284 // we may need a binding from a viewport in memory to one recovered from
4286 // and then recover its containing af to allow the settings to be applied.
4287 // TODO: fix for vamsas demo
4288 jalview.bin.Console.errPrintln(
4289 "About to recover a viewport for existing alignment: Sequence set ID is "
4291 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4292 if (seqsetobj != null)
4294 if (seqsetobj instanceof String)
4296 uniqueSeqSetId = (String) seqsetobj;
4297 jalview.bin.Console.errPrintln(
4298 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4303 jalview.bin.Console.errPrintln(
4304 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4310 * indicate that annotation colours are applied across all groups (pre
4311 * Jalview 2.8.1 behaviour)
4313 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4314 jalviewModel.getVersion());
4316 AlignmentPanel ap = null;
4317 boolean isnewview = true;
4320 // Check to see if this alignment already has a view id == viewId
4321 jalview.gui.AlignmentPanel views[] = Desktop
4322 .getAlignmentPanels(uniqueSeqSetId);
4323 if (views != null && views.length > 0)
4325 for (int v = 0; v < views.length; v++)
4327 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4329 // recover the existing alignpanel, alignframe, viewport
4330 af = views[v].alignFrame;
4333 // TODO: could even skip resetting view settings if we don't want to
4334 // change the local settings from other jalview processes
4343 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4344 uniqueSeqSetId, viewId, autoAlan);
4345 av = af.getViewport();
4350 * Load any trees, PDB structures and viewers, Overview
4352 * Not done if flag is false (when this method is used for New View)
4354 if (loadTreesAndStructures)
4356 loadTrees(jalviewModel, view, af, av, ap);
4357 loadPCAViewers(jalviewModel, ap);
4358 loadPDBStructures(jprovider, jseqs, af, ap);
4359 loadRnaViewers(jprovider, jseqs, ap);
4360 loadOverview(view, jalviewModel.getVersion(), af);
4362 // and finally return.
4367 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4368 * and geometry as saved
4373 protected void loadOverview(Viewport view, String version, AlignFrame af)
4375 if (!isVersionStringLaterThan("2.11.3", version)
4376 && view.getOverview() == null)
4381 * first close any Overview that was opened automatically
4382 * (if so configured in Preferences) so that the view is
4383 * restored in the same state as saved
4385 af.alignPanel.closeOverviewPanel();
4387 Overview overview = view.getOverview();
4388 if (overview != null)
4390 OverviewPanel overviewPanel = af
4391 .openOverviewPanel(overview.isShowHidden());
4392 overviewPanel.setTitle(overview.getTitle());
4393 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4394 overview.getWidth(), overview.getHeight());
4395 Color gap = new Color(overview.getGapColour());
4396 Color residue = new Color(overview.getResidueColour());
4397 Color hidden = new Color(overview.getHiddenColour());
4398 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4403 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4404 * panel is restored from separate jar entries, two (gapped and trimmed) per
4405 * sequence and secondary structure.
4407 * Currently each viewer shows just one sequence and structure (gapped and
4408 * trimmed), however this method is designed to support multiple sequences or
4409 * structures in viewers if wanted in future.
4415 private void loadRnaViewers(jarInputStreamProvider jprovider,
4416 List<JSeq> jseqs, AlignmentPanel ap)
4419 * scan the sequences for references to viewers; create each one the first
4420 * time it is referenced, add Rna models to existing viewers
4422 for (JSeq jseq : jseqs)
4424 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4426 RnaViewer viewer = jseq.getRnaViewer().get(i);
4427 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4430 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4432 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4433 SequenceI seq = seqRefIds.get(jseq.getId());
4434 AlignmentAnnotation ann = this.annotationIds
4435 .get(ss.getAnnotationId());
4438 * add the structure to the Varna display (with session state copied
4439 * from the jar to a temporary file)
4441 boolean gapped = safeBoolean(ss.isGapped());
4442 String rnaTitle = ss.getTitle();
4443 String sessionState = ss.getViewerState();
4444 String tempStateFile = copyJarEntry(jprovider, sessionState,
4446 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4447 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4449 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4455 * Locate and return an already instantiated matching AppVarna, or create one
4459 * @param viewIdSuffix
4463 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4464 String viewIdSuffix, AlignmentPanel ap)
4467 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4468 * if load is repeated
4470 String postLoadId = viewer.getViewId() + viewIdSuffix;
4471 for (JInternalFrame frame : getAllFrames())
4473 if (frame instanceof AppVarna)
4475 AppVarna varna = (AppVarna) frame;
4476 if (postLoadId.equals(varna.getViewId()))
4478 // this viewer is already instantiated
4479 // could in future here add ap as another 'parent' of the
4480 // AppVarna window; currently just 1-to-many
4487 * viewer not found - make it
4489 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4490 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4491 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4492 safeInt(viewer.getDividerLocation()));
4493 AppVarna varna = new AppVarna(model, ap);
4499 * Load any saved trees
4507 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4508 AlignViewport av, AlignmentPanel ap)
4510 // TODO result of automated refactoring - are all these parameters needed?
4513 for (int t = 0; t < jm.getTree().size(); t++)
4516 Tree tree = jm.getTree().get(t);
4518 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4521 if (tree.isColumnWise())
4523 AlignmentAnnotation aa = annotationIds
4524 .get(tree.getColumnReference());
4528 "Null alignment annotation when restoring columnwise tree");
4530 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4531 tree.getTitle(), safeInt(tree.getWidth()),
4532 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4533 safeInt(tree.getYpos()));
4538 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4539 tree.getTitle(), safeInt(tree.getWidth()),
4540 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4541 safeInt(tree.getYpos()));
4543 if (tree.getId() != null)
4545 // perhaps bind the tree id to something ?
4550 // update local tree attributes ?
4551 // TODO: should check if tp has been manipulated by user - if so its
4552 // settings shouldn't be modified
4553 tp.setTitle(tree.getTitle());
4554 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4555 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4556 safeInt(tree.getHeight())));
4557 tp.setViewport(av); // af.viewport;
4558 // TODO: verify 'associate with all views' works still
4559 tp.getTreeCanvas().setViewport(av); // af.viewport;
4560 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4562 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4566 "There was a problem recovering stored Newick tree: \n"
4567 + tree.getNewick());
4571 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4572 tp.fitToWindow_actionPerformed(null);
4574 if (tree.getFontName() != null)
4577 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4578 safeInt(tree.getFontSize())));
4583 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4584 safeInt(view.getFontSize())));
4587 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4588 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4589 tp.showDistances(safeBoolean(tree.isShowDistances()));
4591 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4593 if (safeBoolean(tree.isCurrentTree()))
4595 af.getViewport().setCurrentTree(tp.getTree());
4599 } catch (Exception ex)
4601 ex.printStackTrace();
4606 * Load and link any saved structure viewers.
4613 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4614 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4617 * Run through all PDB ids on the alignment, and collect mappings between
4618 * distinct view ids and all sequences referring to that view.
4620 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4622 for (int i = 0; i < jseqs.size(); i++)
4624 JSeq jseq = jseqs.get(i);
4625 if (jseq.getPdbids().size() > 0)
4627 List<Pdbids> ids = jseq.getPdbids();
4628 for (int p = 0; p < ids.size(); p++)
4630 Pdbids pdbid = ids.get(p);
4631 final int structureStateCount = pdbid.getStructureState().size();
4632 for (int s = 0; s < structureStateCount; s++)
4634 // check to see if we haven't already created this structure view
4635 final StructureState structureState = pdbid.getStructureState()
4637 String sviewid = (structureState.getViewId() == null) ? null
4638 : structureState.getViewId() + uniqueSetSuffix;
4639 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4640 // Originally : pdbid.getFile()
4641 // : TODO: verify external PDB file recovery still works in normal
4642 // jalview project load
4644 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4645 jpdb.setId(pdbid.getId());
4647 int x = safeInt(structureState.getXpos());
4648 int y = safeInt(structureState.getYpos());
4649 int width = safeInt(structureState.getWidth());
4650 int height = safeInt(structureState.getHeight());
4652 // Probably don't need to do this anymore...
4653 // Desktop.desktop.getComponentAt(x, y);
4654 // TODO: NOW: check that this recovers the PDB file correctly.
4655 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4657 jalview.datamodel.SequenceI seq = seqRefIds
4658 .get(jseq.getId() + "");
4659 if (sviewid == null)
4661 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4664 if (!structureViewers.containsKey(sviewid))
4666 String viewerType = structureState.getType();
4667 if (viewerType == null) // pre Jalview 2.9
4669 viewerType = ViewerType.JMOL.toString();
4671 structureViewers.put(sviewid,
4672 new StructureViewerModel(x, y, width, height, false,
4673 false, true, structureState.getViewId(),
4675 // Legacy pre-2.7 conversion JAL-823 :
4676 // do not assume any view has to be linked for colour by
4680 // assemble String[] { pdb files }, String[] { id for each
4681 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4682 // seqs_file 2}, boolean[] {
4683 // linkAlignPanel,superposeWithAlignpanel}} from hash
4684 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4685 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4686 || structureState.isAlignwithAlignPanel());
4689 * Default colour by linked panel to false if not specified (e.g.
4690 * for pre-2.7 projects)
4692 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4693 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4694 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4697 * Default colour by viewer to true if not specified (e.g. for
4700 boolean colourByViewer = jmoldat.isColourByViewer();
4701 colourByViewer &= structureState.isColourByJmol();
4702 jmoldat.setColourByViewer(colourByViewer);
4704 if (jmoldat.getStateData().length() < structureState.getValue()
4705 /*Content()*/.length())
4707 jmoldat.setStateData(structureState.getValue());// Content());
4709 if (pdbid.getFile() != null)
4711 File mapkey = new File(pdbid.getFile());
4712 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4713 if (seqstrmaps == null)
4715 jmoldat.getFileData().put(mapkey,
4716 seqstrmaps = jmoldat.new StructureData(pdbFile,
4719 if (!seqstrmaps.getSeqList().contains(seq))
4721 seqstrmaps.getSeqList().add(seq);
4727 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");
4728 Console.warn(errorMessage);
4734 // Instantiate the associated structure views
4735 for (Entry<String, StructureViewerModel> entry : structureViewers
4740 createOrLinkStructureViewer(entry, af, ap, jprovider);
4741 } catch (Exception e)
4743 jalview.bin.Console.errPrintln(
4744 "Error loading structure viewer: " + e.getMessage());
4745 // failed - try the next one
4757 protected void createOrLinkStructureViewer(
4758 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4759 AlignmentPanel ap, jarInputStreamProvider jprovider)
4761 final StructureViewerModel stateData = viewerData.getValue();
4764 * Search for any viewer windows already open from other alignment views
4765 * that exactly match the stored structure state
4767 StructureViewerBase comp = findMatchingViewer(viewerData);
4771 linkStructureViewer(ap, comp, stateData);
4775 String type = stateData.getType();
4778 ViewerType viewerType = ViewerType.valueOf(type);
4779 createStructureViewer(viewerType, viewerData, af, jprovider);
4780 } catch (IllegalArgumentException | NullPointerException e)
4782 // TODO JAL-3619 show error dialog / offer an alternative viewer
4783 Console.error("Invalid structure viewer type: " + type);
4788 * Generates a name for the entry in the project jar file to hold state
4789 * information for a structure viewer
4794 protected String getViewerJarEntryName(String viewId)
4796 return VIEWER_PREFIX + viewId;
4800 * Returns any open frame that matches given structure viewer data. The match
4801 * is based on the unique viewId, or (for older project versions) the frame's
4807 protected StructureViewerBase findMatchingViewer(
4808 Entry<String, StructureViewerModel> viewerData)
4810 final String sviewid = viewerData.getKey();
4811 final StructureViewerModel svattrib = viewerData.getValue();
4812 StructureViewerBase comp = null;
4813 JInternalFrame[] frames = getAllFrames();
4814 for (JInternalFrame frame : frames)
4816 if (frame instanceof StructureViewerBase)
4819 * Post jalview 2.4 schema includes structure view id
4821 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4824 comp = (StructureViewerBase) frame;
4825 break; // break added in 2.9
4828 * Otherwise test for matching position and size of viewer frame
4830 else if (frame.getX() == svattrib.getX()
4831 && frame.getY() == svattrib.getY()
4832 && frame.getHeight() == svattrib.getHeight()
4833 && frame.getWidth() == svattrib.getWidth())
4835 comp = (StructureViewerBase) frame;
4836 // no break in faint hope of an exact match on viewId
4844 * Link an AlignmentPanel to an existing structure viewer.
4849 * @param useinViewerSuperpos
4850 * @param usetoColourbyseq
4851 * @param viewerColouring
4853 protected void linkStructureViewer(AlignmentPanel ap,
4854 StructureViewerBase viewer, StructureViewerModel stateData)
4856 // NOTE: if the jalview project is part of a shared session then
4857 // view synchronization should/could be done here.
4859 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4860 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4861 final boolean viewerColouring = stateData.isColourByViewer();
4862 Map<File, StructureData> oldFiles = stateData.getFileData();
4865 * Add mapping for sequences in this view to an already open viewer
4867 final AAStructureBindingModel binding = viewer.getBinding();
4868 for (File id : oldFiles.keySet())
4870 // add this and any other pdb files that should be present in the
4872 StructureData filedat = oldFiles.get(id);
4873 String pdbFile = filedat.getFilePath();
4874 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4875 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4877 binding.addSequenceForStructFile(pdbFile, seq);
4879 // and add the AlignmentPanel's reference to the view panel
4880 viewer.addAlignmentPanel(ap);
4881 if (useinViewerSuperpos)
4883 viewer.useAlignmentPanelForSuperposition(ap);
4887 viewer.excludeAlignmentPanelForSuperposition(ap);
4889 if (usetoColourbyseq)
4891 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4895 viewer.excludeAlignmentPanelForColourbyseq(ap);
4900 * Get all frames within the Desktop.
4904 protected JInternalFrame[] getAllFrames()
4906 JInternalFrame[] frames = null;
4907 // TODO is this necessary - is it safe - risk of hanging?
4912 frames = Desktop.desktop.getAllFrames();
4913 } catch (ArrayIndexOutOfBoundsException e)
4915 // occasional No such child exceptions are thrown here...
4919 } catch (InterruptedException f)
4923 } while (frames == null);
4928 * Answers true if 'version' is equal to or later than 'supported', where each
4929 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4930 * changes. Development and test values for 'version' are leniently treated
4934 * - minimum version we are comparing against
4936 * - version of data being processsed
4937 * @return true if version is equal to or later than supported
4939 public static boolean isVersionStringLaterThan(String supported,
4942 if (supported == null || version == null
4943 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4944 || version.equalsIgnoreCase("Test")
4945 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4947 jalview.bin.Console.errPrintln("Assuming project file with "
4948 + (version == null ? "null" : version)
4949 + " is compatible with Jalview version " + supported);
4954 return StringUtils.compareVersions(version, supported, "b") >= 0;
4958 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4960 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4962 if (newStructureViewers != null)
4964 sview.getBinding().setFinishedLoadingFromArchive(false);
4965 newStructureViewers.add(sview);
4969 protected void setLoadingFinishedForNewStructureViewers()
4971 if (newStructureViewers != null)
4973 for (JalviewStructureDisplayI sview : newStructureViewers)
4975 sview.getBinding().setFinishedLoadingFromArchive(true);
4977 newStructureViewers.clear();
4978 newStructureViewers = null;
4982 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4983 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4984 Viewport view, String uniqueSeqSetId, String viewId,
4985 List<JvAnnotRow> autoAlan)
4987 AlignFrame af = null;
4988 af = new AlignFrame(al, safeInt(view.getWidth()),
4989 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4993 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4994 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
4995 // super.processKeyEvent(e);
5002 af.setFileName(file, FileFormat.Jalview);
5004 final AlignViewport viewport = af.getViewport();
5005 for (int i = 0; i < JSEQ.size(); i++)
5007 int colour = safeInt(JSEQ.get(i).getColour());
5008 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5014 viewport.setColourByReferenceSeq(true);
5015 viewport.setDisplayReferenceSeq(true);
5018 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5020 if (view.getSequenceSetId() != null)
5022 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5024 viewport.setSequenceSetId(uniqueSeqSetId);
5027 // propagate shared settings to this new view
5028 viewport.setHistoryList(av.getHistoryList());
5029 viewport.setRedoList(av.getRedoList());
5033 viewportsAdded.put(uniqueSeqSetId, viewport);
5035 // TODO: check if this method can be called repeatedly without
5036 // side-effects if alignpanel already registered.
5037 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5039 // apply Hidden regions to view.
5040 if (hiddenSeqs != null)
5042 for (int s = 0; s < JSEQ.size(); s++)
5044 SequenceGroup hidden = new SequenceGroup();
5045 boolean isRepresentative = false;
5046 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5048 isRepresentative = true;
5049 SequenceI sequenceToHide = al
5050 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5051 hidden.addSequence(sequenceToHide, false);
5052 // remove from hiddenSeqs list so we don't try to hide it twice
5053 hiddenSeqs.remove(sequenceToHide);
5055 if (isRepresentative)
5057 SequenceI representativeSequence = al.getSequenceAt(s);
5058 hidden.addSequence(representativeSequence, false);
5059 viewport.hideRepSequences(representativeSequence, hidden);
5063 SequenceI[] hseqs = hiddenSeqs
5064 .toArray(new SequenceI[hiddenSeqs.size()]);
5065 viewport.hideSequence(hseqs);
5068 // recover view properties and display parameters
5070 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5071 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5072 final int pidThreshold = safeInt(view.getPidThreshold());
5073 viewport.setThreshold(pidThreshold);
5075 viewport.setColourText(safeBoolean(view.isShowColourText()));
5077 viewport.setConservationSelected(
5078 safeBoolean(view.isConservationSelected()));
5079 viewport.setIncrement(safeInt(view.getConsThreshold()));
5080 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5081 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5083 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5084 safeInt(view.getFontSize())),
5085 (view.getCharWidth() != null) ? false : true);
5086 if (view.getCharWidth() != null)
5088 viewport.setCharWidth(view.getCharWidth());
5089 viewport.setCharHeight(view.getCharHeight());
5091 ViewStyleI vs = viewport.getViewStyle();
5092 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5093 viewport.setViewStyle(vs);
5094 // TODO: allow custom charWidth/Heights to be restored by updating them
5095 // after setting font - which means set above to false
5096 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5097 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5098 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5100 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5102 viewport.setShowText(safeBoolean(view.isShowText()));
5104 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5105 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5106 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5107 viewport.setShowUnconserved(view.isShowUnconserved());
5108 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5110 if (view.getViewName() != null)
5112 viewport.setViewName(view.getViewName());
5113 af.setInitialTabVisible();
5115 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5116 safeInt(view.getWidth()), safeInt(view.getHeight()));
5118 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID width
5119 if (view.getIdWidth()==null)
5121 if (!isVersionStringLaterThan("2.11.3", jm.getVersion())) {
5122 // Pre 2.11.3 jalview projects do not store the id width
5123 // idWidth was also calculated in a different way.
5124 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5125 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5128 viewport.setIdWidth(view.getIdWidth());
5129 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5132 // startSeq set in af.alignPanel.updateLayout below
5133 af.alignPanel.updateLayout();
5134 ColourSchemeI cs = null;
5135 // apply colourschemes
5136 if (view.getBgColour() != null)
5138 if (view.getBgColour().startsWith("ucs"))
5140 cs = getUserColourScheme(jm, view.getBgColour());
5142 else if (view.getBgColour().startsWith("Annotation"))
5144 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5145 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5152 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5153 view.getBgColour());
5158 * turn off 'alignment colour applies to all groups'
5159 * while restoring global colour scheme
5161 viewport.setColourAppliesToAllGroups(false);
5162 viewport.setGlobalColourScheme(cs);
5163 viewport.getResidueShading().setThreshold(pidThreshold,
5164 view.isIgnoreGapsinConsensus());
5165 viewport.getResidueShading()
5166 .setConsensus(viewport.getSequenceConsensusHash());
5167 if (safeBoolean(view.isConservationSelected()) && cs != null)
5169 viewport.getResidueShading()
5170 .setConservationInc(safeInt(view.getConsThreshold()));
5172 af.changeColour(cs);
5173 viewport.setColourAppliesToAllGroups(true);
5175 viewport.setShowSequenceFeatures(
5176 safeBoolean(view.isShowSequenceFeatures()));
5178 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5179 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5180 viewport.setFollowHighlight(view.isFollowHighlight());
5181 viewport.followSelection = view.isFollowSelection();
5182 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5183 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5184 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5185 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5186 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5187 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5188 viewport.setShowGroupConservation(view.isShowGroupConservation());
5189 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5190 viewport.setShowComplementFeaturesOnTop(
5191 view.isShowComplementFeaturesOnTop());
5193 // recover feature settings
5194 if (jm.getFeatureSettings() != null)
5196 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5197 .getFeatureRenderer();
5198 FeaturesDisplayed fdi;
5199 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5200 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5202 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5203 Map<String, Float> featureOrder = new Hashtable<>();
5205 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5208 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5209 String featureType = setting.getType();
5212 * restore feature filters (if any)
5214 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5216 if (filters != null)
5218 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5220 if (!filter.isEmpty())
5222 fr.setFeatureFilter(featureType, filter);
5227 * restore feature colour scheme
5229 Color maxColour = new Color(setting.getColour());
5230 if (setting.getMincolour() != null)
5233 * minColour is always set unless a simple colour
5234 * (including for colour by label though it doesn't use it)
5236 Color minColour = new Color(setting.getMincolour().intValue());
5237 Color noValueColour = minColour;
5238 NoValueColour noColour = setting.getNoValueColour();
5239 if (noColour == NoValueColour.NONE)
5241 noValueColour = null;
5243 else if (noColour == NoValueColour.MAX)
5245 noValueColour = maxColour;
5247 float min = safeFloat(safeFloat(setting.getMin()));
5248 float max = setting.getMax() == null ? 1f
5249 : setting.getMax().floatValue();
5250 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5251 maxColour, noValueColour, min, max);
5252 if (setting.getAttributeName().size() > 0)
5254 gc.setAttributeName(setting.getAttributeName().toArray(
5255 new String[setting.getAttributeName().size()]));
5257 if (setting.getThreshold() != null)
5259 gc.setThreshold(setting.getThreshold().floatValue());
5260 int threshstate = safeInt(setting.getThreshstate());
5261 // -1 = None, 0 = Below, 1 = Above threshold
5262 if (threshstate == 0)
5264 gc.setBelowThreshold(true);
5266 else if (threshstate == 1)
5268 gc.setAboveThreshold(true);
5271 gc.setAutoScaled(true); // default
5272 if (setting.isAutoScale() != null)
5274 gc.setAutoScaled(setting.isAutoScale());
5276 if (setting.isColourByLabel() != null)
5278 gc.setColourByLabel(setting.isColourByLabel());
5280 // and put in the feature colour table.
5281 featureColours.put(featureType, gc);
5285 featureColours.put(featureType, new FeatureColour(maxColour));
5287 renderOrder[fs] = featureType;
5288 if (setting.getOrder() != null)
5290 featureOrder.put(featureType, setting.getOrder().floatValue());
5294 featureOrder.put(featureType, Float.valueOf(
5295 fs / jm.getFeatureSettings().getSetting().size()));
5297 if (safeBoolean(setting.isDisplay()))
5299 fdi.setVisible(featureType);
5302 Map<String, Boolean> fgtable = new Hashtable<>();
5303 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5305 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5306 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5308 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5309 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5310 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5311 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5312 fgtable, featureColours, 1.0f, featureOrder);
5313 fr.transferSettings(frs);
5316 if (view.getHiddenColumns().size() > 0)
5318 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5320 final HiddenColumns hc = view.getHiddenColumns().get(c);
5321 viewport.hideColumns(safeInt(hc.getStart()),
5322 safeInt(hc.getEnd()) /* +1 */);
5325 if (view.getCalcIdParam() != null)
5327 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5329 if (calcIdParam != null)
5331 if (recoverCalcIdParam(calcIdParam, viewport))
5336 Console.warn("Couldn't recover parameters for "
5337 + calcIdParam.getCalcId());
5342 af.setMenusFromViewport(viewport);
5343 af.setTitle(view.getTitle());
5344 // TODO: we don't need to do this if the viewport is aready visible.
5346 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5347 * has a 'cdna/protein complement' view, in which case save it in order to
5348 * populate a SplitFrame once all views have been read in.
5350 String complementaryViewId = view.getComplementId();
5351 if (complementaryViewId == null)
5353 Desktop.addInternalFrame(af, view.getTitle(),
5354 safeInt(view.getWidth()), safeInt(view.getHeight()));
5355 // recompute any autoannotation
5356 af.alignPanel.updateAnnotation(false, true);
5357 reorderAutoannotation(af, al, autoAlan);
5358 af.alignPanel.alignmentChanged();
5362 splitFrameCandidates.put(view, af);
5369 * Reads saved data to restore Colour by Annotation settings
5371 * @param viewAnnColour
5375 * @param checkGroupAnnColour
5378 private ColourSchemeI constructAnnotationColour(
5379 AnnotationColourScheme viewAnnColour, AlignFrame af,
5380 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5382 boolean propagateAnnColour = false;
5383 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5385 if (checkGroupAnnColour && al.getGroups() != null
5386 && al.getGroups().size() > 0)
5388 // pre 2.8.1 behaviour
5389 // check to see if we should transfer annotation colours
5390 propagateAnnColour = true;
5391 for (SequenceGroup sg : al.getGroups())
5393 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5395 propagateAnnColour = false;
5401 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5403 String annotationId = viewAnnColour.getAnnotation();
5404 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5407 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5409 if (matchedAnnotation == null
5410 && annAlignment.getAlignmentAnnotation() != null)
5412 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5415 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5417 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5422 if (matchedAnnotation == null)
5425 .errPrintln("Failed to match annotation colour scheme for "
5429 // belt-and-braces create a threshold line if the
5430 // colourscheme needs one but the matchedAnnotation doesn't have one
5431 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5432 && matchedAnnotation.getThreshold() == null)
5434 matchedAnnotation.setThreshold(
5435 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5436 "Threshold", Color.black));
5439 AnnotationColourGradient cs = null;
5440 if (viewAnnColour.getColourScheme().equals("None"))
5442 cs = new AnnotationColourGradient(matchedAnnotation,
5443 new Color(safeInt(viewAnnColour.getMinColour())),
5444 new Color(safeInt(viewAnnColour.getMaxColour())),
5445 safeInt(viewAnnColour.getAboveThreshold()));
5447 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5449 cs = new AnnotationColourGradient(matchedAnnotation,
5450 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5451 safeInt(viewAnnColour.getAboveThreshold()));
5455 cs = new AnnotationColourGradient(matchedAnnotation,
5456 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5457 viewAnnColour.getColourScheme()),
5458 safeInt(viewAnnColour.getAboveThreshold()));
5461 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5462 boolean useOriginalColours = safeBoolean(
5463 viewAnnColour.isPredefinedColours());
5464 cs.setSeqAssociated(perSequenceOnly);
5465 cs.setPredefinedColours(useOriginalColours);
5467 if (propagateAnnColour && al.getGroups() != null)
5469 // Also use these settings for all the groups
5470 for (int g = 0; g < al.getGroups().size(); g++)
5472 SequenceGroup sg = al.getGroups().get(g);
5473 if (sg.getGroupColourScheme() == null)
5478 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5479 matchedAnnotation, sg.getColourScheme(),
5480 safeInt(viewAnnColour.getAboveThreshold()));
5481 sg.setColourScheme(groupScheme);
5482 groupScheme.setSeqAssociated(perSequenceOnly);
5483 groupScheme.setPredefinedColours(useOriginalColours);
5489 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5490 List<JvAnnotRow> autoAlan)
5492 // copy over visualization settings for autocalculated annotation in the
5494 if (al.getAlignmentAnnotation() != null)
5497 * Kludge for magic autoannotation names (see JAL-811)
5499 String[] magicNames = new String[] { "Consensus", "Quality",
5501 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5502 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5503 for (String nm : magicNames)
5505 visan.put(nm, nullAnnot);
5507 for (JvAnnotRow auan : autoAlan)
5509 visan.put(auan.template.label
5510 + (auan.template.getCalcId() == null ? ""
5511 : "\t" + auan.template.getCalcId()),
5514 int hSize = al.getAlignmentAnnotation().length;
5515 List<JvAnnotRow> reorder = new ArrayList<>();
5516 // work through any autoCalculated annotation already on the view
5517 // removing it if it should be placed in a different location on the
5518 // annotation panel.
5519 List<String> remains = new ArrayList<>(visan.keySet());
5520 for (int h = 0; h < hSize; h++)
5522 jalview.datamodel.AlignmentAnnotation jalan = al
5523 .getAlignmentAnnotation()[h];
5524 if (jalan.autoCalculated)
5527 JvAnnotRow valan = visan.get(k = jalan.label);
5528 if (jalan.getCalcId() != null)
5530 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5535 // delete the auto calculated row from the alignment
5536 al.deleteAnnotation(jalan, false);
5540 if (valan != nullAnnot)
5542 if (jalan != valan.template)
5544 // newly created autoannotation row instance
5545 // so keep a reference to the visible annotation row
5546 // and copy over all relevant attributes
5547 if (valan.template.graphHeight >= 0)
5550 jalan.graphHeight = valan.template.graphHeight;
5552 jalan.visible = valan.template.visible;
5554 reorder.add(new JvAnnotRow(valan.order, jalan));
5559 // Add any (possibly stale) autocalculated rows that were not appended to
5560 // the view during construction
5561 for (String other : remains)
5563 JvAnnotRow othera = visan.get(other);
5564 if (othera != nullAnnot && othera.template.getCalcId() != null
5565 && othera.template.getCalcId().length() > 0)
5567 reorder.add(othera);
5570 // now put the automatic annotation in its correct place
5571 int s = 0, srt[] = new int[reorder.size()];
5572 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5573 for (JvAnnotRow jvar : reorder)
5576 srt[s++] = jvar.order;
5579 jalview.util.QuickSort.sort(srt, rws);
5580 // and re-insert the annotation at its correct position
5581 for (JvAnnotRow jvar : rws)
5583 al.addAnnotation(jvar.template, jvar.order);
5585 af.alignPanel.adjustAnnotationHeight();
5589 Hashtable skipList = null;
5592 * TODO remove this method
5595 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5596 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5597 * throw new Error("Implementation Error. No skipList defined for this
5598 * Jalview2XML instance."); } return (AlignFrame)
5599 * skipList.get(view.getSequenceSetId()); }
5603 * Check if the Jalview view contained in object should be skipped or not.
5606 * @return true if view's sequenceSetId is a key in skipList
5608 private boolean skipViewport(JalviewModel object)
5610 if (skipList == null)
5614 String id = object.getViewport().get(0).getSequenceSetId();
5615 if (skipList.containsKey(id))
5617 Console.debug("Skipping seuqence set id " + id);
5623 public void addToSkipList(AlignFrame af)
5625 if (skipList == null)
5627 skipList = new Hashtable();
5629 skipList.put(af.getViewport().getSequenceSetId(), af);
5632 public void clearSkipList()
5634 if (skipList != null)
5641 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5642 boolean ignoreUnrefed, String uniqueSeqSetId)
5644 jalview.datamodel.AlignmentI ds = getDatasetFor(
5645 vamsasSet.getDatasetId());
5646 AlignmentI xtant_ds = ds;
5647 if (xtant_ds == null)
5649 // good chance we are about to create a new dataset, but check if we've
5650 // seen some of the dataset sequence IDs before.
5651 // TODO: skip this check if we are working with project generated by
5652 // version 2.11 or later
5653 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5654 if (xtant_ds != null)
5657 addDatasetRef(vamsasSet.getDatasetId(), ds);
5660 Vector<SequenceI> dseqs = null;
5663 // recovering an alignment View
5664 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5665 if (seqSetDS != null)
5667 if (ds != null && ds != seqSetDS)
5670 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5671 + " - CDS/Protein crossreference data may be lost");
5672 if (xtant_ds != null)
5674 // This can only happen if the unique sequence set ID was bound to a
5675 // dataset that did not contain any of the sequences in the view
5676 // currently being restored.
5678 "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.");
5682 addDatasetRef(vamsasSet.getDatasetId(), ds);
5687 // try even harder to restore dataset
5688 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5689 // create a list of new dataset sequences
5690 dseqs = new Vector<>();
5692 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5694 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5695 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5697 // create a new dataset
5700 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5701 dseqs.copyInto(dsseqs);
5702 ds = new jalview.datamodel.Alignment(dsseqs);
5703 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5704 + " for alignment " + System.identityHashCode(al));
5705 addDatasetRef(vamsasSet.getDatasetId(), ds);
5707 // set the dataset for the newly imported alignment.
5708 if (al.getDataset() == null && !ignoreUnrefed)
5711 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5712 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5714 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5718 * XML dataset sequence ID to materialised dataset reference
5720 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5723 * @return the first materialised dataset reference containing a dataset
5724 * sequence referenced in the given view
5726 * - sequences from the view
5728 AlignmentI checkIfHasDataset(List<Sequence> list)
5730 for (Sequence restoredSeq : list)
5732 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5733 if (datasetFor != null)
5742 * Register ds as the containing dataset for the dataset sequences referenced
5743 * by sequences in list
5746 * - sequences in a view
5749 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5751 for (Sequence restoredSeq : list)
5753 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5754 if (prevDS != null && prevDS != ds)
5756 Console.warn("Dataset sequence appears in many datasets: "
5757 + restoredSeq.getDsseqid());
5758 // TODO: try to merge!
5766 * sequence definition to create/merge dataset sequence for
5770 * vector to add new dataset sequence to
5771 * @param ignoreUnrefed
5772 * - when true, don't create new sequences from vamsasSeq if it's id
5773 * doesn't already have an asssociated Jalview sequence.
5775 * - used to reorder the sequence in the alignment according to the
5776 * vamsasSeq array ordering, to preserve ordering of dataset
5778 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5779 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5782 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5784 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5785 boolean reorder = false;
5786 SequenceI dsq = null;
5787 if (sq != null && sq.getDatasetSequence() != null)
5789 dsq = sq.getDatasetSequence();
5795 if (sq == null && ignoreUnrefed)
5799 String sqid = vamsasSeq.getDsseqid();
5802 // need to create or add a new dataset sequence reference to this sequence
5805 dsq = seqRefIds.get(sqid);
5810 // make a new dataset sequence
5811 dsq = sq.createDatasetSequence();
5814 // make up a new dataset reference for this sequence
5815 sqid = seqHash(dsq);
5817 dsq.setVamsasId(uniqueSetSuffix + sqid);
5818 seqRefIds.put(sqid, dsq);
5823 dseqs.addElement(dsq);
5828 ds.addSequence(dsq);
5834 { // make this dataset sequence sq's dataset sequence
5835 sq.setDatasetSequence(dsq);
5836 // and update the current dataset alignment
5841 if (!dseqs.contains(dsq))
5848 if (ds.findIndex(dsq) < 0)
5850 ds.addSequence(dsq);
5857 // TODO: refactor this as a merge dataset sequence function
5858 // now check that sq (the dataset sequence) sequence really is the union of
5859 // all references to it
5860 // boolean pre = sq.getStart() < dsq.getStart();
5861 // boolean post = sq.getEnd() > dsq.getEnd();
5865 // StringBuffer sb = new StringBuffer();
5866 String newres = jalview.analysis.AlignSeq.extractGaps(
5867 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5868 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5869 && newres.length() > dsq.getLength())
5871 // Update with the longer sequence.
5875 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5876 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5877 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5878 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5880 dsq.setSequence(newres);
5882 // TODO: merges will never happen if we 'know' we have the real dataset
5883 // sequence - this should be detected when id==dssid
5884 jalview.bin.Console.errPrintln(
5885 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5886 // + (pre ? "prepended" : "") + " "
5887 // + (post ? "appended" : ""));
5892 // sequence refs are identical. We may need to update the existing dataset
5893 // alignment with this one, though.
5894 if (ds != null && dseqs == null)
5896 int opos = ds.findIndex(dsq);
5897 SequenceI tseq = null;
5898 if (opos != -1 && vseqpos != opos)
5900 // remove from old position
5901 ds.deleteSequence(dsq);
5903 if (vseqpos < ds.getHeight())
5905 if (vseqpos != opos)
5907 // save sequence at destination position
5908 tseq = ds.getSequenceAt(vseqpos);
5909 ds.replaceSequenceAt(vseqpos, dsq);
5910 ds.addSequence(tseq);
5915 ds.addSequence(dsq);
5922 * TODO use AlignmentI here and in related methods - needs
5923 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5925 Hashtable<String, AlignmentI> datasetIds = null;
5927 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5929 private AlignmentI getDatasetFor(String datasetId)
5931 if (datasetIds == null)
5933 datasetIds = new Hashtable<>();
5936 if (datasetIds.containsKey(datasetId))
5938 return datasetIds.get(datasetId);
5943 private void addDatasetRef(String datasetId, AlignmentI dataset)
5945 if (datasetIds == null)
5947 datasetIds = new Hashtable<>();
5949 datasetIds.put(datasetId, dataset);
5953 * make a new dataset ID for this jalview dataset alignment
5958 private String getDatasetIdRef(AlignmentI dataset)
5960 if (dataset.getDataset() != null)
5963 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5965 String datasetId = makeHashCode(dataset, null);
5966 if (datasetId == null)
5968 // make a new datasetId and record it
5969 if (dataset2Ids == null)
5971 dataset2Ids = new IdentityHashMap<>();
5975 datasetId = dataset2Ids.get(dataset);
5977 if (datasetId == null)
5979 datasetId = "ds" + dataset2Ids.size() + 1;
5980 dataset2Ids.put(dataset, datasetId);
5987 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5988 * constructed as a special subclass GeneLocus.
5990 * @param datasetSequence
5993 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5995 for (int d = 0; d < sequence.getDBRef().size(); d++)
5997 DBRef dr = sequence.getDBRef().get(d);
6001 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6002 dr.getAccessionId());
6006 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6007 dr.getAccessionId());
6009 if (dr.getMapping() != null)
6011 entry.setMap(addMapping(dr.getMapping()));
6013 entry.setCanonical(dr.isCanonical());
6014 datasetSequence.addDBRef(entry);
6018 private jalview.datamodel.Mapping addMapping(Mapping m)
6020 SequenceI dsto = null;
6021 // Mapping m = dr.getMapping();
6022 int fr[] = new int[m.getMapListFrom().size() * 2];
6023 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6024 for (int _i = 0; from.hasNext(); _i += 2)
6026 MapListFrom mf = from.next();
6027 fr[_i] = mf.getStart();
6028 fr[_i + 1] = mf.getEnd();
6030 int fto[] = new int[m.getMapListTo().size() * 2];
6031 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6032 for (int _i = 0; to.hasNext(); _i += 2)
6034 MapListTo mf = to.next();
6035 fto[_i] = mf.getStart();
6036 fto[_i + 1] = mf.getEnd();
6038 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6039 fto, m.getMapFromUnit().intValue(),
6040 m.getMapToUnit().intValue());
6043 * (optional) choice of dseqFor or Sequence
6045 if (m.getDseqFor() != null)
6047 String dsfor = m.getDseqFor();
6048 if (seqRefIds.containsKey(dsfor))
6053 jmap.setTo(seqRefIds.get(dsfor));
6057 frefedSequence.add(newMappingRef(dsfor, jmap));
6060 else if (m.getSequence() != null)
6063 * local sequence definition
6065 Sequence ms = m.getSequence();
6066 SequenceI djs = null;
6067 String sqid = ms.getDsseqid();
6068 if (sqid != null && sqid.length() > 0)
6071 * recover dataset sequence
6073 djs = seqRefIds.get(sqid);
6077 jalview.bin.Console.errPrintln(
6078 "Warning - making up dataset sequence id for DbRef sequence map reference");
6079 sqid = ((Object) ms).toString(); // make up a new hascode for
6080 // undefined dataset sequence hash
6081 // (unlikely to happen)
6087 * make a new dataset sequence and add it to refIds hash
6089 djs = new jalview.datamodel.Sequence(ms.getName(),
6091 djs.setStart(jmap.getMap().getToLowest());
6092 djs.setEnd(jmap.getMap().getToHighest());
6093 djs.setVamsasId(uniqueSetSuffix + sqid);
6095 incompleteSeqs.put(sqid, djs);
6096 seqRefIds.put(sqid, djs);
6099 Console.debug("about to recurse on addDBRefs.");
6108 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6109 * view as XML (but not to file), and then reloading it
6114 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6117 JalviewModel jm = saveState(ap, null, null, null);
6120 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6121 ap.getAlignment().getDataset());
6123 uniqueSetSuffix = "";
6124 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6125 jm.getViewport().get(0).setId(null);
6126 // we don't overwrite the view we just copied
6128 if (this.frefedSequence == null)
6130 frefedSequence = new Vector<>();
6133 viewportsAdded.clear();
6135 AlignFrame af = loadFromObject(jm, null, false, null);
6136 af.getAlignPanels().clear();
6137 af.closeMenuItem_actionPerformed(true);
6140 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6141 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6142 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6143 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6144 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6147 return af.alignPanel;
6150 private Hashtable jvids2vobj;
6153 * set the object to ID mapping tables used to write/recover objects and XML
6154 * ID strings for the jalview project. If external tables are provided then
6155 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6156 * object goes out of scope. - also populates the datasetIds hashtable with
6157 * alignment objects containing dataset sequences
6160 * Map from ID strings to jalview datamodel
6162 * Map from jalview datamodel to ID strings
6166 public void setObjectMappingTables(Hashtable vobj2jv,
6167 IdentityHashMap jv2vobj)
6169 this.jv2vobj = jv2vobj;
6170 this.vobj2jv = vobj2jv;
6171 Iterator ds = jv2vobj.keySet().iterator();
6173 while (ds.hasNext())
6175 Object jvobj = ds.next();
6176 id = jv2vobj.get(jvobj).toString();
6177 if (jvobj instanceof jalview.datamodel.Alignment)
6179 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6181 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6184 else if (jvobj instanceof jalview.datamodel.Sequence)
6186 // register sequence object so the XML parser can recover it.
6187 if (seqRefIds == null)
6189 seqRefIds = new HashMap<>();
6191 if (seqsToIds == null)
6193 seqsToIds = new IdentityHashMap<>();
6195 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6196 seqsToIds.put((SequenceI) jvobj, id);
6198 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6201 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6202 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6203 if (jvann.annotationId == null)
6205 jvann.annotationId = anid;
6207 if (!jvann.annotationId.equals(anid))
6209 // TODO verify that this is the correct behaviour
6210 Console.warn("Overriding Annotation ID for " + anid
6211 + " from different id : " + jvann.annotationId);
6212 jvann.annotationId = anid;
6215 else if (jvobj instanceof String)
6217 if (jvids2vobj == null)
6219 jvids2vobj = new Hashtable();
6220 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6225 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6231 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6232 * objects created from the project archive. If string is null (default for
6233 * construction) then suffix will be set automatically.
6237 public void setUniqueSetSuffix(String string)
6239 uniqueSetSuffix = string;
6244 * uses skipList2 as the skipList for skipping views on sequence sets
6245 * associated with keys in the skipList
6249 public void setSkipList(Hashtable skipList2)
6251 skipList = skipList2;
6255 * Reads the jar entry of given name and returns its contents, or null if the
6256 * entry is not found.
6259 * @param jarEntryName
6262 protected String readJarEntry(jarInputStreamProvider jprovider,
6263 String jarEntryName)
6265 String result = null;
6266 BufferedReader in = null;
6271 * Reopen the jar input stream and traverse its entries to find a matching
6274 JarInputStream jin = jprovider.getJarInputStream();
6275 JarEntry entry = null;
6278 entry = jin.getNextJarEntry();
6279 } while (entry != null && !entry.getName().equals(jarEntryName));
6283 StringBuilder out = new StringBuilder(256);
6284 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6287 while ((data = in.readLine()) != null)
6291 result = out.toString();
6296 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6298 } catch (Exception ex)
6300 ex.printStackTrace();
6308 } catch (IOException e)
6319 * Returns an incrementing counter (0, 1, 2...)
6323 private synchronized int nextCounter()
6329 * Loads any saved PCA viewers
6334 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6338 List<PcaViewer> pcaviewers = model.getPcaViewer();
6339 for (PcaViewer viewer : pcaviewers)
6341 String modelName = viewer.getScoreModelName();
6342 SimilarityParamsI params = new SimilarityParams(
6343 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6344 viewer.isIncludeGaps(),
6345 viewer.isDenominateByShortestLength());
6348 * create the panel (without computing the PCA)
6350 PCAPanel panel = new PCAPanel(ap, modelName, params);
6352 panel.setTitle(viewer.getTitle());
6353 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6354 viewer.getWidth(), viewer.getHeight()));
6356 boolean showLabels = viewer.isShowLabels();
6357 panel.setShowLabels(showLabels);
6358 panel.getRotatableCanvas().setShowLabels(showLabels);
6359 panel.getRotatableCanvas()
6360 .setBgColour(new Color(viewer.getBgColour()));
6361 panel.getRotatableCanvas()
6362 .setApplyToAllViews(viewer.isLinkToAllViews());
6365 * load PCA output data
6367 ScoreModelI scoreModel = ScoreModels.getInstance()
6368 .getScoreModel(modelName, ap);
6369 PCA pca = new PCA(null, scoreModel, params);
6370 PcaDataType pcaData = viewer.getPcaData();
6372 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6373 pca.setPairwiseScores(pairwise);
6375 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6376 pca.setTridiagonal(triDiag);
6378 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6379 pca.setEigenmatrix(result);
6381 panel.getPcaModel().setPCA(pca);
6384 * we haven't saved the input data! (JAL-2647 to do)
6386 panel.setInputData(null);
6389 * add the sequence points for the PCA display
6391 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6392 for (SequencePoint sp : viewer.getSequencePoint())
6394 String seqId = sp.getSequenceRef();
6395 SequenceI seq = seqRefIds.get(seqId);
6398 throw new IllegalStateException(
6399 "Unmatched seqref for PCA: " + seqId);
6401 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6402 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6404 seqPoints.add(seqPoint);
6406 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6409 * set min-max ranges and scale after setPoints (which recomputes them)
6411 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6412 SeqPointMin spMin = viewer.getSeqPointMin();
6413 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6415 SeqPointMax spMax = viewer.getSeqPointMax();
6416 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6418 panel.getRotatableCanvas().setSeqMinMax(min, max);
6420 // todo: hold points list in PCAModel only
6421 panel.getPcaModel().setSequencePoints(seqPoints);
6423 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6424 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6425 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6427 // is this duplication needed?
6428 panel.setTop(seqPoints.size() - 1);
6429 panel.getPcaModel().setTop(seqPoints.size() - 1);
6432 * add the axes' end points for the display
6434 for (int i = 0; i < 3; i++)
6436 Axis axis = viewer.getAxis().get(i);
6437 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6438 axis.getXPos(), axis.getYPos(), axis.getZPos());
6441 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6442 "label.calc_title", "PCA", modelName), 475, 450);
6444 } catch (Exception ex)
6446 Console.error("Error loading PCA: " + ex.toString());
6451 * Creates a new structure viewer window
6458 protected void createStructureViewer(ViewerType viewerType,
6459 final Entry<String, StructureViewerModel> viewerData,
6460 AlignFrame af, jarInputStreamProvider jprovider)
6462 final StructureViewerModel viewerModel = viewerData.getValue();
6463 String sessionFilePath = null;
6465 if (viewerType == ViewerType.JMOL)
6467 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6471 String viewerJarEntryName = getViewerJarEntryName(
6472 viewerModel.getViewId());
6473 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6474 "viewerSession", ".tmp");
6476 final String sessionPath = sessionFilePath;
6477 final String sviewid = viewerData.getKey();
6480 SwingUtilities.invokeAndWait(new Runnable()
6485 JalviewStructureDisplayI sview = null;
6488 sview = StructureViewer.createView(viewerType, af.alignPanel,
6489 viewerModel, sessionPath, sviewid);
6490 addNewStructureViewer(sview);
6491 } catch (OutOfMemoryError ex)
6493 new OOMWarning("Restoring structure view for " + viewerType,
6494 (OutOfMemoryError) ex.getCause());
6495 if (sview != null && sview.isVisible())
6497 sview.closeViewer(false);
6498 sview.setVisible(false);
6504 } catch (InvocationTargetException | InterruptedException ex)
6506 Console.warn("Unexpected error when opening " + viewerType
6507 + " structure viewer", ex);
6512 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6513 * the path of the file. "load file" commands are rewritten to change the
6514 * original PDB file names to those created as the Jalview project is loaded.
6520 private String rewriteJmolSession(StructureViewerModel svattrib,
6521 jarInputStreamProvider jprovider)
6523 String state = svattrib.getStateData(); // Jalview < 2.9
6524 if (state == null || state.isEmpty()) // Jalview >= 2.9
6526 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6527 state = readJarEntry(jprovider, jarEntryName);
6529 // TODO or simpler? for each key in oldFiles,
6530 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6531 // (allowing for different path escapings)
6532 StringBuilder rewritten = new StringBuilder(state.length());
6533 int cp = 0, ncp, ecp;
6534 Map<File, StructureData> oldFiles = svattrib.getFileData();
6535 while ((ncp = state.indexOf("load ", cp)) > -1)
6539 // look for next filename in load statement
6540 rewritten.append(state.substring(cp,
6541 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6542 String oldfilenam = state.substring(ncp,
6543 ecp = state.indexOf("\"", ncp));
6544 // recover the new mapping data for this old filename
6545 // have to normalize filename - since Jmol and jalview do
6546 // filename translation differently.
6547 StructureData filedat = oldFiles.get(new File(oldfilenam));
6548 if (filedat == null)
6550 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6551 filedat = oldFiles.get(new File(reformatedOldFilename));
6553 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6554 rewritten.append("\"");
6555 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6556 // look for next file statement.
6557 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6561 // just append rest of state
6562 rewritten.append(state.substring(cp));
6566 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6567 rewritten = new StringBuilder(state);
6568 rewritten.append("; load append ");
6569 for (File id : oldFiles.keySet())
6571 // add pdb files that should be present in the viewer
6572 StructureData filedat = oldFiles.get(id);
6573 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6575 rewritten.append(";");
6578 if (rewritten.length() == 0)
6582 final String history = "history = ";
6583 int historyIndex = rewritten.indexOf(history);
6584 if (historyIndex > -1)
6587 * change "history = [true|false];" to "history = [1|0];"
6589 historyIndex += history.length();
6590 String val = rewritten.substring(historyIndex, historyIndex + 5);
6591 if (val.startsWith("true"))
6593 rewritten.replace(historyIndex, historyIndex + 4, "1");
6595 else if (val.startsWith("false"))
6597 rewritten.replace(historyIndex, historyIndex + 5, "0");
6603 File tmp = File.createTempFile("viewerSession", ".tmp");
6604 try (OutputStream os = new FileOutputStream(tmp))
6606 InputStream is = new ByteArrayInputStream(
6607 rewritten.toString().getBytes());
6609 return tmp.getAbsolutePath();
6611 } catch (IOException e)
6613 Console.error("Error restoring Jmol session: " + e.toString());
6619 * Populates an XML model of the feature colour scheme for one feature type
6621 * @param featureType
6625 public static Colour marshalColour(String featureType,
6626 FeatureColourI fcol)
6628 Colour col = new Colour();
6629 if (fcol.isSimpleColour())
6631 col.setRGB(Format.getHexString(fcol.getColour()));
6635 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6636 col.setMin(fcol.getMin());
6637 col.setMax(fcol.getMax());
6638 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6639 col.setAutoScale(fcol.isAutoScaled());
6640 col.setThreshold(fcol.getThreshold());
6641 col.setColourByLabel(fcol.isColourByLabel());
6642 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6643 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6644 : ThresholdType.NONE));
6645 if (fcol.isColourByAttribute())
6647 final String[] attName = fcol.getAttributeName();
6648 col.getAttributeName().add(attName[0]);
6649 if (attName.length > 1)
6651 col.getAttributeName().add(attName[1]);
6654 Color noColour = fcol.getNoColour();
6655 if (noColour == null)
6657 col.setNoValueColour(NoValueColour.NONE);
6659 else if (noColour == fcol.getMaxColour())
6661 col.setNoValueColour(NoValueColour.MAX);
6665 col.setNoValueColour(NoValueColour.MIN);
6668 col.setName(featureType);
6673 * Populates an XML model of the feature filter(s) for one feature type
6675 * @param firstMatcher
6676 * the first (or only) match condition)
6678 * remaining match conditions (if any)
6680 * if true, conditions are and-ed, else or-ed
6682 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6683 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6686 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6688 if (filters.hasNext())
6693 CompoundMatcher compound = new CompoundMatcher();
6694 compound.setAnd(and);
6695 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6696 firstMatcher, Collections.emptyIterator(), and);
6697 // compound.addMatcherSet(matcher1);
6698 compound.getMatcherSet().add(matcher1);
6699 FeatureMatcherI nextMatcher = filters.next();
6700 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6701 nextMatcher, filters, and);
6702 // compound.addMatcherSet(matcher2);
6703 compound.getMatcherSet().add(matcher2);
6704 result.setCompoundMatcher(compound);
6709 * single condition matcher
6711 // MatchCondition matcherModel = new MatchCondition();
6712 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6713 matcherModel.setCondition(
6714 firstMatcher.getMatcher().getCondition().getStableName());
6715 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6716 if (firstMatcher.isByAttribute())
6718 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6719 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6720 String[] attName = firstMatcher.getAttribute();
6721 matcherModel.getAttributeName().add(attName[0]); // attribute
6722 if (attName.length > 1)
6724 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6727 else if (firstMatcher.isByLabel())
6729 matcherModel.setBy(FilterBy.BY_LABEL);
6731 else if (firstMatcher.isByScore())
6733 matcherModel.setBy(FilterBy.BY_SCORE);
6735 result.setMatchCondition(matcherModel);
6742 * Loads one XML model of a feature filter to a Jalview object
6744 * @param featureType
6745 * @param matcherSetModel
6748 public static FeatureMatcherSetI parseFilter(String featureType,
6749 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6751 FeatureMatcherSetI result = new FeatureMatcherSet();
6754 parseFilterConditions(result, matcherSetModel, true);
6755 } catch (IllegalStateException e)
6757 // mixing AND and OR conditions perhaps
6758 jalview.bin.Console.errPrintln(
6759 String.format("Error reading filter conditions for '%s': %s",
6760 featureType, e.getMessage()));
6761 // return as much as was parsed up to the error
6768 * Adds feature match conditions to matcherSet as unmarshalled from XML
6769 * (possibly recursively for compound conditions)
6772 * @param matcherSetModel
6774 * if true, multiple conditions are AND-ed, else they are OR-ed
6775 * @throws IllegalStateException
6776 * if AND and OR conditions are mixed
6778 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6779 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6782 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6783 .getMatchCondition();
6789 FilterBy filterBy = mc.getBy();
6790 Condition cond = Condition.fromString(mc.getCondition());
6791 String pattern = mc.getValue();
6792 FeatureMatcherI matchCondition = null;
6793 if (filterBy == FilterBy.BY_LABEL)
6795 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6797 else if (filterBy == FilterBy.BY_SCORE)
6799 matchCondition = FeatureMatcher.byScore(cond, pattern);
6802 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6804 final List<String> attributeName = mc.getAttributeName();
6805 String[] attNames = attributeName
6806 .toArray(new String[attributeName.size()]);
6807 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6812 * note this throws IllegalStateException if AND-ing to a
6813 * previously OR-ed compound condition, or vice versa
6817 matcherSet.and(matchCondition);
6821 matcherSet.or(matchCondition);
6827 * compound condition
6829 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6830 .getCompoundMatcher().getMatcherSet();
6831 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6832 if (matchers.size() == 2)
6834 parseFilterConditions(matcherSet, matchers.get(0), anded);
6835 parseFilterConditions(matcherSet, matchers.get(1), anded);
6840 .errPrintln("Malformed compound filter condition");
6846 * Loads one XML model of a feature colour to a Jalview object
6848 * @param colourModel
6851 public static FeatureColourI parseColour(Colour colourModel)
6853 FeatureColourI colour = null;
6855 if (colourModel.getMax() != null)
6857 Color mincol = null;
6858 Color maxcol = null;
6859 Color noValueColour = null;
6863 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6864 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6865 } catch (Exception e)
6867 Console.warn("Couldn't parse out graduated feature color.", e);
6870 NoValueColour noCol = colourModel.getNoValueColour();
6871 if (noCol == NoValueColour.MIN)
6873 noValueColour = mincol;
6875 else if (noCol == NoValueColour.MAX)
6877 noValueColour = maxcol;
6880 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6881 safeFloat(colourModel.getMin()),
6882 safeFloat(colourModel.getMax()));
6883 final List<String> attributeName = colourModel.getAttributeName();
6884 String[] attributes = attributeName
6885 .toArray(new String[attributeName.size()]);
6886 if (attributes != null && attributes.length > 0)
6888 colour.setAttributeName(attributes);
6890 if (colourModel.isAutoScale() != null)
6892 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6894 if (colourModel.isColourByLabel() != null)
6896 colour.setColourByLabel(
6897 colourModel.isColourByLabel().booleanValue());
6899 if (colourModel.getThreshold() != null)
6901 colour.setThreshold(colourModel.getThreshold().floatValue());
6903 ThresholdType ttyp = colourModel.getThreshType();
6904 if (ttyp == ThresholdType.ABOVE)
6906 colour.setAboveThreshold(true);
6908 else if (ttyp == ThresholdType.BELOW)
6910 colour.setBelowThreshold(true);
6915 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6916 colour = new FeatureColour(color);
6922 public static void setStateSavedUpToDate(boolean s)
6924 Console.debug("Setting overall stateSavedUpToDate to " + s);
6925 stateSavedUpToDate = s;
6928 public static boolean stateSavedUpToDate()
6930 Console.debug("Returning overall stateSavedUpToDate value: "
6931 + stateSavedUpToDate);
6932 return stateSavedUpToDate;
6935 public static boolean allSavedUpToDate()
6937 if (stateSavedUpToDate()) // nothing happened since last project save
6940 AlignFrame[] frames = Desktop.getAlignFrames();
6943 for (int i = 0; i < frames.length; i++)
6945 if (frames[i] == null)
6947 if (!frames[i].getViewport().savedUpToDate())
6948 return false; // at least one alignment is not individually saved
6954 // used for debugging and tests
6955 private static int debugDelaySave = 20;
6957 public static void setDebugDelaySave(int n)