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 BackupFiles backupfiles = new BackupFiles(statefile);
468 fos = new FileOutputStream(backupfiles.getTempFile());
470 JarOutputStream jout = new JarOutputStream(fos);
473 backupfiles.setWriteSuccess(true);
474 backupfiles.rollBackupsAndRenameTempFile();
476 } catch (Exception e)
478 // TODO: inform user of the problem - they need to know if their data was
480 if (errorMessage == null)
482 errorMessage = "Couldn't write Jalview Archive to output file '"
483 + statefile + "' - See console error log for details";
487 errorMessage += "(output file was '" + statefile + "')";
497 } catch (IOException e)
507 * Writes a jalview project archive to the given Jar output stream.
511 public void saveState(JarOutputStream jout)
513 AlignFrame[] frames = Desktop.getAlignFrames();
519 saveAllFrames(Arrays.asList(frames), jout);
523 * core method for storing state for a set of AlignFrames.
526 * - frames involving all data to be exported (including containing
529 * - project output stream
531 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
533 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
536 * ensure cached data is clear before starting
538 // todo tidy up seqRefIds, seqsToIds initialisation / reset
540 splitFrameCandidates.clear();
545 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
546 // //////////////////////////////////////////////////
548 List<String> shortNames = new ArrayList<>();
549 List<String> viewIds = new ArrayList<>();
552 for (int i = frames.size() - 1; i > -1; i--)
554 AlignFrame af = frames.get(i);
556 if (skipList != null && skipList
557 .containsKey(af.getViewport().getSequenceSetId()))
562 String shortName = makeFilename(af, shortNames);
564 int ap, apSize = af.alignPanels.size();
566 for (ap = 0; ap < apSize; ap++)
568 AlignmentPanel apanel = af.alignPanels.get(ap);
569 String fileName = apSize == 1 ? shortName : ap + shortName;
570 if (!fileName.endsWith(".xml"))
572 fileName = fileName + ".xml";
575 saveState(apanel, fileName, jout, viewIds);
577 String dssid = getDatasetIdRef(
578 af.getViewport().getAlignment().getDataset());
579 if (!dsses.containsKey(dssid))
581 dsses.put(dssid, af);
586 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
592 } catch (Exception foo)
597 } catch (Exception ex)
599 // TODO: inform user of the problem - they need to know if their data was
601 if (errorMessage == null)
603 errorMessage = "Couldn't write Jalview Archive - see error output for details";
605 ex.printStackTrace();
610 * Generates a distinct file name, based on the title of the AlignFrame, by
611 * appending _n for increasing n until an unused name is generated. The new
612 * name (without its extension) is added to the list.
616 * @return the generated name, with .xml extension
618 protected String makeFilename(AlignFrame af, List<String> namesUsed)
620 String shortName = af.getTitle();
622 if (shortName.indexOf(File.separatorChar) > -1)
624 shortName = shortName
625 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
630 while (namesUsed.contains(shortName))
632 if (shortName.endsWith("_" + (count - 1)))
634 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
637 shortName = shortName.concat("_" + count);
641 namesUsed.add(shortName);
643 if (!shortName.endsWith(".xml"))
645 shortName = shortName + ".xml";
650 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
651 public boolean saveAlignment(AlignFrame af, String jarFile,
656 // create backupfiles object and get new temp filename destination
657 BackupFiles backupfiles = new BackupFiles(jarFile);
658 FileOutputStream fos = new FileOutputStream(
659 backupfiles.getTempFilePath());
661 JarOutputStream jout = new JarOutputStream(fos);
662 List<AlignFrame> frames = new ArrayList<>();
664 // resolve splitframes
665 if (af.getViewport().getCodingComplement() != null)
667 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
673 saveAllFrames(frames, jout);
677 } catch (Exception foo)
682 boolean success = true;
684 backupfiles.setWriteSuccess(success);
685 success = backupfiles.rollBackupsAndRenameTempFile();
688 } catch (Exception ex)
690 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
691 ex.printStackTrace();
696 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
697 String fileName, JarOutputStream jout)
700 for (String dssids : dsses.keySet())
702 AlignFrame _af = dsses.get(dssids);
703 String jfileName = fileName + " Dataset for " + _af.getTitle();
704 if (!jfileName.endsWith(".xml"))
706 jfileName = jfileName + ".xml";
708 saveState(_af.alignPanel, jfileName, true, jout, null);
713 * create a JalviewModel from an alignment view and marshall it to a
717 * panel to create jalview model for
719 * name of alignment panel written to output stream
726 public JalviewModel saveState(AlignmentPanel ap, String fileName,
727 JarOutputStream jout, List<String> viewIds)
729 return saveState(ap, fileName, false, jout, viewIds);
733 * create a JalviewModel from an alignment view and marshall it to a
737 * panel to create jalview model for
739 * name of alignment panel written to output stream
741 * when true, only write the dataset for the alignment, not the data
742 * associated with the view.
748 public JalviewModel saveState(AlignmentPanel ap, String fileName,
749 boolean storeDS, JarOutputStream jout, List<String> viewIds)
753 viewIds = new ArrayList<>();
758 List<UserColourScheme> userColours = new ArrayList<>();
760 AlignViewport av = ap.av;
761 ViewportRanges vpRanges = av.getRanges();
763 JalviewModel object = new JalviewModel();
764 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
766 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
768 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
771 * rjal is full height alignment, jal is actual alignment with full metadata
772 * but excludes hidden sequences.
774 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
776 if (av.hasHiddenRows())
778 rjal = jal.getHiddenSequences().getFullAlignment();
781 SequenceSet vamsasSet = new SequenceSet();
783 JalviewModelSequence jms = new JalviewModelSequence();
785 vamsasSet.setGapChar(jal.getGapCharacter() + "");
787 if (jal.getDataset() != null)
789 // dataset id is the dataset's hashcode
790 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
793 // switch jal and the dataset
794 jal = jal.getDataset();
798 if (jal.getProperties() != null)
800 Enumeration en = jal.getProperties().keys();
801 while (en.hasMoreElements())
803 String key = en.nextElement().toString();
804 SequenceSetProperties ssp = new SequenceSetProperties();
806 ssp.setValue(jal.getProperties().get(key).toString());
807 vamsasSet.addSequenceSetProperties(ssp);
812 Set<String> calcIdSet = new HashSet<>();
813 // record the set of vamsas sequence XML POJO we create.
814 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
816 for (final SequenceI jds : rjal.getSequences())
818 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
819 : jds.getDatasetSequence();
820 String id = seqHash(jds);
821 if (vamsasSetIds.get(id) == null)
823 if (seqRefIds.get(id) != null && !storeDS)
825 // This happens for two reasons: 1. multiple views are being
827 // 2. the hashCode has collided with another sequence's code. This
829 // HAPPEN! (PF00072.15.stk does this)
830 // JBPNote: Uncomment to debug writing out of files that do not read
831 // back in due to ArrayOutOfBoundExceptions.
832 // System.err.println("vamsasSeq backref: "+id+"");
833 // System.err.println(jds.getName()+"
834 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
835 // System.err.println("Hashcode: "+seqHash(jds));
836 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
837 // System.err.println(rsq.getName()+"
838 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
839 // System.err.println("Hashcode: "+seqHash(rsq));
843 vamsasSeq = createVamsasSequence(id, jds);
844 vamsasSet.addSequence(vamsasSeq);
845 vamsasSetIds.put(id, vamsasSeq);
846 seqRefIds.put(id, jds);
850 jseq.setStart(jds.getStart());
851 jseq.setEnd(jds.getEnd());
852 jseq.setColour(av.getSequenceColour(jds).getRGB());
854 jseq.setId(id); // jseq id should be a string not a number
857 // Store any sequences this sequence represents
858 if (av.hasHiddenRows())
860 // use rjal, contains the full height alignment
862 av.getAlignment().getHiddenSequences().isHidden(jds));
864 if (av.isHiddenRepSequence(jds))
866 jalview.datamodel.SequenceI[] reps = av
867 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
869 for (int h = 0; h < reps.length; h++)
873 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
878 // mark sequence as reference - if it is the reference for this view
881 jseq.setViewreference(jds == jal.getSeqrep());
885 // TODO: omit sequence features from each alignment view's XML dump if we
886 // are storing dataset
887 List<jalview.datamodel.SequenceFeature> sfs = jds
888 .getSequenceFeatures();
889 for (SequenceFeature sf : sfs)
891 Features features = new Features();
893 features.setBegin(sf.getBegin());
894 features.setEnd(sf.getEnd());
895 features.setDescription(sf.getDescription());
896 features.setType(sf.getType());
897 features.setFeatureGroup(sf.getFeatureGroup());
898 features.setScore(sf.getScore());
899 if (sf.links != null)
901 for (int l = 0; l < sf.links.size(); l++)
903 OtherData keyValue = new OtherData();
904 keyValue.setKey("LINK_" + l);
905 keyValue.setValue(sf.links.elementAt(l).toString());
906 features.addOtherData(keyValue);
909 if (sf.otherDetails != null)
912 * save feature attributes, which may be simple strings or
913 * map valued (have sub-attributes)
915 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
917 String key = entry.getKey();
918 Object value = entry.getValue();
919 if (value instanceof Map<?, ?>)
921 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
924 OtherData otherData = new OtherData();
925 otherData.setKey(key);
926 otherData.setKey2(subAttribute.getKey());
927 otherData.setValue(subAttribute.getValue().toString());
928 features.addOtherData(otherData);
933 OtherData otherData = new OtherData();
934 otherData.setKey(key);
935 otherData.setValue(value.toString());
936 features.addOtherData(otherData);
941 jseq.addFeatures(features);
944 if (jdatasq.getAllPDBEntries() != null)
946 Enumeration en = jdatasq.getAllPDBEntries().elements();
947 while (en.hasMoreElements())
949 Pdbids pdb = new Pdbids();
950 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
953 String pdbId = entry.getId();
955 pdb.setType(entry.getType());
958 * Store any structure views associated with this sequence. This
959 * section copes with duplicate entries in the project, so a dataset
960 * only view *should* be coped with sensibly.
962 // This must have been loaded, is it still visible?
963 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
964 String matchedFile = null;
965 for (int f = frames.length - 1; f > -1; f--)
967 if (frames[f] instanceof StructureViewerBase)
969 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
970 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
971 matchedFile, viewFrame);
973 * Only store each structure viewer's state once in the project
974 * jar. First time through only (storeDS==false)
976 String viewId = viewFrame.getViewId();
977 if (!storeDS && !viewIds.contains(viewId))
982 String viewerState = viewFrame.getStateInfo();
983 writeJarEntry(jout, getViewerJarEntryName(viewId),
984 viewerState.getBytes());
985 } catch (IOException e)
988 "Error saving viewer state: " + e.getMessage());
994 if (matchedFile != null || entry.getFile() != null)
996 if (entry.getFile() != null)
999 matchedFile = entry.getFile();
1001 pdb.setFile(matchedFile); // entry.getFile());
1002 if (pdbfiles == null)
1004 pdbfiles = new ArrayList<>();
1007 if (!pdbfiles.contains(pdbId))
1009 pdbfiles.add(pdbId);
1010 copyFileToJar(jout, matchedFile, pdbId);
1014 Enumeration<String> props = entry.getProperties();
1015 if (props.hasMoreElements())
1017 PdbentryItem item = new PdbentryItem();
1018 while (props.hasMoreElements())
1020 Property prop = new Property();
1021 String key = props.nextElement();
1023 prop.setValue(entry.getProperty(key).toString());
1024 item.addProperty(prop);
1026 pdb.addPdbentryItem(item);
1029 jseq.addPdbids(pdb);
1033 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1038 if (!storeDS && av.hasHiddenRows())
1040 jal = av.getAlignment();
1044 if (storeDS && jal.getCodonFrames() != null)
1046 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1047 for (AlignedCodonFrame acf : jac)
1049 AlcodonFrame alc = new AlcodonFrame();
1050 if (acf.getProtMappings() != null
1051 && acf.getProtMappings().length > 0)
1053 boolean hasMap = false;
1054 SequenceI[] dnas = acf.getdnaSeqs();
1055 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1056 for (int m = 0; m < pmaps.length; m++)
1058 AlcodMap alcmap = new AlcodMap();
1059 alcmap.setDnasq(seqHash(dnas[m]));
1061 createVamsasMapping(pmaps[m], dnas[m], null, false));
1062 alc.addAlcodMap(alcmap);
1067 vamsasSet.addAlcodonFrame(alc);
1070 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1072 // AlcodonFrame alc = new AlcodonFrame();
1073 // vamsasSet.addAlcodonFrame(alc);
1074 // for (int p = 0; p < acf.aaWidth; p++)
1076 // Alcodon cmap = new Alcodon();
1077 // if (acf.codons[p] != null)
1079 // // Null codons indicate a gapped column in the translated peptide
1081 // cmap.setPos1(acf.codons[p][0]);
1082 // cmap.setPos2(acf.codons[p][1]);
1083 // cmap.setPos3(acf.codons[p][2]);
1085 // alc.addAlcodon(cmap);
1087 // if (acf.getProtMappings() != null
1088 // && acf.getProtMappings().length > 0)
1090 // SequenceI[] dnas = acf.getdnaSeqs();
1091 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1092 // for (int m = 0; m < pmaps.length; m++)
1094 // AlcodMap alcmap = new AlcodMap();
1095 // alcmap.setDnasq(seqHash(dnas[m]));
1096 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1098 // alc.addAlcodMap(alcmap);
1105 // /////////////////////////////////
1106 if (!storeDS && av.getCurrentTree() != null)
1108 // FIND ANY ASSOCIATED TREES
1109 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1110 if (Desktop.desktop != null)
1112 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1114 for (int t = 0; t < frames.length; t++)
1116 if (frames[t] instanceof TreePanel)
1118 TreePanel tp = (TreePanel) frames[t];
1120 if (tp.treeCanvas.av.getAlignment() == jal)
1122 Tree tree = new Tree();
1123 tree.setTitle(tp.getTitle());
1124 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1125 tree.setNewick(tp.getTree().print());
1126 tree.setThreshold(tp.treeCanvas.threshold);
1128 tree.setFitToWindow(tp.fitToWindow.getState());
1129 tree.setFontName(tp.getTreeFont().getName());
1130 tree.setFontSize(tp.getTreeFont().getSize());
1131 tree.setFontStyle(tp.getTreeFont().getStyle());
1132 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1134 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1135 tree.setShowDistances(tp.distanceMenu.getState());
1137 tree.setHeight(tp.getHeight());
1138 tree.setWidth(tp.getWidth());
1139 tree.setXpos(tp.getX());
1140 tree.setYpos(tp.getY());
1141 tree.setId(makeHashCode(tp, null));
1151 * store forward refs from an annotationRow to any groups
1153 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1156 for (SequenceI sq : jal.getSequences())
1158 // Store annotation on dataset sequences only
1159 AlignmentAnnotation[] aa = sq.getAnnotation();
1160 if (aa != null && aa.length > 0)
1162 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1169 if (jal.getAlignmentAnnotation() != null)
1171 // Store the annotation shown on the alignment.
1172 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1173 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1178 if (jal.getGroups() != null)
1180 JGroup[] groups = new JGroup[jal.getGroups().size()];
1182 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1184 JGroup jGroup = new JGroup();
1185 groups[++i] = jGroup;
1187 jGroup.setStart(sg.getStartRes());
1188 jGroup.setEnd(sg.getEndRes());
1189 jGroup.setName(sg.getName());
1190 if (groupRefs.containsKey(sg))
1192 // group has references so set its ID field
1193 jGroup.setId(groupRefs.get(sg));
1195 ColourSchemeI colourScheme = sg.getColourScheme();
1196 if (colourScheme != null)
1198 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1199 if (groupColourScheme.conservationApplied())
1201 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1203 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1206 setUserColourScheme(colourScheme, userColours, jms));
1210 jGroup.setColour(colourScheme.getSchemeName());
1213 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1215 jGroup.setColour("AnnotationColourGradient");
1216 jGroup.setAnnotationColours(constructAnnotationColours(
1217 (jalview.schemes.AnnotationColourGradient) colourScheme,
1220 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1223 setUserColourScheme(colourScheme, userColours, jms));
1227 jGroup.setColour(colourScheme.getSchemeName());
1230 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1233 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1234 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1235 jGroup.setDisplayText(sg.getDisplayText());
1236 jGroup.setColourText(sg.getColourText());
1237 jGroup.setTextCol1(sg.textColour.getRGB());
1238 jGroup.setTextCol2(sg.textColour2.getRGB());
1239 jGroup.setTextColThreshold(sg.thresholdTextColour);
1240 jGroup.setShowUnconserved(sg.getShowNonconserved());
1241 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1242 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1243 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1244 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1245 for (SequenceI seq : sg.getSequences())
1247 jGroup.addSeq(seqHash(seq));
1251 jms.setJGroup(groups);
1255 // /////////SAVE VIEWPORT
1256 Viewport view = new Viewport();
1257 view.setTitle(ap.alignFrame.getTitle());
1258 view.setSequenceSetId(
1259 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1260 view.setId(av.getViewId());
1261 if (av.getCodingComplement() != null)
1263 view.setComplementId(av.getCodingComplement().getViewId());
1265 view.setViewName(av.viewName);
1266 view.setGatheredViews(av.isGatherViewsHere());
1268 Rectangle size = ap.av.getExplodedGeometry();
1269 Rectangle position = size;
1272 size = ap.alignFrame.getBounds();
1273 if (av.getCodingComplement() != null)
1275 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1283 view.setXpos(position.x);
1284 view.setYpos(position.y);
1286 view.setWidth(size.width);
1287 view.setHeight(size.height);
1289 view.setStartRes(vpRanges.getStartRes());
1290 view.setStartSeq(vpRanges.getStartSeq());
1292 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1294 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1298 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1300 AnnotationColours ac = constructAnnotationColours(
1301 (jalview.schemes.AnnotationColourGradient) av
1302 .getGlobalColourScheme(),
1305 view.setAnnotationColours(ac);
1306 view.setBgColour("AnnotationColourGradient");
1310 view.setBgColour(ColourSchemeProperty
1311 .getColourName(av.getGlobalColourScheme()));
1314 ResidueShaderI vcs = av.getResidueShading();
1315 ColourSchemeI cs = av.getGlobalColourScheme();
1319 if (vcs.conservationApplied())
1321 view.setConsThreshold(vcs.getConservationInc());
1322 if (cs instanceof jalview.schemes.UserColourScheme)
1324 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1327 view.setPidThreshold(vcs.getThreshold());
1330 view.setConservationSelected(av.getConservationSelected());
1331 view.setPidSelected(av.getAbovePIDThreshold());
1332 view.setFontName(av.font.getName());
1333 view.setFontSize(av.font.getSize());
1334 view.setFontStyle(av.font.getStyle());
1335 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1336 view.setRenderGaps(av.isRenderGaps());
1337 view.setShowAnnotation(av.isShowAnnotation());
1338 view.setShowBoxes(av.getShowBoxes());
1339 view.setShowColourText(av.getColourText());
1340 view.setShowFullId(av.getShowJVSuffix());
1341 view.setRightAlignIds(av.isRightAlignIds());
1342 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1343 view.setShowText(av.getShowText());
1344 view.setShowUnconserved(av.getShowUnconserved());
1345 view.setWrapAlignment(av.getWrapAlignment());
1346 view.setTextCol1(av.getTextColour().getRGB());
1347 view.setTextCol2(av.getTextColour2().getRGB());
1348 view.setTextColThreshold(av.getThresholdTextColour());
1349 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1350 view.setShowSequenceLogo(av.isShowSequenceLogo());
1351 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1352 view.setShowGroupConsensus(av.isShowGroupConsensus());
1353 view.setShowGroupConservation(av.isShowGroupConservation());
1354 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1355 view.setShowDbRefTooltip(av.isShowDBRefs());
1356 view.setFollowHighlight(av.isFollowHighlight());
1357 view.setFollowSelection(av.followSelection);
1358 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1359 if (av.getFeaturesDisplayed() != null)
1361 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1363 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1364 .getFeatureRenderer();
1365 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1367 Vector<String> settingsAdded = new Vector<>();
1368 if (renderOrder != null)
1370 for (String featureType : renderOrder)
1372 Setting setting = new Setting();
1373 setting.setType(featureType);
1376 * save any filter for the feature type
1378 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1379 if (filter != null) {
1380 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1381 FeatureMatcherI firstFilter = filters.next();
1382 setting.setMatcherSet(Jalview2XML.marshalFilter(
1383 firstFilter, filters, filter.isAnded()));
1387 * save colour scheme for the feature type
1389 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1390 if (!fcol.isSimpleColour())
1392 setting.setColour(fcol.getMaxColour().getRGB());
1393 setting.setMincolour(fcol.getMinColour().getRGB());
1394 setting.setMin(fcol.getMin());
1395 setting.setMax(fcol.getMax());
1396 setting.setColourByLabel(fcol.isColourByLabel());
1397 if (fcol.isColourByAttribute())
1399 setting.setAttributeName(fcol.getAttributeName());
1401 setting.setAutoScale(fcol.isAutoScaled());
1402 setting.setThreshold(fcol.getThreshold());
1403 Color noColour = fcol.getNoColour();
1404 if (noColour == null)
1406 setting.setNoValueColour(NoValueColour.NONE);
1408 else if (noColour.equals(fcol.getMaxColour()))
1410 setting.setNoValueColour(NoValueColour.MAX);
1414 setting.setNoValueColour(NoValueColour.MIN);
1416 // -1 = No threshold, 0 = Below, 1 = Above
1417 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1418 : (fcol.isBelowThreshold() ? 0 : -1));
1422 setting.setColour(fcol.getColour().getRGB());
1426 av.getFeaturesDisplayed().isVisible(featureType));
1428 .getOrder(featureType);
1431 setting.setOrder(rorder);
1433 fs.addSetting(setting);
1434 settingsAdded.addElement(featureType);
1438 // is groups actually supposed to be a map here ?
1439 Iterator<String> en = fr.getFeatureGroups().iterator();
1440 Vector<String> groupsAdded = new Vector<>();
1441 while (en.hasNext())
1443 String grp = en.next();
1444 if (groupsAdded.contains(grp))
1448 Group g = new Group();
1450 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1453 groupsAdded.addElement(grp);
1455 jms.setFeatureSettings(fs);
1458 if (av.hasHiddenColumns())
1460 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1461 .getHiddenColumns();
1464 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1468 Iterator<int[]> hiddenRegions = hidden.iterator();
1469 while (hiddenRegions.hasNext())
1471 int[] region = hiddenRegions.next();
1472 HiddenColumns hc = new HiddenColumns();
1473 hc.setStart(region[0]);
1474 hc.setEnd(region[1]);
1475 view.addHiddenColumns(hc);
1479 if (calcIdSet.size() > 0)
1481 for (String calcId : calcIdSet)
1483 if (calcId.trim().length() > 0)
1485 CalcIdParam cidp = createCalcIdParam(calcId, av);
1486 // Some calcIds have no parameters.
1489 view.addCalcIdParam(cidp);
1495 jms.addViewport(view);
1497 object.setJalviewModelSequence(jms);
1498 object.getVamsasModel().addSequenceSet(vamsasSet);
1500 if (jout != null && fileName != null)
1502 // We may not want to write the object to disk,
1503 // eg we can copy the alignViewport to a new view object
1504 // using save and then load
1507 System.out.println("Writing jar entry " + fileName);
1508 JarEntry entry = new JarEntry(fileName);
1509 jout.putNextEntry(entry);
1510 PrintWriter pout = new PrintWriter(
1511 new OutputStreamWriter(jout, UTF_8));
1512 Marshaller marshaller = new Marshaller(pout);
1513 marshaller.marshal(object);
1516 } catch (Exception ex)
1518 // TODO: raise error in GUI if marshalling failed.
1519 ex.printStackTrace();
1526 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1527 * for each viewer, with
1529 * <li>viewer geometry (position, size, split pane divider location)</li>
1530 * <li>index of the selected structure in the viewer (currently shows gapped
1532 * <li>the id of the annotation holding RNA secondary structure</li>
1533 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1535 * Varna viewer state is also written out (in native Varna XML) to separate
1536 * project jar entries. A separate entry is written for each RNA structure
1537 * displayed, with the naming convention
1539 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1547 * @param storeDataset
1549 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1550 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1551 boolean storeDataset)
1553 if (Desktop.desktop == null)
1557 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1558 for (int f = frames.length - 1; f > -1; f--)
1560 if (frames[f] instanceof AppVarna)
1562 AppVarna varna = (AppVarna) frames[f];
1564 * link the sequence to every viewer that is showing it and is linked to
1565 * its alignment panel
1567 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1569 String viewId = varna.getViewId();
1570 RnaViewer rna = new RnaViewer();
1571 rna.setViewId(viewId);
1572 rna.setTitle(varna.getTitle());
1573 rna.setXpos(varna.getX());
1574 rna.setYpos(varna.getY());
1575 rna.setWidth(varna.getWidth());
1576 rna.setHeight(varna.getHeight());
1577 rna.setDividerLocation(varna.getDividerLocation());
1578 rna.setSelectedRna(varna.getSelectedIndex());
1579 jseq.addRnaViewer(rna);
1582 * Store each Varna panel's state once in the project per sequence.
1583 * First time through only (storeDataset==false)
1585 // boolean storeSessions = false;
1586 // String sequenceViewId = viewId + seqsToIds.get(jds);
1587 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1589 // viewIds.add(sequenceViewId);
1590 // storeSessions = true;
1592 for (RnaModel model : varna.getModels())
1594 if (model.seq == jds)
1597 * VARNA saves each view (sequence or alignment secondary
1598 * structure, gapped or trimmed) as a separate XML file
1600 String jarEntryName = rnaSessions.get(model);
1601 if (jarEntryName == null)
1604 String varnaStateFile = varna.getStateInfo(model.rna);
1605 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1606 copyFileToJar(jout, varnaStateFile, jarEntryName);
1607 rnaSessions.put(model, jarEntryName);
1609 SecondaryStructure ss = new SecondaryStructure();
1610 String annotationId = varna.getAnnotation(jds).annotationId;
1611 ss.setAnnotationId(annotationId);
1612 ss.setViewerState(jarEntryName);
1613 ss.setGapped(model.gapped);
1614 ss.setTitle(model.title);
1615 rna.addSecondaryStructure(ss);
1624 * Copy the contents of a file to a new entry added to the output jar
1628 * @param jarEntryName
1630 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1631 String jarEntryName)
1633 DataInputStream dis = null;
1636 File file = new File(infilePath);
1637 if (file.exists() && jout != null)
1639 dis = new DataInputStream(new FileInputStream(file));
1640 byte[] data = new byte[(int) file.length()];
1641 dis.readFully(data);
1642 writeJarEntry(jout, jarEntryName, data);
1644 } catch (Exception ex)
1646 ex.printStackTrace();
1654 } catch (IOException e)
1663 * Write the data to a new entry of given name in the output jar file
1666 * @param jarEntryName
1668 * @throws IOException
1670 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1671 byte[] data) throws IOException
1675 System.out.println("Writing jar entry " + jarEntryName);
1676 jout.putNextEntry(new JarEntry(jarEntryName));
1677 DataOutputStream dout = new DataOutputStream(jout);
1678 dout.write(data, 0, data.length);
1685 * Save the state of a structure viewer
1690 * the archive XML element under which to save the state
1693 * @param matchedFile
1697 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1698 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1699 String matchedFile, StructureViewerBase viewFrame)
1701 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1704 * Look for any bindings for this viewer to the PDB file of interest
1705 * (including part matches excluding chain id)
1707 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1709 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1710 final String pdbId = pdbentry.getId();
1711 if (!pdbId.equals(entry.getId())
1712 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1713 .startsWith(pdbId.toLowerCase())))
1716 * not interested in a binding to a different PDB entry here
1720 if (matchedFile == null)
1722 matchedFile = pdbentry.getFile();
1724 else if (!matchedFile.equals(pdbentry.getFile()))
1727 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1728 + pdbentry.getFile());
1732 // can get at it if the ID
1733 // match is ambiguous (e.g.
1736 for (int smap = 0; smap < viewFrame.getBinding()
1737 .getSequence()[peid].length; smap++)
1739 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1740 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1742 StructureState state = new StructureState();
1743 state.setVisible(true);
1744 state.setXpos(viewFrame.getX());
1745 state.setYpos(viewFrame.getY());
1746 state.setWidth(viewFrame.getWidth());
1747 state.setHeight(viewFrame.getHeight());
1748 final String viewId = viewFrame.getViewId();
1749 state.setViewId(viewId);
1750 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1751 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1752 state.setColourByJmol(viewFrame.isColouredByViewer());
1753 state.setType(viewFrame.getViewerType().toString());
1754 pdb.addStructureState(state);
1762 * Populates the AnnotationColours xml for save. This captures the settings of
1763 * the options in the 'Colour by Annotation' dialog.
1766 * @param userColours
1770 private AnnotationColours constructAnnotationColours(
1771 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1772 JalviewModelSequence jms)
1774 AnnotationColours ac = new AnnotationColours();
1775 ac.setAboveThreshold(acg.getAboveThreshold());
1776 ac.setThreshold(acg.getAnnotationThreshold());
1777 // 2.10.2 save annotationId (unique) not annotation label
1778 ac.setAnnotation(acg.getAnnotation().annotationId);
1779 if (acg.getBaseColour() instanceof UserColourScheme)
1782 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1787 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1790 ac.setMaxColour(acg.getMaxColour().getRGB());
1791 ac.setMinColour(acg.getMinColour().getRGB());
1792 ac.setPerSequence(acg.isSeqAssociated());
1793 ac.setPredefinedColours(acg.isPredefinedColours());
1797 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1798 IdentityHashMap<SequenceGroup, String> groupRefs,
1799 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1800 SequenceSet vamsasSet)
1803 for (int i = 0; i < aa.length; i++)
1805 Annotation an = new Annotation();
1807 AlignmentAnnotation annotation = aa[i];
1808 if (annotation.annotationId != null)
1810 annotationIds.put(annotation.annotationId, annotation);
1813 an.setId(annotation.annotationId);
1815 an.setVisible(annotation.visible);
1817 an.setDescription(annotation.description);
1819 if (annotation.sequenceRef != null)
1821 // 2.9 JAL-1781 xref on sequence id rather than name
1822 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1824 if (annotation.groupRef != null)
1826 String groupIdr = groupRefs.get(annotation.groupRef);
1827 if (groupIdr == null)
1829 // make a locally unique String
1830 groupRefs.put(annotation.groupRef,
1831 groupIdr = ("" + System.currentTimeMillis()
1832 + annotation.groupRef.getName()
1833 + groupRefs.size()));
1835 an.setGroupRef(groupIdr.toString());
1838 // store all visualization attributes for annotation
1839 an.setGraphHeight(annotation.graphHeight);
1840 an.setCentreColLabels(annotation.centreColLabels);
1841 an.setScaleColLabels(annotation.scaleColLabel);
1842 an.setShowAllColLabels(annotation.showAllColLabels);
1843 an.setBelowAlignment(annotation.belowAlignment);
1845 if (annotation.graph > 0)
1848 an.setGraphType(annotation.graph);
1849 an.setGraphGroup(annotation.graphGroup);
1850 if (annotation.getThreshold() != null)
1852 ThresholdLine line = new ThresholdLine();
1853 line.setLabel(annotation.getThreshold().label);
1854 line.setValue(annotation.getThreshold().value);
1855 line.setColour(annotation.getThreshold().colour.getRGB());
1856 an.setThresholdLine(line);
1864 an.setLabel(annotation.label);
1866 if (annotation == av.getAlignmentQualityAnnot()
1867 || annotation == av.getAlignmentConservationAnnotation()
1868 || annotation == av.getAlignmentConsensusAnnotation()
1869 || annotation.autoCalculated)
1871 // new way of indicating autocalculated annotation -
1872 an.setAutoCalculated(annotation.autoCalculated);
1874 if (annotation.hasScore())
1876 an.setScore(annotation.getScore());
1879 if (annotation.getCalcId() != null)
1881 calcIdSet.add(annotation.getCalcId());
1882 an.setCalcId(annotation.getCalcId());
1884 if (annotation.hasProperties())
1886 for (String pr : annotation.getProperties())
1888 Property prop = new Property();
1890 prop.setValue(annotation.getProperty(pr));
1891 an.addProperty(prop);
1895 AnnotationElement ae;
1896 if (annotation.annotations != null)
1898 an.setScoreOnly(false);
1899 for (int a = 0; a < annotation.annotations.length; a++)
1901 if ((annotation == null) || (annotation.annotations[a] == null))
1906 ae = new AnnotationElement();
1907 if (annotation.annotations[a].description != null)
1909 ae.setDescription(annotation.annotations[a].description);
1911 if (annotation.annotations[a].displayCharacter != null)
1913 ae.setDisplayCharacter(
1914 annotation.annotations[a].displayCharacter);
1917 if (!Float.isNaN(annotation.annotations[a].value))
1919 ae.setValue(annotation.annotations[a].value);
1923 if (annotation.annotations[a].secondaryStructure > ' ')
1925 ae.setSecondaryStructure(
1926 annotation.annotations[a].secondaryStructure + "");
1929 if (annotation.annotations[a].colour != null
1930 && annotation.annotations[a].colour != java.awt.Color.black)
1932 ae.setColour(annotation.annotations[a].colour.getRGB());
1935 an.addAnnotationElement(ae);
1936 if (annotation.autoCalculated)
1938 // only write one non-null entry into the annotation row -
1939 // sufficient to get the visualization attributes necessary to
1947 an.setScoreOnly(true);
1949 if (!storeDS || (storeDS && !annotation.autoCalculated))
1951 // skip autocalculated annotation - these are only provided for
1953 vamsasSet.addAnnotation(an);
1959 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1961 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1962 if (settings != null)
1964 CalcIdParam vCalcIdParam = new CalcIdParam();
1965 vCalcIdParam.setCalcId(calcId);
1966 vCalcIdParam.addServiceURL(settings.getServiceURI());
1967 // generic URI allowing a third party to resolve another instance of the
1968 // service used for this calculation
1969 for (String urls : settings.getServiceURLs())
1971 vCalcIdParam.addServiceURL(urls);
1973 vCalcIdParam.setVersion("1.0");
1974 if (settings.getPreset() != null)
1976 WsParamSetI setting = settings.getPreset();
1977 vCalcIdParam.setName(setting.getName());
1978 vCalcIdParam.setDescription(setting.getDescription());
1982 vCalcIdParam.setName("");
1983 vCalcIdParam.setDescription("Last used parameters");
1985 // need to be able to recover 1) settings 2) user-defined presets or
1986 // recreate settings from preset 3) predefined settings provided by
1987 // service - or settings that can be transferred (or discarded)
1988 vCalcIdParam.setParameters(
1989 settings.getWsParamFile().replace("\n", "|\\n|"));
1990 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1991 // todo - decide if updateImmediately is needed for any projects.
1993 return vCalcIdParam;
1998 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2001 if (calcIdParam.getVersion().equals("1.0"))
2003 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2004 .getPreferredServiceFor(calcIdParam.getServiceURL());
2005 if (service != null)
2007 WsParamSetI parmSet = null;
2010 parmSet = service.getParamStore().parseServiceParameterFile(
2011 calcIdParam.getName(), calcIdParam.getDescription(),
2012 calcIdParam.getServiceURL(),
2013 calcIdParam.getParameters().replace("|\\n|", "\n"));
2014 } catch (IOException x)
2016 warn("Couldn't parse parameter data for "
2017 + calcIdParam.getCalcId(), x);
2020 List<ArgumentI> argList = null;
2021 if (calcIdParam.getName().length() > 0)
2023 parmSet = service.getParamStore()
2024 .getPreset(calcIdParam.getName());
2025 if (parmSet != null)
2027 // TODO : check we have a good match with settings in AACon -
2028 // otherwise we'll need to create a new preset
2033 argList = parmSet.getArguments();
2036 AAConSettings settings = new AAConSettings(
2037 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2038 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2039 calcIdParam.isNeedsUpdate());
2044 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2048 throw new Error(MessageManager.formatMessage(
2049 "error.unsupported_version_calcIdparam", new Object[]
2050 { calcIdParam.toString() }));
2054 * External mapping between jalview objects and objects yielding a valid and
2055 * unique object ID string. This is null for normal Jalview project IO, but
2056 * non-null when a jalview project is being read or written as part of a
2059 IdentityHashMap jv2vobj = null;
2062 * Construct a unique ID for jvobj using either existing bindings or if none
2063 * exist, the result of the hashcode call for the object.
2066 * jalview data object
2067 * @return unique ID for referring to jvobj
2069 private String makeHashCode(Object jvobj, String altCode)
2071 if (jv2vobj != null)
2073 Object id = jv2vobj.get(jvobj);
2076 return id.toString();
2078 // check string ID mappings
2079 if (jvids2vobj != null && jvobj instanceof String)
2081 id = jvids2vobj.get(jvobj);
2085 return id.toString();
2087 // give up and warn that something has gone wrong
2088 warn("Cannot find ID for object in external mapping : " + jvobj);
2094 * return local jalview object mapped to ID, if it exists
2098 * @return null or object bound to idcode
2100 private Object retrieveExistingObj(String idcode)
2102 if (idcode != null && vobj2jv != null)
2104 return vobj2jv.get(idcode);
2110 * binding from ID strings from external mapping table to jalview data model
2113 private Hashtable vobj2jv;
2115 private Sequence createVamsasSequence(String id, SequenceI jds)
2117 return createVamsasSequence(true, id, jds, null);
2120 private Sequence createVamsasSequence(boolean recurse, String id,
2121 SequenceI jds, SequenceI parentseq)
2123 Sequence vamsasSeq = new Sequence();
2124 vamsasSeq.setId(id);
2125 vamsasSeq.setName(jds.getName());
2126 vamsasSeq.setSequence(jds.getSequenceAsString());
2127 vamsasSeq.setDescription(jds.getDescription());
2128 jalview.datamodel.DBRefEntry[] dbrefs = null;
2129 if (jds.getDatasetSequence() != null)
2131 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2135 // seqId==dsseqid so we can tell which sequences really are
2136 // dataset sequences only
2137 vamsasSeq.setDsseqid(id);
2138 dbrefs = jds.getDBRefs();
2139 if (parentseq == null)
2146 for (int d = 0; d < dbrefs.length; d++)
2148 DBRef dbref = new DBRef();
2149 dbref.setSource(dbrefs[d].getSource());
2150 dbref.setVersion(dbrefs[d].getVersion());
2151 dbref.setAccessionId(dbrefs[d].getAccessionId());
2152 if (dbrefs[d].hasMap())
2154 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2156 dbref.setMapping(mp);
2158 vamsasSeq.addDBRef(dbref);
2164 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2165 SequenceI parentseq, SequenceI jds, boolean recurse)
2168 if (jmp.getMap() != null)
2172 jalview.util.MapList mlst = jmp.getMap();
2173 List<int[]> r = mlst.getFromRanges();
2174 for (int[] range : r)
2176 MapListFrom mfrom = new MapListFrom();
2177 mfrom.setStart(range[0]);
2178 mfrom.setEnd(range[1]);
2179 mp.addMapListFrom(mfrom);
2181 r = mlst.getToRanges();
2182 for (int[] range : r)
2184 MapListTo mto = new MapListTo();
2185 mto.setStart(range[0]);
2186 mto.setEnd(range[1]);
2187 mp.addMapListTo(mto);
2189 mp.setMapFromUnit(mlst.getFromRatio());
2190 mp.setMapToUnit(mlst.getToRatio());
2191 if (jmp.getTo() != null)
2193 MappingChoice mpc = new MappingChoice();
2195 // check/create ID for the sequence referenced by getTo()
2198 SequenceI ps = null;
2199 if (parentseq != jmp.getTo()
2200 && parentseq.getDatasetSequence() != jmp.getTo())
2202 // chaining dbref rather than a handshaking one
2203 jmpid = seqHash(ps = jmp.getTo());
2207 jmpid = seqHash(ps = parentseq);
2209 mpc.setDseqFor(jmpid);
2210 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2212 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2213 seqRefIds.put(mpc.getDseqFor(), ps);
2217 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2220 mp.setMappingChoice(mpc);
2226 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2227 List<UserColourScheme> userColours, JalviewModelSequence jms)
2230 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2231 boolean newucs = false;
2232 if (!userColours.contains(ucs))
2234 userColours.add(ucs);
2237 id = "ucs" + userColours.indexOf(ucs);
2240 // actually create the scheme's entry in the XML model
2241 java.awt.Color[] colours = ucs.getColours();
2242 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2243 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2245 for (int i = 0; i < colours.length; i++)
2247 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2248 col.setName(ResidueProperties.aa[i]);
2249 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2250 jbucs.addColour(col);
2252 if (ucs.getLowerCaseColours() != null)
2254 colours = ucs.getLowerCaseColours();
2255 for (int i = 0; i < colours.length; i++)
2257 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2258 col.setName(ResidueProperties.aa[i].toLowerCase());
2259 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2260 jbucs.addColour(col);
2265 uc.setUserColourScheme(jbucs);
2266 jms.addUserColours(uc);
2272 jalview.schemes.UserColourScheme getUserColourScheme(
2273 JalviewModelSequence jms, String id)
2275 UserColours[] uc = jms.getUserColours();
2276 UserColours colours = null;
2278 for (int i = 0; i < uc.length; i++)
2280 if (uc[i].getId().equals(id))
2288 java.awt.Color[] newColours = new java.awt.Color[24];
2290 for (int i = 0; i < 24; i++)
2292 newColours[i] = new java.awt.Color(Integer.parseInt(
2293 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2296 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2299 if (colours.getUserColourScheme().getColourCount() > 24)
2301 newColours = new java.awt.Color[23];
2302 for (int i = 0; i < 23; i++)
2304 newColours[i] = new java.awt.Color(Integer.parseInt(
2305 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2308 ucs.setLowerCaseColours(newColours);
2315 * contains last error message (if any) encountered by XML loader.
2317 String errorMessage = null;
2320 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2321 * exceptions are raised during project XML parsing
2323 public boolean attemptversion1parse = true;
2326 * Load a jalview project archive from a jar file
2329 * - HTTP URL or filename
2331 public AlignFrame loadJalviewAlign(final String file)
2334 jalview.gui.AlignFrame af = null;
2338 // create list to store references for any new Jmol viewers created
2339 newStructureViewers = new Vector<>();
2340 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2341 // Workaround is to make sure caller implements the JarInputStreamProvider
2343 // so we can re-open the jar input stream for each entry.
2345 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2346 af = loadJalviewAlign(jprovider);
2347 af.setMenusForViewport();
2349 } catch (MalformedURLException e)
2351 errorMessage = "Invalid URL format for '" + file + "'";
2357 SwingUtilities.invokeAndWait(new Runnable()
2362 setLoadingFinishedForNewStructureViewers();
2365 } catch (Exception x)
2367 System.err.println("Error loading alignment: " + x.getMessage());
2373 private jarInputStreamProvider createjarInputStreamProvider(
2374 final String file) throws MalformedURLException
2377 errorMessage = null;
2378 uniqueSetSuffix = null;
2380 viewportsAdded.clear();
2381 frefedSequence = null;
2383 if (file.startsWith("http://"))
2385 url = new URL(file);
2387 final URL _url = url;
2388 return new jarInputStreamProvider()
2392 public JarInputStream getJarInputStream() throws IOException
2396 return new JarInputStream(_url.openStream());
2400 return new JarInputStream(new FileInputStream(file));
2405 public String getFilename()
2413 * Recover jalview session from a jalview project archive. Caller may
2414 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2415 * themselves. Any null fields will be initialised with default values,
2416 * non-null fields are left alone.
2421 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2423 errorMessage = null;
2424 if (uniqueSetSuffix == null)
2426 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2428 if (seqRefIds == null)
2432 AlignFrame af = null, _af = null;
2433 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2434 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2435 final String file = jprovider.getFilename();
2438 JarInputStream jin = null;
2439 JarEntry jarentry = null;
2444 jin = jprovider.getJarInputStream();
2445 for (int i = 0; i < entryCount; i++)
2447 jarentry = jin.getNextJarEntry();
2450 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2452 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2453 JalviewModel object = new JalviewModel();
2455 Unmarshaller unmar = new Unmarshaller(object);
2456 unmar.setValidation(false);
2457 object = (JalviewModel) unmar.unmarshal(in);
2458 if (true) // !skipViewport(object))
2460 _af = loadFromObject(object, file, true, jprovider);
2461 if (_af != null && object.getJalviewModelSequence()
2462 .getViewportCount() > 0)
2466 // store a reference to the first view
2469 if (_af.viewport.isGatherViewsHere())
2471 // if this is a gathered view, keep its reference since
2472 // after gathering views, only this frame will remain
2474 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2476 // Save dataset to register mappings once all resolved
2477 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2478 af.viewport.getAlignment().getDataset());
2483 else if (jarentry != null)
2485 // Some other file here.
2488 } while (jarentry != null);
2489 resolveFrefedSequences();
2490 } catch (IOException ex)
2492 ex.printStackTrace();
2493 errorMessage = "Couldn't locate Jalview XML file : " + file;
2495 "Exception whilst loading jalview XML file : " + ex + "\n");
2496 } catch (Exception ex)
2498 System.err.println("Parsing as Jalview Version 2 file failed.");
2499 ex.printStackTrace(System.err);
2500 if (attemptversion1parse)
2502 // Is Version 1 Jar file?
2505 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2506 } catch (Exception ex2)
2508 System.err.println("Exception whilst loading as jalviewXMLV1:");
2509 ex2.printStackTrace();
2513 if (Desktop.instance != null)
2515 Desktop.instance.stopLoading();
2519 System.out.println("Successfully loaded archive file");
2522 ex.printStackTrace();
2525 "Exception whilst loading jalview XML file : " + ex + "\n");
2526 } catch (OutOfMemoryError e)
2528 // Don't use the OOM Window here
2529 errorMessage = "Out of memory loading jalview XML file";
2530 System.err.println("Out of memory whilst loading jalview XML file");
2531 e.printStackTrace();
2535 * Regather multiple views (with the same sequence set id) to the frame (if
2536 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2537 * views instead of separate frames. Note this doesn't restore a state where
2538 * some expanded views in turn have tabbed views - the last "first tab" read
2539 * in will play the role of gatherer for all.
2541 for (AlignFrame fr : gatherToThisFrame.values())
2543 Desktop.instance.gatherViews(fr);
2546 restoreSplitFrames();
2547 for (AlignmentI ds : importedDatasets.keySet())
2549 if (ds.getCodonFrames() != null)
2551 StructureSelectionManager
2552 .getStructureSelectionManager(Desktop.instance)
2553 .registerMappings(ds.getCodonFrames());
2556 if (errorMessage != null)
2561 if (Desktop.instance != null)
2563 Desktop.instance.stopLoading();
2570 * Try to reconstruct and display SplitFrame windows, where each contains
2571 * complementary dna and protein alignments. Done by pairing up AlignFrame
2572 * objects (created earlier) which have complementary viewport ids associated.
2574 protected void restoreSplitFrames()
2576 List<SplitFrame> gatherTo = new ArrayList<>();
2577 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2578 Map<String, AlignFrame> dna = new HashMap<>();
2581 * Identify the DNA alignments
2583 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2586 AlignFrame af = candidate.getValue();
2587 if (af.getViewport().getAlignment().isNucleotide())
2589 dna.put(candidate.getKey().getId(), af);
2594 * Try to match up the protein complements
2596 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2599 AlignFrame af = candidate.getValue();
2600 if (!af.getViewport().getAlignment().isNucleotide())
2602 String complementId = candidate.getKey().getComplementId();
2603 // only non-null complements should be in the Map
2604 if (complementId != null && dna.containsKey(complementId))
2606 final AlignFrame dnaFrame = dna.get(complementId);
2607 SplitFrame sf = createSplitFrame(dnaFrame, af);
2608 addedToSplitFrames.add(dnaFrame);
2609 addedToSplitFrames.add(af);
2610 dnaFrame.setMenusForViewport();
2611 af.setMenusForViewport();
2612 if (af.viewport.isGatherViewsHere())
2621 * Open any that we failed to pair up (which shouldn't happen!) as
2622 * standalone AlignFrame's.
2624 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2627 AlignFrame af = candidate.getValue();
2628 if (!addedToSplitFrames.contains(af))
2630 Viewport view = candidate.getKey();
2631 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2633 af.setMenusForViewport();
2634 System.err.println("Failed to restore view " + view.getTitle()
2635 + " to split frame");
2640 * Gather back into tabbed views as flagged.
2642 for (SplitFrame sf : gatherTo)
2644 Desktop.instance.gatherViews(sf);
2647 splitFrameCandidates.clear();
2651 * Construct and display one SplitFrame holding DNA and protein alignments.
2654 * @param proteinFrame
2657 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2658 AlignFrame proteinFrame)
2660 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2661 String title = MessageManager.getString("label.linked_view_title");
2662 int width = (int) dnaFrame.getBounds().getWidth();
2663 int height = (int) (dnaFrame.getBounds().getHeight()
2664 + proteinFrame.getBounds().getHeight() + 50);
2667 * SplitFrame location is saved to both enclosed frames
2669 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2670 Desktop.addInternalFrame(splitFrame, title, width, height);
2673 * And compute cDNA consensus (couldn't do earlier with consensus as
2674 * mappings were not yet present)
2676 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2682 * check errorMessage for a valid error message and raise an error box in the
2683 * GUI or write the current errorMessage to stderr and then clear the error
2686 protected void reportErrors()
2688 reportErrors(false);
2691 protected void reportErrors(final boolean saving)
2693 if (errorMessage != null)
2695 final String finalErrorMessage = errorMessage;
2698 javax.swing.SwingUtilities.invokeLater(new Runnable()
2703 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2705 "Error " + (saving ? "saving" : "loading")
2707 JvOptionPane.WARNING_MESSAGE);
2713 System.err.println("Problem loading Jalview file: " + errorMessage);
2716 errorMessage = null;
2719 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2722 * when set, local views will be updated from view stored in JalviewXML
2723 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2724 * sync if this is set to true.
2726 private final boolean updateLocalViews = false;
2729 * Returns the path to a temporary file holding the PDB file for the given PDB
2730 * id. The first time of asking, searches for a file of that name in the
2731 * Jalview project jar, and copies it to a new temporary file. Any repeat
2732 * requests just return the path to the file previously created.
2738 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2741 if (alreadyLoadedPDB.containsKey(pdbId))
2743 return alreadyLoadedPDB.get(pdbId).toString();
2746 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2748 if (tempFile != null)
2750 alreadyLoadedPDB.put(pdbId, tempFile);
2756 * Copies the jar entry of given name to a new temporary file and returns the
2757 * path to the file, or null if the entry is not found.
2760 * @param jarEntryName
2762 * a prefix for the temporary file name, must be at least three
2765 * null or original file - so new file can be given the same suffix
2769 protected String copyJarEntry(jarInputStreamProvider jprovider,
2770 String jarEntryName, String prefix, String origFile)
2772 BufferedReader in = null;
2773 PrintWriter out = null;
2774 String suffix = ".tmp";
2775 if (origFile == null)
2777 origFile = jarEntryName;
2779 int sfpos = origFile.lastIndexOf(".");
2780 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2782 suffix = "." + origFile.substring(sfpos + 1);
2786 JarInputStream jin = jprovider.getJarInputStream();
2788 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2789 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2790 * FileInputStream(jprovider)); }
2793 JarEntry entry = null;
2796 entry = jin.getNextJarEntry();
2797 } while (entry != null && !entry.getName().equals(jarEntryName));
2800 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2801 File outFile = File.createTempFile(prefix, suffix);
2802 outFile.deleteOnExit();
2803 out = new PrintWriter(new FileOutputStream(outFile));
2806 while ((data = in.readLine()) != null)
2811 String t = outFile.getAbsolutePath();
2816 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2818 } catch (Exception ex)
2820 ex.printStackTrace();
2828 } catch (IOException e)
2842 private class JvAnnotRow
2844 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2851 * persisted version of annotation row from which to take vis properties
2853 public jalview.datamodel.AlignmentAnnotation template;
2856 * original position of the annotation row in the alignment
2862 * Load alignment frame from jalview XML DOM object
2867 * filename source string
2868 * @param loadTreesAndStructures
2869 * when false only create Viewport
2871 * data source provider
2872 * @return alignment frame created from view stored in DOM
2874 AlignFrame loadFromObject(JalviewModel object, String file,
2875 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2877 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2878 Sequence[] vamsasSeq = vamsasSet.getSequence();
2880 JalviewModelSequence jms = object.getJalviewModelSequence();
2882 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2885 // ////////////////////////////////
2888 List<SequenceI> hiddenSeqs = null;
2890 List<SequenceI> tmpseqs = new ArrayList<>();
2892 boolean multipleView = false;
2893 SequenceI referenceseqForView = null;
2894 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2895 int vi = 0; // counter in vamsasSeq array
2896 for (int i = 0; i < jseqs.length; i++)
2898 String seqId = jseqs[i].getId();
2900 SequenceI tmpSeq = seqRefIds.get(seqId);
2903 if (!incompleteSeqs.containsKey(seqId))
2905 // may not need this check, but keep it for at least 2.9,1 release
2906 if (tmpSeq.getStart() != jseqs[i].getStart()
2907 || tmpSeq.getEnd() != jseqs[i].getEnd())
2910 "Warning JAL-2154 regression: updating start/end for sequence "
2911 + tmpSeq.toString() + " to " + jseqs[i]);
2916 incompleteSeqs.remove(seqId);
2918 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2920 // most likely we are reading a dataset XML document so
2921 // update from vamsasSeq section of XML for this sequence
2922 tmpSeq.setName(vamsasSeq[vi].getName());
2923 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2924 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2929 // reading multiple views, so vamsasSeq set is a subset of JSeq
2930 multipleView = true;
2932 tmpSeq.setStart(jseqs[i].getStart());
2933 tmpSeq.setEnd(jseqs[i].getEnd());
2934 tmpseqs.add(tmpSeq);
2938 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2939 vamsasSeq[vi].getSequence());
2940 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2941 tmpSeq.setStart(jseqs[i].getStart());
2942 tmpSeq.setEnd(jseqs[i].getEnd());
2943 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2944 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2945 tmpseqs.add(tmpSeq);
2949 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2951 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2954 if (jseqs[i].getHidden())
2956 if (hiddenSeqs == null)
2958 hiddenSeqs = new ArrayList<>();
2961 hiddenSeqs.add(tmpSeq);
2966 // Create the alignment object from the sequence set
2967 // ///////////////////////////////
2968 SequenceI[] orderedSeqs = tmpseqs
2969 .toArray(new SequenceI[tmpseqs.size()]);
2971 AlignmentI al = null;
2972 // so we must create or recover the dataset alignment before going further
2973 // ///////////////////////////////
2974 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2976 // older jalview projects do not have a dataset - so creat alignment and
2978 al = new Alignment(orderedSeqs);
2979 al.setDataset(null);
2983 boolean isdsal = object.getJalviewModelSequence()
2984 .getViewportCount() == 0;
2987 // we are importing a dataset record, so
2988 // recover reference to an alignment already materialsed as dataset
2989 al = getDatasetFor(vamsasSet.getDatasetId());
2993 // materialse the alignment
2994 al = new Alignment(orderedSeqs);
2998 addDatasetRef(vamsasSet.getDatasetId(), al);
3001 // finally, verify all data in vamsasSet is actually present in al
3002 // passing on flag indicating if it is actually a stored dataset
3003 recoverDatasetFor(vamsasSet, al, isdsal);
3006 if (referenceseqForView != null)
3008 al.setSeqrep(referenceseqForView);
3010 // / Add the alignment properties
3011 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3013 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3014 al.setProperty(ssp.getKey(), ssp.getValue());
3017 // ///////////////////////////////
3019 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3022 // load sequence features, database references and any associated PDB
3023 // structures for the alignment
3025 // prior to 2.10, this part would only be executed the first time a
3026 // sequence was encountered, but not afterwards.
3027 // now, for 2.10 projects, this is also done if the xml doc includes
3028 // dataset sequences not actually present in any particular view.
3030 for (int i = 0; i < vamsasSeq.length; i++)
3032 if (jseqs[i].getFeaturesCount() > 0)
3034 Features[] features = jseqs[i].getFeatures();
3035 for (int f = 0; f < features.length; f++)
3037 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3038 features[f].getDescription(), features[f].getBegin(),
3039 features[f].getEnd(), features[f].getScore(),
3040 features[f].getFeatureGroup());
3041 sf.setStatus(features[f].getStatus());
3044 * load any feature attributes - include map-valued attributes
3046 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3047 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3049 OtherData keyValue = features[f].getOtherData(od);
3050 String attributeName = keyValue.getKey();
3051 String attributeValue = keyValue.getValue();
3052 if (attributeName.startsWith("LINK"))
3054 sf.addLink(attributeValue);
3058 String subAttribute = keyValue.getKey2();
3059 if (subAttribute == null)
3061 // simple string-valued attribute
3062 sf.setValue(attributeName, attributeValue);
3066 // attribute 'key' has sub-attribute 'key2'
3067 if (!mapAttributes.containsKey(attributeName))
3069 mapAttributes.put(attributeName, new HashMap<>());
3071 mapAttributes.get(attributeName).put(subAttribute,
3076 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3079 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3082 // adds feature to datasequence's feature set (since Jalview 2.10)
3083 al.getSequenceAt(i).addSequenceFeature(sf);
3086 if (vamsasSeq[i].getDBRefCount() > 0)
3088 // adds dbrefs to datasequence's set (since Jalview 2.10)
3090 al.getSequenceAt(i).getDatasetSequence() == null
3091 ? al.getSequenceAt(i)
3092 : al.getSequenceAt(i).getDatasetSequence(),
3095 if (jseqs[i].getPdbidsCount() > 0)
3097 Pdbids[] ids = jseqs[i].getPdbids();
3098 for (int p = 0; p < ids.length; p++)
3100 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3101 entry.setId(ids[p].getId());
3102 if (ids[p].getType() != null)
3104 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3106 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3110 entry.setType(PDBEntry.Type.FILE);
3113 // jprovider is null when executing 'New View'
3114 if (ids[p].getFile() != null && jprovider != null)
3116 if (!pdbloaded.containsKey(ids[p].getFile()))
3118 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3123 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3126 if (ids[p].getPdbentryItem() != null)
3128 for (PdbentryItem item : ids[p].getPdbentryItem())
3130 for (Property pr : item.getProperty())
3132 entry.setProperty(pr.getName(), pr.getValue());
3136 StructureSelectionManager
3137 .getStructureSelectionManager(Desktop.instance)
3138 .registerPDBEntry(entry);
3139 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3140 if (al.getSequenceAt(i).getDatasetSequence() != null)
3142 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3146 al.getSequenceAt(i).addPDBId(entry);
3151 } // end !multipleview
3153 // ///////////////////////////////
3154 // LOAD SEQUENCE MAPPINGS
3156 if (vamsasSet.getAlcodonFrameCount() > 0)
3158 // TODO Potentially this should only be done once for all views of an
3160 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3161 for (int i = 0; i < alc.length; i++)
3163 AlignedCodonFrame cf = new AlignedCodonFrame();
3164 if (alc[i].getAlcodMapCount() > 0)
3166 AlcodMap[] maps = alc[i].getAlcodMap();
3167 for (int m = 0; m < maps.length; m++)
3169 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3171 jalview.datamodel.Mapping mapping = null;
3172 // attach to dna sequence reference.
3173 if (maps[m].getMapping() != null)
3175 mapping = addMapping(maps[m].getMapping());
3176 if (dnaseq != null && mapping.getTo() != null)
3178 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3184 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3188 al.addCodonFrame(cf);
3193 // ////////////////////////////////
3195 List<JvAnnotRow> autoAlan = new ArrayList<>();
3198 * store any annotations which forward reference a group's ID
3200 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3202 if (vamsasSet.getAnnotationCount() > 0)
3204 Annotation[] an = vamsasSet.getAnnotation();
3206 for (int i = 0; i < an.length; i++)
3208 Annotation annotation = an[i];
3211 * test if annotation is automatically calculated for this view only
3213 boolean autoForView = false;
3214 if (annotation.getLabel().equals("Quality")
3215 || annotation.getLabel().equals("Conservation")
3216 || annotation.getLabel().equals("Consensus"))
3218 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3220 if (!annotation.hasAutoCalculated())
3222 annotation.setAutoCalculated(true);
3225 if (autoForView || (annotation.hasAutoCalculated()
3226 && annotation.isAutoCalculated()))
3228 // remove ID - we don't recover annotation from other views for
3229 // view-specific annotation
3230 annotation.setId(null);
3233 // set visiblity for other annotation in this view
3234 String annotationId = annotation.getId();
3235 if (annotationId != null && annotationIds.containsKey(annotationId))
3237 AlignmentAnnotation jda = annotationIds.get(annotationId);
3238 // in principle Visible should always be true for annotation displayed
3239 // in multiple views
3240 if (annotation.hasVisible())
3242 jda.visible = annotation.getVisible();
3245 al.addAnnotation(jda);
3249 // Construct new annotation from model.
3250 AnnotationElement[] ae = annotation.getAnnotationElement();
3251 jalview.datamodel.Annotation[] anot = null;
3252 java.awt.Color firstColour = null;
3254 if (!annotation.getScoreOnly())
3256 anot = new jalview.datamodel.Annotation[al.getWidth()];
3257 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3259 anpos = ae[aa].getPosition();
3261 if (anpos >= anot.length)
3266 anot[anpos] = new jalview.datamodel.Annotation(
3268 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3269 (ae[aa].getSecondaryStructure() == null
3270 || ae[aa].getSecondaryStructure().length() == 0)
3272 : ae[aa].getSecondaryStructure()
3277 // JBPNote: Consider verifying dataflow for IO of secondary
3278 // structure annotation read from Stockholm files
3279 // this was added to try to ensure that
3280 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3282 // anot[ae[aa].getPosition()].displayCharacter = "";
3284 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3285 if (firstColour == null)
3287 firstColour = anot[anpos].colour;
3291 jalview.datamodel.AlignmentAnnotation jaa = null;
3293 if (annotation.getGraph())
3295 float llim = 0, hlim = 0;
3296 // if (autoForView || an[i].isAutoCalculated()) {
3299 jaa = new jalview.datamodel.AlignmentAnnotation(
3300 annotation.getLabel(), annotation.getDescription(), anot,
3301 llim, hlim, annotation.getGraphType());
3303 jaa.graphGroup = annotation.getGraphGroup();
3304 jaa._linecolour = firstColour;
3305 if (annotation.getThresholdLine() != null)
3307 jaa.setThreshold(new jalview.datamodel.GraphLine(
3308 annotation.getThresholdLine().getValue(),
3309 annotation.getThresholdLine().getLabel(),
3311 annotation.getThresholdLine().getColour())));
3314 if (autoForView || annotation.isAutoCalculated())
3316 // Hardwire the symbol display line to ensure that labels for
3317 // histograms are displayed
3323 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3324 an[i].getDescription(), anot);
3325 jaa._linecolour = firstColour;
3327 // register new annotation
3328 if (an[i].getId() != null)
3330 annotationIds.put(an[i].getId(), jaa);
3331 jaa.annotationId = an[i].getId();
3333 // recover sequence association
3334 String sequenceRef = an[i].getSequenceRef();
3335 if (sequenceRef != null)
3337 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3338 SequenceI sequence = seqRefIds.get(sequenceRef);
3339 if (sequence == null)
3341 // in pre-2.9 projects sequence ref is to sequence name
3342 sequence = al.findName(sequenceRef);
3344 if (sequence != null)
3346 jaa.createSequenceMapping(sequence, 1, true);
3347 sequence.addAlignmentAnnotation(jaa);
3350 // and make a note of any group association
3351 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3353 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3354 .get(an[i].getGroupRef());
3357 aal = new ArrayList<>();
3358 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3363 if (an[i].hasScore())
3365 jaa.setScore(an[i].getScore());
3367 if (an[i].hasVisible())
3369 jaa.visible = an[i].getVisible();
3372 if (an[i].hasCentreColLabels())
3374 jaa.centreColLabels = an[i].getCentreColLabels();
3377 if (an[i].hasScaleColLabels())
3379 jaa.scaleColLabel = an[i].getScaleColLabels();
3381 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3383 // newer files have an 'autoCalculated' flag and store calculation
3384 // state in viewport properties
3385 jaa.autoCalculated = true; // means annotation will be marked for
3386 // update at end of load.
3388 if (an[i].hasGraphHeight())
3390 jaa.graphHeight = an[i].getGraphHeight();
3392 if (an[i].hasBelowAlignment())
3394 jaa.belowAlignment = an[i].isBelowAlignment();
3396 jaa.setCalcId(an[i].getCalcId());
3397 if (an[i].getPropertyCount() > 0)
3399 for (jalview.schemabinding.version2.Property prop : an[i]
3402 jaa.setProperty(prop.getName(), prop.getValue());
3405 if (jaa.autoCalculated)
3407 autoAlan.add(new JvAnnotRow(i, jaa));
3410 // if (!autoForView)
3412 // add autocalculated group annotation and any user created annotation
3414 al.addAnnotation(jaa);
3418 // ///////////////////////
3420 // Create alignment markup and styles for this view
3421 if (jms.getJGroupCount() > 0)
3423 JGroup[] groups = jms.getJGroup();
3424 boolean addAnnotSchemeGroup = false;
3425 for (int i = 0; i < groups.length; i++)
3427 JGroup jGroup = groups[i];
3428 ColourSchemeI cs = null;
3429 if (jGroup.getColour() != null)
3431 if (jGroup.getColour().startsWith("ucs"))
3433 cs = getUserColourScheme(jms, jGroup.getColour());
3435 else if (jGroup.getColour().equals("AnnotationColourGradient")
3436 && jGroup.getAnnotationColours() != null)
3438 addAnnotSchemeGroup = true;
3442 cs = ColourSchemeProperty.getColourScheme(al,
3443 jGroup.getColour());
3446 int pidThreshold = jGroup.getPidThreshold();
3448 Vector<SequenceI> seqs = new Vector<>();
3450 for (int s = 0; s < jGroup.getSeqCount(); s++)
3452 String seqId = jGroup.getSeq(s) + "";
3453 SequenceI ts = seqRefIds.get(seqId);
3457 seqs.addElement(ts);
3461 if (seqs.size() < 1)
3466 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3467 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3468 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3469 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3470 sg.getGroupColourScheme()
3471 .setConservationInc(jGroup.getConsThreshold());
3472 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3474 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3475 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3476 sg.setShowNonconserved(
3477 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3479 sg.thresholdTextColour = jGroup.getTextColThreshold();
3480 if (jGroup.hasShowConsensusHistogram())
3482 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3485 if (jGroup.hasShowSequenceLogo())
3487 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3489 if (jGroup.hasNormaliseSequenceLogo())
3491 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3493 if (jGroup.hasIgnoreGapsinConsensus())
3495 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3497 if (jGroup.getConsThreshold() != 0)
3499 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3502 c.verdict(false, 25);
3503 sg.cs.setConservation(c);
3506 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3508 // re-instate unique group/annotation row reference
3509 List<AlignmentAnnotation> jaal = groupAnnotRefs
3510 .get(jGroup.getId());
3513 for (AlignmentAnnotation jaa : jaal)
3516 if (jaa.autoCalculated)
3518 // match up and try to set group autocalc alignment row for this
3520 if (jaa.label.startsWith("Consensus for "))
3522 sg.setConsensus(jaa);
3524 // match up and try to set group autocalc alignment row for this
3526 if (jaa.label.startsWith("Conservation for "))
3528 sg.setConservationRow(jaa);
3535 if (addAnnotSchemeGroup)
3537 // reconstruct the annotation colourscheme
3538 sg.setColourScheme(constructAnnotationColour(
3539 jGroup.getAnnotationColours(), null, al, jms, false));
3545 // only dataset in this model, so just return.
3548 // ///////////////////////////////
3551 // If we just load in the same jar file again, the sequenceSetId
3552 // will be the same, and we end up with multiple references
3553 // to the same sequenceSet. We must modify this id on load
3554 // so that each load of the file gives a unique id
3555 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3556 String viewId = (view.getId() == null ? null
3557 : view.getId() + uniqueSetSuffix);
3558 AlignFrame af = null;
3559 AlignViewport av = null;
3560 // now check to see if we really need to create a new viewport.
3561 if (multipleView && viewportsAdded.size() == 0)
3563 // We recovered an alignment for which a viewport already exists.
3564 // TODO: fix up any settings necessary for overlaying stored state onto
3565 // state recovered from another document. (may not be necessary).
3566 // we may need a binding from a viewport in memory to one recovered from
3568 // and then recover its containing af to allow the settings to be applied.
3569 // TODO: fix for vamsas demo
3571 "About to recover a viewport for existing alignment: Sequence set ID is "
3573 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3574 if (seqsetobj != null)
3576 if (seqsetobj instanceof String)
3578 uniqueSeqSetId = (String) seqsetobj;
3580 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3586 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3592 * indicate that annotation colours are applied across all groups (pre
3593 * Jalview 2.8.1 behaviour)
3595 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3596 object.getVersion());
3598 AlignmentPanel ap = null;
3599 boolean isnewview = true;
3602 // Check to see if this alignment already has a view id == viewId
3603 jalview.gui.AlignmentPanel views[] = Desktop
3604 .getAlignmentPanels(uniqueSeqSetId);
3605 if (views != null && views.length > 0)
3607 for (int v = 0; v < views.length; v++)
3609 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3611 // recover the existing alignpanel, alignframe, viewport
3612 af = views[v].alignFrame;
3615 // TODO: could even skip resetting view settings if we don't want to
3616 // change the local settings from other jalview processes
3625 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3626 uniqueSeqSetId, viewId, autoAlan);
3632 * Load any trees, PDB structures and viewers
3634 * Not done if flag is false (when this method is used for New View)
3636 if (loadTreesAndStructures)
3638 loadTrees(jms, view, af, av, ap);
3639 loadPDBStructures(jprovider, jseqs, af, ap);
3640 loadRnaViewers(jprovider, jseqs, ap);
3642 // and finally return.
3647 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3648 * panel is restored from separate jar entries, two (gapped and trimmed) per
3649 * sequence and secondary structure.
3651 * Currently each viewer shows just one sequence and structure (gapped and
3652 * trimmed), however this method is designed to support multiple sequences or
3653 * structures in viewers if wanted in future.
3659 private void loadRnaViewers(jarInputStreamProvider jprovider,
3660 JSeq[] jseqs, AlignmentPanel ap)
3663 * scan the sequences for references to viewers; create each one the first
3664 * time it is referenced, add Rna models to existing viewers
3666 for (JSeq jseq : jseqs)
3668 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3670 RnaViewer viewer = jseq.getRnaViewer(i);
3671 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3674 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3676 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3677 SequenceI seq = seqRefIds.get(jseq.getId());
3678 AlignmentAnnotation ann = this.annotationIds
3679 .get(ss.getAnnotationId());
3682 * add the structure to the Varna display (with session state copied
3683 * from the jar to a temporary file)
3685 boolean gapped = ss.isGapped();
3686 String rnaTitle = ss.getTitle();
3687 String sessionState = ss.getViewerState();
3688 String tempStateFile = copyJarEntry(jprovider, sessionState,
3690 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3691 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3693 appVarna.setInitialSelection(viewer.getSelectedRna());
3699 * Locate and return an already instantiated matching AppVarna, or create one
3703 * @param viewIdSuffix
3707 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3708 String viewIdSuffix, AlignmentPanel ap)
3711 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3712 * if load is repeated
3714 String postLoadId = viewer.getViewId() + viewIdSuffix;
3715 for (JInternalFrame frame : getAllFrames())
3717 if (frame instanceof AppVarna)
3719 AppVarna varna = (AppVarna) frame;
3720 if (postLoadId.equals(varna.getViewId()))
3722 // this viewer is already instantiated
3723 // could in future here add ap as another 'parent' of the
3724 // AppVarna window; currently just 1-to-many
3731 * viewer not found - make it
3733 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3734 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3735 viewer.getHeight(), viewer.getDividerLocation());
3736 AppVarna varna = new AppVarna(model, ap);
3742 * Load any saved trees
3750 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3751 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3753 // TODO result of automated refactoring - are all these parameters needed?
3756 for (int t = 0; t < jms.getTreeCount(); t++)
3759 Tree tree = jms.getTree(t);
3761 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3764 tp = af.showNewickTree(
3765 new jalview.io.NewickFile(tree.getNewick()),
3766 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3767 tree.getXpos(), tree.getYpos());
3768 if (tree.getId() != null)
3770 // perhaps bind the tree id to something ?
3775 // update local tree attributes ?
3776 // TODO: should check if tp has been manipulated by user - if so its
3777 // settings shouldn't be modified
3778 tp.setTitle(tree.getTitle());
3779 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3780 tree.getWidth(), tree.getHeight()));
3781 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3784 tp.treeCanvas.av = av; // af.viewport;
3785 tp.treeCanvas.ap = ap; // af.alignPanel;
3790 warn("There was a problem recovering stored Newick tree: \n"
3791 + tree.getNewick());
3795 tp.fitToWindow.setState(tree.getFitToWindow());
3796 tp.fitToWindow_actionPerformed(null);
3798 if (tree.getFontName() != null)
3800 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3801 tree.getFontStyle(), tree.getFontSize()));
3805 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3806 view.getFontStyle(), tree.getFontSize()));
3809 tp.showPlaceholders(tree.getMarkUnlinked());
3810 tp.showBootstrap(tree.getShowBootstrap());
3811 tp.showDistances(tree.getShowDistances());
3813 tp.treeCanvas.threshold = tree.getThreshold();
3815 if (tree.getCurrentTree())
3817 af.viewport.setCurrentTree(tp.getTree());
3821 } catch (Exception ex)
3823 ex.printStackTrace();
3828 * Load and link any saved structure viewers.
3835 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3836 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3839 * Run through all PDB ids on the alignment, and collect mappings between
3840 * distinct view ids and all sequences referring to that view.
3842 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3844 for (int i = 0; i < jseqs.length; i++)
3846 if (jseqs[i].getPdbidsCount() > 0)
3848 Pdbids[] ids = jseqs[i].getPdbids();
3849 for (int p = 0; p < ids.length; p++)
3851 final int structureStateCount = ids[p].getStructureStateCount();
3852 for (int s = 0; s < structureStateCount; s++)
3854 // check to see if we haven't already created this structure view
3855 final StructureState structureState = ids[p]
3856 .getStructureState(s);
3857 String sviewid = (structureState.getViewId() == null) ? null
3858 : structureState.getViewId() + uniqueSetSuffix;
3859 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3860 // Originally : ids[p].getFile()
3861 // : TODO: verify external PDB file recovery still works in normal
3862 // jalview project load
3863 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3865 jpdb.setId(ids[p].getId());
3867 int x = structureState.getXpos();
3868 int y = structureState.getYpos();
3869 int width = structureState.getWidth();
3870 int height = structureState.getHeight();
3872 // Probably don't need to do this anymore...
3873 // Desktop.desktop.getComponentAt(x, y);
3874 // TODO: NOW: check that this recovers the PDB file correctly.
3875 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3877 jalview.datamodel.SequenceI seq = seqRefIds
3878 .get(jseqs[i].getId() + "");
3879 if (sviewid == null)
3881 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3884 if (!structureViewers.containsKey(sviewid))
3886 structureViewers.put(sviewid,
3887 new StructureViewerModel(x, y, width, height, false,
3888 false, true, structureState.getViewId(),
3889 structureState.getType()));
3890 // Legacy pre-2.7 conversion JAL-823 :
3891 // do not assume any view has to be linked for colour by
3895 // assemble String[] { pdb files }, String[] { id for each
3896 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3897 // seqs_file 2}, boolean[] {
3898 // linkAlignPanel,superposeWithAlignpanel}} from hash
3899 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3900 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3901 | (structureState.hasAlignwithAlignPanel()
3902 ? structureState.getAlignwithAlignPanel()
3906 * Default colour by linked panel to false if not specified (e.g.
3907 * for pre-2.7 projects)
3909 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3910 colourWithAlignPanel |= (structureState
3911 .hasColourwithAlignPanel()
3912 ? structureState.getColourwithAlignPanel()
3914 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3917 * Default colour by viewer to true if not specified (e.g. for
3920 boolean colourByViewer = jmoldat.isColourByViewer();
3921 colourByViewer &= structureState.hasColourByJmol()
3922 ? structureState.getColourByJmol()
3924 jmoldat.setColourByViewer(colourByViewer);
3926 if (jmoldat.getStateData().length() < structureState
3927 .getContent().length())
3930 jmoldat.setStateData(structureState.getContent());
3933 if (ids[p].getFile() != null)
3935 File mapkey = new File(ids[p].getFile());
3936 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3937 if (seqstrmaps == null)
3939 jmoldat.getFileData().put(mapkey,
3940 seqstrmaps = jmoldat.new StructureData(pdbFile,
3943 if (!seqstrmaps.getSeqList().contains(seq))
3945 seqstrmaps.getSeqList().add(seq);
3951 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");
3958 // Instantiate the associated structure views
3959 for (Entry<String, StructureViewerModel> entry : structureViewers
3964 createOrLinkStructureViewer(entry, af, ap, jprovider);
3965 } catch (Exception e)
3968 "Error loading structure viewer: " + e.getMessage());
3969 // failed - try the next one
3981 protected void createOrLinkStructureViewer(
3982 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3983 AlignmentPanel ap, jarInputStreamProvider jprovider)
3985 final StructureViewerModel stateData = viewerData.getValue();
3988 * Search for any viewer windows already open from other alignment views
3989 * that exactly match the stored structure state
3991 StructureViewerBase comp = findMatchingViewer(viewerData);
3995 linkStructureViewer(ap, comp, stateData);
4000 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4001 * "viewer_"+stateData.viewId
4003 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4005 createChimeraViewer(viewerData, af, jprovider);
4010 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4012 createJmolViewer(viewerData, af, jprovider);
4017 * Create a new Chimera viewer.
4023 protected void createChimeraViewer(
4024 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4025 jarInputStreamProvider jprovider)
4027 StructureViewerModel data = viewerData.getValue();
4028 String chimeraSessionFile = data.getStateData();
4031 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4033 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4034 * 'uniquified' sviewid used to reconstruct the viewer here
4036 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4037 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4040 Set<Entry<File, StructureData>> fileData = data.getFileData()
4042 List<PDBEntry> pdbs = new ArrayList<>();
4043 List<SequenceI[]> allseqs = new ArrayList<>();
4044 for (Entry<File, StructureData> pdb : fileData)
4046 String filePath = pdb.getValue().getFilePath();
4047 String pdbId = pdb.getValue().getPdbId();
4048 // pdbs.add(new PDBEntry(filePath, pdbId));
4049 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4050 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4051 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4055 boolean colourByChimera = data.isColourByViewer();
4056 boolean colourBySequence = data.isColourWithAlignPanel();
4058 // TODO use StructureViewer as a factory here, see JAL-1761
4059 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4060 final SequenceI[][] seqsArray = allseqs
4061 .toArray(new SequenceI[allseqs.size()][]);
4062 String newViewId = viewerData.getKey();
4064 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4065 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4066 colourBySequence, newViewId);
4067 cvf.setSize(data.getWidth(), data.getHeight());
4068 cvf.setLocation(data.getX(), data.getY());
4072 * Create a new Jmol window. First parse the Jmol state to translate filenames
4073 * loaded into the view, and record the order in which files are shown in the
4074 * Jmol view, so we can add the sequence mappings in same order.
4080 protected void createJmolViewer(
4081 final Entry<String, StructureViewerModel> viewerData,
4082 AlignFrame af, jarInputStreamProvider jprovider)
4084 final StructureViewerModel svattrib = viewerData.getValue();
4085 String state = svattrib.getStateData();
4088 * Pre-2.9: state element value is the Jmol state string
4090 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4093 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4095 state = readJarEntry(jprovider,
4096 getViewerJarEntryName(svattrib.getViewId()));
4099 List<String> pdbfilenames = new ArrayList<>();
4100 List<SequenceI[]> seqmaps = new ArrayList<>();
4101 List<String> pdbids = new ArrayList<>();
4102 StringBuilder newFileLoc = new StringBuilder(64);
4103 int cp = 0, ncp, ecp;
4104 Map<File, StructureData> oldFiles = svattrib.getFileData();
4105 while ((ncp = state.indexOf("load ", cp)) > -1)
4109 // look for next filename in load statement
4110 newFileLoc.append(state.substring(cp,
4111 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4112 String oldfilenam = state.substring(ncp,
4113 ecp = state.indexOf("\"", ncp));
4114 // recover the new mapping data for this old filename
4115 // have to normalize filename - since Jmol and jalview do
4117 // translation differently.
4118 StructureData filedat = oldFiles.get(new File(oldfilenam));
4119 if (filedat == null)
4121 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4122 filedat = oldFiles.get(new File(reformatedOldFilename));
4124 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4125 pdbfilenames.add(filedat.getFilePath());
4126 pdbids.add(filedat.getPdbId());
4127 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4128 newFileLoc.append("\"");
4129 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4130 // look for next file statement.
4131 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4135 // just append rest of state
4136 newFileLoc.append(state.substring(cp));
4140 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4141 newFileLoc = new StringBuilder(state);
4142 newFileLoc.append("; load append ");
4143 for (File id : oldFiles.keySet())
4145 // add this and any other pdb files that should be present in
4147 StructureData filedat = oldFiles.get(id);
4148 newFileLoc.append(filedat.getFilePath());
4149 pdbfilenames.add(filedat.getFilePath());
4150 pdbids.add(filedat.getPdbId());
4151 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4152 newFileLoc.append(" \"");
4153 newFileLoc.append(filedat.getFilePath());
4154 newFileLoc.append("\"");
4157 newFileLoc.append(";");
4160 if (newFileLoc.length() == 0)
4164 int histbug = newFileLoc.indexOf("history = ");
4168 * change "history = [true|false];" to "history = [1|0];"
4171 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4172 String val = (diff == -1) ? null
4173 : newFileLoc.substring(histbug, diff);
4174 if (val != null && val.length() >= 4)
4176 if (val.contains("e")) // eh? what can it be?
4178 if (val.trim().equals("true"))
4186 newFileLoc.replace(histbug, diff, val);
4191 final String[] pdbf = pdbfilenames
4192 .toArray(new String[pdbfilenames.size()]);
4193 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4194 final SequenceI[][] sq = seqmaps
4195 .toArray(new SequenceI[seqmaps.size()][]);
4196 final String fileloc = newFileLoc.toString();
4197 final String sviewid = viewerData.getKey();
4198 final AlignFrame alf = af;
4199 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4200 svattrib.getWidth(), svattrib.getHeight());
4203 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4208 JalviewStructureDisplayI sview = null;
4211 sview = new StructureViewer(
4212 alf.alignPanel.getStructureSelectionManager())
4213 .createView(StructureViewer.ViewerType.JMOL,
4214 pdbf, id, sq, alf.alignPanel, svattrib,
4215 fileloc, rect, sviewid);
4216 addNewStructureViewer(sview);
4217 } catch (OutOfMemoryError ex)
4219 new OOMWarning("restoring structure view for PDB id " + id,
4220 (OutOfMemoryError) ex.getCause());
4221 if (sview != null && sview.isVisible())
4223 sview.closeViewer(false);
4224 sview.setVisible(false);
4230 } catch (InvocationTargetException ex)
4232 warn("Unexpected error when opening Jmol view.", ex);
4234 } catch (InterruptedException e)
4236 // e.printStackTrace();
4242 * Generates a name for the entry in the project jar file to hold state
4243 * information for a structure viewer
4248 protected String getViewerJarEntryName(String viewId)
4250 return VIEWER_PREFIX + viewId;
4254 * Returns any open frame that matches given structure viewer data. The match
4255 * is based on the unique viewId, or (for older project versions) the frame's
4261 protected StructureViewerBase findMatchingViewer(
4262 Entry<String, StructureViewerModel> viewerData)
4264 final String sviewid = viewerData.getKey();
4265 final StructureViewerModel svattrib = viewerData.getValue();
4266 StructureViewerBase comp = null;
4267 JInternalFrame[] frames = getAllFrames();
4268 for (JInternalFrame frame : frames)
4270 if (frame instanceof StructureViewerBase)
4273 * Post jalview 2.4 schema includes structure view id
4275 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4278 comp = (StructureViewerBase) frame;
4279 break; // break added in 2.9
4282 * Otherwise test for matching position and size of viewer frame
4284 else if (frame.getX() == svattrib.getX()
4285 && frame.getY() == svattrib.getY()
4286 && frame.getHeight() == svattrib.getHeight()
4287 && frame.getWidth() == svattrib.getWidth())
4289 comp = (StructureViewerBase) frame;
4290 // no break in faint hope of an exact match on viewId
4298 * Link an AlignmentPanel to an existing structure viewer.
4303 * @param useinViewerSuperpos
4304 * @param usetoColourbyseq
4305 * @param viewerColouring
4307 protected void linkStructureViewer(AlignmentPanel ap,
4308 StructureViewerBase viewer, StructureViewerModel stateData)
4310 // NOTE: if the jalview project is part of a shared session then
4311 // view synchronization should/could be done here.
4313 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4314 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4315 final boolean viewerColouring = stateData.isColourByViewer();
4316 Map<File, StructureData> oldFiles = stateData.getFileData();
4319 * Add mapping for sequences in this view to an already open viewer
4321 final AAStructureBindingModel binding = viewer.getBinding();
4322 for (File id : oldFiles.keySet())
4324 // add this and any other pdb files that should be present in the
4326 StructureData filedat = oldFiles.get(id);
4327 String pdbFile = filedat.getFilePath();
4328 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4329 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4331 binding.addSequenceForStructFile(pdbFile, seq);
4333 // and add the AlignmentPanel's reference to the view panel
4334 viewer.addAlignmentPanel(ap);
4335 if (useinViewerSuperpos)
4337 viewer.useAlignmentPanelForSuperposition(ap);
4341 viewer.excludeAlignmentPanelForSuperposition(ap);
4343 if (usetoColourbyseq)
4345 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4349 viewer.excludeAlignmentPanelForColourbyseq(ap);
4354 * Get all frames within the Desktop.
4358 protected JInternalFrame[] getAllFrames()
4360 JInternalFrame[] frames = null;
4361 // TODO is this necessary - is it safe - risk of hanging?
4366 frames = Desktop.desktop.getAllFrames();
4367 } catch (ArrayIndexOutOfBoundsException e)
4369 // occasional No such child exceptions are thrown here...
4373 } catch (InterruptedException f)
4377 } while (frames == null);
4382 * Answers true if 'version' is equal to or later than 'supported', where each
4383 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4384 * changes. Development and test values for 'version' are leniently treated
4388 * - minimum version we are comparing against
4390 * - version of data being processsed
4393 public static boolean isVersionStringLaterThan(String supported,
4396 if (supported == null || version == null
4397 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4398 || version.equalsIgnoreCase("Test")
4399 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4401 System.err.println("Assuming project file with "
4402 + (version == null ? "null" : version)
4403 + " is compatible with Jalview version " + supported);
4408 return StringUtils.compareVersions(version, supported, "b") >= 0;
4412 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4414 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4416 if (newStructureViewers != null)
4418 sview.getBinding().setFinishedLoadingFromArchive(false);
4419 newStructureViewers.add(sview);
4423 protected void setLoadingFinishedForNewStructureViewers()
4425 if (newStructureViewers != null)
4427 for (JalviewStructureDisplayI sview : newStructureViewers)
4429 sview.getBinding().setFinishedLoadingFromArchive(true);
4431 newStructureViewers.clear();
4432 newStructureViewers = null;
4436 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4437 List<SequenceI> hiddenSeqs, AlignmentI al,
4438 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4439 String viewId, List<JvAnnotRow> autoAlan)
4441 AlignFrame af = null;
4442 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4443 uniqueSeqSetId, viewId);
4445 af.setFileName(file, FileFormat.Jalview);
4447 for (int i = 0; i < JSEQ.length; i++)
4449 af.viewport.setSequenceColour(
4450 af.viewport.getAlignment().getSequenceAt(i),
4451 new java.awt.Color(JSEQ[i].getColour()));
4456 af.getViewport().setColourByReferenceSeq(true);
4457 af.getViewport().setDisplayReferenceSeq(true);
4460 af.viewport.setGatherViewsHere(view.getGatheredViews());
4462 if (view.getSequenceSetId() != null)
4464 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4466 af.viewport.setSequenceSetId(uniqueSeqSetId);
4469 // propagate shared settings to this new view
4470 af.viewport.setHistoryList(av.getHistoryList());
4471 af.viewport.setRedoList(av.getRedoList());
4475 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4477 // TODO: check if this method can be called repeatedly without
4478 // side-effects if alignpanel already registered.
4479 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4481 // apply Hidden regions to view.
4482 if (hiddenSeqs != null)
4484 for (int s = 0; s < JSEQ.length; s++)
4486 SequenceGroup hidden = new SequenceGroup();
4487 boolean isRepresentative = false;
4488 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4490 isRepresentative = true;
4491 SequenceI sequenceToHide = al
4492 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4493 hidden.addSequence(sequenceToHide, false);
4494 // remove from hiddenSeqs list so we don't try to hide it twice
4495 hiddenSeqs.remove(sequenceToHide);
4497 if (isRepresentative)
4499 SequenceI representativeSequence = al.getSequenceAt(s);
4500 hidden.addSequence(representativeSequence, false);
4501 af.viewport.hideRepSequences(representativeSequence, hidden);
4505 SequenceI[] hseqs = hiddenSeqs
4506 .toArray(new SequenceI[hiddenSeqs.size()]);
4507 af.viewport.hideSequence(hseqs);
4510 // recover view properties and display parameters
4512 af.viewport.setShowAnnotation(view.getShowAnnotation());
4513 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4514 af.viewport.setThreshold(view.getPidThreshold());
4516 af.viewport.setColourText(view.getShowColourText());
4518 af.viewport.setConservationSelected(view.getConservationSelected());
4519 af.viewport.setIncrement(view.getConsThreshold());
4520 af.viewport.setShowJVSuffix(view.getShowFullId());
4521 af.viewport.setRightAlignIds(view.getRightAlignIds());
4522 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4523 view.getFontStyle(), view.getFontSize()), true);
4524 ViewStyleI vs = af.viewport.getViewStyle();
4525 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4526 af.viewport.setViewStyle(vs);
4527 // TODO: allow custom charWidth/Heights to be restored by updating them
4528 // after setting font - which means set above to false
4529 af.viewport.setRenderGaps(view.getRenderGaps());
4530 af.viewport.setWrapAlignment(view.getWrapAlignment());
4531 af.viewport.setShowAnnotation(view.getShowAnnotation());
4533 af.viewport.setShowBoxes(view.getShowBoxes());
4535 af.viewport.setShowText(view.getShowText());
4537 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4538 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4539 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4540 af.viewport.setShowUnconserved(
4541 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4542 af.viewport.getRanges().setStartRes(view.getStartRes());
4544 if (view.getViewName() != null)
4546 af.viewport.viewName = view.getViewName();
4547 af.setInitialTabVisible();
4549 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4551 // startSeq set in af.alignPanel.updateLayout below
4552 af.alignPanel.updateLayout();
4553 ColourSchemeI cs = null;
4554 // apply colourschemes
4555 if (view.getBgColour() != null)
4557 if (view.getBgColour().startsWith("ucs"))
4559 cs = getUserColourScheme(jms, view.getBgColour());
4561 else if (view.getBgColour().startsWith("Annotation"))
4563 AnnotationColours viewAnnColour = view.getAnnotationColours();
4564 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4571 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4575 af.viewport.setGlobalColourScheme(cs);
4576 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4577 view.getIgnoreGapsinConsensus());
4578 af.viewport.getResidueShading()
4579 .setConsensus(af.viewport.getSequenceConsensusHash());
4580 af.viewport.setColourAppliesToAllGroups(false);
4582 if (view.getConservationSelected() && cs != null)
4584 af.viewport.getResidueShading()
4585 .setConservationInc(view.getConsThreshold());
4588 af.changeColour(cs);
4590 af.viewport.setColourAppliesToAllGroups(true);
4592 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4594 if (view.hasCentreColumnLabels())
4596 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4598 if (view.hasIgnoreGapsinConsensus())
4600 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4603 if (view.hasFollowHighlight())
4605 af.viewport.setFollowHighlight(view.getFollowHighlight());
4607 if (view.hasFollowSelection())
4609 af.viewport.followSelection = view.getFollowSelection();
4611 if (view.hasShowConsensusHistogram())
4614 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4618 af.viewport.setShowConsensusHistogram(true);
4620 if (view.hasShowSequenceLogo())
4622 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4626 af.viewport.setShowSequenceLogo(false);
4628 if (view.hasNormaliseSequenceLogo())
4630 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4632 if (view.hasShowDbRefTooltip())
4634 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4636 if (view.hasShowNPfeatureTooltip())
4638 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4640 if (view.hasShowGroupConsensus())
4642 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4646 af.viewport.setShowGroupConsensus(false);
4648 if (view.hasShowGroupConservation())
4650 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4654 af.viewport.setShowGroupConservation(false);
4657 // recover feature settings
4658 if (jms.getFeatureSettings() != null)
4660 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4661 .getFeatureRenderer();
4662 FeaturesDisplayed fdi;
4663 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4664 String[] renderOrder = new String[jms.getFeatureSettings()
4665 .getSettingCount()];
4666 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4667 Map<String, Float> featureOrder = new Hashtable<>();
4669 for (int fs = 0; fs < jms.getFeatureSettings()
4670 .getSettingCount(); fs++)
4672 Setting setting = jms.getFeatureSettings().getSetting(fs);
4673 String featureType = setting.getType();
4676 * restore feature filters (if any)
4678 MatcherSet filters = setting.getMatcherSet();
4679 if (filters != null)
4681 FeatureMatcherSetI filter = Jalview2XML
4682 .unmarshalFilter(featureType, filters);
4683 if (!filter.isEmpty())
4685 fr.setFeatureFilter(featureType, filter);
4690 * restore feature colour scheme
4692 Color maxColour = new Color(setting.getColour());
4693 if (setting.hasMincolour())
4696 * minColour is always set unless a simple colour
4697 * (including for colour by label though it doesn't use it)
4699 Color minColour = new Color(setting.getMincolour());
4700 Color noValueColour = minColour;
4701 NoValueColour noColour = setting.getNoValueColour();
4702 if (noColour == NoValueColour.NONE)
4704 noValueColour = null;
4706 else if (noColour == NoValueColour.MAX)
4708 noValueColour = maxColour;
4710 float min = setting.hasMin() ? setting.getMin() : 0f;
4711 float max = setting.hasMin() ? setting.getMax() : 1f;
4712 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4713 noValueColour, min, max);
4714 if (setting.getAttributeNameCount() > 0)
4716 gc.setAttributeName(setting.getAttributeName());
4718 if (setting.hasThreshold())
4720 gc.setThreshold(setting.getThreshold());
4721 int threshstate = setting.getThreshstate();
4722 // -1 = None, 0 = Below, 1 = Above threshold
4723 if (threshstate == 0)
4725 gc.setBelowThreshold(true);
4727 else if (threshstate == 1)
4729 gc.setAboveThreshold(true);
4732 gc.setAutoScaled(true); // default
4733 if (setting.hasAutoScale())
4735 gc.setAutoScaled(setting.getAutoScale());
4737 if (setting.hasColourByLabel())
4739 gc.setColourByLabel(setting.getColourByLabel());
4741 // and put in the feature colour table.
4742 featureColours.put(featureType, gc);
4746 featureColours.put(featureType,
4747 new FeatureColour(maxColour));
4749 renderOrder[fs] = featureType;
4750 if (setting.hasOrder())
4752 featureOrder.put(featureType, setting.getOrder());
4756 featureOrder.put(featureType, new Float(
4757 fs / jms.getFeatureSettings().getSettingCount()));
4759 if (setting.getDisplay())
4761 fdi.setVisible(featureType);
4764 Map<String, Boolean> fgtable = new Hashtable<>();
4765 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4767 Group grp = jms.getFeatureSettings().getGroup(gs);
4768 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4770 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4771 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4772 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4773 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4774 fgtable, featureColours, 1.0f, featureOrder);
4775 fr.transferSettings(frs);
4778 if (view.getHiddenColumnsCount() > 0)
4780 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4782 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4783 view.getHiddenColumns(c).getEnd() // +1
4787 if (view.getCalcIdParam() != null)
4789 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4791 if (calcIdParam != null)
4793 if (recoverCalcIdParam(calcIdParam, af.viewport))
4798 warn("Couldn't recover parameters for "
4799 + calcIdParam.getCalcId());
4804 af.setMenusFromViewport(af.viewport);
4805 af.setTitle(view.getTitle());
4806 // TODO: we don't need to do this if the viewport is aready visible.
4808 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4809 * has a 'cdna/protein complement' view, in which case save it in order to
4810 * populate a SplitFrame once all views have been read in.
4812 String complementaryViewId = view.getComplementId();
4813 if (complementaryViewId == null)
4815 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4817 // recompute any autoannotation
4818 af.alignPanel.updateAnnotation(false, true);
4819 reorderAutoannotation(af, al, autoAlan);
4820 af.alignPanel.alignmentChanged();
4824 splitFrameCandidates.put(view, af);
4830 * Reads saved data to restore Colour by Annotation settings
4832 * @param viewAnnColour
4836 * @param checkGroupAnnColour
4839 private ColourSchemeI constructAnnotationColour(
4840 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4841 JalviewModelSequence jms, boolean checkGroupAnnColour)
4843 boolean propagateAnnColour = false;
4844 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4845 if (checkGroupAnnColour && al.getGroups() != null
4846 && al.getGroups().size() > 0)
4848 // pre 2.8.1 behaviour
4849 // check to see if we should transfer annotation colours
4850 propagateAnnColour = true;
4851 for (SequenceGroup sg : al.getGroups())
4853 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4855 propagateAnnColour = false;
4861 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4863 String annotationId = viewAnnColour.getAnnotation();
4864 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4867 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4869 if (matchedAnnotation == null
4870 && annAlignment.getAlignmentAnnotation() != null)
4872 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4875 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4877 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4882 if (matchedAnnotation == null)
4884 System.err.println("Failed to match annotation colour scheme for "
4888 if (matchedAnnotation.getThreshold() == null)
4890 matchedAnnotation.setThreshold(new GraphLine(
4891 viewAnnColour.getThreshold(), "Threshold", Color.black));
4894 AnnotationColourGradient cs = null;
4895 if (viewAnnColour.getColourScheme().equals("None"))
4897 cs = new AnnotationColourGradient(matchedAnnotation,
4898 new Color(viewAnnColour.getMinColour()),
4899 new Color(viewAnnColour.getMaxColour()),
4900 viewAnnColour.getAboveThreshold());
4902 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4904 cs = new AnnotationColourGradient(matchedAnnotation,
4905 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4906 viewAnnColour.getAboveThreshold());
4910 cs = new AnnotationColourGradient(matchedAnnotation,
4911 ColourSchemeProperty.getColourScheme(al,
4912 viewAnnColour.getColourScheme()),
4913 viewAnnColour.getAboveThreshold());
4916 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4917 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4918 cs.setSeqAssociated(perSequenceOnly);
4919 cs.setPredefinedColours(useOriginalColours);
4921 if (propagateAnnColour && al.getGroups() != null)
4923 // Also use these settings for all the groups
4924 for (int g = 0; g < al.getGroups().size(); g++)
4926 SequenceGroup sg = al.getGroups().get(g);
4927 if (sg.getGroupColourScheme() == null)
4932 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4933 matchedAnnotation, sg.getColourScheme(),
4934 viewAnnColour.getAboveThreshold());
4935 sg.setColourScheme(groupScheme);
4936 groupScheme.setSeqAssociated(perSequenceOnly);
4937 groupScheme.setPredefinedColours(useOriginalColours);
4943 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4944 List<JvAnnotRow> autoAlan)
4946 // copy over visualization settings for autocalculated annotation in the
4948 if (al.getAlignmentAnnotation() != null)
4951 * Kludge for magic autoannotation names (see JAL-811)
4953 String[] magicNames = new String[] { "Consensus", "Quality",
4955 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4956 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4957 for (String nm : magicNames)
4959 visan.put(nm, nullAnnot);
4961 for (JvAnnotRow auan : autoAlan)
4963 visan.put(auan.template.label
4964 + (auan.template.getCalcId() == null ? ""
4965 : "\t" + auan.template.getCalcId()),
4968 int hSize = al.getAlignmentAnnotation().length;
4969 List<JvAnnotRow> reorder = new ArrayList<>();
4970 // work through any autoCalculated annotation already on the view
4971 // removing it if it should be placed in a different location on the
4972 // annotation panel.
4973 List<String> remains = new ArrayList<>(visan.keySet());
4974 for (int h = 0; h < hSize; h++)
4976 jalview.datamodel.AlignmentAnnotation jalan = al
4977 .getAlignmentAnnotation()[h];
4978 if (jalan.autoCalculated)
4981 JvAnnotRow valan = visan.get(k = jalan.label);
4982 if (jalan.getCalcId() != null)
4984 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4989 // delete the auto calculated row from the alignment
4990 al.deleteAnnotation(jalan, false);
4994 if (valan != nullAnnot)
4996 if (jalan != valan.template)
4998 // newly created autoannotation row instance
4999 // so keep a reference to the visible annotation row
5000 // and copy over all relevant attributes
5001 if (valan.template.graphHeight >= 0)
5004 jalan.graphHeight = valan.template.graphHeight;
5006 jalan.visible = valan.template.visible;
5008 reorder.add(new JvAnnotRow(valan.order, jalan));
5013 // Add any (possibly stale) autocalculated rows that were not appended to
5014 // the view during construction
5015 for (String other : remains)
5017 JvAnnotRow othera = visan.get(other);
5018 if (othera != nullAnnot && othera.template.getCalcId() != null
5019 && othera.template.getCalcId().length() > 0)
5021 reorder.add(othera);
5024 // now put the automatic annotation in its correct place
5025 int s = 0, srt[] = new int[reorder.size()];
5026 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5027 for (JvAnnotRow jvar : reorder)
5030 srt[s++] = jvar.order;
5033 jalview.util.QuickSort.sort(srt, rws);
5034 // and re-insert the annotation at its correct position
5035 for (JvAnnotRow jvar : rws)
5037 al.addAnnotation(jvar.template, jvar.order);
5039 af.alignPanel.adjustAnnotationHeight();
5043 Hashtable skipList = null;
5046 * TODO remove this method
5049 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5050 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5051 * throw new Error("Implementation Error. No skipList defined for this
5052 * Jalview2XML instance."); } return (AlignFrame)
5053 * skipList.get(view.getSequenceSetId()); }
5057 * Check if the Jalview view contained in object should be skipped or not.
5060 * @return true if view's sequenceSetId is a key in skipList
5062 private boolean skipViewport(JalviewModel object)
5064 if (skipList == null)
5069 if (skipList.containsKey(
5070 id = object.getJalviewModelSequence().getViewport()[0]
5071 .getSequenceSetId()))
5073 if (Cache.log != null && Cache.log.isDebugEnabled())
5075 Cache.log.debug("Skipping seuqence set id " + id);
5082 public void addToSkipList(AlignFrame af)
5084 if (skipList == null)
5086 skipList = new Hashtable();
5088 skipList.put(af.getViewport().getSequenceSetId(), af);
5091 public void clearSkipList()
5093 if (skipList != null)
5100 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5101 boolean ignoreUnrefed)
5103 jalview.datamodel.AlignmentI ds = getDatasetFor(
5104 vamsasSet.getDatasetId());
5105 Vector dseqs = null;
5108 // create a list of new dataset sequences
5109 dseqs = new Vector();
5111 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5113 Sequence vamsasSeq = vamsasSet.getSequence(i);
5114 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5116 // create a new dataset
5119 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5120 dseqs.copyInto(dsseqs);
5121 ds = new jalview.datamodel.Alignment(dsseqs);
5122 debug("Created new dataset " + vamsasSet.getDatasetId()
5123 + " for alignment " + System.identityHashCode(al));
5124 addDatasetRef(vamsasSet.getDatasetId(), ds);
5126 // set the dataset for the newly imported alignment.
5127 if (al.getDataset() == null && !ignoreUnrefed)
5136 * sequence definition to create/merge dataset sequence for
5140 * vector to add new dataset sequence to
5141 * @param ignoreUnrefed
5142 * - when true, don't create new sequences from vamsasSeq if it's id
5143 * doesn't already have an asssociated Jalview sequence.
5145 * - used to reorder the sequence in the alignment according to the
5146 * vamsasSeq array ordering, to preserve ordering of dataset
5148 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5149 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5151 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5153 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5154 boolean reorder = false;
5155 SequenceI dsq = null;
5156 if (sq != null && sq.getDatasetSequence() != null)
5158 dsq = sq.getDatasetSequence();
5164 if (sq == null && ignoreUnrefed)
5168 String sqid = vamsasSeq.getDsseqid();
5171 // need to create or add a new dataset sequence reference to this sequence
5174 dsq = seqRefIds.get(sqid);
5179 // make a new dataset sequence
5180 dsq = sq.createDatasetSequence();
5183 // make up a new dataset reference for this sequence
5184 sqid = seqHash(dsq);
5186 dsq.setVamsasId(uniqueSetSuffix + sqid);
5187 seqRefIds.put(sqid, dsq);
5192 dseqs.addElement(dsq);
5197 ds.addSequence(dsq);
5203 { // make this dataset sequence sq's dataset sequence
5204 sq.setDatasetSequence(dsq);
5205 // and update the current dataset alignment
5210 if (!dseqs.contains(dsq))
5217 if (ds.findIndex(dsq) < 0)
5219 ds.addSequence(dsq);
5226 // TODO: refactor this as a merge dataset sequence function
5227 // now check that sq (the dataset sequence) sequence really is the union of
5228 // all references to it
5229 // boolean pre = sq.getStart() < dsq.getStart();
5230 // boolean post = sq.getEnd() > dsq.getEnd();
5234 // StringBuffer sb = new StringBuffer();
5235 String newres = jalview.analysis.AlignSeq.extractGaps(
5236 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5237 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5238 && newres.length() > dsq.getLength())
5240 // Update with the longer sequence.
5244 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5245 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5246 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5247 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5249 dsq.setSequence(newres);
5251 // TODO: merges will never happen if we 'know' we have the real dataset
5252 // sequence - this should be detected when id==dssid
5254 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5255 // + (pre ? "prepended" : "") + " "
5256 // + (post ? "appended" : ""));
5261 // sequence refs are identical. We may need to update the existing dataset
5262 // alignment with this one, though.
5263 if (ds != null && dseqs == null)
5265 int opos = ds.findIndex(dsq);
5266 SequenceI tseq = null;
5267 if (opos != -1 && vseqpos != opos)
5269 // remove from old position
5270 ds.deleteSequence(dsq);
5272 if (vseqpos < ds.getHeight())
5274 if (vseqpos != opos)
5276 // save sequence at destination position
5277 tseq = ds.getSequenceAt(vseqpos);
5278 ds.replaceSequenceAt(vseqpos, dsq);
5279 ds.addSequence(tseq);
5284 ds.addSequence(dsq);
5291 * TODO use AlignmentI here and in related methods - needs
5292 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5294 Hashtable<String, AlignmentI> datasetIds = null;
5296 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5298 private AlignmentI getDatasetFor(String datasetId)
5300 if (datasetIds == null)
5302 datasetIds = new Hashtable<>();
5305 if (datasetIds.containsKey(datasetId))
5307 return datasetIds.get(datasetId);
5312 private void addDatasetRef(String datasetId, AlignmentI dataset)
5314 if (datasetIds == null)
5316 datasetIds = new Hashtable<>();
5318 datasetIds.put(datasetId, dataset);
5322 * make a new dataset ID for this jalview dataset alignment
5327 private String getDatasetIdRef(AlignmentI dataset)
5329 if (dataset.getDataset() != null)
5331 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5333 String datasetId = makeHashCode(dataset, null);
5334 if (datasetId == null)
5336 // make a new datasetId and record it
5337 if (dataset2Ids == null)
5339 dataset2Ids = new IdentityHashMap<>();
5343 datasetId = dataset2Ids.get(dataset);
5345 if (datasetId == null)
5347 datasetId = "ds" + dataset2Ids.size() + 1;
5348 dataset2Ids.put(dataset, datasetId);
5354 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5356 for (int d = 0; d < sequence.getDBRefCount(); d++)
5358 DBRef dr = sequence.getDBRef(d);
5359 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5360 sequence.getDBRef(d).getSource(),
5361 sequence.getDBRef(d).getVersion(),
5362 sequence.getDBRef(d).getAccessionId());
5363 if (dr.getMapping() != null)
5365 entry.setMap(addMapping(dr.getMapping()));
5367 datasetSequence.addDBRef(entry);
5371 private jalview.datamodel.Mapping addMapping(Mapping m)
5373 SequenceI dsto = null;
5374 // Mapping m = dr.getMapping();
5375 int fr[] = new int[m.getMapListFromCount() * 2];
5376 Enumeration f = m.enumerateMapListFrom();
5377 for (int _i = 0; f.hasMoreElements(); _i += 2)
5379 MapListFrom mf = (MapListFrom) f.nextElement();
5380 fr[_i] = mf.getStart();
5381 fr[_i + 1] = mf.getEnd();
5383 int fto[] = new int[m.getMapListToCount() * 2];
5384 f = m.enumerateMapListTo();
5385 for (int _i = 0; f.hasMoreElements(); _i += 2)
5387 MapListTo mf = (MapListTo) f.nextElement();
5388 fto[_i] = mf.getStart();
5389 fto[_i + 1] = mf.getEnd();
5391 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5392 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5393 if (m.getMappingChoice() != null)
5395 MappingChoice mc = m.getMappingChoice();
5396 if (mc.getDseqFor() != null)
5398 String dsfor = "" + mc.getDseqFor();
5399 if (seqRefIds.containsKey(dsfor))
5404 jmap.setTo(seqRefIds.get(dsfor));
5408 frefedSequence.add(newMappingRef(dsfor, jmap));
5414 * local sequence definition
5416 Sequence ms = mc.getSequence();
5417 SequenceI djs = null;
5418 String sqid = ms.getDsseqid();
5419 if (sqid != null && sqid.length() > 0)
5422 * recover dataset sequence
5424 djs = seqRefIds.get(sqid);
5429 "Warning - making up dataset sequence id for DbRef sequence map reference");
5430 sqid = ((Object) ms).toString(); // make up a new hascode for
5431 // undefined dataset sequence hash
5432 // (unlikely to happen)
5438 * make a new dataset sequence and add it to refIds hash
5440 djs = new jalview.datamodel.Sequence(ms.getName(),
5442 djs.setStart(jmap.getMap().getToLowest());
5443 djs.setEnd(jmap.getMap().getToHighest());
5444 djs.setVamsasId(uniqueSetSuffix + sqid);
5446 incompleteSeqs.put(sqid, djs);
5447 seqRefIds.put(sqid, djs);
5450 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5460 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5461 * view as XML (but not to file), and then reloading it
5466 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5469 JalviewModel jm = saveState(ap, null, null, null);
5471 uniqueSetSuffix = "";
5472 jm.getJalviewModelSequence().getViewport(0).setId(null);
5473 // we don't overwrite the view we just copied
5475 if (this.frefedSequence == null)
5477 frefedSequence = new Vector<>();
5480 viewportsAdded.clear();
5482 AlignFrame af = loadFromObject(jm, null, false, null);
5483 af.alignPanels.clear();
5484 af.closeMenuItem_actionPerformed(true);
5487 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5488 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5489 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5490 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5491 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5494 return af.alignPanel;
5497 private Hashtable jvids2vobj;
5499 private void warn(String msg)
5504 private void warn(String msg, Exception e)
5506 if (Cache.log != null)
5510 Cache.log.warn(msg, e);
5514 Cache.log.warn(msg);
5519 System.err.println("Warning: " + msg);
5522 e.printStackTrace();
5527 private void debug(String string)
5529 debug(string, null);
5532 private void debug(String msg, Exception e)
5534 if (Cache.log != null)
5538 Cache.log.debug(msg, e);
5542 Cache.log.debug(msg);
5547 System.err.println("Warning: " + msg);
5550 e.printStackTrace();
5556 * set the object to ID mapping tables used to write/recover objects and XML
5557 * ID strings for the jalview project. If external tables are provided then
5558 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5559 * object goes out of scope. - also populates the datasetIds hashtable with
5560 * alignment objects containing dataset sequences
5563 * Map from ID strings to jalview datamodel
5565 * Map from jalview datamodel to ID strings
5569 public void setObjectMappingTables(Hashtable vobj2jv,
5570 IdentityHashMap jv2vobj)
5572 this.jv2vobj = jv2vobj;
5573 this.vobj2jv = vobj2jv;
5574 Iterator ds = jv2vobj.keySet().iterator();
5576 while (ds.hasNext())
5578 Object jvobj = ds.next();
5579 id = jv2vobj.get(jvobj).toString();
5580 if (jvobj instanceof jalview.datamodel.Alignment)
5582 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5584 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5587 else if (jvobj instanceof jalview.datamodel.Sequence)
5589 // register sequence object so the XML parser can recover it.
5590 if (seqRefIds == null)
5592 seqRefIds = new HashMap<>();
5594 if (seqsToIds == null)
5596 seqsToIds = new IdentityHashMap<>();
5598 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5599 seqsToIds.put((SequenceI) jvobj, id);
5601 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5604 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5605 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5606 if (jvann.annotationId == null)
5608 jvann.annotationId = anid;
5610 if (!jvann.annotationId.equals(anid))
5612 // TODO verify that this is the correct behaviour
5613 this.warn("Overriding Annotation ID for " + anid
5614 + " from different id : " + jvann.annotationId);
5615 jvann.annotationId = anid;
5618 else if (jvobj instanceof String)
5620 if (jvids2vobj == null)
5622 jvids2vobj = new Hashtable();
5623 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5628 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5634 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5635 * objects created from the project archive. If string is null (default for
5636 * construction) then suffix will be set automatically.
5640 public void setUniqueSetSuffix(String string)
5642 uniqueSetSuffix = string;
5647 * uses skipList2 as the skipList for skipping views on sequence sets
5648 * associated with keys in the skipList
5652 public void setSkipList(Hashtable skipList2)
5654 skipList = skipList2;
5658 * Reads the jar entry of given name and returns its contents, or null if the
5659 * entry is not found.
5662 * @param jarEntryName
5665 protected String readJarEntry(jarInputStreamProvider jprovider,
5666 String jarEntryName)
5668 String result = null;
5669 BufferedReader in = null;
5674 * Reopen the jar input stream and traverse its entries to find a matching
5677 JarInputStream jin = jprovider.getJarInputStream();
5678 JarEntry entry = null;
5681 entry = jin.getNextJarEntry();
5682 } while (entry != null && !entry.getName().equals(jarEntryName));
5686 StringBuilder out = new StringBuilder(256);
5687 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5690 while ((data = in.readLine()) != null)
5694 result = out.toString();
5698 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5700 } catch (Exception ex)
5702 ex.printStackTrace();
5710 } catch (IOException e)
5721 * Returns an incrementing counter (0, 1, 2...)
5725 private synchronized int nextCounter()
5731 * Populates an XML model of the feature colour scheme for one feature type
5733 * @param featureType
5737 protected static jalview.schemabinding.version2.Colour marshalColour(
5738 String featureType, FeatureColourI fcol)
5740 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5741 if (fcol.isSimpleColour())
5743 col.setRGB(Format.getHexString(fcol.getColour()));
5747 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5748 col.setMin(fcol.getMin());
5749 col.setMax(fcol.getMax());
5750 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5751 col.setAutoScale(fcol.isAutoScaled());
5752 col.setThreshold(fcol.getThreshold());
5753 col.setColourByLabel(fcol.isColourByLabel());
5754 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5755 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5756 : ColourThreshTypeType.NONE));
5757 if (fcol.isColourByAttribute())
5759 col.setAttributeName(fcol.getAttributeName());
5761 Color noColour = fcol.getNoColour();
5762 if (noColour == null)
5764 col.setNoValueColour(NoValueColour.NONE);
5766 else if (noColour == fcol.getMaxColour())
5768 col.setNoValueColour(NoValueColour.MAX);
5772 col.setNoValueColour(NoValueColour.MIN);
5775 col.setName(featureType);
5780 * Populates an XML model of the feature filter(s) for one feature type
5782 * @param firstMatcher
5783 * the first (or only) match condition)
5785 * remaining match conditions (if any)
5787 * if true, conditions are and-ed, else or-ed
5789 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5790 Iterator<FeatureMatcherI> filters, boolean and)
5792 MatcherSet result = new MatcherSet();
5794 if (filters.hasNext())
5799 CompoundMatcher compound = new CompoundMatcher();
5800 compound.setAnd(and);
5801 MatcherSet matcher1 = marshalFilter(firstMatcher,
5802 Collections.emptyIterator(), and);
5803 compound.addMatcherSet(matcher1);
5804 FeatureMatcherI nextMatcher = filters.next();
5805 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5806 compound.addMatcherSet(matcher2);
5807 result.setCompoundMatcher(compound);
5812 * single condition matcher
5814 MatchCondition matcherModel = new MatchCondition();
5815 matcherModel.setCondition(
5816 firstMatcher.getMatcher().getCondition().getStableName());
5817 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5818 if (firstMatcher.isByAttribute())
5820 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5821 matcherModel.setAttributeName(firstMatcher.getAttribute());
5823 else if (firstMatcher.isByLabel())
5825 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5827 else if (firstMatcher.isByScore())
5829 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5831 result.setMatchCondition(matcherModel);
5838 * Loads one XML model of a feature filter to a Jalview object
5840 * @param featureType
5841 * @param matcherSetModel
5844 protected static FeatureMatcherSetI unmarshalFilter(
5845 String featureType, MatcherSet matcherSetModel)
5847 FeatureMatcherSetI result = new FeatureMatcherSet();
5850 unmarshalFilterConditions(result, matcherSetModel, true);
5851 } catch (IllegalStateException e)
5853 // mixing AND and OR conditions perhaps
5855 String.format("Error reading filter conditions for '%s': %s",
5856 featureType, e.getMessage()));
5857 // return as much as was parsed up to the error
5864 * Adds feature match conditions to matcherSet as unmarshalled from XML
5865 * (possibly recursively for compound conditions)
5868 * @param matcherSetModel
5870 * if true, multiple conditions are AND-ed, else they are OR-ed
5871 * @throws IllegalStateException
5872 * if AND and OR conditions are mixed
5874 protected static void unmarshalFilterConditions(
5875 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5878 MatchCondition mc = matcherSetModel.getMatchCondition();
5884 FeatureMatcherByType filterBy = mc.getBy();
5885 Condition cond = Condition.fromString(mc.getCondition());
5886 String pattern = mc.getValue();
5887 FeatureMatcherI matchCondition = null;
5888 if (filterBy == FeatureMatcherByType.BYLABEL)
5890 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5892 else if (filterBy == FeatureMatcherByType.BYSCORE)
5894 matchCondition = FeatureMatcher.byScore(cond, pattern);
5897 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5899 String[] attNames = mc.getAttributeName();
5900 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5905 * note this throws IllegalStateException if AND-ing to a
5906 * previously OR-ed compound condition, or vice versa
5910 matcherSet.and(matchCondition);
5914 matcherSet.or(matchCondition);
5920 * compound condition
5922 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5924 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5925 if (matchers.length == 2)
5927 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5928 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5932 System.err.println("Malformed compound filter condition");
5938 * Loads one XML model of a feature colour to a Jalview object
5940 * @param colourModel
5943 protected static FeatureColourI unmarshalColour(
5944 jalview.schemabinding.version2.Colour colourModel)
5946 FeatureColourI colour = null;
5948 if (colourModel.hasMax())
5950 Color mincol = null;
5951 Color maxcol = null;
5952 Color noValueColour = null;
5956 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5957 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5958 } catch (Exception e)
5960 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5963 NoValueColour noCol = colourModel.getNoValueColour();
5964 if (noCol == NoValueColour.MIN)
5966 noValueColour = mincol;
5968 else if (noCol == NoValueColour.MAX)
5970 noValueColour = maxcol;
5973 colour = new FeatureColour(mincol, maxcol, noValueColour,
5974 colourModel.getMin(),
5975 colourModel.getMax());
5976 String[] attributes = colourModel.getAttributeName();
5977 if (attributes != null && attributes.length > 0)
5979 colour.setAttributeName(attributes);
5981 if (colourModel.hasAutoScale())
5983 colour.setAutoScaled(colourModel.getAutoScale());
5985 if (colourModel.hasColourByLabel())
5987 colour.setColourByLabel(colourModel.getColourByLabel());
5989 if (colourModel.hasThreshold())
5991 colour.setThreshold(colourModel.getThreshold());
5993 ColourThreshTypeType ttyp = colourModel.getThreshType();
5996 if (ttyp == ColourThreshTypeType.ABOVE)
5998 colour.setAboveThreshold(true);
6000 else if (ttyp == ColourThreshTypeType.BELOW)
6002 colour.setBelowThreshold(true);
6008 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6009 colour = new FeatureColour(color);