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.
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.GraphLine;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.Point;
44 import jalview.datamodel.RnaViewerModel;
45 import jalview.datamodel.SequenceFeature;
46 import jalview.datamodel.SequenceGroup;
47 import jalview.datamodel.SequenceI;
48 import jalview.datamodel.StructureViewerModel;
49 import jalview.datamodel.StructureViewerModel.StructureData;
50 import jalview.datamodel.features.FeatureMatcher;
51 import jalview.datamodel.features.FeatureMatcherI;
52 import jalview.datamodel.features.FeatureMatcherSet;
53 import jalview.datamodel.features.FeatureMatcherSetI;
54 import jalview.ext.varna.RnaModel;
55 import jalview.gui.StructureViewer.ViewerType;
56 import jalview.io.DataSourceType;
57 import jalview.io.FileFormat;
58 import jalview.math.Matrix;
59 import jalview.math.MatrixI;
60 import jalview.renderer.ResidueShaderI;
61 import jalview.schemabinding.version2.AlcodMap;
62 import jalview.schemabinding.version2.AlcodonFrame;
63 import jalview.schemabinding.version2.Annotation;
64 import jalview.schemabinding.version2.AnnotationColours;
65 import jalview.schemabinding.version2.AnnotationElement;
66 import jalview.schemabinding.version2.Axis;
67 import jalview.schemabinding.version2.CalcIdParam;
68 import jalview.schemabinding.version2.CompoundMatcher;
69 import jalview.schemabinding.version2.D;
70 import jalview.schemabinding.version2.DBRef;
71 import jalview.schemabinding.version2.DoubleMatrix;
72 import jalview.schemabinding.version2.E;
73 import jalview.schemabinding.version2.EigenMatrix;
74 import jalview.schemabinding.version2.Features;
75 import jalview.schemabinding.version2.Group;
76 import jalview.schemabinding.version2.HiddenColumns;
77 import jalview.schemabinding.version2.JGroup;
78 import jalview.schemabinding.version2.JSeq;
79 import jalview.schemabinding.version2.JalviewModel;
80 import jalview.schemabinding.version2.JalviewModelSequence;
81 import jalview.schemabinding.version2.MapListFrom;
82 import jalview.schemabinding.version2.MapListTo;
83 import jalview.schemabinding.version2.Mapping;
84 import jalview.schemabinding.version2.MappingChoice;
85 import jalview.schemabinding.version2.MatchCondition;
86 import jalview.schemabinding.version2.MatcherSet;
87 import jalview.schemabinding.version2.OtherData;
88 import jalview.schemabinding.version2.PairwiseMatrix;
89 import jalview.schemabinding.version2.PcaData;
90 import jalview.schemabinding.version2.PcaViewer;
91 import jalview.schemabinding.version2.PdbentryItem;
92 import jalview.schemabinding.version2.Pdbids;
93 import jalview.schemabinding.version2.Property;
94 import jalview.schemabinding.version2.RnaViewer;
95 import jalview.schemabinding.version2.Row;
96 import jalview.schemabinding.version2.SecondaryStructure;
97 import jalview.schemabinding.version2.SeqPointMax;
98 import jalview.schemabinding.version2.SeqPointMin;
99 import jalview.schemabinding.version2.Sequence;
100 import jalview.schemabinding.version2.SequencePoint;
101 import jalview.schemabinding.version2.SequenceSet;
102 import jalview.schemabinding.version2.SequenceSetProperties;
103 import jalview.schemabinding.version2.Setting;
104 import jalview.schemabinding.version2.StructureState;
105 import jalview.schemabinding.version2.ThresholdLine;
106 import jalview.schemabinding.version2.Tree;
107 import jalview.schemabinding.version2.TridiagonalMatrix;
108 import jalview.schemabinding.version2.UserColours;
109 import jalview.schemabinding.version2.Viewport;
110 import jalview.schemabinding.version2.types.ColourThreshTypeType;
111 import jalview.schemabinding.version2.types.FeatureMatcherByType;
112 import jalview.schemabinding.version2.types.NoValueColour;
113 import jalview.schemes.AnnotationColourGradient;
114 import jalview.schemes.ColourSchemeI;
115 import jalview.schemes.ColourSchemeProperty;
116 import jalview.schemes.FeatureColour;
117 import jalview.schemes.ResidueProperties;
118 import jalview.schemes.UserColourScheme;
119 import jalview.structure.StructureSelectionManager;
120 import jalview.structures.models.AAStructureBindingModel;
121 import jalview.util.Format;
122 import jalview.util.MessageManager;
123 import jalview.util.Platform;
124 import jalview.util.StringUtils;
125 import jalview.util.jarInputStreamProvider;
126 import jalview.util.matcher.Condition;
127 import jalview.viewmodel.AlignmentViewport;
128 import jalview.viewmodel.PCAModel;
129 import jalview.viewmodel.ViewportRanges;
130 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
131 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
132 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
133 import jalview.ws.jws2.Jws2Discoverer;
134 import jalview.ws.jws2.dm.AAConSettings;
135 import jalview.ws.jws2.jabaws2.Jws2Instance;
136 import jalview.ws.params.ArgumentI;
137 import jalview.ws.params.AutoCalcSetting;
138 import jalview.ws.params.WsParamSetI;
140 import java.awt.Color;
141 import java.awt.Rectangle;
142 import java.io.BufferedReader;
143 import java.io.DataInputStream;
144 import java.io.DataOutputStream;
146 import java.io.FileInputStream;
147 import java.io.FileOutputStream;
148 import java.io.IOException;
149 import java.io.InputStreamReader;
150 import java.io.OutputStreamWriter;
151 import java.io.PrintWriter;
152 import java.lang.reflect.InvocationTargetException;
153 import java.net.MalformedURLException;
155 import java.util.ArrayList;
156 import java.util.Arrays;
157 import java.util.Collections;
158 import java.util.Enumeration;
159 import java.util.HashMap;
160 import java.util.HashSet;
161 import java.util.Hashtable;
162 import java.util.IdentityHashMap;
163 import java.util.Iterator;
164 import java.util.LinkedHashMap;
165 import java.util.List;
166 import java.util.Map;
167 import java.util.Map.Entry;
168 import java.util.Set;
169 import java.util.Vector;
170 import java.util.jar.JarEntry;
171 import java.util.jar.JarInputStream;
172 import java.util.jar.JarOutputStream;
174 import javax.swing.JInternalFrame;
175 import javax.swing.SwingUtilities;
177 import org.exolab.castor.xml.Marshaller;
178 import org.exolab.castor.xml.Unmarshaller;
181 * Write out the current jalview desktop state as a Jalview XML stream.
183 * Note: the vamsas objects referred to here are primitive versions of the
184 * VAMSAS project schema elements - they are not the same and most likely never
188 * @version $Revision: 1.134 $
190 public class Jalview2XML
192 private static final String VIEWER_PREFIX = "viewer_";
194 private static final String RNA_PREFIX = "rna_";
196 private static final String UTF_8 = "UTF-8";
199 * prefix for recovering datasets for alignments with multiple views where
200 * non-existent dataset IDs were written for some views
202 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
204 // use this with nextCounter() to make unique names for entities
205 private int counter = 0;
208 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
209 * of sequence objects are created.
211 IdentityHashMap<SequenceI, String> seqsToIds = null;
214 * jalview XML Sequence ID to jalview sequence object reference (both dataset
215 * and alignment sequences. Populated as XML reps of sequence objects are
218 Map<String, SequenceI> seqRefIds = null;
220 Map<String, SequenceI> incompleteSeqs = null;
222 List<SeqFref> frefedSequence = null;
224 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
227 * Map of reconstructed AlignFrame objects that appear to have come from
228 * SplitFrame objects (have a dna/protein complement view).
230 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
233 * Map from displayed rna structure models to their saved session state jar
236 private Map<RnaModel, String> rnaSessions = new HashMap<>();
239 * create/return unique hash string for sq
242 * @return new or existing unique string for sq
244 String seqHash(SequenceI sq)
246 if (seqsToIds == null)
250 if (seqsToIds.containsKey(sq))
252 return seqsToIds.get(sq);
256 // create sequential key
257 String key = "sq" + (seqsToIds.size() + 1);
258 key = makeHashCode(sq, key); // check we don't have an external reference
260 seqsToIds.put(sq, key);
267 if (seqsToIds == null)
269 seqsToIds = new IdentityHashMap<>();
271 if (seqRefIds == null)
273 seqRefIds = new HashMap<>();
275 if (incompleteSeqs == null)
277 incompleteSeqs = new HashMap<>();
279 if (frefedSequence == null)
281 frefedSequence = new ArrayList<>();
289 public Jalview2XML(boolean raiseGUI)
291 this.raiseGUI = raiseGUI;
295 * base class for resolving forward references to sequences by their ID
300 abstract class SeqFref
306 public SeqFref(String _sref, String type)
312 public String getSref()
317 public SequenceI getSrefSeq()
319 return seqRefIds.get(sref);
322 public boolean isResolvable()
324 return seqRefIds.get(sref) != null;
327 public SequenceI getSrefDatasetSeq()
329 SequenceI sq = seqRefIds.get(sref);
332 while (sq.getDatasetSequence() != null)
334 sq = sq.getDatasetSequence();
341 * @return true if the forward reference was fully resolved
343 abstract boolean resolve();
346 public String toString()
348 return type + " reference to " + sref;
353 * create forward reference for a mapping
359 public SeqFref newMappingRef(final String sref,
360 final jalview.datamodel.Mapping _jmap)
362 SeqFref fref = new SeqFref(sref, "Mapping")
364 public jalview.datamodel.Mapping jmap = _jmap;
369 SequenceI seq = getSrefDatasetSeq();
381 public SeqFref newAlcodMapRef(final String sref,
382 final AlignedCodonFrame _cf,
383 final jalview.datamodel.Mapping _jmap)
386 SeqFref fref = new SeqFref(sref, "Codon Frame")
388 AlignedCodonFrame cf = _cf;
390 public jalview.datamodel.Mapping mp = _jmap;
393 public boolean isResolvable()
395 return super.isResolvable() && mp.getTo() != null;
401 SequenceI seq = getSrefDatasetSeq();
406 cf.addMap(seq, mp.getTo(), mp.getMap());
413 public void resolveFrefedSequences()
415 Iterator<SeqFref> nextFref = frefedSequence.iterator();
416 int toresolve = frefedSequence.size();
417 int unresolved = 0, failedtoresolve = 0;
418 while (nextFref.hasNext())
420 SeqFref ref = nextFref.next();
421 if (ref.isResolvable())
433 } catch (Exception x)
436 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
449 System.err.println("Jalview Project Import: There were " + unresolved
450 + " forward references left unresolved on the stack.");
452 if (failedtoresolve > 0)
454 System.err.println("SERIOUS! " + failedtoresolve
455 + " resolvable forward references failed to resolve.");
457 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
460 "Jalview Project Import: There are " + incompleteSeqs.size()
461 + " sequences which may have incomplete metadata.");
462 if (incompleteSeqs.size() < 10)
464 for (SequenceI s : incompleteSeqs.values())
466 System.err.println(s.toString());
472 "Too many to report. Skipping output of incomplete sequences.");
478 * This maintains a map of viewports, the key being the seqSetId. Important to
479 * set historyItem and redoList for multiple views
481 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
483 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
485 String uniqueSetSuffix = "";
488 * List of pdbfiles added to Jar
490 List<String> pdbfiles = null;
492 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
493 public void saveState(File statefile)
495 FileOutputStream fos = null;
498 fos = new FileOutputStream(statefile);
499 JarOutputStream jout = new JarOutputStream(fos);
502 } catch (Exception e)
504 // TODO: inform user of the problem - they need to know if their data was
506 if (errorMessage == null)
508 errorMessage = "Couldn't write Jalview Archive to output file '"
509 + statefile + "' - See console error log for details";
513 errorMessage += "(output file was '" + statefile + "')";
523 } catch (IOException e)
533 * Writes a jalview project archive to the given Jar output stream.
537 public void saveState(JarOutputStream jout)
539 AlignFrame[] frames = Desktop.getAlignFrames();
545 saveAllFrames(Arrays.asList(frames), jout);
549 * core method for storing state for a set of AlignFrames.
552 * - frames involving all data to be exported (including containing
555 * - project output stream
557 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
559 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
562 * ensure cached data is clear before starting
564 // todo tidy up seqRefIds, seqsToIds initialisation / reset
566 splitFrameCandidates.clear();
571 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
572 // //////////////////////////////////////////////////
574 List<String> shortNames = new ArrayList<>();
575 List<String> viewIds = new ArrayList<>();
578 for (int i = frames.size() - 1; i > -1; i--)
580 AlignFrame af = frames.get(i);
582 if (skipList != null && skipList
583 .containsKey(af.getViewport().getSequenceSetId()))
588 String shortName = makeFilename(af, shortNames);
590 int ap, apSize = af.alignPanels.size();
592 for (ap = 0; ap < apSize; ap++)
594 AlignmentPanel apanel = af.alignPanels.get(ap);
595 String fileName = apSize == 1 ? shortName : ap + shortName;
596 if (!fileName.endsWith(".xml"))
598 fileName = fileName + ".xml";
601 saveState(apanel, fileName, jout, viewIds);
603 String dssid = getDatasetIdRef(
604 af.getViewport().getAlignment().getDataset());
605 if (!dsses.containsKey(dssid))
607 dsses.put(dssid, af);
612 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
618 } catch (Exception foo)
623 } catch (Exception ex)
625 // TODO: inform user of the problem - they need to know if their data was
627 if (errorMessage == null)
629 errorMessage = "Couldn't write Jalview Archive - see error output for details";
631 ex.printStackTrace();
636 * Generates a distinct file name, based on the title of the AlignFrame, by
637 * appending _n for increasing n until an unused name is generated. The new
638 * name (without its extension) is added to the list.
642 * @return the generated name, with .xml extension
644 protected String makeFilename(AlignFrame af, List<String> namesUsed)
646 String shortName = af.getTitle();
648 if (shortName.indexOf(File.separatorChar) > -1)
650 shortName = shortName
651 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
656 while (namesUsed.contains(shortName))
658 if (shortName.endsWith("_" + (count - 1)))
660 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
663 shortName = shortName.concat("_" + count);
667 namesUsed.add(shortName);
669 if (!shortName.endsWith(".xml"))
671 shortName = shortName + ".xml";
676 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
677 public boolean saveAlignment(AlignFrame af, String jarFile,
682 FileOutputStream fos = new FileOutputStream(jarFile);
683 JarOutputStream jout = new JarOutputStream(fos);
684 List<AlignFrame> frames = new ArrayList<>();
686 // resolve splitframes
687 if (af.getViewport().getCodingComplement() != null)
689 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
695 saveAllFrames(frames, jout);
699 } catch (Exception foo)
705 } catch (Exception ex)
707 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
708 ex.printStackTrace();
713 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
714 String fileName, JarOutputStream jout)
717 for (String dssids : dsses.keySet())
719 AlignFrame _af = dsses.get(dssids);
720 String jfileName = fileName + " Dataset for " + _af.getTitle();
721 if (!jfileName.endsWith(".xml"))
723 jfileName = jfileName + ".xml";
725 saveState(_af.alignPanel, jfileName, true, jout, null);
730 * create a JalviewModel from an alignment view and marshall it to a
734 * panel to create jalview model for
736 * name of alignment panel written to output stream
743 public JalviewModel saveState(AlignmentPanel ap, String fileName,
744 JarOutputStream jout, List<String> viewIds)
746 return saveState(ap, fileName, false, jout, viewIds);
750 * create a JalviewModel from an alignment view and marshall it to a
754 * panel to create jalview model for
756 * name of alignment panel written to output stream
758 * when true, only write the dataset for the alignment, not the data
759 * associated with the view.
765 public JalviewModel saveState(AlignmentPanel ap, String fileName,
766 boolean storeDS, JarOutputStream jout, List<String> viewIds)
770 viewIds = new ArrayList<>();
775 List<UserColourScheme> userColours = new ArrayList<>();
777 AlignViewport av = ap.av;
778 ViewportRanges vpRanges = av.getRanges();
780 JalviewModel object = new JalviewModel();
781 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
783 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
785 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
788 * rjal is full height alignment, jal is actual alignment with full metadata
789 * but excludes hidden sequences.
791 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
793 if (av.hasHiddenRows())
795 rjal = jal.getHiddenSequences().getFullAlignment();
798 SequenceSet vamsasSet = new SequenceSet();
800 JalviewModelSequence jms = new JalviewModelSequence();
802 vamsasSet.setGapChar(jal.getGapCharacter() + "");
804 if (jal.getDataset() != null)
806 // dataset id is the dataset's hashcode
807 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
810 // switch jal and the dataset
811 jal = jal.getDataset();
815 if (jal.getProperties() != null)
817 Enumeration en = jal.getProperties().keys();
818 while (en.hasMoreElements())
820 String key = en.nextElement().toString();
821 SequenceSetProperties ssp = new SequenceSetProperties();
823 ssp.setValue(jal.getProperties().get(key).toString());
824 vamsasSet.addSequenceSetProperties(ssp);
829 Set<String> calcIdSet = new HashSet<>();
830 // record the set of vamsas sequence XML POJO we create.
831 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
833 for (final SequenceI jds : rjal.getSequences())
835 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
836 : jds.getDatasetSequence();
837 String id = seqHash(jds);
838 if (vamsasSetIds.get(id) == null)
840 if (seqRefIds.get(id) != null && !storeDS)
842 // This happens for two reasons: 1. multiple views are being
844 // 2. the hashCode has collided with another sequence's code. This
846 // HAPPEN! (PF00072.15.stk does this)
847 // JBPNote: Uncomment to debug writing out of files that do not read
848 // back in due to ArrayOutOfBoundExceptions.
849 // System.err.println("vamsasSeq backref: "+id+"");
850 // System.err.println(jds.getName()+"
851 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
852 // System.err.println("Hashcode: "+seqHash(jds));
853 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
854 // System.err.println(rsq.getName()+"
855 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
856 // System.err.println("Hashcode: "+seqHash(rsq));
860 vamsasSeq = createVamsasSequence(id, jds);
861 vamsasSet.addSequence(vamsasSeq);
862 vamsasSetIds.put(id, vamsasSeq);
863 seqRefIds.put(id, jds);
867 jseq.setStart(jds.getStart());
868 jseq.setEnd(jds.getEnd());
869 jseq.setColour(av.getSequenceColour(jds).getRGB());
871 jseq.setId(id); // jseq id should be a string not a number
874 // Store any sequences this sequence represents
875 if (av.hasHiddenRows())
877 // use rjal, contains the full height alignment
879 av.getAlignment().getHiddenSequences().isHidden(jds));
881 if (av.isHiddenRepSequence(jds))
883 jalview.datamodel.SequenceI[] reps = av
884 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
886 for (int h = 0; h < reps.length; h++)
890 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
895 // mark sequence as reference - if it is the reference for this view
898 jseq.setViewreference(jds == jal.getSeqrep());
902 // TODO: omit sequence features from each alignment view's XML dump if we
903 // are storing dataset
904 List<jalview.datamodel.SequenceFeature> sfs = jds
905 .getSequenceFeatures();
906 for (SequenceFeature sf : sfs)
908 Features features = new Features();
910 features.setBegin(sf.getBegin());
911 features.setEnd(sf.getEnd());
912 features.setDescription(sf.getDescription());
913 features.setType(sf.getType());
914 features.setFeatureGroup(sf.getFeatureGroup());
915 features.setScore(sf.getScore());
916 if (sf.links != null)
918 for (int l = 0; l < sf.links.size(); l++)
920 OtherData keyValue = new OtherData();
921 keyValue.setKey("LINK_" + l);
922 keyValue.setValue(sf.links.elementAt(l).toString());
923 features.addOtherData(keyValue);
926 if (sf.otherDetails != null)
929 * save feature attributes, which may be simple strings or
930 * map valued (have sub-attributes)
932 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
934 String key = entry.getKey();
935 Object value = entry.getValue();
936 if (value instanceof Map<?, ?>)
938 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
941 OtherData otherData = new OtherData();
942 otherData.setKey(key);
943 otherData.setKey2(subAttribute.getKey());
944 otherData.setValue(subAttribute.getValue().toString());
945 features.addOtherData(otherData);
950 OtherData otherData = new OtherData();
951 otherData.setKey(key);
952 otherData.setValue(value.toString());
953 features.addOtherData(otherData);
958 jseq.addFeatures(features);
961 if (jdatasq.getAllPDBEntries() != null)
963 Enumeration en = jdatasq.getAllPDBEntries().elements();
964 while (en.hasMoreElements())
966 Pdbids pdb = new Pdbids();
967 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
970 String pdbId = entry.getId();
972 pdb.setType(entry.getType());
975 * Store any structure views associated with this sequence. This
976 * section copes with duplicate entries in the project, so a dataset
977 * only view *should* be coped with sensibly.
979 // This must have been loaded, is it still visible?
980 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
981 String matchedFile = null;
982 for (int f = frames.length - 1; f > -1; f--)
984 if (frames[f] instanceof StructureViewerBase)
986 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
987 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
988 matchedFile, viewFrame);
990 * Only store each structure viewer's state once in the project
991 * jar. First time through only (storeDS==false)
993 String viewId = viewFrame.getViewId();
994 if (!storeDS && !viewIds.contains(viewId))
999 String viewerState = viewFrame.getStateInfo();
1000 writeJarEntry(jout, getViewerJarEntryName(viewId),
1001 viewerState.getBytes());
1002 } catch (IOException e)
1005 "Error saving viewer state: " + e.getMessage());
1011 if (matchedFile != null || entry.getFile() != null)
1013 if (entry.getFile() != null)
1016 matchedFile = entry.getFile();
1018 pdb.setFile(matchedFile); // entry.getFile());
1019 if (pdbfiles == null)
1021 pdbfiles = new ArrayList<>();
1024 if (!pdbfiles.contains(pdbId))
1026 pdbfiles.add(pdbId);
1027 copyFileToJar(jout, matchedFile, pdbId);
1031 Enumeration<String> props = entry.getProperties();
1032 if (props.hasMoreElements())
1034 PdbentryItem item = new PdbentryItem();
1035 while (props.hasMoreElements())
1037 Property prop = new Property();
1038 String key = props.nextElement();
1040 prop.setValue(entry.getProperty(key).toString());
1041 item.addProperty(prop);
1043 pdb.addPdbentryItem(item);
1046 jseq.addPdbids(pdb);
1050 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1055 if (!storeDS && av.hasHiddenRows())
1057 jal = av.getAlignment();
1061 if (storeDS && jal.getCodonFrames() != null)
1063 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1064 for (AlignedCodonFrame acf : jac)
1066 AlcodonFrame alc = new AlcodonFrame();
1067 if (acf.getProtMappings() != null
1068 && acf.getProtMappings().length > 0)
1070 boolean hasMap = false;
1071 SequenceI[] dnas = acf.getdnaSeqs();
1072 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1073 for (int m = 0; m < pmaps.length; m++)
1075 AlcodMap alcmap = new AlcodMap();
1076 alcmap.setDnasq(seqHash(dnas[m]));
1078 createVamsasMapping(pmaps[m], dnas[m], null, false));
1079 alc.addAlcodMap(alcmap);
1084 vamsasSet.addAlcodonFrame(alc);
1087 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1089 // AlcodonFrame alc = new AlcodonFrame();
1090 // vamsasSet.addAlcodonFrame(alc);
1091 // for (int p = 0; p < acf.aaWidth; p++)
1093 // Alcodon cmap = new Alcodon();
1094 // if (acf.codons[p] != null)
1096 // // Null codons indicate a gapped column in the translated peptide
1098 // cmap.setPos1(acf.codons[p][0]);
1099 // cmap.setPos2(acf.codons[p][1]);
1100 // cmap.setPos3(acf.codons[p][2]);
1102 // alc.addAlcodon(cmap);
1104 // if (acf.getProtMappings() != null
1105 // && acf.getProtMappings().length > 0)
1107 // SequenceI[] dnas = acf.getdnaSeqs();
1108 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1109 // for (int m = 0; m < pmaps.length; m++)
1111 // AlcodMap alcmap = new AlcodMap();
1112 // alcmap.setDnasq(seqHash(dnas[m]));
1113 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1115 // alc.addAlcodMap(alcmap);
1122 // /////////////////////////////////
1123 if (!storeDS && av.getCurrentTree() != null)
1125 // FIND ANY ASSOCIATED TREES
1126 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1127 if (Desktop.desktop != null)
1129 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1131 for (int t = 0; t < frames.length; t++)
1133 if (frames[t] instanceof TreePanel)
1135 TreePanel tp = (TreePanel) frames[t];
1137 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1139 Tree tree = new Tree();
1140 tree.setTitle(tp.getTitle());
1141 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1142 tree.setNewick(tp.getTree().print());
1143 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1145 tree.setFitToWindow(tp.fitToWindow.getState());
1146 tree.setFontName(tp.getTreeFont().getName());
1147 tree.setFontSize(tp.getTreeFont().getSize());
1148 tree.setFontStyle(tp.getTreeFont().getStyle());
1149 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1151 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1152 tree.setShowDistances(tp.distanceMenu.getState());
1154 tree.setHeight(tp.getHeight());
1155 tree.setWidth(tp.getWidth());
1156 tree.setXpos(tp.getX());
1157 tree.setYpos(tp.getY());
1158 tree.setId(makeHashCode(tp, null));
1159 tree.setLinkToAllViews(tp.getTreeCanvas().applyToAllViews);
1170 if (!storeDS && Desktop.desktop != null)
1172 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1174 if (frame instanceof PCAPanel)
1176 PCAPanel panel = (PCAPanel) frame;
1177 if (panel.av.getAlignment() == jal)
1179 savePCA(panel, jms);
1187 * store forward refs from an annotationRow to any groups
1189 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1192 for (SequenceI sq : jal.getSequences())
1194 // Store annotation on dataset sequences only
1195 AlignmentAnnotation[] aa = sq.getAnnotation();
1196 if (aa != null && aa.length > 0)
1198 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1205 if (jal.getAlignmentAnnotation() != null)
1207 // Store the annotation shown on the alignment.
1208 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1209 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1214 if (jal.getGroups() != null)
1216 JGroup[] groups = new JGroup[jal.getGroups().size()];
1218 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1220 JGroup jGroup = new JGroup();
1221 groups[++i] = jGroup;
1223 jGroup.setStart(sg.getStartRes());
1224 jGroup.setEnd(sg.getEndRes());
1225 jGroup.setName(sg.getName());
1226 if (groupRefs.containsKey(sg))
1228 // group has references so set its ID field
1229 jGroup.setId(groupRefs.get(sg));
1231 ColourSchemeI colourScheme = sg.getColourScheme();
1232 if (colourScheme != null)
1234 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1235 if (groupColourScheme.conservationApplied())
1237 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1239 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1242 setUserColourScheme(colourScheme, userColours, jms));
1246 jGroup.setColour(colourScheme.getSchemeName());
1249 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1251 jGroup.setColour("AnnotationColourGradient");
1252 jGroup.setAnnotationColours(constructAnnotationColours(
1253 (jalview.schemes.AnnotationColourGradient) colourScheme,
1256 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1259 setUserColourScheme(colourScheme, userColours, jms));
1263 jGroup.setColour(colourScheme.getSchemeName());
1266 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1269 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1270 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1271 jGroup.setDisplayText(sg.getDisplayText());
1272 jGroup.setColourText(sg.getColourText());
1273 jGroup.setTextCol1(sg.textColour.getRGB());
1274 jGroup.setTextCol2(sg.textColour2.getRGB());
1275 jGroup.setTextColThreshold(sg.thresholdTextColour);
1276 jGroup.setShowUnconserved(sg.getShowNonconserved());
1277 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1278 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1279 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1280 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1281 for (SequenceI seq : sg.getSequences())
1283 jGroup.addSeq(seqHash(seq));
1287 jms.setJGroup(groups);
1291 // /////////SAVE VIEWPORT
1292 Viewport view = new Viewport();
1293 view.setTitle(ap.alignFrame.getTitle());
1294 view.setSequenceSetId(
1295 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1296 view.setId(av.getViewId());
1297 if (av.getCodingComplement() != null)
1299 view.setComplementId(av.getCodingComplement().getViewId());
1301 view.setViewName(av.getViewName());
1302 view.setGatheredViews(av.isGatherViewsHere());
1304 Rectangle size = ap.av.getExplodedGeometry();
1305 Rectangle position = size;
1308 size = ap.alignFrame.getBounds();
1309 if (av.getCodingComplement() != null)
1311 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1319 view.setXpos(position.x);
1320 view.setYpos(position.y);
1322 view.setWidth(size.width);
1323 view.setHeight(size.height);
1325 view.setStartRes(vpRanges.getStartRes());
1326 view.setStartSeq(vpRanges.getStartSeq());
1328 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1330 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1334 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1336 AnnotationColours ac = constructAnnotationColours(
1337 (jalview.schemes.AnnotationColourGradient) av
1338 .getGlobalColourScheme(),
1341 view.setAnnotationColours(ac);
1342 view.setBgColour("AnnotationColourGradient");
1346 view.setBgColour(ColourSchemeProperty
1347 .getColourName(av.getGlobalColourScheme()));
1350 ResidueShaderI vcs = av.getResidueShading();
1351 ColourSchemeI cs = av.getGlobalColourScheme();
1355 if (vcs.conservationApplied())
1357 view.setConsThreshold(vcs.getConservationInc());
1358 if (cs instanceof jalview.schemes.UserColourScheme)
1360 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1363 view.setPidThreshold(vcs.getThreshold());
1366 view.setConservationSelected(av.getConservationSelected());
1367 view.setPidSelected(av.getAbovePIDThreshold());
1368 view.setFontName(av.font.getName());
1369 view.setFontSize(av.font.getSize());
1370 view.setFontStyle(av.font.getStyle());
1371 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1372 view.setRenderGaps(av.isRenderGaps());
1373 view.setShowAnnotation(av.isShowAnnotation());
1374 view.setShowBoxes(av.getShowBoxes());
1375 view.setShowColourText(av.getColourText());
1376 view.setShowFullId(av.getShowJVSuffix());
1377 view.setRightAlignIds(av.isRightAlignIds());
1378 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1379 view.setShowText(av.getShowText());
1380 view.setShowUnconserved(av.getShowUnconserved());
1381 view.setWrapAlignment(av.getWrapAlignment());
1382 view.setTextCol1(av.getTextColour().getRGB());
1383 view.setTextCol2(av.getTextColour2().getRGB());
1384 view.setTextColThreshold(av.getThresholdTextColour());
1385 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1386 view.setShowSequenceLogo(av.isShowSequenceLogo());
1387 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1388 view.setShowGroupConsensus(av.isShowGroupConsensus());
1389 view.setShowGroupConservation(av.isShowGroupConservation());
1390 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1391 view.setShowDbRefTooltip(av.isShowDBRefs());
1392 view.setFollowHighlight(av.isFollowHighlight());
1393 view.setFollowSelection(av.followSelection);
1394 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1395 if (av.getFeaturesDisplayed() != null)
1397 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1399 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1400 .getFeatureRenderer();
1401 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1403 Vector<String> settingsAdded = new Vector<>();
1404 if (renderOrder != null)
1406 for (String featureType : renderOrder)
1408 Setting setting = new Setting();
1409 setting.setType(featureType);
1412 * save any filter for the feature type
1414 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1415 if (filter != null) {
1416 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1417 FeatureMatcherI firstFilter = filters.next();
1418 setting.setMatcherSet(Jalview2XML.marshalFilter(
1419 firstFilter, filters, filter.isAnded()));
1423 * save colour scheme for the feature type
1425 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1426 if (!fcol.isSimpleColour())
1428 setting.setColour(fcol.getMaxColour().getRGB());
1429 setting.setMincolour(fcol.getMinColour().getRGB());
1430 setting.setMin(fcol.getMin());
1431 setting.setMax(fcol.getMax());
1432 setting.setColourByLabel(fcol.isColourByLabel());
1433 if (fcol.isColourByAttribute())
1435 setting.setAttributeName(fcol.getAttributeName());
1437 setting.setAutoScale(fcol.isAutoScaled());
1438 setting.setThreshold(fcol.getThreshold());
1439 Color noColour = fcol.getNoColour();
1440 if (noColour == null)
1442 setting.setNoValueColour(NoValueColour.NONE);
1444 else if (noColour.equals(fcol.getMaxColour()))
1446 setting.setNoValueColour(NoValueColour.MAX);
1450 setting.setNoValueColour(NoValueColour.MIN);
1452 // -1 = No threshold, 0 = Below, 1 = Above
1453 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1454 : (fcol.isBelowThreshold() ? 0 : -1));
1458 setting.setColour(fcol.getColour().getRGB());
1462 av.getFeaturesDisplayed().isVisible(featureType));
1464 .getOrder(featureType);
1467 setting.setOrder(rorder);
1469 fs.addSetting(setting);
1470 settingsAdded.addElement(featureType);
1474 // is groups actually supposed to be a map here ?
1475 Iterator<String> en = fr.getFeatureGroups().iterator();
1476 Vector<String> groupsAdded = new Vector<>();
1477 while (en.hasNext())
1479 String grp = en.next();
1480 if (groupsAdded.contains(grp))
1484 Group g = new Group();
1486 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1489 groupsAdded.addElement(grp);
1491 jms.setFeatureSettings(fs);
1494 if (av.hasHiddenColumns())
1496 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1497 .getHiddenColumns();
1500 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1504 Iterator<int[]> hiddenRegions = hidden.iterator();
1505 while (hiddenRegions.hasNext())
1507 int[] region = hiddenRegions.next();
1508 HiddenColumns hc = new HiddenColumns();
1509 hc.setStart(region[0]);
1510 hc.setEnd(region[1]);
1511 view.addHiddenColumns(hc);
1515 if (calcIdSet.size() > 0)
1517 for (String calcId : calcIdSet)
1519 if (calcId.trim().length() > 0)
1521 CalcIdParam cidp = createCalcIdParam(calcId, av);
1522 // Some calcIds have no parameters.
1525 view.addCalcIdParam(cidp);
1531 jms.addViewport(view);
1533 object.setJalviewModelSequence(jms);
1534 object.getVamsasModel().addSequenceSet(vamsasSet);
1536 if (jout != null && fileName != null)
1538 // We may not want to write the object to disk,
1539 // eg we can copy the alignViewport to a new view object
1540 // using save and then load
1543 System.out.println("Writing jar entry " + fileName);
1544 JarEntry entry = new JarEntry(fileName);
1545 jout.putNextEntry(entry);
1546 PrintWriter pout = new PrintWriter(
1547 new OutputStreamWriter(jout, UTF_8));
1548 Marshaller marshaller = new Marshaller(pout);
1549 marshaller.marshal(object);
1552 } catch (Exception ex)
1554 // TODO: raise error in GUI if marshalling failed.
1555 ex.printStackTrace();
1562 * Writes PCA viewer attributes and computed values to an XML model object and adds it to the JalviewModel. Any exceptions are reported by logging.
1564 protected void savePCA(PCAPanel panel, JalviewModelSequence jms)
1568 PcaViewer viewer = new PcaViewer();
1569 viewer.setHeight(panel.getHeight());
1570 viewer.setWidth(panel.getWidth());
1571 viewer.setXpos(panel.getX());
1572 viewer.setYpos(panel.getY());
1573 viewer.setTitle(panel.getTitle());
1574 PCAModel pcaModel = panel.getPcaModel();
1575 viewer.setScoreModelName(pcaModel.getScoreModelName());
1576 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1577 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1578 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1579 viewer.setBgColour(panel.getRotatableCanvas().getBackgroundColour().getRGB());
1580 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1581 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1582 SeqPointMin spmin = new SeqPointMin();
1583 spmin.setXPos(spMin[0]);
1584 spmin.setYPos(spMin[1]);
1585 spmin.setZPos(spMin[2]);
1586 viewer.setSeqPointMin(spmin);
1587 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1588 SeqPointMax spmax = new SeqPointMax();
1589 spmax.setXPos(spMax[0]);
1590 spmax.setYPos(spMax[1]);
1591 spmax.setZPos(spMax[2]);
1592 viewer.setSeqPointMax(spmax);
1593 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1594 viewer.setLinkToAllViews(panel.getRotatableCanvas().isApplyToAllViews());
1595 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1596 viewer.setIncludeGaps(sp.includeGaps());
1597 viewer.setMatchGaps(sp.matchGaps());
1598 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1599 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1602 * sequence points on display
1604 for (jalview.datamodel.SequencePoint spt : pcaModel
1605 .getSequencePoints())
1607 SequencePoint point = new SequencePoint();
1608 point.setSequenceRef(seqHash(spt.getSequence()));
1609 point.setXPos(spt.coord.x);
1610 point.setYPos(spt.coord.y);
1611 point.setZPos(spt.coord.z);
1612 viewer.addSequencePoint(point);
1616 * (end points of) axes on display
1618 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1620 Axis axis = new Axis();
1624 viewer.addAxis(axis);
1628 * raw PCA data (note we are not restoring PCA inputs here -
1629 * alignment view, score model, similarity parameters)
1631 PcaData data = new PcaData();
1632 viewer.setPcaData(data);
1633 PCA pca = pcaModel.getPcaData();
1635 PairwiseMatrix pm = new PairwiseMatrix();
1636 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1637 data.setPairwiseMatrix(pm);
1639 TridiagonalMatrix tm = new TridiagonalMatrix();
1640 saveDoubleMatrix(pca.getTridiagonal(), tm);
1641 data.setTridiagonalMatrix(tm);
1643 EigenMatrix eigenMatrix = new EigenMatrix();
1644 data.setEigenMatrix(eigenMatrix);
1645 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1647 jms.addPcaViewer(viewer);
1648 } catch (Throwable t)
1650 Cache.log.error("Error saving PCA: " + t.getMessage());
1655 * Stores values from a matrix into an XML element, including (if present) the
1660 * @see #loadDoubleMatrix(DoubleMatrix)
1662 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1664 xmlMatrix.setRows(m.height());
1665 xmlMatrix.setColumns(m.width());
1666 for (int i = 0; i < m.height(); i++)
1668 Row row = new Row();
1669 for (int j = 0; j < m.width(); j++)
1671 row.addV(m.getValue(i, j));
1673 xmlMatrix.addRow(row);
1675 if (m.getD() != null)
1677 D dVector = new D();
1678 dVector.setV(m.getD());
1679 xmlMatrix.setD(dVector);
1681 if (m.getE() != null)
1683 E eVector = new E();
1684 eVector.setV(m.getE());
1685 xmlMatrix.setE(eVector);
1690 * Loads XML matrix data into a new Matrix object, including the D and/or E
1691 * vectors (if present)
1695 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1697 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1699 int rows = mData.getRows();
1700 double[][] vals = new double[rows][];
1702 for (int i = 0; i < rows; i++)
1704 vals[i] = mData.getRow(i).getV();
1707 MatrixI m = new Matrix(vals);
1709 if (mData.getD() != null) {
1710 m.setD(mData.getD().getV());
1712 if (mData.getE() != null)
1714 m.setE(mData.getE().getV());
1721 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1722 * for each viewer, with
1724 * <li>viewer geometry (position, size, split pane divider location)</li>
1725 * <li>index of the selected structure in the viewer (currently shows gapped
1727 * <li>the id of the annotation holding RNA secondary structure</li>
1728 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1730 * Varna viewer state is also written out (in native Varna XML) to separate
1731 * project jar entries. A separate entry is written for each RNA structure
1732 * displayed, with the naming convention
1734 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1742 * @param storeDataset
1744 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1745 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1746 boolean storeDataset)
1748 if (Desktop.desktop == null)
1752 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1753 for (int f = frames.length - 1; f > -1; f--)
1755 if (frames[f] instanceof AppVarna)
1757 AppVarna varna = (AppVarna) frames[f];
1759 * link the sequence to every viewer that is showing it and is linked to
1760 * its alignment panel
1762 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1764 String viewId = varna.getViewId();
1765 RnaViewer rna = new RnaViewer();
1766 rna.setViewId(viewId);
1767 rna.setTitle(varna.getTitle());
1768 rna.setXpos(varna.getX());
1769 rna.setYpos(varna.getY());
1770 rna.setWidth(varna.getWidth());
1771 rna.setHeight(varna.getHeight());
1772 rna.setDividerLocation(varna.getDividerLocation());
1773 rna.setSelectedRna(varna.getSelectedIndex());
1774 jseq.addRnaViewer(rna);
1777 * Store each Varna panel's state once in the project per sequence.
1778 * First time through only (storeDataset==false)
1780 // boolean storeSessions = false;
1781 // String sequenceViewId = viewId + seqsToIds.get(jds);
1782 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1784 // viewIds.add(sequenceViewId);
1785 // storeSessions = true;
1787 for (RnaModel model : varna.getModels())
1789 if (model.seq == jds)
1792 * VARNA saves each view (sequence or alignment secondary
1793 * structure, gapped or trimmed) as a separate XML file
1795 String jarEntryName = rnaSessions.get(model);
1796 if (jarEntryName == null)
1799 String varnaStateFile = varna.getStateInfo(model.rna);
1800 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1801 copyFileToJar(jout, varnaStateFile, jarEntryName);
1802 rnaSessions.put(model, jarEntryName);
1804 SecondaryStructure ss = new SecondaryStructure();
1805 String annotationId = varna.getAnnotation(jds).annotationId;
1806 ss.setAnnotationId(annotationId);
1807 ss.setViewerState(jarEntryName);
1808 ss.setGapped(model.gapped);
1809 ss.setTitle(model.title);
1810 rna.addSecondaryStructure(ss);
1819 * Copy the contents of a file to a new entry added to the output jar
1823 * @param jarEntryName
1825 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1826 String jarEntryName)
1828 DataInputStream dis = null;
1831 File file = new File(infilePath);
1832 if (file.exists() && jout != null)
1834 dis = new DataInputStream(new FileInputStream(file));
1835 byte[] data = new byte[(int) file.length()];
1836 dis.readFully(data);
1837 writeJarEntry(jout, jarEntryName, data);
1839 } catch (Exception ex)
1841 ex.printStackTrace();
1849 } catch (IOException e)
1858 * Write the data to a new entry of given name in the output jar file
1861 * @param jarEntryName
1863 * @throws IOException
1865 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1866 byte[] data) throws IOException
1870 System.out.println("Writing jar entry " + jarEntryName);
1871 jout.putNextEntry(new JarEntry(jarEntryName));
1872 DataOutputStream dout = new DataOutputStream(jout);
1873 dout.write(data, 0, data.length);
1880 * Save the state of a structure viewer
1885 * the archive XML element under which to save the state
1888 * @param matchedFile
1892 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1893 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1894 String matchedFile, StructureViewerBase viewFrame)
1896 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1899 * Look for any bindings for this viewer to the PDB file of interest
1900 * (including part matches excluding chain id)
1902 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1904 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1905 final String pdbId = pdbentry.getId();
1906 if (!pdbId.equals(entry.getId())
1907 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1908 .startsWith(pdbId.toLowerCase())))
1911 * not interested in a binding to a different PDB entry here
1915 if (matchedFile == null)
1917 matchedFile = pdbentry.getFile();
1919 else if (!matchedFile.equals(pdbentry.getFile()))
1922 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1923 + pdbentry.getFile());
1927 // can get at it if the ID
1928 // match is ambiguous (e.g.
1931 for (int smap = 0; smap < viewFrame.getBinding()
1932 .getSequence()[peid].length; smap++)
1934 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1935 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1937 StructureState state = new StructureState();
1938 state.setVisible(true);
1939 state.setXpos(viewFrame.getX());
1940 state.setYpos(viewFrame.getY());
1941 state.setWidth(viewFrame.getWidth());
1942 state.setHeight(viewFrame.getHeight());
1943 final String viewId = viewFrame.getViewId();
1944 state.setViewId(viewId);
1945 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1946 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1947 state.setColourByJmol(viewFrame.isColouredByViewer());
1948 state.setType(viewFrame.getViewerType().toString());
1949 pdb.addStructureState(state);
1957 * Populates the AnnotationColours xml for save. This captures the settings of
1958 * the options in the 'Colour by Annotation' dialog.
1961 * @param userColours
1965 private AnnotationColours constructAnnotationColours(
1966 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1967 JalviewModelSequence jms)
1969 AnnotationColours ac = new AnnotationColours();
1970 ac.setAboveThreshold(acg.getAboveThreshold());
1971 ac.setThreshold(acg.getAnnotationThreshold());
1972 // 2.10.2 save annotationId (unique) not annotation label
1973 ac.setAnnotation(acg.getAnnotation().annotationId);
1974 if (acg.getBaseColour() instanceof UserColourScheme)
1977 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1982 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1985 ac.setMaxColour(acg.getMaxColour().getRGB());
1986 ac.setMinColour(acg.getMinColour().getRGB());
1987 ac.setPerSequence(acg.isSeqAssociated());
1988 ac.setPredefinedColours(acg.isPredefinedColours());
1992 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1993 IdentityHashMap<SequenceGroup, String> groupRefs,
1994 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1995 SequenceSet vamsasSet)
1998 for (int i = 0; i < aa.length; i++)
2000 Annotation an = new Annotation();
2002 AlignmentAnnotation annotation = aa[i];
2003 if (annotation.annotationId != null)
2005 annotationIds.put(annotation.annotationId, annotation);
2008 an.setId(annotation.annotationId);
2010 an.setVisible(annotation.visible);
2012 an.setDescription(annotation.description);
2014 if (annotation.sequenceRef != null)
2016 // 2.9 JAL-1781 xref on sequence id rather than name
2017 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2019 if (annotation.groupRef != null)
2021 String groupIdr = groupRefs.get(annotation.groupRef);
2022 if (groupIdr == null)
2024 // make a locally unique String
2025 groupRefs.put(annotation.groupRef,
2026 groupIdr = ("" + System.currentTimeMillis()
2027 + annotation.groupRef.getName()
2028 + groupRefs.size()));
2030 an.setGroupRef(groupIdr.toString());
2033 // store all visualization attributes for annotation
2034 an.setGraphHeight(annotation.graphHeight);
2035 an.setCentreColLabels(annotation.centreColLabels);
2036 an.setScaleColLabels(annotation.scaleColLabel);
2037 an.setShowAllColLabels(annotation.showAllColLabels);
2038 an.setBelowAlignment(annotation.belowAlignment);
2040 if (annotation.graph > 0)
2043 an.setGraphType(annotation.graph);
2044 an.setGraphGroup(annotation.graphGroup);
2045 if (annotation.getThreshold() != null)
2047 ThresholdLine line = new ThresholdLine();
2048 line.setLabel(annotation.getThreshold().label);
2049 line.setValue(annotation.getThreshold().value);
2050 line.setColour(annotation.getThreshold().colour.getRGB());
2051 an.setThresholdLine(line);
2059 an.setLabel(annotation.label);
2061 if (annotation == av.getAlignmentQualityAnnot()
2062 || annotation == av.getAlignmentConservationAnnotation()
2063 || annotation == av.getAlignmentConsensusAnnotation()
2064 || annotation.autoCalculated)
2066 // new way of indicating autocalculated annotation -
2067 an.setAutoCalculated(annotation.autoCalculated);
2069 if (annotation.hasScore())
2071 an.setScore(annotation.getScore());
2074 if (annotation.getCalcId() != null)
2076 calcIdSet.add(annotation.getCalcId());
2077 an.setCalcId(annotation.getCalcId());
2079 if (annotation.hasProperties())
2081 for (String pr : annotation.getProperties())
2083 Property prop = new Property();
2085 prop.setValue(annotation.getProperty(pr));
2086 an.addProperty(prop);
2090 AnnotationElement ae;
2091 if (annotation.annotations != null)
2093 an.setScoreOnly(false);
2094 for (int a = 0; a < annotation.annotations.length; a++)
2096 if ((annotation == null) || (annotation.annotations[a] == null))
2101 ae = new AnnotationElement();
2102 if (annotation.annotations[a].description != null)
2104 ae.setDescription(annotation.annotations[a].description);
2106 if (annotation.annotations[a].displayCharacter != null)
2108 ae.setDisplayCharacter(
2109 annotation.annotations[a].displayCharacter);
2112 if (!Float.isNaN(annotation.annotations[a].value))
2114 ae.setValue(annotation.annotations[a].value);
2118 if (annotation.annotations[a].secondaryStructure > ' ')
2120 ae.setSecondaryStructure(
2121 annotation.annotations[a].secondaryStructure + "");
2124 if (annotation.annotations[a].colour != null
2125 && annotation.annotations[a].colour != java.awt.Color.black)
2127 ae.setColour(annotation.annotations[a].colour.getRGB());
2130 an.addAnnotationElement(ae);
2131 if (annotation.autoCalculated)
2133 // only write one non-null entry into the annotation row -
2134 // sufficient to get the visualization attributes necessary to
2142 an.setScoreOnly(true);
2144 if (!storeDS || (storeDS && !annotation.autoCalculated))
2146 // skip autocalculated annotation - these are only provided for
2148 vamsasSet.addAnnotation(an);
2154 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2156 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2157 if (settings != null)
2159 CalcIdParam vCalcIdParam = new CalcIdParam();
2160 vCalcIdParam.setCalcId(calcId);
2161 vCalcIdParam.addServiceURL(settings.getServiceURI());
2162 // generic URI allowing a third party to resolve another instance of the
2163 // service used for this calculation
2164 for (String urls : settings.getServiceURLs())
2166 vCalcIdParam.addServiceURL(urls);
2168 vCalcIdParam.setVersion("1.0");
2169 if (settings.getPreset() != null)
2171 WsParamSetI setting = settings.getPreset();
2172 vCalcIdParam.setName(setting.getName());
2173 vCalcIdParam.setDescription(setting.getDescription());
2177 vCalcIdParam.setName("");
2178 vCalcIdParam.setDescription("Last used parameters");
2180 // need to be able to recover 1) settings 2) user-defined presets or
2181 // recreate settings from preset 3) predefined settings provided by
2182 // service - or settings that can be transferred (or discarded)
2183 vCalcIdParam.setParameters(
2184 settings.getWsParamFile().replace("\n", "|\\n|"));
2185 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2186 // todo - decide if updateImmediately is needed for any projects.
2188 return vCalcIdParam;
2193 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2196 if (calcIdParam.getVersion().equals("1.0"))
2198 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2199 .getPreferredServiceFor(calcIdParam.getServiceURL());
2200 if (service != null)
2202 WsParamSetI parmSet = null;
2205 parmSet = service.getParamStore().parseServiceParameterFile(
2206 calcIdParam.getName(), calcIdParam.getDescription(),
2207 calcIdParam.getServiceURL(),
2208 calcIdParam.getParameters().replace("|\\n|", "\n"));
2209 } catch (IOException x)
2211 warn("Couldn't parse parameter data for "
2212 + calcIdParam.getCalcId(), x);
2215 List<ArgumentI> argList = null;
2216 if (calcIdParam.getName().length() > 0)
2218 parmSet = service.getParamStore()
2219 .getPreset(calcIdParam.getName());
2220 if (parmSet != null)
2222 // TODO : check we have a good match with settings in AACon -
2223 // otherwise we'll need to create a new preset
2228 argList = parmSet.getArguments();
2231 AAConSettings settings = new AAConSettings(
2232 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2233 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2234 calcIdParam.isNeedsUpdate());
2239 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2243 throw new Error(MessageManager.formatMessage(
2244 "error.unsupported_version_calcIdparam", new Object[]
2245 { calcIdParam.toString() }));
2249 * External mapping between jalview objects and objects yielding a valid and
2250 * unique object ID string. This is null for normal Jalview project IO, but
2251 * non-null when a jalview project is being read or written as part of a
2254 IdentityHashMap jv2vobj = null;
2257 * Construct a unique ID for jvobj using either existing bindings or if none
2258 * exist, the result of the hashcode call for the object.
2261 * jalview data object
2262 * @return unique ID for referring to jvobj
2264 private String makeHashCode(Object jvobj, String altCode)
2266 if (jv2vobj != null)
2268 Object id = jv2vobj.get(jvobj);
2271 return id.toString();
2273 // check string ID mappings
2274 if (jvids2vobj != null && jvobj instanceof String)
2276 id = jvids2vobj.get(jvobj);
2280 return id.toString();
2282 // give up and warn that something has gone wrong
2283 warn("Cannot find ID for object in external mapping : " + jvobj);
2289 * return local jalview object mapped to ID, if it exists
2293 * @return null or object bound to idcode
2295 private Object retrieveExistingObj(String idcode)
2297 if (idcode != null && vobj2jv != null)
2299 return vobj2jv.get(idcode);
2305 * binding from ID strings from external mapping table to jalview data model
2308 private Hashtable vobj2jv;
2310 private Sequence createVamsasSequence(String id, SequenceI jds)
2312 return createVamsasSequence(true, id, jds, null);
2315 private Sequence createVamsasSequence(boolean recurse, String id,
2316 SequenceI jds, SequenceI parentseq)
2318 Sequence vamsasSeq = new Sequence();
2319 vamsasSeq.setId(id);
2320 vamsasSeq.setName(jds.getName());
2321 vamsasSeq.setSequence(jds.getSequenceAsString());
2322 vamsasSeq.setDescription(jds.getDescription());
2323 jalview.datamodel.DBRefEntry[] dbrefs = null;
2324 if (jds.getDatasetSequence() != null)
2326 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2330 // seqId==dsseqid so we can tell which sequences really are
2331 // dataset sequences only
2332 vamsasSeq.setDsseqid(id);
2333 dbrefs = jds.getDBRefs();
2334 if (parentseq == null)
2341 for (int d = 0; d < dbrefs.length; d++)
2343 DBRef dbref = new DBRef();
2344 dbref.setSource(dbrefs[d].getSource());
2345 dbref.setVersion(dbrefs[d].getVersion());
2346 dbref.setAccessionId(dbrefs[d].getAccessionId());
2347 if (dbrefs[d].hasMap())
2349 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2351 dbref.setMapping(mp);
2353 vamsasSeq.addDBRef(dbref);
2359 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2360 SequenceI parentseq, SequenceI jds, boolean recurse)
2363 if (jmp.getMap() != null)
2367 jalview.util.MapList mlst = jmp.getMap();
2368 List<int[]> r = mlst.getFromRanges();
2369 for (int[] range : r)
2371 MapListFrom mfrom = new MapListFrom();
2372 mfrom.setStart(range[0]);
2373 mfrom.setEnd(range[1]);
2374 mp.addMapListFrom(mfrom);
2376 r = mlst.getToRanges();
2377 for (int[] range : r)
2379 MapListTo mto = new MapListTo();
2380 mto.setStart(range[0]);
2381 mto.setEnd(range[1]);
2382 mp.addMapListTo(mto);
2384 mp.setMapFromUnit(mlst.getFromRatio());
2385 mp.setMapToUnit(mlst.getToRatio());
2386 if (jmp.getTo() != null)
2388 MappingChoice mpc = new MappingChoice();
2390 // check/create ID for the sequence referenced by getTo()
2393 SequenceI ps = null;
2394 if (parentseq != jmp.getTo()
2395 && parentseq.getDatasetSequence() != jmp.getTo())
2397 // chaining dbref rather than a handshaking one
2398 jmpid = seqHash(ps = jmp.getTo());
2402 jmpid = seqHash(ps = parentseq);
2404 mpc.setDseqFor(jmpid);
2405 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2407 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2408 seqRefIds.put(mpc.getDseqFor(), ps);
2412 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2415 mp.setMappingChoice(mpc);
2421 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2422 List<UserColourScheme> userColours, JalviewModelSequence jms)
2425 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2426 boolean newucs = false;
2427 if (!userColours.contains(ucs))
2429 userColours.add(ucs);
2432 id = "ucs" + userColours.indexOf(ucs);
2435 // actually create the scheme's entry in the XML model
2436 java.awt.Color[] colours = ucs.getColours();
2437 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2438 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2440 for (int i = 0; i < colours.length; i++)
2442 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2443 col.setName(ResidueProperties.aa[i]);
2444 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2445 jbucs.addColour(col);
2447 if (ucs.getLowerCaseColours() != null)
2449 colours = ucs.getLowerCaseColours();
2450 for (int i = 0; i < colours.length; i++)
2452 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2453 col.setName(ResidueProperties.aa[i].toLowerCase());
2454 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2455 jbucs.addColour(col);
2460 uc.setUserColourScheme(jbucs);
2461 jms.addUserColours(uc);
2467 jalview.schemes.UserColourScheme getUserColourScheme(
2468 JalviewModelSequence jms, String id)
2470 UserColours[] uc = jms.getUserColours();
2471 UserColours colours = null;
2473 for (int i = 0; i < uc.length; i++)
2475 if (uc[i].getId().equals(id))
2483 java.awt.Color[] newColours = new java.awt.Color[24];
2485 for (int i = 0; i < 24; i++)
2487 newColours[i] = new java.awt.Color(Integer.parseInt(
2488 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2491 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2494 if (colours.getUserColourScheme().getColourCount() > 24)
2496 newColours = new java.awt.Color[23];
2497 for (int i = 0; i < 23; i++)
2499 newColours[i] = new java.awt.Color(Integer.parseInt(
2500 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2503 ucs.setLowerCaseColours(newColours);
2510 * contains last error message (if any) encountered by XML loader.
2512 String errorMessage = null;
2515 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2516 * exceptions are raised during project XML parsing
2518 public boolean attemptversion1parse = true;
2521 * Load a jalview project archive from a jar file
2524 * - HTTP URL or filename
2526 public AlignFrame loadJalviewAlign(final String file)
2529 jalview.gui.AlignFrame af = null;
2533 // create list to store references for any new Jmol viewers created
2534 newStructureViewers = new Vector<>();
2535 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2536 // Workaround is to make sure caller implements the JarInputStreamProvider
2538 // so we can re-open the jar input stream for each entry.
2540 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2541 af = loadJalviewAlign(jprovider);
2542 af.setMenusForViewport();
2544 } catch (MalformedURLException e)
2546 errorMessage = "Invalid URL format for '" + file + "'";
2552 SwingUtilities.invokeAndWait(new Runnable()
2557 setLoadingFinishedForNewStructureViewers();
2560 } catch (Exception x)
2562 System.err.println("Error loading alignment: " + x.getMessage());
2568 private jarInputStreamProvider createjarInputStreamProvider(
2569 final String file) throws MalformedURLException
2572 errorMessage = null;
2573 uniqueSetSuffix = null;
2575 viewportsAdded.clear();
2576 frefedSequence = null;
2578 if (file.startsWith("http://"))
2580 url = new URL(file);
2582 final URL _url = url;
2583 return new jarInputStreamProvider()
2587 public JarInputStream getJarInputStream() throws IOException
2591 return new JarInputStream(_url.openStream());
2595 return new JarInputStream(new FileInputStream(file));
2600 public String getFilename()
2608 * Recover jalview session from a jalview project archive. Caller may
2609 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2610 * themselves. Any null fields will be initialised with default values,
2611 * non-null fields are left alone.
2616 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2618 errorMessage = null;
2619 if (uniqueSetSuffix == null)
2621 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2623 if (seqRefIds == null)
2627 AlignFrame af = null, _af = null;
2628 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2629 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2630 final String file = jprovider.getFilename();
2633 JarInputStream jin = null;
2634 JarEntry jarentry = null;
2639 jin = jprovider.getJarInputStream();
2640 for (int i = 0; i < entryCount; i++)
2642 jarentry = jin.getNextJarEntry();
2645 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2647 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2648 JalviewModel object = new JalviewModel();
2650 Unmarshaller unmar = new Unmarshaller(object);
2651 unmar.setValidation(false);
2652 object = (JalviewModel) unmar.unmarshal(in);
2653 if (true) // !skipViewport(object))
2655 _af = loadFromObject(object, file, true, jprovider);
2656 if (_af != null && object.getJalviewModelSequence()
2657 .getViewportCount() > 0)
2661 // store a reference to the first view
2664 if (_af.viewport.isGatherViewsHere())
2666 // if this is a gathered view, keep its reference since
2667 // after gathering views, only this frame will remain
2669 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2671 // Save dataset to register mappings once all resolved
2672 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2673 af.viewport.getAlignment().getDataset());
2678 else if (jarentry != null)
2680 // Some other file here.
2683 } while (jarentry != null);
2684 resolveFrefedSequences();
2685 } catch (IOException ex)
2687 ex.printStackTrace();
2688 errorMessage = "Couldn't locate Jalview XML file : " + file;
2690 "Exception whilst loading jalview XML file : " + ex + "\n");
2691 } catch (Exception ex)
2693 System.err.println("Parsing as Jalview Version 2 file failed.");
2694 ex.printStackTrace(System.err);
2695 if (attemptversion1parse)
2697 // Is Version 1 Jar file?
2700 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2701 } catch (Exception ex2)
2703 System.err.println("Exception whilst loading as jalviewXMLV1:");
2704 ex2.printStackTrace();
2708 if (Desktop.instance != null)
2710 Desktop.instance.stopLoading();
2714 System.out.println("Successfully loaded archive file");
2717 ex.printStackTrace();
2720 "Exception whilst loading jalview XML file : " + ex + "\n");
2721 } catch (OutOfMemoryError e)
2723 // Don't use the OOM Window here
2724 errorMessage = "Out of memory loading jalview XML file";
2725 System.err.println("Out of memory whilst loading jalview XML file");
2726 e.printStackTrace();
2730 * Regather multiple views (with the same sequence set id) to the frame (if
2731 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2732 * views instead of separate frames. Note this doesn't restore a state where
2733 * some expanded views in turn have tabbed views - the last "first tab" read
2734 * in will play the role of gatherer for all.
2736 for (AlignFrame fr : gatherToThisFrame.values())
2738 Desktop.instance.gatherViews(fr);
2741 restoreSplitFrames();
2742 for (AlignmentI ds : importedDatasets.keySet())
2744 if (ds.getCodonFrames() != null)
2746 StructureSelectionManager
2747 .getStructureSelectionManager(Desktop.instance)
2748 .registerMappings(ds.getCodonFrames());
2751 if (errorMessage != null)
2756 if (Desktop.instance != null)
2758 Desktop.instance.stopLoading();
2765 * Try to reconstruct and display SplitFrame windows, where each contains
2766 * complementary dna and protein alignments. Done by pairing up AlignFrame
2767 * objects (created earlier) which have complementary viewport ids associated.
2769 protected void restoreSplitFrames()
2771 List<SplitFrame> gatherTo = new ArrayList<>();
2772 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2773 Map<String, AlignFrame> dna = new HashMap<>();
2776 * Identify the DNA alignments
2778 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2781 AlignFrame af = candidate.getValue();
2782 if (af.getViewport().getAlignment().isNucleotide())
2784 dna.put(candidate.getKey().getId(), af);
2789 * Try to match up the protein complements
2791 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2794 AlignFrame af = candidate.getValue();
2795 if (!af.getViewport().getAlignment().isNucleotide())
2797 String complementId = candidate.getKey().getComplementId();
2798 // only non-null complements should be in the Map
2799 if (complementId != null && dna.containsKey(complementId))
2801 final AlignFrame dnaFrame = dna.get(complementId);
2802 SplitFrame sf = createSplitFrame(dnaFrame, af);
2803 addedToSplitFrames.add(dnaFrame);
2804 addedToSplitFrames.add(af);
2805 dnaFrame.setMenusForViewport();
2806 af.setMenusForViewport();
2807 if (af.viewport.isGatherViewsHere())
2816 * Open any that we failed to pair up (which shouldn't happen!) as
2817 * standalone AlignFrame's.
2819 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2822 AlignFrame af = candidate.getValue();
2823 if (!addedToSplitFrames.contains(af))
2825 Viewport view = candidate.getKey();
2826 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2828 af.setMenusForViewport();
2829 System.err.println("Failed to restore view " + view.getTitle()
2830 + " to split frame");
2835 * Gather back into tabbed views as flagged.
2837 for (SplitFrame sf : gatherTo)
2839 Desktop.instance.gatherViews(sf);
2842 splitFrameCandidates.clear();
2846 * Construct and display one SplitFrame holding DNA and protein alignments.
2849 * @param proteinFrame
2852 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2853 AlignFrame proteinFrame)
2855 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2856 String title = MessageManager.getString("label.linked_view_title");
2857 int width = (int) dnaFrame.getBounds().getWidth();
2858 int height = (int) (dnaFrame.getBounds().getHeight()
2859 + proteinFrame.getBounds().getHeight() + 50);
2862 * SplitFrame location is saved to both enclosed frames
2864 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2865 Desktop.addInternalFrame(splitFrame, title, width, height);
2868 * And compute cDNA consensus (couldn't do earlier with consensus as
2869 * mappings were not yet present)
2871 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2877 * check errorMessage for a valid error message and raise an error box in the
2878 * GUI or write the current errorMessage to stderr and then clear the error
2881 protected void reportErrors()
2883 reportErrors(false);
2886 protected void reportErrors(final boolean saving)
2888 if (errorMessage != null)
2890 final String finalErrorMessage = errorMessage;
2893 javax.swing.SwingUtilities.invokeLater(new Runnable()
2898 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2900 "Error " + (saving ? "saving" : "loading")
2902 JvOptionPane.WARNING_MESSAGE);
2908 System.err.println("Problem loading Jalview file: " + errorMessage);
2911 errorMessage = null;
2914 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2917 * when set, local views will be updated from view stored in JalviewXML
2918 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2919 * sync if this is set to true.
2921 private final boolean updateLocalViews = false;
2924 * Returns the path to a temporary file holding the PDB file for the given PDB
2925 * id. The first time of asking, searches for a file of that name in the
2926 * Jalview project jar, and copies it to a new temporary file. Any repeat
2927 * requests just return the path to the file previously created.
2933 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2936 if (alreadyLoadedPDB.containsKey(pdbId))
2938 return alreadyLoadedPDB.get(pdbId).toString();
2941 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2943 if (tempFile != null)
2945 alreadyLoadedPDB.put(pdbId, tempFile);
2951 * Copies the jar entry of given name to a new temporary file and returns the
2952 * path to the file, or null if the entry is not found.
2955 * @param jarEntryName
2957 * a prefix for the temporary file name, must be at least three
2960 * null or original file - so new file can be given the same suffix
2964 protected String copyJarEntry(jarInputStreamProvider jprovider,
2965 String jarEntryName, String prefix, String origFile)
2967 BufferedReader in = null;
2968 PrintWriter out = null;
2969 String suffix = ".tmp";
2970 if (origFile == null)
2972 origFile = jarEntryName;
2974 int sfpos = origFile.lastIndexOf(".");
2975 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2977 suffix = "." + origFile.substring(sfpos + 1);
2981 JarInputStream jin = jprovider.getJarInputStream();
2983 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2984 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2985 * FileInputStream(jprovider)); }
2988 JarEntry entry = null;
2991 entry = jin.getNextJarEntry();
2992 } while (entry != null && !entry.getName().equals(jarEntryName));
2995 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2996 File outFile = File.createTempFile(prefix, suffix);
2997 outFile.deleteOnExit();
2998 out = new PrintWriter(new FileOutputStream(outFile));
3001 while ((data = in.readLine()) != null)
3006 String t = outFile.getAbsolutePath();
3011 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3013 } catch (Exception ex)
3015 ex.printStackTrace();
3023 } catch (IOException e)
3037 private class JvAnnotRow
3039 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3046 * persisted version of annotation row from which to take vis properties
3048 public jalview.datamodel.AlignmentAnnotation template;
3051 * original position of the annotation row in the alignment
3057 * Load alignment frame from jalview XML DOM object
3062 * filename source string
3063 * @param loadTreesAndStructures
3064 * when false only create Viewport
3066 * data source provider
3067 * @return alignment frame created from view stored in DOM
3069 AlignFrame loadFromObject(JalviewModel object, String file,
3070 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3072 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
3073 Sequence[] vamsasSeq = vamsasSet.getSequence();
3075 JalviewModelSequence jms = object.getJalviewModelSequence();
3077 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3080 // ////////////////////////////////
3081 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3084 // If we just load in the same jar file again, the sequenceSetId
3085 // will be the same, and we end up with multiple references
3086 // to the same sequenceSet. We must modify this id on load
3087 // so that each load of the file gives a unique id
3090 * used to resolve correct alignment dataset for alignments with multiple
3093 String uniqueSeqSetId = null;
3094 String viewId = null;
3097 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3098 viewId = (view.getId() == null ? null
3099 : view.getId() + uniqueSetSuffix);
3102 // ////////////////////////////////
3105 List<SequenceI> hiddenSeqs = null;
3107 List<SequenceI> tmpseqs = new ArrayList<>();
3109 boolean multipleView = false;
3110 SequenceI referenceseqForView = null;
3111 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3112 int vi = 0; // counter in vamsasSeq array
3113 for (int i = 0; i < jseqs.length; i++)
3115 String seqId = jseqs[i].getId();
3117 SequenceI tmpSeq = seqRefIds.get(seqId);
3120 if (!incompleteSeqs.containsKey(seqId))
3122 // may not need this check, but keep it for at least 2.9,1 release
3123 if (tmpSeq.getStart() != jseqs[i].getStart()
3124 || tmpSeq.getEnd() != jseqs[i].getEnd())
3127 "Warning JAL-2154 regression: updating start/end for sequence "
3128 + tmpSeq.toString() + " to " + jseqs[i]);
3133 incompleteSeqs.remove(seqId);
3135 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
3137 // most likely we are reading a dataset XML document so
3138 // update from vamsasSeq section of XML for this sequence
3139 tmpSeq.setName(vamsasSeq[vi].getName());
3140 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
3141 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
3146 // reading multiple views, so vamsasSeq set is a subset of JSeq
3147 multipleView = true;
3149 tmpSeq.setStart(jseqs[i].getStart());
3150 tmpSeq.setEnd(jseqs[i].getEnd());
3151 tmpseqs.add(tmpSeq);
3155 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
3156 vamsasSeq[vi].getSequence());
3157 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
3158 tmpSeq.setStart(jseqs[i].getStart());
3159 tmpSeq.setEnd(jseqs[i].getEnd());
3160 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3161 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
3162 tmpseqs.add(tmpSeq);
3166 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
3168 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3171 if (jseqs[i].getHidden())
3173 if (hiddenSeqs == null)
3175 hiddenSeqs = new ArrayList<>();
3178 hiddenSeqs.add(tmpSeq);
3183 // Create the alignment object from the sequence set
3184 // ///////////////////////////////
3185 SequenceI[] orderedSeqs = tmpseqs
3186 .toArray(new SequenceI[tmpseqs.size()]);
3188 AlignmentI al = null;
3189 // so we must create or recover the dataset alignment before going further
3190 // ///////////////////////////////
3191 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3193 // older jalview projects do not have a dataset - so creat alignment and
3195 al = new Alignment(orderedSeqs);
3196 al.setDataset(null);
3200 boolean isdsal = object.getJalviewModelSequence()
3201 .getViewportCount() == 0;
3204 // we are importing a dataset record, so
3205 // recover reference to an alignment already materialsed as dataset
3206 al = getDatasetFor(vamsasSet.getDatasetId());
3210 // materialse the alignment
3211 al = new Alignment(orderedSeqs);
3215 addDatasetRef(vamsasSet.getDatasetId(), al);
3218 // finally, verify all data in vamsasSet is actually present in al
3219 // passing on flag indicating if it is actually a stored dataset
3220 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3223 if (referenceseqForView != null)
3225 al.setSeqrep(referenceseqForView);
3227 // / Add the alignment properties
3228 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3230 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3231 al.setProperty(ssp.getKey(), ssp.getValue());
3234 // ///////////////////////////////
3236 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3239 // load sequence features, database references and any associated PDB
3240 // structures for the alignment
3242 // prior to 2.10, this part would only be executed the first time a
3243 // sequence was encountered, but not afterwards.
3244 // now, for 2.10 projects, this is also done if the xml doc includes
3245 // dataset sequences not actually present in any particular view.
3247 for (int i = 0; i < vamsasSeq.length; i++)
3249 if (jseqs[i].getFeaturesCount() > 0)
3251 Features[] features = jseqs[i].getFeatures();
3252 for (int f = 0; f < features.length; f++)
3254 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3255 features[f].getDescription(), features[f].getBegin(),
3256 features[f].getEnd(), features[f].getScore(),
3257 features[f].getFeatureGroup());
3258 sf.setStatus(features[f].getStatus());
3261 * load any feature attributes - include map-valued attributes
3263 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3264 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3266 OtherData keyValue = features[f].getOtherData(od);
3267 String attributeName = keyValue.getKey();
3268 String attributeValue = keyValue.getValue();
3269 if (attributeName.startsWith("LINK"))
3271 sf.addLink(attributeValue);
3275 String subAttribute = keyValue.getKey2();
3276 if (subAttribute == null)
3278 // simple string-valued attribute
3279 sf.setValue(attributeName, attributeValue);
3283 // attribute 'key' has sub-attribute 'key2'
3284 if (!mapAttributes.containsKey(attributeName))
3286 mapAttributes.put(attributeName, new HashMap<>());
3288 mapAttributes.get(attributeName).put(subAttribute,
3293 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3296 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3299 // adds feature to datasequence's feature set (since Jalview 2.10)
3300 al.getSequenceAt(i).addSequenceFeature(sf);
3303 if (vamsasSeq[i].getDBRefCount() > 0)
3305 // adds dbrefs to datasequence's set (since Jalview 2.10)
3307 al.getSequenceAt(i).getDatasetSequence() == null
3308 ? al.getSequenceAt(i)
3309 : al.getSequenceAt(i).getDatasetSequence(),
3312 if (jseqs[i].getPdbidsCount() > 0)
3314 Pdbids[] ids = jseqs[i].getPdbids();
3315 for (int p = 0; p < ids.length; p++)
3317 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3318 entry.setId(ids[p].getId());
3319 if (ids[p].getType() != null)
3321 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3323 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3327 entry.setType(PDBEntry.Type.FILE);
3330 // jprovider is null when executing 'New View'
3331 if (ids[p].getFile() != null && jprovider != null)
3333 if (!pdbloaded.containsKey(ids[p].getFile()))
3335 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3340 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3343 if (ids[p].getPdbentryItem() != null)
3345 for (PdbentryItem item : ids[p].getPdbentryItem())
3347 for (Property pr : item.getProperty())
3349 entry.setProperty(pr.getName(), pr.getValue());
3353 StructureSelectionManager
3354 .getStructureSelectionManager(Desktop.instance)
3355 .registerPDBEntry(entry);
3356 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3357 if (al.getSequenceAt(i).getDatasetSequence() != null)
3359 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3363 al.getSequenceAt(i).addPDBId(entry);
3368 } // end !multipleview
3370 // ///////////////////////////////
3371 // LOAD SEQUENCE MAPPINGS
3373 if (vamsasSet.getAlcodonFrameCount() > 0)
3375 // TODO Potentially this should only be done once for all views of an
3377 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3378 for (int i = 0; i < alc.length; i++)
3380 AlignedCodonFrame cf = new AlignedCodonFrame();
3381 if (alc[i].getAlcodMapCount() > 0)
3383 AlcodMap[] maps = alc[i].getAlcodMap();
3384 for (int m = 0; m < maps.length; m++)
3386 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3388 jalview.datamodel.Mapping mapping = null;
3389 // attach to dna sequence reference.
3390 if (maps[m].getMapping() != null)
3392 mapping = addMapping(maps[m].getMapping());
3393 if (dnaseq != null && mapping.getTo() != null)
3395 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3401 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3405 al.addCodonFrame(cf);
3410 // ////////////////////////////////
3412 List<JvAnnotRow> autoAlan = new ArrayList<>();
3415 * store any annotations which forward reference a group's ID
3417 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3419 if (vamsasSet.getAnnotationCount() > 0)
3421 Annotation[] an = vamsasSet.getAnnotation();
3423 for (int i = 0; i < an.length; i++)
3425 Annotation annotation = an[i];
3428 * test if annotation is automatically calculated for this view only
3430 boolean autoForView = false;
3431 if (annotation.getLabel().equals("Quality")
3432 || annotation.getLabel().equals("Conservation")
3433 || annotation.getLabel().equals("Consensus"))
3435 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3437 if (!annotation.hasAutoCalculated())
3439 annotation.setAutoCalculated(true);
3442 if (autoForView || (annotation.hasAutoCalculated()
3443 && annotation.isAutoCalculated()))
3445 // remove ID - we don't recover annotation from other views for
3446 // view-specific annotation
3447 annotation.setId(null);
3450 // set visiblity for other annotation in this view
3451 String annotationId = annotation.getId();
3452 if (annotationId != null && annotationIds.containsKey(annotationId))
3454 AlignmentAnnotation jda = annotationIds.get(annotationId);
3455 // in principle Visible should always be true for annotation displayed
3456 // in multiple views
3457 if (annotation.hasVisible())
3459 jda.visible = annotation.getVisible();
3462 al.addAnnotation(jda);
3466 // Construct new annotation from model.
3467 AnnotationElement[] ae = annotation.getAnnotationElement();
3468 jalview.datamodel.Annotation[] anot = null;
3469 java.awt.Color firstColour = null;
3471 if (!annotation.getScoreOnly())
3473 anot = new jalview.datamodel.Annotation[al.getWidth()];
3474 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3476 anpos = ae[aa].getPosition();
3478 if (anpos >= anot.length)
3483 anot[anpos] = new jalview.datamodel.Annotation(
3485 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3486 (ae[aa].getSecondaryStructure() == null
3487 || ae[aa].getSecondaryStructure().length() == 0)
3489 : ae[aa].getSecondaryStructure()
3494 // JBPNote: Consider verifying dataflow for IO of secondary
3495 // structure annotation read from Stockholm files
3496 // this was added to try to ensure that
3497 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3499 // anot[ae[aa].getPosition()].displayCharacter = "";
3501 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3502 if (firstColour == null)
3504 firstColour = anot[anpos].colour;
3508 jalview.datamodel.AlignmentAnnotation jaa = null;
3510 if (annotation.getGraph())
3512 float llim = 0, hlim = 0;
3513 // if (autoForView || an[i].isAutoCalculated()) {
3516 jaa = new jalview.datamodel.AlignmentAnnotation(
3517 annotation.getLabel(), annotation.getDescription(), anot,
3518 llim, hlim, annotation.getGraphType());
3520 jaa.graphGroup = annotation.getGraphGroup();
3521 jaa._linecolour = firstColour;
3522 if (annotation.getThresholdLine() != null)
3524 jaa.setThreshold(new jalview.datamodel.GraphLine(
3525 annotation.getThresholdLine().getValue(),
3526 annotation.getThresholdLine().getLabel(),
3528 annotation.getThresholdLine().getColour())));
3531 if (autoForView || annotation.isAutoCalculated())
3533 // Hardwire the symbol display line to ensure that labels for
3534 // histograms are displayed
3540 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3541 an[i].getDescription(), anot);
3542 jaa._linecolour = firstColour;
3544 // register new annotation
3545 if (an[i].getId() != null)
3547 annotationIds.put(an[i].getId(), jaa);
3548 jaa.annotationId = an[i].getId();
3550 // recover sequence association
3551 String sequenceRef = an[i].getSequenceRef();
3552 if (sequenceRef != null)
3554 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3555 SequenceI sequence = seqRefIds.get(sequenceRef);
3556 if (sequence == null)
3558 // in pre-2.9 projects sequence ref is to sequence name
3559 sequence = al.findName(sequenceRef);
3561 if (sequence != null)
3563 jaa.createSequenceMapping(sequence, 1, true);
3564 sequence.addAlignmentAnnotation(jaa);
3567 // and make a note of any group association
3568 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3570 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3571 .get(an[i].getGroupRef());
3574 aal = new ArrayList<>();
3575 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3580 if (an[i].hasScore())
3582 jaa.setScore(an[i].getScore());
3584 if (an[i].hasVisible())
3586 jaa.visible = an[i].getVisible();
3589 if (an[i].hasCentreColLabels())
3591 jaa.centreColLabels = an[i].getCentreColLabels();
3594 if (an[i].hasScaleColLabels())
3596 jaa.scaleColLabel = an[i].getScaleColLabels();
3598 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3600 // newer files have an 'autoCalculated' flag and store calculation
3601 // state in viewport properties
3602 jaa.autoCalculated = true; // means annotation will be marked for
3603 // update at end of load.
3605 if (an[i].hasGraphHeight())
3607 jaa.graphHeight = an[i].getGraphHeight();
3609 if (an[i].hasBelowAlignment())
3611 jaa.belowAlignment = an[i].isBelowAlignment();
3613 jaa.setCalcId(an[i].getCalcId());
3614 if (an[i].getPropertyCount() > 0)
3616 for (jalview.schemabinding.version2.Property prop : an[i]
3619 jaa.setProperty(prop.getName(), prop.getValue());
3622 if (jaa.autoCalculated)
3624 autoAlan.add(new JvAnnotRow(i, jaa));
3627 // if (!autoForView)
3629 // add autocalculated group annotation and any user created annotation
3631 al.addAnnotation(jaa);
3635 // ///////////////////////
3637 // Create alignment markup and styles for this view
3638 if (jms.getJGroupCount() > 0)
3640 JGroup[] groups = jms.getJGroup();
3641 boolean addAnnotSchemeGroup = false;
3642 for (int i = 0; i < groups.length; i++)
3644 JGroup jGroup = groups[i];
3645 ColourSchemeI cs = null;
3646 if (jGroup.getColour() != null)
3648 if (jGroup.getColour().startsWith("ucs"))
3650 cs = getUserColourScheme(jms, jGroup.getColour());
3652 else if (jGroup.getColour().equals("AnnotationColourGradient")
3653 && jGroup.getAnnotationColours() != null)
3655 addAnnotSchemeGroup = true;
3659 cs = ColourSchemeProperty.getColourScheme(al,
3660 jGroup.getColour());
3663 int pidThreshold = jGroup.getPidThreshold();
3665 Vector<SequenceI> seqs = new Vector<>();
3667 for (int s = 0; s < jGroup.getSeqCount(); s++)
3669 String seqId = jGroup.getSeq(s) + "";
3670 SequenceI ts = seqRefIds.get(seqId);
3674 seqs.addElement(ts);
3678 if (seqs.size() < 1)
3683 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3684 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3685 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3686 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3687 sg.getGroupColourScheme()
3688 .setConservationInc(jGroup.getConsThreshold());
3689 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3691 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3692 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3693 sg.setShowNonconserved(
3694 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3696 sg.thresholdTextColour = jGroup.getTextColThreshold();
3697 if (jGroup.hasShowConsensusHistogram())
3699 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3702 if (jGroup.hasShowSequenceLogo())
3704 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3706 if (jGroup.hasNormaliseSequenceLogo())
3708 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3710 if (jGroup.hasIgnoreGapsinConsensus())
3712 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3714 if (jGroup.getConsThreshold() != 0)
3716 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3719 c.verdict(false, 25);
3720 sg.cs.setConservation(c);
3723 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3725 // re-instate unique group/annotation row reference
3726 List<AlignmentAnnotation> jaal = groupAnnotRefs
3727 .get(jGroup.getId());
3730 for (AlignmentAnnotation jaa : jaal)
3733 if (jaa.autoCalculated)
3735 // match up and try to set group autocalc alignment row for this
3737 if (jaa.label.startsWith("Consensus for "))
3739 sg.setConsensus(jaa);
3741 // match up and try to set group autocalc alignment row for this
3743 if (jaa.label.startsWith("Conservation for "))
3745 sg.setConservationRow(jaa);
3752 if (addAnnotSchemeGroup)
3754 // reconstruct the annotation colourscheme
3755 sg.setColourScheme(constructAnnotationColour(
3756 jGroup.getAnnotationColours(), null, al, jms, false));
3762 // only dataset in this model, so just return.
3765 // ///////////////////////////////
3768 AlignFrame af = null;
3769 AlignViewport av = null;
3770 // now check to see if we really need to create a new viewport.
3771 if (multipleView && viewportsAdded.size() == 0)
3773 // We recovered an alignment for which a viewport already exists.
3774 // TODO: fix up any settings necessary for overlaying stored state onto
3775 // state recovered from another document. (may not be necessary).
3776 // we may need a binding from a viewport in memory to one recovered from
3778 // and then recover its containing af to allow the settings to be applied.
3779 // TODO: fix for vamsas demo
3781 "About to recover a viewport for existing alignment: Sequence set ID is "
3783 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3784 if (seqsetobj != null)
3786 if (seqsetobj instanceof String)
3788 uniqueSeqSetId = (String) seqsetobj;
3790 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3796 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3802 * indicate that annotation colours are applied across all groups (pre
3803 * Jalview 2.8.1 behaviour)
3805 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3806 object.getVersion());
3808 AlignmentPanel ap = null;
3809 boolean isnewview = true;
3812 // Check to see if this alignment already has a view id == viewId
3813 jalview.gui.AlignmentPanel views[] = Desktop
3814 .getAlignmentPanels(uniqueSeqSetId);
3815 if (views != null && views.length > 0)
3817 for (int v = 0; v < views.length; v++)
3819 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3821 // recover the existing alignpanel, alignframe, viewport
3822 af = views[v].alignFrame;
3825 // TODO: could even skip resetting view settings if we don't want to
3826 // change the local settings from other jalview processes
3835 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3836 uniqueSeqSetId, viewId, autoAlan);
3842 * Load any trees, PDB structures and viewers
3844 * Not done if flag is false (when this method is used for New View)
3846 if (loadTreesAndStructures)
3848 loadTrees(jms, view, af, av, ap);
3849 loadPCAViewers(jms, ap);
3850 loadPDBStructures(jprovider, jseqs, af, ap);
3851 loadRnaViewers(jprovider, jseqs, ap);
3853 // and finally return.
3858 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3859 * panel is restored from separate jar entries, two (gapped and trimmed) per
3860 * sequence and secondary structure.
3862 * Currently each viewer shows just one sequence and structure (gapped and
3863 * trimmed), however this method is designed to support multiple sequences or
3864 * structures in viewers if wanted in future.
3870 private void loadRnaViewers(jarInputStreamProvider jprovider,
3871 JSeq[] jseqs, AlignmentPanel ap)
3874 * scan the sequences for references to viewers; create each one the first
3875 * time it is referenced, add Rna models to existing viewers
3877 for (JSeq jseq : jseqs)
3879 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3881 RnaViewer viewer = jseq.getRnaViewer(i);
3882 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3885 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3887 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3888 SequenceI seq = seqRefIds.get(jseq.getId());
3889 AlignmentAnnotation ann = this.annotationIds
3890 .get(ss.getAnnotationId());
3893 * add the structure to the Varna display (with session state copied
3894 * from the jar to a temporary file)
3896 boolean gapped = ss.isGapped();
3897 String rnaTitle = ss.getTitle();
3898 String sessionState = ss.getViewerState();
3899 String tempStateFile = copyJarEntry(jprovider, sessionState,
3901 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3902 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3904 appVarna.setInitialSelection(viewer.getSelectedRna());
3910 * Locate and return an already instantiated matching AppVarna, or create one
3914 * @param viewIdSuffix
3918 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3919 String viewIdSuffix, AlignmentPanel ap)
3922 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3923 * if load is repeated
3925 String postLoadId = viewer.getViewId() + viewIdSuffix;
3926 for (JInternalFrame frame : getAllFrames())
3928 if (frame instanceof AppVarna)
3930 AppVarna varna = (AppVarna) frame;
3931 if (postLoadId.equals(varna.getViewId()))
3933 // this viewer is already instantiated
3934 // could in future here add ap as another 'parent' of the
3935 // AppVarna window; currently just 1-to-many
3942 * viewer not found - make it
3944 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3945 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3946 viewer.getHeight(), viewer.getDividerLocation());
3947 AppVarna varna = new AppVarna(model, ap);
3953 * Load any saved trees
3961 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3962 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3964 // TODO result of automated refactoring - are all these parameters needed?
3967 for (int t = 0; t < jms.getTreeCount(); t++)
3970 Tree tree = jms.getTree(t);
3972 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3975 tp = af.showNewickTree(
3976 new jalview.io.NewickFile(tree.getNewick()),
3977 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3978 tree.getXpos(), tree.getYpos());
3979 if (tree.getId() != null)
3981 // perhaps bind the tree id to something ?
3986 // update local tree attributes ?
3987 // TODO: should check if tp has been manipulated by user - if so its
3988 // settings shouldn't be modified
3989 tp.setTitle(tree.getTitle());
3990 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3991 tree.getWidth(), tree.getHeight()));
3992 tp.setViewport(av); // af.viewport; // TODO: verify 'associate with all
3995 tp.getTreeCanvas().setViewport(av); // af.viewport;
3996 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4000 warn("There was a problem recovering stored Newick tree: \n"
4001 + tree.getNewick());
4005 tp.fitToWindow.setState(tree.getFitToWindow());
4006 tp.fitToWindow_actionPerformed(null);
4008 if (tree.getFontName() != null)
4010 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
4011 tree.getFontStyle(), tree.getFontSize()));
4015 tp.setTreeFont(new java.awt.Font(view.getFontName(),
4016 view.getFontStyle(), tree.getFontSize()));
4019 tp.showPlaceholders(tree.getMarkUnlinked());
4020 tp.showBootstrap(tree.getShowBootstrap());
4021 tp.showDistances(tree.getShowDistances());
4023 tp.getTreeCanvas().setThreshold(tree.getThreshold());
4024 tp.getTreeCanvas().applyToAllViews = tree.isLinkToAllViews();
4026 if (tree.getCurrentTree())
4028 af.viewport.setCurrentTree(tp.getTree());
4032 } catch (Exception ex)
4034 ex.printStackTrace();
4039 * Load and link any saved structure viewers.
4046 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4047 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
4050 * Run through all PDB ids on the alignment, and collect mappings between
4051 * distinct view ids and all sequences referring to that view.
4053 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4055 for (int i = 0; i < jseqs.length; i++)
4057 if (jseqs[i].getPdbidsCount() > 0)
4059 Pdbids[] ids = jseqs[i].getPdbids();
4060 for (int p = 0; p < ids.length; p++)
4062 final int structureStateCount = ids[p].getStructureStateCount();
4063 for (int s = 0; s < structureStateCount; s++)
4065 // check to see if we haven't already created this structure view
4066 final StructureState structureState = ids[p]
4067 .getStructureState(s);
4068 String sviewid = (structureState.getViewId() == null) ? null
4069 : structureState.getViewId() + uniqueSetSuffix;
4070 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4071 // Originally : ids[p].getFile()
4072 // : TODO: verify external PDB file recovery still works in normal
4073 // jalview project load
4074 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
4076 jpdb.setId(ids[p].getId());
4078 int x = structureState.getXpos();
4079 int y = structureState.getYpos();
4080 int width = structureState.getWidth();
4081 int height = structureState.getHeight();
4083 // Probably don't need to do this anymore...
4084 // Desktop.desktop.getComponentAt(x, y);
4085 // TODO: NOW: check that this recovers the PDB file correctly.
4086 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
4088 jalview.datamodel.SequenceI seq = seqRefIds
4089 .get(jseqs[i].getId() + "");
4090 if (sviewid == null)
4092 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4095 if (!structureViewers.containsKey(sviewid))
4097 structureViewers.put(sviewid,
4098 new StructureViewerModel(x, y, width, height, false,
4099 false, true, structureState.getViewId(),
4100 structureState.getType()));
4101 // Legacy pre-2.7 conversion JAL-823 :
4102 // do not assume any view has to be linked for colour by
4106 // assemble String[] { pdb files }, String[] { id for each
4107 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4108 // seqs_file 2}, boolean[] {
4109 // linkAlignPanel,superposeWithAlignpanel}} from hash
4110 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4111 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4112 | (structureState.hasAlignwithAlignPanel()
4113 ? structureState.getAlignwithAlignPanel()
4117 * Default colour by linked panel to false if not specified (e.g.
4118 * for pre-2.7 projects)
4120 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4121 colourWithAlignPanel |= (structureState
4122 .hasColourwithAlignPanel()
4123 ? structureState.getColourwithAlignPanel()
4125 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4128 * Default colour by viewer to true if not specified (e.g. for
4131 boolean colourByViewer = jmoldat.isColourByViewer();
4132 colourByViewer &= structureState.hasColourByJmol()
4133 ? structureState.getColourByJmol()
4135 jmoldat.setColourByViewer(colourByViewer);
4137 if (jmoldat.getStateData().length() < structureState
4138 .getContent().length())
4141 jmoldat.setStateData(structureState.getContent());
4144 if (ids[p].getFile() != null)
4146 File mapkey = new File(ids[p].getFile());
4147 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4148 if (seqstrmaps == null)
4150 jmoldat.getFileData().put(mapkey,
4151 seqstrmaps = jmoldat.new StructureData(pdbFile,
4154 if (!seqstrmaps.getSeqList().contains(seq))
4156 seqstrmaps.getSeqList().add(seq);
4162 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");
4169 // Instantiate the associated structure views
4170 for (Entry<String, StructureViewerModel> entry : structureViewers
4175 createOrLinkStructureViewer(entry, af, ap, jprovider);
4176 } catch (Exception e)
4179 "Error loading structure viewer: " + e.getMessage());
4180 // failed - try the next one
4192 protected void createOrLinkStructureViewer(
4193 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4194 AlignmentPanel ap, jarInputStreamProvider jprovider)
4196 final StructureViewerModel stateData = viewerData.getValue();
4199 * Search for any viewer windows already open from other alignment views
4200 * that exactly match the stored structure state
4202 StructureViewerBase comp = findMatchingViewer(viewerData);
4206 linkStructureViewer(ap, comp, stateData);
4211 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4212 * "viewer_"+stateData.viewId
4214 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4216 createChimeraViewer(viewerData, af, jprovider);
4221 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4223 createJmolViewer(viewerData, af, jprovider);
4228 * Create a new Chimera viewer.
4234 protected void createChimeraViewer(
4235 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4236 jarInputStreamProvider jprovider)
4238 StructureViewerModel data = viewerData.getValue();
4239 String chimeraSessionFile = data.getStateData();
4242 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4244 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4245 * 'uniquified' sviewid used to reconstruct the viewer here
4247 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4248 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4251 Set<Entry<File, StructureData>> fileData = data.getFileData()
4253 List<PDBEntry> pdbs = new ArrayList<>();
4254 List<SequenceI[]> allseqs = new ArrayList<>();
4255 for (Entry<File, StructureData> pdb : fileData)
4257 String filePath = pdb.getValue().getFilePath();
4258 String pdbId = pdb.getValue().getPdbId();
4259 // pdbs.add(new PDBEntry(filePath, pdbId));
4260 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4261 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4262 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4266 boolean colourByChimera = data.isColourByViewer();
4267 boolean colourBySequence = data.isColourWithAlignPanel();
4269 // TODO use StructureViewer as a factory here, see JAL-1761
4270 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4271 final SequenceI[][] seqsArray = allseqs
4272 .toArray(new SequenceI[allseqs.size()][]);
4273 String newViewId = viewerData.getKey();
4275 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4276 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4277 colourBySequence, newViewId);
4278 cvf.setSize(data.getWidth(), data.getHeight());
4279 cvf.setLocation(data.getX(), data.getY());
4283 * Create a new Jmol window. First parse the Jmol state to translate filenames
4284 * loaded into the view, and record the order in which files are shown in the
4285 * Jmol view, so we can add the sequence mappings in same order.
4291 protected void createJmolViewer(
4292 final Entry<String, StructureViewerModel> viewerData,
4293 AlignFrame af, jarInputStreamProvider jprovider)
4295 final StructureViewerModel svattrib = viewerData.getValue();
4296 String state = svattrib.getStateData();
4299 * Pre-2.9: state element value is the Jmol state string
4301 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4304 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4306 state = readJarEntry(jprovider,
4307 getViewerJarEntryName(svattrib.getViewId()));
4310 List<String> pdbfilenames = new ArrayList<>();
4311 List<SequenceI[]> seqmaps = new ArrayList<>();
4312 List<String> pdbids = new ArrayList<>();
4313 StringBuilder newFileLoc = new StringBuilder(64);
4314 int cp = 0, ncp, ecp;
4315 Map<File, StructureData> oldFiles = svattrib.getFileData();
4316 while ((ncp = state.indexOf("load ", cp)) > -1)
4320 // look for next filename in load statement
4321 newFileLoc.append(state.substring(cp,
4322 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4323 String oldfilenam = state.substring(ncp,
4324 ecp = state.indexOf("\"", ncp));
4325 // recover the new mapping data for this old filename
4326 // have to normalize filename - since Jmol and jalview do
4328 // translation differently.
4329 StructureData filedat = oldFiles.get(new File(oldfilenam));
4330 if (filedat == null)
4332 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4333 filedat = oldFiles.get(new File(reformatedOldFilename));
4335 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4336 pdbfilenames.add(filedat.getFilePath());
4337 pdbids.add(filedat.getPdbId());
4338 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4339 newFileLoc.append("\"");
4340 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4341 // look for next file statement.
4342 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4346 // just append rest of state
4347 newFileLoc.append(state.substring(cp));
4351 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4352 newFileLoc = new StringBuilder(state);
4353 newFileLoc.append("; load append ");
4354 for (File id : oldFiles.keySet())
4356 // add this and any other pdb files that should be present in
4358 StructureData filedat = oldFiles.get(id);
4359 newFileLoc.append(filedat.getFilePath());
4360 pdbfilenames.add(filedat.getFilePath());
4361 pdbids.add(filedat.getPdbId());
4362 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4363 newFileLoc.append(" \"");
4364 newFileLoc.append(filedat.getFilePath());
4365 newFileLoc.append("\"");
4368 newFileLoc.append(";");
4371 if (newFileLoc.length() == 0)
4375 int histbug = newFileLoc.indexOf("history = ");
4379 * change "history = [true|false];" to "history = [1|0];"
4382 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4383 String val = (diff == -1) ? null
4384 : newFileLoc.substring(histbug, diff);
4385 if (val != null && val.length() >= 4)
4387 if (val.contains("e")) // eh? what can it be?
4389 if (val.trim().equals("true"))
4397 newFileLoc.replace(histbug, diff, val);
4402 final String[] pdbf = pdbfilenames
4403 .toArray(new String[pdbfilenames.size()]);
4404 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4405 final SequenceI[][] sq = seqmaps
4406 .toArray(new SequenceI[seqmaps.size()][]);
4407 final String fileloc = newFileLoc.toString();
4408 final String sviewid = viewerData.getKey();
4409 final AlignFrame alf = af;
4410 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4411 svattrib.getWidth(), svattrib.getHeight());
4414 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4419 JalviewStructureDisplayI sview = null;
4422 sview = new StructureViewer(
4423 alf.alignPanel.getStructureSelectionManager())
4424 .createView(StructureViewer.ViewerType.JMOL,
4425 pdbf, id, sq, alf.alignPanel, svattrib,
4426 fileloc, rect, sviewid);
4427 addNewStructureViewer(sview);
4428 } catch (OutOfMemoryError ex)
4430 new OOMWarning("restoring structure view for PDB id " + id,
4431 (OutOfMemoryError) ex.getCause());
4432 if (sview != null && sview.isVisible())
4434 sview.closeViewer(false);
4435 sview.setVisible(false);
4441 } catch (InvocationTargetException ex)
4443 warn("Unexpected error when opening Jmol view.", ex);
4445 } catch (InterruptedException e)
4447 // e.printStackTrace();
4453 * Generates a name for the entry in the project jar file to hold state
4454 * information for a structure viewer
4459 protected String getViewerJarEntryName(String viewId)
4461 return VIEWER_PREFIX + viewId;
4465 * Returns any open frame that matches given structure viewer data. The match
4466 * is based on the unique viewId, or (for older project versions) the frame's
4472 protected StructureViewerBase findMatchingViewer(
4473 Entry<String, StructureViewerModel> viewerData)
4475 final String sviewid = viewerData.getKey();
4476 final StructureViewerModel svattrib = viewerData.getValue();
4477 StructureViewerBase comp = null;
4478 JInternalFrame[] frames = getAllFrames();
4479 for (JInternalFrame frame : frames)
4481 if (frame instanceof StructureViewerBase)
4484 * Post jalview 2.4 schema includes structure view id
4486 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4489 comp = (StructureViewerBase) frame;
4490 break; // break added in 2.9
4493 * Otherwise test for matching position and size of viewer frame
4495 else if (frame.getX() == svattrib.getX()
4496 && frame.getY() == svattrib.getY()
4497 && frame.getHeight() == svattrib.getHeight()
4498 && frame.getWidth() == svattrib.getWidth())
4500 comp = (StructureViewerBase) frame;
4501 // no break in faint hope of an exact match on viewId
4509 * Link an AlignmentPanel to an existing structure viewer.
4514 * @param useinViewerSuperpos
4515 * @param usetoColourbyseq
4516 * @param viewerColouring
4518 protected void linkStructureViewer(AlignmentPanel ap,
4519 StructureViewerBase viewer, StructureViewerModel stateData)
4521 // NOTE: if the jalview project is part of a shared session then
4522 // view synchronization should/could be done here.
4524 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4525 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4526 final boolean viewerColouring = stateData.isColourByViewer();
4527 Map<File, StructureData> oldFiles = stateData.getFileData();
4530 * Add mapping for sequences in this view to an already open viewer
4532 final AAStructureBindingModel binding = viewer.getBinding();
4533 for (File id : oldFiles.keySet())
4535 // add this and any other pdb files that should be present in the
4537 StructureData filedat = oldFiles.get(id);
4538 String pdbFile = filedat.getFilePath();
4539 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4540 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4542 binding.addSequenceForStructFile(pdbFile, seq);
4544 // and add the AlignmentPanel's reference to the view panel
4545 viewer.addAlignmentPanel(ap);
4546 if (useinViewerSuperpos)
4548 viewer.useAlignmentPanelForSuperposition(ap);
4552 viewer.excludeAlignmentPanelForSuperposition(ap);
4554 if (usetoColourbyseq)
4556 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4560 viewer.excludeAlignmentPanelForColourbyseq(ap);
4565 * Get all frames within the Desktop.
4569 protected JInternalFrame[] getAllFrames()
4571 JInternalFrame[] frames = null;
4572 // TODO is this necessary - is it safe - risk of hanging?
4577 frames = Desktop.desktop.getAllFrames();
4578 } catch (ArrayIndexOutOfBoundsException e)
4580 // occasional No such child exceptions are thrown here...
4584 } catch (InterruptedException f)
4588 } while (frames == null);
4593 * Answers true if 'version' is equal to or later than 'supported', where each
4594 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4595 * changes. Development and test values for 'version' are leniently treated
4599 * - minimum version we are comparing against
4601 * - version of data being processsed
4604 public static boolean isVersionStringLaterThan(String supported,
4607 if (supported == null || version == null
4608 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4609 || version.equalsIgnoreCase("Test")
4610 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4612 System.err.println("Assuming project file with "
4613 + (version == null ? "null" : version)
4614 + " is compatible with Jalview version " + supported);
4619 return StringUtils.compareVersions(version, supported, "b") >= 0;
4623 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4625 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4627 if (newStructureViewers != null)
4629 sview.getBinding().setFinishedLoadingFromArchive(false);
4630 newStructureViewers.add(sview);
4634 protected void setLoadingFinishedForNewStructureViewers()
4636 if (newStructureViewers != null)
4638 for (JalviewStructureDisplayI sview : newStructureViewers)
4640 sview.getBinding().setFinishedLoadingFromArchive(true);
4642 newStructureViewers.clear();
4643 newStructureViewers = null;
4647 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4648 List<SequenceI> hiddenSeqs, AlignmentI al,
4649 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4650 String viewId, List<JvAnnotRow> autoAlan)
4652 AlignFrame af = null;
4653 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4654 uniqueSeqSetId, viewId);
4656 af.setFileName(file, FileFormat.Jalview);
4658 for (int i = 0; i < JSEQ.length; i++)
4660 af.viewport.setSequenceColour(
4661 af.viewport.getAlignment().getSequenceAt(i),
4662 new java.awt.Color(JSEQ[i].getColour()));
4667 af.getViewport().setColourByReferenceSeq(true);
4668 af.getViewport().setDisplayReferenceSeq(true);
4671 af.viewport.setGatherViewsHere(view.getGatheredViews());
4673 if (view.getSequenceSetId() != null)
4675 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4677 af.viewport.setSequenceSetId(uniqueSeqSetId);
4680 // propagate shared settings to this new view
4681 af.viewport.setHistoryList(av.getHistoryList());
4682 af.viewport.setRedoList(av.getRedoList());
4686 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4688 // TODO: check if this method can be called repeatedly without
4689 // side-effects if alignpanel already registered.
4690 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4692 // apply Hidden regions to view.
4693 if (hiddenSeqs != null)
4695 for (int s = 0; s < JSEQ.length; s++)
4697 SequenceGroup hidden = new SequenceGroup();
4698 boolean isRepresentative = false;
4699 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4701 isRepresentative = true;
4702 SequenceI sequenceToHide = al
4703 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4704 hidden.addSequence(sequenceToHide, false);
4705 // remove from hiddenSeqs list so we don't try to hide it twice
4706 hiddenSeqs.remove(sequenceToHide);
4708 if (isRepresentative)
4710 SequenceI representativeSequence = al.getSequenceAt(s);
4711 hidden.addSequence(representativeSequence, false);
4712 af.viewport.hideRepSequences(representativeSequence, hidden);
4716 SequenceI[] hseqs = hiddenSeqs
4717 .toArray(new SequenceI[hiddenSeqs.size()]);
4718 af.viewport.hideSequence(hseqs);
4721 // recover view properties and display parameters
4723 af.viewport.setShowAnnotation(view.getShowAnnotation());
4724 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4725 af.viewport.setThreshold(view.getPidThreshold());
4727 af.viewport.setColourText(view.getShowColourText());
4729 af.viewport.setConservationSelected(view.getConservationSelected());
4730 af.viewport.setIncrement(view.getConsThreshold());
4731 af.viewport.setShowJVSuffix(view.getShowFullId());
4732 af.viewport.setRightAlignIds(view.getRightAlignIds());
4733 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4734 view.getFontStyle(), view.getFontSize()), true);
4735 ViewStyleI vs = af.viewport.getViewStyle();
4736 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4737 af.viewport.setViewStyle(vs);
4738 // TODO: allow custom charWidth/Heights to be restored by updating them
4739 // after setting font - which means set above to false
4740 af.viewport.setRenderGaps(view.getRenderGaps());
4741 af.viewport.setWrapAlignment(view.getWrapAlignment());
4742 af.viewport.setShowAnnotation(view.getShowAnnotation());
4744 af.viewport.setShowBoxes(view.getShowBoxes());
4746 af.viewport.setShowText(view.getShowText());
4748 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4749 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4750 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4751 af.viewport.setShowUnconserved(
4752 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4753 af.viewport.getRanges().setStartRes(view.getStartRes());
4755 if (view.getViewName() != null)
4757 af.viewport.setViewName(view.getViewName());
4758 af.setInitialTabVisible();
4760 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4762 // startSeq set in af.alignPanel.updateLayout below
4763 af.alignPanel.updateLayout();
4764 ColourSchemeI cs = null;
4765 // apply colourschemes
4766 if (view.getBgColour() != null)
4768 if (view.getBgColour().startsWith("ucs"))
4770 cs = getUserColourScheme(jms, view.getBgColour());
4772 else if (view.getBgColour().startsWith("Annotation"))
4774 AnnotationColours viewAnnColour = view.getAnnotationColours();
4775 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4782 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4786 af.viewport.setGlobalColourScheme(cs);
4787 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4788 view.getIgnoreGapsinConsensus());
4789 af.viewport.getResidueShading()
4790 .setConsensus(af.viewport.getSequenceConsensusHash());
4791 af.viewport.setColourAppliesToAllGroups(false);
4793 if (view.getConservationSelected() && cs != null)
4795 af.viewport.getResidueShading()
4796 .setConservationInc(view.getConsThreshold());
4799 af.changeColour(cs);
4801 af.viewport.setColourAppliesToAllGroups(true);
4803 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4805 if (view.hasCentreColumnLabels())
4807 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4809 if (view.hasIgnoreGapsinConsensus())
4811 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4814 if (view.hasFollowHighlight())
4816 af.viewport.setFollowHighlight(view.getFollowHighlight());
4818 if (view.hasFollowSelection())
4820 af.viewport.followSelection = view.getFollowSelection();
4822 if (view.hasShowConsensusHistogram())
4825 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4829 af.viewport.setShowConsensusHistogram(true);
4831 if (view.hasShowSequenceLogo())
4833 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4837 af.viewport.setShowSequenceLogo(false);
4839 if (view.hasNormaliseSequenceLogo())
4841 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4843 if (view.hasShowDbRefTooltip())
4845 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4847 if (view.hasShowNPfeatureTooltip())
4849 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4851 if (view.hasShowGroupConsensus())
4853 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4857 af.viewport.setShowGroupConsensus(false);
4859 if (view.hasShowGroupConservation())
4861 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4865 af.viewport.setShowGroupConservation(false);
4868 // recover feature settings
4869 if (jms.getFeatureSettings() != null)
4871 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4872 .getFeatureRenderer();
4873 FeaturesDisplayed fdi;
4874 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4875 String[] renderOrder = new String[jms.getFeatureSettings()
4876 .getSettingCount()];
4877 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4878 Map<String, Float> featureOrder = new Hashtable<>();
4880 for (int fs = 0; fs < jms.getFeatureSettings()
4881 .getSettingCount(); fs++)
4883 Setting setting = jms.getFeatureSettings().getSetting(fs);
4884 String featureType = setting.getType();
4887 * restore feature filters (if any)
4889 MatcherSet filters = setting.getMatcherSet();
4890 if (filters != null)
4892 FeatureMatcherSetI filter = Jalview2XML
4893 .unmarshalFilter(featureType, filters);
4894 if (!filter.isEmpty())
4896 fr.setFeatureFilter(featureType, filter);
4901 * restore feature colour scheme
4903 Color maxColour = new Color(setting.getColour());
4904 if (setting.hasMincolour())
4907 * minColour is always set unless a simple colour
4908 * (including for colour by label though it doesn't use it)
4910 Color minColour = new Color(setting.getMincolour());
4911 Color noValueColour = minColour;
4912 NoValueColour noColour = setting.getNoValueColour();
4913 if (noColour == NoValueColour.NONE)
4915 noValueColour = null;
4917 else if (noColour == NoValueColour.MAX)
4919 noValueColour = maxColour;
4921 float min = setting.hasMin() ? setting.getMin() : 0f;
4922 float max = setting.hasMin() ? setting.getMax() : 1f;
4923 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4924 noValueColour, min, max);
4925 if (setting.getAttributeNameCount() > 0)
4927 gc.setAttributeName(setting.getAttributeName());
4929 if (setting.hasThreshold())
4931 gc.setThreshold(setting.getThreshold());
4932 int threshstate = setting.getThreshstate();
4933 // -1 = None, 0 = Below, 1 = Above threshold
4934 if (threshstate == 0)
4936 gc.setBelowThreshold(true);
4938 else if (threshstate == 1)
4940 gc.setAboveThreshold(true);
4943 gc.setAutoScaled(true); // default
4944 if (setting.hasAutoScale())
4946 gc.setAutoScaled(setting.getAutoScale());
4948 if (setting.hasColourByLabel())
4950 gc.setColourByLabel(setting.getColourByLabel());
4952 // and put in the feature colour table.
4953 featureColours.put(featureType, gc);
4957 featureColours.put(featureType,
4958 new FeatureColour(maxColour));
4960 renderOrder[fs] = featureType;
4961 if (setting.hasOrder())
4963 featureOrder.put(featureType, setting.getOrder());
4967 featureOrder.put(featureType, new Float(
4968 fs / jms.getFeatureSettings().getSettingCount()));
4970 if (setting.getDisplay())
4972 fdi.setVisible(featureType);
4975 Map<String, Boolean> fgtable = new Hashtable<>();
4976 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4978 Group grp = jms.getFeatureSettings().getGroup(gs);
4979 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4981 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4982 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4983 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4984 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4985 fgtable, featureColours, 1.0f, featureOrder);
4986 fr.transferSettings(frs);
4989 if (view.getHiddenColumnsCount() > 0)
4991 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4993 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4994 view.getHiddenColumns(c).getEnd() // +1
4998 if (view.getCalcIdParam() != null)
5000 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5002 if (calcIdParam != null)
5004 if (recoverCalcIdParam(calcIdParam, af.viewport))
5009 warn("Couldn't recover parameters for "
5010 + calcIdParam.getCalcId());
5015 af.setMenusFromViewport(af.viewport);
5016 af.setTitle(view.getTitle());
5017 // TODO: we don't need to do this if the viewport is aready visible.
5019 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5020 * has a 'cdna/protein complement' view, in which case save it in order to
5021 * populate a SplitFrame once all views have been read in.
5023 String complementaryViewId = view.getComplementId();
5024 if (complementaryViewId == null)
5026 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
5028 // recompute any autoannotation
5029 af.alignPanel.updateAnnotation(false, true);
5030 reorderAutoannotation(af, al, autoAlan);
5031 af.alignPanel.alignmentChanged();
5035 splitFrameCandidates.put(view, af);
5041 * Reads saved data to restore Colour by Annotation settings
5043 * @param viewAnnColour
5047 * @param checkGroupAnnColour
5050 private ColourSchemeI constructAnnotationColour(
5051 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
5052 JalviewModelSequence jms, boolean checkGroupAnnColour)
5054 boolean propagateAnnColour = false;
5055 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
5056 if (checkGroupAnnColour && al.getGroups() != null
5057 && al.getGroups().size() > 0)
5059 // pre 2.8.1 behaviour
5060 // check to see if we should transfer annotation colours
5061 propagateAnnColour = true;
5062 for (SequenceGroup sg : al.getGroups())
5064 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5066 propagateAnnColour = false;
5072 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5074 String annotationId = viewAnnColour.getAnnotation();
5075 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5078 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5080 if (matchedAnnotation == null
5081 && annAlignment.getAlignmentAnnotation() != null)
5083 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5086 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5088 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5093 if (matchedAnnotation == null)
5095 System.err.println("Failed to match annotation colour scheme for "
5099 if (matchedAnnotation.getThreshold() == null)
5101 matchedAnnotation.setThreshold(new GraphLine(
5102 viewAnnColour.getThreshold(), "Threshold", Color.black));
5105 AnnotationColourGradient cs = null;
5106 if (viewAnnColour.getColourScheme().equals("None"))
5108 cs = new AnnotationColourGradient(matchedAnnotation,
5109 new Color(viewAnnColour.getMinColour()),
5110 new Color(viewAnnColour.getMaxColour()),
5111 viewAnnColour.getAboveThreshold());
5113 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5115 cs = new AnnotationColourGradient(matchedAnnotation,
5116 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
5117 viewAnnColour.getAboveThreshold());
5121 cs = new AnnotationColourGradient(matchedAnnotation,
5122 ColourSchemeProperty.getColourScheme(al,
5123 viewAnnColour.getColourScheme()),
5124 viewAnnColour.getAboveThreshold());
5127 boolean perSequenceOnly = viewAnnColour.isPerSequence();
5128 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
5129 cs.setSeqAssociated(perSequenceOnly);
5130 cs.setPredefinedColours(useOriginalColours);
5132 if (propagateAnnColour && al.getGroups() != null)
5134 // Also use these settings for all the groups
5135 for (int g = 0; g < al.getGroups().size(); g++)
5137 SequenceGroup sg = al.getGroups().get(g);
5138 if (sg.getGroupColourScheme() == null)
5143 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5144 matchedAnnotation, sg.getColourScheme(),
5145 viewAnnColour.getAboveThreshold());
5146 sg.setColourScheme(groupScheme);
5147 groupScheme.setSeqAssociated(perSequenceOnly);
5148 groupScheme.setPredefinedColours(useOriginalColours);
5154 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5155 List<JvAnnotRow> autoAlan)
5157 // copy over visualization settings for autocalculated annotation in the
5159 if (al.getAlignmentAnnotation() != null)
5162 * Kludge for magic autoannotation names (see JAL-811)
5164 String[] magicNames = new String[] { "Consensus", "Quality",
5166 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5167 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5168 for (String nm : magicNames)
5170 visan.put(nm, nullAnnot);
5172 for (JvAnnotRow auan : autoAlan)
5174 visan.put(auan.template.label
5175 + (auan.template.getCalcId() == null ? ""
5176 : "\t" + auan.template.getCalcId()),
5179 int hSize = al.getAlignmentAnnotation().length;
5180 List<JvAnnotRow> reorder = new ArrayList<>();
5181 // work through any autoCalculated annotation already on the view
5182 // removing it if it should be placed in a different location on the
5183 // annotation panel.
5184 List<String> remains = new ArrayList<>(visan.keySet());
5185 for (int h = 0; h < hSize; h++)
5187 jalview.datamodel.AlignmentAnnotation jalan = al
5188 .getAlignmentAnnotation()[h];
5189 if (jalan.autoCalculated)
5192 JvAnnotRow valan = visan.get(k = jalan.label);
5193 if (jalan.getCalcId() != null)
5195 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5200 // delete the auto calculated row from the alignment
5201 al.deleteAnnotation(jalan, false);
5205 if (valan != nullAnnot)
5207 if (jalan != valan.template)
5209 // newly created autoannotation row instance
5210 // so keep a reference to the visible annotation row
5211 // and copy over all relevant attributes
5212 if (valan.template.graphHeight >= 0)
5215 jalan.graphHeight = valan.template.graphHeight;
5217 jalan.visible = valan.template.visible;
5219 reorder.add(new JvAnnotRow(valan.order, jalan));
5224 // Add any (possibly stale) autocalculated rows that were not appended to
5225 // the view during construction
5226 for (String other : remains)
5228 JvAnnotRow othera = visan.get(other);
5229 if (othera != nullAnnot && othera.template.getCalcId() != null
5230 && othera.template.getCalcId().length() > 0)
5232 reorder.add(othera);
5235 // now put the automatic annotation in its correct place
5236 int s = 0, srt[] = new int[reorder.size()];
5237 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5238 for (JvAnnotRow jvar : reorder)
5241 srt[s++] = jvar.order;
5244 jalview.util.QuickSort.sort(srt, rws);
5245 // and re-insert the annotation at its correct position
5246 for (JvAnnotRow jvar : rws)
5248 al.addAnnotation(jvar.template, jvar.order);
5250 af.alignPanel.adjustAnnotationHeight();
5254 Hashtable skipList = null;
5257 * TODO remove this method
5260 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5261 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5262 * throw new Error("Implementation Error. No skipList defined for this
5263 * Jalview2XML instance."); } return (AlignFrame)
5264 * skipList.get(view.getSequenceSetId()); }
5268 * Check if the Jalview view contained in object should be skipped or not.
5271 * @return true if view's sequenceSetId is a key in skipList
5273 private boolean skipViewport(JalviewModel object)
5275 if (skipList == null)
5280 if (skipList.containsKey(
5281 id = object.getJalviewModelSequence().getViewport()[0]
5282 .getSequenceSetId()))
5284 if (Cache.log != null && Cache.log.isDebugEnabled())
5286 Cache.log.debug("Skipping seuqence set id " + id);
5293 public void addToSkipList(AlignFrame af)
5295 if (skipList == null)
5297 skipList = new Hashtable();
5299 skipList.put(af.getViewport().getSequenceSetId(), af);
5302 public void clearSkipList()
5304 if (skipList != null)
5311 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5312 boolean ignoreUnrefed, String uniqueSeqSetId)
5314 jalview.datamodel.AlignmentI ds = getDatasetFor(
5315 vamsasSet.getDatasetId());
5316 Vector dseqs = null;
5321 // try to resolve the dataset via uniqueSeqSetId
5322 ds = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5325 addDatasetRef(vamsasSet.getDatasetId(), ds);
5331 // create a list of new dataset sequences
5332 dseqs = new Vector();
5334 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5336 Sequence vamsasSeq = vamsasSet.getSequence(i);
5337 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5339 // create a new dataset
5342 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5343 dseqs.copyInto(dsseqs);
5344 ds = new jalview.datamodel.Alignment(dsseqs);
5345 debug("Created new dataset " + vamsasSet.getDatasetId()
5346 + " for alignment " + System.identityHashCode(al));
5347 addDatasetRef(vamsasSet.getDatasetId(), ds);
5349 // set the dataset for the newly imported alignment.
5350 if (al.getDataset() == null && !ignoreUnrefed)
5353 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5354 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5361 * sequence definition to create/merge dataset sequence for
5365 * vector to add new dataset sequence to
5366 * @param ignoreUnrefed
5367 * - when true, don't create new sequences from vamsasSeq if it's id
5368 * doesn't already have an asssociated Jalview sequence.
5370 * - used to reorder the sequence in the alignment according to the
5371 * vamsasSeq array ordering, to preserve ordering of dataset
5373 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5374 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5376 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5378 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5379 boolean reorder = false;
5380 SequenceI dsq = null;
5381 if (sq != null && sq.getDatasetSequence() != null)
5383 dsq = sq.getDatasetSequence();
5389 if (sq == null && ignoreUnrefed)
5393 String sqid = vamsasSeq.getDsseqid();
5396 // need to create or add a new dataset sequence reference to this sequence
5399 dsq = seqRefIds.get(sqid);
5404 // make a new dataset sequence
5405 dsq = sq.createDatasetSequence();
5408 // make up a new dataset reference for this sequence
5409 sqid = seqHash(dsq);
5411 dsq.setVamsasId(uniqueSetSuffix + sqid);
5412 seqRefIds.put(sqid, dsq);
5417 dseqs.addElement(dsq);
5422 ds.addSequence(dsq);
5428 { // make this dataset sequence sq's dataset sequence
5429 sq.setDatasetSequence(dsq);
5430 // and update the current dataset alignment
5435 if (!dseqs.contains(dsq))
5442 if (ds.findIndex(dsq) < 0)
5444 ds.addSequence(dsq);
5451 // TODO: refactor this as a merge dataset sequence function
5452 // now check that sq (the dataset sequence) sequence really is the union of
5453 // all references to it
5454 // boolean pre = sq.getStart() < dsq.getStart();
5455 // boolean post = sq.getEnd() > dsq.getEnd();
5459 // StringBuffer sb = new StringBuffer();
5460 String newres = jalview.analysis.AlignSeq.extractGaps(
5461 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5462 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5463 && newres.length() > dsq.getLength())
5465 // Update with the longer sequence.
5469 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5470 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5471 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5472 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5474 dsq.setSequence(newres);
5476 // TODO: merges will never happen if we 'know' we have the real dataset
5477 // sequence - this should be detected when id==dssid
5479 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5480 // + (pre ? "prepended" : "") + " "
5481 // + (post ? "appended" : ""));
5486 // sequence refs are identical. We may need to update the existing dataset
5487 // alignment with this one, though.
5488 if (ds != null && dseqs == null)
5490 int opos = ds.findIndex(dsq);
5491 SequenceI tseq = null;
5492 if (opos != -1 && vseqpos != opos)
5494 // remove from old position
5495 ds.deleteSequence(dsq);
5497 if (vseqpos < ds.getHeight())
5499 if (vseqpos != opos)
5501 // save sequence at destination position
5502 tseq = ds.getSequenceAt(vseqpos);
5503 ds.replaceSequenceAt(vseqpos, dsq);
5504 ds.addSequence(tseq);
5509 ds.addSequence(dsq);
5516 * TODO use AlignmentI here and in related methods - needs
5517 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5519 Hashtable<String, AlignmentI> datasetIds = null;
5521 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5523 private AlignmentI getDatasetFor(String datasetId)
5525 if (datasetIds == null)
5527 datasetIds = new Hashtable<>();
5530 if (datasetIds.containsKey(datasetId))
5532 return datasetIds.get(datasetId);
5537 private void addDatasetRef(String datasetId, AlignmentI dataset)
5539 if (datasetIds == null)
5541 datasetIds = new Hashtable<>();
5543 datasetIds.put(datasetId, dataset);
5547 * make a new dataset ID for this jalview dataset alignment
5552 private String getDatasetIdRef(AlignmentI dataset)
5554 if (dataset.getDataset() != null)
5556 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5558 String datasetId = makeHashCode(dataset, null);
5559 if (datasetId == null)
5561 // make a new datasetId and record it
5562 if (dataset2Ids == null)
5564 dataset2Ids = new IdentityHashMap<>();
5568 datasetId = dataset2Ids.get(dataset);
5570 if (datasetId == null)
5572 datasetId = "ds" + dataset2Ids.size() + 1;
5573 dataset2Ids.put(dataset, datasetId);
5579 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5581 for (int d = 0; d < sequence.getDBRefCount(); d++)
5583 DBRef dr = sequence.getDBRef(d);
5584 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5585 sequence.getDBRef(d).getSource(),
5586 sequence.getDBRef(d).getVersion(),
5587 sequence.getDBRef(d).getAccessionId());
5588 if (dr.getMapping() != null)
5590 entry.setMap(addMapping(dr.getMapping()));
5592 datasetSequence.addDBRef(entry);
5596 private jalview.datamodel.Mapping addMapping(Mapping m)
5598 SequenceI dsto = null;
5599 // Mapping m = dr.getMapping();
5600 int fr[] = new int[m.getMapListFromCount() * 2];
5601 Enumeration f = m.enumerateMapListFrom();
5602 for (int _i = 0; f.hasMoreElements(); _i += 2)
5604 MapListFrom mf = (MapListFrom) f.nextElement();
5605 fr[_i] = mf.getStart();
5606 fr[_i + 1] = mf.getEnd();
5608 int fto[] = new int[m.getMapListToCount() * 2];
5609 f = m.enumerateMapListTo();
5610 for (int _i = 0; f.hasMoreElements(); _i += 2)
5612 MapListTo mf = (MapListTo) f.nextElement();
5613 fto[_i] = mf.getStart();
5614 fto[_i + 1] = mf.getEnd();
5616 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5617 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5618 if (m.getMappingChoice() != null)
5620 MappingChoice mc = m.getMappingChoice();
5621 if (mc.getDseqFor() != null)
5623 String dsfor = "" + mc.getDseqFor();
5624 if (seqRefIds.containsKey(dsfor))
5629 jmap.setTo(seqRefIds.get(dsfor));
5633 frefedSequence.add(newMappingRef(dsfor, jmap));
5639 * local sequence definition
5641 Sequence ms = mc.getSequence();
5642 SequenceI djs = null;
5643 String sqid = ms.getDsseqid();
5644 if (sqid != null && sqid.length() > 0)
5647 * recover dataset sequence
5649 djs = seqRefIds.get(sqid);
5654 "Warning - making up dataset sequence id for DbRef sequence map reference");
5655 sqid = ((Object) ms).toString(); // make up a new hascode for
5656 // undefined dataset sequence hash
5657 // (unlikely to happen)
5663 * make a new dataset sequence and add it to refIds hash
5665 djs = new jalview.datamodel.Sequence(ms.getName(),
5667 djs.setStart(jmap.getMap().getToLowest());
5668 djs.setEnd(jmap.getMap().getToHighest());
5669 djs.setVamsasId(uniqueSetSuffix + sqid);
5671 incompleteSeqs.put(sqid, djs);
5672 seqRefIds.put(sqid, djs);
5675 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5685 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5686 * view as XML (but not to file), and then reloading it
5691 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5694 JalviewModel jm = saveState(ap, null, null, null);
5696 addDatasetRef(jm.getVamsasModel().getSequenceSet()[0].getDatasetId(),
5697 ap.getAlignment().getDataset());
5699 uniqueSetSuffix = "";
5700 jm.getJalviewModelSequence().getViewport(0).setId(null);
5701 // we don't overwrite the view we just copied
5703 if (this.frefedSequence == null)
5705 frefedSequence = new Vector<>();
5708 viewportsAdded.clear();
5710 AlignFrame af = loadFromObject(jm, null, false, null);
5711 af.alignPanels.clear();
5712 af.closeMenuItem_actionPerformed(true);
5715 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5716 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5717 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5718 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5719 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5722 return af.alignPanel;
5725 private Hashtable jvids2vobj;
5727 private void warn(String msg)
5732 private void warn(String msg, Exception e)
5734 if (Cache.log != null)
5738 Cache.log.warn(msg, e);
5742 Cache.log.warn(msg);
5747 System.err.println("Warning: " + msg);
5750 e.printStackTrace();
5755 private void debug(String string)
5757 debug(string, null);
5760 private void debug(String msg, Exception e)
5762 if (Cache.log != null)
5766 Cache.log.debug(msg, e);
5770 Cache.log.debug(msg);
5775 System.err.println("Warning: " + msg);
5778 e.printStackTrace();
5784 * set the object to ID mapping tables used to write/recover objects and XML
5785 * ID strings for the jalview project. If external tables are provided then
5786 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5787 * object goes out of scope. - also populates the datasetIds hashtable with
5788 * alignment objects containing dataset sequences
5791 * Map from ID strings to jalview datamodel
5793 * Map from jalview datamodel to ID strings
5797 public void setObjectMappingTables(Hashtable vobj2jv,
5798 IdentityHashMap jv2vobj)
5800 this.jv2vobj = jv2vobj;
5801 this.vobj2jv = vobj2jv;
5802 Iterator ds = jv2vobj.keySet().iterator();
5804 while (ds.hasNext())
5806 Object jvobj = ds.next();
5807 id = jv2vobj.get(jvobj).toString();
5808 if (jvobj instanceof jalview.datamodel.Alignment)
5810 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5812 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5815 else if (jvobj instanceof jalview.datamodel.Sequence)
5817 // register sequence object so the XML parser can recover it.
5818 if (seqRefIds == null)
5820 seqRefIds = new HashMap<>();
5822 if (seqsToIds == null)
5824 seqsToIds = new IdentityHashMap<>();
5826 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5827 seqsToIds.put((SequenceI) jvobj, id);
5829 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5832 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5833 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5834 if (jvann.annotationId == null)
5836 jvann.annotationId = anid;
5838 if (!jvann.annotationId.equals(anid))
5840 // TODO verify that this is the correct behaviour
5841 this.warn("Overriding Annotation ID for " + anid
5842 + " from different id : " + jvann.annotationId);
5843 jvann.annotationId = anid;
5846 else if (jvobj instanceof String)
5848 if (jvids2vobj == null)
5850 jvids2vobj = new Hashtable();
5851 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5856 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5862 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5863 * objects created from the project archive. If string is null (default for
5864 * construction) then suffix will be set automatically.
5868 public void setUniqueSetSuffix(String string)
5870 uniqueSetSuffix = string;
5875 * uses skipList2 as the skipList for skipping views on sequence sets
5876 * associated with keys in the skipList
5880 public void setSkipList(Hashtable skipList2)
5882 skipList = skipList2;
5886 * Reads the jar entry of given name and returns its contents, or null if the
5887 * entry is not found.
5890 * @param jarEntryName
5893 protected String readJarEntry(jarInputStreamProvider jprovider,
5894 String jarEntryName)
5896 String result = null;
5897 BufferedReader in = null;
5902 * Reopen the jar input stream and traverse its entries to find a matching
5905 JarInputStream jin = jprovider.getJarInputStream();
5906 JarEntry entry = null;
5909 entry = jin.getNextJarEntry();
5910 } while (entry != null && !entry.getName().equals(jarEntryName));
5914 StringBuilder out = new StringBuilder(256);
5915 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5918 while ((data = in.readLine()) != null)
5922 result = out.toString();
5926 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5928 } catch (Exception ex)
5930 ex.printStackTrace();
5938 } catch (IOException e)
5949 * Returns an incrementing counter (0, 1, 2...)
5953 private synchronized int nextCounter()
5959 * Loads any saved PCA viewers
5964 protected void loadPCAViewers(JalviewModelSequence jms, AlignmentPanel ap)
5968 for (int t = 0; t < jms.getPcaViewerCount(); t++)
5970 PcaViewer viewer = jms.getPcaViewer(t);
5971 String modelName = viewer.getScoreModelName();
5972 SimilarityParamsI params = new SimilarityParams(
5973 viewer.isIncludeGappedColumns(),
5974 viewer.isMatchGaps(), viewer.isIncludeGaps(),
5975 viewer.isDenominateByShortestLength());
5978 * create the panel (without computing the PCA)
5980 PCAPanel panel = new PCAPanel(ap, modelName, params);
5982 panel.setTitle(viewer.getTitle());
5983 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
5984 viewer.getWidth(), viewer.getHeight()));
5986 boolean showLabels = viewer.isShowLabels();
5987 panel.setShowLabels(showLabels);
5988 panel.getRotatableCanvas().setShowLabels(showLabels);
5989 panel.getRotatableCanvas().setBgColour(new Color(viewer.getBgColour()));
5990 panel.getRotatableCanvas().setApplyToAllViews(viewer.isLinkToAllViews());
5993 * load PCA output data
5995 ScoreModelI scoreModel = ScoreModels.getInstance()
5996 .getScoreModel(modelName, ap);
5997 PCA pca = new PCA(null, scoreModel, params);
5998 PcaData pcaData = viewer.getPcaData();
6000 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6001 pca.setPairwiseScores(pairwise);
6003 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6004 pca.setTridiagonal(triDiag);
6006 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6007 pca.setEigenmatrix(result);
6009 panel.getPcaModel().setPCA(pca);
6012 * we haven't saved the input data! (JAL-2647 to do)
6014 panel.setInputData(null);
6017 * add the sequence points for the PCA display
6019 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6020 for (SequencePoint sp : viewer.getSequencePoint())
6022 String seqId = sp.getSequenceRef();
6023 SequenceI seq = seqRefIds.get(seqId);
6026 throw new IllegalStateException(
6027 "Unmatched seqref for PCA: " + seqId);
6029 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6030 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6032 seqPoints.add(seqPoint);
6034 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6037 * set min-max ranges and scale after setPoints (which recomputes them)
6039 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6040 SeqPointMin spMin = viewer.getSeqPointMin();
6041 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6043 SeqPointMax spMax = viewer.getSeqPointMax();
6044 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6046 panel.getRotatableCanvas().setSeqMinMax(min, max);
6048 // todo: hold points list in PCAModel only
6049 panel.getPcaModel().setSequencePoints(seqPoints);
6051 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6052 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6053 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6055 // is this duplication needed?
6056 panel.setTop(seqPoints.size() - 1);
6057 panel.getPcaModel().setTop(seqPoints.size() - 1);
6060 * add the axes' end points for the display
6062 for (int i = 0; i < 3; i++)
6064 Axis axis = viewer.getAxis(i);
6065 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(axis.getXPos(),
6066 axis.getYPos(), axis.getZPos());
6069 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6070 "label.calc_title", "PCA", modelName), 475, 450);
6072 } catch (Exception ex)
6074 Cache.log.error("Error loading PCA: " + ex.toString());
6079 * Populates an XML model of the feature colour scheme for one feature type
6081 * @param featureType
6085 protected static jalview.schemabinding.version2.Colour marshalColour(
6086 String featureType, FeatureColourI fcol)
6088 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
6089 if (fcol.isSimpleColour())
6091 col.setRGB(Format.getHexString(fcol.getColour()));
6095 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6096 col.setMin(fcol.getMin());
6097 col.setMax(fcol.getMax());
6098 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6099 col.setAutoScale(fcol.isAutoScaled());
6100 col.setThreshold(fcol.getThreshold());
6101 col.setColourByLabel(fcol.isColourByLabel());
6102 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
6103 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
6104 : ColourThreshTypeType.NONE));
6105 if (fcol.isColourByAttribute())
6107 col.setAttributeName(fcol.getAttributeName());
6109 Color noColour = fcol.getNoColour();
6110 if (noColour == null)
6112 col.setNoValueColour(NoValueColour.NONE);
6114 else if (noColour == fcol.getMaxColour())
6116 col.setNoValueColour(NoValueColour.MAX);
6120 col.setNoValueColour(NoValueColour.MIN);
6123 col.setName(featureType);
6128 * Populates an XML model of the feature filter(s) for one feature type
6130 * @param firstMatcher
6131 * the first (or only) match condition)
6133 * remaining match conditions (if any)
6135 * if true, conditions are and-ed, else or-ed
6137 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
6138 Iterator<FeatureMatcherI> filters, boolean and)
6140 MatcherSet result = new MatcherSet();
6142 if (filters.hasNext())
6147 CompoundMatcher compound = new CompoundMatcher();
6148 compound.setAnd(and);
6149 MatcherSet matcher1 = marshalFilter(firstMatcher,
6150 Collections.emptyIterator(), and);
6151 compound.addMatcherSet(matcher1);
6152 FeatureMatcherI nextMatcher = filters.next();
6153 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
6154 compound.addMatcherSet(matcher2);
6155 result.setCompoundMatcher(compound);
6160 * single condition matcher
6162 MatchCondition matcherModel = new MatchCondition();
6163 matcherModel.setCondition(
6164 firstMatcher.getMatcher().getCondition().getStableName());
6165 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6166 if (firstMatcher.isByAttribute())
6168 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
6169 matcherModel.setAttributeName(firstMatcher.getAttribute());
6171 else if (firstMatcher.isByLabel())
6173 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
6175 else if (firstMatcher.isByScore())
6177 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
6179 result.setMatchCondition(matcherModel);
6186 * Loads one XML model of a feature filter to a Jalview object
6188 * @param featureType
6189 * @param matcherSetModel
6192 protected static FeatureMatcherSetI unmarshalFilter(
6193 String featureType, MatcherSet matcherSetModel)
6195 FeatureMatcherSetI result = new FeatureMatcherSet();
6198 unmarshalFilterConditions(result, matcherSetModel, true);
6199 } catch (IllegalStateException e)
6201 // mixing AND and OR conditions perhaps
6203 String.format("Error reading filter conditions for '%s': %s",
6204 featureType, e.getMessage()));
6205 // return as much as was parsed up to the error
6212 * Adds feature match conditions to matcherSet as unmarshalled from XML
6213 * (possibly recursively for compound conditions)
6216 * @param matcherSetModel
6218 * if true, multiple conditions are AND-ed, else they are OR-ed
6219 * @throws IllegalStateException
6220 * if AND and OR conditions are mixed
6222 protected static void unmarshalFilterConditions(
6223 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
6226 MatchCondition mc = matcherSetModel.getMatchCondition();
6232 FeatureMatcherByType filterBy = mc.getBy();
6233 Condition cond = Condition.fromString(mc.getCondition());
6234 String pattern = mc.getValue();
6235 FeatureMatcherI matchCondition = null;
6236 if (filterBy == FeatureMatcherByType.BYLABEL)
6238 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6240 else if (filterBy == FeatureMatcherByType.BYSCORE)
6242 matchCondition = FeatureMatcher.byScore(cond, pattern);
6245 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
6247 String[] attNames = mc.getAttributeName();
6248 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6253 * note this throws IllegalStateException if AND-ing to a
6254 * previously OR-ed compound condition, or vice versa
6258 matcherSet.and(matchCondition);
6262 matcherSet.or(matchCondition);
6268 * compound condition
6270 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
6272 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
6273 if (matchers.length == 2)
6275 unmarshalFilterConditions(matcherSet, matchers[0], anded);
6276 unmarshalFilterConditions(matcherSet, matchers[1], anded);
6280 System.err.println("Malformed compound filter condition");
6286 * Loads one XML model of a feature colour to a Jalview object
6288 * @param colourModel
6291 protected static FeatureColourI unmarshalColour(
6292 jalview.schemabinding.version2.Colour colourModel)
6294 FeatureColourI colour = null;
6296 if (colourModel.hasMax())
6298 Color mincol = null;
6299 Color maxcol = null;
6300 Color noValueColour = null;
6304 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6305 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6306 } catch (Exception e)
6308 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6311 NoValueColour noCol = colourModel.getNoValueColour();
6312 if (noCol == NoValueColour.MIN)
6314 noValueColour = mincol;
6316 else if (noCol == NoValueColour.MAX)
6318 noValueColour = maxcol;
6321 colour = new FeatureColour(mincol, maxcol, noValueColour,
6322 colourModel.getMin(),
6323 colourModel.getMax());
6324 String[] attributes = colourModel.getAttributeName();
6325 if (attributes != null && attributes.length > 0)
6327 colour.setAttributeName(attributes);
6329 if (colourModel.hasAutoScale())
6331 colour.setAutoScaled(colourModel.getAutoScale());
6333 if (colourModel.hasColourByLabel())
6335 colour.setColourByLabel(colourModel.getColourByLabel());
6337 if (colourModel.hasThreshold())
6339 colour.setThreshold(colourModel.getThreshold());
6341 ColourThreshTypeType ttyp = colourModel.getThreshType();
6344 if (ttyp == ColourThreshTypeType.ABOVE)
6346 colour.setAboveThreshold(true);
6348 else if (ttyp == ColourThreshTypeType.BELOW)
6350 colour.setBelowThreshold(true);
6356 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6357 colour = new FeatureColour(color);