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 jalview.analysis.Conservation;
24 import jalview.api.FeatureColourI;
25 import jalview.api.ViewStyleI;
26 import jalview.api.structures.JalviewStructureDisplayI;
27 import jalview.bin.Cache;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.GraphLine;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.RnaViewerModel;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.datamodel.StructureViewerModel;
39 import jalview.datamodel.StructureViewerModel.StructureData;
40 import jalview.datamodel.features.FeatureMatcher;
41 import jalview.datamodel.features.FeatureMatcherI;
42 import jalview.datamodel.features.FeatureMatcherSet;
43 import jalview.datamodel.features.FeatureMatcherSetI;
44 import jalview.ext.varna.RnaModel;
45 import jalview.gui.StructureViewer.ViewerType;
46 import jalview.io.BackupFiles;
47 import jalview.io.DataSourceType;
48 import jalview.io.FileFormat;
49 import jalview.renderer.ResidueShaderI;
50 import jalview.schemabinding.version2.AlcodMap;
51 import jalview.schemabinding.version2.AlcodonFrame;
52 import jalview.schemabinding.version2.Annotation;
53 import jalview.schemabinding.version2.AnnotationColours;
54 import jalview.schemabinding.version2.AnnotationElement;
55 import jalview.schemabinding.version2.CalcIdParam;
56 import jalview.schemabinding.version2.CompoundMatcher;
57 import jalview.schemabinding.version2.DBRef;
58 import jalview.schemabinding.version2.Features;
59 import jalview.schemabinding.version2.Group;
60 import jalview.schemabinding.version2.HiddenColumns;
61 import jalview.schemabinding.version2.JGroup;
62 import jalview.schemabinding.version2.JSeq;
63 import jalview.schemabinding.version2.JalviewModel;
64 import jalview.schemabinding.version2.JalviewModelSequence;
65 import jalview.schemabinding.version2.MapListFrom;
66 import jalview.schemabinding.version2.MapListTo;
67 import jalview.schemabinding.version2.Mapping;
68 import jalview.schemabinding.version2.MappingChoice;
69 import jalview.schemabinding.version2.MatchCondition;
70 import jalview.schemabinding.version2.MatcherSet;
71 import jalview.schemabinding.version2.OtherData;
72 import jalview.schemabinding.version2.PdbentryItem;
73 import jalview.schemabinding.version2.Pdbids;
74 import jalview.schemabinding.version2.Property;
75 import jalview.schemabinding.version2.RnaViewer;
76 import jalview.schemabinding.version2.SecondaryStructure;
77 import jalview.schemabinding.version2.Sequence;
78 import jalview.schemabinding.version2.SequenceSet;
79 import jalview.schemabinding.version2.SequenceSetProperties;
80 import jalview.schemabinding.version2.Setting;
81 import jalview.schemabinding.version2.StructureState;
82 import jalview.schemabinding.version2.ThresholdLine;
83 import jalview.schemabinding.version2.Tree;
84 import jalview.schemabinding.version2.UserColours;
85 import jalview.schemabinding.version2.Viewport;
86 import jalview.schemabinding.version2.types.ColourThreshTypeType;
87 import jalview.schemabinding.version2.types.FeatureMatcherByType;
88 import jalview.schemabinding.version2.types.NoValueColour;
89 import jalview.schemes.AnnotationColourGradient;
90 import jalview.schemes.ColourSchemeI;
91 import jalview.schemes.ColourSchemeProperty;
92 import jalview.schemes.FeatureColour;
93 import jalview.schemes.ResidueProperties;
94 import jalview.schemes.UserColourScheme;
95 import jalview.structure.StructureSelectionManager;
96 import jalview.structures.models.AAStructureBindingModel;
97 import jalview.util.Format;
98 import jalview.util.MessageManager;
99 import jalview.util.Platform;
100 import jalview.util.StringUtils;
101 import jalview.util.jarInputStreamProvider;
102 import jalview.util.matcher.Condition;
103 import jalview.viewmodel.AlignmentViewport;
104 import jalview.viewmodel.ViewportRanges;
105 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
106 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
107 import jalview.ws.jws2.Jws2Discoverer;
108 import jalview.ws.jws2.dm.AAConSettings;
109 import jalview.ws.jws2.jabaws2.Jws2Instance;
110 import jalview.ws.params.ArgumentI;
111 import jalview.ws.params.AutoCalcSetting;
112 import jalview.ws.params.WsParamSetI;
114 import java.awt.Color;
115 import java.awt.Rectangle;
116 import java.io.BufferedReader;
117 import java.io.DataInputStream;
118 import java.io.DataOutputStream;
120 import java.io.FileInputStream;
121 import java.io.FileOutputStream;
122 import java.io.IOException;
123 import java.io.InputStreamReader;
124 import java.io.OutputStreamWriter;
125 import java.io.PrintWriter;
126 import java.lang.reflect.InvocationTargetException;
127 import java.net.MalformedURLException;
129 import java.util.ArrayList;
130 import java.util.Arrays;
131 import java.util.Collections;
132 import java.util.Enumeration;
133 import java.util.HashMap;
134 import java.util.HashSet;
135 import java.util.Hashtable;
136 import java.util.IdentityHashMap;
137 import java.util.Iterator;
138 import java.util.LinkedHashMap;
139 import java.util.List;
140 import java.util.Map;
141 import java.util.Map.Entry;
142 import java.util.Set;
143 import java.util.Vector;
144 import java.util.jar.JarEntry;
145 import java.util.jar.JarInputStream;
146 import java.util.jar.JarOutputStream;
148 import javax.swing.JInternalFrame;
149 import javax.swing.SwingUtilities;
151 import org.exolab.castor.xml.Marshaller;
152 import org.exolab.castor.xml.Unmarshaller;
155 * Write out the current jalview desktop state as a Jalview XML stream.
157 * Note: the vamsas objects referred to here are primitive versions of the
158 * VAMSAS project schema elements - they are not the same and most likely never
162 * @version $Revision: 1.134 $
164 public class Jalview2XML
166 private static final String VIEWER_PREFIX = "viewer_";
168 private static final String RNA_PREFIX = "rna_";
170 private static final String UTF_8 = "UTF-8";
172 // use this with nextCounter() to make unique names for entities
173 private int counter = 0;
176 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
177 * of sequence objects are created.
179 IdentityHashMap<SequenceI, String> seqsToIds = null;
182 * jalview XML Sequence ID to jalview sequence object reference (both dataset
183 * and alignment sequences. Populated as XML reps of sequence objects are
186 Map<String, SequenceI> seqRefIds = null;
188 Map<String, SequenceI> incompleteSeqs = null;
190 List<SeqFref> frefedSequence = null;
192 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
195 * Map of reconstructed AlignFrame objects that appear to have come from
196 * SplitFrame objects (have a dna/protein complement view).
198 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
201 * Map from displayed rna structure models to their saved session state jar
204 private Map<RnaModel, String> rnaSessions = new HashMap<>();
207 * create/return unique hash string for sq
210 * @return new or existing unique string for sq
212 String seqHash(SequenceI sq)
214 if (seqsToIds == null)
218 if (seqsToIds.containsKey(sq))
220 return seqsToIds.get(sq);
224 // create sequential key
225 String key = "sq" + (seqsToIds.size() + 1);
226 key = makeHashCode(sq, key); // check we don't have an external reference
228 seqsToIds.put(sq, key);
235 if (seqsToIds == null)
237 seqsToIds = new IdentityHashMap<>();
239 if (seqRefIds == null)
241 seqRefIds = new HashMap<>();
243 if (incompleteSeqs == null)
245 incompleteSeqs = new HashMap<>();
247 if (frefedSequence == null)
249 frefedSequence = new ArrayList<>();
257 public Jalview2XML(boolean raiseGUI)
259 this.raiseGUI = raiseGUI;
263 * base class for resolving forward references to sequences by their ID
268 abstract class SeqFref
274 public SeqFref(String _sref, String type)
280 public String getSref()
285 public SequenceI getSrefSeq()
287 return seqRefIds.get(sref);
290 public boolean isResolvable()
292 return seqRefIds.get(sref) != null;
295 public SequenceI getSrefDatasetSeq()
297 SequenceI sq = seqRefIds.get(sref);
300 while (sq.getDatasetSequence() != null)
302 sq = sq.getDatasetSequence();
309 * @return true if the forward reference was fully resolved
311 abstract boolean resolve();
314 public String toString()
316 return type + " reference to " + sref;
321 * create forward reference for a mapping
327 public SeqFref newMappingRef(final String sref,
328 final jalview.datamodel.Mapping _jmap)
330 SeqFref fref = new SeqFref(sref, "Mapping")
332 public jalview.datamodel.Mapping jmap = _jmap;
337 SequenceI seq = getSrefDatasetSeq();
349 public SeqFref newAlcodMapRef(final String sref,
350 final AlignedCodonFrame _cf,
351 final jalview.datamodel.Mapping _jmap)
354 SeqFref fref = new SeqFref(sref, "Codon Frame")
356 AlignedCodonFrame cf = _cf;
358 public jalview.datamodel.Mapping mp = _jmap;
361 public boolean isResolvable()
363 return super.isResolvable() && mp.getTo() != null;
369 SequenceI seq = getSrefDatasetSeq();
374 cf.addMap(seq, mp.getTo(), mp.getMap());
381 public void resolveFrefedSequences()
383 Iterator<SeqFref> nextFref = frefedSequence.iterator();
384 int toresolve = frefedSequence.size();
385 int unresolved = 0, failedtoresolve = 0;
386 while (nextFref.hasNext())
388 SeqFref ref = nextFref.next();
389 if (ref.isResolvable())
401 } catch (Exception x)
404 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
417 System.err.println("Jalview Project Import: There were " + unresolved
418 + " forward references left unresolved on the stack.");
420 if (failedtoresolve > 0)
422 System.err.println("SERIOUS! " + failedtoresolve
423 + " resolvable forward references failed to resolve.");
425 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
428 "Jalview Project Import: There are " + incompleteSeqs.size()
429 + " sequences which may have incomplete metadata.");
430 if (incompleteSeqs.size() < 10)
432 for (SequenceI s : incompleteSeqs.values())
434 System.err.println(s.toString());
440 "Too many to report. Skipping output of incomplete sequences.");
446 * This maintains a map of viewports, the key being the seqSetId. Important to
447 * set historyItem and redoList for multiple views
449 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
451 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
453 String uniqueSetSuffix = "";
456 * List of pdbfiles added to Jar
458 List<String> pdbfiles = null;
460 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
461 public void saveState(File statefile)
463 FileOutputStream fos = null;
467 fos = new FileOutputStream(statefile);
469 JarOutputStream jout = new JarOutputStream(fos);
472 } catch (Exception e)
474 // TODO: inform user of the problem - they need to know if their data was
476 if (errorMessage == null)
478 errorMessage = "Couldn't write Jalview Archive to output file '"
479 + statefile + "' - See console error log for details";
483 errorMessage += "(output file was '" + statefile + "')";
493 } catch (IOException e)
503 * Writes a jalview project archive to the given Jar output stream.
507 public void saveState(JarOutputStream jout)
509 AlignFrame[] frames = Desktop.getAlignFrames();
515 saveAllFrames(Arrays.asList(frames), jout);
519 * core method for storing state for a set of AlignFrames.
522 * - frames involving all data to be exported (including containing
525 * - project output stream
527 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
529 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
532 * ensure cached data is clear before starting
534 // todo tidy up seqRefIds, seqsToIds initialisation / reset
536 splitFrameCandidates.clear();
541 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
542 // //////////////////////////////////////////////////
544 List<String> shortNames = new ArrayList<>();
545 List<String> viewIds = new ArrayList<>();
548 for (int i = frames.size() - 1; i > -1; i--)
550 AlignFrame af = frames.get(i);
552 if (skipList != null && skipList
553 .containsKey(af.getViewport().getSequenceSetId()))
558 String shortName = makeFilename(af, shortNames);
560 int ap, apSize = af.alignPanels.size();
562 for (ap = 0; ap < apSize; ap++)
564 AlignmentPanel apanel = af.alignPanels.get(ap);
565 String fileName = apSize == 1 ? shortName : ap + shortName;
566 if (!fileName.endsWith(".xml"))
568 fileName = fileName + ".xml";
571 saveState(apanel, fileName, jout, viewIds);
573 String dssid = getDatasetIdRef(
574 af.getViewport().getAlignment().getDataset());
575 if (!dsses.containsKey(dssid))
577 dsses.put(dssid, af);
582 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
588 } catch (Exception foo)
593 } catch (Exception ex)
595 // TODO: inform user of the problem - they need to know if their data was
597 if (errorMessage == null)
599 errorMessage = "Couldn't write Jalview Archive - see error output for details";
601 ex.printStackTrace();
606 * Generates a distinct file name, based on the title of the AlignFrame, by
607 * appending _n for increasing n until an unused name is generated. The new
608 * name (without its extension) is added to the list.
612 * @return the generated name, with .xml extension
614 protected String makeFilename(AlignFrame af, List<String> namesUsed)
616 String shortName = af.getTitle();
618 if (shortName.indexOf(File.separatorChar) > -1)
620 shortName = shortName
621 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
626 while (namesUsed.contains(shortName))
628 if (shortName.endsWith("_" + (count - 1)))
630 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
633 shortName = shortName.concat("_" + count);
637 namesUsed.add(shortName);
639 if (!shortName.endsWith(".xml"))
641 shortName = shortName + ".xml";
646 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
647 public boolean saveAlignment(AlignFrame af, String jarFile,
652 // create backupfiles object and get new temp filename destination
653 BackupFiles backupfiles = new BackupFiles(jarFile);
654 FileOutputStream fos = new FileOutputStream(
655 backupfiles.getTempFilePath());
657 JarOutputStream jout = new JarOutputStream(fos);
658 List<AlignFrame> frames = new ArrayList<>();
660 // resolve splitframes
661 if (af.getViewport().getCodingComplement() != null)
663 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
669 saveAllFrames(frames, jout);
673 } catch (Exception foo)
678 boolean success = true;
680 backupfiles.setWriteSuccess(success);
681 success = backupfiles.rollBackupsAndRenameTempFile();
684 } catch (Exception ex)
686 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
687 ex.printStackTrace();
692 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
693 String fileName, JarOutputStream jout)
696 for (String dssids : dsses.keySet())
698 AlignFrame _af = dsses.get(dssids);
699 String jfileName = fileName + " Dataset for " + _af.getTitle();
700 if (!jfileName.endsWith(".xml"))
702 jfileName = jfileName + ".xml";
704 saveState(_af.alignPanel, jfileName, true, jout, null);
709 * create a JalviewModel from an alignment view and marshall it to a
713 * panel to create jalview model for
715 * name of alignment panel written to output stream
722 public JalviewModel saveState(AlignmentPanel ap, String fileName,
723 JarOutputStream jout, List<String> viewIds)
725 return saveState(ap, fileName, false, jout, viewIds);
729 * create a JalviewModel from an alignment view and marshall it to a
733 * panel to create jalview model for
735 * name of alignment panel written to output stream
737 * when true, only write the dataset for the alignment, not the data
738 * associated with the view.
744 public JalviewModel saveState(AlignmentPanel ap, String fileName,
745 boolean storeDS, JarOutputStream jout, List<String> viewIds)
749 viewIds = new ArrayList<>();
754 List<UserColourScheme> userColours = new ArrayList<>();
756 AlignViewport av = ap.av;
757 ViewportRanges vpRanges = av.getRanges();
759 JalviewModel object = new JalviewModel();
760 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
762 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
764 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
767 * rjal is full height alignment, jal is actual alignment with full metadata
768 * but excludes hidden sequences.
770 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
772 if (av.hasHiddenRows())
774 rjal = jal.getHiddenSequences().getFullAlignment();
777 SequenceSet vamsasSet = new SequenceSet();
779 JalviewModelSequence jms = new JalviewModelSequence();
781 vamsasSet.setGapChar(jal.getGapCharacter() + "");
783 if (jal.getDataset() != null)
785 // dataset id is the dataset's hashcode
786 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
789 // switch jal and the dataset
790 jal = jal.getDataset();
794 if (jal.getProperties() != null)
796 Enumeration en = jal.getProperties().keys();
797 while (en.hasMoreElements())
799 String key = en.nextElement().toString();
800 SequenceSetProperties ssp = new SequenceSetProperties();
802 ssp.setValue(jal.getProperties().get(key).toString());
803 vamsasSet.addSequenceSetProperties(ssp);
808 Set<String> calcIdSet = new HashSet<>();
809 // record the set of vamsas sequence XML POJO we create.
810 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
812 for (final SequenceI jds : rjal.getSequences())
814 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
815 : jds.getDatasetSequence();
816 String id = seqHash(jds);
817 if (vamsasSetIds.get(id) == null)
819 if (seqRefIds.get(id) != null && !storeDS)
821 // This happens for two reasons: 1. multiple views are being
823 // 2. the hashCode has collided with another sequence's code. This
825 // HAPPEN! (PF00072.15.stk does this)
826 // JBPNote: Uncomment to debug writing out of files that do not read
827 // back in due to ArrayOutOfBoundExceptions.
828 // System.err.println("vamsasSeq backref: "+id+"");
829 // System.err.println(jds.getName()+"
830 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
831 // System.err.println("Hashcode: "+seqHash(jds));
832 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
833 // System.err.println(rsq.getName()+"
834 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
835 // System.err.println("Hashcode: "+seqHash(rsq));
839 vamsasSeq = createVamsasSequence(id, jds);
840 vamsasSet.addSequence(vamsasSeq);
841 vamsasSetIds.put(id, vamsasSeq);
842 seqRefIds.put(id, jds);
846 jseq.setStart(jds.getStart());
847 jseq.setEnd(jds.getEnd());
848 jseq.setColour(av.getSequenceColour(jds).getRGB());
850 jseq.setId(id); // jseq id should be a string not a number
853 // Store any sequences this sequence represents
854 if (av.hasHiddenRows())
856 // use rjal, contains the full height alignment
858 av.getAlignment().getHiddenSequences().isHidden(jds));
860 if (av.isHiddenRepSequence(jds))
862 jalview.datamodel.SequenceI[] reps = av
863 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
865 for (int h = 0; h < reps.length; h++)
869 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
874 // mark sequence as reference - if it is the reference for this view
877 jseq.setViewreference(jds == jal.getSeqrep());
881 // TODO: omit sequence features from each alignment view's XML dump if we
882 // are storing dataset
883 List<jalview.datamodel.SequenceFeature> sfs = jds
884 .getSequenceFeatures();
885 for (SequenceFeature sf : sfs)
887 Features features = new Features();
889 features.setBegin(sf.getBegin());
890 features.setEnd(sf.getEnd());
891 features.setDescription(sf.getDescription());
892 features.setType(sf.getType());
893 features.setFeatureGroup(sf.getFeatureGroup());
894 features.setScore(sf.getScore());
895 if (sf.links != null)
897 for (int l = 0; l < sf.links.size(); l++)
899 OtherData keyValue = new OtherData();
900 keyValue.setKey("LINK_" + l);
901 keyValue.setValue(sf.links.elementAt(l).toString());
902 features.addOtherData(keyValue);
905 if (sf.otherDetails != null)
908 * save feature attributes, which may be simple strings or
909 * map valued (have sub-attributes)
911 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
913 String key = entry.getKey();
914 Object value = entry.getValue();
915 if (value instanceof Map<?, ?>)
917 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
920 OtherData otherData = new OtherData();
921 otherData.setKey(key);
922 otherData.setKey2(subAttribute.getKey());
923 otherData.setValue(subAttribute.getValue().toString());
924 features.addOtherData(otherData);
929 OtherData otherData = new OtherData();
930 otherData.setKey(key);
931 otherData.setValue(value.toString());
932 features.addOtherData(otherData);
937 jseq.addFeatures(features);
940 if (jdatasq.getAllPDBEntries() != null)
942 Enumeration en = jdatasq.getAllPDBEntries().elements();
943 while (en.hasMoreElements())
945 Pdbids pdb = new Pdbids();
946 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
949 String pdbId = entry.getId();
951 pdb.setType(entry.getType());
954 * Store any structure views associated with this sequence. This
955 * section copes with duplicate entries in the project, so a dataset
956 * only view *should* be coped with sensibly.
958 // This must have been loaded, is it still visible?
959 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
960 String matchedFile = null;
961 for (int f = frames.length - 1; f > -1; f--)
963 if (frames[f] instanceof StructureViewerBase)
965 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
966 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
967 matchedFile, viewFrame);
969 * Only store each structure viewer's state once in the project
970 * jar. First time through only (storeDS==false)
972 String viewId = viewFrame.getViewId();
973 if (!storeDS && !viewIds.contains(viewId))
978 String viewerState = viewFrame.getStateInfo();
979 writeJarEntry(jout, getViewerJarEntryName(viewId),
980 viewerState.getBytes());
981 } catch (IOException e)
984 "Error saving viewer state: " + e.getMessage());
990 if (matchedFile != null || entry.getFile() != null)
992 if (entry.getFile() != null)
995 matchedFile = entry.getFile();
997 pdb.setFile(matchedFile); // entry.getFile());
998 if (pdbfiles == null)
1000 pdbfiles = new ArrayList<>();
1003 if (!pdbfiles.contains(pdbId))
1005 pdbfiles.add(pdbId);
1006 copyFileToJar(jout, matchedFile, pdbId);
1010 Enumeration<String> props = entry.getProperties();
1011 if (props.hasMoreElements())
1013 PdbentryItem item = new PdbentryItem();
1014 while (props.hasMoreElements())
1016 Property prop = new Property();
1017 String key = props.nextElement();
1019 prop.setValue(entry.getProperty(key).toString());
1020 item.addProperty(prop);
1022 pdb.addPdbentryItem(item);
1025 jseq.addPdbids(pdb);
1029 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1034 if (!storeDS && av.hasHiddenRows())
1036 jal = av.getAlignment();
1040 if (storeDS && jal.getCodonFrames() != null)
1042 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1043 for (AlignedCodonFrame acf : jac)
1045 AlcodonFrame alc = new AlcodonFrame();
1046 if (acf.getProtMappings() != null
1047 && acf.getProtMappings().length > 0)
1049 boolean hasMap = false;
1050 SequenceI[] dnas = acf.getdnaSeqs();
1051 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1052 for (int m = 0; m < pmaps.length; m++)
1054 AlcodMap alcmap = new AlcodMap();
1055 alcmap.setDnasq(seqHash(dnas[m]));
1057 createVamsasMapping(pmaps[m], dnas[m], null, false));
1058 alc.addAlcodMap(alcmap);
1063 vamsasSet.addAlcodonFrame(alc);
1066 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1068 // AlcodonFrame alc = new AlcodonFrame();
1069 // vamsasSet.addAlcodonFrame(alc);
1070 // for (int p = 0; p < acf.aaWidth; p++)
1072 // Alcodon cmap = new Alcodon();
1073 // if (acf.codons[p] != null)
1075 // // Null codons indicate a gapped column in the translated peptide
1077 // cmap.setPos1(acf.codons[p][0]);
1078 // cmap.setPos2(acf.codons[p][1]);
1079 // cmap.setPos3(acf.codons[p][2]);
1081 // alc.addAlcodon(cmap);
1083 // if (acf.getProtMappings() != null
1084 // && acf.getProtMappings().length > 0)
1086 // SequenceI[] dnas = acf.getdnaSeqs();
1087 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1088 // for (int m = 0; m < pmaps.length; m++)
1090 // AlcodMap alcmap = new AlcodMap();
1091 // alcmap.setDnasq(seqHash(dnas[m]));
1092 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1094 // alc.addAlcodMap(alcmap);
1101 // /////////////////////////////////
1102 if (!storeDS && av.getCurrentTree() != null)
1104 // FIND ANY ASSOCIATED TREES
1105 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1106 if (Desktop.desktop != null)
1108 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1110 for (int t = 0; t < frames.length; t++)
1112 if (frames[t] instanceof TreePanel)
1114 TreePanel tp = (TreePanel) frames[t];
1116 if (tp.treeCanvas.av.getAlignment() == jal)
1118 Tree tree = new Tree();
1119 tree.setTitle(tp.getTitle());
1120 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1121 tree.setNewick(tp.getTree().print());
1122 tree.setThreshold(tp.treeCanvas.threshold);
1124 tree.setFitToWindow(tp.fitToWindow.getState());
1125 tree.setFontName(tp.getTreeFont().getName());
1126 tree.setFontSize(tp.getTreeFont().getSize());
1127 tree.setFontStyle(tp.getTreeFont().getStyle());
1128 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1130 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1131 tree.setShowDistances(tp.distanceMenu.getState());
1133 tree.setHeight(tp.getHeight());
1134 tree.setWidth(tp.getWidth());
1135 tree.setXpos(tp.getX());
1136 tree.setYpos(tp.getY());
1137 tree.setId(makeHashCode(tp, null));
1147 * store forward refs from an annotationRow to any groups
1149 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1152 for (SequenceI sq : jal.getSequences())
1154 // Store annotation on dataset sequences only
1155 AlignmentAnnotation[] aa = sq.getAnnotation();
1156 if (aa != null && aa.length > 0)
1158 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1165 if (jal.getAlignmentAnnotation() != null)
1167 // Store the annotation shown on the alignment.
1168 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1169 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1174 if (jal.getGroups() != null)
1176 JGroup[] groups = new JGroup[jal.getGroups().size()];
1178 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1180 JGroup jGroup = new JGroup();
1181 groups[++i] = jGroup;
1183 jGroup.setStart(sg.getStartRes());
1184 jGroup.setEnd(sg.getEndRes());
1185 jGroup.setName(sg.getName());
1186 if (groupRefs.containsKey(sg))
1188 // group has references so set its ID field
1189 jGroup.setId(groupRefs.get(sg));
1191 ColourSchemeI colourScheme = sg.getColourScheme();
1192 if (colourScheme != null)
1194 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1195 if (groupColourScheme.conservationApplied())
1197 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1199 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1202 setUserColourScheme(colourScheme, userColours, jms));
1206 jGroup.setColour(colourScheme.getSchemeName());
1209 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1211 jGroup.setColour("AnnotationColourGradient");
1212 jGroup.setAnnotationColours(constructAnnotationColours(
1213 (jalview.schemes.AnnotationColourGradient) colourScheme,
1216 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1219 setUserColourScheme(colourScheme, userColours, jms));
1223 jGroup.setColour(colourScheme.getSchemeName());
1226 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1229 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1230 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1231 jGroup.setDisplayText(sg.getDisplayText());
1232 jGroup.setColourText(sg.getColourText());
1233 jGroup.setTextCol1(sg.textColour.getRGB());
1234 jGroup.setTextCol2(sg.textColour2.getRGB());
1235 jGroup.setTextColThreshold(sg.thresholdTextColour);
1236 jGroup.setShowUnconserved(sg.getShowNonconserved());
1237 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1238 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1239 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1240 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1241 for (SequenceI seq : sg.getSequences())
1243 jGroup.addSeq(seqHash(seq));
1247 jms.setJGroup(groups);
1251 // /////////SAVE VIEWPORT
1252 Viewport view = new Viewport();
1253 view.setTitle(ap.alignFrame.getTitle());
1254 view.setSequenceSetId(
1255 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1256 view.setId(av.getViewId());
1257 if (av.getCodingComplement() != null)
1259 view.setComplementId(av.getCodingComplement().getViewId());
1261 view.setViewName(av.viewName);
1262 view.setGatheredViews(av.isGatherViewsHere());
1264 Rectangle size = ap.av.getExplodedGeometry();
1265 Rectangle position = size;
1268 size = ap.alignFrame.getBounds();
1269 if (av.getCodingComplement() != null)
1271 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1279 view.setXpos(position.x);
1280 view.setYpos(position.y);
1282 view.setWidth(size.width);
1283 view.setHeight(size.height);
1285 view.setStartRes(vpRanges.getStartRes());
1286 view.setStartSeq(vpRanges.getStartSeq());
1288 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1290 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1294 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1296 AnnotationColours ac = constructAnnotationColours(
1297 (jalview.schemes.AnnotationColourGradient) av
1298 .getGlobalColourScheme(),
1301 view.setAnnotationColours(ac);
1302 view.setBgColour("AnnotationColourGradient");
1306 view.setBgColour(ColourSchemeProperty
1307 .getColourName(av.getGlobalColourScheme()));
1310 ResidueShaderI vcs = av.getResidueShading();
1311 ColourSchemeI cs = av.getGlobalColourScheme();
1315 if (vcs.conservationApplied())
1317 view.setConsThreshold(vcs.getConservationInc());
1318 if (cs instanceof jalview.schemes.UserColourScheme)
1320 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1323 view.setPidThreshold(vcs.getThreshold());
1326 view.setConservationSelected(av.getConservationSelected());
1327 view.setPidSelected(av.getAbovePIDThreshold());
1328 view.setFontName(av.font.getName());
1329 view.setFontSize(av.font.getSize());
1330 view.setFontStyle(av.font.getStyle());
1331 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1332 view.setRenderGaps(av.isRenderGaps());
1333 view.setShowAnnotation(av.isShowAnnotation());
1334 view.setShowBoxes(av.getShowBoxes());
1335 view.setShowColourText(av.getColourText());
1336 view.setShowFullId(av.getShowJVSuffix());
1337 view.setRightAlignIds(av.isRightAlignIds());
1338 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1339 view.setShowText(av.getShowText());
1340 view.setShowUnconserved(av.getShowUnconserved());
1341 view.setWrapAlignment(av.getWrapAlignment());
1342 view.setTextCol1(av.getTextColour().getRGB());
1343 view.setTextCol2(av.getTextColour2().getRGB());
1344 view.setTextColThreshold(av.getThresholdTextColour());
1345 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1346 view.setShowSequenceLogo(av.isShowSequenceLogo());
1347 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1348 view.setShowGroupConsensus(av.isShowGroupConsensus());
1349 view.setShowGroupConservation(av.isShowGroupConservation());
1350 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1351 view.setShowDbRefTooltip(av.isShowDBRefs());
1352 view.setFollowHighlight(av.isFollowHighlight());
1353 view.setFollowSelection(av.followSelection);
1354 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1355 if (av.getFeaturesDisplayed() != null)
1357 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1359 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1360 .getFeatureRenderer();
1361 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1363 Vector<String> settingsAdded = new Vector<>();
1364 if (renderOrder != null)
1366 for (String featureType : renderOrder)
1368 Setting setting = new Setting();
1369 setting.setType(featureType);
1372 * save any filter for the feature type
1374 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1375 if (filter != null) {
1376 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1377 FeatureMatcherI firstFilter = filters.next();
1378 setting.setMatcherSet(Jalview2XML.marshalFilter(
1379 firstFilter, filters, filter.isAnded()));
1383 * save colour scheme for the feature type
1385 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1386 if (!fcol.isSimpleColour())
1388 setting.setColour(fcol.getMaxColour().getRGB());
1389 setting.setMincolour(fcol.getMinColour().getRGB());
1390 setting.setMin(fcol.getMin());
1391 setting.setMax(fcol.getMax());
1392 setting.setColourByLabel(fcol.isColourByLabel());
1393 if (fcol.isColourByAttribute())
1395 setting.setAttributeName(fcol.getAttributeName());
1397 setting.setAutoScale(fcol.isAutoScaled());
1398 setting.setThreshold(fcol.getThreshold());
1399 Color noColour = fcol.getNoColour();
1400 if (noColour == null)
1402 setting.setNoValueColour(NoValueColour.NONE);
1404 else if (noColour.equals(fcol.getMaxColour()))
1406 setting.setNoValueColour(NoValueColour.MAX);
1410 setting.setNoValueColour(NoValueColour.MIN);
1412 // -1 = No threshold, 0 = Below, 1 = Above
1413 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1414 : (fcol.isBelowThreshold() ? 0 : -1));
1418 setting.setColour(fcol.getColour().getRGB());
1422 av.getFeaturesDisplayed().isVisible(featureType));
1424 .getOrder(featureType);
1427 setting.setOrder(rorder);
1429 fs.addSetting(setting);
1430 settingsAdded.addElement(featureType);
1434 // is groups actually supposed to be a map here ?
1435 Iterator<String> en = fr.getFeatureGroups().iterator();
1436 Vector<String> groupsAdded = new Vector<>();
1437 while (en.hasNext())
1439 String grp = en.next();
1440 if (groupsAdded.contains(grp))
1444 Group g = new Group();
1446 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1449 groupsAdded.addElement(grp);
1451 jms.setFeatureSettings(fs);
1454 if (av.hasHiddenColumns())
1456 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1457 .getHiddenColumns();
1460 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1464 Iterator<int[]> hiddenRegions = hidden.iterator();
1465 while (hiddenRegions.hasNext())
1467 int[] region = hiddenRegions.next();
1468 HiddenColumns hc = new HiddenColumns();
1469 hc.setStart(region[0]);
1470 hc.setEnd(region[1]);
1471 view.addHiddenColumns(hc);
1475 if (calcIdSet.size() > 0)
1477 for (String calcId : calcIdSet)
1479 if (calcId.trim().length() > 0)
1481 CalcIdParam cidp = createCalcIdParam(calcId, av);
1482 // Some calcIds have no parameters.
1485 view.addCalcIdParam(cidp);
1491 jms.addViewport(view);
1493 object.setJalviewModelSequence(jms);
1494 object.getVamsasModel().addSequenceSet(vamsasSet);
1496 if (jout != null && fileName != null)
1498 // We may not want to write the object to disk,
1499 // eg we can copy the alignViewport to a new view object
1500 // using save and then load
1503 System.out.println("Writing jar entry " + fileName);
1504 JarEntry entry = new JarEntry(fileName);
1505 jout.putNextEntry(entry);
1506 PrintWriter pout = new PrintWriter(
1507 new OutputStreamWriter(jout, UTF_8));
1508 Marshaller marshaller = new Marshaller(pout);
1509 marshaller.marshal(object);
1512 } catch (Exception ex)
1514 // TODO: raise error in GUI if marshalling failed.
1515 ex.printStackTrace();
1522 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1523 * for each viewer, with
1525 * <li>viewer geometry (position, size, split pane divider location)</li>
1526 * <li>index of the selected structure in the viewer (currently shows gapped
1528 * <li>the id of the annotation holding RNA secondary structure</li>
1529 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1531 * Varna viewer state is also written out (in native Varna XML) to separate
1532 * project jar entries. A separate entry is written for each RNA structure
1533 * displayed, with the naming convention
1535 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1543 * @param storeDataset
1545 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1546 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1547 boolean storeDataset)
1549 if (Desktop.desktop == null)
1553 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1554 for (int f = frames.length - 1; f > -1; f--)
1556 if (frames[f] instanceof AppVarna)
1558 AppVarna varna = (AppVarna) frames[f];
1560 * link the sequence to every viewer that is showing it and is linked to
1561 * its alignment panel
1563 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1565 String viewId = varna.getViewId();
1566 RnaViewer rna = new RnaViewer();
1567 rna.setViewId(viewId);
1568 rna.setTitle(varna.getTitle());
1569 rna.setXpos(varna.getX());
1570 rna.setYpos(varna.getY());
1571 rna.setWidth(varna.getWidth());
1572 rna.setHeight(varna.getHeight());
1573 rna.setDividerLocation(varna.getDividerLocation());
1574 rna.setSelectedRna(varna.getSelectedIndex());
1575 jseq.addRnaViewer(rna);
1578 * Store each Varna panel's state once in the project per sequence.
1579 * First time through only (storeDataset==false)
1581 // boolean storeSessions = false;
1582 // String sequenceViewId = viewId + seqsToIds.get(jds);
1583 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1585 // viewIds.add(sequenceViewId);
1586 // storeSessions = true;
1588 for (RnaModel model : varna.getModels())
1590 if (model.seq == jds)
1593 * VARNA saves each view (sequence or alignment secondary
1594 * structure, gapped or trimmed) as a separate XML file
1596 String jarEntryName = rnaSessions.get(model);
1597 if (jarEntryName == null)
1600 String varnaStateFile = varna.getStateInfo(model.rna);
1601 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1602 copyFileToJar(jout, varnaStateFile, jarEntryName);
1603 rnaSessions.put(model, jarEntryName);
1605 SecondaryStructure ss = new SecondaryStructure();
1606 String annotationId = varna.getAnnotation(jds).annotationId;
1607 ss.setAnnotationId(annotationId);
1608 ss.setViewerState(jarEntryName);
1609 ss.setGapped(model.gapped);
1610 ss.setTitle(model.title);
1611 rna.addSecondaryStructure(ss);
1620 * Copy the contents of a file to a new entry added to the output jar
1624 * @param jarEntryName
1626 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1627 String jarEntryName)
1629 DataInputStream dis = null;
1632 File file = new File(infilePath);
1633 if (file.exists() && jout != null)
1635 dis = new DataInputStream(new FileInputStream(file));
1636 byte[] data = new byte[(int) file.length()];
1637 dis.readFully(data);
1638 writeJarEntry(jout, jarEntryName, data);
1640 } catch (Exception ex)
1642 ex.printStackTrace();
1650 } catch (IOException e)
1659 * Write the data to a new entry of given name in the output jar file
1662 * @param jarEntryName
1664 * @throws IOException
1666 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1667 byte[] data) throws IOException
1671 System.out.println("Writing jar entry " + jarEntryName);
1672 jout.putNextEntry(new JarEntry(jarEntryName));
1673 DataOutputStream dout = new DataOutputStream(jout);
1674 dout.write(data, 0, data.length);
1681 * Save the state of a structure viewer
1686 * the archive XML element under which to save the state
1689 * @param matchedFile
1693 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1694 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1695 String matchedFile, StructureViewerBase viewFrame)
1697 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1700 * Look for any bindings for this viewer to the PDB file of interest
1701 * (including part matches excluding chain id)
1703 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1705 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1706 final String pdbId = pdbentry.getId();
1707 if (!pdbId.equals(entry.getId())
1708 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1709 .startsWith(pdbId.toLowerCase())))
1712 * not interested in a binding to a different PDB entry here
1716 if (matchedFile == null)
1718 matchedFile = pdbentry.getFile();
1720 else if (!matchedFile.equals(pdbentry.getFile()))
1723 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1724 + pdbentry.getFile());
1728 // can get at it if the ID
1729 // match is ambiguous (e.g.
1732 for (int smap = 0; smap < viewFrame.getBinding()
1733 .getSequence()[peid].length; smap++)
1735 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1736 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1738 StructureState state = new StructureState();
1739 state.setVisible(true);
1740 state.setXpos(viewFrame.getX());
1741 state.setYpos(viewFrame.getY());
1742 state.setWidth(viewFrame.getWidth());
1743 state.setHeight(viewFrame.getHeight());
1744 final String viewId = viewFrame.getViewId();
1745 state.setViewId(viewId);
1746 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1747 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1748 state.setColourByJmol(viewFrame.isColouredByViewer());
1749 state.setType(viewFrame.getViewerType().toString());
1750 pdb.addStructureState(state);
1758 * Populates the AnnotationColours xml for save. This captures the settings of
1759 * the options in the 'Colour by Annotation' dialog.
1762 * @param userColours
1766 private AnnotationColours constructAnnotationColours(
1767 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1768 JalviewModelSequence jms)
1770 AnnotationColours ac = new AnnotationColours();
1771 ac.setAboveThreshold(acg.getAboveThreshold());
1772 ac.setThreshold(acg.getAnnotationThreshold());
1773 // 2.10.2 save annotationId (unique) not annotation label
1774 ac.setAnnotation(acg.getAnnotation().annotationId);
1775 if (acg.getBaseColour() instanceof UserColourScheme)
1778 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1783 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1786 ac.setMaxColour(acg.getMaxColour().getRGB());
1787 ac.setMinColour(acg.getMinColour().getRGB());
1788 ac.setPerSequence(acg.isSeqAssociated());
1789 ac.setPredefinedColours(acg.isPredefinedColours());
1793 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1794 IdentityHashMap<SequenceGroup, String> groupRefs,
1795 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1796 SequenceSet vamsasSet)
1799 for (int i = 0; i < aa.length; i++)
1801 Annotation an = new Annotation();
1803 AlignmentAnnotation annotation = aa[i];
1804 if (annotation.annotationId != null)
1806 annotationIds.put(annotation.annotationId, annotation);
1809 an.setId(annotation.annotationId);
1811 an.setVisible(annotation.visible);
1813 an.setDescription(annotation.description);
1815 if (annotation.sequenceRef != null)
1817 // 2.9 JAL-1781 xref on sequence id rather than name
1818 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1820 if (annotation.groupRef != null)
1822 String groupIdr = groupRefs.get(annotation.groupRef);
1823 if (groupIdr == null)
1825 // make a locally unique String
1826 groupRefs.put(annotation.groupRef,
1827 groupIdr = ("" + System.currentTimeMillis()
1828 + annotation.groupRef.getName()
1829 + groupRefs.size()));
1831 an.setGroupRef(groupIdr.toString());
1834 // store all visualization attributes for annotation
1835 an.setGraphHeight(annotation.graphHeight);
1836 an.setCentreColLabels(annotation.centreColLabels);
1837 an.setScaleColLabels(annotation.scaleColLabel);
1838 an.setShowAllColLabels(annotation.showAllColLabels);
1839 an.setBelowAlignment(annotation.belowAlignment);
1841 if (annotation.graph > 0)
1844 an.setGraphType(annotation.graph);
1845 an.setGraphGroup(annotation.graphGroup);
1846 if (annotation.getThreshold() != null)
1848 ThresholdLine line = new ThresholdLine();
1849 line.setLabel(annotation.getThreshold().label);
1850 line.setValue(annotation.getThreshold().value);
1851 line.setColour(annotation.getThreshold().colour.getRGB());
1852 an.setThresholdLine(line);
1860 an.setLabel(annotation.label);
1862 if (annotation == av.getAlignmentQualityAnnot()
1863 || annotation == av.getAlignmentConservationAnnotation()
1864 || annotation == av.getAlignmentConsensusAnnotation()
1865 || annotation.autoCalculated)
1867 // new way of indicating autocalculated annotation -
1868 an.setAutoCalculated(annotation.autoCalculated);
1870 if (annotation.hasScore())
1872 an.setScore(annotation.getScore());
1875 if (annotation.getCalcId() != null)
1877 calcIdSet.add(annotation.getCalcId());
1878 an.setCalcId(annotation.getCalcId());
1880 if (annotation.hasProperties())
1882 for (String pr : annotation.getProperties())
1884 Property prop = new Property();
1886 prop.setValue(annotation.getProperty(pr));
1887 an.addProperty(prop);
1891 AnnotationElement ae;
1892 if (annotation.annotations != null)
1894 an.setScoreOnly(false);
1895 for (int a = 0; a < annotation.annotations.length; a++)
1897 if ((annotation == null) || (annotation.annotations[a] == null))
1902 ae = new AnnotationElement();
1903 if (annotation.annotations[a].description != null)
1905 ae.setDescription(annotation.annotations[a].description);
1907 if (annotation.annotations[a].displayCharacter != null)
1909 ae.setDisplayCharacter(
1910 annotation.annotations[a].displayCharacter);
1913 if (!Float.isNaN(annotation.annotations[a].value))
1915 ae.setValue(annotation.annotations[a].value);
1919 if (annotation.annotations[a].secondaryStructure > ' ')
1921 ae.setSecondaryStructure(
1922 annotation.annotations[a].secondaryStructure + "");
1925 if (annotation.annotations[a].colour != null
1926 && annotation.annotations[a].colour != java.awt.Color.black)
1928 ae.setColour(annotation.annotations[a].colour.getRGB());
1931 an.addAnnotationElement(ae);
1932 if (annotation.autoCalculated)
1934 // only write one non-null entry into the annotation row -
1935 // sufficient to get the visualization attributes necessary to
1943 an.setScoreOnly(true);
1945 if (!storeDS || (storeDS && !annotation.autoCalculated))
1947 // skip autocalculated annotation - these are only provided for
1949 vamsasSet.addAnnotation(an);
1955 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1957 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1958 if (settings != null)
1960 CalcIdParam vCalcIdParam = new CalcIdParam();
1961 vCalcIdParam.setCalcId(calcId);
1962 vCalcIdParam.addServiceURL(settings.getServiceURI());
1963 // generic URI allowing a third party to resolve another instance of the
1964 // service used for this calculation
1965 for (String urls : settings.getServiceURLs())
1967 vCalcIdParam.addServiceURL(urls);
1969 vCalcIdParam.setVersion("1.0");
1970 if (settings.getPreset() != null)
1972 WsParamSetI setting = settings.getPreset();
1973 vCalcIdParam.setName(setting.getName());
1974 vCalcIdParam.setDescription(setting.getDescription());
1978 vCalcIdParam.setName("");
1979 vCalcIdParam.setDescription("Last used parameters");
1981 // need to be able to recover 1) settings 2) user-defined presets or
1982 // recreate settings from preset 3) predefined settings provided by
1983 // service - or settings that can be transferred (or discarded)
1984 vCalcIdParam.setParameters(
1985 settings.getWsParamFile().replace("\n", "|\\n|"));
1986 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1987 // todo - decide if updateImmediately is needed for any projects.
1989 return vCalcIdParam;
1994 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1997 if (calcIdParam.getVersion().equals("1.0"))
1999 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2000 .getPreferredServiceFor(calcIdParam.getServiceURL());
2001 if (service != null)
2003 WsParamSetI parmSet = null;
2006 parmSet = service.getParamStore().parseServiceParameterFile(
2007 calcIdParam.getName(), calcIdParam.getDescription(),
2008 calcIdParam.getServiceURL(),
2009 calcIdParam.getParameters().replace("|\\n|", "\n"));
2010 } catch (IOException x)
2012 warn("Couldn't parse parameter data for "
2013 + calcIdParam.getCalcId(), x);
2016 List<ArgumentI> argList = null;
2017 if (calcIdParam.getName().length() > 0)
2019 parmSet = service.getParamStore()
2020 .getPreset(calcIdParam.getName());
2021 if (parmSet != null)
2023 // TODO : check we have a good match with settings in AACon -
2024 // otherwise we'll need to create a new preset
2029 argList = parmSet.getArguments();
2032 AAConSettings settings = new AAConSettings(
2033 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2034 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2035 calcIdParam.isNeedsUpdate());
2040 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2044 throw new Error(MessageManager.formatMessage(
2045 "error.unsupported_version_calcIdparam", new Object[]
2046 { calcIdParam.toString() }));
2050 * External mapping between jalview objects and objects yielding a valid and
2051 * unique object ID string. This is null for normal Jalview project IO, but
2052 * non-null when a jalview project is being read or written as part of a
2055 IdentityHashMap jv2vobj = null;
2058 * Construct a unique ID for jvobj using either existing bindings or if none
2059 * exist, the result of the hashcode call for the object.
2062 * jalview data object
2063 * @return unique ID for referring to jvobj
2065 private String makeHashCode(Object jvobj, String altCode)
2067 if (jv2vobj != null)
2069 Object id = jv2vobj.get(jvobj);
2072 return id.toString();
2074 // check string ID mappings
2075 if (jvids2vobj != null && jvobj instanceof String)
2077 id = jvids2vobj.get(jvobj);
2081 return id.toString();
2083 // give up and warn that something has gone wrong
2084 warn("Cannot find ID for object in external mapping : " + jvobj);
2090 * return local jalview object mapped to ID, if it exists
2094 * @return null or object bound to idcode
2096 private Object retrieveExistingObj(String idcode)
2098 if (idcode != null && vobj2jv != null)
2100 return vobj2jv.get(idcode);
2106 * binding from ID strings from external mapping table to jalview data model
2109 private Hashtable vobj2jv;
2111 private Sequence createVamsasSequence(String id, SequenceI jds)
2113 return createVamsasSequence(true, id, jds, null);
2116 private Sequence createVamsasSequence(boolean recurse, String id,
2117 SequenceI jds, SequenceI parentseq)
2119 Sequence vamsasSeq = new Sequence();
2120 vamsasSeq.setId(id);
2121 vamsasSeq.setName(jds.getName());
2122 vamsasSeq.setSequence(jds.getSequenceAsString());
2123 vamsasSeq.setDescription(jds.getDescription());
2124 jalview.datamodel.DBRefEntry[] dbrefs = null;
2125 if (jds.getDatasetSequence() != null)
2127 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2131 // seqId==dsseqid so we can tell which sequences really are
2132 // dataset sequences only
2133 vamsasSeq.setDsseqid(id);
2134 dbrefs = jds.getDBRefs();
2135 if (parentseq == null)
2142 for (int d = 0; d < dbrefs.length; d++)
2144 DBRef dbref = new DBRef();
2145 dbref.setSource(dbrefs[d].getSource());
2146 dbref.setVersion(dbrefs[d].getVersion());
2147 dbref.setAccessionId(dbrefs[d].getAccessionId());
2148 if (dbrefs[d].hasMap())
2150 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2152 dbref.setMapping(mp);
2154 vamsasSeq.addDBRef(dbref);
2160 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2161 SequenceI parentseq, SequenceI jds, boolean recurse)
2164 if (jmp.getMap() != null)
2168 jalview.util.MapList mlst = jmp.getMap();
2169 List<int[]> r = mlst.getFromRanges();
2170 for (int[] range : r)
2172 MapListFrom mfrom = new MapListFrom();
2173 mfrom.setStart(range[0]);
2174 mfrom.setEnd(range[1]);
2175 mp.addMapListFrom(mfrom);
2177 r = mlst.getToRanges();
2178 for (int[] range : r)
2180 MapListTo mto = new MapListTo();
2181 mto.setStart(range[0]);
2182 mto.setEnd(range[1]);
2183 mp.addMapListTo(mto);
2185 mp.setMapFromUnit(mlst.getFromRatio());
2186 mp.setMapToUnit(mlst.getToRatio());
2187 if (jmp.getTo() != null)
2189 MappingChoice mpc = new MappingChoice();
2191 // check/create ID for the sequence referenced by getTo()
2194 SequenceI ps = null;
2195 if (parentseq != jmp.getTo()
2196 && parentseq.getDatasetSequence() != jmp.getTo())
2198 // chaining dbref rather than a handshaking one
2199 jmpid = seqHash(ps = jmp.getTo());
2203 jmpid = seqHash(ps = parentseq);
2205 mpc.setDseqFor(jmpid);
2206 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2208 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2209 seqRefIds.put(mpc.getDseqFor(), ps);
2213 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2216 mp.setMappingChoice(mpc);
2222 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2223 List<UserColourScheme> userColours, JalviewModelSequence jms)
2226 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2227 boolean newucs = false;
2228 if (!userColours.contains(ucs))
2230 userColours.add(ucs);
2233 id = "ucs" + userColours.indexOf(ucs);
2236 // actually create the scheme's entry in the XML model
2237 java.awt.Color[] colours = ucs.getColours();
2238 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2239 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2241 for (int i = 0; i < colours.length; i++)
2243 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2244 col.setName(ResidueProperties.aa[i]);
2245 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2246 jbucs.addColour(col);
2248 if (ucs.getLowerCaseColours() != null)
2250 colours = ucs.getLowerCaseColours();
2251 for (int i = 0; i < colours.length; i++)
2253 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2254 col.setName(ResidueProperties.aa[i].toLowerCase());
2255 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2256 jbucs.addColour(col);
2261 uc.setUserColourScheme(jbucs);
2262 jms.addUserColours(uc);
2268 jalview.schemes.UserColourScheme getUserColourScheme(
2269 JalviewModelSequence jms, String id)
2271 UserColours[] uc = jms.getUserColours();
2272 UserColours colours = null;
2274 for (int i = 0; i < uc.length; i++)
2276 if (uc[i].getId().equals(id))
2284 java.awt.Color[] newColours = new java.awt.Color[24];
2286 for (int i = 0; i < 24; i++)
2288 newColours[i] = new java.awt.Color(Integer.parseInt(
2289 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2292 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2295 if (colours.getUserColourScheme().getColourCount() > 24)
2297 newColours = new java.awt.Color[23];
2298 for (int i = 0; i < 23; i++)
2300 newColours[i] = new java.awt.Color(Integer.parseInt(
2301 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2304 ucs.setLowerCaseColours(newColours);
2311 * contains last error message (if any) encountered by XML loader.
2313 String errorMessage = null;
2316 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2317 * exceptions are raised during project XML parsing
2319 public boolean attemptversion1parse = true;
2322 * Load a jalview project archive from a jar file
2325 * - HTTP URL or filename
2327 public AlignFrame loadJalviewAlign(final String file)
2330 jalview.gui.AlignFrame af = null;
2334 // create list to store references for any new Jmol viewers created
2335 newStructureViewers = new Vector<>();
2336 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2337 // Workaround is to make sure caller implements the JarInputStreamProvider
2339 // so we can re-open the jar input stream for each entry.
2341 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2342 af = loadJalviewAlign(jprovider);
2343 af.setMenusForViewport();
2345 } catch (MalformedURLException e)
2347 errorMessage = "Invalid URL format for '" + file + "'";
2353 SwingUtilities.invokeAndWait(new Runnable()
2358 setLoadingFinishedForNewStructureViewers();
2361 } catch (Exception x)
2363 System.err.println("Error loading alignment: " + x.getMessage());
2369 private jarInputStreamProvider createjarInputStreamProvider(
2370 final String file) throws MalformedURLException
2373 errorMessage = null;
2374 uniqueSetSuffix = null;
2376 viewportsAdded.clear();
2377 frefedSequence = null;
2379 if (file.startsWith("http://"))
2381 url = new URL(file);
2383 final URL _url = url;
2384 return new jarInputStreamProvider()
2388 public JarInputStream getJarInputStream() throws IOException
2392 return new JarInputStream(_url.openStream());
2396 return new JarInputStream(new FileInputStream(file));
2401 public String getFilename()
2409 * Recover jalview session from a jalview project archive. Caller may
2410 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2411 * themselves. Any null fields will be initialised with default values,
2412 * non-null fields are left alone.
2417 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2419 errorMessage = null;
2420 if (uniqueSetSuffix == null)
2422 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2424 if (seqRefIds == null)
2428 AlignFrame af = null, _af = null;
2429 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2430 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2431 final String file = jprovider.getFilename();
2434 JarInputStream jin = null;
2435 JarEntry jarentry = null;
2440 jin = jprovider.getJarInputStream();
2441 for (int i = 0; i < entryCount; i++)
2443 jarentry = jin.getNextJarEntry();
2446 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2448 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2449 JalviewModel object = new JalviewModel();
2451 Unmarshaller unmar = new Unmarshaller(object);
2452 unmar.setValidation(false);
2453 object = (JalviewModel) unmar.unmarshal(in);
2454 if (true) // !skipViewport(object))
2456 _af = loadFromObject(object, file, true, jprovider);
2457 if (_af != null && object.getJalviewModelSequence()
2458 .getViewportCount() > 0)
2462 // store a reference to the first view
2465 if (_af.viewport.isGatherViewsHere())
2467 // if this is a gathered view, keep its reference since
2468 // after gathering views, only this frame will remain
2470 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2472 // Save dataset to register mappings once all resolved
2473 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2474 af.viewport.getAlignment().getDataset());
2479 else if (jarentry != null)
2481 // Some other file here.
2484 } while (jarentry != null);
2485 resolveFrefedSequences();
2486 } catch (IOException ex)
2488 ex.printStackTrace();
2489 errorMessage = "Couldn't locate Jalview XML file : " + file;
2491 "Exception whilst loading jalview XML file : " + ex + "\n");
2492 } catch (Exception ex)
2494 System.err.println("Parsing as Jalview Version 2 file failed.");
2495 ex.printStackTrace(System.err);
2496 if (attemptversion1parse)
2498 // Is Version 1 Jar file?
2501 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2502 } catch (Exception ex2)
2504 System.err.println("Exception whilst loading as jalviewXMLV1:");
2505 ex2.printStackTrace();
2509 if (Desktop.instance != null)
2511 Desktop.instance.stopLoading();
2515 System.out.println("Successfully loaded archive file");
2518 ex.printStackTrace();
2521 "Exception whilst loading jalview XML file : " + ex + "\n");
2522 } catch (OutOfMemoryError e)
2524 // Don't use the OOM Window here
2525 errorMessage = "Out of memory loading jalview XML file";
2526 System.err.println("Out of memory whilst loading jalview XML file");
2527 e.printStackTrace();
2531 * Regather multiple views (with the same sequence set id) to the frame (if
2532 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2533 * views instead of separate frames. Note this doesn't restore a state where
2534 * some expanded views in turn have tabbed views - the last "first tab" read
2535 * in will play the role of gatherer for all.
2537 for (AlignFrame fr : gatherToThisFrame.values())
2539 Desktop.instance.gatherViews(fr);
2542 restoreSplitFrames();
2543 for (AlignmentI ds : importedDatasets.keySet())
2545 if (ds.getCodonFrames() != null)
2547 StructureSelectionManager
2548 .getStructureSelectionManager(Desktop.instance)
2549 .registerMappings(ds.getCodonFrames());
2552 if (errorMessage != null)
2557 if (Desktop.instance != null)
2559 Desktop.instance.stopLoading();
2566 * Try to reconstruct and display SplitFrame windows, where each contains
2567 * complementary dna and protein alignments. Done by pairing up AlignFrame
2568 * objects (created earlier) which have complementary viewport ids associated.
2570 protected void restoreSplitFrames()
2572 List<SplitFrame> gatherTo = new ArrayList<>();
2573 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2574 Map<String, AlignFrame> dna = new HashMap<>();
2577 * Identify the DNA alignments
2579 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2582 AlignFrame af = candidate.getValue();
2583 if (af.getViewport().getAlignment().isNucleotide())
2585 dna.put(candidate.getKey().getId(), af);
2590 * Try to match up the protein complements
2592 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2595 AlignFrame af = candidate.getValue();
2596 if (!af.getViewport().getAlignment().isNucleotide())
2598 String complementId = candidate.getKey().getComplementId();
2599 // only non-null complements should be in the Map
2600 if (complementId != null && dna.containsKey(complementId))
2602 final AlignFrame dnaFrame = dna.get(complementId);
2603 SplitFrame sf = createSplitFrame(dnaFrame, af);
2604 addedToSplitFrames.add(dnaFrame);
2605 addedToSplitFrames.add(af);
2606 dnaFrame.setMenusForViewport();
2607 af.setMenusForViewport();
2608 if (af.viewport.isGatherViewsHere())
2617 * Open any that we failed to pair up (which shouldn't happen!) as
2618 * standalone AlignFrame's.
2620 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2623 AlignFrame af = candidate.getValue();
2624 if (!addedToSplitFrames.contains(af))
2626 Viewport view = candidate.getKey();
2627 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2629 af.setMenusForViewport();
2630 System.err.println("Failed to restore view " + view.getTitle()
2631 + " to split frame");
2636 * Gather back into tabbed views as flagged.
2638 for (SplitFrame sf : gatherTo)
2640 Desktop.instance.gatherViews(sf);
2643 splitFrameCandidates.clear();
2647 * Construct and display one SplitFrame holding DNA and protein alignments.
2650 * @param proteinFrame
2653 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2654 AlignFrame proteinFrame)
2656 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2657 String title = MessageManager.getString("label.linked_view_title");
2658 int width = (int) dnaFrame.getBounds().getWidth();
2659 int height = (int) (dnaFrame.getBounds().getHeight()
2660 + proteinFrame.getBounds().getHeight() + 50);
2663 * SplitFrame location is saved to both enclosed frames
2665 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2666 Desktop.addInternalFrame(splitFrame, title, width, height);
2669 * And compute cDNA consensus (couldn't do earlier with consensus as
2670 * mappings were not yet present)
2672 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2678 * check errorMessage for a valid error message and raise an error box in the
2679 * GUI or write the current errorMessage to stderr and then clear the error
2682 protected void reportErrors()
2684 reportErrors(false);
2687 protected void reportErrors(final boolean saving)
2689 if (errorMessage != null)
2691 final String finalErrorMessage = errorMessage;
2694 javax.swing.SwingUtilities.invokeLater(new Runnable()
2699 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2701 "Error " + (saving ? "saving" : "loading")
2703 JvOptionPane.WARNING_MESSAGE);
2709 System.err.println("Problem loading Jalview file: " + errorMessage);
2712 errorMessage = null;
2715 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2718 * when set, local views will be updated from view stored in JalviewXML
2719 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2720 * sync if this is set to true.
2722 private final boolean updateLocalViews = false;
2725 * Returns the path to a temporary file holding the PDB file for the given PDB
2726 * id. The first time of asking, searches for a file of that name in the
2727 * Jalview project jar, and copies it to a new temporary file. Any repeat
2728 * requests just return the path to the file previously created.
2734 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2737 if (alreadyLoadedPDB.containsKey(pdbId))
2739 return alreadyLoadedPDB.get(pdbId).toString();
2742 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2744 if (tempFile != null)
2746 alreadyLoadedPDB.put(pdbId, tempFile);
2752 * Copies the jar entry of given name to a new temporary file and returns the
2753 * path to the file, or null if the entry is not found.
2756 * @param jarEntryName
2758 * a prefix for the temporary file name, must be at least three
2761 * null or original file - so new file can be given the same suffix
2765 protected String copyJarEntry(jarInputStreamProvider jprovider,
2766 String jarEntryName, String prefix, String origFile)
2768 BufferedReader in = null;
2769 PrintWriter out = null;
2770 String suffix = ".tmp";
2771 if (origFile == null)
2773 origFile = jarEntryName;
2775 int sfpos = origFile.lastIndexOf(".");
2776 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2778 suffix = "." + origFile.substring(sfpos + 1);
2782 JarInputStream jin = jprovider.getJarInputStream();
2784 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2785 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2786 * FileInputStream(jprovider)); }
2789 JarEntry entry = null;
2792 entry = jin.getNextJarEntry();
2793 } while (entry != null && !entry.getName().equals(jarEntryName));
2796 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2797 File outFile = File.createTempFile(prefix, suffix);
2798 outFile.deleteOnExit();
2799 out = new PrintWriter(new FileOutputStream(outFile));
2802 while ((data = in.readLine()) != null)
2807 String t = outFile.getAbsolutePath();
2812 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2814 } catch (Exception ex)
2816 ex.printStackTrace();
2824 } catch (IOException e)
2838 private class JvAnnotRow
2840 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2847 * persisted version of annotation row from which to take vis properties
2849 public jalview.datamodel.AlignmentAnnotation template;
2852 * original position of the annotation row in the alignment
2858 * Load alignment frame from jalview XML DOM object
2863 * filename source string
2864 * @param loadTreesAndStructures
2865 * when false only create Viewport
2867 * data source provider
2868 * @return alignment frame created from view stored in DOM
2870 AlignFrame loadFromObject(JalviewModel object, String file,
2871 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2873 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2874 Sequence[] vamsasSeq = vamsasSet.getSequence();
2876 JalviewModelSequence jms = object.getJalviewModelSequence();
2878 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2881 // ////////////////////////////////
2884 List<SequenceI> hiddenSeqs = null;
2886 List<SequenceI> tmpseqs = new ArrayList<>();
2888 boolean multipleView = false;
2889 SequenceI referenceseqForView = null;
2890 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2891 int vi = 0; // counter in vamsasSeq array
2892 for (int i = 0; i < jseqs.length; i++)
2894 String seqId = jseqs[i].getId();
2896 SequenceI tmpSeq = seqRefIds.get(seqId);
2899 if (!incompleteSeqs.containsKey(seqId))
2901 // may not need this check, but keep it for at least 2.9,1 release
2902 if (tmpSeq.getStart() != jseqs[i].getStart()
2903 || tmpSeq.getEnd() != jseqs[i].getEnd())
2906 "Warning JAL-2154 regression: updating start/end for sequence "
2907 + tmpSeq.toString() + " to " + jseqs[i]);
2912 incompleteSeqs.remove(seqId);
2914 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2916 // most likely we are reading a dataset XML document so
2917 // update from vamsasSeq section of XML for this sequence
2918 tmpSeq.setName(vamsasSeq[vi].getName());
2919 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2920 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2925 // reading multiple views, so vamsasSeq set is a subset of JSeq
2926 multipleView = true;
2928 tmpSeq.setStart(jseqs[i].getStart());
2929 tmpSeq.setEnd(jseqs[i].getEnd());
2930 tmpseqs.add(tmpSeq);
2934 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2935 vamsasSeq[vi].getSequence());
2936 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2937 tmpSeq.setStart(jseqs[i].getStart());
2938 tmpSeq.setEnd(jseqs[i].getEnd());
2939 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2940 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2941 tmpseqs.add(tmpSeq);
2945 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2947 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2950 if (jseqs[i].getHidden())
2952 if (hiddenSeqs == null)
2954 hiddenSeqs = new ArrayList<>();
2957 hiddenSeqs.add(tmpSeq);
2962 // Create the alignment object from the sequence set
2963 // ///////////////////////////////
2964 SequenceI[] orderedSeqs = tmpseqs
2965 .toArray(new SequenceI[tmpseqs.size()]);
2967 AlignmentI al = null;
2968 // so we must create or recover the dataset alignment before going further
2969 // ///////////////////////////////
2970 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2972 // older jalview projects do not have a dataset - so creat alignment and
2974 al = new Alignment(orderedSeqs);
2975 al.setDataset(null);
2979 boolean isdsal = object.getJalviewModelSequence()
2980 .getViewportCount() == 0;
2983 // we are importing a dataset record, so
2984 // recover reference to an alignment already materialsed as dataset
2985 al = getDatasetFor(vamsasSet.getDatasetId());
2989 // materialse the alignment
2990 al = new Alignment(orderedSeqs);
2994 addDatasetRef(vamsasSet.getDatasetId(), al);
2997 // finally, verify all data in vamsasSet is actually present in al
2998 // passing on flag indicating if it is actually a stored dataset
2999 recoverDatasetFor(vamsasSet, al, isdsal);
3002 if (referenceseqForView != null)
3004 al.setSeqrep(referenceseqForView);
3006 // / Add the alignment properties
3007 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3009 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3010 al.setProperty(ssp.getKey(), ssp.getValue());
3013 // ///////////////////////////////
3015 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3018 // load sequence features, database references and any associated PDB
3019 // structures for the alignment
3021 // prior to 2.10, this part would only be executed the first time a
3022 // sequence was encountered, but not afterwards.
3023 // now, for 2.10 projects, this is also done if the xml doc includes
3024 // dataset sequences not actually present in any particular view.
3026 for (int i = 0; i < vamsasSeq.length; i++)
3028 if (jseqs[i].getFeaturesCount() > 0)
3030 Features[] features = jseqs[i].getFeatures();
3031 for (int f = 0; f < features.length; f++)
3033 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3034 features[f].getDescription(), features[f].getBegin(),
3035 features[f].getEnd(), features[f].getScore(),
3036 features[f].getFeatureGroup());
3037 sf.setStatus(features[f].getStatus());
3040 * load any feature attributes - include map-valued attributes
3042 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3043 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3045 OtherData keyValue = features[f].getOtherData(od);
3046 String attributeName = keyValue.getKey();
3047 String attributeValue = keyValue.getValue();
3048 if (attributeName.startsWith("LINK"))
3050 sf.addLink(attributeValue);
3054 String subAttribute = keyValue.getKey2();
3055 if (subAttribute == null)
3057 // simple string-valued attribute
3058 sf.setValue(attributeName, attributeValue);
3062 // attribute 'key' has sub-attribute 'key2'
3063 if (!mapAttributes.containsKey(attributeName))
3065 mapAttributes.put(attributeName, new HashMap<>());
3067 mapAttributes.get(attributeName).put(subAttribute,
3072 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3075 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3078 // adds feature to datasequence's feature set (since Jalview 2.10)
3079 al.getSequenceAt(i).addSequenceFeature(sf);
3082 if (vamsasSeq[i].getDBRefCount() > 0)
3084 // adds dbrefs to datasequence's set (since Jalview 2.10)
3086 al.getSequenceAt(i).getDatasetSequence() == null
3087 ? al.getSequenceAt(i)
3088 : al.getSequenceAt(i).getDatasetSequence(),
3091 if (jseqs[i].getPdbidsCount() > 0)
3093 Pdbids[] ids = jseqs[i].getPdbids();
3094 for (int p = 0; p < ids.length; p++)
3096 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3097 entry.setId(ids[p].getId());
3098 if (ids[p].getType() != null)
3100 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3102 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3106 entry.setType(PDBEntry.Type.FILE);
3109 // jprovider is null when executing 'New View'
3110 if (ids[p].getFile() != null && jprovider != null)
3112 if (!pdbloaded.containsKey(ids[p].getFile()))
3114 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3119 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3122 if (ids[p].getPdbentryItem() != null)
3124 for (PdbentryItem item : ids[p].getPdbentryItem())
3126 for (Property pr : item.getProperty())
3128 entry.setProperty(pr.getName(), pr.getValue());
3132 StructureSelectionManager
3133 .getStructureSelectionManager(Desktop.instance)
3134 .registerPDBEntry(entry);
3135 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3136 if (al.getSequenceAt(i).getDatasetSequence() != null)
3138 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3142 al.getSequenceAt(i).addPDBId(entry);
3147 } // end !multipleview
3149 // ///////////////////////////////
3150 // LOAD SEQUENCE MAPPINGS
3152 if (vamsasSet.getAlcodonFrameCount() > 0)
3154 // TODO Potentially this should only be done once for all views of an
3156 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3157 for (int i = 0; i < alc.length; i++)
3159 AlignedCodonFrame cf = new AlignedCodonFrame();
3160 if (alc[i].getAlcodMapCount() > 0)
3162 AlcodMap[] maps = alc[i].getAlcodMap();
3163 for (int m = 0; m < maps.length; m++)
3165 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3167 jalview.datamodel.Mapping mapping = null;
3168 // attach to dna sequence reference.
3169 if (maps[m].getMapping() != null)
3171 mapping = addMapping(maps[m].getMapping());
3172 if (dnaseq != null && mapping.getTo() != null)
3174 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3180 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3184 al.addCodonFrame(cf);
3189 // ////////////////////////////////
3191 List<JvAnnotRow> autoAlan = new ArrayList<>();
3194 * store any annotations which forward reference a group's ID
3196 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3198 if (vamsasSet.getAnnotationCount() > 0)
3200 Annotation[] an = vamsasSet.getAnnotation();
3202 for (int i = 0; i < an.length; i++)
3204 Annotation annotation = an[i];
3207 * test if annotation is automatically calculated for this view only
3209 boolean autoForView = false;
3210 if (annotation.getLabel().equals("Quality")
3211 || annotation.getLabel().equals("Conservation")
3212 || annotation.getLabel().equals("Consensus"))
3214 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3216 if (!annotation.hasAutoCalculated())
3218 annotation.setAutoCalculated(true);
3221 if (autoForView || (annotation.hasAutoCalculated()
3222 && annotation.isAutoCalculated()))
3224 // remove ID - we don't recover annotation from other views for
3225 // view-specific annotation
3226 annotation.setId(null);
3229 // set visiblity for other annotation in this view
3230 String annotationId = annotation.getId();
3231 if (annotationId != null && annotationIds.containsKey(annotationId))
3233 AlignmentAnnotation jda = annotationIds.get(annotationId);
3234 // in principle Visible should always be true for annotation displayed
3235 // in multiple views
3236 if (annotation.hasVisible())
3238 jda.visible = annotation.getVisible();
3241 al.addAnnotation(jda);
3245 // Construct new annotation from model.
3246 AnnotationElement[] ae = annotation.getAnnotationElement();
3247 jalview.datamodel.Annotation[] anot = null;
3248 java.awt.Color firstColour = null;
3250 if (!annotation.getScoreOnly())
3252 anot = new jalview.datamodel.Annotation[al.getWidth()];
3253 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3255 anpos = ae[aa].getPosition();
3257 if (anpos >= anot.length)
3262 anot[anpos] = new jalview.datamodel.Annotation(
3264 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3265 (ae[aa].getSecondaryStructure() == null
3266 || ae[aa].getSecondaryStructure().length() == 0)
3268 : ae[aa].getSecondaryStructure()
3273 // JBPNote: Consider verifying dataflow for IO of secondary
3274 // structure annotation read from Stockholm files
3275 // this was added to try to ensure that
3276 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3278 // anot[ae[aa].getPosition()].displayCharacter = "";
3280 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3281 if (firstColour == null)
3283 firstColour = anot[anpos].colour;
3287 jalview.datamodel.AlignmentAnnotation jaa = null;
3289 if (annotation.getGraph())
3291 float llim = 0, hlim = 0;
3292 // if (autoForView || an[i].isAutoCalculated()) {
3295 jaa = new jalview.datamodel.AlignmentAnnotation(
3296 annotation.getLabel(), annotation.getDescription(), anot,
3297 llim, hlim, annotation.getGraphType());
3299 jaa.graphGroup = annotation.getGraphGroup();
3300 jaa._linecolour = firstColour;
3301 if (annotation.getThresholdLine() != null)
3303 jaa.setThreshold(new jalview.datamodel.GraphLine(
3304 annotation.getThresholdLine().getValue(),
3305 annotation.getThresholdLine().getLabel(),
3307 annotation.getThresholdLine().getColour())));
3310 if (autoForView || annotation.isAutoCalculated())
3312 // Hardwire the symbol display line to ensure that labels for
3313 // histograms are displayed
3319 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3320 an[i].getDescription(), anot);
3321 jaa._linecolour = firstColour;
3323 // register new annotation
3324 if (an[i].getId() != null)
3326 annotationIds.put(an[i].getId(), jaa);
3327 jaa.annotationId = an[i].getId();
3329 // recover sequence association
3330 String sequenceRef = an[i].getSequenceRef();
3331 if (sequenceRef != null)
3333 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3334 SequenceI sequence = seqRefIds.get(sequenceRef);
3335 if (sequence == null)
3337 // in pre-2.9 projects sequence ref is to sequence name
3338 sequence = al.findName(sequenceRef);
3340 if (sequence != null)
3342 jaa.createSequenceMapping(sequence, 1, true);
3343 sequence.addAlignmentAnnotation(jaa);
3346 // and make a note of any group association
3347 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3349 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3350 .get(an[i].getGroupRef());
3353 aal = new ArrayList<>();
3354 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3359 if (an[i].hasScore())
3361 jaa.setScore(an[i].getScore());
3363 if (an[i].hasVisible())
3365 jaa.visible = an[i].getVisible();
3368 if (an[i].hasCentreColLabels())
3370 jaa.centreColLabels = an[i].getCentreColLabels();
3373 if (an[i].hasScaleColLabels())
3375 jaa.scaleColLabel = an[i].getScaleColLabels();
3377 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3379 // newer files have an 'autoCalculated' flag and store calculation
3380 // state in viewport properties
3381 jaa.autoCalculated = true; // means annotation will be marked for
3382 // update at end of load.
3384 if (an[i].hasGraphHeight())
3386 jaa.graphHeight = an[i].getGraphHeight();
3388 if (an[i].hasBelowAlignment())
3390 jaa.belowAlignment = an[i].isBelowAlignment();
3392 jaa.setCalcId(an[i].getCalcId());
3393 if (an[i].getPropertyCount() > 0)
3395 for (jalview.schemabinding.version2.Property prop : an[i]
3398 jaa.setProperty(prop.getName(), prop.getValue());
3401 if (jaa.autoCalculated)
3403 autoAlan.add(new JvAnnotRow(i, jaa));
3406 // if (!autoForView)
3408 // add autocalculated group annotation and any user created annotation
3410 al.addAnnotation(jaa);
3414 // ///////////////////////
3416 // Create alignment markup and styles for this view
3417 if (jms.getJGroupCount() > 0)
3419 JGroup[] groups = jms.getJGroup();
3420 boolean addAnnotSchemeGroup = false;
3421 for (int i = 0; i < groups.length; i++)
3423 JGroup jGroup = groups[i];
3424 ColourSchemeI cs = null;
3425 if (jGroup.getColour() != null)
3427 if (jGroup.getColour().startsWith("ucs"))
3429 cs = getUserColourScheme(jms, jGroup.getColour());
3431 else if (jGroup.getColour().equals("AnnotationColourGradient")
3432 && jGroup.getAnnotationColours() != null)
3434 addAnnotSchemeGroup = true;
3438 cs = ColourSchemeProperty.getColourScheme(al,
3439 jGroup.getColour());
3442 int pidThreshold = jGroup.getPidThreshold();
3444 Vector<SequenceI> seqs = new Vector<>();
3446 for (int s = 0; s < jGroup.getSeqCount(); s++)
3448 String seqId = jGroup.getSeq(s) + "";
3449 SequenceI ts = seqRefIds.get(seqId);
3453 seqs.addElement(ts);
3457 if (seqs.size() < 1)
3462 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3463 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3464 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3465 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3466 sg.getGroupColourScheme()
3467 .setConservationInc(jGroup.getConsThreshold());
3468 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3470 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3471 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3472 sg.setShowNonconserved(
3473 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3475 sg.thresholdTextColour = jGroup.getTextColThreshold();
3476 if (jGroup.hasShowConsensusHistogram())
3478 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3481 if (jGroup.hasShowSequenceLogo())
3483 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3485 if (jGroup.hasNormaliseSequenceLogo())
3487 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3489 if (jGroup.hasIgnoreGapsinConsensus())
3491 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3493 if (jGroup.getConsThreshold() != 0)
3495 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3498 c.verdict(false, 25);
3499 sg.cs.setConservation(c);
3502 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3504 // re-instate unique group/annotation row reference
3505 List<AlignmentAnnotation> jaal = groupAnnotRefs
3506 .get(jGroup.getId());
3509 for (AlignmentAnnotation jaa : jaal)
3512 if (jaa.autoCalculated)
3514 // match up and try to set group autocalc alignment row for this
3516 if (jaa.label.startsWith("Consensus for "))
3518 sg.setConsensus(jaa);
3520 // match up and try to set group autocalc alignment row for this
3522 if (jaa.label.startsWith("Conservation for "))
3524 sg.setConservationRow(jaa);
3531 if (addAnnotSchemeGroup)
3533 // reconstruct the annotation colourscheme
3534 sg.setColourScheme(constructAnnotationColour(
3535 jGroup.getAnnotationColours(), null, al, jms, false));
3541 // only dataset in this model, so just return.
3544 // ///////////////////////////////
3547 // If we just load in the same jar file again, the sequenceSetId
3548 // will be the same, and we end up with multiple references
3549 // to the same sequenceSet. We must modify this id on load
3550 // so that each load of the file gives a unique id
3551 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3552 String viewId = (view.getId() == null ? null
3553 : view.getId() + uniqueSetSuffix);
3554 AlignFrame af = null;
3555 AlignViewport av = null;
3556 // now check to see if we really need to create a new viewport.
3557 if (multipleView && viewportsAdded.size() == 0)
3559 // We recovered an alignment for which a viewport already exists.
3560 // TODO: fix up any settings necessary for overlaying stored state onto
3561 // state recovered from another document. (may not be necessary).
3562 // we may need a binding from a viewport in memory to one recovered from
3564 // and then recover its containing af to allow the settings to be applied.
3565 // TODO: fix for vamsas demo
3567 "About to recover a viewport for existing alignment: Sequence set ID is "
3569 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3570 if (seqsetobj != null)
3572 if (seqsetobj instanceof String)
3574 uniqueSeqSetId = (String) seqsetobj;
3576 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3582 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3588 * indicate that annotation colours are applied across all groups (pre
3589 * Jalview 2.8.1 behaviour)
3591 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3592 object.getVersion());
3594 AlignmentPanel ap = null;
3595 boolean isnewview = true;
3598 // Check to see if this alignment already has a view id == viewId
3599 jalview.gui.AlignmentPanel views[] = Desktop
3600 .getAlignmentPanels(uniqueSeqSetId);
3601 if (views != null && views.length > 0)
3603 for (int v = 0; v < views.length; v++)
3605 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3607 // recover the existing alignpanel, alignframe, viewport
3608 af = views[v].alignFrame;
3611 // TODO: could even skip resetting view settings if we don't want to
3612 // change the local settings from other jalview processes
3621 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3622 uniqueSeqSetId, viewId, autoAlan);
3628 * Load any trees, PDB structures and viewers
3630 * Not done if flag is false (when this method is used for New View)
3632 if (loadTreesAndStructures)
3634 loadTrees(jms, view, af, av, ap);
3635 loadPDBStructures(jprovider, jseqs, af, ap);
3636 loadRnaViewers(jprovider, jseqs, ap);
3638 // and finally return.
3643 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3644 * panel is restored from separate jar entries, two (gapped and trimmed) per
3645 * sequence and secondary structure.
3647 * Currently each viewer shows just one sequence and structure (gapped and
3648 * trimmed), however this method is designed to support multiple sequences or
3649 * structures in viewers if wanted in future.
3655 private void loadRnaViewers(jarInputStreamProvider jprovider,
3656 JSeq[] jseqs, AlignmentPanel ap)
3659 * scan the sequences for references to viewers; create each one the first
3660 * time it is referenced, add Rna models to existing viewers
3662 for (JSeq jseq : jseqs)
3664 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3666 RnaViewer viewer = jseq.getRnaViewer(i);
3667 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3670 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3672 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3673 SequenceI seq = seqRefIds.get(jseq.getId());
3674 AlignmentAnnotation ann = this.annotationIds
3675 .get(ss.getAnnotationId());
3678 * add the structure to the Varna display (with session state copied
3679 * from the jar to a temporary file)
3681 boolean gapped = ss.isGapped();
3682 String rnaTitle = ss.getTitle();
3683 String sessionState = ss.getViewerState();
3684 String tempStateFile = copyJarEntry(jprovider, sessionState,
3686 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3687 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3689 appVarna.setInitialSelection(viewer.getSelectedRna());
3695 * Locate and return an already instantiated matching AppVarna, or create one
3699 * @param viewIdSuffix
3703 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3704 String viewIdSuffix, AlignmentPanel ap)
3707 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3708 * if load is repeated
3710 String postLoadId = viewer.getViewId() + viewIdSuffix;
3711 for (JInternalFrame frame : getAllFrames())
3713 if (frame instanceof AppVarna)
3715 AppVarna varna = (AppVarna) frame;
3716 if (postLoadId.equals(varna.getViewId()))
3718 // this viewer is already instantiated
3719 // could in future here add ap as another 'parent' of the
3720 // AppVarna window; currently just 1-to-many
3727 * viewer not found - make it
3729 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3730 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3731 viewer.getHeight(), viewer.getDividerLocation());
3732 AppVarna varna = new AppVarna(model, ap);
3738 * Load any saved trees
3746 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3747 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3749 // TODO result of automated refactoring - are all these parameters needed?
3752 for (int t = 0; t < jms.getTreeCount(); t++)
3755 Tree tree = jms.getTree(t);
3757 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3760 tp = af.showNewickTree(
3761 new jalview.io.NewickFile(tree.getNewick()),
3762 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3763 tree.getXpos(), tree.getYpos());
3764 if (tree.getId() != null)
3766 // perhaps bind the tree id to something ?
3771 // update local tree attributes ?
3772 // TODO: should check if tp has been manipulated by user - if so its
3773 // settings shouldn't be modified
3774 tp.setTitle(tree.getTitle());
3775 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3776 tree.getWidth(), tree.getHeight()));
3777 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3780 tp.treeCanvas.av = av; // af.viewport;
3781 tp.treeCanvas.ap = ap; // af.alignPanel;
3786 warn("There was a problem recovering stored Newick tree: \n"
3787 + tree.getNewick());
3791 tp.fitToWindow.setState(tree.getFitToWindow());
3792 tp.fitToWindow_actionPerformed(null);
3794 if (tree.getFontName() != null)
3796 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3797 tree.getFontStyle(), tree.getFontSize()));
3801 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3802 view.getFontStyle(), tree.getFontSize()));
3805 tp.showPlaceholders(tree.getMarkUnlinked());
3806 tp.showBootstrap(tree.getShowBootstrap());
3807 tp.showDistances(tree.getShowDistances());
3809 tp.treeCanvas.threshold = tree.getThreshold();
3811 if (tree.getCurrentTree())
3813 af.viewport.setCurrentTree(tp.getTree());
3817 } catch (Exception ex)
3819 ex.printStackTrace();
3824 * Load and link any saved structure viewers.
3831 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3832 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3835 * Run through all PDB ids on the alignment, and collect mappings between
3836 * distinct view ids and all sequences referring to that view.
3838 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3840 for (int i = 0; i < jseqs.length; i++)
3842 if (jseqs[i].getPdbidsCount() > 0)
3844 Pdbids[] ids = jseqs[i].getPdbids();
3845 for (int p = 0; p < ids.length; p++)
3847 final int structureStateCount = ids[p].getStructureStateCount();
3848 for (int s = 0; s < structureStateCount; s++)
3850 // check to see if we haven't already created this structure view
3851 final StructureState structureState = ids[p]
3852 .getStructureState(s);
3853 String sviewid = (structureState.getViewId() == null) ? null
3854 : structureState.getViewId() + uniqueSetSuffix;
3855 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3856 // Originally : ids[p].getFile()
3857 // : TODO: verify external PDB file recovery still works in normal
3858 // jalview project load
3859 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3861 jpdb.setId(ids[p].getId());
3863 int x = structureState.getXpos();
3864 int y = structureState.getYpos();
3865 int width = structureState.getWidth();
3866 int height = structureState.getHeight();
3868 // Probably don't need to do this anymore...
3869 // Desktop.desktop.getComponentAt(x, y);
3870 // TODO: NOW: check that this recovers the PDB file correctly.
3871 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3873 jalview.datamodel.SequenceI seq = seqRefIds
3874 .get(jseqs[i].getId() + "");
3875 if (sviewid == null)
3877 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3880 if (!structureViewers.containsKey(sviewid))
3882 structureViewers.put(sviewid,
3883 new StructureViewerModel(x, y, width, height, false,
3884 false, true, structureState.getViewId(),
3885 structureState.getType()));
3886 // Legacy pre-2.7 conversion JAL-823 :
3887 // do not assume any view has to be linked for colour by
3891 // assemble String[] { pdb files }, String[] { id for each
3892 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3893 // seqs_file 2}, boolean[] {
3894 // linkAlignPanel,superposeWithAlignpanel}} from hash
3895 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3896 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3897 | (structureState.hasAlignwithAlignPanel()
3898 ? structureState.getAlignwithAlignPanel()
3902 * Default colour by linked panel to false if not specified (e.g.
3903 * for pre-2.7 projects)
3905 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3906 colourWithAlignPanel |= (structureState
3907 .hasColourwithAlignPanel()
3908 ? structureState.getColourwithAlignPanel()
3910 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3913 * Default colour by viewer to true if not specified (e.g. for
3916 boolean colourByViewer = jmoldat.isColourByViewer();
3917 colourByViewer &= structureState.hasColourByJmol()
3918 ? structureState.getColourByJmol()
3920 jmoldat.setColourByViewer(colourByViewer);
3922 if (jmoldat.getStateData().length() < structureState
3923 .getContent().length())
3926 jmoldat.setStateData(structureState.getContent());
3929 if (ids[p].getFile() != null)
3931 File mapkey = new File(ids[p].getFile());
3932 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3933 if (seqstrmaps == null)
3935 jmoldat.getFileData().put(mapkey,
3936 seqstrmaps = jmoldat.new StructureData(pdbFile,
3939 if (!seqstrmaps.getSeqList().contains(seq))
3941 seqstrmaps.getSeqList().add(seq);
3947 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");
3954 // Instantiate the associated structure views
3955 for (Entry<String, StructureViewerModel> entry : structureViewers
3960 createOrLinkStructureViewer(entry, af, ap, jprovider);
3961 } catch (Exception e)
3964 "Error loading structure viewer: " + e.getMessage());
3965 // failed - try the next one
3977 protected void createOrLinkStructureViewer(
3978 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3979 AlignmentPanel ap, jarInputStreamProvider jprovider)
3981 final StructureViewerModel stateData = viewerData.getValue();
3984 * Search for any viewer windows already open from other alignment views
3985 * that exactly match the stored structure state
3987 StructureViewerBase comp = findMatchingViewer(viewerData);
3991 linkStructureViewer(ap, comp, stateData);
3996 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3997 * "viewer_"+stateData.viewId
3999 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4001 createChimeraViewer(viewerData, af, jprovider);
4006 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4008 createJmolViewer(viewerData, af, jprovider);
4013 * Create a new Chimera viewer.
4019 protected void createChimeraViewer(
4020 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4021 jarInputStreamProvider jprovider)
4023 StructureViewerModel data = viewerData.getValue();
4024 String chimeraSessionFile = data.getStateData();
4027 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4029 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4030 * 'uniquified' sviewid used to reconstruct the viewer here
4032 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4033 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4036 Set<Entry<File, StructureData>> fileData = data.getFileData()
4038 List<PDBEntry> pdbs = new ArrayList<>();
4039 List<SequenceI[]> allseqs = new ArrayList<>();
4040 for (Entry<File, StructureData> pdb : fileData)
4042 String filePath = pdb.getValue().getFilePath();
4043 String pdbId = pdb.getValue().getPdbId();
4044 // pdbs.add(new PDBEntry(filePath, pdbId));
4045 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4046 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4047 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4051 boolean colourByChimera = data.isColourByViewer();
4052 boolean colourBySequence = data.isColourWithAlignPanel();
4054 // TODO use StructureViewer as a factory here, see JAL-1761
4055 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4056 final SequenceI[][] seqsArray = allseqs
4057 .toArray(new SequenceI[allseqs.size()][]);
4058 String newViewId = viewerData.getKey();
4060 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4061 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4062 colourBySequence, newViewId);
4063 cvf.setSize(data.getWidth(), data.getHeight());
4064 cvf.setLocation(data.getX(), data.getY());
4068 * Create a new Jmol window. First parse the Jmol state to translate filenames
4069 * loaded into the view, and record the order in which files are shown in the
4070 * Jmol view, so we can add the sequence mappings in same order.
4076 protected void createJmolViewer(
4077 final Entry<String, StructureViewerModel> viewerData,
4078 AlignFrame af, jarInputStreamProvider jprovider)
4080 final StructureViewerModel svattrib = viewerData.getValue();
4081 String state = svattrib.getStateData();
4084 * Pre-2.9: state element value is the Jmol state string
4086 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4089 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4091 state = readJarEntry(jprovider,
4092 getViewerJarEntryName(svattrib.getViewId()));
4095 List<String> pdbfilenames = new ArrayList<>();
4096 List<SequenceI[]> seqmaps = new ArrayList<>();
4097 List<String> pdbids = new ArrayList<>();
4098 StringBuilder newFileLoc = new StringBuilder(64);
4099 int cp = 0, ncp, ecp;
4100 Map<File, StructureData> oldFiles = svattrib.getFileData();
4101 while ((ncp = state.indexOf("load ", cp)) > -1)
4105 // look for next filename in load statement
4106 newFileLoc.append(state.substring(cp,
4107 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4108 String oldfilenam = state.substring(ncp,
4109 ecp = state.indexOf("\"", ncp));
4110 // recover the new mapping data for this old filename
4111 // have to normalize filename - since Jmol and jalview do
4113 // translation differently.
4114 StructureData filedat = oldFiles.get(new File(oldfilenam));
4115 if (filedat == null)
4117 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4118 filedat = oldFiles.get(new File(reformatedOldFilename));
4120 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4121 pdbfilenames.add(filedat.getFilePath());
4122 pdbids.add(filedat.getPdbId());
4123 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4124 newFileLoc.append("\"");
4125 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4126 // look for next file statement.
4127 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4131 // just append rest of state
4132 newFileLoc.append(state.substring(cp));
4136 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4137 newFileLoc = new StringBuilder(state);
4138 newFileLoc.append("; load append ");
4139 for (File id : oldFiles.keySet())
4141 // add this and any other pdb files that should be present in
4143 StructureData filedat = oldFiles.get(id);
4144 newFileLoc.append(filedat.getFilePath());
4145 pdbfilenames.add(filedat.getFilePath());
4146 pdbids.add(filedat.getPdbId());
4147 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4148 newFileLoc.append(" \"");
4149 newFileLoc.append(filedat.getFilePath());
4150 newFileLoc.append("\"");
4153 newFileLoc.append(";");
4156 if (newFileLoc.length() == 0)
4160 int histbug = newFileLoc.indexOf("history = ");
4164 * change "history = [true|false];" to "history = [1|0];"
4167 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4168 String val = (diff == -1) ? null
4169 : newFileLoc.substring(histbug, diff);
4170 if (val != null && val.length() >= 4)
4172 if (val.contains("e")) // eh? what can it be?
4174 if (val.trim().equals("true"))
4182 newFileLoc.replace(histbug, diff, val);
4187 final String[] pdbf = pdbfilenames
4188 .toArray(new String[pdbfilenames.size()]);
4189 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4190 final SequenceI[][] sq = seqmaps
4191 .toArray(new SequenceI[seqmaps.size()][]);
4192 final String fileloc = newFileLoc.toString();
4193 final String sviewid = viewerData.getKey();
4194 final AlignFrame alf = af;
4195 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4196 svattrib.getWidth(), svattrib.getHeight());
4199 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4204 JalviewStructureDisplayI sview = null;
4207 sview = new StructureViewer(
4208 alf.alignPanel.getStructureSelectionManager())
4209 .createView(StructureViewer.ViewerType.JMOL,
4210 pdbf, id, sq, alf.alignPanel, svattrib,
4211 fileloc, rect, sviewid);
4212 addNewStructureViewer(sview);
4213 } catch (OutOfMemoryError ex)
4215 new OOMWarning("restoring structure view for PDB id " + id,
4216 (OutOfMemoryError) ex.getCause());
4217 if (sview != null && sview.isVisible())
4219 sview.closeViewer(false);
4220 sview.setVisible(false);
4226 } catch (InvocationTargetException ex)
4228 warn("Unexpected error when opening Jmol view.", ex);
4230 } catch (InterruptedException e)
4232 // e.printStackTrace();
4238 * Generates a name for the entry in the project jar file to hold state
4239 * information for a structure viewer
4244 protected String getViewerJarEntryName(String viewId)
4246 return VIEWER_PREFIX + viewId;
4250 * Returns any open frame that matches given structure viewer data. The match
4251 * is based on the unique viewId, or (for older project versions) the frame's
4257 protected StructureViewerBase findMatchingViewer(
4258 Entry<String, StructureViewerModel> viewerData)
4260 final String sviewid = viewerData.getKey();
4261 final StructureViewerModel svattrib = viewerData.getValue();
4262 StructureViewerBase comp = null;
4263 JInternalFrame[] frames = getAllFrames();
4264 for (JInternalFrame frame : frames)
4266 if (frame instanceof StructureViewerBase)
4269 * Post jalview 2.4 schema includes structure view id
4271 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4274 comp = (StructureViewerBase) frame;
4275 break; // break added in 2.9
4278 * Otherwise test for matching position and size of viewer frame
4280 else if (frame.getX() == svattrib.getX()
4281 && frame.getY() == svattrib.getY()
4282 && frame.getHeight() == svattrib.getHeight()
4283 && frame.getWidth() == svattrib.getWidth())
4285 comp = (StructureViewerBase) frame;
4286 // no break in faint hope of an exact match on viewId
4294 * Link an AlignmentPanel to an existing structure viewer.
4299 * @param useinViewerSuperpos
4300 * @param usetoColourbyseq
4301 * @param viewerColouring
4303 protected void linkStructureViewer(AlignmentPanel ap,
4304 StructureViewerBase viewer, StructureViewerModel stateData)
4306 // NOTE: if the jalview project is part of a shared session then
4307 // view synchronization should/could be done here.
4309 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4310 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4311 final boolean viewerColouring = stateData.isColourByViewer();
4312 Map<File, StructureData> oldFiles = stateData.getFileData();
4315 * Add mapping for sequences in this view to an already open viewer
4317 final AAStructureBindingModel binding = viewer.getBinding();
4318 for (File id : oldFiles.keySet())
4320 // add this and any other pdb files that should be present in the
4322 StructureData filedat = oldFiles.get(id);
4323 String pdbFile = filedat.getFilePath();
4324 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4325 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4327 binding.addSequenceForStructFile(pdbFile, seq);
4329 // and add the AlignmentPanel's reference to the view panel
4330 viewer.addAlignmentPanel(ap);
4331 if (useinViewerSuperpos)
4333 viewer.useAlignmentPanelForSuperposition(ap);
4337 viewer.excludeAlignmentPanelForSuperposition(ap);
4339 if (usetoColourbyseq)
4341 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4345 viewer.excludeAlignmentPanelForColourbyseq(ap);
4350 * Get all frames within the Desktop.
4354 protected JInternalFrame[] getAllFrames()
4356 JInternalFrame[] frames = null;
4357 // TODO is this necessary - is it safe - risk of hanging?
4362 frames = Desktop.desktop.getAllFrames();
4363 } catch (ArrayIndexOutOfBoundsException e)
4365 // occasional No such child exceptions are thrown here...
4369 } catch (InterruptedException f)
4373 } while (frames == null);
4378 * Answers true if 'version' is equal to or later than 'supported', where each
4379 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4380 * changes. Development and test values for 'version' are leniently treated
4384 * - minimum version we are comparing against
4386 * - version of data being processsed
4389 public static boolean isVersionStringLaterThan(String supported,
4392 if (supported == null || version == null
4393 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4394 || version.equalsIgnoreCase("Test")
4395 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4397 System.err.println("Assuming project file with "
4398 + (version == null ? "null" : version)
4399 + " is compatible with Jalview version " + supported);
4404 return StringUtils.compareVersions(version, supported, "b") >= 0;
4408 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4410 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4412 if (newStructureViewers != null)
4414 sview.getBinding().setFinishedLoadingFromArchive(false);
4415 newStructureViewers.add(sview);
4419 protected void setLoadingFinishedForNewStructureViewers()
4421 if (newStructureViewers != null)
4423 for (JalviewStructureDisplayI sview : newStructureViewers)
4425 sview.getBinding().setFinishedLoadingFromArchive(true);
4427 newStructureViewers.clear();
4428 newStructureViewers = null;
4432 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4433 List<SequenceI> hiddenSeqs, AlignmentI al,
4434 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4435 String viewId, List<JvAnnotRow> autoAlan)
4437 AlignFrame af = null;
4438 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4439 uniqueSeqSetId, viewId);
4441 af.setFileName(file, FileFormat.Jalview);
4443 for (int i = 0; i < JSEQ.length; i++)
4445 af.viewport.setSequenceColour(
4446 af.viewport.getAlignment().getSequenceAt(i),
4447 new java.awt.Color(JSEQ[i].getColour()));
4452 af.getViewport().setColourByReferenceSeq(true);
4453 af.getViewport().setDisplayReferenceSeq(true);
4456 af.viewport.setGatherViewsHere(view.getGatheredViews());
4458 if (view.getSequenceSetId() != null)
4460 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4462 af.viewport.setSequenceSetId(uniqueSeqSetId);
4465 // propagate shared settings to this new view
4466 af.viewport.setHistoryList(av.getHistoryList());
4467 af.viewport.setRedoList(av.getRedoList());
4471 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4473 // TODO: check if this method can be called repeatedly without
4474 // side-effects if alignpanel already registered.
4475 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4477 // apply Hidden regions to view.
4478 if (hiddenSeqs != null)
4480 for (int s = 0; s < JSEQ.length; s++)
4482 SequenceGroup hidden = new SequenceGroup();
4483 boolean isRepresentative = false;
4484 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4486 isRepresentative = true;
4487 SequenceI sequenceToHide = al
4488 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4489 hidden.addSequence(sequenceToHide, false);
4490 // remove from hiddenSeqs list so we don't try to hide it twice
4491 hiddenSeqs.remove(sequenceToHide);
4493 if (isRepresentative)
4495 SequenceI representativeSequence = al.getSequenceAt(s);
4496 hidden.addSequence(representativeSequence, false);
4497 af.viewport.hideRepSequences(representativeSequence, hidden);
4501 SequenceI[] hseqs = hiddenSeqs
4502 .toArray(new SequenceI[hiddenSeqs.size()]);
4503 af.viewport.hideSequence(hseqs);
4506 // recover view properties and display parameters
4508 af.viewport.setShowAnnotation(view.getShowAnnotation());
4509 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4510 af.viewport.setThreshold(view.getPidThreshold());
4512 af.viewport.setColourText(view.getShowColourText());
4514 af.viewport.setConservationSelected(view.getConservationSelected());
4515 af.viewport.setIncrement(view.getConsThreshold());
4516 af.viewport.setShowJVSuffix(view.getShowFullId());
4517 af.viewport.setRightAlignIds(view.getRightAlignIds());
4518 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4519 view.getFontStyle(), view.getFontSize()), true);
4520 ViewStyleI vs = af.viewport.getViewStyle();
4521 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4522 af.viewport.setViewStyle(vs);
4523 // TODO: allow custom charWidth/Heights to be restored by updating them
4524 // after setting font - which means set above to false
4525 af.viewport.setRenderGaps(view.getRenderGaps());
4526 af.viewport.setWrapAlignment(view.getWrapAlignment());
4527 af.viewport.setShowAnnotation(view.getShowAnnotation());
4529 af.viewport.setShowBoxes(view.getShowBoxes());
4531 af.viewport.setShowText(view.getShowText());
4533 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4534 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4535 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4536 af.viewport.setShowUnconserved(
4537 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4538 af.viewport.getRanges().setStartRes(view.getStartRes());
4540 if (view.getViewName() != null)
4542 af.viewport.viewName = view.getViewName();
4543 af.setInitialTabVisible();
4545 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4547 // startSeq set in af.alignPanel.updateLayout below
4548 af.alignPanel.updateLayout();
4549 ColourSchemeI cs = null;
4550 // apply colourschemes
4551 if (view.getBgColour() != null)
4553 if (view.getBgColour().startsWith("ucs"))
4555 cs = getUserColourScheme(jms, view.getBgColour());
4557 else if (view.getBgColour().startsWith("Annotation"))
4559 AnnotationColours viewAnnColour = view.getAnnotationColours();
4560 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4567 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4571 af.viewport.setGlobalColourScheme(cs);
4572 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4573 view.getIgnoreGapsinConsensus());
4574 af.viewport.getResidueShading()
4575 .setConsensus(af.viewport.getSequenceConsensusHash());
4576 af.viewport.setColourAppliesToAllGroups(false);
4578 if (view.getConservationSelected() && cs != null)
4580 af.viewport.getResidueShading()
4581 .setConservationInc(view.getConsThreshold());
4584 af.changeColour(cs);
4586 af.viewport.setColourAppliesToAllGroups(true);
4588 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4590 if (view.hasCentreColumnLabels())
4592 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4594 if (view.hasIgnoreGapsinConsensus())
4596 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4599 if (view.hasFollowHighlight())
4601 af.viewport.setFollowHighlight(view.getFollowHighlight());
4603 if (view.hasFollowSelection())
4605 af.viewport.followSelection = view.getFollowSelection();
4607 if (view.hasShowConsensusHistogram())
4610 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4614 af.viewport.setShowConsensusHistogram(true);
4616 if (view.hasShowSequenceLogo())
4618 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4622 af.viewport.setShowSequenceLogo(false);
4624 if (view.hasNormaliseSequenceLogo())
4626 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4628 if (view.hasShowDbRefTooltip())
4630 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4632 if (view.hasShowNPfeatureTooltip())
4634 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4636 if (view.hasShowGroupConsensus())
4638 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4642 af.viewport.setShowGroupConsensus(false);
4644 if (view.hasShowGroupConservation())
4646 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4650 af.viewport.setShowGroupConservation(false);
4653 // recover feature settings
4654 if (jms.getFeatureSettings() != null)
4656 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4657 .getFeatureRenderer();
4658 FeaturesDisplayed fdi;
4659 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4660 String[] renderOrder = new String[jms.getFeatureSettings()
4661 .getSettingCount()];
4662 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4663 Map<String, Float> featureOrder = new Hashtable<>();
4665 for (int fs = 0; fs < jms.getFeatureSettings()
4666 .getSettingCount(); fs++)
4668 Setting setting = jms.getFeatureSettings().getSetting(fs);
4669 String featureType = setting.getType();
4672 * restore feature filters (if any)
4674 MatcherSet filters = setting.getMatcherSet();
4675 if (filters != null)
4677 FeatureMatcherSetI filter = Jalview2XML
4678 .unmarshalFilter(featureType, filters);
4679 if (!filter.isEmpty())
4681 fr.setFeatureFilter(featureType, filter);
4686 * restore feature colour scheme
4688 Color maxColour = new Color(setting.getColour());
4689 if (setting.hasMincolour())
4692 * minColour is always set unless a simple colour
4693 * (including for colour by label though it doesn't use it)
4695 Color minColour = new Color(setting.getMincolour());
4696 Color noValueColour = minColour;
4697 NoValueColour noColour = setting.getNoValueColour();
4698 if (noColour == NoValueColour.NONE)
4700 noValueColour = null;
4702 else if (noColour == NoValueColour.MAX)
4704 noValueColour = maxColour;
4706 float min = setting.hasMin() ? setting.getMin() : 0f;
4707 float max = setting.hasMin() ? setting.getMax() : 1f;
4708 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4709 noValueColour, min, max);
4710 if (setting.getAttributeNameCount() > 0)
4712 gc.setAttributeName(setting.getAttributeName());
4714 if (setting.hasThreshold())
4716 gc.setThreshold(setting.getThreshold());
4717 int threshstate = setting.getThreshstate();
4718 // -1 = None, 0 = Below, 1 = Above threshold
4719 if (threshstate == 0)
4721 gc.setBelowThreshold(true);
4723 else if (threshstate == 1)
4725 gc.setAboveThreshold(true);
4728 gc.setAutoScaled(true); // default
4729 if (setting.hasAutoScale())
4731 gc.setAutoScaled(setting.getAutoScale());
4733 if (setting.hasColourByLabel())
4735 gc.setColourByLabel(setting.getColourByLabel());
4737 // and put in the feature colour table.
4738 featureColours.put(featureType, gc);
4742 featureColours.put(featureType,
4743 new FeatureColour(maxColour));
4745 renderOrder[fs] = featureType;
4746 if (setting.hasOrder())
4748 featureOrder.put(featureType, setting.getOrder());
4752 featureOrder.put(featureType, new Float(
4753 fs / jms.getFeatureSettings().getSettingCount()));
4755 if (setting.getDisplay())
4757 fdi.setVisible(featureType);
4760 Map<String, Boolean> fgtable = new Hashtable<>();
4761 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4763 Group grp = jms.getFeatureSettings().getGroup(gs);
4764 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4766 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4767 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4768 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4769 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4770 fgtable, featureColours, 1.0f, featureOrder);
4771 fr.transferSettings(frs);
4774 if (view.getHiddenColumnsCount() > 0)
4776 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4778 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4779 view.getHiddenColumns(c).getEnd() // +1
4783 if (view.getCalcIdParam() != null)
4785 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4787 if (calcIdParam != null)
4789 if (recoverCalcIdParam(calcIdParam, af.viewport))
4794 warn("Couldn't recover parameters for "
4795 + calcIdParam.getCalcId());
4800 af.setMenusFromViewport(af.viewport);
4801 af.setTitle(view.getTitle());
4802 // TODO: we don't need to do this if the viewport is aready visible.
4804 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4805 * has a 'cdna/protein complement' view, in which case save it in order to
4806 * populate a SplitFrame once all views have been read in.
4808 String complementaryViewId = view.getComplementId();
4809 if (complementaryViewId == null)
4811 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4813 // recompute any autoannotation
4814 af.alignPanel.updateAnnotation(false, true);
4815 reorderAutoannotation(af, al, autoAlan);
4816 af.alignPanel.alignmentChanged();
4820 splitFrameCandidates.put(view, af);
4826 * Reads saved data to restore Colour by Annotation settings
4828 * @param viewAnnColour
4832 * @param checkGroupAnnColour
4835 private ColourSchemeI constructAnnotationColour(
4836 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4837 JalviewModelSequence jms, boolean checkGroupAnnColour)
4839 boolean propagateAnnColour = false;
4840 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4841 if (checkGroupAnnColour && al.getGroups() != null
4842 && al.getGroups().size() > 0)
4844 // pre 2.8.1 behaviour
4845 // check to see if we should transfer annotation colours
4846 propagateAnnColour = true;
4847 for (SequenceGroup sg : al.getGroups())
4849 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4851 propagateAnnColour = false;
4857 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4859 String annotationId = viewAnnColour.getAnnotation();
4860 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4863 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4865 if (matchedAnnotation == null
4866 && annAlignment.getAlignmentAnnotation() != null)
4868 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4871 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4873 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4878 if (matchedAnnotation == null)
4880 System.err.println("Failed to match annotation colour scheme for "
4884 if (matchedAnnotation.getThreshold() == null)
4886 matchedAnnotation.setThreshold(new GraphLine(
4887 viewAnnColour.getThreshold(), "Threshold", Color.black));
4890 AnnotationColourGradient cs = null;
4891 if (viewAnnColour.getColourScheme().equals("None"))
4893 cs = new AnnotationColourGradient(matchedAnnotation,
4894 new Color(viewAnnColour.getMinColour()),
4895 new Color(viewAnnColour.getMaxColour()),
4896 viewAnnColour.getAboveThreshold());
4898 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4900 cs = new AnnotationColourGradient(matchedAnnotation,
4901 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4902 viewAnnColour.getAboveThreshold());
4906 cs = new AnnotationColourGradient(matchedAnnotation,
4907 ColourSchemeProperty.getColourScheme(al,
4908 viewAnnColour.getColourScheme()),
4909 viewAnnColour.getAboveThreshold());
4912 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4913 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4914 cs.setSeqAssociated(perSequenceOnly);
4915 cs.setPredefinedColours(useOriginalColours);
4917 if (propagateAnnColour && al.getGroups() != null)
4919 // Also use these settings for all the groups
4920 for (int g = 0; g < al.getGroups().size(); g++)
4922 SequenceGroup sg = al.getGroups().get(g);
4923 if (sg.getGroupColourScheme() == null)
4928 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4929 matchedAnnotation, sg.getColourScheme(),
4930 viewAnnColour.getAboveThreshold());
4931 sg.setColourScheme(groupScheme);
4932 groupScheme.setSeqAssociated(perSequenceOnly);
4933 groupScheme.setPredefinedColours(useOriginalColours);
4939 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4940 List<JvAnnotRow> autoAlan)
4942 // copy over visualization settings for autocalculated annotation in the
4944 if (al.getAlignmentAnnotation() != null)
4947 * Kludge for magic autoannotation names (see JAL-811)
4949 String[] magicNames = new String[] { "Consensus", "Quality",
4951 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4952 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4953 for (String nm : magicNames)
4955 visan.put(nm, nullAnnot);
4957 for (JvAnnotRow auan : autoAlan)
4959 visan.put(auan.template.label
4960 + (auan.template.getCalcId() == null ? ""
4961 : "\t" + auan.template.getCalcId()),
4964 int hSize = al.getAlignmentAnnotation().length;
4965 List<JvAnnotRow> reorder = new ArrayList<>();
4966 // work through any autoCalculated annotation already on the view
4967 // removing it if it should be placed in a different location on the
4968 // annotation panel.
4969 List<String> remains = new ArrayList<>(visan.keySet());
4970 for (int h = 0; h < hSize; h++)
4972 jalview.datamodel.AlignmentAnnotation jalan = al
4973 .getAlignmentAnnotation()[h];
4974 if (jalan.autoCalculated)
4977 JvAnnotRow valan = visan.get(k = jalan.label);
4978 if (jalan.getCalcId() != null)
4980 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4985 // delete the auto calculated row from the alignment
4986 al.deleteAnnotation(jalan, false);
4990 if (valan != nullAnnot)
4992 if (jalan != valan.template)
4994 // newly created autoannotation row instance
4995 // so keep a reference to the visible annotation row
4996 // and copy over all relevant attributes
4997 if (valan.template.graphHeight >= 0)
5000 jalan.graphHeight = valan.template.graphHeight;
5002 jalan.visible = valan.template.visible;
5004 reorder.add(new JvAnnotRow(valan.order, jalan));
5009 // Add any (possibly stale) autocalculated rows that were not appended to
5010 // the view during construction
5011 for (String other : remains)
5013 JvAnnotRow othera = visan.get(other);
5014 if (othera != nullAnnot && othera.template.getCalcId() != null
5015 && othera.template.getCalcId().length() > 0)
5017 reorder.add(othera);
5020 // now put the automatic annotation in its correct place
5021 int s = 0, srt[] = new int[reorder.size()];
5022 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5023 for (JvAnnotRow jvar : reorder)
5026 srt[s++] = jvar.order;
5029 jalview.util.QuickSort.sort(srt, rws);
5030 // and re-insert the annotation at its correct position
5031 for (JvAnnotRow jvar : rws)
5033 al.addAnnotation(jvar.template, jvar.order);
5035 af.alignPanel.adjustAnnotationHeight();
5039 Hashtable skipList = null;
5042 * TODO remove this method
5045 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5046 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5047 * throw new Error("Implementation Error. No skipList defined for this
5048 * Jalview2XML instance."); } return (AlignFrame)
5049 * skipList.get(view.getSequenceSetId()); }
5053 * Check if the Jalview view contained in object should be skipped or not.
5056 * @return true if view's sequenceSetId is a key in skipList
5058 private boolean skipViewport(JalviewModel object)
5060 if (skipList == null)
5065 if (skipList.containsKey(
5066 id = object.getJalviewModelSequence().getViewport()[0]
5067 .getSequenceSetId()))
5069 if (Cache.log != null && Cache.log.isDebugEnabled())
5071 Cache.log.debug("Skipping seuqence set id " + id);
5078 public void addToSkipList(AlignFrame af)
5080 if (skipList == null)
5082 skipList = new Hashtable();
5084 skipList.put(af.getViewport().getSequenceSetId(), af);
5087 public void clearSkipList()
5089 if (skipList != null)
5096 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5097 boolean ignoreUnrefed)
5099 jalview.datamodel.AlignmentI ds = getDatasetFor(
5100 vamsasSet.getDatasetId());
5101 Vector dseqs = null;
5104 // create a list of new dataset sequences
5105 dseqs = new Vector();
5107 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5109 Sequence vamsasSeq = vamsasSet.getSequence(i);
5110 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5112 // create a new dataset
5115 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5116 dseqs.copyInto(dsseqs);
5117 ds = new jalview.datamodel.Alignment(dsseqs);
5118 debug("Created new dataset " + vamsasSet.getDatasetId()
5119 + " for alignment " + System.identityHashCode(al));
5120 addDatasetRef(vamsasSet.getDatasetId(), ds);
5122 // set the dataset for the newly imported alignment.
5123 if (al.getDataset() == null && !ignoreUnrefed)
5132 * sequence definition to create/merge dataset sequence for
5136 * vector to add new dataset sequence to
5137 * @param ignoreUnrefed
5138 * - when true, don't create new sequences from vamsasSeq if it's id
5139 * doesn't already have an asssociated Jalview sequence.
5141 * - used to reorder the sequence in the alignment according to the
5142 * vamsasSeq array ordering, to preserve ordering of dataset
5144 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5145 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5147 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5149 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5150 boolean reorder = false;
5151 SequenceI dsq = null;
5152 if (sq != null && sq.getDatasetSequence() != null)
5154 dsq = sq.getDatasetSequence();
5160 if (sq == null && ignoreUnrefed)
5164 String sqid = vamsasSeq.getDsseqid();
5167 // need to create or add a new dataset sequence reference to this sequence
5170 dsq = seqRefIds.get(sqid);
5175 // make a new dataset sequence
5176 dsq = sq.createDatasetSequence();
5179 // make up a new dataset reference for this sequence
5180 sqid = seqHash(dsq);
5182 dsq.setVamsasId(uniqueSetSuffix + sqid);
5183 seqRefIds.put(sqid, dsq);
5188 dseqs.addElement(dsq);
5193 ds.addSequence(dsq);
5199 { // make this dataset sequence sq's dataset sequence
5200 sq.setDatasetSequence(dsq);
5201 // and update the current dataset alignment
5206 if (!dseqs.contains(dsq))
5213 if (ds.findIndex(dsq) < 0)
5215 ds.addSequence(dsq);
5222 // TODO: refactor this as a merge dataset sequence function
5223 // now check that sq (the dataset sequence) sequence really is the union of
5224 // all references to it
5225 // boolean pre = sq.getStart() < dsq.getStart();
5226 // boolean post = sq.getEnd() > dsq.getEnd();
5230 // StringBuffer sb = new StringBuffer();
5231 String newres = jalview.analysis.AlignSeq.extractGaps(
5232 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5233 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5234 && newres.length() > dsq.getLength())
5236 // Update with the longer sequence.
5240 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5241 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5242 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5243 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5245 dsq.setSequence(newres);
5247 // TODO: merges will never happen if we 'know' we have the real dataset
5248 // sequence - this should be detected when id==dssid
5250 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5251 // + (pre ? "prepended" : "") + " "
5252 // + (post ? "appended" : ""));
5257 // sequence refs are identical. We may need to update the existing dataset
5258 // alignment with this one, though.
5259 if (ds != null && dseqs == null)
5261 int opos = ds.findIndex(dsq);
5262 SequenceI tseq = null;
5263 if (opos != -1 && vseqpos != opos)
5265 // remove from old position
5266 ds.deleteSequence(dsq);
5268 if (vseqpos < ds.getHeight())
5270 if (vseqpos != opos)
5272 // save sequence at destination position
5273 tseq = ds.getSequenceAt(vseqpos);
5274 ds.replaceSequenceAt(vseqpos, dsq);
5275 ds.addSequence(tseq);
5280 ds.addSequence(dsq);
5287 * TODO use AlignmentI here and in related methods - needs
5288 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5290 Hashtable<String, AlignmentI> datasetIds = null;
5292 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5294 private AlignmentI getDatasetFor(String datasetId)
5296 if (datasetIds == null)
5298 datasetIds = new Hashtable<>();
5301 if (datasetIds.containsKey(datasetId))
5303 return datasetIds.get(datasetId);
5308 private void addDatasetRef(String datasetId, AlignmentI dataset)
5310 if (datasetIds == null)
5312 datasetIds = new Hashtable<>();
5314 datasetIds.put(datasetId, dataset);
5318 * make a new dataset ID for this jalview dataset alignment
5323 private String getDatasetIdRef(AlignmentI dataset)
5325 if (dataset.getDataset() != null)
5327 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5329 String datasetId = makeHashCode(dataset, null);
5330 if (datasetId == null)
5332 // make a new datasetId and record it
5333 if (dataset2Ids == null)
5335 dataset2Ids = new IdentityHashMap<>();
5339 datasetId = dataset2Ids.get(dataset);
5341 if (datasetId == null)
5343 datasetId = "ds" + dataset2Ids.size() + 1;
5344 dataset2Ids.put(dataset, datasetId);
5350 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5352 for (int d = 0; d < sequence.getDBRefCount(); d++)
5354 DBRef dr = sequence.getDBRef(d);
5355 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5356 sequence.getDBRef(d).getSource(),
5357 sequence.getDBRef(d).getVersion(),
5358 sequence.getDBRef(d).getAccessionId());
5359 if (dr.getMapping() != null)
5361 entry.setMap(addMapping(dr.getMapping()));
5363 datasetSequence.addDBRef(entry);
5367 private jalview.datamodel.Mapping addMapping(Mapping m)
5369 SequenceI dsto = null;
5370 // Mapping m = dr.getMapping();
5371 int fr[] = new int[m.getMapListFromCount() * 2];
5372 Enumeration f = m.enumerateMapListFrom();
5373 for (int _i = 0; f.hasMoreElements(); _i += 2)
5375 MapListFrom mf = (MapListFrom) f.nextElement();
5376 fr[_i] = mf.getStart();
5377 fr[_i + 1] = mf.getEnd();
5379 int fto[] = new int[m.getMapListToCount() * 2];
5380 f = m.enumerateMapListTo();
5381 for (int _i = 0; f.hasMoreElements(); _i += 2)
5383 MapListTo mf = (MapListTo) f.nextElement();
5384 fto[_i] = mf.getStart();
5385 fto[_i + 1] = mf.getEnd();
5387 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5388 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5389 if (m.getMappingChoice() != null)
5391 MappingChoice mc = m.getMappingChoice();
5392 if (mc.getDseqFor() != null)
5394 String dsfor = "" + mc.getDseqFor();
5395 if (seqRefIds.containsKey(dsfor))
5400 jmap.setTo(seqRefIds.get(dsfor));
5404 frefedSequence.add(newMappingRef(dsfor, jmap));
5410 * local sequence definition
5412 Sequence ms = mc.getSequence();
5413 SequenceI djs = null;
5414 String sqid = ms.getDsseqid();
5415 if (sqid != null && sqid.length() > 0)
5418 * recover dataset sequence
5420 djs = seqRefIds.get(sqid);
5425 "Warning - making up dataset sequence id for DbRef sequence map reference");
5426 sqid = ((Object) ms).toString(); // make up a new hascode for
5427 // undefined dataset sequence hash
5428 // (unlikely to happen)
5434 * make a new dataset sequence and add it to refIds hash
5436 djs = new jalview.datamodel.Sequence(ms.getName(),
5438 djs.setStart(jmap.getMap().getToLowest());
5439 djs.setEnd(jmap.getMap().getToHighest());
5440 djs.setVamsasId(uniqueSetSuffix + sqid);
5442 incompleteSeqs.put(sqid, djs);
5443 seqRefIds.put(sqid, djs);
5446 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5456 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5457 * view as XML (but not to file), and then reloading it
5462 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5465 JalviewModel jm = saveState(ap, null, null, null);
5467 uniqueSetSuffix = "";
5468 jm.getJalviewModelSequence().getViewport(0).setId(null);
5469 // we don't overwrite the view we just copied
5471 if (this.frefedSequence == null)
5473 frefedSequence = new Vector<>();
5476 viewportsAdded.clear();
5478 AlignFrame af = loadFromObject(jm, null, false, null);
5479 af.alignPanels.clear();
5480 af.closeMenuItem_actionPerformed(true);
5483 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5484 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5485 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5486 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5487 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5490 return af.alignPanel;
5493 private Hashtable jvids2vobj;
5495 private void warn(String msg)
5500 private void warn(String msg, Exception e)
5502 if (Cache.log != null)
5506 Cache.log.warn(msg, e);
5510 Cache.log.warn(msg);
5515 System.err.println("Warning: " + msg);
5518 e.printStackTrace();
5523 private void debug(String string)
5525 debug(string, null);
5528 private void debug(String msg, Exception e)
5530 if (Cache.log != null)
5534 Cache.log.debug(msg, e);
5538 Cache.log.debug(msg);
5543 System.err.println("Warning: " + msg);
5546 e.printStackTrace();
5552 * set the object to ID mapping tables used to write/recover objects and XML
5553 * ID strings for the jalview project. If external tables are provided then
5554 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5555 * object goes out of scope. - also populates the datasetIds hashtable with
5556 * alignment objects containing dataset sequences
5559 * Map from ID strings to jalview datamodel
5561 * Map from jalview datamodel to ID strings
5565 public void setObjectMappingTables(Hashtable vobj2jv,
5566 IdentityHashMap jv2vobj)
5568 this.jv2vobj = jv2vobj;
5569 this.vobj2jv = vobj2jv;
5570 Iterator ds = jv2vobj.keySet().iterator();
5572 while (ds.hasNext())
5574 Object jvobj = ds.next();
5575 id = jv2vobj.get(jvobj).toString();
5576 if (jvobj instanceof jalview.datamodel.Alignment)
5578 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5580 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5583 else if (jvobj instanceof jalview.datamodel.Sequence)
5585 // register sequence object so the XML parser can recover it.
5586 if (seqRefIds == null)
5588 seqRefIds = new HashMap<>();
5590 if (seqsToIds == null)
5592 seqsToIds = new IdentityHashMap<>();
5594 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5595 seqsToIds.put((SequenceI) jvobj, id);
5597 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5600 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5601 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5602 if (jvann.annotationId == null)
5604 jvann.annotationId = anid;
5606 if (!jvann.annotationId.equals(anid))
5608 // TODO verify that this is the correct behaviour
5609 this.warn("Overriding Annotation ID for " + anid
5610 + " from different id : " + jvann.annotationId);
5611 jvann.annotationId = anid;
5614 else if (jvobj instanceof String)
5616 if (jvids2vobj == null)
5618 jvids2vobj = new Hashtable();
5619 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5624 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5630 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5631 * objects created from the project archive. If string is null (default for
5632 * construction) then suffix will be set automatically.
5636 public void setUniqueSetSuffix(String string)
5638 uniqueSetSuffix = string;
5643 * uses skipList2 as the skipList for skipping views on sequence sets
5644 * associated with keys in the skipList
5648 public void setSkipList(Hashtable skipList2)
5650 skipList = skipList2;
5654 * Reads the jar entry of given name and returns its contents, or null if the
5655 * entry is not found.
5658 * @param jarEntryName
5661 protected String readJarEntry(jarInputStreamProvider jprovider,
5662 String jarEntryName)
5664 String result = null;
5665 BufferedReader in = null;
5670 * Reopen the jar input stream and traverse its entries to find a matching
5673 JarInputStream jin = jprovider.getJarInputStream();
5674 JarEntry entry = null;
5677 entry = jin.getNextJarEntry();
5678 } while (entry != null && !entry.getName().equals(jarEntryName));
5682 StringBuilder out = new StringBuilder(256);
5683 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5686 while ((data = in.readLine()) != null)
5690 result = out.toString();
5694 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5696 } catch (Exception ex)
5698 ex.printStackTrace();
5706 } catch (IOException e)
5717 * Returns an incrementing counter (0, 1, 2...)
5721 private synchronized int nextCounter()
5727 * Populates an XML model of the feature colour scheme for one feature type
5729 * @param featureType
5733 protected static jalview.schemabinding.version2.Colour marshalColour(
5734 String featureType, FeatureColourI fcol)
5736 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5737 if (fcol.isSimpleColour())
5739 col.setRGB(Format.getHexString(fcol.getColour()));
5743 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5744 col.setMin(fcol.getMin());
5745 col.setMax(fcol.getMax());
5746 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5747 col.setAutoScale(fcol.isAutoScaled());
5748 col.setThreshold(fcol.getThreshold());
5749 col.setColourByLabel(fcol.isColourByLabel());
5750 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5751 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5752 : ColourThreshTypeType.NONE));
5753 if (fcol.isColourByAttribute())
5755 col.setAttributeName(fcol.getAttributeName());
5757 Color noColour = fcol.getNoColour();
5758 if (noColour == null)
5760 col.setNoValueColour(NoValueColour.NONE);
5762 else if (noColour == fcol.getMaxColour())
5764 col.setNoValueColour(NoValueColour.MAX);
5768 col.setNoValueColour(NoValueColour.MIN);
5771 col.setName(featureType);
5776 * Populates an XML model of the feature filter(s) for one feature type
5778 * @param firstMatcher
5779 * the first (or only) match condition)
5781 * remaining match conditions (if any)
5783 * if true, conditions are and-ed, else or-ed
5785 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5786 Iterator<FeatureMatcherI> filters, boolean and)
5788 MatcherSet result = new MatcherSet();
5790 if (filters.hasNext())
5795 CompoundMatcher compound = new CompoundMatcher();
5796 compound.setAnd(and);
5797 MatcherSet matcher1 = marshalFilter(firstMatcher,
5798 Collections.emptyIterator(), and);
5799 compound.addMatcherSet(matcher1);
5800 FeatureMatcherI nextMatcher = filters.next();
5801 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5802 compound.addMatcherSet(matcher2);
5803 result.setCompoundMatcher(compound);
5808 * single condition matcher
5810 MatchCondition matcherModel = new MatchCondition();
5811 matcherModel.setCondition(
5812 firstMatcher.getMatcher().getCondition().getStableName());
5813 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5814 if (firstMatcher.isByAttribute())
5816 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5817 matcherModel.setAttributeName(firstMatcher.getAttribute());
5819 else if (firstMatcher.isByLabel())
5821 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5823 else if (firstMatcher.isByScore())
5825 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5827 result.setMatchCondition(matcherModel);
5834 * Loads one XML model of a feature filter to a Jalview object
5836 * @param featureType
5837 * @param matcherSetModel
5840 protected static FeatureMatcherSetI unmarshalFilter(
5841 String featureType, MatcherSet matcherSetModel)
5843 FeatureMatcherSetI result = new FeatureMatcherSet();
5846 unmarshalFilterConditions(result, matcherSetModel, true);
5847 } catch (IllegalStateException e)
5849 // mixing AND and OR conditions perhaps
5851 String.format("Error reading filter conditions for '%s': %s",
5852 featureType, e.getMessage()));
5853 // return as much as was parsed up to the error
5860 * Adds feature match conditions to matcherSet as unmarshalled from XML
5861 * (possibly recursively for compound conditions)
5864 * @param matcherSetModel
5866 * if true, multiple conditions are AND-ed, else they are OR-ed
5867 * @throws IllegalStateException
5868 * if AND and OR conditions are mixed
5870 protected static void unmarshalFilterConditions(
5871 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5874 MatchCondition mc = matcherSetModel.getMatchCondition();
5880 FeatureMatcherByType filterBy = mc.getBy();
5881 Condition cond = Condition.fromString(mc.getCondition());
5882 String pattern = mc.getValue();
5883 FeatureMatcherI matchCondition = null;
5884 if (filterBy == FeatureMatcherByType.BYLABEL)
5886 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5888 else if (filterBy == FeatureMatcherByType.BYSCORE)
5890 matchCondition = FeatureMatcher.byScore(cond, pattern);
5893 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5895 String[] attNames = mc.getAttributeName();
5896 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5901 * note this throws IllegalStateException if AND-ing to a
5902 * previously OR-ed compound condition, or vice versa
5906 matcherSet.and(matchCondition);
5910 matcherSet.or(matchCondition);
5916 * compound condition
5918 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5920 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5921 if (matchers.length == 2)
5923 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5924 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5928 System.err.println("Malformed compound filter condition");
5934 * Loads one XML model of a feature colour to a Jalview object
5936 * @param colourModel
5939 protected static FeatureColourI unmarshalColour(
5940 jalview.schemabinding.version2.Colour colourModel)
5942 FeatureColourI colour = null;
5944 if (colourModel.hasMax())
5946 Color mincol = null;
5947 Color maxcol = null;
5948 Color noValueColour = null;
5952 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5953 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5954 } catch (Exception e)
5956 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5959 NoValueColour noCol = colourModel.getNoValueColour();
5960 if (noCol == NoValueColour.MIN)
5962 noValueColour = mincol;
5964 else if (noCol == NoValueColour.MAX)
5966 noValueColour = maxcol;
5969 colour = new FeatureColour(mincol, maxcol, noValueColour,
5970 colourModel.getMin(),
5971 colourModel.getMax());
5972 String[] attributes = colourModel.getAttributeName();
5973 if (attributes != null && attributes.length > 0)
5975 colour.setAttributeName(attributes);
5977 if (colourModel.hasAutoScale())
5979 colour.setAutoScaled(colourModel.getAutoScale());
5981 if (colourModel.hasColourByLabel())
5983 colour.setColourByLabel(colourModel.getColourByLabel());
5985 if (colourModel.hasThreshold())
5987 colour.setThreshold(colourModel.getThreshold());
5989 ColourThreshTypeType ttyp = colourModel.getThreshType();
5992 if (ttyp == ColourThreshTypeType.ABOVE)
5994 colour.setAboveThreshold(true);
5996 else if (ttyp == ColourThreshTypeType.BELOW)
5998 colour.setBelowThreshold(true);
6004 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6005 colour = new FeatureColour(color);