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 jalview.analysis.Conservation;
28 import jalview.analysis.PCA;
29 import jalview.analysis.scoremodels.ScoreModels;
30 import jalview.analysis.scoremodels.SimilarityParams;
31 import jalview.api.FeatureColourI;
32 import jalview.api.ViewStyleI;
33 import jalview.api.analysis.ScoreModelI;
34 import jalview.api.analysis.SimilarityParamsI;
35 import jalview.api.structures.JalviewStructureDisplayI;
36 import jalview.bin.Cache;
37 import jalview.datamodel.AlignedCodonFrame;
38 import jalview.datamodel.Alignment;
39 import jalview.datamodel.AlignmentAnnotation;
40 import jalview.datamodel.AlignmentI;
41 import jalview.datamodel.DBRefEntry;
42 import jalview.datamodel.GeneLocus;
43 import jalview.datamodel.GraphLine;
44 import jalview.datamodel.PDBEntry;
45 import jalview.datamodel.Point;
46 import jalview.datamodel.RnaViewerModel;
47 import jalview.datamodel.SequenceFeature;
48 import jalview.datamodel.SequenceGroup;
49 import jalview.datamodel.SequenceI;
50 import jalview.datamodel.StructureViewerModel;
51 import jalview.datamodel.StructureViewerModel.StructureData;
52 import jalview.datamodel.features.FeatureMatcher;
53 import jalview.datamodel.features.FeatureMatcherI;
54 import jalview.datamodel.features.FeatureMatcherSet;
55 import jalview.datamodel.features.FeatureMatcherSetI;
56 import jalview.ext.varna.RnaModel;
57 import jalview.gui.AlignFrame;
58 import jalview.gui.AlignViewport;
59 import jalview.gui.AlignmentPanel;
60 import jalview.gui.AppVarna;
61 import jalview.gui.ChimeraViewFrame;
62 import jalview.gui.Desktop;
63 import jalview.gui.JvOptionPane;
64 import jalview.gui.OOMWarning;
65 import jalview.gui.PCAPanel;
66 import jalview.gui.PaintRefresher;
67 import jalview.gui.SplitFrame;
68 import jalview.gui.StructureViewer;
69 import jalview.gui.StructureViewer.ViewerType;
70 import jalview.gui.StructureViewerBase;
71 import jalview.gui.TreePanel;
72 import jalview.io.BackupFiles;
73 import jalview.io.DataSourceType;
74 import jalview.io.FileFormat;
75 import jalview.io.NewickFile;
76 import jalview.math.Matrix;
77 import jalview.math.MatrixI;
78 import jalview.renderer.ResidueShaderI;
79 import jalview.schemes.AnnotationColourGradient;
80 import jalview.schemes.ColourSchemeI;
81 import jalview.schemes.ColourSchemeProperty;
82 import jalview.schemes.FeatureColour;
83 import jalview.schemes.ResidueProperties;
84 import jalview.schemes.UserColourScheme;
85 import jalview.structure.StructureSelectionManager;
86 import jalview.structures.models.AAStructureBindingModel;
87 import jalview.util.Format;
88 import jalview.util.MessageManager;
89 import jalview.util.Platform;
90 import jalview.util.StringUtils;
91 import jalview.util.jarInputStreamProvider;
92 import jalview.util.matcher.Condition;
93 import jalview.viewmodel.AlignmentViewport;
94 import jalview.viewmodel.PCAModel;
95 import jalview.viewmodel.ViewportRanges;
96 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
97 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
98 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
99 import jalview.ws.jws2.Jws2Discoverer;
100 import jalview.ws.jws2.dm.AAConSettings;
101 import jalview.ws.jws2.jabaws2.Jws2Instance;
102 import jalview.ws.params.ArgumentI;
103 import jalview.ws.params.AutoCalcSetting;
104 import jalview.ws.params.WsParamSetI;
105 import jalview.xml.binding.jalview.AlcodonFrame;
106 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
107 import jalview.xml.binding.jalview.Annotation;
108 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
109 import jalview.xml.binding.jalview.AnnotationColourScheme;
110 import jalview.xml.binding.jalview.AnnotationElement;
111 import jalview.xml.binding.jalview.DoubleMatrix;
112 import jalview.xml.binding.jalview.DoubleVector;
113 import jalview.xml.binding.jalview.Feature;
114 import jalview.xml.binding.jalview.Feature.OtherData;
115 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
116 import jalview.xml.binding.jalview.FilterBy;
117 import jalview.xml.binding.jalview.JalviewModel;
118 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
119 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
120 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
121 import jalview.xml.binding.jalview.JalviewModel.JGroup;
122 import jalview.xml.binding.jalview.JalviewModel.JSeq;
123 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
124 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
125 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
126 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
127 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
128 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
129 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
130 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
131 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
132 import jalview.xml.binding.jalview.JalviewModel.Tree;
133 import jalview.xml.binding.jalview.JalviewModel.UserColours;
134 import jalview.xml.binding.jalview.JalviewModel.Viewport;
135 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
136 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
137 import jalview.xml.binding.jalview.JalviewUserColours;
138 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
139 import jalview.xml.binding.jalview.MapListType.MapListFrom;
140 import jalview.xml.binding.jalview.MapListType.MapListTo;
141 import jalview.xml.binding.jalview.Mapping;
142 import jalview.xml.binding.jalview.NoValueColour;
143 import jalview.xml.binding.jalview.ObjectFactory;
144 import jalview.xml.binding.jalview.PcaDataType;
145 import jalview.xml.binding.jalview.Pdbentry.Property;
146 import jalview.xml.binding.jalview.Sequence;
147 import jalview.xml.binding.jalview.Sequence.DBRef;
148 import jalview.xml.binding.jalview.SequenceSet;
149 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
150 import jalview.xml.binding.jalview.ThresholdType;
151 import jalview.xml.binding.jalview.VAMSAS;
153 import java.awt.Color;
154 import java.awt.Font;
155 import java.awt.Rectangle;
156 import java.io.BufferedReader;
157 import java.io.DataInputStream;
158 import java.io.DataOutputStream;
160 import java.io.FileInputStream;
161 import java.io.FileOutputStream;
162 import java.io.IOException;
163 import java.io.InputStreamReader;
164 import java.io.OutputStreamWriter;
165 import java.io.PrintWriter;
166 import java.lang.reflect.InvocationTargetException;
167 import java.math.BigInteger;
168 import java.net.MalformedURLException;
170 import java.util.ArrayList;
171 import java.util.Arrays;
172 import java.util.Collections;
173 import java.util.Enumeration;
174 import java.util.GregorianCalendar;
175 import java.util.HashMap;
176 import java.util.HashSet;
177 import java.util.Hashtable;
178 import java.util.IdentityHashMap;
179 import java.util.Iterator;
180 import java.util.LinkedHashMap;
181 import java.util.List;
182 import java.util.Map;
183 import java.util.Map.Entry;
184 import java.util.Set;
185 import java.util.Vector;
186 import java.util.jar.JarEntry;
187 import java.util.jar.JarInputStream;
188 import java.util.jar.JarOutputStream;
190 import javax.swing.JInternalFrame;
191 import javax.swing.SwingUtilities;
192 import javax.xml.bind.JAXBContext;
193 import javax.xml.bind.JAXBElement;
194 import javax.xml.bind.Marshaller;
195 import javax.xml.datatype.DatatypeConfigurationException;
196 import javax.xml.datatype.DatatypeFactory;
197 import javax.xml.datatype.XMLGregorianCalendar;
198 import javax.xml.stream.XMLInputFactory;
199 import javax.xml.stream.XMLStreamReader;
202 * Write out the current jalview desktop state as a Jalview XML stream.
204 * Note: the vamsas objects referred to here are primitive versions of the
205 * VAMSAS project schema elements - they are not the same and most likely never
209 * @version $Revision: 1.134 $
211 public class Jalview2XML
213 private static final String VIEWER_PREFIX = "viewer_";
215 private static final String RNA_PREFIX = "rna_";
217 private static final String UTF_8 = "UTF-8";
220 * prefix for recovering datasets for alignments with multiple views where
221 * non-existent dataset IDs were written for some views
223 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
225 // use this with nextCounter() to make unique names for entities
226 private int counter = 0;
229 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
230 * of sequence objects are created.
232 IdentityHashMap<SequenceI, String> seqsToIds = null;
235 * jalview XML Sequence ID to jalview sequence object reference (both dataset
236 * and alignment sequences. Populated as XML reps of sequence objects are
239 Map<String, SequenceI> seqRefIds = null;
241 Map<String, SequenceI> incompleteSeqs = null;
243 List<SeqFref> frefedSequence = null;
245 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
248 * Map of reconstructed AlignFrame objects that appear to have come from
249 * SplitFrame objects (have a dna/protein complement view).
251 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
254 * Map from displayed rna structure models to their saved session state jar
257 private Map<RnaModel, String> rnaSessions = new HashMap<>();
260 * A helper method for safely using the value of an optional attribute that
261 * may be null if not present in the XML. Answers the boolean value, or false
267 public static boolean safeBoolean(Boolean b)
269 return b == null ? false : b.booleanValue();
273 * A helper method for safely using the value of an optional attribute that
274 * may be null if not present in the XML. Answers the integer value, or zero
280 public static int safeInt(Integer i)
282 return i == null ? 0 : i.intValue();
286 * A helper method for safely using the value of an optional attribute that
287 * may be null if not present in the XML. Answers the float value, or zero if
293 public static float safeFloat(Float f)
295 return f == null ? 0f : f.floatValue();
299 * create/return unique hash string for sq
302 * @return new or existing unique string for sq
304 String seqHash(SequenceI sq)
306 if (seqsToIds == null)
310 if (seqsToIds.containsKey(sq))
312 return seqsToIds.get(sq);
316 // create sequential key
317 String key = "sq" + (seqsToIds.size() + 1);
318 key = makeHashCode(sq, key); // check we don't have an external reference
320 seqsToIds.put(sq, key);
327 if (seqsToIds == null)
329 seqsToIds = new IdentityHashMap<>();
331 if (seqRefIds == null)
333 seqRefIds = new HashMap<>();
335 if (incompleteSeqs == null)
337 incompleteSeqs = new HashMap<>();
339 if (frefedSequence == null)
341 frefedSequence = new ArrayList<>();
349 public Jalview2XML(boolean raiseGUI)
351 this.raiseGUI = raiseGUI;
355 * base class for resolving forward references to sequences by their ID
360 abstract class SeqFref
366 public SeqFref(String _sref, String type)
372 public String getSref()
377 public SequenceI getSrefSeq()
379 return seqRefIds.get(sref);
382 public boolean isResolvable()
384 return seqRefIds.get(sref) != null;
387 public SequenceI getSrefDatasetSeq()
389 SequenceI sq = seqRefIds.get(sref);
392 while (sq.getDatasetSequence() != null)
394 sq = sq.getDatasetSequence();
401 * @return true if the forward reference was fully resolved
403 abstract boolean resolve();
406 public String toString()
408 return type + " reference to " + sref;
413 * create forward reference for a mapping
419 public SeqFref newMappingRef(final String sref,
420 final jalview.datamodel.Mapping _jmap)
422 SeqFref fref = new SeqFref(sref, "Mapping")
424 public jalview.datamodel.Mapping jmap = _jmap;
429 SequenceI seq = getSrefDatasetSeq();
441 public SeqFref newAlcodMapRef(final String sref,
442 final AlignedCodonFrame _cf,
443 final jalview.datamodel.Mapping _jmap)
446 SeqFref fref = new SeqFref(sref, "Codon Frame")
448 AlignedCodonFrame cf = _cf;
450 public jalview.datamodel.Mapping mp = _jmap;
453 public boolean isResolvable()
455 return super.isResolvable() && mp.getTo() != null;
461 SequenceI seq = getSrefDatasetSeq();
466 cf.addMap(seq, mp.getTo(), mp.getMap());
473 public void resolveFrefedSequences()
475 Iterator<SeqFref> nextFref = frefedSequence.iterator();
476 int toresolve = frefedSequence.size();
477 int unresolved = 0, failedtoresolve = 0;
478 while (nextFref.hasNext())
480 SeqFref ref = nextFref.next();
481 if (ref.isResolvable())
493 } catch (Exception x)
496 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
509 System.err.println("Jalview Project Import: There were " + unresolved
510 + " forward references left unresolved on the stack.");
512 if (failedtoresolve > 0)
514 System.err.println("SERIOUS! " + failedtoresolve
515 + " resolvable forward references failed to resolve.");
517 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
520 "Jalview Project Import: There are " + incompleteSeqs.size()
521 + " sequences which may have incomplete metadata.");
522 if (incompleteSeqs.size() < 10)
524 for (SequenceI s : incompleteSeqs.values())
526 System.err.println(s.toString());
532 "Too many to report. Skipping output of incomplete sequences.");
538 * This maintains a map of viewports, the key being the seqSetId. Important to
539 * set historyItem and redoList for multiple views
541 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
543 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
545 String uniqueSetSuffix = "";
548 * List of pdbfiles added to Jar
550 List<String> pdbfiles = null;
552 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
553 public void saveState(File statefile)
555 FileOutputStream fos = null;
560 fos = new FileOutputStream(statefile);
562 JarOutputStream jout = new JarOutputStream(fos);
566 } catch (Exception e)
568 Cache.log.error("Couln't write Jalview state to " + statefile, e);
569 // TODO: inform user of the problem - they need to know if their data was
571 if (errorMessage == null)
573 errorMessage = "Did't write Jalview Archive to output file '"
574 + statefile + "' - See console error log for details";
578 errorMessage += "(Didn't write Jalview Archive to output file '"
589 } catch (IOException e)
599 * Writes a jalview project archive to the given Jar output stream.
603 public void saveState(JarOutputStream jout)
605 AlignFrame[] frames = Desktop.getAlignFrames();
611 saveAllFrames(Arrays.asList(frames), jout);
615 * core method for storing state for a set of AlignFrames.
618 * - frames involving all data to be exported (including containing
621 * - project output stream
623 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
625 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
628 * ensure cached data is clear before starting
630 // todo tidy up seqRefIds, seqsToIds initialisation / reset
632 splitFrameCandidates.clear();
637 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
638 // //////////////////////////////////////////////////
640 List<String> shortNames = new ArrayList<>();
641 List<String> viewIds = new ArrayList<>();
644 for (int i = frames.size() - 1; i > -1; i--)
646 AlignFrame af = frames.get(i);
648 if (skipList != null && skipList
649 .containsKey(af.getViewport().getSequenceSetId()))
654 String shortName = makeFilename(af, shortNames);
656 int apSize = af.getAlignPanels().size();
658 for (int ap = 0; ap < apSize; ap++)
660 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
662 String fileName = apSize == 1 ? shortName : ap + shortName;
663 if (!fileName.endsWith(".xml"))
665 fileName = fileName + ".xml";
668 saveState(apanel, fileName, jout, viewIds);
670 String dssid = getDatasetIdRef(
671 af.getViewport().getAlignment().getDataset());
672 if (!dsses.containsKey(dssid))
674 dsses.put(dssid, af);
679 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
685 } catch (Exception foo)
690 } catch (Exception ex)
692 // TODO: inform user of the problem - they need to know if their data was
694 if (errorMessage == null)
696 errorMessage = "Couldn't write Jalview Archive - see error output for details";
698 ex.printStackTrace();
703 * Generates a distinct file name, based on the title of the AlignFrame, by
704 * appending _n for increasing n until an unused name is generated. The new
705 * name (without its extension) is added to the list.
709 * @return the generated name, with .xml extension
711 protected String makeFilename(AlignFrame af, List<String> namesUsed)
713 String shortName = af.getTitle();
715 if (shortName.indexOf(File.separatorChar) > -1)
717 shortName = shortName
718 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
723 while (namesUsed.contains(shortName))
725 if (shortName.endsWith("_" + (count - 1)))
727 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
730 shortName = shortName.concat("_" + count);
734 namesUsed.add(shortName);
736 if (!shortName.endsWith(".xml"))
738 shortName = shortName + ".xml";
743 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
744 public boolean saveAlignment(AlignFrame af, String jarFile,
749 // create backupfiles object and get new temp filename destination
750 BackupFiles backupfiles = new BackupFiles(jarFile);
751 FileOutputStream fos = new FileOutputStream(
752 backupfiles.getTempFilePath());
754 JarOutputStream jout = new JarOutputStream(fos);
755 List<AlignFrame> frames = new ArrayList<>();
757 // resolve splitframes
758 if (af.getViewport().getCodingComplement() != null)
760 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
766 saveAllFrames(frames, jout);
770 } catch (Exception foo)
775 boolean success = true;
777 backupfiles.setWriteSuccess(success);
778 success = backupfiles.rollBackupsAndRenameTempFile();
781 } catch (Exception ex)
783 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
784 ex.printStackTrace();
789 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
790 String fileName, JarOutputStream jout)
793 for (String dssids : dsses.keySet())
795 AlignFrame _af = dsses.get(dssids);
796 String jfileName = fileName + " Dataset for " + _af.getTitle();
797 if (!jfileName.endsWith(".xml"))
799 jfileName = jfileName + ".xml";
801 saveState(_af.alignPanel, jfileName, true, jout, null);
806 * create a JalviewModel from an alignment view and marshall it to a
810 * panel to create jalview model for
812 * name of alignment panel written to output stream
819 public JalviewModel saveState(AlignmentPanel ap, String fileName,
820 JarOutputStream jout, List<String> viewIds)
822 return saveState(ap, fileName, false, jout, viewIds);
826 * create a JalviewModel from an alignment view and marshall it to a
830 * panel to create jalview model for
832 * name of alignment panel written to output stream
834 * when true, only write the dataset for the alignment, not the data
835 * associated with the view.
841 public JalviewModel saveState(AlignmentPanel ap, String fileName,
842 boolean storeDS, JarOutputStream jout, List<String> viewIds)
846 viewIds = new ArrayList<>();
851 List<UserColourScheme> userColours = new ArrayList<>();
853 AlignViewport av = ap.av;
854 ViewportRanges vpRanges = av.getRanges();
856 final ObjectFactory objectFactory = new ObjectFactory();
857 JalviewModel object = objectFactory.createJalviewModel();
858 object.setVamsasModel(new VAMSAS());
860 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
863 GregorianCalendar c = new GregorianCalendar();
864 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
865 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
866 object.setCreationDate(now);
867 } catch (DatatypeConfigurationException e)
869 System.err.println("error writing date: " + e.toString());
872 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
875 * rjal is full height alignment, jal is actual alignment with full metadata
876 * but excludes hidden sequences.
878 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
880 if (av.hasHiddenRows())
882 rjal = jal.getHiddenSequences().getFullAlignment();
885 SequenceSet vamsasSet = new SequenceSet();
887 // JalviewModelSequence jms = new JalviewModelSequence();
889 vamsasSet.setGapChar(jal.getGapCharacter() + "");
891 if (jal.getDataset() != null)
893 // dataset id is the dataset's hashcode
894 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
897 // switch jal and the dataset
898 jal = jal.getDataset();
902 if (jal.getProperties() != null)
904 Enumeration en = jal.getProperties().keys();
905 while (en.hasMoreElements())
907 String key = en.nextElement().toString();
908 SequenceSetProperties ssp = new SequenceSetProperties();
910 ssp.setValue(jal.getProperties().get(key).toString());
911 // vamsasSet.addSequenceSetProperties(ssp);
912 vamsasSet.getSequenceSetProperties().add(ssp);
917 Set<String> calcIdSet = new HashSet<>();
918 // record the set of vamsas sequence XML POJO we create.
919 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
921 for (final SequenceI jds : rjal.getSequences())
923 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
924 : jds.getDatasetSequence();
925 String id = seqHash(jds);
926 if (vamsasSetIds.get(id) == null)
928 if (seqRefIds.get(id) != null && !storeDS)
930 // This happens for two reasons: 1. multiple views are being
932 // 2. the hashCode has collided with another sequence's code. This
934 // HAPPEN! (PF00072.15.stk does this)
935 // JBPNote: Uncomment to debug writing out of files that do not read
936 // back in due to ArrayOutOfBoundExceptions.
937 // System.err.println("vamsasSeq backref: "+id+"");
938 // System.err.println(jds.getName()+"
939 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
940 // System.err.println("Hashcode: "+seqHash(jds));
941 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
942 // System.err.println(rsq.getName()+"
943 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
944 // System.err.println("Hashcode: "+seqHash(rsq));
948 vamsasSeq = createVamsasSequence(id, jds);
949 // vamsasSet.addSequence(vamsasSeq);
950 vamsasSet.getSequence().add(vamsasSeq);
951 vamsasSetIds.put(id, vamsasSeq);
952 seqRefIds.put(id, jds);
956 jseq.setStart(jds.getStart());
957 jseq.setEnd(jds.getEnd());
958 jseq.setColour(av.getSequenceColour(jds).getRGB());
960 jseq.setId(id); // jseq id should be a string not a number
963 // Store any sequences this sequence represents
964 if (av.hasHiddenRows())
966 // use rjal, contains the full height alignment
968 av.getAlignment().getHiddenSequences().isHidden(jds));
970 if (av.isHiddenRepSequence(jds))
972 jalview.datamodel.SequenceI[] reps = av
973 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
975 for (int h = 0; h < reps.length; h++)
979 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
980 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
985 // mark sequence as reference - if it is the reference for this view
988 jseq.setViewreference(jds == jal.getSeqrep());
992 // TODO: omit sequence features from each alignment view's XML dump if we
993 // are storing dataset
994 List<SequenceFeature> sfs = jds.getSequenceFeatures();
995 for (SequenceFeature sf : sfs)
997 // Features features = new Features();
998 Feature features = new Feature();
1000 features.setBegin(sf.getBegin());
1001 features.setEnd(sf.getEnd());
1002 features.setDescription(sf.getDescription());
1003 features.setType(sf.getType());
1004 features.setFeatureGroup(sf.getFeatureGroup());
1005 features.setScore(sf.getScore());
1006 if (sf.links != null)
1008 for (int l = 0; l < sf.links.size(); l++)
1010 OtherData keyValue = new OtherData();
1011 keyValue.setKey("LINK_" + l);
1012 keyValue.setValue(sf.links.elementAt(l).toString());
1013 // features.addOtherData(keyValue);
1014 features.getOtherData().add(keyValue);
1017 if (sf.otherDetails != null)
1020 * save feature attributes, which may be simple strings or
1021 * map valued (have sub-attributes)
1023 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1025 String key = entry.getKey();
1026 Object value = entry.getValue();
1027 if (value instanceof Map<?, ?>)
1029 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1032 OtherData otherData = new OtherData();
1033 otherData.setKey(key);
1034 otherData.setKey2(subAttribute.getKey());
1035 otherData.setValue(subAttribute.getValue().toString());
1036 // features.addOtherData(otherData);
1037 features.getOtherData().add(otherData);
1042 OtherData otherData = new OtherData();
1043 otherData.setKey(key);
1044 otherData.setValue(value.toString());
1045 // features.addOtherData(otherData);
1046 features.getOtherData().add(otherData);
1051 // jseq.addFeatures(features);
1052 jseq.getFeatures().add(features);
1055 if (jdatasq.getAllPDBEntries() != null)
1057 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1058 while (en.hasMoreElements())
1060 Pdbids pdb = new Pdbids();
1061 jalview.datamodel.PDBEntry entry = en.nextElement();
1063 String pdbId = entry.getId();
1065 pdb.setType(entry.getType());
1068 * Store any structure views associated with this sequence. This
1069 * section copes with duplicate entries in the project, so a dataset
1070 * only view *should* be coped with sensibly.
1072 // This must have been loaded, is it still visible?
1073 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1074 String matchedFile = null;
1075 for (int f = frames.length - 1; f > -1; f--)
1077 if (frames[f] instanceof StructureViewerBase)
1079 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1080 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1081 matchedFile, viewFrame);
1083 * Only store each structure viewer's state once in the project
1084 * jar. First time through only (storeDS==false)
1086 String viewId = viewFrame.getViewId();
1087 if (!storeDS && !viewIds.contains(viewId))
1089 viewIds.add(viewId);
1092 String viewerState = viewFrame.getStateInfo();
1093 writeJarEntry(jout, getViewerJarEntryName(viewId),
1094 viewerState.getBytes());
1095 } catch (IOException e)
1098 "Error saving viewer state: " + e.getMessage());
1104 if (matchedFile != null || entry.getFile() != null)
1106 if (entry.getFile() != null)
1109 matchedFile = entry.getFile();
1111 pdb.setFile(matchedFile); // entry.getFile());
1112 if (pdbfiles == null)
1114 pdbfiles = new ArrayList<>();
1117 if (!pdbfiles.contains(pdbId))
1119 pdbfiles.add(pdbId);
1120 copyFileToJar(jout, matchedFile, pdbId);
1124 Enumeration<String> props = entry.getProperties();
1125 if (props.hasMoreElements())
1127 // PdbentryItem item = new PdbentryItem();
1128 while (props.hasMoreElements())
1130 Property prop = new Property();
1131 String key = props.nextElement();
1133 prop.setValue(entry.getProperty(key).toString());
1134 // item.addProperty(prop);
1135 pdb.getProperty().add(prop);
1137 // pdb.addPdbentryItem(item);
1140 // jseq.addPdbids(pdb);
1141 jseq.getPdbids().add(pdb);
1145 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1147 // jms.addJSeq(jseq);
1148 object.getJSeq().add(jseq);
1151 if (!storeDS && av.hasHiddenRows())
1153 jal = av.getAlignment();
1157 if (storeDS && jal.getCodonFrames() != null)
1159 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1160 for (AlignedCodonFrame acf : jac)
1162 AlcodonFrame alc = new AlcodonFrame();
1163 if (acf.getProtMappings() != null
1164 && acf.getProtMappings().length > 0)
1166 boolean hasMap = false;
1167 SequenceI[] dnas = acf.getdnaSeqs();
1168 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1169 for (int m = 0; m < pmaps.length; m++)
1171 AlcodMap alcmap = new AlcodMap();
1172 alcmap.setDnasq(seqHash(dnas[m]));
1174 createVamsasMapping(pmaps[m], dnas[m], null, false));
1175 // alc.addAlcodMap(alcmap);
1176 alc.getAlcodMap().add(alcmap);
1181 // vamsasSet.addAlcodonFrame(alc);
1182 vamsasSet.getAlcodonFrame().add(alc);
1185 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1187 // AlcodonFrame alc = new AlcodonFrame();
1188 // vamsasSet.addAlcodonFrame(alc);
1189 // for (int p = 0; p < acf.aaWidth; p++)
1191 // Alcodon cmap = new Alcodon();
1192 // if (acf.codons[p] != null)
1194 // // Null codons indicate a gapped column in the translated peptide
1196 // cmap.setPos1(acf.codons[p][0]);
1197 // cmap.setPos2(acf.codons[p][1]);
1198 // cmap.setPos3(acf.codons[p][2]);
1200 // alc.addAlcodon(cmap);
1202 // if (acf.getProtMappings() != null
1203 // && acf.getProtMappings().length > 0)
1205 // SequenceI[] dnas = acf.getdnaSeqs();
1206 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1207 // for (int m = 0; m < pmaps.length; m++)
1209 // AlcodMap alcmap = new AlcodMap();
1210 // alcmap.setDnasq(seqHash(dnas[m]));
1211 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1213 // alc.addAlcodMap(alcmap);
1220 // /////////////////////////////////
1221 if (!storeDS && av.getCurrentTree() != null)
1223 // FIND ANY ASSOCIATED TREES
1224 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1225 if (Desktop.desktop != null)
1227 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1229 for (int t = 0; t < frames.length; t++)
1231 if (frames[t] instanceof TreePanel)
1233 TreePanel tp = (TreePanel) frames[t];
1235 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1237 JalviewModel.Tree tree = new JalviewModel.Tree();
1238 tree.setTitle(tp.getTitle());
1239 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1240 tree.setNewick(tp.getTree().print());
1241 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1243 tree.setFitToWindow(tp.fitToWindow.getState());
1244 tree.setFontName(tp.getTreeFont().getName());
1245 tree.setFontSize(tp.getTreeFont().getSize());
1246 tree.setFontStyle(tp.getTreeFont().getStyle());
1247 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1249 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1250 tree.setShowDistances(tp.distanceMenu.getState());
1252 tree.setHeight(tp.getHeight());
1253 tree.setWidth(tp.getWidth());
1254 tree.setXpos(tp.getX());
1255 tree.setYpos(tp.getY());
1256 tree.setId(makeHashCode(tp, null));
1257 tree.setLinkToAllViews(
1258 tp.getTreeCanvas().isApplyToAllViews());
1260 // jms.addTree(tree);
1261 object.getTree().add(tree);
1271 if (!storeDS && Desktop.desktop != null)
1273 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1275 if (frame instanceof PCAPanel)
1277 PCAPanel panel = (PCAPanel) frame;
1278 if (panel.getAlignViewport().getAlignment() == jal)
1280 savePCA(panel, object);
1288 * store forward refs from an annotationRow to any groups
1290 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1293 for (SequenceI sq : jal.getSequences())
1295 // Store annotation on dataset sequences only
1296 AlignmentAnnotation[] aa = sq.getAnnotation();
1297 if (aa != null && aa.length > 0)
1299 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1306 if (jal.getAlignmentAnnotation() != null)
1308 // Store the annotation shown on the alignment.
1309 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1310 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1315 if (jal.getGroups() != null)
1317 JGroup[] groups = new JGroup[jal.getGroups().size()];
1319 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1321 JGroup jGroup = new JGroup();
1322 groups[++i] = jGroup;
1324 jGroup.setStart(sg.getStartRes());
1325 jGroup.setEnd(sg.getEndRes());
1326 jGroup.setName(sg.getName());
1327 if (groupRefs.containsKey(sg))
1329 // group has references so set its ID field
1330 jGroup.setId(groupRefs.get(sg));
1332 ColourSchemeI colourScheme = sg.getColourScheme();
1333 if (colourScheme != null)
1335 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1336 if (groupColourScheme.conservationApplied())
1338 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1340 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1343 setUserColourScheme(colourScheme, userColours,
1348 jGroup.setColour(colourScheme.getSchemeName());
1351 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1353 jGroup.setColour("AnnotationColourGradient");
1354 jGroup.setAnnotationColours(constructAnnotationColours(
1355 (jalview.schemes.AnnotationColourGradient) colourScheme,
1356 userColours, object));
1358 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1361 setUserColourScheme(colourScheme, userColours, object));
1365 jGroup.setColour(colourScheme.getSchemeName());
1368 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1371 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1372 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1373 jGroup.setDisplayText(sg.getDisplayText());
1374 jGroup.setColourText(sg.getColourText());
1375 jGroup.setTextCol1(sg.textColour.getRGB());
1376 jGroup.setTextCol2(sg.textColour2.getRGB());
1377 jGroup.setTextColThreshold(sg.thresholdTextColour);
1378 jGroup.setShowUnconserved(sg.getShowNonconserved());
1379 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1380 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1381 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1382 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1383 for (SequenceI seq : sg.getSequences())
1385 // jGroup.addSeq(seqHash(seq));
1386 jGroup.getSeq().add(seqHash(seq));
1390 //jms.setJGroup(groups);
1392 for (JGroup grp : groups)
1394 object.getJGroup().add(grp);
1399 // /////////SAVE VIEWPORT
1400 Viewport view = new Viewport();
1401 view.setTitle(ap.alignFrame.getTitle());
1402 view.setSequenceSetId(
1403 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1404 view.setId(av.getViewId());
1405 if (av.getCodingComplement() != null)
1407 view.setComplementId(av.getCodingComplement().getViewId());
1409 view.setViewName(av.getViewName());
1410 view.setGatheredViews(av.isGatherViewsHere());
1412 Rectangle size = ap.av.getExplodedGeometry();
1413 Rectangle position = size;
1416 size = ap.alignFrame.getBounds();
1417 if (av.getCodingComplement() != null)
1419 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1427 view.setXpos(position.x);
1428 view.setYpos(position.y);
1430 view.setWidth(size.width);
1431 view.setHeight(size.height);
1433 view.setStartRes(vpRanges.getStartRes());
1434 view.setStartSeq(vpRanges.getStartSeq());
1436 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1438 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1439 userColours, object));
1442 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1444 AnnotationColourScheme ac = constructAnnotationColours(
1445 (jalview.schemes.AnnotationColourGradient) av
1446 .getGlobalColourScheme(),
1447 userColours, object);
1449 view.setAnnotationColours(ac);
1450 view.setBgColour("AnnotationColourGradient");
1454 view.setBgColour(ColourSchemeProperty
1455 .getColourName(av.getGlobalColourScheme()));
1458 ResidueShaderI vcs = av.getResidueShading();
1459 ColourSchemeI cs = av.getGlobalColourScheme();
1463 if (vcs.conservationApplied())
1465 view.setConsThreshold(vcs.getConservationInc());
1466 if (cs instanceof jalview.schemes.UserColourScheme)
1468 view.setBgColour(setUserColourScheme(cs, userColours, object));
1471 view.setPidThreshold(vcs.getThreshold());
1474 view.setConservationSelected(av.getConservationSelected());
1475 view.setPidSelected(av.getAbovePIDThreshold());
1476 final Font font = av.getFont();
1477 view.setFontName(font.getName());
1478 view.setFontSize(font.getSize());
1479 view.setFontStyle(font.getStyle());
1480 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1481 view.setRenderGaps(av.isRenderGaps());
1482 view.setShowAnnotation(av.isShowAnnotation());
1483 view.setShowBoxes(av.getShowBoxes());
1484 view.setShowColourText(av.getColourText());
1485 view.setShowFullId(av.getShowJVSuffix());
1486 view.setRightAlignIds(av.isRightAlignIds());
1487 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1488 view.setShowText(av.getShowText());
1489 view.setShowUnconserved(av.getShowUnconserved());
1490 view.setWrapAlignment(av.getWrapAlignment());
1491 view.setTextCol1(av.getTextColour().getRGB());
1492 view.setTextCol2(av.getTextColour2().getRGB());
1493 view.setTextColThreshold(av.getThresholdTextColour());
1494 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1495 view.setShowSequenceLogo(av.isShowSequenceLogo());
1496 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1497 view.setShowGroupConsensus(av.isShowGroupConsensus());
1498 view.setShowGroupConservation(av.isShowGroupConservation());
1499 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1500 view.setShowDbRefTooltip(av.isShowDBRefs());
1501 view.setFollowHighlight(av.isFollowHighlight());
1502 view.setFollowSelection(av.followSelection);
1503 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1504 view.setShowComplementFeatures(av.isShowComplementFeatures());
1505 view.setShowComplementFeaturesOnTop(
1506 av.isShowComplementFeaturesOnTop());
1507 if (av.getFeaturesDisplayed() != null)
1509 FeatureSettings fs = new FeatureSettings();
1511 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1512 .getFeatureRenderer();
1513 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1515 Vector<String> settingsAdded = new Vector<>();
1516 if (renderOrder != null)
1518 for (String featureType : renderOrder)
1520 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1521 setting.setType(featureType);
1524 * save any filter for the feature type
1526 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1527 if (filter != null) {
1528 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1529 FeatureMatcherI firstFilter = filters.next();
1530 setting.setMatcherSet(Jalview2XML.marshalFilter(
1531 firstFilter, filters, filter.isAnded()));
1535 * save colour scheme for the feature type
1537 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1538 if (!fcol.isSimpleColour())
1540 setting.setColour(fcol.getMaxColour().getRGB());
1541 setting.setMincolour(fcol.getMinColour().getRGB());
1542 setting.setMin(fcol.getMin());
1543 setting.setMax(fcol.getMax());
1544 setting.setColourByLabel(fcol.isColourByLabel());
1545 if (fcol.isColourByAttribute())
1547 String[] attName = fcol.getAttributeName();
1548 setting.getAttributeName().add(attName[0]);
1549 if (attName.length > 1)
1551 setting.getAttributeName().add(attName[1]);
1554 setting.setAutoScale(fcol.isAutoScaled());
1555 setting.setThreshold(fcol.getThreshold());
1556 Color noColour = fcol.getNoColour();
1557 if (noColour == null)
1559 setting.setNoValueColour(NoValueColour.NONE);
1561 else if (noColour.equals(fcol.getMaxColour()))
1563 setting.setNoValueColour(NoValueColour.MAX);
1567 setting.setNoValueColour(NoValueColour.MIN);
1569 // -1 = No threshold, 0 = Below, 1 = Above
1570 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1571 : (fcol.isBelowThreshold() ? 0 : -1));
1575 setting.setColour(fcol.getColour().getRGB());
1579 av.getFeaturesDisplayed().isVisible(featureType));
1581 .getOrder(featureType);
1584 setting.setOrder(rorder);
1586 /// fs.addSetting(setting);
1587 fs.getSetting().add(setting);
1588 settingsAdded.addElement(featureType);
1592 // is groups actually supposed to be a map here ?
1593 Iterator<String> en = fr.getFeatureGroups().iterator();
1594 Vector<String> groupsAdded = new Vector<>();
1595 while (en.hasNext())
1597 String grp = en.next();
1598 if (groupsAdded.contains(grp))
1602 Group g = new Group();
1604 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1607 fs.getGroup().add(g);
1608 groupsAdded.addElement(grp);
1610 // jms.setFeatureSettings(fs);
1611 object.setFeatureSettings(fs);
1614 if (av.hasHiddenColumns())
1616 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1617 .getHiddenColumns();
1620 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1624 Iterator<int[]> hiddenRegions = hidden.iterator();
1625 while (hiddenRegions.hasNext())
1627 int[] region = hiddenRegions.next();
1628 HiddenColumns hc = new HiddenColumns();
1629 hc.setStart(region[0]);
1630 hc.setEnd(region[1]);
1631 // view.addHiddenColumns(hc);
1632 view.getHiddenColumns().add(hc);
1636 if (calcIdSet.size() > 0)
1638 for (String calcId : calcIdSet)
1640 if (calcId.trim().length() > 0)
1642 CalcIdParam cidp = createCalcIdParam(calcId, av);
1643 // Some calcIds have no parameters.
1646 // view.addCalcIdParam(cidp);
1647 view.getCalcIdParam().add(cidp);
1653 // jms.addViewport(view);
1654 object.getViewport().add(view);
1656 // object.setJalviewModelSequence(jms);
1657 // object.getVamsasModel().addSequenceSet(vamsasSet);
1658 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1660 if (jout != null && fileName != null)
1662 // We may not want to write the object to disk,
1663 // eg we can copy the alignViewport to a new view object
1664 // using save and then load
1667 System.out.println("Writing jar entry " + fileName);
1668 JarEntry entry = new JarEntry(fileName);
1669 jout.putNextEntry(entry);
1670 PrintWriter pout = new PrintWriter(
1671 new OutputStreamWriter(jout, UTF_8));
1672 JAXBContext jaxbContext = JAXBContext
1673 .newInstance(JalviewModel.class);
1674 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1676 // output pretty printed
1677 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1678 jaxbMarshaller.marshal(
1679 new ObjectFactory().createJalviewModel(object), pout);
1681 // jaxbMarshaller.marshal(object, pout);
1682 // marshaller.marshal(object);
1685 } catch (Exception ex)
1687 // TODO: raise error in GUI if marshalling failed.
1688 System.err.println("Error writing Jalview project");
1689 ex.printStackTrace();
1696 * Writes PCA viewer attributes and computed values to an XML model object and
1697 * adds it to the JalviewModel. Any exceptions are reported by logging.
1699 protected void savePCA(PCAPanel panel, JalviewModel object)
1703 PcaViewer viewer = new PcaViewer();
1704 viewer.setHeight(panel.getHeight());
1705 viewer.setWidth(panel.getWidth());
1706 viewer.setXpos(panel.getX());
1707 viewer.setYpos(panel.getY());
1708 viewer.setTitle(panel.getTitle());
1709 PCAModel pcaModel = panel.getPcaModel();
1710 viewer.setScoreModelName(pcaModel.getScoreModelName());
1711 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1712 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1713 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1715 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1716 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1717 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1718 SeqPointMin spmin = new SeqPointMin();
1719 spmin.setXPos(spMin[0]);
1720 spmin.setYPos(spMin[1]);
1721 spmin.setZPos(spMin[2]);
1722 viewer.setSeqPointMin(spmin);
1723 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1724 SeqPointMax spmax = new SeqPointMax();
1725 spmax.setXPos(spMax[0]);
1726 spmax.setYPos(spMax[1]);
1727 spmax.setZPos(spMax[2]);
1728 viewer.setSeqPointMax(spmax);
1729 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1730 viewer.setLinkToAllViews(
1731 panel.getRotatableCanvas().isApplyToAllViews());
1732 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1733 viewer.setIncludeGaps(sp.includeGaps());
1734 viewer.setMatchGaps(sp.matchGaps());
1735 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1736 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1739 * sequence points on display
1741 for (jalview.datamodel.SequencePoint spt : pcaModel
1742 .getSequencePoints())
1744 SequencePoint point = new SequencePoint();
1745 point.setSequenceRef(seqHash(spt.getSequence()));
1746 point.setXPos(spt.coord.x);
1747 point.setYPos(spt.coord.y);
1748 point.setZPos(spt.coord.z);
1749 viewer.getSequencePoint().add(point);
1753 * (end points of) axes on display
1755 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1758 Axis axis = new Axis();
1762 viewer.getAxis().add(axis);
1766 * raw PCA data (note we are not restoring PCA inputs here -
1767 * alignment view, score model, similarity parameters)
1769 PcaDataType data = new PcaDataType();
1770 viewer.setPcaData(data);
1771 PCA pca = pcaModel.getPcaData();
1773 DoubleMatrix pm = new DoubleMatrix();
1774 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1775 data.setPairwiseMatrix(pm);
1777 DoubleMatrix tm = new DoubleMatrix();
1778 saveDoubleMatrix(pca.getTridiagonal(), tm);
1779 data.setTridiagonalMatrix(tm);
1781 DoubleMatrix eigenMatrix = new DoubleMatrix();
1782 data.setEigenMatrix(eigenMatrix);
1783 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1785 object.getPcaViewer().add(viewer);
1786 } catch (Throwable t)
1788 Cache.log.error("Error saving PCA: " + t.getMessage());
1793 * Stores values from a matrix into an XML element, including (if present) the
1798 * @see #loadDoubleMatrix(DoubleMatrix)
1800 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1802 xmlMatrix.setRows(m.height());
1803 xmlMatrix.setColumns(m.width());
1804 for (int i = 0; i < m.height(); i++)
1806 DoubleVector row = new DoubleVector();
1807 for (int j = 0; j < m.width(); j++)
1809 row.getV().add(m.getValue(i, j));
1811 xmlMatrix.getRow().add(row);
1813 if (m.getD() != null)
1815 DoubleVector dVector = new DoubleVector();
1816 for (double d : m.getD())
1818 dVector.getV().add(d);
1820 xmlMatrix.setD(dVector);
1822 if (m.getE() != null)
1824 DoubleVector eVector = new DoubleVector();
1825 for (double e : m.getE())
1827 eVector.getV().add(e);
1829 xmlMatrix.setE(eVector);
1834 * Loads XML matrix data into a new Matrix object, including the D and/or E
1835 * vectors (if present)
1839 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1841 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1843 int rows = mData.getRows();
1844 double[][] vals = new double[rows][];
1846 for (int i = 0; i < rows; i++)
1848 List<Double> dVector = mData.getRow().get(i).getV();
1849 vals[i] = new double[dVector.size()];
1851 for (Double d : dVector)
1857 MatrixI m = new Matrix(vals);
1859 if (mData.getD() != null)
1861 List<Double> dVector = mData.getD().getV();
1862 double[] vec = new double[dVector.size()];
1864 for (Double d : dVector)
1870 if (mData.getE() != null)
1872 List<Double> dVector = mData.getE().getV();
1873 double[] vec = new double[dVector.size()];
1875 for (Double d : dVector)
1886 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1887 * for each viewer, with
1889 * <li>viewer geometry (position, size, split pane divider location)</li>
1890 * <li>index of the selected structure in the viewer (currently shows gapped
1892 * <li>the id of the annotation holding RNA secondary structure</li>
1893 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1895 * Varna viewer state is also written out (in native Varna XML) to separate
1896 * project jar entries. A separate entry is written for each RNA structure
1897 * displayed, with the naming convention
1899 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1907 * @param storeDataset
1909 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1910 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1911 boolean storeDataset)
1913 if (Desktop.desktop == null)
1917 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1918 for (int f = frames.length - 1; f > -1; f--)
1920 if (frames[f] instanceof AppVarna)
1922 AppVarna varna = (AppVarna) frames[f];
1924 * link the sequence to every viewer that is showing it and is linked to
1925 * its alignment panel
1927 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1929 String viewId = varna.getViewId();
1930 RnaViewer rna = new RnaViewer();
1931 rna.setViewId(viewId);
1932 rna.setTitle(varna.getTitle());
1933 rna.setXpos(varna.getX());
1934 rna.setYpos(varna.getY());
1935 rna.setWidth(varna.getWidth());
1936 rna.setHeight(varna.getHeight());
1937 rna.setDividerLocation(varna.getDividerLocation());
1938 rna.setSelectedRna(varna.getSelectedIndex());
1939 // jseq.addRnaViewer(rna);
1940 jseq.getRnaViewer().add(rna);
1943 * Store each Varna panel's state once in the project per sequence.
1944 * First time through only (storeDataset==false)
1946 // boolean storeSessions = false;
1947 // String sequenceViewId = viewId + seqsToIds.get(jds);
1948 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1950 // viewIds.add(sequenceViewId);
1951 // storeSessions = true;
1953 for (RnaModel model : varna.getModels())
1955 if (model.seq == jds)
1958 * VARNA saves each view (sequence or alignment secondary
1959 * structure, gapped or trimmed) as a separate XML file
1961 String jarEntryName = rnaSessions.get(model);
1962 if (jarEntryName == null)
1965 String varnaStateFile = varna.getStateInfo(model.rna);
1966 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1967 copyFileToJar(jout, varnaStateFile, jarEntryName);
1968 rnaSessions.put(model, jarEntryName);
1970 SecondaryStructure ss = new SecondaryStructure();
1971 String annotationId = varna.getAnnotation(jds).annotationId;
1972 ss.setAnnotationId(annotationId);
1973 ss.setViewerState(jarEntryName);
1974 ss.setGapped(model.gapped);
1975 ss.setTitle(model.title);
1976 // rna.addSecondaryStructure(ss);
1977 rna.getSecondaryStructure().add(ss);
1986 * Copy the contents of a file to a new entry added to the output jar
1990 * @param jarEntryName
1992 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1993 String jarEntryName)
1995 DataInputStream dis = null;
1998 File file = new File(infilePath);
1999 if (file.exists() && jout != null)
2001 dis = new DataInputStream(new FileInputStream(file));
2002 byte[] data = new byte[(int) file.length()];
2003 dis.readFully(data);
2004 writeJarEntry(jout, jarEntryName, data);
2006 } catch (Exception ex)
2008 ex.printStackTrace();
2016 } catch (IOException e)
2025 * Write the data to a new entry of given name in the output jar file
2028 * @param jarEntryName
2030 * @throws IOException
2032 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2033 byte[] data) throws IOException
2037 System.out.println("Writing jar entry " + jarEntryName);
2038 jout.putNextEntry(new JarEntry(jarEntryName));
2039 DataOutputStream dout = new DataOutputStream(jout);
2040 dout.write(data, 0, data.length);
2047 * Save the state of a structure viewer
2052 * the archive XML element under which to save the state
2055 * @param matchedFile
2059 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2060 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2061 String matchedFile, StructureViewerBase viewFrame)
2063 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2066 * Look for any bindings for this viewer to the PDB file of interest
2067 * (including part matches excluding chain id)
2069 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2071 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2072 final String pdbId = pdbentry.getId();
2073 if (!pdbId.equals(entry.getId())
2074 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2075 .startsWith(pdbId.toLowerCase())))
2078 * not interested in a binding to a different PDB entry here
2082 if (matchedFile == null)
2084 matchedFile = pdbentry.getFile();
2086 else if (!matchedFile.equals(pdbentry.getFile()))
2089 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2090 + pdbentry.getFile());
2094 // can get at it if the ID
2095 // match is ambiguous (e.g.
2098 for (int smap = 0; smap < viewFrame.getBinding()
2099 .getSequence()[peid].length; smap++)
2101 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2102 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2104 StructureState state = new StructureState();
2105 state.setVisible(true);
2106 state.setXpos(viewFrame.getX());
2107 state.setYpos(viewFrame.getY());
2108 state.setWidth(viewFrame.getWidth());
2109 state.setHeight(viewFrame.getHeight());
2110 final String viewId = viewFrame.getViewId();
2111 state.setViewId(viewId);
2112 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2113 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2114 state.setColourByJmol(viewFrame.isColouredByViewer());
2115 state.setType(viewFrame.getViewerType().toString());
2116 // pdb.addStructureState(state);
2117 pdb.getStructureState().add(state);
2125 * Populates the AnnotationColourScheme xml for save. This captures the
2126 * settings of the options in the 'Colour by Annotation' dialog.
2129 * @param userColours
2133 private AnnotationColourScheme constructAnnotationColours(
2134 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2137 AnnotationColourScheme ac = new AnnotationColourScheme();
2138 ac.setAboveThreshold(acg.getAboveThreshold());
2139 ac.setThreshold(acg.getAnnotationThreshold());
2140 // 2.10.2 save annotationId (unique) not annotation label
2141 ac.setAnnotation(acg.getAnnotation().annotationId);
2142 if (acg.getBaseColour() instanceof UserColourScheme)
2145 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2150 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2153 ac.setMaxColour(acg.getMaxColour().getRGB());
2154 ac.setMinColour(acg.getMinColour().getRGB());
2155 ac.setPerSequence(acg.isSeqAssociated());
2156 ac.setPredefinedColours(acg.isPredefinedColours());
2160 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2161 IdentityHashMap<SequenceGroup, String> groupRefs,
2162 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2163 SequenceSet vamsasSet)
2166 for (int i = 0; i < aa.length; i++)
2168 Annotation an = new Annotation();
2170 AlignmentAnnotation annotation = aa[i];
2171 if (annotation.annotationId != null)
2173 annotationIds.put(annotation.annotationId, annotation);
2176 an.setId(annotation.annotationId);
2178 an.setVisible(annotation.visible);
2180 an.setDescription(annotation.description);
2182 if (annotation.sequenceRef != null)
2184 // 2.9 JAL-1781 xref on sequence id rather than name
2185 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2187 if (annotation.groupRef != null)
2189 String groupIdr = groupRefs.get(annotation.groupRef);
2190 if (groupIdr == null)
2192 // make a locally unique String
2193 groupRefs.put(annotation.groupRef,
2194 groupIdr = ("" + System.currentTimeMillis()
2195 + annotation.groupRef.getName()
2196 + groupRefs.size()));
2198 an.setGroupRef(groupIdr.toString());
2201 // store all visualization attributes for annotation
2202 an.setGraphHeight(annotation.graphHeight);
2203 an.setCentreColLabels(annotation.centreColLabels);
2204 an.setScaleColLabels(annotation.scaleColLabel);
2205 an.setShowAllColLabels(annotation.showAllColLabels);
2206 an.setBelowAlignment(annotation.belowAlignment);
2208 if (annotation.graph > 0)
2211 an.setGraphType(annotation.graph);
2212 an.setGraphGroup(annotation.graphGroup);
2213 if (annotation.getThreshold() != null)
2215 ThresholdLine line = new ThresholdLine();
2216 line.setLabel(annotation.getThreshold().label);
2217 line.setValue(annotation.getThreshold().value);
2218 line.setColour(annotation.getThreshold().colour.getRGB());
2219 an.setThresholdLine(line);
2227 an.setLabel(annotation.label);
2229 if (annotation == av.getAlignmentQualityAnnot()
2230 || annotation == av.getAlignmentConservationAnnotation()
2231 || annotation == av.getAlignmentConsensusAnnotation()
2232 || annotation.autoCalculated)
2234 // new way of indicating autocalculated annotation -
2235 an.setAutoCalculated(annotation.autoCalculated);
2237 if (annotation.hasScore())
2239 an.setScore(annotation.getScore());
2242 if (annotation.getCalcId() != null)
2244 calcIdSet.add(annotation.getCalcId());
2245 an.setCalcId(annotation.getCalcId());
2247 if (annotation.hasProperties())
2249 for (String pr : annotation.getProperties())
2251 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2253 prop.setValue(annotation.getProperty(pr));
2254 // an.addProperty(prop);
2255 an.getProperty().add(prop);
2259 AnnotationElement ae;
2260 if (annotation.annotations != null)
2262 an.setScoreOnly(false);
2263 for (int a = 0; a < annotation.annotations.length; a++)
2265 if ((annotation == null) || (annotation.annotations[a] == null))
2270 ae = new AnnotationElement();
2271 if (annotation.annotations[a].description != null)
2273 ae.setDescription(annotation.annotations[a].description);
2275 if (annotation.annotations[a].displayCharacter != null)
2277 ae.setDisplayCharacter(
2278 annotation.annotations[a].displayCharacter);
2281 if (!Float.isNaN(annotation.annotations[a].value))
2283 ae.setValue(annotation.annotations[a].value);
2287 if (annotation.annotations[a].secondaryStructure > ' ')
2289 ae.setSecondaryStructure(
2290 annotation.annotations[a].secondaryStructure + "");
2293 if (annotation.annotations[a].colour != null
2294 && annotation.annotations[a].colour != java.awt.Color.black)
2296 ae.setColour(annotation.annotations[a].colour.getRGB());
2299 // an.addAnnotationElement(ae);
2300 an.getAnnotationElement().add(ae);
2301 if (annotation.autoCalculated)
2303 // only write one non-null entry into the annotation row -
2304 // sufficient to get the visualization attributes necessary to
2312 an.setScoreOnly(true);
2314 if (!storeDS || (storeDS && !annotation.autoCalculated))
2316 // skip autocalculated annotation - these are only provided for
2318 // vamsasSet.addAnnotation(an);
2319 vamsasSet.getAnnotation().add(an);
2325 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2327 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2328 if (settings != null)
2330 CalcIdParam vCalcIdParam = new CalcIdParam();
2331 vCalcIdParam.setCalcId(calcId);
2332 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2333 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2334 // generic URI allowing a third party to resolve another instance of the
2335 // service used for this calculation
2336 for (String url : settings.getServiceURLs())
2338 // vCalcIdParam.addServiceURL(urls);
2339 vCalcIdParam.getServiceURL().add(url);
2341 vCalcIdParam.setVersion("1.0");
2342 if (settings.getPreset() != null)
2344 WsParamSetI setting = settings.getPreset();
2345 vCalcIdParam.setName(setting.getName());
2346 vCalcIdParam.setDescription(setting.getDescription());
2350 vCalcIdParam.setName("");
2351 vCalcIdParam.setDescription("Last used parameters");
2353 // need to be able to recover 1) settings 2) user-defined presets or
2354 // recreate settings from preset 3) predefined settings provided by
2355 // service - or settings that can be transferred (or discarded)
2356 vCalcIdParam.setParameters(
2357 settings.getWsParamFile().replace("\n", "|\\n|"));
2358 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2359 // todo - decide if updateImmediately is needed for any projects.
2361 return vCalcIdParam;
2366 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2369 if (calcIdParam.getVersion().equals("1.0"))
2371 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2372 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2373 .getPreferredServiceFor(calcIds);
2374 if (service != null)
2376 WsParamSetI parmSet = null;
2379 parmSet = service.getParamStore().parseServiceParameterFile(
2380 calcIdParam.getName(), calcIdParam.getDescription(),
2382 calcIdParam.getParameters().replace("|\\n|", "\n"));
2383 } catch (IOException x)
2385 warn("Couldn't parse parameter data for "
2386 + calcIdParam.getCalcId(), x);
2389 List<ArgumentI> argList = null;
2390 if (calcIdParam.getName().length() > 0)
2392 parmSet = service.getParamStore()
2393 .getPreset(calcIdParam.getName());
2394 if (parmSet != null)
2396 // TODO : check we have a good match with settings in AACon -
2397 // otherwise we'll need to create a new preset
2402 argList = parmSet.getArguments();
2405 AAConSettings settings = new AAConSettings(
2406 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2407 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2408 calcIdParam.isNeedsUpdate());
2413 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2417 throw new Error(MessageManager.formatMessage(
2418 "error.unsupported_version_calcIdparam", new Object[]
2419 { calcIdParam.toString() }));
2423 * External mapping between jalview objects and objects yielding a valid and
2424 * unique object ID string. This is null for normal Jalview project IO, but
2425 * non-null when a jalview project is being read or written as part of a
2428 IdentityHashMap jv2vobj = null;
2431 * Construct a unique ID for jvobj using either existing bindings or if none
2432 * exist, the result of the hashcode call for the object.
2435 * jalview data object
2436 * @return unique ID for referring to jvobj
2438 private String makeHashCode(Object jvobj, String altCode)
2440 if (jv2vobj != null)
2442 Object id = jv2vobj.get(jvobj);
2445 return id.toString();
2447 // check string ID mappings
2448 if (jvids2vobj != null && jvobj instanceof String)
2450 id = jvids2vobj.get(jvobj);
2454 return id.toString();
2456 // give up and warn that something has gone wrong
2457 warn("Cannot find ID for object in external mapping : " + jvobj);
2463 * return local jalview object mapped to ID, if it exists
2467 * @return null or object bound to idcode
2469 private Object retrieveExistingObj(String idcode)
2471 if (idcode != null && vobj2jv != null)
2473 return vobj2jv.get(idcode);
2479 * binding from ID strings from external mapping table to jalview data model
2482 private Hashtable vobj2jv;
2484 private Sequence createVamsasSequence(String id, SequenceI jds)
2486 return createVamsasSequence(true, id, jds, null);
2489 private Sequence createVamsasSequence(boolean recurse, String id,
2490 SequenceI jds, SequenceI parentseq)
2492 Sequence vamsasSeq = new Sequence();
2493 vamsasSeq.setId(id);
2494 vamsasSeq.setName(jds.getName());
2495 vamsasSeq.setSequence(jds.getSequenceAsString());
2496 vamsasSeq.setDescription(jds.getDescription());
2497 jalview.datamodel.DBRefEntry[] dbrefs = null;
2498 if (jds.getDatasetSequence() != null)
2500 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2504 // seqId==dsseqid so we can tell which sequences really are
2505 // dataset sequences only
2506 vamsasSeq.setDsseqid(id);
2507 dbrefs = jds.getDBRefs();
2508 if (parentseq == null)
2515 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2519 for (int d = 0; d < dbrefs.length; d++)
2521 DBRef dbref = new DBRef();
2522 DBRefEntry dbRefEntry = dbrefs[d];
2523 dbref.setSource(dbRefEntry.getSource());
2524 dbref.setVersion(dbRefEntry.getVersion());
2525 dbref.setAccessionId(dbRefEntry.getAccessionId());
2526 if (dbRefEntry instanceof GeneLocus)
2528 dbref.setLocus(true);
2530 if (dbRefEntry.hasMap())
2532 Mapping mp = createVamsasMapping(dbRefEntry.getMap(), parentseq,
2534 dbref.setMapping(mp);
2536 vamsasSeq.getDBRef().add(dbref);
2542 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2543 SequenceI parentseq, SequenceI jds, boolean recurse)
2546 if (jmp.getMap() != null)
2550 jalview.util.MapList mlst = jmp.getMap();
2551 List<int[]> r = mlst.getFromRanges();
2552 for (int[] range : r)
2554 MapListFrom mfrom = new MapListFrom();
2555 mfrom.setStart(range[0]);
2556 mfrom.setEnd(range[1]);
2557 // mp.addMapListFrom(mfrom);
2558 mp.getMapListFrom().add(mfrom);
2560 r = mlst.getToRanges();
2561 for (int[] range : r)
2563 MapListTo mto = new MapListTo();
2564 mto.setStart(range[0]);
2565 mto.setEnd(range[1]);
2566 // mp.addMapListTo(mto);
2567 mp.getMapListTo().add(mto);
2569 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2570 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2571 if (jmp.getTo() != null)
2573 // MappingChoice mpc = new MappingChoice();
2575 // check/create ID for the sequence referenced by getTo()
2578 SequenceI ps = null;
2579 if (parentseq != jmp.getTo()
2580 && parentseq.getDatasetSequence() != jmp.getTo())
2582 // chaining dbref rather than a handshaking one
2583 jmpid = seqHash(ps = jmp.getTo());
2587 jmpid = seqHash(ps = parentseq);
2589 // mpc.setDseqFor(jmpid);
2590 mp.setDseqFor(jmpid);
2591 if (!seqRefIds.containsKey(jmpid))
2593 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2594 seqRefIds.put(jmpid, ps);
2598 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2601 // mp.setMappingChoice(mpc);
2607 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2608 List<UserColourScheme> userColours, JalviewModel jm)
2611 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2612 boolean newucs = false;
2613 if (!userColours.contains(ucs))
2615 userColours.add(ucs);
2618 id = "ucs" + userColours.indexOf(ucs);
2621 // actually create the scheme's entry in the XML model
2622 java.awt.Color[] colours = ucs.getColours();
2623 UserColours uc = new UserColours();
2624 // UserColourScheme jbucs = new UserColourScheme();
2625 JalviewUserColours jbucs = new JalviewUserColours();
2627 for (int i = 0; i < colours.length; i++)
2629 Colour col = new Colour();
2630 col.setName(ResidueProperties.aa[i]);
2631 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2632 // jbucs.addColour(col);
2633 jbucs.getColour().add(col);
2635 if (ucs.getLowerCaseColours() != null)
2637 colours = ucs.getLowerCaseColours();
2638 for (int i = 0; i < colours.length; i++)
2640 Colour col = new Colour();
2641 col.setName(ResidueProperties.aa[i].toLowerCase());
2642 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2643 // jbucs.addColour(col);
2644 jbucs.getColour().add(col);
2649 uc.setUserColourScheme(jbucs);
2650 // jm.addUserColours(uc);
2651 jm.getUserColours().add(uc);
2657 jalview.schemes.UserColourScheme getUserColourScheme(
2658 JalviewModel jm, String id)
2660 List<UserColours> uc = jm.getUserColours();
2661 UserColours colours = null;
2663 for (int i = 0; i < uc.length; i++)
2665 if (uc[i].getId().equals(id))
2672 for (UserColours c : uc)
2674 if (c.getId().equals(id))
2681 java.awt.Color[] newColours = new java.awt.Color[24];
2683 for (int i = 0; i < 24; i++)
2685 newColours[i] = new java.awt.Color(Integer.parseInt(
2686 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2687 colours.getUserColourScheme().getColour().get(i).getRGB(),
2691 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2694 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2696 newColours = new java.awt.Color[23];
2697 for (int i = 0; i < 23; i++)
2699 newColours[i] = new java.awt.Color(Integer.parseInt(
2700 colours.getUserColourScheme().getColour().get(i + 24)
2704 ucs.setLowerCaseColours(newColours);
2711 * contains last error message (if any) encountered by XML loader.
2713 String errorMessage = null;
2716 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2717 * exceptions are raised during project XML parsing
2719 public boolean attemptversion1parse = false;
2722 * Load a jalview project archive from a jar file
2725 * - HTTP URL or filename
2727 public AlignFrame loadJalviewAlign(final String file)
2730 jalview.gui.AlignFrame af = null;
2734 // create list to store references for any new Jmol viewers created
2735 newStructureViewers = new Vector<>();
2736 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2737 // Workaround is to make sure caller implements the JarInputStreamProvider
2739 // so we can re-open the jar input stream for each entry.
2741 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2742 af = loadJalviewAlign(jprovider);
2745 af.setMenusForViewport();
2747 } catch (MalformedURLException e)
2749 errorMessage = "Invalid URL format for '" + file + "'";
2755 SwingUtilities.invokeAndWait(new Runnable()
2760 setLoadingFinishedForNewStructureViewers();
2763 } catch (Exception x)
2765 System.err.println("Error loading alignment: " + x.getMessage());
2771 private jarInputStreamProvider createjarInputStreamProvider(
2772 final String file) throws MalformedURLException
2775 errorMessage = null;
2776 uniqueSetSuffix = null;
2778 viewportsAdded.clear();
2779 frefedSequence = null;
2781 if (file.startsWith("http://"))
2783 url = new URL(file);
2785 final URL _url = url;
2786 return new jarInputStreamProvider()
2790 public JarInputStream getJarInputStream() throws IOException
2794 return new JarInputStream(_url.openStream());
2798 return new JarInputStream(new FileInputStream(file));
2803 public String getFilename()
2811 * Recover jalview session from a jalview project archive. Caller may
2812 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2813 * themselves. Any null fields will be initialised with default values,
2814 * non-null fields are left alone.
2819 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2821 errorMessage = null;
2822 if (uniqueSetSuffix == null)
2824 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2826 if (seqRefIds == null)
2830 AlignFrame af = null, _af = null;
2831 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2832 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2833 final String file = jprovider.getFilename();
2836 JarInputStream jin = null;
2837 JarEntry jarentry = null;
2842 jin = jprovider.getJarInputStream();
2843 for (int i = 0; i < entryCount; i++)
2845 jarentry = jin.getNextJarEntry();
2848 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2850 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2851 // JalviewModel object = new JalviewModel();
2853 JAXBContext jc = JAXBContext
2854 .newInstance("jalview.xml.binding.jalview");
2855 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2856 .createXMLStreamReader(jin);
2857 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2858 JAXBElement<JalviewModel> jbe = um
2859 .unmarshal(streamReader, JalviewModel.class);
2860 JalviewModel object = jbe.getValue();
2863 Unmarshaller unmar = new Unmarshaller(object);
2864 unmar.setValidation(false);
2865 object = (JalviewModel) unmar.unmarshal(in);
2867 if (true) // !skipViewport(object))
2869 _af = loadFromObject(object, file, true, jprovider);
2870 if (_af != null && object.getViewport().size() > 0)
2871 // getJalviewModelSequence().getViewportCount() > 0)
2875 // store a reference to the first view
2878 if (_af.getViewport().isGatherViewsHere())
2880 // if this is a gathered view, keep its reference since
2881 // after gathering views, only this frame will remain
2883 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2886 // Save dataset to register mappings once all resolved
2887 importedDatasets.put(
2888 af.getViewport().getAlignment().getDataset(),
2889 af.getViewport().getAlignment().getDataset());
2894 else if (jarentry != null)
2896 // Some other file here.
2899 } while (jarentry != null);
2900 resolveFrefedSequences();
2901 } catch (IOException ex)
2903 ex.printStackTrace();
2904 errorMessage = "Couldn't locate Jalview XML file : " + file;
2906 "Exception whilst loading jalview XML file : " + ex + "\n");
2907 } catch (Exception ex)
2909 System.err.println("Parsing as Jalview Version 2 file failed.");
2910 ex.printStackTrace(System.err);
2911 if (attemptversion1parse)
2913 // used to attempt to parse as V1 castor-generated xml
2915 if (Desktop.instance != null)
2917 Desktop.instance.stopLoading();
2921 System.out.println("Successfully loaded archive file");
2924 ex.printStackTrace();
2927 "Exception whilst loading jalview XML file : " + ex + "\n");
2928 } catch (OutOfMemoryError e)
2930 // Don't use the OOM Window here
2931 errorMessage = "Out of memory loading jalview XML file";
2932 System.err.println("Out of memory whilst loading jalview XML file");
2933 e.printStackTrace();
2937 * Regather multiple views (with the same sequence set id) to the frame (if
2938 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2939 * views instead of separate frames. Note this doesn't restore a state where
2940 * some expanded views in turn have tabbed views - the last "first tab" read
2941 * in will play the role of gatherer for all.
2943 for (AlignFrame fr : gatherToThisFrame.values())
2945 Desktop.instance.gatherViews(fr);
2948 restoreSplitFrames();
2949 for (AlignmentI ds : importedDatasets.keySet())
2951 if (ds.getCodonFrames() != null)
2953 StructureSelectionManager
2954 .getStructureSelectionManager(Desktop.instance)
2955 .registerMappings(ds.getCodonFrames());
2958 if (errorMessage != null)
2963 if (Desktop.instance != null)
2965 Desktop.instance.stopLoading();
2972 * Try to reconstruct and display SplitFrame windows, where each contains
2973 * complementary dna and protein alignments. Done by pairing up AlignFrame
2974 * objects (created earlier) which have complementary viewport ids associated.
2976 protected void restoreSplitFrames()
2978 List<SplitFrame> gatherTo = new ArrayList<>();
2979 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2980 Map<String, AlignFrame> dna = new HashMap<>();
2983 * Identify the DNA alignments
2985 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2988 AlignFrame af = candidate.getValue();
2989 if (af.getViewport().getAlignment().isNucleotide())
2991 dna.put(candidate.getKey().getId(), af);
2996 * Try to match up the protein complements
2998 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3001 AlignFrame af = candidate.getValue();
3002 if (!af.getViewport().getAlignment().isNucleotide())
3004 String complementId = candidate.getKey().getComplementId();
3005 // only non-null complements should be in the Map
3006 if (complementId != null && dna.containsKey(complementId))
3008 final AlignFrame dnaFrame = dna.get(complementId);
3009 SplitFrame sf = createSplitFrame(dnaFrame, af);
3010 addedToSplitFrames.add(dnaFrame);
3011 addedToSplitFrames.add(af);
3012 dnaFrame.setMenusForViewport();
3013 af.setMenusForViewport();
3014 if (af.getViewport().isGatherViewsHere())
3023 * Open any that we failed to pair up (which shouldn't happen!) as
3024 * standalone AlignFrame's.
3026 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3029 AlignFrame af = candidate.getValue();
3030 if (!addedToSplitFrames.contains(af))
3032 Viewport view = candidate.getKey();
3033 Desktop.addInternalFrame(af, view.getTitle(),
3034 safeInt(view.getWidth()), safeInt(view.getHeight()));
3035 af.setMenusForViewport();
3036 System.err.println("Failed to restore view " + view.getTitle()
3037 + " to split frame");
3042 * Gather back into tabbed views as flagged.
3044 for (SplitFrame sf : gatherTo)
3046 Desktop.instance.gatherViews(sf);
3049 splitFrameCandidates.clear();
3053 * Construct and display one SplitFrame holding DNA and protein alignments.
3056 * @param proteinFrame
3059 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3060 AlignFrame proteinFrame)
3062 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3063 String title = MessageManager.getString("label.linked_view_title");
3064 int width = (int) dnaFrame.getBounds().getWidth();
3065 int height = (int) (dnaFrame.getBounds().getHeight()
3066 + proteinFrame.getBounds().getHeight() + 50);
3069 * SplitFrame location is saved to both enclosed frames
3071 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3072 Desktop.addInternalFrame(splitFrame, title, width, height);
3075 * And compute cDNA consensus (couldn't do earlier with consensus as
3076 * mappings were not yet present)
3078 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3084 * check errorMessage for a valid error message and raise an error box in the
3085 * GUI or write the current errorMessage to stderr and then clear the error
3088 protected void reportErrors()
3090 reportErrors(false);
3093 protected void reportErrors(final boolean saving)
3095 if (errorMessage != null)
3097 final String finalErrorMessage = errorMessage;
3100 javax.swing.SwingUtilities.invokeLater(new Runnable()
3105 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3107 "Error " + (saving ? "saving" : "loading")
3109 JvOptionPane.WARNING_MESSAGE);
3115 System.err.println("Problem loading Jalview file: " + errorMessage);
3118 errorMessage = null;
3121 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3124 * when set, local views will be updated from view stored in JalviewXML
3125 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3126 * sync if this is set to true.
3128 private final boolean updateLocalViews = false;
3131 * Returns the path to a temporary file holding the PDB file for the given PDB
3132 * id. The first time of asking, searches for a file of that name in the
3133 * Jalview project jar, and copies it to a new temporary file. Any repeat
3134 * requests just return the path to the file previously created.
3140 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3143 if (alreadyLoadedPDB.containsKey(pdbId))
3145 return alreadyLoadedPDB.get(pdbId).toString();
3148 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3150 if (tempFile != null)
3152 alreadyLoadedPDB.put(pdbId, tempFile);
3158 * Copies the jar entry of given name to a new temporary file and returns the
3159 * path to the file, or null if the entry is not found.
3162 * @param jarEntryName
3164 * a prefix for the temporary file name, must be at least three
3166 * @param suffixModel
3167 * null or original file - so new file can be given the same suffix
3171 protected String copyJarEntry(jarInputStreamProvider jprovider,
3172 String jarEntryName, String prefix, String suffixModel)
3174 BufferedReader in = null;
3175 PrintWriter out = null;
3176 String suffix = ".tmp";
3177 if (suffixModel == null)
3179 suffixModel = jarEntryName;
3181 int sfpos = suffixModel.lastIndexOf(".");
3182 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3184 suffix = "." + suffixModel.substring(sfpos + 1);
3188 JarInputStream jin = jprovider.getJarInputStream();
3190 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3191 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3192 * FileInputStream(jprovider)); }
3195 JarEntry entry = null;
3198 entry = jin.getNextJarEntry();
3199 } while (entry != null && !entry.getName().equals(jarEntryName));
3202 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3203 File outFile = File.createTempFile(prefix, suffix);
3204 outFile.deleteOnExit();
3205 out = new PrintWriter(new FileOutputStream(outFile));
3208 while ((data = in.readLine()) != null)
3213 String t = outFile.getAbsolutePath();
3218 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3220 } catch (Exception ex)
3222 ex.printStackTrace();
3230 } catch (IOException e)
3244 private class JvAnnotRow
3246 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3253 * persisted version of annotation row from which to take vis properties
3255 public jalview.datamodel.AlignmentAnnotation template;
3258 * original position of the annotation row in the alignment
3264 * Load alignment frame from jalview XML DOM object
3266 * @param jalviewModel
3269 * filename source string
3270 * @param loadTreesAndStructures
3271 * when false only create Viewport
3273 * data source provider
3274 * @return alignment frame created from view stored in DOM
3276 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3277 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3279 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3280 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3282 // JalviewModelSequence jms = object.getJalviewModelSequence();
3284 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3286 Viewport view = (jalviewModel.getViewport().size() > 0)
3287 ? jalviewModel.getViewport().get(0)
3290 // ////////////////////////////////
3291 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3294 // If we just load in the same jar file again, the sequenceSetId
3295 // will be the same, and we end up with multiple references
3296 // to the same sequenceSet. We must modify this id on load
3297 // so that each load of the file gives a unique id
3300 * used to resolve correct alignment dataset for alignments with multiple
3303 String uniqueSeqSetId = null;
3304 String viewId = null;
3307 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3308 viewId = (view.getId() == null ? null
3309 : view.getId() + uniqueSetSuffix);
3312 // ////////////////////////////////
3315 List<SequenceI> hiddenSeqs = null;
3317 List<SequenceI> tmpseqs = new ArrayList<>();
3319 boolean multipleView = false;
3320 SequenceI referenceseqForView = null;
3321 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3322 List<JSeq> jseqs = jalviewModel.getJSeq();
3323 int vi = 0; // counter in vamsasSeq array
3324 for (int i = 0; i < jseqs.size(); i++)
3326 JSeq jseq = jseqs.get(i);
3327 String seqId = jseq.getId();
3329 SequenceI tmpSeq = seqRefIds.get(seqId);
3332 if (!incompleteSeqs.containsKey(seqId))
3334 // may not need this check, but keep it for at least 2.9,1 release
3335 if (tmpSeq.getStart() != jseq.getStart()
3336 || tmpSeq.getEnd() != jseq.getEnd())
3339 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3340 tmpSeq.getName(), tmpSeq.getStart(),
3341 tmpSeq.getEnd(), jseq.getStart(),
3347 incompleteSeqs.remove(seqId);
3349 if (vamsasSeqs.size() > vi
3350 && vamsasSeqs.get(vi).getId().equals(seqId))
3352 // most likely we are reading a dataset XML document so
3353 // update from vamsasSeq section of XML for this sequence
3354 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3355 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3356 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3361 // reading multiple views, so vamsasSeq set is a subset of JSeq
3362 multipleView = true;
3364 tmpSeq.setStart(jseq.getStart());
3365 tmpSeq.setEnd(jseq.getEnd());
3366 tmpseqs.add(tmpSeq);
3370 Sequence vamsasSeq = vamsasSeqs.get(vi);
3371 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3372 vamsasSeq.getSequence());
3373 tmpSeq.setDescription(vamsasSeq.getDescription());
3374 tmpSeq.setStart(jseq.getStart());
3375 tmpSeq.setEnd(jseq.getEnd());
3376 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3377 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3378 tmpseqs.add(tmpSeq);
3382 if (safeBoolean(jseq.isViewreference()))
3384 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3387 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3389 if (hiddenSeqs == null)
3391 hiddenSeqs = new ArrayList<>();
3394 hiddenSeqs.add(tmpSeq);
3399 // Create the alignment object from the sequence set
3400 // ///////////////////////////////
3401 SequenceI[] orderedSeqs = tmpseqs
3402 .toArray(new SequenceI[tmpseqs.size()]);
3404 AlignmentI al = null;
3405 // so we must create or recover the dataset alignment before going further
3406 // ///////////////////////////////
3407 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3409 // older jalview projects do not have a dataset - so creat alignment and
3411 al = new Alignment(orderedSeqs);
3412 al.setDataset(null);
3416 boolean isdsal = jalviewModel.getViewport().isEmpty();
3419 // we are importing a dataset record, so
3420 // recover reference to an alignment already materialsed as dataset
3421 al = getDatasetFor(vamsasSet.getDatasetId());
3425 // materialse the alignment
3426 al = new Alignment(orderedSeqs);
3430 addDatasetRef(vamsasSet.getDatasetId(), al);
3433 // finally, verify all data in vamsasSet is actually present in al
3434 // passing on flag indicating if it is actually a stored dataset
3435 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3438 if (referenceseqForView != null)
3440 al.setSeqrep(referenceseqForView);
3442 // / Add the alignment properties
3443 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3445 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3447 al.setProperty(ssp.getKey(), ssp.getValue());
3450 // ///////////////////////////////
3452 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3455 // load sequence features, database references and any associated PDB
3456 // structures for the alignment
3458 // prior to 2.10, this part would only be executed the first time a
3459 // sequence was encountered, but not afterwards.
3460 // now, for 2.10 projects, this is also done if the xml doc includes
3461 // dataset sequences not actually present in any particular view.
3463 for (int i = 0; i < vamsasSeqs.size(); i++)
3465 JSeq jseq = jseqs.get(i);
3466 if (jseq.getFeatures().size() > 0)
3468 List<Feature> features = jseq.getFeatures();
3469 for (int f = 0; f < features.size(); f++)
3471 Feature feat = features.get(f);
3472 SequenceFeature sf = new SequenceFeature(feat.getType(),
3473 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3474 safeFloat(feat.getScore()), feat.getFeatureGroup());
3475 sf.setStatus(feat.getStatus());
3478 * load any feature attributes - include map-valued attributes
3480 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3481 for (int od = 0; od < feat.getOtherData().size(); od++)
3483 OtherData keyValue = feat.getOtherData().get(od);
3484 String attributeName = keyValue.getKey();
3485 String attributeValue = keyValue.getValue();
3486 if (attributeName.startsWith("LINK"))
3488 sf.addLink(attributeValue);
3492 String subAttribute = keyValue.getKey2();
3493 if (subAttribute == null)
3495 // simple string-valued attribute
3496 sf.setValue(attributeName, attributeValue);
3500 // attribute 'key' has sub-attribute 'key2'
3501 if (!mapAttributes.containsKey(attributeName))
3503 mapAttributes.put(attributeName, new HashMap<>());
3505 mapAttributes.get(attributeName).put(subAttribute,
3510 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3513 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3516 // adds feature to datasequence's feature set (since Jalview 2.10)
3517 al.getSequenceAt(i).addSequenceFeature(sf);
3520 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3522 // adds dbrefs to datasequence's set (since Jalview 2.10)
3524 al.getSequenceAt(i).getDatasetSequence() == null
3525 ? al.getSequenceAt(i)
3526 : al.getSequenceAt(i).getDatasetSequence(),
3529 if (jseq.getPdbids().size() > 0)
3531 List<Pdbids> ids = jseq.getPdbids();
3532 for (int p = 0; p < ids.size(); p++)
3534 Pdbids pdbid = ids.get(p);
3535 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3536 entry.setId(pdbid.getId());
3537 if (pdbid.getType() != null)
3539 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3541 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3545 entry.setType(PDBEntry.Type.FILE);
3548 // jprovider is null when executing 'New View'
3549 if (pdbid.getFile() != null && jprovider != null)
3551 if (!pdbloaded.containsKey(pdbid.getFile()))
3553 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3558 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3562 if (pdbid.getPdbentryItem() != null)
3564 for (PdbentryItem item : pdbid.getPdbentryItem())
3566 for (Property pr : item.getProperty())
3568 entry.setProperty(pr.getName(), pr.getValue());
3573 for (Property prop : pdbid.getProperty())
3575 entry.setProperty(prop.getName(), prop.getValue());
3577 StructureSelectionManager
3578 .getStructureSelectionManager(Desktop.instance)
3579 .registerPDBEntry(entry);
3580 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3581 if (al.getSequenceAt(i).getDatasetSequence() != null)
3583 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3587 al.getSequenceAt(i).addPDBId(entry);
3592 } // end !multipleview
3594 // ///////////////////////////////
3595 // LOAD SEQUENCE MAPPINGS
3597 if (vamsasSet.getAlcodonFrame().size() > 0)
3599 // TODO Potentially this should only be done once for all views of an
3601 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3602 for (int i = 0; i < alc.size(); i++)
3604 AlignedCodonFrame cf = new AlignedCodonFrame();
3605 if (alc.get(i).getAlcodMap().size() > 0)
3607 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3608 for (int m = 0; m < maps.size(); m++)
3610 AlcodMap map = maps.get(m);
3611 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3613 jalview.datamodel.Mapping mapping = null;
3614 // attach to dna sequence reference.
3615 if (map.getMapping() != null)
3617 mapping = addMapping(map.getMapping());
3618 if (dnaseq != null && mapping.getTo() != null)
3620 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3626 newAlcodMapRef(map.getDnasq(), cf, mapping));
3630 al.addCodonFrame(cf);
3635 // ////////////////////////////////
3637 List<JvAnnotRow> autoAlan = new ArrayList<>();
3640 * store any annotations which forward reference a group's ID
3642 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3644 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3646 List<Annotation> an = vamsasSet.getAnnotation();
3648 for (int i = 0; i < an.size(); i++)
3650 Annotation annotation = an.get(i);
3653 * test if annotation is automatically calculated for this view only
3655 boolean autoForView = false;
3656 if (annotation.getLabel().equals("Quality")
3657 || annotation.getLabel().equals("Conservation")
3658 || annotation.getLabel().equals("Consensus"))
3660 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3662 // JAXB has no has() test; schema defaults value to false
3663 // if (!annotation.hasAutoCalculated())
3665 // annotation.setAutoCalculated(true);
3668 if (autoForView || annotation.isAutoCalculated())
3670 // remove ID - we don't recover annotation from other views for
3671 // view-specific annotation
3672 annotation.setId(null);
3675 // set visibility for other annotation in this view
3676 String annotationId = annotation.getId();
3677 if (annotationId != null && annotationIds.containsKey(annotationId))
3679 AlignmentAnnotation jda = annotationIds.get(annotationId);
3680 // in principle Visible should always be true for annotation displayed
3681 // in multiple views
3682 if (annotation.isVisible() != null)
3684 jda.visible = annotation.isVisible();
3687 al.addAnnotation(jda);
3691 // Construct new annotation from model.
3692 List<AnnotationElement> ae = annotation.getAnnotationElement();
3693 jalview.datamodel.Annotation[] anot = null;
3694 java.awt.Color firstColour = null;
3696 if (!annotation.isScoreOnly())
3698 anot = new jalview.datamodel.Annotation[al.getWidth()];
3699 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3701 AnnotationElement annElement = ae.get(aa);
3702 anpos = annElement.getPosition();
3704 if (anpos >= anot.length)
3709 float value = safeFloat(annElement.getValue());
3710 anot[anpos] = new jalview.datamodel.Annotation(
3711 annElement.getDisplayCharacter(),
3712 annElement.getDescription(),
3713 (annElement.getSecondaryStructure() == null
3714 || annElement.getSecondaryStructure()
3718 .getSecondaryStructure()
3721 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3722 if (firstColour == null)
3724 firstColour = anot[anpos].colour;
3728 jalview.datamodel.AlignmentAnnotation jaa = null;
3730 if (annotation.isGraph())
3732 float llim = 0, hlim = 0;
3733 // if (autoForView || an[i].isAutoCalculated()) {
3736 jaa = new jalview.datamodel.AlignmentAnnotation(
3737 annotation.getLabel(), annotation.getDescription(), anot,
3738 llim, hlim, safeInt(annotation.getGraphType()));
3740 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3741 jaa._linecolour = firstColour;
3742 if (annotation.getThresholdLine() != null)
3744 jaa.setThreshold(new jalview.datamodel.GraphLine(
3745 safeFloat(annotation.getThresholdLine().getValue()),
3746 annotation.getThresholdLine().getLabel(),
3747 new java.awt.Color(safeInt(
3748 annotation.getThresholdLine().getColour()))));
3750 if (autoForView || annotation.isAutoCalculated())
3752 // Hardwire the symbol display line to ensure that labels for
3753 // histograms are displayed
3759 jaa = new jalview.datamodel.AlignmentAnnotation(
3760 annotation.getLabel(), annotation.getDescription(), anot);
3761 jaa._linecolour = firstColour;
3763 // register new annotation
3764 if (annotation.getId() != null)
3766 annotationIds.put(annotation.getId(), jaa);
3767 jaa.annotationId = annotation.getId();
3769 // recover sequence association
3770 String sequenceRef = annotation.getSequenceRef();
3771 if (sequenceRef != null)
3773 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3774 SequenceI sequence = seqRefIds.get(sequenceRef);
3775 if (sequence == null)
3777 // in pre-2.9 projects sequence ref is to sequence name
3778 sequence = al.findName(sequenceRef);
3780 if (sequence != null)
3782 jaa.createSequenceMapping(sequence, 1, true);
3783 sequence.addAlignmentAnnotation(jaa);
3786 // and make a note of any group association
3787 if (annotation.getGroupRef() != null
3788 && annotation.getGroupRef().length() > 0)
3790 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3791 .get(annotation.getGroupRef());
3794 aal = new ArrayList<>();
3795 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3800 if (annotation.getScore() != null)
3802 jaa.setScore(annotation.getScore().doubleValue());
3804 if (annotation.isVisible() != null)
3806 jaa.visible = annotation.isVisible().booleanValue();
3809 if (annotation.isCentreColLabels() != null)
3811 jaa.centreColLabels = annotation.isCentreColLabels()
3815 if (annotation.isScaleColLabels() != null)
3817 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3819 if (annotation.isAutoCalculated())
3821 // newer files have an 'autoCalculated' flag and store calculation
3822 // state in viewport properties
3823 jaa.autoCalculated = true; // means annotation will be marked for
3824 // update at end of load.
3826 if (annotation.getGraphHeight() != null)
3828 jaa.graphHeight = annotation.getGraphHeight().intValue();
3830 jaa.belowAlignment = annotation.isBelowAlignment();
3831 jaa.setCalcId(annotation.getCalcId());
3832 if (annotation.getProperty().size() > 0)
3834 for (Annotation.Property prop : annotation
3837 jaa.setProperty(prop.getName(), prop.getValue());
3840 if (jaa.autoCalculated)
3842 autoAlan.add(new JvAnnotRow(i, jaa));
3845 // if (!autoForView)
3847 // add autocalculated group annotation and any user created annotation
3849 al.addAnnotation(jaa);
3853 // ///////////////////////
3855 // Create alignment markup and styles for this view
3856 if (jalviewModel.getJGroup().size() > 0)
3858 List<JGroup> groups = jalviewModel.getJGroup();
3859 boolean addAnnotSchemeGroup = false;
3860 for (int i = 0; i < groups.size(); i++)
3862 JGroup jGroup = groups.get(i);
3863 ColourSchemeI cs = null;
3864 if (jGroup.getColour() != null)
3866 if (jGroup.getColour().startsWith("ucs"))
3868 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3870 else if (jGroup.getColour().equals("AnnotationColourGradient")
3871 && jGroup.getAnnotationColours() != null)
3873 addAnnotSchemeGroup = true;
3877 cs = ColourSchemeProperty.getColourScheme(null, al,
3878 jGroup.getColour());
3881 int pidThreshold = safeInt(jGroup.getPidThreshold());
3883 Vector<SequenceI> seqs = new Vector<>();
3885 for (int s = 0; s < jGroup.getSeq().size(); s++)
3887 String seqId = jGroup.getSeq().get(s);
3888 SequenceI ts = seqRefIds.get(seqId);
3892 seqs.addElement(ts);
3896 if (seqs.size() < 1)
3901 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3902 safeBoolean(jGroup.isDisplayBoxes()),
3903 safeBoolean(jGroup.isDisplayText()),
3904 safeBoolean(jGroup.isColourText()),
3905 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3906 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3907 sg.getGroupColourScheme()
3908 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3909 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3911 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3912 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3913 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3914 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3915 // attributes with a default in the schema are never null
3916 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3917 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3918 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3919 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3920 if (jGroup.getConsThreshold() != null
3921 && jGroup.getConsThreshold().intValue() != 0)
3923 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3926 c.verdict(false, 25);
3927 sg.cs.setConservation(c);
3930 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3932 // re-instate unique group/annotation row reference
3933 List<AlignmentAnnotation> jaal = groupAnnotRefs
3934 .get(jGroup.getId());
3937 for (AlignmentAnnotation jaa : jaal)
3940 if (jaa.autoCalculated)
3942 // match up and try to set group autocalc alignment row for this
3944 if (jaa.label.startsWith("Consensus for "))
3946 sg.setConsensus(jaa);
3948 // match up and try to set group autocalc alignment row for this
3950 if (jaa.label.startsWith("Conservation for "))
3952 sg.setConservationRow(jaa);
3959 if (addAnnotSchemeGroup)
3961 // reconstruct the annotation colourscheme
3962 sg.setColourScheme(constructAnnotationColour(
3963 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3969 // only dataset in this model, so just return.
3972 // ///////////////////////////////
3975 AlignFrame af = null;
3976 AlignViewport av = null;
3977 // now check to see if we really need to create a new viewport.
3978 if (multipleView && viewportsAdded.size() == 0)
3980 // We recovered an alignment for which a viewport already exists.
3981 // TODO: fix up any settings necessary for overlaying stored state onto
3982 // state recovered from another document. (may not be necessary).
3983 // we may need a binding from a viewport in memory to one recovered from
3985 // and then recover its containing af to allow the settings to be applied.
3986 // TODO: fix for vamsas demo
3988 "About to recover a viewport for existing alignment: Sequence set ID is "
3990 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3991 if (seqsetobj != null)
3993 if (seqsetobj instanceof String)
3995 uniqueSeqSetId = (String) seqsetobj;
3997 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4003 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4009 * indicate that annotation colours are applied across all groups (pre
4010 * Jalview 2.8.1 behaviour)
4012 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4013 jalviewModel.getVersion());
4015 AlignmentPanel ap = null;
4016 boolean isnewview = true;
4019 // Check to see if this alignment already has a view id == viewId
4020 jalview.gui.AlignmentPanel views[] = Desktop
4021 .getAlignmentPanels(uniqueSeqSetId);
4022 if (views != null && views.length > 0)
4024 for (int v = 0; v < views.length; v++)
4026 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4028 // recover the existing alignpanel, alignframe, viewport
4029 af = views[v].alignFrame;
4032 // TODO: could even skip resetting view settings if we don't want to
4033 // change the local settings from other jalview processes
4042 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4043 uniqueSeqSetId, viewId, autoAlan);
4044 av = af.getViewport();
4049 * Load any trees, PDB structures and viewers
4051 * Not done if flag is false (when this method is used for New View)
4053 if (loadTreesAndStructures)
4055 loadTrees(jalviewModel, view, af, av, ap);
4056 loadPCAViewers(jalviewModel, ap);
4057 loadPDBStructures(jprovider, jseqs, af, ap);
4058 loadRnaViewers(jprovider, jseqs, ap);
4060 // and finally return.
4065 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4066 * panel is restored from separate jar entries, two (gapped and trimmed) per
4067 * sequence and secondary structure.
4069 * Currently each viewer shows just one sequence and structure (gapped and
4070 * trimmed), however this method is designed to support multiple sequences or
4071 * structures in viewers if wanted in future.
4077 private void loadRnaViewers(jarInputStreamProvider jprovider,
4078 List<JSeq> jseqs, AlignmentPanel ap)
4081 * scan the sequences for references to viewers; create each one the first
4082 * time it is referenced, add Rna models to existing viewers
4084 for (JSeq jseq : jseqs)
4086 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4088 RnaViewer viewer = jseq.getRnaViewer().get(i);
4089 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4092 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4094 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4095 SequenceI seq = seqRefIds.get(jseq.getId());
4096 AlignmentAnnotation ann = this.annotationIds
4097 .get(ss.getAnnotationId());
4100 * add the structure to the Varna display (with session state copied
4101 * from the jar to a temporary file)
4103 boolean gapped = safeBoolean(ss.isGapped());
4104 String rnaTitle = ss.getTitle();
4105 String sessionState = ss.getViewerState();
4106 String tempStateFile = copyJarEntry(jprovider, sessionState,
4108 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4109 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4111 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4117 * Locate and return an already instantiated matching AppVarna, or create one
4121 * @param viewIdSuffix
4125 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4126 String viewIdSuffix, AlignmentPanel ap)
4129 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4130 * if load is repeated
4132 String postLoadId = viewer.getViewId() + viewIdSuffix;
4133 for (JInternalFrame frame : getAllFrames())
4135 if (frame instanceof AppVarna)
4137 AppVarna varna = (AppVarna) frame;
4138 if (postLoadId.equals(varna.getViewId()))
4140 // this viewer is already instantiated
4141 // could in future here add ap as another 'parent' of the
4142 // AppVarna window; currently just 1-to-many
4149 * viewer not found - make it
4151 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4152 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4153 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4154 safeInt(viewer.getDividerLocation()));
4155 AppVarna varna = new AppVarna(model, ap);
4161 * Load any saved trees
4169 protected void loadTrees(JalviewModel jm, Viewport view,
4170 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4172 // TODO result of automated refactoring - are all these parameters needed?
4175 for (int t = 0; t < jm.getTree().size(); t++)
4178 Tree tree = jm.getTree().get(t);
4180 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4183 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4184 tree.getTitle(), safeInt(tree.getWidth()),
4185 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4186 safeInt(tree.getYpos()));
4187 if (tree.getId() != null)
4189 // perhaps bind the tree id to something ?
4194 // update local tree attributes ?
4195 // TODO: should check if tp has been manipulated by user - if so its
4196 // settings shouldn't be modified
4197 tp.setTitle(tree.getTitle());
4198 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4199 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4200 safeInt(tree.getHeight())));
4201 tp.setViewport(av); // af.viewport;
4202 // TODO: verify 'associate with all views' works still
4203 tp.getTreeCanvas().setViewport(av); // af.viewport;
4204 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4206 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4209 warn("There was a problem recovering stored Newick tree: \n"
4210 + tree.getNewick());
4214 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4215 tp.fitToWindow_actionPerformed(null);
4217 if (tree.getFontName() != null)
4220 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4221 safeInt(tree.getFontSize())));
4226 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4227 safeInt(view.getFontSize())));
4230 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4231 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4232 tp.showDistances(safeBoolean(tree.isShowDistances()));
4234 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4236 if (safeBoolean(tree.isCurrentTree()))
4238 af.getViewport().setCurrentTree(tp.getTree());
4242 } catch (Exception ex)
4244 ex.printStackTrace();
4249 * Load and link any saved structure viewers.
4256 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4257 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4260 * Run through all PDB ids on the alignment, and collect mappings between
4261 * distinct view ids and all sequences referring to that view.
4263 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4265 for (int i = 0; i < jseqs.size(); i++)
4267 JSeq jseq = jseqs.get(i);
4268 if (jseq.getPdbids().size() > 0)
4270 List<Pdbids> ids = jseq.getPdbids();
4271 for (int p = 0; p < ids.size(); p++)
4273 Pdbids pdbid = ids.get(p);
4274 final int structureStateCount = pdbid.getStructureState().size();
4275 for (int s = 0; s < structureStateCount; s++)
4277 // check to see if we haven't already created this structure view
4278 final StructureState structureState = pdbid
4279 .getStructureState().get(s);
4280 String sviewid = (structureState.getViewId() == null) ? null
4281 : structureState.getViewId() + uniqueSetSuffix;
4282 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4283 // Originally : pdbid.getFile()
4284 // : TODO: verify external PDB file recovery still works in normal
4285 // jalview project load
4287 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4288 jpdb.setId(pdbid.getId());
4290 int x = safeInt(structureState.getXpos());
4291 int y = safeInt(structureState.getYpos());
4292 int width = safeInt(structureState.getWidth());
4293 int height = safeInt(structureState.getHeight());
4295 // Probably don't need to do this anymore...
4296 // Desktop.desktop.getComponentAt(x, y);
4297 // TODO: NOW: check that this recovers the PDB file correctly.
4298 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4300 jalview.datamodel.SequenceI seq = seqRefIds
4301 .get(jseq.getId() + "");
4302 if (sviewid == null)
4304 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4307 if (!structureViewers.containsKey(sviewid))
4309 structureViewers.put(sviewid,
4310 new StructureViewerModel(x, y, width, height, false,
4311 false, true, structureState.getViewId(),
4312 structureState.getType()));
4313 // Legacy pre-2.7 conversion JAL-823 :
4314 // do not assume any view has to be linked for colour by
4318 // assemble String[] { pdb files }, String[] { id for each
4319 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4320 // seqs_file 2}, boolean[] {
4321 // linkAlignPanel,superposeWithAlignpanel}} from hash
4322 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4323 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4324 || structureState.isAlignwithAlignPanel());
4327 * Default colour by linked panel to false if not specified (e.g.
4328 * for pre-2.7 projects)
4330 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4331 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4332 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4335 * Default colour by viewer to true if not specified (e.g. for
4338 boolean colourByViewer = jmoldat.isColourByViewer();
4339 colourByViewer &= structureState.isColourByJmol();
4340 jmoldat.setColourByViewer(colourByViewer);
4342 if (jmoldat.getStateData().length() < structureState
4343 .getValue()/*Content()*/.length())
4345 jmoldat.setStateData(structureState.getValue());// Content());
4347 if (pdbid.getFile() != null)
4349 File mapkey = new File(pdbid.getFile());
4350 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4351 if (seqstrmaps == null)
4353 jmoldat.getFileData().put(mapkey,
4354 seqstrmaps = jmoldat.new StructureData(pdbFile,
4357 if (!seqstrmaps.getSeqList().contains(seq))
4359 seqstrmaps.getSeqList().add(seq);
4365 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");
4372 // Instantiate the associated structure views
4373 for (Entry<String, StructureViewerModel> entry : structureViewers
4378 createOrLinkStructureViewer(entry, af, ap, jprovider);
4379 } catch (Exception e)
4382 "Error loading structure viewer: " + e.getMessage());
4383 // failed - try the next one
4395 protected void createOrLinkStructureViewer(
4396 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4397 AlignmentPanel ap, jarInputStreamProvider jprovider)
4399 final StructureViewerModel stateData = viewerData.getValue();
4402 * Search for any viewer windows already open from other alignment views
4403 * that exactly match the stored structure state
4405 StructureViewerBase comp = findMatchingViewer(viewerData);
4409 linkStructureViewer(ap, comp, stateData);
4414 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4415 * "viewer_"+stateData.viewId
4417 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4419 createChimeraViewer(viewerData, af, jprovider);
4424 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4426 createJmolViewer(viewerData, af, jprovider);
4431 * Create a new Chimera viewer.
4437 protected void createChimeraViewer(
4438 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4439 jarInputStreamProvider jprovider)
4441 StructureViewerModel data = viewerData.getValue();
4442 String chimeraSessionFile = data.getStateData();
4445 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4447 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4448 * 'uniquified' sviewid used to reconstruct the viewer here
4450 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4451 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4454 Set<Entry<File, StructureData>> fileData = data.getFileData()
4456 List<PDBEntry> pdbs = new ArrayList<>();
4457 List<SequenceI[]> allseqs = new ArrayList<>();
4458 for (Entry<File, StructureData> pdb : fileData)
4460 String filePath = pdb.getValue().getFilePath();
4461 String pdbId = pdb.getValue().getPdbId();
4462 // pdbs.add(new PDBEntry(filePath, pdbId));
4463 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4464 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4465 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4469 boolean colourByChimera = data.isColourByViewer();
4470 boolean colourBySequence = data.isColourWithAlignPanel();
4472 // TODO use StructureViewer as a factory here, see JAL-1761
4473 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4474 final SequenceI[][] seqsArray = allseqs
4475 .toArray(new SequenceI[allseqs.size()][]);
4476 String newViewId = viewerData.getKey();
4478 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4479 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4480 colourBySequence, newViewId);
4481 cvf.setSize(data.getWidth(), data.getHeight());
4482 cvf.setLocation(data.getX(), data.getY());
4486 * Create a new Jmol window. First parse the Jmol state to translate filenames
4487 * loaded into the view, and record the order in which files are shown in the
4488 * Jmol view, so we can add the sequence mappings in same order.
4494 protected void createJmolViewer(
4495 final Entry<String, StructureViewerModel> viewerData,
4496 AlignFrame af, jarInputStreamProvider jprovider)
4498 final StructureViewerModel svattrib = viewerData.getValue();
4499 String state = svattrib.getStateData();
4502 * Pre-2.9: state element value is the Jmol state string
4504 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4507 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4509 state = readJarEntry(jprovider,
4510 getViewerJarEntryName(svattrib.getViewId()));
4513 List<String> pdbfilenames = new ArrayList<>();
4514 List<SequenceI[]> seqmaps = new ArrayList<>();
4515 List<String> pdbids = new ArrayList<>();
4516 StringBuilder newFileLoc = new StringBuilder(64);
4517 int cp = 0, ncp, ecp;
4518 Map<File, StructureData> oldFiles = svattrib.getFileData();
4519 while ((ncp = state.indexOf("load ", cp)) > -1)
4523 // look for next filename in load statement
4524 newFileLoc.append(state.substring(cp,
4525 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4526 String oldfilenam = state.substring(ncp,
4527 ecp = state.indexOf("\"", ncp));
4528 // recover the new mapping data for this old filename
4529 // have to normalize filename - since Jmol and jalview do
4531 // translation differently.
4532 StructureData filedat = oldFiles.get(new File(oldfilenam));
4533 if (filedat == null)
4535 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4536 filedat = oldFiles.get(new File(reformatedOldFilename));
4538 newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath()));
4539 pdbfilenames.add(filedat.getFilePath());
4540 pdbids.add(filedat.getPdbId());
4541 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4542 newFileLoc.append("\"");
4543 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4544 // look for next file statement.
4545 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4549 // just append rest of state
4550 newFileLoc.append(state.substring(cp));
4554 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4555 newFileLoc = new StringBuilder(state);
4556 newFileLoc.append("; load append ");
4557 for (File id : oldFiles.keySet())
4559 // add this and any other pdb files that should be present in
4561 StructureData filedat = oldFiles.get(id);
4562 newFileLoc.append(filedat.getFilePath());
4563 pdbfilenames.add(filedat.getFilePath());
4564 pdbids.add(filedat.getPdbId());
4565 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4566 newFileLoc.append(" \"");
4567 newFileLoc.append(filedat.getFilePath());
4568 newFileLoc.append("\"");
4571 newFileLoc.append(";");
4574 if (newFileLoc.length() == 0)
4578 int histbug = newFileLoc.indexOf("history = ");
4582 * change "history = [true|false];" to "history = [1|0];"
4585 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4586 String val = (diff == -1) ? null
4587 : newFileLoc.substring(histbug, diff);
4588 if (val != null && val.length() >= 4)
4590 if (val.contains("e")) // eh? what can it be?
4592 if (val.trim().equals("true"))
4600 newFileLoc.replace(histbug, diff, val);
4605 final String[] pdbf = pdbfilenames
4606 .toArray(new String[pdbfilenames.size()]);
4607 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4608 final SequenceI[][] sq = seqmaps
4609 .toArray(new SequenceI[seqmaps.size()][]);
4610 final String fileloc = newFileLoc.toString();
4611 final String sviewid = viewerData.getKey();
4612 final AlignFrame alf = af;
4613 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4614 svattrib.getWidth(), svattrib.getHeight());
4617 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4622 JalviewStructureDisplayI sview = null;
4625 sview = new StructureViewer(
4626 alf.alignPanel.getStructureSelectionManager())
4627 .createView(StructureViewer.ViewerType.JMOL,
4628 pdbf, id, sq, alf.alignPanel, svattrib,
4629 fileloc, rect, sviewid);
4630 addNewStructureViewer(sview);
4631 } catch (OutOfMemoryError ex)
4633 new OOMWarning("restoring structure view for PDB id " + id,
4634 (OutOfMemoryError) ex.getCause());
4635 if (sview != null && sview.isVisible())
4637 sview.closeViewer(false);
4638 sview.setVisible(false);
4644 } catch (InvocationTargetException ex)
4646 warn("Unexpected error when opening Jmol view.", ex);
4648 } catch (InterruptedException e)
4650 // e.printStackTrace();
4656 * Generates a name for the entry in the project jar file to hold state
4657 * information for a structure viewer
4662 protected String getViewerJarEntryName(String viewId)
4664 return VIEWER_PREFIX + viewId;
4668 * Returns any open frame that matches given structure viewer data. The match
4669 * is based on the unique viewId, or (for older project versions) the frame's
4675 protected StructureViewerBase findMatchingViewer(
4676 Entry<String, StructureViewerModel> viewerData)
4678 final String sviewid = viewerData.getKey();
4679 final StructureViewerModel svattrib = viewerData.getValue();
4680 StructureViewerBase comp = null;
4681 JInternalFrame[] frames = getAllFrames();
4682 for (JInternalFrame frame : frames)
4684 if (frame instanceof StructureViewerBase)
4687 * Post jalview 2.4 schema includes structure view id
4689 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4692 comp = (StructureViewerBase) frame;
4693 break; // break added in 2.9
4696 * Otherwise test for matching position and size of viewer frame
4698 else if (frame.getX() == svattrib.getX()
4699 && frame.getY() == svattrib.getY()
4700 && frame.getHeight() == svattrib.getHeight()
4701 && frame.getWidth() == svattrib.getWidth())
4703 comp = (StructureViewerBase) frame;
4704 // no break in faint hope of an exact match on viewId
4712 * Link an AlignmentPanel to an existing structure viewer.
4717 * @param useinViewerSuperpos
4718 * @param usetoColourbyseq
4719 * @param viewerColouring
4721 protected void linkStructureViewer(AlignmentPanel ap,
4722 StructureViewerBase viewer, StructureViewerModel stateData)
4724 // NOTE: if the jalview project is part of a shared session then
4725 // view synchronization should/could be done here.
4727 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4728 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4729 final boolean viewerColouring = stateData.isColourByViewer();
4730 Map<File, StructureData> oldFiles = stateData.getFileData();
4733 * Add mapping for sequences in this view to an already open viewer
4735 final AAStructureBindingModel binding = viewer.getBinding();
4736 for (File id : oldFiles.keySet())
4738 // add this and any other pdb files that should be present in the
4740 StructureData filedat = oldFiles.get(id);
4741 String pdbFile = filedat.getFilePath();
4742 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4743 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4745 binding.addSequenceForStructFile(pdbFile, seq);
4747 // and add the AlignmentPanel's reference to the view panel
4748 viewer.addAlignmentPanel(ap);
4749 if (useinViewerSuperpos)
4751 viewer.useAlignmentPanelForSuperposition(ap);
4755 viewer.excludeAlignmentPanelForSuperposition(ap);
4757 if (usetoColourbyseq)
4759 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4763 viewer.excludeAlignmentPanelForColourbyseq(ap);
4768 * Get all frames within the Desktop.
4772 protected JInternalFrame[] getAllFrames()
4774 JInternalFrame[] frames = null;
4775 // TODO is this necessary - is it safe - risk of hanging?
4780 frames = Desktop.desktop.getAllFrames();
4781 } catch (ArrayIndexOutOfBoundsException e)
4783 // occasional No such child exceptions are thrown here...
4787 } catch (InterruptedException f)
4791 } while (frames == null);
4796 * Answers true if 'version' is equal to or later than 'supported', where each
4797 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4798 * changes. Development and test values for 'version' are leniently treated
4802 * - minimum version we are comparing against
4804 * - version of data being processsed
4807 public static boolean isVersionStringLaterThan(String supported,
4810 if (supported == null || version == null
4811 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4812 || version.equalsIgnoreCase("Test")
4813 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4815 System.err.println("Assuming project file with "
4816 + (version == null ? "null" : version)
4817 + " is compatible with Jalview version " + supported);
4822 return StringUtils.compareVersions(version, supported, "b") >= 0;
4826 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4828 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4830 if (newStructureViewers != null)
4832 sview.getBinding().setFinishedLoadingFromArchive(false);
4833 newStructureViewers.add(sview);
4837 protected void setLoadingFinishedForNewStructureViewers()
4839 if (newStructureViewers != null)
4841 for (JalviewStructureDisplayI sview : newStructureViewers)
4843 sview.getBinding().setFinishedLoadingFromArchive(true);
4845 newStructureViewers.clear();
4846 newStructureViewers = null;
4850 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4851 List<SequenceI> hiddenSeqs, AlignmentI al,
4852 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4853 String viewId, List<JvAnnotRow> autoAlan)
4855 AlignFrame af = null;
4856 af = new AlignFrame(al, safeInt(view.getWidth()),
4857 safeInt(view.getHeight()), uniqueSeqSetId, viewId);
4859 af.setFileName(file, FileFormat.Jalview);
4861 final AlignViewport viewport = af.getViewport();
4862 for (int i = 0; i < JSEQ.size(); i++)
4864 int colour = safeInt(JSEQ.get(i).getColour());
4865 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4871 viewport.setColourByReferenceSeq(true);
4872 viewport.setDisplayReferenceSeq(true);
4875 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4877 if (view.getSequenceSetId() != null)
4879 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4881 viewport.setSequenceSetId(uniqueSeqSetId);
4884 // propagate shared settings to this new view
4885 viewport.setHistoryList(av.getHistoryList());
4886 viewport.setRedoList(av.getRedoList());
4890 viewportsAdded.put(uniqueSeqSetId, viewport);
4892 // TODO: check if this method can be called repeatedly without
4893 // side-effects if alignpanel already registered.
4894 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4896 // apply Hidden regions to view.
4897 if (hiddenSeqs != null)
4899 for (int s = 0; s < JSEQ.size(); s++)
4901 SequenceGroup hidden = new SequenceGroup();
4902 boolean isRepresentative = false;
4903 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4905 isRepresentative = true;
4906 SequenceI sequenceToHide = al
4907 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4908 hidden.addSequence(sequenceToHide, false);
4909 // remove from hiddenSeqs list so we don't try to hide it twice
4910 hiddenSeqs.remove(sequenceToHide);
4912 if (isRepresentative)
4914 SequenceI representativeSequence = al.getSequenceAt(s);
4915 hidden.addSequence(representativeSequence, false);
4916 viewport.hideRepSequences(representativeSequence, hidden);
4920 SequenceI[] hseqs = hiddenSeqs
4921 .toArray(new SequenceI[hiddenSeqs.size()]);
4922 viewport.hideSequence(hseqs);
4925 // recover view properties and display parameters
4927 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4928 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4929 final int pidThreshold = safeInt(view.getPidThreshold());
4930 viewport.setThreshold(pidThreshold);
4932 viewport.setColourText(safeBoolean(view.isShowColourText()));
4935 .setConservationSelected(
4936 safeBoolean(view.isConservationSelected()));
4937 viewport.setIncrement(safeInt(view.getConsThreshold()));
4938 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4939 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4940 viewport.setFont(new Font(view.getFontName(),
4941 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4943 ViewStyleI vs = viewport.getViewStyle();
4944 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4945 viewport.setViewStyle(vs);
4946 // TODO: allow custom charWidth/Heights to be restored by updating them
4947 // after setting font - which means set above to false
4948 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4949 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4950 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4952 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4954 viewport.setShowText(safeBoolean(view.isShowText()));
4956 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4957 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4958 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4959 viewport.setShowUnconserved(view.isShowUnconserved());
4960 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4962 if (view.getViewName() != null)
4964 viewport.setViewName(view.getViewName());
4965 af.setInitialTabVisible();
4967 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4968 safeInt(view.getWidth()), safeInt(view.getHeight()));
4969 // startSeq set in af.alignPanel.updateLayout below
4970 af.alignPanel.updateLayout();
4971 ColourSchemeI cs = null;
4972 // apply colourschemes
4973 if (view.getBgColour() != null)
4975 if (view.getBgColour().startsWith("ucs"))
4977 cs = getUserColourScheme(jm, view.getBgColour());
4979 else if (view.getBgColour().startsWith("Annotation"))
4981 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4982 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4989 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4990 view.getBgColour());
4995 * turn off 'alignment colour applies to all groups'
4996 * while restoring global colour scheme
4998 viewport.setColourAppliesToAllGroups(false);
4999 viewport.setGlobalColourScheme(cs);
5000 viewport.getResidueShading().setThreshold(pidThreshold,
5001 view.isIgnoreGapsinConsensus());
5002 viewport.getResidueShading()
5003 .setConsensus(viewport.getSequenceConsensusHash());
5004 if (safeBoolean(view.isConservationSelected()) && cs != null)
5006 viewport.getResidueShading()
5007 .setConservationInc(safeInt(view.getConsThreshold()));
5009 af.changeColour(cs);
5010 viewport.setColourAppliesToAllGroups(true);
5013 .setShowSequenceFeatures(
5014 safeBoolean(view.isShowSequenceFeatures()));
5016 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5017 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5018 viewport.setFollowHighlight(view.isFollowHighlight());
5019 viewport.followSelection = view.isFollowSelection();
5020 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5021 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5022 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5023 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5024 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5025 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5026 viewport.setShowGroupConservation(view.isShowGroupConservation());
5027 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5028 viewport.setShowComplementFeaturesOnTop(
5029 view.isShowComplementFeaturesOnTop());
5031 // recover feature settings
5032 if (jm.getFeatureSettings() != null)
5034 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5035 .getFeatureRenderer();
5036 FeaturesDisplayed fdi;
5037 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5038 String[] renderOrder = new String[jm.getFeatureSettings()
5039 .getSetting().size()];
5040 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5041 Map<String, Float> featureOrder = new Hashtable<>();
5043 for (int fs = 0; fs < jm.getFeatureSettings()
5044 .getSetting().size(); fs++)
5046 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5047 String featureType = setting.getType();
5050 * restore feature filters (if any)
5052 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5054 if (filters != null)
5056 FeatureMatcherSetI filter = Jalview2XML
5057 .parseFilter(featureType, filters);
5058 if (!filter.isEmpty())
5060 fr.setFeatureFilter(featureType, filter);
5065 * restore feature colour scheme
5067 Color maxColour = new Color(setting.getColour());
5068 if (setting.getMincolour() != null)
5071 * minColour is always set unless a simple colour
5072 * (including for colour by label though it doesn't use it)
5074 Color minColour = new Color(setting.getMincolour().intValue());
5075 Color noValueColour = minColour;
5076 NoValueColour noColour = setting.getNoValueColour();
5077 if (noColour == NoValueColour.NONE)
5079 noValueColour = null;
5081 else if (noColour == NoValueColour.MAX)
5083 noValueColour = maxColour;
5085 float min = safeFloat(safeFloat(setting.getMin()));
5086 float max = setting.getMax() == null ? 1f
5087 : setting.getMax().floatValue();
5088 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5090 noValueColour, min, max);
5091 if (setting.getAttributeName().size() > 0)
5093 gc.setAttributeName(setting.getAttributeName().toArray(
5094 new String[setting.getAttributeName().size()]));
5096 if (setting.getThreshold() != null)
5098 gc.setThreshold(setting.getThreshold().floatValue());
5099 int threshstate = safeInt(setting.getThreshstate());
5100 // -1 = None, 0 = Below, 1 = Above threshold
5101 if (threshstate == 0)
5103 gc.setBelowThreshold(true);
5105 else if (threshstate == 1)
5107 gc.setAboveThreshold(true);
5110 gc.setAutoScaled(true); // default
5111 if (setting.isAutoScale() != null)
5113 gc.setAutoScaled(setting.isAutoScale());
5115 if (setting.isColourByLabel() != null)
5117 gc.setColourByLabel(setting.isColourByLabel());
5119 // and put in the feature colour table.
5120 featureColours.put(featureType, gc);
5124 featureColours.put(featureType,
5125 new FeatureColour(maxColour));
5127 renderOrder[fs] = featureType;
5128 if (setting.getOrder() != null)
5130 featureOrder.put(featureType, setting.getOrder().floatValue());
5134 featureOrder.put(featureType, Float.valueOf(
5135 fs / jm.getFeatureSettings().getSetting().size()));
5137 if (safeBoolean(setting.isDisplay()))
5139 fdi.setVisible(featureType);
5142 Map<String, Boolean> fgtable = new Hashtable<>();
5143 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5145 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5146 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5148 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5149 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5150 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5151 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5152 fgtable, featureColours, 1.0f, featureOrder);
5153 fr.transferSettings(frs);
5156 if (view.getHiddenColumns().size() > 0)
5158 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5160 final HiddenColumns hc = view.getHiddenColumns().get(c);
5161 viewport.hideColumns(safeInt(hc.getStart()),
5162 safeInt(hc.getEnd()) /* +1 */);
5165 if (view.getCalcIdParam() != null)
5167 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5169 if (calcIdParam != null)
5171 if (recoverCalcIdParam(calcIdParam, viewport))
5176 warn("Couldn't recover parameters for "
5177 + calcIdParam.getCalcId());
5182 af.setMenusFromViewport(viewport);
5183 af.setTitle(view.getTitle());
5184 // TODO: we don't need to do this if the viewport is aready visible.
5186 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5187 * has a 'cdna/protein complement' view, in which case save it in order to
5188 * populate a SplitFrame once all views have been read in.
5190 String complementaryViewId = view.getComplementId();
5191 if (complementaryViewId == null)
5193 Desktop.addInternalFrame(af, view.getTitle(),
5194 safeInt(view.getWidth()), safeInt(view.getHeight()));
5195 // recompute any autoannotation
5196 af.alignPanel.updateAnnotation(false, true);
5197 reorderAutoannotation(af, al, autoAlan);
5198 af.alignPanel.alignmentChanged();
5202 splitFrameCandidates.put(view, af);
5208 * Reads saved data to restore Colour by Annotation settings
5210 * @param viewAnnColour
5214 * @param checkGroupAnnColour
5217 private ColourSchemeI constructAnnotationColour(
5218 AnnotationColourScheme viewAnnColour, AlignFrame af,
5219 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5221 boolean propagateAnnColour = false;
5222 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5224 if (checkGroupAnnColour && al.getGroups() != null
5225 && al.getGroups().size() > 0)
5227 // pre 2.8.1 behaviour
5228 // check to see if we should transfer annotation colours
5229 propagateAnnColour = true;
5230 for (SequenceGroup sg : al.getGroups())
5232 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5234 propagateAnnColour = false;
5240 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5242 String annotationId = viewAnnColour.getAnnotation();
5243 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5246 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5248 if (matchedAnnotation == null
5249 && annAlignment.getAlignmentAnnotation() != null)
5251 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5254 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5256 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5261 if (matchedAnnotation == null)
5263 System.err.println("Failed to match annotation colour scheme for "
5267 if (matchedAnnotation.getThreshold() == null)
5269 matchedAnnotation.setThreshold(
5270 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5271 "Threshold", Color.black));
5274 AnnotationColourGradient cs = null;
5275 if (viewAnnColour.getColourScheme().equals("None"))
5277 cs = new AnnotationColourGradient(matchedAnnotation,
5278 new Color(safeInt(viewAnnColour.getMinColour())),
5279 new Color(safeInt(viewAnnColour.getMaxColour())),
5280 safeInt(viewAnnColour.getAboveThreshold()));
5282 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5284 cs = new AnnotationColourGradient(matchedAnnotation,
5285 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5286 safeInt(viewAnnColour.getAboveThreshold()));
5290 cs = new AnnotationColourGradient(matchedAnnotation,
5291 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5292 viewAnnColour.getColourScheme()),
5293 safeInt(viewAnnColour.getAboveThreshold()));
5296 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5297 boolean useOriginalColours = safeBoolean(
5298 viewAnnColour.isPredefinedColours());
5299 cs.setSeqAssociated(perSequenceOnly);
5300 cs.setPredefinedColours(useOriginalColours);
5302 if (propagateAnnColour && al.getGroups() != null)
5304 // Also use these settings for all the groups
5305 for (int g = 0; g < al.getGroups().size(); g++)
5307 SequenceGroup sg = al.getGroups().get(g);
5308 if (sg.getGroupColourScheme() == null)
5313 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5314 matchedAnnotation, sg.getColourScheme(),
5315 safeInt(viewAnnColour.getAboveThreshold()));
5316 sg.setColourScheme(groupScheme);
5317 groupScheme.setSeqAssociated(perSequenceOnly);
5318 groupScheme.setPredefinedColours(useOriginalColours);
5324 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5325 List<JvAnnotRow> autoAlan)
5327 // copy over visualization settings for autocalculated annotation in the
5329 if (al.getAlignmentAnnotation() != null)
5332 * Kludge for magic autoannotation names (see JAL-811)
5334 String[] magicNames = new String[] { "Consensus", "Quality",
5336 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5337 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5338 for (String nm : magicNames)
5340 visan.put(nm, nullAnnot);
5342 for (JvAnnotRow auan : autoAlan)
5344 visan.put(auan.template.label
5345 + (auan.template.getCalcId() == null ? ""
5346 : "\t" + auan.template.getCalcId()),
5349 int hSize = al.getAlignmentAnnotation().length;
5350 List<JvAnnotRow> reorder = new ArrayList<>();
5351 // work through any autoCalculated annotation already on the view
5352 // removing it if it should be placed in a different location on the
5353 // annotation panel.
5354 List<String> remains = new ArrayList<>(visan.keySet());
5355 for (int h = 0; h < hSize; h++)
5357 jalview.datamodel.AlignmentAnnotation jalan = al
5358 .getAlignmentAnnotation()[h];
5359 if (jalan.autoCalculated)
5362 JvAnnotRow valan = visan.get(k = jalan.label);
5363 if (jalan.getCalcId() != null)
5365 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5370 // delete the auto calculated row from the alignment
5371 al.deleteAnnotation(jalan, false);
5375 if (valan != nullAnnot)
5377 if (jalan != valan.template)
5379 // newly created autoannotation row instance
5380 // so keep a reference to the visible annotation row
5381 // and copy over all relevant attributes
5382 if (valan.template.graphHeight >= 0)
5385 jalan.graphHeight = valan.template.graphHeight;
5387 jalan.visible = valan.template.visible;
5389 reorder.add(new JvAnnotRow(valan.order, jalan));
5394 // Add any (possibly stale) autocalculated rows that were not appended to
5395 // the view during construction
5396 for (String other : remains)
5398 JvAnnotRow othera = visan.get(other);
5399 if (othera != nullAnnot && othera.template.getCalcId() != null
5400 && othera.template.getCalcId().length() > 0)
5402 reorder.add(othera);
5405 // now put the automatic annotation in its correct place
5406 int s = 0, srt[] = new int[reorder.size()];
5407 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5408 for (JvAnnotRow jvar : reorder)
5411 srt[s++] = jvar.order;
5414 jalview.util.QuickSort.sort(srt, rws);
5415 // and re-insert the annotation at its correct position
5416 for (JvAnnotRow jvar : rws)
5418 al.addAnnotation(jvar.template, jvar.order);
5420 af.alignPanel.adjustAnnotationHeight();
5424 Hashtable skipList = null;
5427 * TODO remove this method
5430 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5431 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5432 * throw new Error("Implementation Error. No skipList defined for this
5433 * Jalview2XML instance."); } return (AlignFrame)
5434 * skipList.get(view.getSequenceSetId()); }
5438 * Check if the Jalview view contained in object should be skipped or not.
5441 * @return true if view's sequenceSetId is a key in skipList
5443 private boolean skipViewport(JalviewModel object)
5445 if (skipList == null)
5449 String id = object.getViewport().get(0).getSequenceSetId();
5450 if (skipList.containsKey(id))
5452 if (Cache.log != null && Cache.log.isDebugEnabled())
5454 Cache.log.debug("Skipping seuqence set id " + id);
5461 public void addToSkipList(AlignFrame af)
5463 if (skipList == null)
5465 skipList = new Hashtable();
5467 skipList.put(af.getViewport().getSequenceSetId(), af);
5470 public void clearSkipList()
5472 if (skipList != null)
5479 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5480 boolean ignoreUnrefed, String uniqueSeqSetId)
5482 jalview.datamodel.AlignmentI ds = getDatasetFor(
5483 vamsasSet.getDatasetId());
5484 AlignmentI xtant_ds = ds;
5485 if (xtant_ds == null)
5487 // good chance we are about to create a new dataset, but check if we've
5488 // seen some of the dataset sequence IDs before.
5489 // TODO: skip this check if we are working with project generated by
5490 // version 2.11 or later
5491 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5492 if (xtant_ds != null)
5495 addDatasetRef(vamsasSet.getDatasetId(), ds);
5498 Vector dseqs = null;
5501 // recovering an alignment View
5502 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5503 if (seqSetDS != null)
5505 if (ds != null && ds != seqSetDS)
5507 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5508 + " - CDS/Protein crossreference data may be lost");
5509 if (xtant_ds != null)
5511 // This can only happen if the unique sequence set ID was bound to a
5512 // dataset that did not contain any of the sequences in the view
5513 // currently being restored.
5514 warn("JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
5518 addDatasetRef(vamsasSet.getDatasetId(), ds);
5523 // try even harder to restore dataset
5524 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5525 // create a list of new dataset sequences
5526 dseqs = new Vector();
5528 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5530 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5531 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5533 // create a new dataset
5536 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5537 dseqs.copyInto(dsseqs);
5538 ds = new jalview.datamodel.Alignment(dsseqs);
5539 debug("Created new dataset " + vamsasSet.getDatasetId()
5540 + " for alignment " + System.identityHashCode(al));
5541 addDatasetRef(vamsasSet.getDatasetId(), ds);
5543 // set the dataset for the newly imported alignment.
5544 if (al.getDataset() == null && !ignoreUnrefed)
5547 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5548 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5550 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5554 * XML dataset sequence ID to materialised dataset reference
5556 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5559 * @return the first materialised dataset reference containing a dataset
5560 * sequence referenced in the given view
5562 * - sequences from the view
5564 AlignmentI checkIfHasDataset(List<Sequence> list)
5566 for (Sequence restoredSeq : list)
5568 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5569 if (datasetFor != null)
5578 * Register ds as the containing dataset for the dataset sequences referenced
5579 * by sequences in list
5582 * - sequences in a view
5585 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5587 for (Sequence restoredSeq : list)
5589 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5590 if (prevDS != null && prevDS != ds)
5592 warn("Dataset sequence appears in many datasets: "
5593 + restoredSeq.getDsseqid());
5594 // TODO: try to merge!
5601 * sequence definition to create/merge dataset sequence for
5605 * vector to add new dataset sequence to
5606 * @param ignoreUnrefed
5607 * - when true, don't create new sequences from vamsasSeq if it's id
5608 * doesn't already have an asssociated Jalview sequence.
5610 * - used to reorder the sequence in the alignment according to the
5611 * vamsasSeq array ordering, to preserve ordering of dataset
5613 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5614 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5616 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5618 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5619 boolean reorder = false;
5620 SequenceI dsq = null;
5621 if (sq != null && sq.getDatasetSequence() != null)
5623 dsq = sq.getDatasetSequence();
5629 if (sq == null && ignoreUnrefed)
5633 String sqid = vamsasSeq.getDsseqid();
5636 // need to create or add a new dataset sequence reference to this sequence
5639 dsq = seqRefIds.get(sqid);
5644 // make a new dataset sequence
5645 dsq = sq.createDatasetSequence();
5648 // make up a new dataset reference for this sequence
5649 sqid = seqHash(dsq);
5651 dsq.setVamsasId(uniqueSetSuffix + sqid);
5652 seqRefIds.put(sqid, dsq);
5657 dseqs.addElement(dsq);
5662 ds.addSequence(dsq);
5668 { // make this dataset sequence sq's dataset sequence
5669 sq.setDatasetSequence(dsq);
5670 // and update the current dataset alignment
5675 if (!dseqs.contains(dsq))
5682 if (ds.findIndex(dsq) < 0)
5684 ds.addSequence(dsq);
5691 // TODO: refactor this as a merge dataset sequence function
5692 // now check that sq (the dataset sequence) sequence really is the union of
5693 // all references to it
5694 // boolean pre = sq.getStart() < dsq.getStart();
5695 // boolean post = sq.getEnd() > dsq.getEnd();
5699 // StringBuffer sb = new StringBuffer();
5700 String newres = jalview.analysis.AlignSeq.extractGaps(
5701 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5702 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5703 && newres.length() > dsq.getLength())
5705 // Update with the longer sequence.
5709 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5710 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5711 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5712 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5714 dsq.setSequence(newres);
5716 // TODO: merges will never happen if we 'know' we have the real dataset
5717 // sequence - this should be detected when id==dssid
5719 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5720 // + (pre ? "prepended" : "") + " "
5721 // + (post ? "appended" : ""));
5726 // sequence refs are identical. We may need to update the existing dataset
5727 // alignment with this one, though.
5728 if (ds != null && dseqs == null)
5730 int opos = ds.findIndex(dsq);
5731 SequenceI tseq = null;
5732 if (opos != -1 && vseqpos != opos)
5734 // remove from old position
5735 ds.deleteSequence(dsq);
5737 if (vseqpos < ds.getHeight())
5739 if (vseqpos != opos)
5741 // save sequence at destination position
5742 tseq = ds.getSequenceAt(vseqpos);
5743 ds.replaceSequenceAt(vseqpos, dsq);
5744 ds.addSequence(tseq);
5749 ds.addSequence(dsq);
5756 * TODO use AlignmentI here and in related methods - needs
5757 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5759 Hashtable<String, AlignmentI> datasetIds = null;
5761 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5763 private AlignmentI getDatasetFor(String datasetId)
5765 if (datasetIds == null)
5767 datasetIds = new Hashtable<>();
5770 if (datasetIds.containsKey(datasetId))
5772 return datasetIds.get(datasetId);
5777 private void addDatasetRef(String datasetId, AlignmentI dataset)
5779 if (datasetIds == null)
5781 datasetIds = new Hashtable<>();
5783 datasetIds.put(datasetId, dataset);
5787 * make a new dataset ID for this jalview dataset alignment
5792 private String getDatasetIdRef(AlignmentI dataset)
5794 if (dataset.getDataset() != null)
5796 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5798 String datasetId = makeHashCode(dataset, null);
5799 if (datasetId == null)
5801 // make a new datasetId and record it
5802 if (dataset2Ids == null)
5804 dataset2Ids = new IdentityHashMap<>();
5808 datasetId = dataset2Ids.get(dataset);
5810 if (datasetId == null)
5812 datasetId = "ds" + dataset2Ids.size() + 1;
5813 dataset2Ids.put(dataset, datasetId);
5820 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5821 * constructed as a special subclass GeneLocus.
5823 * @param datasetSequence
5826 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5828 for (int d = 0; d < sequence.getDBRef().size(); d++)
5830 DBRef dr = sequence.getDBRef().get(d);
5834 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5835 dr.getAccessionId());
5839 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5840 dr.getAccessionId());
5842 if (dr.getMapping() != null)
5844 entry.setMap(addMapping(dr.getMapping()));
5846 datasetSequence.addDBRef(entry);
5850 private jalview.datamodel.Mapping addMapping(Mapping m)
5852 SequenceI dsto = null;
5853 // Mapping m = dr.getMapping();
5854 int fr[] = new int[m.getMapListFrom().size() * 2];
5855 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5856 for (int _i = 0; from.hasNext(); _i += 2)
5858 MapListFrom mf = from.next();
5859 fr[_i] = mf.getStart();
5860 fr[_i + 1] = mf.getEnd();
5862 int fto[] = new int[m.getMapListTo().size() * 2];
5863 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5864 for (int _i = 0; to.hasNext(); _i += 2)
5866 MapListTo mf = to.next();
5867 fto[_i] = mf.getStart();
5868 fto[_i + 1] = mf.getEnd();
5870 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5871 fto, m.getMapFromUnit().intValue(),
5872 m.getMapToUnit().intValue());
5875 * (optional) choice of dseqFor or Sequence
5877 if (m.getDseqFor() != null)
5879 String dsfor = m.getDseqFor();
5880 if (seqRefIds.containsKey(dsfor))
5885 jmap.setTo(seqRefIds.get(dsfor));
5889 frefedSequence.add(newMappingRef(dsfor, jmap));
5892 else if (m.getSequence() != null)
5895 * local sequence definition
5897 Sequence ms = m.getSequence();
5898 SequenceI djs = null;
5899 String sqid = ms.getDsseqid();
5900 if (sqid != null && sqid.length() > 0)
5903 * recover dataset sequence
5905 djs = seqRefIds.get(sqid);
5910 "Warning - making up dataset sequence id for DbRef sequence map reference");
5911 sqid = ((Object) ms).toString(); // make up a new hascode for
5912 // undefined dataset sequence hash
5913 // (unlikely to happen)
5919 * make a new dataset sequence and add it to refIds hash
5921 djs = new jalview.datamodel.Sequence(ms.getName(),
5923 djs.setStart(jmap.getMap().getToLowest());
5924 djs.setEnd(jmap.getMap().getToHighest());
5925 djs.setVamsasId(uniqueSetSuffix + sqid);
5927 incompleteSeqs.put(sqid, djs);
5928 seqRefIds.put(sqid, djs);
5931 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5940 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5941 * view as XML (but not to file), and then reloading it
5946 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5949 JalviewModel jm = saveState(ap, null, null, null);
5952 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5953 ap.getAlignment().getDataset());
5955 uniqueSetSuffix = "";
5956 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5957 jm.getViewport().get(0).setId(null);
5958 // we don't overwrite the view we just copied
5960 if (this.frefedSequence == null)
5962 frefedSequence = new Vector<>();
5965 viewportsAdded.clear();
5967 AlignFrame af = loadFromObject(jm, null, false, null);
5968 af.getAlignPanels().clear();
5969 af.closeMenuItem_actionPerformed(true);
5972 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5973 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5974 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5975 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5976 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5979 return af.alignPanel;
5982 private Hashtable jvids2vobj;
5984 private void warn(String msg)
5989 private void warn(String msg, Exception e)
5991 if (Cache.log != null)
5995 Cache.log.warn(msg, e);
5999 Cache.log.warn(msg);
6004 System.err.println("Warning: " + msg);
6007 e.printStackTrace();
6012 private void debug(String string)
6014 debug(string, null);
6017 private void debug(String msg, Exception e)
6019 if (Cache.log != null)
6023 Cache.log.debug(msg, e);
6027 Cache.log.debug(msg);
6032 System.err.println("Warning: " + msg);
6035 e.printStackTrace();
6041 * set the object to ID mapping tables used to write/recover objects and XML
6042 * ID strings for the jalview project. If external tables are provided then
6043 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6044 * object goes out of scope. - also populates the datasetIds hashtable with
6045 * alignment objects containing dataset sequences
6048 * Map from ID strings to jalview datamodel
6050 * Map from jalview datamodel to ID strings
6054 public void setObjectMappingTables(Hashtable vobj2jv,
6055 IdentityHashMap jv2vobj)
6057 this.jv2vobj = jv2vobj;
6058 this.vobj2jv = vobj2jv;
6059 Iterator ds = jv2vobj.keySet().iterator();
6061 while (ds.hasNext())
6063 Object jvobj = ds.next();
6064 id = jv2vobj.get(jvobj).toString();
6065 if (jvobj instanceof jalview.datamodel.Alignment)
6067 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6069 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6072 else if (jvobj instanceof jalview.datamodel.Sequence)
6074 // register sequence object so the XML parser can recover it.
6075 if (seqRefIds == null)
6077 seqRefIds = new HashMap<>();
6079 if (seqsToIds == null)
6081 seqsToIds = new IdentityHashMap<>();
6083 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6084 seqsToIds.put((SequenceI) jvobj, id);
6086 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6089 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6090 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6091 if (jvann.annotationId == null)
6093 jvann.annotationId = anid;
6095 if (!jvann.annotationId.equals(anid))
6097 // TODO verify that this is the correct behaviour
6098 this.warn("Overriding Annotation ID for " + anid
6099 + " from different id : " + jvann.annotationId);
6100 jvann.annotationId = anid;
6103 else if (jvobj instanceof String)
6105 if (jvids2vobj == null)
6107 jvids2vobj = new Hashtable();
6108 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6113 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6119 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6120 * objects created from the project archive. If string is null (default for
6121 * construction) then suffix will be set automatically.
6125 public void setUniqueSetSuffix(String string)
6127 uniqueSetSuffix = string;
6132 * uses skipList2 as the skipList for skipping views on sequence sets
6133 * associated with keys in the skipList
6137 public void setSkipList(Hashtable skipList2)
6139 skipList = skipList2;
6143 * Reads the jar entry of given name and returns its contents, or null if the
6144 * entry is not found.
6147 * @param jarEntryName
6150 protected String readJarEntry(jarInputStreamProvider jprovider,
6151 String jarEntryName)
6153 String result = null;
6154 BufferedReader in = null;
6159 * Reopen the jar input stream and traverse its entries to find a matching
6162 JarInputStream jin = jprovider.getJarInputStream();
6163 JarEntry entry = null;
6166 entry = jin.getNextJarEntry();
6167 } while (entry != null && !entry.getName().equals(jarEntryName));
6171 StringBuilder out = new StringBuilder(256);
6172 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6175 while ((data = in.readLine()) != null)
6179 result = out.toString();
6183 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6185 } catch (Exception ex)
6187 ex.printStackTrace();
6195 } catch (IOException e)
6206 * Returns an incrementing counter (0, 1, 2...)
6210 private synchronized int nextCounter()
6216 * Loads any saved PCA viewers
6221 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6225 List<PcaViewer> pcaviewers = model.getPcaViewer();
6226 for (PcaViewer viewer : pcaviewers)
6228 String modelName = viewer.getScoreModelName();
6229 SimilarityParamsI params = new SimilarityParams(
6230 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6231 viewer.isIncludeGaps(),
6232 viewer.isDenominateByShortestLength());
6235 * create the panel (without computing the PCA)
6237 PCAPanel panel = new PCAPanel(ap, modelName, params);
6239 panel.setTitle(viewer.getTitle());
6240 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6241 viewer.getWidth(), viewer.getHeight()));
6243 boolean showLabels = viewer.isShowLabels();
6244 panel.setShowLabels(showLabels);
6245 panel.getRotatableCanvas().setShowLabels(showLabels);
6246 panel.getRotatableCanvas()
6247 .setBgColour(new Color(viewer.getBgColour()));
6248 panel.getRotatableCanvas()
6249 .setApplyToAllViews(viewer.isLinkToAllViews());
6252 * load PCA output data
6254 ScoreModelI scoreModel = ScoreModels.getInstance()
6255 .getScoreModel(modelName, ap);
6256 PCA pca = new PCA(null, scoreModel, params);
6257 PcaDataType pcaData = viewer.getPcaData();
6259 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6260 pca.setPairwiseScores(pairwise);
6262 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6263 pca.setTridiagonal(triDiag);
6265 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6266 pca.setEigenmatrix(result);
6268 panel.getPcaModel().setPCA(pca);
6271 * we haven't saved the input data! (JAL-2647 to do)
6273 panel.setInputData(null);
6276 * add the sequence points for the PCA display
6278 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6279 for (SequencePoint sp : viewer.getSequencePoint())
6281 String seqId = sp.getSequenceRef();
6282 SequenceI seq = seqRefIds.get(seqId);
6285 throw new IllegalStateException(
6286 "Unmatched seqref for PCA: " + seqId);
6288 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6289 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6291 seqPoints.add(seqPoint);
6293 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6296 * set min-max ranges and scale after setPoints (which recomputes them)
6298 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6299 SeqPointMin spMin = viewer.getSeqPointMin();
6300 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6302 SeqPointMax spMax = viewer.getSeqPointMax();
6303 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6305 panel.getRotatableCanvas().setSeqMinMax(min, max);
6307 // todo: hold points list in PCAModel only
6308 panel.getPcaModel().setSequencePoints(seqPoints);
6310 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6311 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6312 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6314 // is this duplication needed?
6315 panel.setTop(seqPoints.size() - 1);
6316 panel.getPcaModel().setTop(seqPoints.size() - 1);
6319 * add the axes' end points for the display
6321 for (int i = 0; i < 3; i++)
6323 Axis axis = viewer.getAxis().get(i);
6324 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6325 axis.getXPos(), axis.getYPos(), axis.getZPos());
6328 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6329 "label.calc_title", "PCA", modelName), 475, 450);
6331 } catch (Exception ex)
6333 Cache.log.error("Error loading PCA: " + ex.toString());
6338 * Populates an XML model of the feature colour scheme for one feature type
6340 * @param featureType
6344 public static Colour marshalColour(
6345 String featureType, FeatureColourI fcol)
6347 Colour col = new Colour();
6348 if (fcol.isSimpleColour())
6350 col.setRGB(Format.getHexString(fcol.getColour()));
6354 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6355 col.setMin(fcol.getMin());
6356 col.setMax(fcol.getMax());
6357 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6358 col.setAutoScale(fcol.isAutoScaled());
6359 col.setThreshold(fcol.getThreshold());
6360 col.setColourByLabel(fcol.isColourByLabel());
6361 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6362 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6363 : ThresholdType.NONE));
6364 if (fcol.isColourByAttribute())
6366 final String[] attName = fcol.getAttributeName();
6367 col.getAttributeName().add(attName[0]);
6368 if (attName.length > 1)
6370 col.getAttributeName().add(attName[1]);
6373 Color noColour = fcol.getNoColour();
6374 if (noColour == null)
6376 col.setNoValueColour(NoValueColour.NONE);
6378 else if (noColour == fcol.getMaxColour())
6380 col.setNoValueColour(NoValueColour.MAX);
6384 col.setNoValueColour(NoValueColour.MIN);
6387 col.setName(featureType);
6392 * Populates an XML model of the feature filter(s) for one feature type
6394 * @param firstMatcher
6395 * the first (or only) match condition)
6397 * remaining match conditions (if any)
6399 * if true, conditions are and-ed, else or-ed
6401 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6402 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6405 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6407 if (filters.hasNext())
6412 CompoundMatcher compound = new CompoundMatcher();
6413 compound.setAnd(and);
6414 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6415 firstMatcher, Collections.emptyIterator(), and);
6416 // compound.addMatcherSet(matcher1);
6417 compound.getMatcherSet().add(matcher1);
6418 FeatureMatcherI nextMatcher = filters.next();
6419 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6420 nextMatcher, filters, and);
6421 // compound.addMatcherSet(matcher2);
6422 compound.getMatcherSet().add(matcher2);
6423 result.setCompoundMatcher(compound);
6428 * single condition matcher
6430 // MatchCondition matcherModel = new MatchCondition();
6431 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6432 matcherModel.setCondition(
6433 firstMatcher.getMatcher().getCondition().getStableName());
6434 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6435 if (firstMatcher.isByAttribute())
6437 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6438 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6439 String[] attName = firstMatcher.getAttribute();
6440 matcherModel.getAttributeName().add(attName[0]); // attribute
6441 if (attName.length > 1)
6443 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6446 else if (firstMatcher.isByLabel())
6448 matcherModel.setBy(FilterBy.BY_LABEL);
6450 else if (firstMatcher.isByScore())
6452 matcherModel.setBy(FilterBy.BY_SCORE);
6454 result.setMatchCondition(matcherModel);
6461 * Loads one XML model of a feature filter to a Jalview object
6463 * @param featureType
6464 * @param matcherSetModel
6467 public static FeatureMatcherSetI parseFilter(
6469 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6471 FeatureMatcherSetI result = new FeatureMatcherSet();
6474 parseFilterConditions(result, matcherSetModel, true);
6475 } catch (IllegalStateException e)
6477 // mixing AND and OR conditions perhaps
6479 String.format("Error reading filter conditions for '%s': %s",
6480 featureType, e.getMessage()));
6481 // return as much as was parsed up to the error
6488 * Adds feature match conditions to matcherSet as unmarshalled from XML
6489 * (possibly recursively for compound conditions)
6492 * @param matcherSetModel
6494 * if true, multiple conditions are AND-ed, else they are OR-ed
6495 * @throws IllegalStateException
6496 * if AND and OR conditions are mixed
6498 protected static void parseFilterConditions(
6499 FeatureMatcherSetI matcherSet,
6500 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6503 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6504 .getMatchCondition();
6510 FilterBy filterBy = mc.getBy();
6511 Condition cond = Condition.fromString(mc.getCondition());
6512 String pattern = mc.getValue();
6513 FeatureMatcherI matchCondition = null;
6514 if (filterBy == FilterBy.BY_LABEL)
6516 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6518 else if (filterBy == FilterBy.BY_SCORE)
6520 matchCondition = FeatureMatcher.byScore(cond, pattern);
6523 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6525 final List<String> attributeName = mc.getAttributeName();
6526 String[] attNames = attributeName
6527 .toArray(new String[attributeName.size()]);
6528 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6533 * note this throws IllegalStateException if AND-ing to a
6534 * previously OR-ed compound condition, or vice versa
6538 matcherSet.and(matchCondition);
6542 matcherSet.or(matchCondition);
6548 * compound condition
6550 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6551 .getCompoundMatcher().getMatcherSet();
6552 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6553 if (matchers.size() == 2)
6555 parseFilterConditions(matcherSet, matchers.get(0), anded);
6556 parseFilterConditions(matcherSet, matchers.get(1), anded);
6560 System.err.println("Malformed compound filter condition");
6566 * Loads one XML model of a feature colour to a Jalview object
6568 * @param colourModel
6571 public static FeatureColourI parseColour(Colour colourModel)
6573 FeatureColourI colour = null;
6575 if (colourModel.getMax() != null)
6577 Color mincol = null;
6578 Color maxcol = null;
6579 Color noValueColour = null;
6583 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6584 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6585 } catch (Exception e)
6587 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6590 NoValueColour noCol = colourModel.getNoValueColour();
6591 if (noCol == NoValueColour.MIN)
6593 noValueColour = mincol;
6595 else if (noCol == NoValueColour.MAX)
6597 noValueColour = maxcol;
6600 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6601 safeFloat(colourModel.getMin()),
6602 safeFloat(colourModel.getMax()));
6603 final List<String> attributeName = colourModel.getAttributeName();
6604 String[] attributes = attributeName
6605 .toArray(new String[attributeName.size()]);
6606 if (attributes != null && attributes.length > 0)
6608 colour.setAttributeName(attributes);
6610 if (colourModel.isAutoScale() != null)
6612 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6614 if (colourModel.isColourByLabel() != null)
6616 colour.setColourByLabel(
6617 colourModel.isColourByLabel().booleanValue());
6619 if (colourModel.getThreshold() != null)
6621 colour.setThreshold(colourModel.getThreshold().floatValue());
6623 ThresholdType ttyp = colourModel.getThreshType();
6624 if (ttyp == ThresholdType.ABOVE)
6626 colour.setAboveThreshold(true);
6628 else if (ttyp == ThresholdType.BELOW)
6630 colour.setBelowThreshold(true);
6635 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6636 colour = new FeatureColour(color);