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.DataSourceType;
47 import jalview.io.FileFormat;
48 import jalview.renderer.ResidueShaderI;
49 import jalview.schemabinding.version2.AlcodMap;
50 import jalview.schemabinding.version2.AlcodonFrame;
51 import jalview.schemabinding.version2.Annotation;
52 import jalview.schemabinding.version2.AnnotationColours;
53 import jalview.schemabinding.version2.AnnotationElement;
54 import jalview.schemabinding.version2.CalcIdParam;
55 import jalview.schemabinding.version2.CompoundMatcher;
56 import jalview.schemabinding.version2.DBRef;
57 import jalview.schemabinding.version2.Features;
58 import jalview.schemabinding.version2.Group;
59 import jalview.schemabinding.version2.HiddenColumns;
60 import jalview.schemabinding.version2.JGroup;
61 import jalview.schemabinding.version2.JSeq;
62 import jalview.schemabinding.version2.JalviewModel;
63 import jalview.schemabinding.version2.JalviewModelSequence;
64 import jalview.schemabinding.version2.MapListFrom;
65 import jalview.schemabinding.version2.MapListTo;
66 import jalview.schemabinding.version2.Mapping;
67 import jalview.schemabinding.version2.MappingChoice;
68 import jalview.schemabinding.version2.MatchCondition;
69 import jalview.schemabinding.version2.MatcherSet;
70 import jalview.schemabinding.version2.OtherData;
71 import jalview.schemabinding.version2.PdbentryItem;
72 import jalview.schemabinding.version2.Pdbids;
73 import jalview.schemabinding.version2.Property;
74 import jalview.schemabinding.version2.RnaViewer;
75 import jalview.schemabinding.version2.SecondaryStructure;
76 import jalview.schemabinding.version2.Sequence;
77 import jalview.schemabinding.version2.SequenceSet;
78 import jalview.schemabinding.version2.SequenceSetProperties;
79 import jalview.schemabinding.version2.Setting;
80 import jalview.schemabinding.version2.StructureState;
81 import jalview.schemabinding.version2.ThresholdLine;
82 import jalview.schemabinding.version2.Tree;
83 import jalview.schemabinding.version2.UserColours;
84 import jalview.schemabinding.version2.Viewport;
85 import jalview.schemabinding.version2.types.ColourThreshTypeType;
86 import jalview.schemabinding.version2.types.FeatureMatcherByType;
87 import jalview.schemabinding.version2.types.NoValueColour;
88 import jalview.schemes.AnnotationColourGradient;
89 import jalview.schemes.ColourSchemeI;
90 import jalview.schemes.ColourSchemeProperty;
91 import jalview.schemes.FeatureColour;
92 import jalview.schemes.ResidueProperties;
93 import jalview.schemes.UserColourScheme;
94 import jalview.structure.StructureSelectionManager;
95 import jalview.structures.models.AAStructureBindingModel;
96 import jalview.util.Format;
97 import jalview.util.MessageManager;
98 import jalview.util.Platform;
99 import jalview.util.StringUtils;
100 import jalview.util.jarInputStreamProvider;
101 import jalview.util.matcher.Condition;
102 import jalview.viewmodel.AlignmentViewport;
103 import jalview.viewmodel.ViewportRanges;
104 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
105 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
106 import jalview.ws.jws2.Jws2Discoverer;
107 import jalview.ws.jws2.dm.AAConSettings;
108 import jalview.ws.jws2.jabaws2.Jws2Instance;
109 import jalview.ws.params.ArgumentI;
110 import jalview.ws.params.AutoCalcSetting;
111 import jalview.ws.params.WsParamSetI;
113 import java.awt.Color;
114 import java.awt.Rectangle;
115 import java.io.BufferedReader;
116 import java.io.DataInputStream;
117 import java.io.DataOutputStream;
119 import java.io.FileInputStream;
120 import java.io.FileOutputStream;
121 import java.io.IOException;
122 import java.io.InputStreamReader;
123 import java.io.OutputStreamWriter;
124 import java.io.PrintWriter;
125 import java.lang.reflect.InvocationTargetException;
126 import java.net.MalformedURLException;
128 import java.util.ArrayList;
129 import java.util.Arrays;
130 import java.util.Collections;
131 import java.util.Enumeration;
132 import java.util.HashMap;
133 import java.util.HashSet;
134 import java.util.Hashtable;
135 import java.util.IdentityHashMap;
136 import java.util.Iterator;
137 import java.util.LinkedHashMap;
138 import java.util.List;
139 import java.util.Map;
140 import java.util.Map.Entry;
141 import java.util.Set;
142 import java.util.Vector;
143 import java.util.jar.JarEntry;
144 import java.util.jar.JarInputStream;
145 import java.util.jar.JarOutputStream;
147 import javax.swing.JInternalFrame;
148 import javax.swing.SwingUtilities;
150 import org.exolab.castor.xml.Marshaller;
151 import org.exolab.castor.xml.Unmarshaller;
154 * Write out the current jalview desktop state as a Jalview XML stream.
156 * Note: the vamsas objects referred to here are primitive versions of the
157 * VAMSAS project schema elements - they are not the same and most likely never
161 * @version $Revision: 1.134 $
163 public class Jalview2XML
165 private static final String VIEWER_PREFIX = "viewer_";
167 private static final String RNA_PREFIX = "rna_";
169 private static final String UTF_8 = "UTF-8";
171 // use this with nextCounter() to make unique names for entities
172 private int counter = 0;
175 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
176 * of sequence objects are created.
178 IdentityHashMap<SequenceI, String> seqsToIds = null;
181 * jalview XML Sequence ID to jalview sequence object reference (both dataset
182 * and alignment sequences. Populated as XML reps of sequence objects are
185 Map<String, SequenceI> seqRefIds = null;
187 Map<String, SequenceI> incompleteSeqs = null;
189 List<SeqFref> frefedSequence = null;
191 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
194 * Map of reconstructed AlignFrame objects that appear to have come from
195 * SplitFrame objects (have a dna/protein complement view).
197 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
200 * Map from displayed rna structure models to their saved session state jar
203 private Map<RnaModel, String> rnaSessions = new HashMap<>();
206 * create/return unique hash string for sq
209 * @return new or existing unique string for sq
211 String seqHash(SequenceI sq)
213 if (seqsToIds == null)
217 if (seqsToIds.containsKey(sq))
219 return seqsToIds.get(sq);
223 // create sequential key
224 String key = "sq" + (seqsToIds.size() + 1);
225 key = makeHashCode(sq, key); // check we don't have an external reference
227 seqsToIds.put(sq, key);
234 if (seqsToIds == null)
236 seqsToIds = new IdentityHashMap<>();
238 if (seqRefIds == null)
240 seqRefIds = new HashMap<>();
242 if (incompleteSeqs == null)
244 incompleteSeqs = new HashMap<>();
246 if (frefedSequence == null)
248 frefedSequence = new ArrayList<>();
256 public Jalview2XML(boolean raiseGUI)
258 this.raiseGUI = raiseGUI;
262 * base class for resolving forward references to sequences by their ID
267 abstract class SeqFref
273 public SeqFref(String _sref, String type)
279 public String getSref()
284 public SequenceI getSrefSeq()
286 return seqRefIds.get(sref);
289 public boolean isResolvable()
291 return seqRefIds.get(sref) != null;
294 public SequenceI getSrefDatasetSeq()
296 SequenceI sq = seqRefIds.get(sref);
299 while (sq.getDatasetSequence() != null)
301 sq = sq.getDatasetSequence();
308 * @return true if the forward reference was fully resolved
310 abstract boolean resolve();
313 public String toString()
315 return type + " reference to " + sref;
320 * create forward reference for a mapping
326 public SeqFref newMappingRef(final String sref,
327 final jalview.datamodel.Mapping _jmap)
329 SeqFref fref = new SeqFref(sref, "Mapping")
331 public jalview.datamodel.Mapping jmap = _jmap;
336 SequenceI seq = getSrefDatasetSeq();
348 public SeqFref newAlcodMapRef(final String sref,
349 final AlignedCodonFrame _cf,
350 final jalview.datamodel.Mapping _jmap)
353 SeqFref fref = new SeqFref(sref, "Codon Frame")
355 AlignedCodonFrame cf = _cf;
357 public jalview.datamodel.Mapping mp = _jmap;
360 public boolean isResolvable()
362 return super.isResolvable() && mp.getTo() != null;
368 SequenceI seq = getSrefDatasetSeq();
373 cf.addMap(seq, mp.getTo(), mp.getMap());
380 public void resolveFrefedSequences()
382 Iterator<SeqFref> nextFref = frefedSequence.iterator();
383 int toresolve = frefedSequence.size();
384 int unresolved = 0, failedtoresolve = 0;
385 while (nextFref.hasNext())
387 SeqFref ref = nextFref.next();
388 if (ref.isResolvable())
400 } catch (Exception x)
403 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
416 System.err.println("Jalview Project Import: There were " + unresolved
417 + " forward references left unresolved on the stack.");
419 if (failedtoresolve > 0)
421 System.err.println("SERIOUS! " + failedtoresolve
422 + " resolvable forward references failed to resolve.");
424 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
427 "Jalview Project Import: There are " + incompleteSeqs.size()
428 + " sequences which may have incomplete metadata.");
429 if (incompleteSeqs.size() < 10)
431 for (SequenceI s : incompleteSeqs.values())
433 System.err.println(s.toString());
439 "Too many to report. Skipping output of incomplete sequences.");
445 * This maintains a map of viewports, the key being the seqSetId. Important to
446 * set historyItem and redoList for multiple views
448 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
450 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
452 String uniqueSetSuffix = "";
455 * List of pdbfiles added to Jar
457 List<String> pdbfiles = null;
459 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
460 public void saveState(File statefile)
462 FileOutputStream fos = null;
465 fos = new FileOutputStream(statefile);
466 JarOutputStream jout = new JarOutputStream(fos);
469 } catch (Exception e)
471 // TODO: inform user of the problem - they need to know if their data was
473 if (errorMessage == null)
475 errorMessage = "Couldn't write Jalview Archive to output file '"
476 + statefile + "' - See console error log for details";
480 errorMessage += "(output file was '" + statefile + "')";
490 } catch (IOException e)
500 * Writes a jalview project archive to the given Jar output stream.
504 public void saveState(JarOutputStream jout)
506 AlignFrame[] frames = Desktop.getAlignFrames();
512 saveAllFrames(Arrays.asList(frames), jout);
516 * core method for storing state for a set of AlignFrames.
519 * - frames involving all data to be exported (including containing
522 * - project output stream
524 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
526 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
529 * ensure cached data is clear before starting
531 // todo tidy up seqRefIds, seqsToIds initialisation / reset
533 splitFrameCandidates.clear();
538 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
539 // //////////////////////////////////////////////////
541 List<String> shortNames = new ArrayList<>();
542 List<String> viewIds = new ArrayList<>();
545 for (int i = frames.size() - 1; i > -1; i--)
547 AlignFrame af = frames.get(i);
549 if (skipList != null && skipList
550 .containsKey(af.getViewport().getSequenceSetId()))
555 String shortName = makeFilename(af, shortNames);
557 int ap, apSize = af.alignPanels.size();
559 for (ap = 0; ap < apSize; ap++)
561 AlignmentPanel apanel = af.alignPanels.get(ap);
562 String fileName = apSize == 1 ? shortName : ap + shortName;
563 if (!fileName.endsWith(".xml"))
565 fileName = fileName + ".xml";
568 saveState(apanel, fileName, jout, viewIds);
570 String dssid = getDatasetIdRef(
571 af.getViewport().getAlignment().getDataset());
572 if (!dsses.containsKey(dssid))
574 dsses.put(dssid, af);
579 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
585 } catch (Exception foo)
590 } catch (Exception ex)
592 // TODO: inform user of the problem - they need to know if their data was
594 if (errorMessage == null)
596 errorMessage = "Couldn't write Jalview Archive - see error output for details";
598 ex.printStackTrace();
603 * Generates a distinct file name, based on the title of the AlignFrame, by
604 * appending _n for increasing n until an unused name is generated. The new
605 * name (without its extension) is added to the list.
609 * @return the generated name, with .xml extension
611 protected String makeFilename(AlignFrame af, List<String> namesUsed)
613 String shortName = af.getTitle();
615 if (shortName.indexOf(File.separatorChar) > -1)
617 shortName = shortName
618 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
623 while (namesUsed.contains(shortName))
625 if (shortName.endsWith("_" + (count - 1)))
627 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
630 shortName = shortName.concat("_" + count);
634 namesUsed.add(shortName);
636 if (!shortName.endsWith(".xml"))
638 shortName = shortName + ".xml";
643 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
644 public boolean saveAlignment(AlignFrame af, String jarFile,
649 FileOutputStream fos = new FileOutputStream(jarFile);
650 JarOutputStream jout = new JarOutputStream(fos);
651 List<AlignFrame> frames = new ArrayList<>();
653 // resolve splitframes
654 if (af.getViewport().getCodingComplement() != null)
656 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
662 saveAllFrames(frames, jout);
666 } catch (Exception foo)
672 } catch (Exception ex)
674 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
675 ex.printStackTrace();
680 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
681 String fileName, JarOutputStream jout)
684 for (String dssids : dsses.keySet())
686 AlignFrame _af = dsses.get(dssids);
687 String jfileName = fileName + " Dataset for " + _af.getTitle();
688 if (!jfileName.endsWith(".xml"))
690 jfileName = jfileName + ".xml";
692 saveState(_af.alignPanel, jfileName, true, jout, null);
697 * create a JalviewModel from an alignment view and marshall it to a
701 * panel to create jalview model for
703 * name of alignment panel written to output stream
710 public JalviewModel saveState(AlignmentPanel ap, String fileName,
711 JarOutputStream jout, List<String> viewIds)
713 return saveState(ap, fileName, false, jout, viewIds);
717 * create a JalviewModel from an alignment view and marshall it to a
721 * panel to create jalview model for
723 * name of alignment panel written to output stream
725 * when true, only write the dataset for the alignment, not the data
726 * associated with the view.
732 public JalviewModel saveState(AlignmentPanel ap, String fileName,
733 boolean storeDS, JarOutputStream jout, List<String> viewIds)
737 viewIds = new ArrayList<>();
742 List<UserColourScheme> userColours = new ArrayList<>();
744 AlignViewport av = ap.av;
745 ViewportRanges vpRanges = av.getRanges();
747 JalviewModel object = new JalviewModel();
748 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
750 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
752 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
755 * rjal is full height alignment, jal is actual alignment with full metadata
756 * but excludes hidden sequences.
758 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
760 if (av.hasHiddenRows())
762 rjal = jal.getHiddenSequences().getFullAlignment();
765 SequenceSet vamsasSet = new SequenceSet();
767 JalviewModelSequence jms = new JalviewModelSequence();
769 vamsasSet.setGapChar(jal.getGapCharacter() + "");
771 if (jal.getDataset() != null)
773 // dataset id is the dataset's hashcode
774 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
777 // switch jal and the dataset
778 jal = jal.getDataset();
782 if (jal.getProperties() != null)
784 Enumeration en = jal.getProperties().keys();
785 while (en.hasMoreElements())
787 String key = en.nextElement().toString();
788 SequenceSetProperties ssp = new SequenceSetProperties();
790 ssp.setValue(jal.getProperties().get(key).toString());
791 vamsasSet.addSequenceSetProperties(ssp);
796 Set<String> calcIdSet = new HashSet<>();
797 // record the set of vamsas sequence XML POJO we create.
798 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
800 for (final SequenceI jds : rjal.getSequences())
802 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
803 : jds.getDatasetSequence();
804 String id = seqHash(jds);
805 if (vamsasSetIds.get(id) == null)
807 if (seqRefIds.get(id) != null && !storeDS)
809 // This happens for two reasons: 1. multiple views are being
811 // 2. the hashCode has collided with another sequence's code. This
813 // HAPPEN! (PF00072.15.stk does this)
814 // JBPNote: Uncomment to debug writing out of files that do not read
815 // back in due to ArrayOutOfBoundExceptions.
816 // System.err.println("vamsasSeq backref: "+id+"");
817 // System.err.println(jds.getName()+"
818 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
819 // System.err.println("Hashcode: "+seqHash(jds));
820 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
821 // System.err.println(rsq.getName()+"
822 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
823 // System.err.println("Hashcode: "+seqHash(rsq));
827 vamsasSeq = createVamsasSequence(id, jds);
828 vamsasSet.addSequence(vamsasSeq);
829 vamsasSetIds.put(id, vamsasSeq);
830 seqRefIds.put(id, jds);
834 jseq.setStart(jds.getStart());
835 jseq.setEnd(jds.getEnd());
836 jseq.setColour(av.getSequenceColour(jds).getRGB());
838 jseq.setId(id); // jseq id should be a string not a number
841 // Store any sequences this sequence represents
842 if (av.hasHiddenRows())
844 // use rjal, contains the full height alignment
846 av.getAlignment().getHiddenSequences().isHidden(jds));
848 if (av.isHiddenRepSequence(jds))
850 jalview.datamodel.SequenceI[] reps = av
851 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
853 for (int h = 0; h < reps.length; h++)
857 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
862 // mark sequence as reference - if it is the reference for this view
865 jseq.setViewreference(jds == jal.getSeqrep());
869 // TODO: omit sequence features from each alignment view's XML dump if we
870 // are storing dataset
871 List<jalview.datamodel.SequenceFeature> sfs = jds
872 .getSequenceFeatures();
873 for (SequenceFeature sf : sfs)
875 Features features = new Features();
877 features.setBegin(sf.getBegin());
878 features.setEnd(sf.getEnd());
879 features.setDescription(sf.getDescription());
880 features.setType(sf.getType());
881 features.setFeatureGroup(sf.getFeatureGroup());
882 features.setScore(sf.getScore());
883 if (sf.links != null)
885 for (int l = 0; l < sf.links.size(); l++)
887 OtherData keyValue = new OtherData();
888 keyValue.setKey("LINK_" + l);
889 keyValue.setValue(sf.links.elementAt(l).toString());
890 features.addOtherData(keyValue);
893 if (sf.otherDetails != null)
896 * save feature attributes, which may be simple strings or
897 * map valued (have sub-attributes)
899 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
901 String key = entry.getKey();
902 Object value = entry.getValue();
903 if (value instanceof Map<?, ?>)
905 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
908 OtherData otherData = new OtherData();
909 otherData.setKey(key);
910 otherData.setKey2(subAttribute.getKey());
911 otherData.setValue(subAttribute.getValue().toString());
912 features.addOtherData(otherData);
917 OtherData otherData = new OtherData();
918 otherData.setKey(key);
919 otherData.setValue(value.toString());
920 features.addOtherData(otherData);
925 jseq.addFeatures(features);
928 if (jdatasq.getAllPDBEntries() != null)
930 Enumeration en = jdatasq.getAllPDBEntries().elements();
931 while (en.hasMoreElements())
933 Pdbids pdb = new Pdbids();
934 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
937 String pdbId = entry.getId();
939 pdb.setType(entry.getType());
942 * Store any structure views associated with this sequence. This
943 * section copes with duplicate entries in the project, so a dataset
944 * only view *should* be coped with sensibly.
946 // This must have been loaded, is it still visible?
947 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
948 String matchedFile = null;
949 for (int f = frames.length - 1; f > -1; f--)
951 if (frames[f] instanceof StructureViewerBase)
953 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
954 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
955 matchedFile, viewFrame);
957 * Only store each structure viewer's state once in the project
958 * jar. First time through only (storeDS==false)
960 String viewId = viewFrame.getViewId();
961 if (!storeDS && !viewIds.contains(viewId))
966 String viewerState = viewFrame.getStateInfo();
967 writeJarEntry(jout, getViewerJarEntryName(viewId),
968 viewerState.getBytes());
969 } catch (IOException e)
972 "Error saving viewer state: " + e.getMessage());
978 if (matchedFile != null || entry.getFile() != null)
980 if (entry.getFile() != null)
983 matchedFile = entry.getFile();
985 pdb.setFile(matchedFile); // entry.getFile());
986 if (pdbfiles == null)
988 pdbfiles = new ArrayList<>();
991 if (!pdbfiles.contains(pdbId))
994 copyFileToJar(jout, matchedFile, pdbId);
998 Enumeration<String> props = entry.getProperties();
999 if (props.hasMoreElements())
1001 PdbentryItem item = new PdbentryItem();
1002 while (props.hasMoreElements())
1004 Property prop = new Property();
1005 String key = props.nextElement();
1007 prop.setValue(entry.getProperty(key).toString());
1008 item.addProperty(prop);
1010 pdb.addPdbentryItem(item);
1013 jseq.addPdbids(pdb);
1017 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1022 if (!storeDS && av.hasHiddenRows())
1024 jal = av.getAlignment();
1028 if (storeDS && jal.getCodonFrames() != null)
1030 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1031 for (AlignedCodonFrame acf : jac)
1033 AlcodonFrame alc = new AlcodonFrame();
1034 if (acf.getProtMappings() != null
1035 && acf.getProtMappings().length > 0)
1037 boolean hasMap = false;
1038 SequenceI[] dnas = acf.getdnaSeqs();
1039 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1040 for (int m = 0; m < pmaps.length; m++)
1042 AlcodMap alcmap = new AlcodMap();
1043 alcmap.setDnasq(seqHash(dnas[m]));
1045 createVamsasMapping(pmaps[m], dnas[m], null, false));
1046 alc.addAlcodMap(alcmap);
1051 vamsasSet.addAlcodonFrame(alc);
1054 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1056 // AlcodonFrame alc = new AlcodonFrame();
1057 // vamsasSet.addAlcodonFrame(alc);
1058 // for (int p = 0; p < acf.aaWidth; p++)
1060 // Alcodon cmap = new Alcodon();
1061 // if (acf.codons[p] != null)
1063 // // Null codons indicate a gapped column in the translated peptide
1065 // cmap.setPos1(acf.codons[p][0]);
1066 // cmap.setPos2(acf.codons[p][1]);
1067 // cmap.setPos3(acf.codons[p][2]);
1069 // alc.addAlcodon(cmap);
1071 // if (acf.getProtMappings() != null
1072 // && acf.getProtMappings().length > 0)
1074 // SequenceI[] dnas = acf.getdnaSeqs();
1075 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1076 // for (int m = 0; m < pmaps.length; m++)
1078 // AlcodMap alcmap = new AlcodMap();
1079 // alcmap.setDnasq(seqHash(dnas[m]));
1080 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1082 // alc.addAlcodMap(alcmap);
1089 // /////////////////////////////////
1090 if (!storeDS && av.getCurrentTree() != null)
1092 // FIND ANY ASSOCIATED TREES
1093 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1094 if (Desktop.desktop != null)
1096 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1098 for (int t = 0; t < frames.length; t++)
1100 if (frames[t] instanceof TreePanel)
1102 TreePanel tp = (TreePanel) frames[t];
1104 if (tp.treeCanvas.av.getAlignment() == jal)
1106 Tree tree = new Tree();
1107 tree.setTitle(tp.getTitle());
1108 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1109 tree.setNewick(tp.getTree().print());
1110 tree.setThreshold(tp.treeCanvas.threshold);
1112 tree.setFitToWindow(tp.fitToWindow.getState());
1113 tree.setFontName(tp.getTreeFont().getName());
1114 tree.setFontSize(tp.getTreeFont().getSize());
1115 tree.setFontStyle(tp.getTreeFont().getStyle());
1116 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1118 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1119 tree.setShowDistances(tp.distanceMenu.getState());
1121 tree.setHeight(tp.getHeight());
1122 tree.setWidth(tp.getWidth());
1123 tree.setXpos(tp.getX());
1124 tree.setYpos(tp.getY());
1125 tree.setId(makeHashCode(tp, null));
1126 tree.setLinkToAllViews(tp.treeCanvas.applyToAllViews);
1136 * store forward refs from an annotationRow to any groups
1138 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1141 for (SequenceI sq : jal.getSequences())
1143 // Store annotation on dataset sequences only
1144 AlignmentAnnotation[] aa = sq.getAnnotation();
1145 if (aa != null && aa.length > 0)
1147 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1154 if (jal.getAlignmentAnnotation() != null)
1156 // Store the annotation shown on the alignment.
1157 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1158 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1163 if (jal.getGroups() != null)
1165 JGroup[] groups = new JGroup[jal.getGroups().size()];
1167 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1169 JGroup jGroup = new JGroup();
1170 groups[++i] = jGroup;
1172 jGroup.setStart(sg.getStartRes());
1173 jGroup.setEnd(sg.getEndRes());
1174 jGroup.setName(sg.getName());
1175 if (groupRefs.containsKey(sg))
1177 // group has references so set its ID field
1178 jGroup.setId(groupRefs.get(sg));
1180 ColourSchemeI colourScheme = sg.getColourScheme();
1181 if (colourScheme != null)
1183 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1184 if (groupColourScheme.conservationApplied())
1186 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1188 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1191 setUserColourScheme(colourScheme, userColours, jms));
1195 jGroup.setColour(colourScheme.getSchemeName());
1198 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1200 jGroup.setColour("AnnotationColourGradient");
1201 jGroup.setAnnotationColours(constructAnnotationColours(
1202 (jalview.schemes.AnnotationColourGradient) colourScheme,
1205 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1208 setUserColourScheme(colourScheme, userColours, jms));
1212 jGroup.setColour(colourScheme.getSchemeName());
1215 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1218 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1219 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1220 jGroup.setDisplayText(sg.getDisplayText());
1221 jGroup.setColourText(sg.getColourText());
1222 jGroup.setTextCol1(sg.textColour.getRGB());
1223 jGroup.setTextCol2(sg.textColour2.getRGB());
1224 jGroup.setTextColThreshold(sg.thresholdTextColour);
1225 jGroup.setShowUnconserved(sg.getShowNonconserved());
1226 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1227 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1228 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1229 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1230 for (SequenceI seq : sg.getSequences())
1232 jGroup.addSeq(seqHash(seq));
1236 jms.setJGroup(groups);
1240 // /////////SAVE VIEWPORT
1241 Viewport view = new Viewport();
1242 view.setTitle(ap.alignFrame.getTitle());
1243 view.setSequenceSetId(
1244 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1245 view.setId(av.getViewId());
1246 if (av.getCodingComplement() != null)
1248 view.setComplementId(av.getCodingComplement().getViewId());
1250 view.setViewName(av.viewName);
1251 view.setGatheredViews(av.isGatherViewsHere());
1253 Rectangle size = ap.av.getExplodedGeometry();
1254 Rectangle position = size;
1257 size = ap.alignFrame.getBounds();
1258 if (av.getCodingComplement() != null)
1260 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1268 view.setXpos(position.x);
1269 view.setYpos(position.y);
1271 view.setWidth(size.width);
1272 view.setHeight(size.height);
1274 view.setStartRes(vpRanges.getStartRes());
1275 view.setStartSeq(vpRanges.getStartSeq());
1277 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1279 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1283 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1285 AnnotationColours ac = constructAnnotationColours(
1286 (jalview.schemes.AnnotationColourGradient) av
1287 .getGlobalColourScheme(),
1290 view.setAnnotationColours(ac);
1291 view.setBgColour("AnnotationColourGradient");
1295 view.setBgColour(ColourSchemeProperty
1296 .getColourName(av.getGlobalColourScheme()));
1299 ResidueShaderI vcs = av.getResidueShading();
1300 ColourSchemeI cs = av.getGlobalColourScheme();
1304 if (vcs.conservationApplied())
1306 view.setConsThreshold(vcs.getConservationInc());
1307 if (cs instanceof jalview.schemes.UserColourScheme)
1309 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1312 view.setPidThreshold(vcs.getThreshold());
1315 view.setConservationSelected(av.getConservationSelected());
1316 view.setPidSelected(av.getAbovePIDThreshold());
1317 view.setFontName(av.font.getName());
1318 view.setFontSize(av.font.getSize());
1319 view.setFontStyle(av.font.getStyle());
1320 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1321 view.setRenderGaps(av.isRenderGaps());
1322 view.setShowAnnotation(av.isShowAnnotation());
1323 view.setShowBoxes(av.getShowBoxes());
1324 view.setShowColourText(av.getColourText());
1325 view.setShowFullId(av.getShowJVSuffix());
1326 view.setRightAlignIds(av.isRightAlignIds());
1327 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1328 view.setShowText(av.getShowText());
1329 view.setShowUnconserved(av.getShowUnconserved());
1330 view.setWrapAlignment(av.getWrapAlignment());
1331 view.setTextCol1(av.getTextColour().getRGB());
1332 view.setTextCol2(av.getTextColour2().getRGB());
1333 view.setTextColThreshold(av.getThresholdTextColour());
1334 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1335 view.setShowSequenceLogo(av.isShowSequenceLogo());
1336 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1337 view.setShowGroupConsensus(av.isShowGroupConsensus());
1338 view.setShowGroupConservation(av.isShowGroupConservation());
1339 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1340 view.setShowDbRefTooltip(av.isShowDBRefs());
1341 view.setFollowHighlight(av.isFollowHighlight());
1342 view.setFollowSelection(av.followSelection);
1343 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1344 if (av.getFeaturesDisplayed() != null)
1346 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1348 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1349 .getFeatureRenderer();
1350 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1352 Vector<String> settingsAdded = new Vector<>();
1353 if (renderOrder != null)
1355 for (String featureType : renderOrder)
1357 Setting setting = new Setting();
1358 setting.setType(featureType);
1361 * save any filter for the feature type
1363 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1364 if (filter != null) {
1365 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1366 FeatureMatcherI firstFilter = filters.next();
1367 setting.setMatcherSet(Jalview2XML.marshalFilter(
1368 firstFilter, filters, filter.isAnded()));
1372 * save colour scheme for the feature type
1374 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1375 if (!fcol.isSimpleColour())
1377 setting.setColour(fcol.getMaxColour().getRGB());
1378 setting.setMincolour(fcol.getMinColour().getRGB());
1379 setting.setMin(fcol.getMin());
1380 setting.setMax(fcol.getMax());
1381 setting.setColourByLabel(fcol.isColourByLabel());
1382 if (fcol.isColourByAttribute())
1384 setting.setAttributeName(fcol.getAttributeName());
1386 setting.setAutoScale(fcol.isAutoScaled());
1387 setting.setThreshold(fcol.getThreshold());
1388 Color noColour = fcol.getNoColour();
1389 if (noColour == null)
1391 setting.setNoValueColour(NoValueColour.NONE);
1393 else if (noColour.equals(fcol.getMaxColour()))
1395 setting.setNoValueColour(NoValueColour.MAX);
1399 setting.setNoValueColour(NoValueColour.MIN);
1401 // -1 = No threshold, 0 = Below, 1 = Above
1402 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1403 : (fcol.isBelowThreshold() ? 0 : -1));
1407 setting.setColour(fcol.getColour().getRGB());
1411 av.getFeaturesDisplayed().isVisible(featureType));
1413 .getOrder(featureType);
1416 setting.setOrder(rorder);
1418 fs.addSetting(setting);
1419 settingsAdded.addElement(featureType);
1423 // is groups actually supposed to be a map here ?
1424 Iterator<String> en = fr.getFeatureGroups().iterator();
1425 Vector<String> groupsAdded = new Vector<>();
1426 while (en.hasNext())
1428 String grp = en.next();
1429 if (groupsAdded.contains(grp))
1433 Group g = new Group();
1435 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1438 groupsAdded.addElement(grp);
1440 jms.setFeatureSettings(fs);
1443 if (av.hasHiddenColumns())
1445 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1446 .getHiddenColumns();
1449 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1453 Iterator<int[]> hiddenRegions = hidden.iterator();
1454 while (hiddenRegions.hasNext())
1456 int[] region = hiddenRegions.next();
1457 HiddenColumns hc = new HiddenColumns();
1458 hc.setStart(region[0]);
1459 hc.setEnd(region[1]);
1460 view.addHiddenColumns(hc);
1464 if (calcIdSet.size() > 0)
1466 for (String calcId : calcIdSet)
1468 if (calcId.trim().length() > 0)
1470 CalcIdParam cidp = createCalcIdParam(calcId, av);
1471 // Some calcIds have no parameters.
1474 view.addCalcIdParam(cidp);
1480 jms.addViewport(view);
1482 object.setJalviewModelSequence(jms);
1483 object.getVamsasModel().addSequenceSet(vamsasSet);
1485 if (jout != null && fileName != null)
1487 // We may not want to write the object to disk,
1488 // eg we can copy the alignViewport to a new view object
1489 // using save and then load
1492 System.out.println("Writing jar entry " + fileName);
1493 JarEntry entry = new JarEntry(fileName);
1494 jout.putNextEntry(entry);
1495 PrintWriter pout = new PrintWriter(
1496 new OutputStreamWriter(jout, UTF_8));
1497 Marshaller marshaller = new Marshaller(pout);
1498 marshaller.marshal(object);
1501 } catch (Exception ex)
1503 // TODO: raise error in GUI if marshalling failed.
1504 ex.printStackTrace();
1511 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1512 * for each viewer, with
1514 * <li>viewer geometry (position, size, split pane divider location)</li>
1515 * <li>index of the selected structure in the viewer (currently shows gapped
1517 * <li>the id of the annotation holding RNA secondary structure</li>
1518 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1520 * Varna viewer state is also written out (in native Varna XML) to separate
1521 * project jar entries. A separate entry is written for each RNA structure
1522 * displayed, with the naming convention
1524 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1532 * @param storeDataset
1534 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1535 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1536 boolean storeDataset)
1538 if (Desktop.desktop == null)
1542 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1543 for (int f = frames.length - 1; f > -1; f--)
1545 if (frames[f] instanceof AppVarna)
1547 AppVarna varna = (AppVarna) frames[f];
1549 * link the sequence to every viewer that is showing it and is linked to
1550 * its alignment panel
1552 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1554 String viewId = varna.getViewId();
1555 RnaViewer rna = new RnaViewer();
1556 rna.setViewId(viewId);
1557 rna.setTitle(varna.getTitle());
1558 rna.setXpos(varna.getX());
1559 rna.setYpos(varna.getY());
1560 rna.setWidth(varna.getWidth());
1561 rna.setHeight(varna.getHeight());
1562 rna.setDividerLocation(varna.getDividerLocation());
1563 rna.setSelectedRna(varna.getSelectedIndex());
1564 jseq.addRnaViewer(rna);
1567 * Store each Varna panel's state once in the project per sequence.
1568 * First time through only (storeDataset==false)
1570 // boolean storeSessions = false;
1571 // String sequenceViewId = viewId + seqsToIds.get(jds);
1572 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1574 // viewIds.add(sequenceViewId);
1575 // storeSessions = true;
1577 for (RnaModel model : varna.getModels())
1579 if (model.seq == jds)
1582 * VARNA saves each view (sequence or alignment secondary
1583 * structure, gapped or trimmed) as a separate XML file
1585 String jarEntryName = rnaSessions.get(model);
1586 if (jarEntryName == null)
1589 String varnaStateFile = varna.getStateInfo(model.rna);
1590 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1591 copyFileToJar(jout, varnaStateFile, jarEntryName);
1592 rnaSessions.put(model, jarEntryName);
1594 SecondaryStructure ss = new SecondaryStructure();
1595 String annotationId = varna.getAnnotation(jds).annotationId;
1596 ss.setAnnotationId(annotationId);
1597 ss.setViewerState(jarEntryName);
1598 ss.setGapped(model.gapped);
1599 ss.setTitle(model.title);
1600 rna.addSecondaryStructure(ss);
1609 * Copy the contents of a file to a new entry added to the output jar
1613 * @param jarEntryName
1615 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1616 String jarEntryName)
1618 DataInputStream dis = null;
1621 File file = new File(infilePath);
1622 if (file.exists() && jout != null)
1624 dis = new DataInputStream(new FileInputStream(file));
1625 byte[] data = new byte[(int) file.length()];
1626 dis.readFully(data);
1627 writeJarEntry(jout, jarEntryName, data);
1629 } catch (Exception ex)
1631 ex.printStackTrace();
1639 } catch (IOException e)
1648 * Write the data to a new entry of given name in the output jar file
1651 * @param jarEntryName
1653 * @throws IOException
1655 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1656 byte[] data) throws IOException
1660 System.out.println("Writing jar entry " + jarEntryName);
1661 jout.putNextEntry(new JarEntry(jarEntryName));
1662 DataOutputStream dout = new DataOutputStream(jout);
1663 dout.write(data, 0, data.length);
1670 * Save the state of a structure viewer
1675 * the archive XML element under which to save the state
1678 * @param matchedFile
1682 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1683 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1684 String matchedFile, StructureViewerBase viewFrame)
1686 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1689 * Look for any bindings for this viewer to the PDB file of interest
1690 * (including part matches excluding chain id)
1692 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1694 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1695 final String pdbId = pdbentry.getId();
1696 if (!pdbId.equals(entry.getId())
1697 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1698 .startsWith(pdbId.toLowerCase())))
1701 * not interested in a binding to a different PDB entry here
1705 if (matchedFile == null)
1707 matchedFile = pdbentry.getFile();
1709 else if (!matchedFile.equals(pdbentry.getFile()))
1712 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1713 + pdbentry.getFile());
1717 // can get at it if the ID
1718 // match is ambiguous (e.g.
1721 for (int smap = 0; smap < viewFrame.getBinding()
1722 .getSequence()[peid].length; smap++)
1724 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1725 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1727 StructureState state = new StructureState();
1728 state.setVisible(true);
1729 state.setXpos(viewFrame.getX());
1730 state.setYpos(viewFrame.getY());
1731 state.setWidth(viewFrame.getWidth());
1732 state.setHeight(viewFrame.getHeight());
1733 final String viewId = viewFrame.getViewId();
1734 state.setViewId(viewId);
1735 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1736 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1737 state.setColourByJmol(viewFrame.isColouredByViewer());
1738 state.setType(viewFrame.getViewerType().toString());
1739 pdb.addStructureState(state);
1747 * Populates the AnnotationColours xml for save. This captures the settings of
1748 * the options in the 'Colour by Annotation' dialog.
1751 * @param userColours
1755 private AnnotationColours constructAnnotationColours(
1756 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1757 JalviewModelSequence jms)
1759 AnnotationColours ac = new AnnotationColours();
1760 ac.setAboveThreshold(acg.getAboveThreshold());
1761 ac.setThreshold(acg.getAnnotationThreshold());
1762 // 2.10.2 save annotationId (unique) not annotation label
1763 ac.setAnnotation(acg.getAnnotation().annotationId);
1764 if (acg.getBaseColour() instanceof UserColourScheme)
1767 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1772 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1775 ac.setMaxColour(acg.getMaxColour().getRGB());
1776 ac.setMinColour(acg.getMinColour().getRGB());
1777 ac.setPerSequence(acg.isSeqAssociated());
1778 ac.setPredefinedColours(acg.isPredefinedColours());
1782 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1783 IdentityHashMap<SequenceGroup, String> groupRefs,
1784 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1785 SequenceSet vamsasSet)
1788 for (int i = 0; i < aa.length; i++)
1790 Annotation an = new Annotation();
1792 AlignmentAnnotation annotation = aa[i];
1793 if (annotation.annotationId != null)
1795 annotationIds.put(annotation.annotationId, annotation);
1798 an.setId(annotation.annotationId);
1800 an.setVisible(annotation.visible);
1802 an.setDescription(annotation.description);
1804 if (annotation.sequenceRef != null)
1806 // 2.9 JAL-1781 xref on sequence id rather than name
1807 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1809 if (annotation.groupRef != null)
1811 String groupIdr = groupRefs.get(annotation.groupRef);
1812 if (groupIdr == null)
1814 // make a locally unique String
1815 groupRefs.put(annotation.groupRef,
1816 groupIdr = ("" + System.currentTimeMillis()
1817 + annotation.groupRef.getName()
1818 + groupRefs.size()));
1820 an.setGroupRef(groupIdr.toString());
1823 // store all visualization attributes for annotation
1824 an.setGraphHeight(annotation.graphHeight);
1825 an.setCentreColLabels(annotation.centreColLabels);
1826 an.setScaleColLabels(annotation.scaleColLabel);
1827 an.setShowAllColLabels(annotation.showAllColLabels);
1828 an.setBelowAlignment(annotation.belowAlignment);
1830 if (annotation.graph > 0)
1833 an.setGraphType(annotation.graph);
1834 an.setGraphGroup(annotation.graphGroup);
1835 if (annotation.getThreshold() != null)
1837 ThresholdLine line = new ThresholdLine();
1838 line.setLabel(annotation.getThreshold().label);
1839 line.setValue(annotation.getThreshold().value);
1840 line.setColour(annotation.getThreshold().colour.getRGB());
1841 an.setThresholdLine(line);
1849 an.setLabel(annotation.label);
1851 if (annotation == av.getAlignmentQualityAnnot()
1852 || annotation == av.getAlignmentConservationAnnotation()
1853 || annotation == av.getAlignmentConsensusAnnotation()
1854 || annotation.autoCalculated)
1856 // new way of indicating autocalculated annotation -
1857 an.setAutoCalculated(annotation.autoCalculated);
1859 if (annotation.hasScore())
1861 an.setScore(annotation.getScore());
1864 if (annotation.getCalcId() != null)
1866 calcIdSet.add(annotation.getCalcId());
1867 an.setCalcId(annotation.getCalcId());
1869 if (annotation.hasProperties())
1871 for (String pr : annotation.getProperties())
1873 Property prop = new Property();
1875 prop.setValue(annotation.getProperty(pr));
1876 an.addProperty(prop);
1880 AnnotationElement ae;
1881 if (annotation.annotations != null)
1883 an.setScoreOnly(false);
1884 for (int a = 0; a < annotation.annotations.length; a++)
1886 if ((annotation == null) || (annotation.annotations[a] == null))
1891 ae = new AnnotationElement();
1892 if (annotation.annotations[a].description != null)
1894 ae.setDescription(annotation.annotations[a].description);
1896 if (annotation.annotations[a].displayCharacter != null)
1898 ae.setDisplayCharacter(
1899 annotation.annotations[a].displayCharacter);
1902 if (!Float.isNaN(annotation.annotations[a].value))
1904 ae.setValue(annotation.annotations[a].value);
1908 if (annotation.annotations[a].secondaryStructure > ' ')
1910 ae.setSecondaryStructure(
1911 annotation.annotations[a].secondaryStructure + "");
1914 if (annotation.annotations[a].colour != null
1915 && annotation.annotations[a].colour != java.awt.Color.black)
1917 ae.setColour(annotation.annotations[a].colour.getRGB());
1920 an.addAnnotationElement(ae);
1921 if (annotation.autoCalculated)
1923 // only write one non-null entry into the annotation row -
1924 // sufficient to get the visualization attributes necessary to
1932 an.setScoreOnly(true);
1934 if (!storeDS || (storeDS && !annotation.autoCalculated))
1936 // skip autocalculated annotation - these are only provided for
1938 vamsasSet.addAnnotation(an);
1944 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1946 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1947 if (settings != null)
1949 CalcIdParam vCalcIdParam = new CalcIdParam();
1950 vCalcIdParam.setCalcId(calcId);
1951 vCalcIdParam.addServiceURL(settings.getServiceURI());
1952 // generic URI allowing a third party to resolve another instance of the
1953 // service used for this calculation
1954 for (String urls : settings.getServiceURLs())
1956 vCalcIdParam.addServiceURL(urls);
1958 vCalcIdParam.setVersion("1.0");
1959 if (settings.getPreset() != null)
1961 WsParamSetI setting = settings.getPreset();
1962 vCalcIdParam.setName(setting.getName());
1963 vCalcIdParam.setDescription(setting.getDescription());
1967 vCalcIdParam.setName("");
1968 vCalcIdParam.setDescription("Last used parameters");
1970 // need to be able to recover 1) settings 2) user-defined presets or
1971 // recreate settings from preset 3) predefined settings provided by
1972 // service - or settings that can be transferred (or discarded)
1973 vCalcIdParam.setParameters(
1974 settings.getWsParamFile().replace("\n", "|\\n|"));
1975 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1976 // todo - decide if updateImmediately is needed for any projects.
1978 return vCalcIdParam;
1983 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1986 if (calcIdParam.getVersion().equals("1.0"))
1988 Jws2Instance service = Jws2Discoverer.getDiscoverer()
1989 .getPreferredServiceFor(calcIdParam.getServiceURL());
1990 if (service != null)
1992 WsParamSetI parmSet = null;
1995 parmSet = service.getParamStore().parseServiceParameterFile(
1996 calcIdParam.getName(), calcIdParam.getDescription(),
1997 calcIdParam.getServiceURL(),
1998 calcIdParam.getParameters().replace("|\\n|", "\n"));
1999 } catch (IOException x)
2001 warn("Couldn't parse parameter data for "
2002 + calcIdParam.getCalcId(), x);
2005 List<ArgumentI> argList = null;
2006 if (calcIdParam.getName().length() > 0)
2008 parmSet = service.getParamStore()
2009 .getPreset(calcIdParam.getName());
2010 if (parmSet != null)
2012 // TODO : check we have a good match with settings in AACon -
2013 // otherwise we'll need to create a new preset
2018 argList = parmSet.getArguments();
2021 AAConSettings settings = new AAConSettings(
2022 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2023 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2024 calcIdParam.isNeedsUpdate());
2029 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2033 throw new Error(MessageManager.formatMessage(
2034 "error.unsupported_version_calcIdparam", new Object[]
2035 { calcIdParam.toString() }));
2039 * External mapping between jalview objects and objects yielding a valid and
2040 * unique object ID string. This is null for normal Jalview project IO, but
2041 * non-null when a jalview project is being read or written as part of a
2044 IdentityHashMap jv2vobj = null;
2047 * Construct a unique ID for jvobj using either existing bindings or if none
2048 * exist, the result of the hashcode call for the object.
2051 * jalview data object
2052 * @return unique ID for referring to jvobj
2054 private String makeHashCode(Object jvobj, String altCode)
2056 if (jv2vobj != null)
2058 Object id = jv2vobj.get(jvobj);
2061 return id.toString();
2063 // check string ID mappings
2064 if (jvids2vobj != null && jvobj instanceof String)
2066 id = jvids2vobj.get(jvobj);
2070 return id.toString();
2072 // give up and warn that something has gone wrong
2073 warn("Cannot find ID for object in external mapping : " + jvobj);
2079 * return local jalview object mapped to ID, if it exists
2083 * @return null or object bound to idcode
2085 private Object retrieveExistingObj(String idcode)
2087 if (idcode != null && vobj2jv != null)
2089 return vobj2jv.get(idcode);
2095 * binding from ID strings from external mapping table to jalview data model
2098 private Hashtable vobj2jv;
2100 private Sequence createVamsasSequence(String id, SequenceI jds)
2102 return createVamsasSequence(true, id, jds, null);
2105 private Sequence createVamsasSequence(boolean recurse, String id,
2106 SequenceI jds, SequenceI parentseq)
2108 Sequence vamsasSeq = new Sequence();
2109 vamsasSeq.setId(id);
2110 vamsasSeq.setName(jds.getName());
2111 vamsasSeq.setSequence(jds.getSequenceAsString());
2112 vamsasSeq.setDescription(jds.getDescription());
2113 jalview.datamodel.DBRefEntry[] dbrefs = null;
2114 if (jds.getDatasetSequence() != null)
2116 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2120 // seqId==dsseqid so we can tell which sequences really are
2121 // dataset sequences only
2122 vamsasSeq.setDsseqid(id);
2123 dbrefs = jds.getDBRefs();
2124 if (parentseq == null)
2131 for (int d = 0; d < dbrefs.length; d++)
2133 DBRef dbref = new DBRef();
2134 dbref.setSource(dbrefs[d].getSource());
2135 dbref.setVersion(dbrefs[d].getVersion());
2136 dbref.setAccessionId(dbrefs[d].getAccessionId());
2137 if (dbrefs[d].hasMap())
2139 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2141 dbref.setMapping(mp);
2143 vamsasSeq.addDBRef(dbref);
2149 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2150 SequenceI parentseq, SequenceI jds, boolean recurse)
2153 if (jmp.getMap() != null)
2157 jalview.util.MapList mlst = jmp.getMap();
2158 List<int[]> r = mlst.getFromRanges();
2159 for (int[] range : r)
2161 MapListFrom mfrom = new MapListFrom();
2162 mfrom.setStart(range[0]);
2163 mfrom.setEnd(range[1]);
2164 mp.addMapListFrom(mfrom);
2166 r = mlst.getToRanges();
2167 for (int[] range : r)
2169 MapListTo mto = new MapListTo();
2170 mto.setStart(range[0]);
2171 mto.setEnd(range[1]);
2172 mp.addMapListTo(mto);
2174 mp.setMapFromUnit(mlst.getFromRatio());
2175 mp.setMapToUnit(mlst.getToRatio());
2176 if (jmp.getTo() != null)
2178 MappingChoice mpc = new MappingChoice();
2180 // check/create ID for the sequence referenced by getTo()
2183 SequenceI ps = null;
2184 if (parentseq != jmp.getTo()
2185 && parentseq.getDatasetSequence() != jmp.getTo())
2187 // chaining dbref rather than a handshaking one
2188 jmpid = seqHash(ps = jmp.getTo());
2192 jmpid = seqHash(ps = parentseq);
2194 mpc.setDseqFor(jmpid);
2195 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2197 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2198 seqRefIds.put(mpc.getDseqFor(), ps);
2202 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2205 mp.setMappingChoice(mpc);
2211 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2212 List<UserColourScheme> userColours, JalviewModelSequence jms)
2215 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2216 boolean newucs = false;
2217 if (!userColours.contains(ucs))
2219 userColours.add(ucs);
2222 id = "ucs" + userColours.indexOf(ucs);
2225 // actually create the scheme's entry in the XML model
2226 java.awt.Color[] colours = ucs.getColours();
2227 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2228 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2230 for (int i = 0; i < colours.length; i++)
2232 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2233 col.setName(ResidueProperties.aa[i]);
2234 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2235 jbucs.addColour(col);
2237 if (ucs.getLowerCaseColours() != null)
2239 colours = ucs.getLowerCaseColours();
2240 for (int i = 0; i < colours.length; i++)
2242 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2243 col.setName(ResidueProperties.aa[i].toLowerCase());
2244 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2245 jbucs.addColour(col);
2250 uc.setUserColourScheme(jbucs);
2251 jms.addUserColours(uc);
2257 jalview.schemes.UserColourScheme getUserColourScheme(
2258 JalviewModelSequence jms, String id)
2260 UserColours[] uc = jms.getUserColours();
2261 UserColours colours = null;
2263 for (int i = 0; i < uc.length; i++)
2265 if (uc[i].getId().equals(id))
2273 java.awt.Color[] newColours = new java.awt.Color[24];
2275 for (int i = 0; i < 24; i++)
2277 newColours[i] = new java.awt.Color(Integer.parseInt(
2278 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2281 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2284 if (colours.getUserColourScheme().getColourCount() > 24)
2286 newColours = new java.awt.Color[23];
2287 for (int i = 0; i < 23; i++)
2289 newColours[i] = new java.awt.Color(Integer.parseInt(
2290 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2293 ucs.setLowerCaseColours(newColours);
2300 * contains last error message (if any) encountered by XML loader.
2302 String errorMessage = null;
2305 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2306 * exceptions are raised during project XML parsing
2308 public boolean attemptversion1parse = true;
2311 * Load a jalview project archive from a jar file
2314 * - HTTP URL or filename
2316 public AlignFrame loadJalviewAlign(final String file)
2319 jalview.gui.AlignFrame af = null;
2323 // create list to store references for any new Jmol viewers created
2324 newStructureViewers = new Vector<>();
2325 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2326 // Workaround is to make sure caller implements the JarInputStreamProvider
2328 // so we can re-open the jar input stream for each entry.
2330 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2331 af = loadJalviewAlign(jprovider);
2332 af.setMenusForViewport();
2334 } catch (MalformedURLException e)
2336 errorMessage = "Invalid URL format for '" + file + "'";
2342 SwingUtilities.invokeAndWait(new Runnable()
2347 setLoadingFinishedForNewStructureViewers();
2350 } catch (Exception x)
2352 System.err.println("Error loading alignment: " + x.getMessage());
2358 private jarInputStreamProvider createjarInputStreamProvider(
2359 final String file) throws MalformedURLException
2362 errorMessage = null;
2363 uniqueSetSuffix = null;
2365 viewportsAdded.clear();
2366 frefedSequence = null;
2368 if (file.startsWith("http://"))
2370 url = new URL(file);
2372 final URL _url = url;
2373 return new jarInputStreamProvider()
2377 public JarInputStream getJarInputStream() throws IOException
2381 return new JarInputStream(_url.openStream());
2385 return new JarInputStream(new FileInputStream(file));
2390 public String getFilename()
2398 * Recover jalview session from a jalview project archive. Caller may
2399 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2400 * themselves. Any null fields will be initialised with default values,
2401 * non-null fields are left alone.
2406 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2408 errorMessage = null;
2409 if (uniqueSetSuffix == null)
2411 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2413 if (seqRefIds == null)
2417 AlignFrame af = null, _af = null;
2418 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2419 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2420 final String file = jprovider.getFilename();
2423 JarInputStream jin = null;
2424 JarEntry jarentry = null;
2429 jin = jprovider.getJarInputStream();
2430 for (int i = 0; i < entryCount; i++)
2432 jarentry = jin.getNextJarEntry();
2435 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2437 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2438 JalviewModel object = new JalviewModel();
2440 Unmarshaller unmar = new Unmarshaller(object);
2441 unmar.setValidation(false);
2442 object = (JalviewModel) unmar.unmarshal(in);
2443 if (true) // !skipViewport(object))
2445 _af = loadFromObject(object, file, true, jprovider);
2446 if (_af != null && object.getJalviewModelSequence()
2447 .getViewportCount() > 0)
2451 // store a reference to the first view
2454 if (_af.viewport.isGatherViewsHere())
2456 // if this is a gathered view, keep its reference since
2457 // after gathering views, only this frame will remain
2459 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2461 // Save dataset to register mappings once all resolved
2462 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2463 af.viewport.getAlignment().getDataset());
2468 else if (jarentry != null)
2470 // Some other file here.
2473 } while (jarentry != null);
2474 resolveFrefedSequences();
2475 } catch (IOException ex)
2477 ex.printStackTrace();
2478 errorMessage = "Couldn't locate Jalview XML file : " + file;
2480 "Exception whilst loading jalview XML file : " + ex + "\n");
2481 } catch (Exception ex)
2483 System.err.println("Parsing as Jalview Version 2 file failed.");
2484 ex.printStackTrace(System.err);
2485 if (attemptversion1parse)
2487 // Is Version 1 Jar file?
2490 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2491 } catch (Exception ex2)
2493 System.err.println("Exception whilst loading as jalviewXMLV1:");
2494 ex2.printStackTrace();
2498 if (Desktop.instance != null)
2500 Desktop.instance.stopLoading();
2504 System.out.println("Successfully loaded archive file");
2507 ex.printStackTrace();
2510 "Exception whilst loading jalview XML file : " + ex + "\n");
2511 } catch (OutOfMemoryError e)
2513 // Don't use the OOM Window here
2514 errorMessage = "Out of memory loading jalview XML file";
2515 System.err.println("Out of memory whilst loading jalview XML file");
2516 e.printStackTrace();
2520 * Regather multiple views (with the same sequence set id) to the frame (if
2521 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2522 * views instead of separate frames. Note this doesn't restore a state where
2523 * some expanded views in turn have tabbed views - the last "first tab" read
2524 * in will play the role of gatherer for all.
2526 for (AlignFrame fr : gatherToThisFrame.values())
2528 Desktop.instance.gatherViews(fr);
2531 restoreSplitFrames();
2532 for (AlignmentI ds : importedDatasets.keySet())
2534 if (ds.getCodonFrames() != null)
2536 StructureSelectionManager
2537 .getStructureSelectionManager(Desktop.instance)
2538 .registerMappings(ds.getCodonFrames());
2541 if (errorMessage != null)
2546 if (Desktop.instance != null)
2548 Desktop.instance.stopLoading();
2555 * Try to reconstruct and display SplitFrame windows, where each contains
2556 * complementary dna and protein alignments. Done by pairing up AlignFrame
2557 * objects (created earlier) which have complementary viewport ids associated.
2559 protected void restoreSplitFrames()
2561 List<SplitFrame> gatherTo = new ArrayList<>();
2562 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2563 Map<String, AlignFrame> dna = new HashMap<>();
2566 * Identify the DNA alignments
2568 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2571 AlignFrame af = candidate.getValue();
2572 if (af.getViewport().getAlignment().isNucleotide())
2574 dna.put(candidate.getKey().getId(), af);
2579 * Try to match up the protein complements
2581 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2584 AlignFrame af = candidate.getValue();
2585 if (!af.getViewport().getAlignment().isNucleotide())
2587 String complementId = candidate.getKey().getComplementId();
2588 // only non-null complements should be in the Map
2589 if (complementId != null && dna.containsKey(complementId))
2591 final AlignFrame dnaFrame = dna.get(complementId);
2592 SplitFrame sf = createSplitFrame(dnaFrame, af);
2593 addedToSplitFrames.add(dnaFrame);
2594 addedToSplitFrames.add(af);
2595 dnaFrame.setMenusForViewport();
2596 af.setMenusForViewport();
2597 if (af.viewport.isGatherViewsHere())
2606 * Open any that we failed to pair up (which shouldn't happen!) as
2607 * standalone AlignFrame's.
2609 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2612 AlignFrame af = candidate.getValue();
2613 if (!addedToSplitFrames.contains(af))
2615 Viewport view = candidate.getKey();
2616 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2618 af.setMenusForViewport();
2619 System.err.println("Failed to restore view " + view.getTitle()
2620 + " to split frame");
2625 * Gather back into tabbed views as flagged.
2627 for (SplitFrame sf : gatherTo)
2629 Desktop.instance.gatherViews(sf);
2632 splitFrameCandidates.clear();
2636 * Construct and display one SplitFrame holding DNA and protein alignments.
2639 * @param proteinFrame
2642 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2643 AlignFrame proteinFrame)
2645 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2646 String title = MessageManager.getString("label.linked_view_title");
2647 int width = (int) dnaFrame.getBounds().getWidth();
2648 int height = (int) (dnaFrame.getBounds().getHeight()
2649 + proteinFrame.getBounds().getHeight() + 50);
2652 * SplitFrame location is saved to both enclosed frames
2654 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2655 Desktop.addInternalFrame(splitFrame, title, width, height);
2658 * And compute cDNA consensus (couldn't do earlier with consensus as
2659 * mappings were not yet present)
2661 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2667 * check errorMessage for a valid error message and raise an error box in the
2668 * GUI or write the current errorMessage to stderr and then clear the error
2671 protected void reportErrors()
2673 reportErrors(false);
2676 protected void reportErrors(final boolean saving)
2678 if (errorMessage != null)
2680 final String finalErrorMessage = errorMessage;
2683 javax.swing.SwingUtilities.invokeLater(new Runnable()
2688 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2690 "Error " + (saving ? "saving" : "loading")
2692 JvOptionPane.WARNING_MESSAGE);
2698 System.err.println("Problem loading Jalview file: " + errorMessage);
2701 errorMessage = null;
2704 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2707 * when set, local views will be updated from view stored in JalviewXML
2708 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2709 * sync if this is set to true.
2711 private final boolean updateLocalViews = false;
2714 * Returns the path to a temporary file holding the PDB file for the given PDB
2715 * id. The first time of asking, searches for a file of that name in the
2716 * Jalview project jar, and copies it to a new temporary file. Any repeat
2717 * requests just return the path to the file previously created.
2723 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2726 if (alreadyLoadedPDB.containsKey(pdbId))
2728 return alreadyLoadedPDB.get(pdbId).toString();
2731 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2733 if (tempFile != null)
2735 alreadyLoadedPDB.put(pdbId, tempFile);
2741 * Copies the jar entry of given name to a new temporary file and returns the
2742 * path to the file, or null if the entry is not found.
2745 * @param jarEntryName
2747 * a prefix for the temporary file name, must be at least three
2750 * null or original file - so new file can be given the same suffix
2754 protected String copyJarEntry(jarInputStreamProvider jprovider,
2755 String jarEntryName, String prefix, String origFile)
2757 BufferedReader in = null;
2758 PrintWriter out = null;
2759 String suffix = ".tmp";
2760 if (origFile == null)
2762 origFile = jarEntryName;
2764 int sfpos = origFile.lastIndexOf(".");
2765 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2767 suffix = "." + origFile.substring(sfpos + 1);
2771 JarInputStream jin = jprovider.getJarInputStream();
2773 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2774 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2775 * FileInputStream(jprovider)); }
2778 JarEntry entry = null;
2781 entry = jin.getNextJarEntry();
2782 } while (entry != null && !entry.getName().equals(jarEntryName));
2785 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2786 File outFile = File.createTempFile(prefix, suffix);
2787 outFile.deleteOnExit();
2788 out = new PrintWriter(new FileOutputStream(outFile));
2791 while ((data = in.readLine()) != null)
2796 String t = outFile.getAbsolutePath();
2801 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2803 } catch (Exception ex)
2805 ex.printStackTrace();
2813 } catch (IOException e)
2827 private class JvAnnotRow
2829 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2836 * persisted version of annotation row from which to take vis properties
2838 public jalview.datamodel.AlignmentAnnotation template;
2841 * original position of the annotation row in the alignment
2847 * Load alignment frame from jalview XML DOM object
2852 * filename source string
2853 * @param loadTreesAndStructures
2854 * when false only create Viewport
2856 * data source provider
2857 * @return alignment frame created from view stored in DOM
2859 AlignFrame loadFromObject(JalviewModel object, String file,
2860 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2862 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2863 Sequence[] vamsasSeq = vamsasSet.getSequence();
2865 JalviewModelSequence jms = object.getJalviewModelSequence();
2867 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2870 // ////////////////////////////////
2873 List<SequenceI> hiddenSeqs = null;
2875 List<SequenceI> tmpseqs = new ArrayList<>();
2877 boolean multipleView = false;
2878 SequenceI referenceseqForView = null;
2879 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2880 int vi = 0; // counter in vamsasSeq array
2881 for (int i = 0; i < jseqs.length; i++)
2883 String seqId = jseqs[i].getId();
2885 SequenceI tmpSeq = seqRefIds.get(seqId);
2888 if (!incompleteSeqs.containsKey(seqId))
2890 // may not need this check, but keep it for at least 2.9,1 release
2891 if (tmpSeq.getStart() != jseqs[i].getStart()
2892 || tmpSeq.getEnd() != jseqs[i].getEnd())
2895 "Warning JAL-2154 regression: updating start/end for sequence "
2896 + tmpSeq.toString() + " to " + jseqs[i]);
2901 incompleteSeqs.remove(seqId);
2903 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2905 // most likely we are reading a dataset XML document so
2906 // update from vamsasSeq section of XML for this sequence
2907 tmpSeq.setName(vamsasSeq[vi].getName());
2908 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2909 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2914 // reading multiple views, so vamsasSeq set is a subset of JSeq
2915 multipleView = true;
2917 tmpSeq.setStart(jseqs[i].getStart());
2918 tmpSeq.setEnd(jseqs[i].getEnd());
2919 tmpseqs.add(tmpSeq);
2923 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2924 vamsasSeq[vi].getSequence());
2925 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2926 tmpSeq.setStart(jseqs[i].getStart());
2927 tmpSeq.setEnd(jseqs[i].getEnd());
2928 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2929 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2930 tmpseqs.add(tmpSeq);
2934 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2936 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2939 if (jseqs[i].getHidden())
2941 if (hiddenSeqs == null)
2943 hiddenSeqs = new ArrayList<>();
2946 hiddenSeqs.add(tmpSeq);
2951 // Create the alignment object from the sequence set
2952 // ///////////////////////////////
2953 SequenceI[] orderedSeqs = tmpseqs
2954 .toArray(new SequenceI[tmpseqs.size()]);
2956 AlignmentI al = null;
2957 // so we must create or recover the dataset alignment before going further
2958 // ///////////////////////////////
2959 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2961 // older jalview projects do not have a dataset - so creat alignment and
2963 al = new Alignment(orderedSeqs);
2964 al.setDataset(null);
2968 boolean isdsal = object.getJalviewModelSequence()
2969 .getViewportCount() == 0;
2972 // we are importing a dataset record, so
2973 // recover reference to an alignment already materialsed as dataset
2974 al = getDatasetFor(vamsasSet.getDatasetId());
2978 // materialse the alignment
2979 al = new Alignment(orderedSeqs);
2983 addDatasetRef(vamsasSet.getDatasetId(), al);
2986 // finally, verify all data in vamsasSet is actually present in al
2987 // passing on flag indicating if it is actually a stored dataset
2988 recoverDatasetFor(vamsasSet, al, isdsal);
2991 if (referenceseqForView != null)
2993 al.setSeqrep(referenceseqForView);
2995 // / Add the alignment properties
2996 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
2998 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
2999 al.setProperty(ssp.getKey(), ssp.getValue());
3002 // ///////////////////////////////
3004 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3007 // load sequence features, database references and any associated PDB
3008 // structures for the alignment
3010 // prior to 2.10, this part would only be executed the first time a
3011 // sequence was encountered, but not afterwards.
3012 // now, for 2.10 projects, this is also done if the xml doc includes
3013 // dataset sequences not actually present in any particular view.
3015 for (int i = 0; i < vamsasSeq.length; i++)
3017 if (jseqs[i].getFeaturesCount() > 0)
3019 Features[] features = jseqs[i].getFeatures();
3020 for (int f = 0; f < features.length; f++)
3022 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3023 features[f].getDescription(), features[f].getBegin(),
3024 features[f].getEnd(), features[f].getScore(),
3025 features[f].getFeatureGroup());
3026 sf.setStatus(features[f].getStatus());
3029 * load any feature attributes - include map-valued attributes
3031 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3032 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3034 OtherData keyValue = features[f].getOtherData(od);
3035 String attributeName = keyValue.getKey();
3036 String attributeValue = keyValue.getValue();
3037 if (attributeName.startsWith("LINK"))
3039 sf.addLink(attributeValue);
3043 String subAttribute = keyValue.getKey2();
3044 if (subAttribute == null)
3046 // simple string-valued attribute
3047 sf.setValue(attributeName, attributeValue);
3051 // attribute 'key' has sub-attribute 'key2'
3052 if (!mapAttributes.containsKey(attributeName))
3054 mapAttributes.put(attributeName, new HashMap<>());
3056 mapAttributes.get(attributeName).put(subAttribute,
3061 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3064 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3067 // adds feature to datasequence's feature set (since Jalview 2.10)
3068 al.getSequenceAt(i).addSequenceFeature(sf);
3071 if (vamsasSeq[i].getDBRefCount() > 0)
3073 // adds dbrefs to datasequence's set (since Jalview 2.10)
3075 al.getSequenceAt(i).getDatasetSequence() == null
3076 ? al.getSequenceAt(i)
3077 : al.getSequenceAt(i).getDatasetSequence(),
3080 if (jseqs[i].getPdbidsCount() > 0)
3082 Pdbids[] ids = jseqs[i].getPdbids();
3083 for (int p = 0; p < ids.length; p++)
3085 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3086 entry.setId(ids[p].getId());
3087 if (ids[p].getType() != null)
3089 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3091 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3095 entry.setType(PDBEntry.Type.FILE);
3098 // jprovider is null when executing 'New View'
3099 if (ids[p].getFile() != null && jprovider != null)
3101 if (!pdbloaded.containsKey(ids[p].getFile()))
3103 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3108 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3111 if (ids[p].getPdbentryItem() != null)
3113 for (PdbentryItem item : ids[p].getPdbentryItem())
3115 for (Property pr : item.getProperty())
3117 entry.setProperty(pr.getName(), pr.getValue());
3121 StructureSelectionManager
3122 .getStructureSelectionManager(Desktop.instance)
3123 .registerPDBEntry(entry);
3124 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3125 if (al.getSequenceAt(i).getDatasetSequence() != null)
3127 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3131 al.getSequenceAt(i).addPDBId(entry);
3136 } // end !multipleview
3138 // ///////////////////////////////
3139 // LOAD SEQUENCE MAPPINGS
3141 if (vamsasSet.getAlcodonFrameCount() > 0)
3143 // TODO Potentially this should only be done once for all views of an
3145 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3146 for (int i = 0; i < alc.length; i++)
3148 AlignedCodonFrame cf = new AlignedCodonFrame();
3149 if (alc[i].getAlcodMapCount() > 0)
3151 AlcodMap[] maps = alc[i].getAlcodMap();
3152 for (int m = 0; m < maps.length; m++)
3154 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3156 jalview.datamodel.Mapping mapping = null;
3157 // attach to dna sequence reference.
3158 if (maps[m].getMapping() != null)
3160 mapping = addMapping(maps[m].getMapping());
3161 if (dnaseq != null && mapping.getTo() != null)
3163 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3169 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3173 al.addCodonFrame(cf);
3178 // ////////////////////////////////
3180 List<JvAnnotRow> autoAlan = new ArrayList<>();
3183 * store any annotations which forward reference a group's ID
3185 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3187 if (vamsasSet.getAnnotationCount() > 0)
3189 Annotation[] an = vamsasSet.getAnnotation();
3191 for (int i = 0; i < an.length; i++)
3193 Annotation annotation = an[i];
3196 * test if annotation is automatically calculated for this view only
3198 boolean autoForView = false;
3199 if (annotation.getLabel().equals("Quality")
3200 || annotation.getLabel().equals("Conservation")
3201 || annotation.getLabel().equals("Consensus"))
3203 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3205 if (!annotation.hasAutoCalculated())
3207 annotation.setAutoCalculated(true);
3210 if (autoForView || (annotation.hasAutoCalculated()
3211 && annotation.isAutoCalculated()))
3213 // remove ID - we don't recover annotation from other views for
3214 // view-specific annotation
3215 annotation.setId(null);
3218 // set visiblity for other annotation in this view
3219 String annotationId = annotation.getId();
3220 if (annotationId != null && annotationIds.containsKey(annotationId))
3222 AlignmentAnnotation jda = annotationIds.get(annotationId);
3223 // in principle Visible should always be true for annotation displayed
3224 // in multiple views
3225 if (annotation.hasVisible())
3227 jda.visible = annotation.getVisible();
3230 al.addAnnotation(jda);
3234 // Construct new annotation from model.
3235 AnnotationElement[] ae = annotation.getAnnotationElement();
3236 jalview.datamodel.Annotation[] anot = null;
3237 java.awt.Color firstColour = null;
3239 if (!annotation.getScoreOnly())
3241 anot = new jalview.datamodel.Annotation[al.getWidth()];
3242 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3244 anpos = ae[aa].getPosition();
3246 if (anpos >= anot.length)
3251 anot[anpos] = new jalview.datamodel.Annotation(
3253 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3254 (ae[aa].getSecondaryStructure() == null
3255 || ae[aa].getSecondaryStructure().length() == 0)
3257 : ae[aa].getSecondaryStructure()
3262 // JBPNote: Consider verifying dataflow for IO of secondary
3263 // structure annotation read from Stockholm files
3264 // this was added to try to ensure that
3265 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3267 // anot[ae[aa].getPosition()].displayCharacter = "";
3269 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3270 if (firstColour == null)
3272 firstColour = anot[anpos].colour;
3276 jalview.datamodel.AlignmentAnnotation jaa = null;
3278 if (annotation.getGraph())
3280 float llim = 0, hlim = 0;
3281 // if (autoForView || an[i].isAutoCalculated()) {
3284 jaa = new jalview.datamodel.AlignmentAnnotation(
3285 annotation.getLabel(), annotation.getDescription(), anot,
3286 llim, hlim, annotation.getGraphType());
3288 jaa.graphGroup = annotation.getGraphGroup();
3289 jaa._linecolour = firstColour;
3290 if (annotation.getThresholdLine() != null)
3292 jaa.setThreshold(new jalview.datamodel.GraphLine(
3293 annotation.getThresholdLine().getValue(),
3294 annotation.getThresholdLine().getLabel(),
3296 annotation.getThresholdLine().getColour())));
3299 if (autoForView || annotation.isAutoCalculated())
3301 // Hardwire the symbol display line to ensure that labels for
3302 // histograms are displayed
3308 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3309 an[i].getDescription(), anot);
3310 jaa._linecolour = firstColour;
3312 // register new annotation
3313 if (an[i].getId() != null)
3315 annotationIds.put(an[i].getId(), jaa);
3316 jaa.annotationId = an[i].getId();
3318 // recover sequence association
3319 String sequenceRef = an[i].getSequenceRef();
3320 if (sequenceRef != null)
3322 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3323 SequenceI sequence = seqRefIds.get(sequenceRef);
3324 if (sequence == null)
3326 // in pre-2.9 projects sequence ref is to sequence name
3327 sequence = al.findName(sequenceRef);
3329 if (sequence != null)
3331 jaa.createSequenceMapping(sequence, 1, true);
3332 sequence.addAlignmentAnnotation(jaa);
3335 // and make a note of any group association
3336 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3338 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3339 .get(an[i].getGroupRef());
3342 aal = new ArrayList<>();
3343 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3348 if (an[i].hasScore())
3350 jaa.setScore(an[i].getScore());
3352 if (an[i].hasVisible())
3354 jaa.visible = an[i].getVisible();
3357 if (an[i].hasCentreColLabels())
3359 jaa.centreColLabels = an[i].getCentreColLabels();
3362 if (an[i].hasScaleColLabels())
3364 jaa.scaleColLabel = an[i].getScaleColLabels();
3366 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3368 // newer files have an 'autoCalculated' flag and store calculation
3369 // state in viewport properties
3370 jaa.autoCalculated = true; // means annotation will be marked for
3371 // update at end of load.
3373 if (an[i].hasGraphHeight())
3375 jaa.graphHeight = an[i].getGraphHeight();
3377 if (an[i].hasBelowAlignment())
3379 jaa.belowAlignment = an[i].isBelowAlignment();
3381 jaa.setCalcId(an[i].getCalcId());
3382 if (an[i].getPropertyCount() > 0)
3384 for (jalview.schemabinding.version2.Property prop : an[i]
3387 jaa.setProperty(prop.getName(), prop.getValue());
3390 if (jaa.autoCalculated)
3392 autoAlan.add(new JvAnnotRow(i, jaa));
3395 // if (!autoForView)
3397 // add autocalculated group annotation and any user created annotation
3399 al.addAnnotation(jaa);
3403 // ///////////////////////
3405 // Create alignment markup and styles for this view
3406 if (jms.getJGroupCount() > 0)
3408 JGroup[] groups = jms.getJGroup();
3409 boolean addAnnotSchemeGroup = false;
3410 for (int i = 0; i < groups.length; i++)
3412 JGroup jGroup = groups[i];
3413 ColourSchemeI cs = null;
3414 if (jGroup.getColour() != null)
3416 if (jGroup.getColour().startsWith("ucs"))
3418 cs = getUserColourScheme(jms, jGroup.getColour());
3420 else if (jGroup.getColour().equals("AnnotationColourGradient")
3421 && jGroup.getAnnotationColours() != null)
3423 addAnnotSchemeGroup = true;
3427 cs = ColourSchemeProperty.getColourScheme(al,
3428 jGroup.getColour());
3431 int pidThreshold = jGroup.getPidThreshold();
3433 Vector<SequenceI> seqs = new Vector<>();
3435 for (int s = 0; s < jGroup.getSeqCount(); s++)
3437 String seqId = jGroup.getSeq(s) + "";
3438 SequenceI ts = seqRefIds.get(seqId);
3442 seqs.addElement(ts);
3446 if (seqs.size() < 1)
3451 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3452 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3453 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3454 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3455 sg.getGroupColourScheme()
3456 .setConservationInc(jGroup.getConsThreshold());
3457 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3459 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3460 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3461 sg.setShowNonconserved(
3462 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3464 sg.thresholdTextColour = jGroup.getTextColThreshold();
3465 if (jGroup.hasShowConsensusHistogram())
3467 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3470 if (jGroup.hasShowSequenceLogo())
3472 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3474 if (jGroup.hasNormaliseSequenceLogo())
3476 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3478 if (jGroup.hasIgnoreGapsinConsensus())
3480 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3482 if (jGroup.getConsThreshold() != 0)
3484 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3487 c.verdict(false, 25);
3488 sg.cs.setConservation(c);
3491 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3493 // re-instate unique group/annotation row reference
3494 List<AlignmentAnnotation> jaal = groupAnnotRefs
3495 .get(jGroup.getId());
3498 for (AlignmentAnnotation jaa : jaal)
3501 if (jaa.autoCalculated)
3503 // match up and try to set group autocalc alignment row for this
3505 if (jaa.label.startsWith("Consensus for "))
3507 sg.setConsensus(jaa);
3509 // match up and try to set group autocalc alignment row for this
3511 if (jaa.label.startsWith("Conservation for "))
3513 sg.setConservationRow(jaa);
3520 if (addAnnotSchemeGroup)
3522 // reconstruct the annotation colourscheme
3523 sg.setColourScheme(constructAnnotationColour(
3524 jGroup.getAnnotationColours(), null, al, jms, false));
3530 // only dataset in this model, so just return.
3533 // ///////////////////////////////
3536 // If we just load in the same jar file again, the sequenceSetId
3537 // will be the same, and we end up with multiple references
3538 // to the same sequenceSet. We must modify this id on load
3539 // so that each load of the file gives a unique id
3540 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3541 String viewId = (view.getId() == null ? null
3542 : view.getId() + uniqueSetSuffix);
3543 AlignFrame af = null;
3544 AlignViewport av = null;
3545 // now check to see if we really need to create a new viewport.
3546 if (multipleView && viewportsAdded.size() == 0)
3548 // We recovered an alignment for which a viewport already exists.
3549 // TODO: fix up any settings necessary for overlaying stored state onto
3550 // state recovered from another document. (may not be necessary).
3551 // we may need a binding from a viewport in memory to one recovered from
3553 // and then recover its containing af to allow the settings to be applied.
3554 // TODO: fix for vamsas demo
3556 "About to recover a viewport for existing alignment: Sequence set ID is "
3558 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3559 if (seqsetobj != null)
3561 if (seqsetobj instanceof String)
3563 uniqueSeqSetId = (String) seqsetobj;
3565 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3571 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3577 * indicate that annotation colours are applied across all groups (pre
3578 * Jalview 2.8.1 behaviour)
3580 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3581 object.getVersion());
3583 AlignmentPanel ap = null;
3584 boolean isnewview = true;
3587 // Check to see if this alignment already has a view id == viewId
3588 jalview.gui.AlignmentPanel views[] = Desktop
3589 .getAlignmentPanels(uniqueSeqSetId);
3590 if (views != null && views.length > 0)
3592 for (int v = 0; v < views.length; v++)
3594 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3596 // recover the existing alignpanel, alignframe, viewport
3597 af = views[v].alignFrame;
3600 // TODO: could even skip resetting view settings if we don't want to
3601 // change the local settings from other jalview processes
3610 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3611 uniqueSeqSetId, viewId, autoAlan);
3617 * Load any trees, PDB structures and viewers
3619 * Not done if flag is false (when this method is used for New View)
3621 if (loadTreesAndStructures)
3623 loadTrees(jms, view, af, av, ap);
3624 loadPDBStructures(jprovider, jseqs, af, ap);
3625 loadRnaViewers(jprovider, jseqs, ap);
3627 // and finally return.
3632 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3633 * panel is restored from separate jar entries, two (gapped and trimmed) per
3634 * sequence and secondary structure.
3636 * Currently each viewer shows just one sequence and structure (gapped and
3637 * trimmed), however this method is designed to support multiple sequences or
3638 * structures in viewers if wanted in future.
3644 private void loadRnaViewers(jarInputStreamProvider jprovider,
3645 JSeq[] jseqs, AlignmentPanel ap)
3648 * scan the sequences for references to viewers; create each one the first
3649 * time it is referenced, add Rna models to existing viewers
3651 for (JSeq jseq : jseqs)
3653 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3655 RnaViewer viewer = jseq.getRnaViewer(i);
3656 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3659 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3661 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3662 SequenceI seq = seqRefIds.get(jseq.getId());
3663 AlignmentAnnotation ann = this.annotationIds
3664 .get(ss.getAnnotationId());
3667 * add the structure to the Varna display (with session state copied
3668 * from the jar to a temporary file)
3670 boolean gapped = ss.isGapped();
3671 String rnaTitle = ss.getTitle();
3672 String sessionState = ss.getViewerState();
3673 String tempStateFile = copyJarEntry(jprovider, sessionState,
3675 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3676 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3678 appVarna.setInitialSelection(viewer.getSelectedRna());
3684 * Locate and return an already instantiated matching AppVarna, or create one
3688 * @param viewIdSuffix
3692 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3693 String viewIdSuffix, AlignmentPanel ap)
3696 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3697 * if load is repeated
3699 String postLoadId = viewer.getViewId() + viewIdSuffix;
3700 for (JInternalFrame frame : getAllFrames())
3702 if (frame instanceof AppVarna)
3704 AppVarna varna = (AppVarna) frame;
3705 if (postLoadId.equals(varna.getViewId()))
3707 // this viewer is already instantiated
3708 // could in future here add ap as another 'parent' of the
3709 // AppVarna window; currently just 1-to-many
3716 * viewer not found - make it
3718 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3719 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3720 viewer.getHeight(), viewer.getDividerLocation());
3721 AppVarna varna = new AppVarna(model, ap);
3727 * Load any saved trees
3735 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3736 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3738 // TODO result of automated refactoring - are all these parameters needed?
3741 for (int t = 0; t < jms.getTreeCount(); t++)
3744 Tree tree = jms.getTree(t);
3746 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3749 tp = af.showNewickTree(
3750 new jalview.io.NewickFile(tree.getNewick()),
3751 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3752 tree.getXpos(), tree.getYpos());
3753 if (tree.getId() != null)
3755 // perhaps bind the tree id to something ?
3760 // update local tree attributes ?
3761 // TODO: should check if tp has been manipulated by user - if so its
3762 // settings shouldn't be modified
3763 tp.setTitle(tree.getTitle());
3764 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3765 tree.getWidth(), tree.getHeight()));
3766 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3769 tp.treeCanvas.av = av; // af.viewport;
3770 tp.treeCanvas.ap = ap; // af.alignPanel;
3775 warn("There was a problem recovering stored Newick tree: \n"
3776 + tree.getNewick());
3780 tp.fitToWindow.setState(tree.getFitToWindow());
3781 tp.fitToWindow_actionPerformed(null);
3783 if (tree.getFontName() != null)
3785 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3786 tree.getFontStyle(), tree.getFontSize()));
3790 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3791 view.getFontStyle(), tree.getFontSize()));
3794 tp.showPlaceholders(tree.getMarkUnlinked());
3795 tp.showBootstrap(tree.getShowBootstrap());
3796 tp.showDistances(tree.getShowDistances());
3798 tp.treeCanvas.threshold = tree.getThreshold();
3799 tp.treeCanvas.applyToAllViews = tree.isLinkToAllViews();
3801 if (tree.getCurrentTree())
3803 af.viewport.setCurrentTree(tp.getTree());
3807 } catch (Exception ex)
3809 ex.printStackTrace();
3814 * Load and link any saved structure viewers.
3821 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3822 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3825 * Run through all PDB ids on the alignment, and collect mappings between
3826 * distinct view ids and all sequences referring to that view.
3828 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3830 for (int i = 0; i < jseqs.length; i++)
3832 if (jseqs[i].getPdbidsCount() > 0)
3834 Pdbids[] ids = jseqs[i].getPdbids();
3835 for (int p = 0; p < ids.length; p++)
3837 final int structureStateCount = ids[p].getStructureStateCount();
3838 for (int s = 0; s < structureStateCount; s++)
3840 // check to see if we haven't already created this structure view
3841 final StructureState structureState = ids[p]
3842 .getStructureState(s);
3843 String sviewid = (structureState.getViewId() == null) ? null
3844 : structureState.getViewId() + uniqueSetSuffix;
3845 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3846 // Originally : ids[p].getFile()
3847 // : TODO: verify external PDB file recovery still works in normal
3848 // jalview project load
3849 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3851 jpdb.setId(ids[p].getId());
3853 int x = structureState.getXpos();
3854 int y = structureState.getYpos();
3855 int width = structureState.getWidth();
3856 int height = structureState.getHeight();
3858 // Probably don't need to do this anymore...
3859 // Desktop.desktop.getComponentAt(x, y);
3860 // TODO: NOW: check that this recovers the PDB file correctly.
3861 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3863 jalview.datamodel.SequenceI seq = seqRefIds
3864 .get(jseqs[i].getId() + "");
3865 if (sviewid == null)
3867 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3870 if (!structureViewers.containsKey(sviewid))
3872 structureViewers.put(sviewid,
3873 new StructureViewerModel(x, y, width, height, false,
3874 false, true, structureState.getViewId(),
3875 structureState.getType()));
3876 // Legacy pre-2.7 conversion JAL-823 :
3877 // do not assume any view has to be linked for colour by
3881 // assemble String[] { pdb files }, String[] { id for each
3882 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3883 // seqs_file 2}, boolean[] {
3884 // linkAlignPanel,superposeWithAlignpanel}} from hash
3885 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3886 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3887 | (structureState.hasAlignwithAlignPanel()
3888 ? structureState.getAlignwithAlignPanel()
3892 * Default colour by linked panel to false if not specified (e.g.
3893 * for pre-2.7 projects)
3895 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3896 colourWithAlignPanel |= (structureState
3897 .hasColourwithAlignPanel()
3898 ? structureState.getColourwithAlignPanel()
3900 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3903 * Default colour by viewer to true if not specified (e.g. for
3906 boolean colourByViewer = jmoldat.isColourByViewer();
3907 colourByViewer &= structureState.hasColourByJmol()
3908 ? structureState.getColourByJmol()
3910 jmoldat.setColourByViewer(colourByViewer);
3912 if (jmoldat.getStateData().length() < structureState
3913 .getContent().length())
3916 jmoldat.setStateData(structureState.getContent());
3919 if (ids[p].getFile() != null)
3921 File mapkey = new File(ids[p].getFile());
3922 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3923 if (seqstrmaps == null)
3925 jmoldat.getFileData().put(mapkey,
3926 seqstrmaps = jmoldat.new StructureData(pdbFile,
3929 if (!seqstrmaps.getSeqList().contains(seq))
3931 seqstrmaps.getSeqList().add(seq);
3937 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");
3944 // Instantiate the associated structure views
3945 for (Entry<String, StructureViewerModel> entry : structureViewers
3950 createOrLinkStructureViewer(entry, af, ap, jprovider);
3951 } catch (Exception e)
3954 "Error loading structure viewer: " + e.getMessage());
3955 // failed - try the next one
3967 protected void createOrLinkStructureViewer(
3968 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3969 AlignmentPanel ap, jarInputStreamProvider jprovider)
3971 final StructureViewerModel stateData = viewerData.getValue();
3974 * Search for any viewer windows already open from other alignment views
3975 * that exactly match the stored structure state
3977 StructureViewerBase comp = findMatchingViewer(viewerData);
3981 linkStructureViewer(ap, comp, stateData);
3986 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3987 * "viewer_"+stateData.viewId
3989 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
3991 createChimeraViewer(viewerData, af, jprovider);
3996 * else Jmol (if pre-2.9, stateData contains JMOL state string)
3998 createJmolViewer(viewerData, af, jprovider);
4003 * Create a new Chimera viewer.
4009 protected void createChimeraViewer(
4010 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4011 jarInputStreamProvider jprovider)
4013 StructureViewerModel data = viewerData.getValue();
4014 String chimeraSessionFile = data.getStateData();
4017 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4019 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4020 * 'uniquified' sviewid used to reconstruct the viewer here
4022 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4023 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4026 Set<Entry<File, StructureData>> fileData = data.getFileData()
4028 List<PDBEntry> pdbs = new ArrayList<>();
4029 List<SequenceI[]> allseqs = new ArrayList<>();
4030 for (Entry<File, StructureData> pdb : fileData)
4032 String filePath = pdb.getValue().getFilePath();
4033 String pdbId = pdb.getValue().getPdbId();
4034 // pdbs.add(new PDBEntry(filePath, pdbId));
4035 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4036 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4037 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4041 boolean colourByChimera = data.isColourByViewer();
4042 boolean colourBySequence = data.isColourWithAlignPanel();
4044 // TODO use StructureViewer as a factory here, see JAL-1761
4045 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4046 final SequenceI[][] seqsArray = allseqs
4047 .toArray(new SequenceI[allseqs.size()][]);
4048 String newViewId = viewerData.getKey();
4050 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4051 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4052 colourBySequence, newViewId);
4053 cvf.setSize(data.getWidth(), data.getHeight());
4054 cvf.setLocation(data.getX(), data.getY());
4058 * Create a new Jmol window. First parse the Jmol state to translate filenames
4059 * loaded into the view, and record the order in which files are shown in the
4060 * Jmol view, so we can add the sequence mappings in same order.
4066 protected void createJmolViewer(
4067 final Entry<String, StructureViewerModel> viewerData,
4068 AlignFrame af, jarInputStreamProvider jprovider)
4070 final StructureViewerModel svattrib = viewerData.getValue();
4071 String state = svattrib.getStateData();
4074 * Pre-2.9: state element value is the Jmol state string
4076 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4079 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4081 state = readJarEntry(jprovider,
4082 getViewerJarEntryName(svattrib.getViewId()));
4085 List<String> pdbfilenames = new ArrayList<>();
4086 List<SequenceI[]> seqmaps = new ArrayList<>();
4087 List<String> pdbids = new ArrayList<>();
4088 StringBuilder newFileLoc = new StringBuilder(64);
4089 int cp = 0, ncp, ecp;
4090 Map<File, StructureData> oldFiles = svattrib.getFileData();
4091 while ((ncp = state.indexOf("load ", cp)) > -1)
4095 // look for next filename in load statement
4096 newFileLoc.append(state.substring(cp,
4097 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4098 String oldfilenam = state.substring(ncp,
4099 ecp = state.indexOf("\"", ncp));
4100 // recover the new mapping data for this old filename
4101 // have to normalize filename - since Jmol and jalview do
4103 // translation differently.
4104 StructureData filedat = oldFiles.get(new File(oldfilenam));
4105 if (filedat == null)
4107 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4108 filedat = oldFiles.get(new File(reformatedOldFilename));
4110 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4111 pdbfilenames.add(filedat.getFilePath());
4112 pdbids.add(filedat.getPdbId());
4113 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4114 newFileLoc.append("\"");
4115 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4116 // look for next file statement.
4117 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4121 // just append rest of state
4122 newFileLoc.append(state.substring(cp));
4126 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4127 newFileLoc = new StringBuilder(state);
4128 newFileLoc.append("; load append ");
4129 for (File id : oldFiles.keySet())
4131 // add this and any other pdb files that should be present in
4133 StructureData filedat = oldFiles.get(id);
4134 newFileLoc.append(filedat.getFilePath());
4135 pdbfilenames.add(filedat.getFilePath());
4136 pdbids.add(filedat.getPdbId());
4137 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4138 newFileLoc.append(" \"");
4139 newFileLoc.append(filedat.getFilePath());
4140 newFileLoc.append("\"");
4143 newFileLoc.append(";");
4146 if (newFileLoc.length() == 0)
4150 int histbug = newFileLoc.indexOf("history = ");
4154 * change "history = [true|false];" to "history = [1|0];"
4157 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4158 String val = (diff == -1) ? null
4159 : newFileLoc.substring(histbug, diff);
4160 if (val != null && val.length() >= 4)
4162 if (val.contains("e")) // eh? what can it be?
4164 if (val.trim().equals("true"))
4172 newFileLoc.replace(histbug, diff, val);
4177 final String[] pdbf = pdbfilenames
4178 .toArray(new String[pdbfilenames.size()]);
4179 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4180 final SequenceI[][] sq = seqmaps
4181 .toArray(new SequenceI[seqmaps.size()][]);
4182 final String fileloc = newFileLoc.toString();
4183 final String sviewid = viewerData.getKey();
4184 final AlignFrame alf = af;
4185 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4186 svattrib.getWidth(), svattrib.getHeight());
4189 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4194 JalviewStructureDisplayI sview = null;
4197 sview = new StructureViewer(
4198 alf.alignPanel.getStructureSelectionManager())
4199 .createView(StructureViewer.ViewerType.JMOL,
4200 pdbf, id, sq, alf.alignPanel, svattrib,
4201 fileloc, rect, sviewid);
4202 addNewStructureViewer(sview);
4203 } catch (OutOfMemoryError ex)
4205 new OOMWarning("restoring structure view for PDB id " + id,
4206 (OutOfMemoryError) ex.getCause());
4207 if (sview != null && sview.isVisible())
4209 sview.closeViewer(false);
4210 sview.setVisible(false);
4216 } catch (InvocationTargetException ex)
4218 warn("Unexpected error when opening Jmol view.", ex);
4220 } catch (InterruptedException e)
4222 // e.printStackTrace();
4228 * Generates a name for the entry in the project jar file to hold state
4229 * information for a structure viewer
4234 protected String getViewerJarEntryName(String viewId)
4236 return VIEWER_PREFIX + viewId;
4240 * Returns any open frame that matches given structure viewer data. The match
4241 * is based on the unique viewId, or (for older project versions) the frame's
4247 protected StructureViewerBase findMatchingViewer(
4248 Entry<String, StructureViewerModel> viewerData)
4250 final String sviewid = viewerData.getKey();
4251 final StructureViewerModel svattrib = viewerData.getValue();
4252 StructureViewerBase comp = null;
4253 JInternalFrame[] frames = getAllFrames();
4254 for (JInternalFrame frame : frames)
4256 if (frame instanceof StructureViewerBase)
4259 * Post jalview 2.4 schema includes structure view id
4261 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4264 comp = (StructureViewerBase) frame;
4265 break; // break added in 2.9
4268 * Otherwise test for matching position and size of viewer frame
4270 else if (frame.getX() == svattrib.getX()
4271 && frame.getY() == svattrib.getY()
4272 && frame.getHeight() == svattrib.getHeight()
4273 && frame.getWidth() == svattrib.getWidth())
4275 comp = (StructureViewerBase) frame;
4276 // no break in faint hope of an exact match on viewId
4284 * Link an AlignmentPanel to an existing structure viewer.
4289 * @param useinViewerSuperpos
4290 * @param usetoColourbyseq
4291 * @param viewerColouring
4293 protected void linkStructureViewer(AlignmentPanel ap,
4294 StructureViewerBase viewer, StructureViewerModel stateData)
4296 // NOTE: if the jalview project is part of a shared session then
4297 // view synchronization should/could be done here.
4299 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4300 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4301 final boolean viewerColouring = stateData.isColourByViewer();
4302 Map<File, StructureData> oldFiles = stateData.getFileData();
4305 * Add mapping for sequences in this view to an already open viewer
4307 final AAStructureBindingModel binding = viewer.getBinding();
4308 for (File id : oldFiles.keySet())
4310 // add this and any other pdb files that should be present in the
4312 StructureData filedat = oldFiles.get(id);
4313 String pdbFile = filedat.getFilePath();
4314 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4315 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4317 binding.addSequenceForStructFile(pdbFile, seq);
4319 // and add the AlignmentPanel's reference to the view panel
4320 viewer.addAlignmentPanel(ap);
4321 if (useinViewerSuperpos)
4323 viewer.useAlignmentPanelForSuperposition(ap);
4327 viewer.excludeAlignmentPanelForSuperposition(ap);
4329 if (usetoColourbyseq)
4331 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4335 viewer.excludeAlignmentPanelForColourbyseq(ap);
4340 * Get all frames within the Desktop.
4344 protected JInternalFrame[] getAllFrames()
4346 JInternalFrame[] frames = null;
4347 // TODO is this necessary - is it safe - risk of hanging?
4352 frames = Desktop.desktop.getAllFrames();
4353 } catch (ArrayIndexOutOfBoundsException e)
4355 // occasional No such child exceptions are thrown here...
4359 } catch (InterruptedException f)
4363 } while (frames == null);
4368 * Answers true if 'version' is equal to or later than 'supported', where each
4369 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4370 * changes. Development and test values for 'version' are leniently treated
4374 * - minimum version we are comparing against
4376 * - version of data being processsed
4379 public static boolean isVersionStringLaterThan(String supported,
4382 if (supported == null || version == null
4383 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4384 || version.equalsIgnoreCase("Test")
4385 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4387 System.err.println("Assuming project file with "
4388 + (version == null ? "null" : version)
4389 + " is compatible with Jalview version " + supported);
4394 return StringUtils.compareVersions(version, supported, "b") >= 0;
4398 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4400 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4402 if (newStructureViewers != null)
4404 sview.getBinding().setFinishedLoadingFromArchive(false);
4405 newStructureViewers.add(sview);
4409 protected void setLoadingFinishedForNewStructureViewers()
4411 if (newStructureViewers != null)
4413 for (JalviewStructureDisplayI sview : newStructureViewers)
4415 sview.getBinding().setFinishedLoadingFromArchive(true);
4417 newStructureViewers.clear();
4418 newStructureViewers = null;
4422 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4423 List<SequenceI> hiddenSeqs, AlignmentI al,
4424 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4425 String viewId, List<JvAnnotRow> autoAlan)
4427 AlignFrame af = null;
4428 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4429 uniqueSeqSetId, viewId);
4431 af.setFileName(file, FileFormat.Jalview);
4433 for (int i = 0; i < JSEQ.length; i++)
4435 af.viewport.setSequenceColour(
4436 af.viewport.getAlignment().getSequenceAt(i),
4437 new java.awt.Color(JSEQ[i].getColour()));
4442 af.getViewport().setColourByReferenceSeq(true);
4443 af.getViewport().setDisplayReferenceSeq(true);
4446 af.viewport.setGatherViewsHere(view.getGatheredViews());
4448 if (view.getSequenceSetId() != null)
4450 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4452 af.viewport.setSequenceSetId(uniqueSeqSetId);
4455 // propagate shared settings to this new view
4456 af.viewport.setHistoryList(av.getHistoryList());
4457 af.viewport.setRedoList(av.getRedoList());
4461 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4463 // TODO: check if this method can be called repeatedly without
4464 // side-effects if alignpanel already registered.
4465 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4467 // apply Hidden regions to view.
4468 if (hiddenSeqs != null)
4470 for (int s = 0; s < JSEQ.length; s++)
4472 SequenceGroup hidden = new SequenceGroup();
4473 boolean isRepresentative = false;
4474 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4476 isRepresentative = true;
4477 SequenceI sequenceToHide = al
4478 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4479 hidden.addSequence(sequenceToHide, false);
4480 // remove from hiddenSeqs list so we don't try to hide it twice
4481 hiddenSeqs.remove(sequenceToHide);
4483 if (isRepresentative)
4485 SequenceI representativeSequence = al.getSequenceAt(s);
4486 hidden.addSequence(representativeSequence, false);
4487 af.viewport.hideRepSequences(representativeSequence, hidden);
4491 SequenceI[] hseqs = hiddenSeqs
4492 .toArray(new SequenceI[hiddenSeqs.size()]);
4493 af.viewport.hideSequence(hseqs);
4496 // recover view properties and display parameters
4498 af.viewport.setShowAnnotation(view.getShowAnnotation());
4499 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4500 af.viewport.setThreshold(view.getPidThreshold());
4502 af.viewport.setColourText(view.getShowColourText());
4504 af.viewport.setConservationSelected(view.getConservationSelected());
4505 af.viewport.setIncrement(view.getConsThreshold());
4506 af.viewport.setShowJVSuffix(view.getShowFullId());
4507 af.viewport.setRightAlignIds(view.getRightAlignIds());
4508 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4509 view.getFontStyle(), view.getFontSize()), true);
4510 ViewStyleI vs = af.viewport.getViewStyle();
4511 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4512 af.viewport.setViewStyle(vs);
4513 // TODO: allow custom charWidth/Heights to be restored by updating them
4514 // after setting font - which means set above to false
4515 af.viewport.setRenderGaps(view.getRenderGaps());
4516 af.viewport.setWrapAlignment(view.getWrapAlignment());
4517 af.viewport.setShowAnnotation(view.getShowAnnotation());
4519 af.viewport.setShowBoxes(view.getShowBoxes());
4521 af.viewport.setShowText(view.getShowText());
4523 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4524 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4525 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4526 af.viewport.setShowUnconserved(
4527 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4528 af.viewport.getRanges().setStartRes(view.getStartRes());
4530 if (view.getViewName() != null)
4532 af.viewport.viewName = view.getViewName();
4533 af.setInitialTabVisible();
4535 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4537 // startSeq set in af.alignPanel.updateLayout below
4538 af.alignPanel.updateLayout();
4539 ColourSchemeI cs = null;
4540 // apply colourschemes
4541 if (view.getBgColour() != null)
4543 if (view.getBgColour().startsWith("ucs"))
4545 cs = getUserColourScheme(jms, view.getBgColour());
4547 else if (view.getBgColour().startsWith("Annotation"))
4549 AnnotationColours viewAnnColour = view.getAnnotationColours();
4550 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4557 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4561 af.viewport.setGlobalColourScheme(cs);
4562 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4563 view.getIgnoreGapsinConsensus());
4564 af.viewport.getResidueShading()
4565 .setConsensus(af.viewport.getSequenceConsensusHash());
4566 af.viewport.setColourAppliesToAllGroups(false);
4568 if (view.getConservationSelected() && cs != null)
4570 af.viewport.getResidueShading()
4571 .setConservationInc(view.getConsThreshold());
4574 af.changeColour(cs);
4576 af.viewport.setColourAppliesToAllGroups(true);
4578 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4580 if (view.hasCentreColumnLabels())
4582 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4584 if (view.hasIgnoreGapsinConsensus())
4586 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4589 if (view.hasFollowHighlight())
4591 af.viewport.setFollowHighlight(view.getFollowHighlight());
4593 if (view.hasFollowSelection())
4595 af.viewport.followSelection = view.getFollowSelection();
4597 if (view.hasShowConsensusHistogram())
4600 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4604 af.viewport.setShowConsensusHistogram(true);
4606 if (view.hasShowSequenceLogo())
4608 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4612 af.viewport.setShowSequenceLogo(false);
4614 if (view.hasNormaliseSequenceLogo())
4616 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4618 if (view.hasShowDbRefTooltip())
4620 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4622 if (view.hasShowNPfeatureTooltip())
4624 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4626 if (view.hasShowGroupConsensus())
4628 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4632 af.viewport.setShowGroupConsensus(false);
4634 if (view.hasShowGroupConservation())
4636 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4640 af.viewport.setShowGroupConservation(false);
4643 // recover feature settings
4644 if (jms.getFeatureSettings() != null)
4646 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4647 .getFeatureRenderer();
4648 FeaturesDisplayed fdi;
4649 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4650 String[] renderOrder = new String[jms.getFeatureSettings()
4651 .getSettingCount()];
4652 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4653 Map<String, Float> featureOrder = new Hashtable<>();
4655 for (int fs = 0; fs < jms.getFeatureSettings()
4656 .getSettingCount(); fs++)
4658 Setting setting = jms.getFeatureSettings().getSetting(fs);
4659 String featureType = setting.getType();
4662 * restore feature filters (if any)
4664 MatcherSet filters = setting.getMatcherSet();
4665 if (filters != null)
4667 FeatureMatcherSetI filter = Jalview2XML
4668 .unmarshalFilter(featureType, filters);
4669 if (!filter.isEmpty())
4671 fr.setFeatureFilter(featureType, filter);
4676 * restore feature colour scheme
4678 Color maxColour = new Color(setting.getColour());
4679 if (setting.hasMincolour())
4682 * minColour is always set unless a simple colour
4683 * (including for colour by label though it doesn't use it)
4685 Color minColour = new Color(setting.getMincolour());
4686 Color noValueColour = minColour;
4687 NoValueColour noColour = setting.getNoValueColour();
4688 if (noColour == NoValueColour.NONE)
4690 noValueColour = null;
4692 else if (noColour == NoValueColour.MAX)
4694 noValueColour = maxColour;
4696 float min = setting.hasMin() ? setting.getMin() : 0f;
4697 float max = setting.hasMin() ? setting.getMax() : 1f;
4698 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4699 noValueColour, min, max);
4700 if (setting.getAttributeNameCount() > 0)
4702 gc.setAttributeName(setting.getAttributeName());
4704 if (setting.hasThreshold())
4706 gc.setThreshold(setting.getThreshold());
4707 int threshstate = setting.getThreshstate();
4708 // -1 = None, 0 = Below, 1 = Above threshold
4709 if (threshstate == 0)
4711 gc.setBelowThreshold(true);
4713 else if (threshstate == 1)
4715 gc.setAboveThreshold(true);
4718 gc.setAutoScaled(true); // default
4719 if (setting.hasAutoScale())
4721 gc.setAutoScaled(setting.getAutoScale());
4723 if (setting.hasColourByLabel())
4725 gc.setColourByLabel(setting.getColourByLabel());
4727 // and put in the feature colour table.
4728 featureColours.put(featureType, gc);
4732 featureColours.put(featureType,
4733 new FeatureColour(maxColour));
4735 renderOrder[fs] = featureType;
4736 if (setting.hasOrder())
4738 featureOrder.put(featureType, setting.getOrder());
4742 featureOrder.put(featureType, new Float(
4743 fs / jms.getFeatureSettings().getSettingCount()));
4745 if (setting.getDisplay())
4747 fdi.setVisible(featureType);
4750 Map<String, Boolean> fgtable = new Hashtable<>();
4751 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4753 Group grp = jms.getFeatureSettings().getGroup(gs);
4754 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4756 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4757 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4758 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4759 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4760 fgtable, featureColours, 1.0f, featureOrder);
4761 fr.transferSettings(frs);
4764 if (view.getHiddenColumnsCount() > 0)
4766 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4768 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4769 view.getHiddenColumns(c).getEnd() // +1
4773 if (view.getCalcIdParam() != null)
4775 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4777 if (calcIdParam != null)
4779 if (recoverCalcIdParam(calcIdParam, af.viewport))
4784 warn("Couldn't recover parameters for "
4785 + calcIdParam.getCalcId());
4790 af.setMenusFromViewport(af.viewport);
4791 af.setTitle(view.getTitle());
4792 // TODO: we don't need to do this if the viewport is aready visible.
4794 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4795 * has a 'cdna/protein complement' view, in which case save it in order to
4796 * populate a SplitFrame once all views have been read in.
4798 String complementaryViewId = view.getComplementId();
4799 if (complementaryViewId == null)
4801 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4803 // recompute any autoannotation
4804 af.alignPanel.updateAnnotation(false, true);
4805 reorderAutoannotation(af, al, autoAlan);
4806 af.alignPanel.alignmentChanged();
4810 splitFrameCandidates.put(view, af);
4816 * Reads saved data to restore Colour by Annotation settings
4818 * @param viewAnnColour
4822 * @param checkGroupAnnColour
4825 private ColourSchemeI constructAnnotationColour(
4826 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4827 JalviewModelSequence jms, boolean checkGroupAnnColour)
4829 boolean propagateAnnColour = false;
4830 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4831 if (checkGroupAnnColour && al.getGroups() != null
4832 && al.getGroups().size() > 0)
4834 // pre 2.8.1 behaviour
4835 // check to see if we should transfer annotation colours
4836 propagateAnnColour = true;
4837 for (SequenceGroup sg : al.getGroups())
4839 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4841 propagateAnnColour = false;
4847 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4849 String annotationId = viewAnnColour.getAnnotation();
4850 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4853 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4855 if (matchedAnnotation == null
4856 && annAlignment.getAlignmentAnnotation() != null)
4858 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4861 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4863 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4868 if (matchedAnnotation == null)
4870 System.err.println("Failed to match annotation colour scheme for "
4874 if (matchedAnnotation.getThreshold() == null)
4876 matchedAnnotation.setThreshold(new GraphLine(
4877 viewAnnColour.getThreshold(), "Threshold", Color.black));
4880 AnnotationColourGradient cs = null;
4881 if (viewAnnColour.getColourScheme().equals("None"))
4883 cs = new AnnotationColourGradient(matchedAnnotation,
4884 new Color(viewAnnColour.getMinColour()),
4885 new Color(viewAnnColour.getMaxColour()),
4886 viewAnnColour.getAboveThreshold());
4888 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4890 cs = new AnnotationColourGradient(matchedAnnotation,
4891 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4892 viewAnnColour.getAboveThreshold());
4896 cs = new AnnotationColourGradient(matchedAnnotation,
4897 ColourSchemeProperty.getColourScheme(al,
4898 viewAnnColour.getColourScheme()),
4899 viewAnnColour.getAboveThreshold());
4902 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4903 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4904 cs.setSeqAssociated(perSequenceOnly);
4905 cs.setPredefinedColours(useOriginalColours);
4907 if (propagateAnnColour && al.getGroups() != null)
4909 // Also use these settings for all the groups
4910 for (int g = 0; g < al.getGroups().size(); g++)
4912 SequenceGroup sg = al.getGroups().get(g);
4913 if (sg.getGroupColourScheme() == null)
4918 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4919 matchedAnnotation, sg.getColourScheme(),
4920 viewAnnColour.getAboveThreshold());
4921 sg.setColourScheme(groupScheme);
4922 groupScheme.setSeqAssociated(perSequenceOnly);
4923 groupScheme.setPredefinedColours(useOriginalColours);
4929 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4930 List<JvAnnotRow> autoAlan)
4932 // copy over visualization settings for autocalculated annotation in the
4934 if (al.getAlignmentAnnotation() != null)
4937 * Kludge for magic autoannotation names (see JAL-811)
4939 String[] magicNames = new String[] { "Consensus", "Quality",
4941 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4942 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4943 for (String nm : magicNames)
4945 visan.put(nm, nullAnnot);
4947 for (JvAnnotRow auan : autoAlan)
4949 visan.put(auan.template.label
4950 + (auan.template.getCalcId() == null ? ""
4951 : "\t" + auan.template.getCalcId()),
4954 int hSize = al.getAlignmentAnnotation().length;
4955 List<JvAnnotRow> reorder = new ArrayList<>();
4956 // work through any autoCalculated annotation already on the view
4957 // removing it if it should be placed in a different location on the
4958 // annotation panel.
4959 List<String> remains = new ArrayList<>(visan.keySet());
4960 for (int h = 0; h < hSize; h++)
4962 jalview.datamodel.AlignmentAnnotation jalan = al
4963 .getAlignmentAnnotation()[h];
4964 if (jalan.autoCalculated)
4967 JvAnnotRow valan = visan.get(k = jalan.label);
4968 if (jalan.getCalcId() != null)
4970 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4975 // delete the auto calculated row from the alignment
4976 al.deleteAnnotation(jalan, false);
4980 if (valan != nullAnnot)
4982 if (jalan != valan.template)
4984 // newly created autoannotation row instance
4985 // so keep a reference to the visible annotation row
4986 // and copy over all relevant attributes
4987 if (valan.template.graphHeight >= 0)
4990 jalan.graphHeight = valan.template.graphHeight;
4992 jalan.visible = valan.template.visible;
4994 reorder.add(new JvAnnotRow(valan.order, jalan));
4999 // Add any (possibly stale) autocalculated rows that were not appended to
5000 // the view during construction
5001 for (String other : remains)
5003 JvAnnotRow othera = visan.get(other);
5004 if (othera != nullAnnot && othera.template.getCalcId() != null
5005 && othera.template.getCalcId().length() > 0)
5007 reorder.add(othera);
5010 // now put the automatic annotation in its correct place
5011 int s = 0, srt[] = new int[reorder.size()];
5012 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5013 for (JvAnnotRow jvar : reorder)
5016 srt[s++] = jvar.order;
5019 jalview.util.QuickSort.sort(srt, rws);
5020 // and re-insert the annotation at its correct position
5021 for (JvAnnotRow jvar : rws)
5023 al.addAnnotation(jvar.template, jvar.order);
5025 af.alignPanel.adjustAnnotationHeight();
5029 Hashtable skipList = null;
5032 * TODO remove this method
5035 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5036 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5037 * throw new Error("Implementation Error. No skipList defined for this
5038 * Jalview2XML instance."); } return (AlignFrame)
5039 * skipList.get(view.getSequenceSetId()); }
5043 * Check if the Jalview view contained in object should be skipped or not.
5046 * @return true if view's sequenceSetId is a key in skipList
5048 private boolean skipViewport(JalviewModel object)
5050 if (skipList == null)
5055 if (skipList.containsKey(
5056 id = object.getJalviewModelSequence().getViewport()[0]
5057 .getSequenceSetId()))
5059 if (Cache.log != null && Cache.log.isDebugEnabled())
5061 Cache.log.debug("Skipping seuqence set id " + id);
5068 public void addToSkipList(AlignFrame af)
5070 if (skipList == null)
5072 skipList = new Hashtable();
5074 skipList.put(af.getViewport().getSequenceSetId(), af);
5077 public void clearSkipList()
5079 if (skipList != null)
5086 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5087 boolean ignoreUnrefed)
5089 jalview.datamodel.AlignmentI ds = getDatasetFor(
5090 vamsasSet.getDatasetId());
5091 Vector dseqs = null;
5094 // create a list of new dataset sequences
5095 dseqs = new Vector();
5097 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5099 Sequence vamsasSeq = vamsasSet.getSequence(i);
5100 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5102 // create a new dataset
5105 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5106 dseqs.copyInto(dsseqs);
5107 ds = new jalview.datamodel.Alignment(dsseqs);
5108 debug("Created new dataset " + vamsasSet.getDatasetId()
5109 + " for alignment " + System.identityHashCode(al));
5110 addDatasetRef(vamsasSet.getDatasetId(), ds);
5112 // set the dataset for the newly imported alignment.
5113 if (al.getDataset() == null && !ignoreUnrefed)
5122 * sequence definition to create/merge dataset sequence for
5126 * vector to add new dataset sequence to
5127 * @param ignoreUnrefed
5128 * - when true, don't create new sequences from vamsasSeq if it's id
5129 * doesn't already have an asssociated Jalview sequence.
5131 * - used to reorder the sequence in the alignment according to the
5132 * vamsasSeq array ordering, to preserve ordering of dataset
5134 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5135 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5137 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5139 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5140 boolean reorder = false;
5141 SequenceI dsq = null;
5142 if (sq != null && sq.getDatasetSequence() != null)
5144 dsq = sq.getDatasetSequence();
5150 if (sq == null && ignoreUnrefed)
5154 String sqid = vamsasSeq.getDsseqid();
5157 // need to create or add a new dataset sequence reference to this sequence
5160 dsq = seqRefIds.get(sqid);
5165 // make a new dataset sequence
5166 dsq = sq.createDatasetSequence();
5169 // make up a new dataset reference for this sequence
5170 sqid = seqHash(dsq);
5172 dsq.setVamsasId(uniqueSetSuffix + sqid);
5173 seqRefIds.put(sqid, dsq);
5178 dseqs.addElement(dsq);
5183 ds.addSequence(dsq);
5189 { // make this dataset sequence sq's dataset sequence
5190 sq.setDatasetSequence(dsq);
5191 // and update the current dataset alignment
5196 if (!dseqs.contains(dsq))
5203 if (ds.findIndex(dsq) < 0)
5205 ds.addSequence(dsq);
5212 // TODO: refactor this as a merge dataset sequence function
5213 // now check that sq (the dataset sequence) sequence really is the union of
5214 // all references to it
5215 // boolean pre = sq.getStart() < dsq.getStart();
5216 // boolean post = sq.getEnd() > dsq.getEnd();
5220 // StringBuffer sb = new StringBuffer();
5221 String newres = jalview.analysis.AlignSeq.extractGaps(
5222 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5223 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5224 && newres.length() > dsq.getLength())
5226 // Update with the longer sequence.
5230 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5231 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5232 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5233 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5235 dsq.setSequence(newres);
5237 // TODO: merges will never happen if we 'know' we have the real dataset
5238 // sequence - this should be detected when id==dssid
5240 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5241 // + (pre ? "prepended" : "") + " "
5242 // + (post ? "appended" : ""));
5247 // sequence refs are identical. We may need to update the existing dataset
5248 // alignment with this one, though.
5249 if (ds != null && dseqs == null)
5251 int opos = ds.findIndex(dsq);
5252 SequenceI tseq = null;
5253 if (opos != -1 && vseqpos != opos)
5255 // remove from old position
5256 ds.deleteSequence(dsq);
5258 if (vseqpos < ds.getHeight())
5260 if (vseqpos != opos)
5262 // save sequence at destination position
5263 tseq = ds.getSequenceAt(vseqpos);
5264 ds.replaceSequenceAt(vseqpos, dsq);
5265 ds.addSequence(tseq);
5270 ds.addSequence(dsq);
5277 * TODO use AlignmentI here and in related methods - needs
5278 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5280 Hashtable<String, AlignmentI> datasetIds = null;
5282 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5284 private AlignmentI getDatasetFor(String datasetId)
5286 if (datasetIds == null)
5288 datasetIds = new Hashtable<>();
5291 if (datasetIds.containsKey(datasetId))
5293 return datasetIds.get(datasetId);
5298 private void addDatasetRef(String datasetId, AlignmentI dataset)
5300 if (datasetIds == null)
5302 datasetIds = new Hashtable<>();
5304 datasetIds.put(datasetId, dataset);
5308 * make a new dataset ID for this jalview dataset alignment
5313 private String getDatasetIdRef(AlignmentI dataset)
5315 if (dataset.getDataset() != null)
5317 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5319 String datasetId = makeHashCode(dataset, null);
5320 if (datasetId == null)
5322 // make a new datasetId and record it
5323 if (dataset2Ids == null)
5325 dataset2Ids = new IdentityHashMap<>();
5329 datasetId = dataset2Ids.get(dataset);
5331 if (datasetId == null)
5333 datasetId = "ds" + dataset2Ids.size() + 1;
5334 dataset2Ids.put(dataset, datasetId);
5340 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5342 for (int d = 0; d < sequence.getDBRefCount(); d++)
5344 DBRef dr = sequence.getDBRef(d);
5345 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5346 sequence.getDBRef(d).getSource(),
5347 sequence.getDBRef(d).getVersion(),
5348 sequence.getDBRef(d).getAccessionId());
5349 if (dr.getMapping() != null)
5351 entry.setMap(addMapping(dr.getMapping()));
5353 datasetSequence.addDBRef(entry);
5357 private jalview.datamodel.Mapping addMapping(Mapping m)
5359 SequenceI dsto = null;
5360 // Mapping m = dr.getMapping();
5361 int fr[] = new int[m.getMapListFromCount() * 2];
5362 Enumeration f = m.enumerateMapListFrom();
5363 for (int _i = 0; f.hasMoreElements(); _i += 2)
5365 MapListFrom mf = (MapListFrom) f.nextElement();
5366 fr[_i] = mf.getStart();
5367 fr[_i + 1] = mf.getEnd();
5369 int fto[] = new int[m.getMapListToCount() * 2];
5370 f = m.enumerateMapListTo();
5371 for (int _i = 0; f.hasMoreElements(); _i += 2)
5373 MapListTo mf = (MapListTo) f.nextElement();
5374 fto[_i] = mf.getStart();
5375 fto[_i + 1] = mf.getEnd();
5377 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5378 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5379 if (m.getMappingChoice() != null)
5381 MappingChoice mc = m.getMappingChoice();
5382 if (mc.getDseqFor() != null)
5384 String dsfor = "" + mc.getDseqFor();
5385 if (seqRefIds.containsKey(dsfor))
5390 jmap.setTo(seqRefIds.get(dsfor));
5394 frefedSequence.add(newMappingRef(dsfor, jmap));
5400 * local sequence definition
5402 Sequence ms = mc.getSequence();
5403 SequenceI djs = null;
5404 String sqid = ms.getDsseqid();
5405 if (sqid != null && sqid.length() > 0)
5408 * recover dataset sequence
5410 djs = seqRefIds.get(sqid);
5415 "Warning - making up dataset sequence id for DbRef sequence map reference");
5416 sqid = ((Object) ms).toString(); // make up a new hascode for
5417 // undefined dataset sequence hash
5418 // (unlikely to happen)
5424 * make a new dataset sequence and add it to refIds hash
5426 djs = new jalview.datamodel.Sequence(ms.getName(),
5428 djs.setStart(jmap.getMap().getToLowest());
5429 djs.setEnd(jmap.getMap().getToHighest());
5430 djs.setVamsasId(uniqueSetSuffix + sqid);
5432 incompleteSeqs.put(sqid, djs);
5433 seqRefIds.put(sqid, djs);
5436 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5446 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5447 * view as XML (but not to file), and then reloading it
5452 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5455 JalviewModel jm = saveState(ap, null, null, null);
5457 uniqueSetSuffix = "";
5458 jm.getJalviewModelSequence().getViewport(0).setId(null);
5459 // we don't overwrite the view we just copied
5461 if (this.frefedSequence == null)
5463 frefedSequence = new Vector<>();
5466 viewportsAdded.clear();
5468 AlignFrame af = loadFromObject(jm, null, false, null);
5469 af.alignPanels.clear();
5470 af.closeMenuItem_actionPerformed(true);
5473 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5474 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5475 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5476 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5477 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5480 return af.alignPanel;
5483 private Hashtable jvids2vobj;
5485 private void warn(String msg)
5490 private void warn(String msg, Exception e)
5492 if (Cache.log != null)
5496 Cache.log.warn(msg, e);
5500 Cache.log.warn(msg);
5505 System.err.println("Warning: " + msg);
5508 e.printStackTrace();
5513 private void debug(String string)
5515 debug(string, null);
5518 private void debug(String msg, Exception e)
5520 if (Cache.log != null)
5524 Cache.log.debug(msg, e);
5528 Cache.log.debug(msg);
5533 System.err.println("Warning: " + msg);
5536 e.printStackTrace();
5542 * set the object to ID mapping tables used to write/recover objects and XML
5543 * ID strings for the jalview project. If external tables are provided then
5544 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5545 * object goes out of scope. - also populates the datasetIds hashtable with
5546 * alignment objects containing dataset sequences
5549 * Map from ID strings to jalview datamodel
5551 * Map from jalview datamodel to ID strings
5555 public void setObjectMappingTables(Hashtable vobj2jv,
5556 IdentityHashMap jv2vobj)
5558 this.jv2vobj = jv2vobj;
5559 this.vobj2jv = vobj2jv;
5560 Iterator ds = jv2vobj.keySet().iterator();
5562 while (ds.hasNext())
5564 Object jvobj = ds.next();
5565 id = jv2vobj.get(jvobj).toString();
5566 if (jvobj instanceof jalview.datamodel.Alignment)
5568 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5570 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5573 else if (jvobj instanceof jalview.datamodel.Sequence)
5575 // register sequence object so the XML parser can recover it.
5576 if (seqRefIds == null)
5578 seqRefIds = new HashMap<>();
5580 if (seqsToIds == null)
5582 seqsToIds = new IdentityHashMap<>();
5584 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5585 seqsToIds.put((SequenceI) jvobj, id);
5587 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5590 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5591 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5592 if (jvann.annotationId == null)
5594 jvann.annotationId = anid;
5596 if (!jvann.annotationId.equals(anid))
5598 // TODO verify that this is the correct behaviour
5599 this.warn("Overriding Annotation ID for " + anid
5600 + " from different id : " + jvann.annotationId);
5601 jvann.annotationId = anid;
5604 else if (jvobj instanceof String)
5606 if (jvids2vobj == null)
5608 jvids2vobj = new Hashtable();
5609 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5614 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5620 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5621 * objects created from the project archive. If string is null (default for
5622 * construction) then suffix will be set automatically.
5626 public void setUniqueSetSuffix(String string)
5628 uniqueSetSuffix = string;
5633 * uses skipList2 as the skipList for skipping views on sequence sets
5634 * associated with keys in the skipList
5638 public void setSkipList(Hashtable skipList2)
5640 skipList = skipList2;
5644 * Reads the jar entry of given name and returns its contents, or null if the
5645 * entry is not found.
5648 * @param jarEntryName
5651 protected String readJarEntry(jarInputStreamProvider jprovider,
5652 String jarEntryName)
5654 String result = null;
5655 BufferedReader in = null;
5660 * Reopen the jar input stream and traverse its entries to find a matching
5663 JarInputStream jin = jprovider.getJarInputStream();
5664 JarEntry entry = null;
5667 entry = jin.getNextJarEntry();
5668 } while (entry != null && !entry.getName().equals(jarEntryName));
5672 StringBuilder out = new StringBuilder(256);
5673 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5676 while ((data = in.readLine()) != null)
5680 result = out.toString();
5684 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5686 } catch (Exception ex)
5688 ex.printStackTrace();
5696 } catch (IOException e)
5707 * Returns an incrementing counter (0, 1, 2...)
5711 private synchronized int nextCounter()
5717 * Populates an XML model of the feature colour scheme for one feature type
5719 * @param featureType
5723 protected static jalview.schemabinding.version2.Colour marshalColour(
5724 String featureType, FeatureColourI fcol)
5726 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5727 if (fcol.isSimpleColour())
5729 col.setRGB(Format.getHexString(fcol.getColour()));
5733 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5734 col.setMin(fcol.getMin());
5735 col.setMax(fcol.getMax());
5736 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5737 col.setAutoScale(fcol.isAutoScaled());
5738 col.setThreshold(fcol.getThreshold());
5739 col.setColourByLabel(fcol.isColourByLabel());
5740 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5741 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5742 : ColourThreshTypeType.NONE));
5743 if (fcol.isColourByAttribute())
5745 col.setAttributeName(fcol.getAttributeName());
5747 Color noColour = fcol.getNoColour();
5748 if (noColour == null)
5750 col.setNoValueColour(NoValueColour.NONE);
5752 else if (noColour == fcol.getMaxColour())
5754 col.setNoValueColour(NoValueColour.MAX);
5758 col.setNoValueColour(NoValueColour.MIN);
5761 col.setName(featureType);
5766 * Populates an XML model of the feature filter(s) for one feature type
5768 * @param firstMatcher
5769 * the first (or only) match condition)
5771 * remaining match conditions (if any)
5773 * if true, conditions are and-ed, else or-ed
5775 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5776 Iterator<FeatureMatcherI> filters, boolean and)
5778 MatcherSet result = new MatcherSet();
5780 if (filters.hasNext())
5785 CompoundMatcher compound = new CompoundMatcher();
5786 compound.setAnd(and);
5787 MatcherSet matcher1 = marshalFilter(firstMatcher,
5788 Collections.emptyIterator(), and);
5789 compound.addMatcherSet(matcher1);
5790 FeatureMatcherI nextMatcher = filters.next();
5791 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5792 compound.addMatcherSet(matcher2);
5793 result.setCompoundMatcher(compound);
5798 * single condition matcher
5800 MatchCondition matcherModel = new MatchCondition();
5801 matcherModel.setCondition(
5802 firstMatcher.getMatcher().getCondition().getStableName());
5803 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5804 if (firstMatcher.isByAttribute())
5806 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5807 matcherModel.setAttributeName(firstMatcher.getAttribute());
5809 else if (firstMatcher.isByLabel())
5811 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5813 else if (firstMatcher.isByScore())
5815 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5817 result.setMatchCondition(matcherModel);
5824 * Loads one XML model of a feature filter to a Jalview object
5826 * @param featureType
5827 * @param matcherSetModel
5830 protected static FeatureMatcherSetI unmarshalFilter(
5831 String featureType, MatcherSet matcherSetModel)
5833 FeatureMatcherSetI result = new FeatureMatcherSet();
5836 unmarshalFilterConditions(result, matcherSetModel, true);
5837 } catch (IllegalStateException e)
5839 // mixing AND and OR conditions perhaps
5841 String.format("Error reading filter conditions for '%s': %s",
5842 featureType, e.getMessage()));
5843 // return as much as was parsed up to the error
5850 * Adds feature match conditions to matcherSet as unmarshalled from XML
5851 * (possibly recursively for compound conditions)
5854 * @param matcherSetModel
5856 * if true, multiple conditions are AND-ed, else they are OR-ed
5857 * @throws IllegalStateException
5858 * if AND and OR conditions are mixed
5860 protected static void unmarshalFilterConditions(
5861 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5864 MatchCondition mc = matcherSetModel.getMatchCondition();
5870 FeatureMatcherByType filterBy = mc.getBy();
5871 Condition cond = Condition.fromString(mc.getCondition());
5872 String pattern = mc.getValue();
5873 FeatureMatcherI matchCondition = null;
5874 if (filterBy == FeatureMatcherByType.BYLABEL)
5876 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5878 else if (filterBy == FeatureMatcherByType.BYSCORE)
5880 matchCondition = FeatureMatcher.byScore(cond, pattern);
5883 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5885 String[] attNames = mc.getAttributeName();
5886 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5891 * note this throws IllegalStateException if AND-ing to a
5892 * previously OR-ed compound condition, or vice versa
5896 matcherSet.and(matchCondition);
5900 matcherSet.or(matchCondition);
5906 * compound condition
5908 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5910 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5911 if (matchers.length == 2)
5913 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5914 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5918 System.err.println("Malformed compound filter condition");
5924 * Loads one XML model of a feature colour to a Jalview object
5926 * @param colourModel
5929 protected static FeatureColourI unmarshalColour(
5930 jalview.schemabinding.version2.Colour colourModel)
5932 FeatureColourI colour = null;
5934 if (colourModel.hasMax())
5936 Color mincol = null;
5937 Color maxcol = null;
5938 Color noValueColour = null;
5942 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5943 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5944 } catch (Exception e)
5946 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5949 NoValueColour noCol = colourModel.getNoValueColour();
5950 if (noCol == NoValueColour.MIN)
5952 noValueColour = mincol;
5954 else if (noCol == NoValueColour.MAX)
5956 noValueColour = maxcol;
5959 colour = new FeatureColour(mincol, maxcol, noValueColour,
5960 colourModel.getMin(),
5961 colourModel.getMax());
5962 String[] attributes = colourModel.getAttributeName();
5963 if (attributes != null && attributes.length > 0)
5965 colour.setAttributeName(attributes);
5967 if (colourModel.hasAutoScale())
5969 colour.setAutoScaled(colourModel.getAutoScale());
5971 if (colourModel.hasColourByLabel())
5973 colour.setColourByLabel(colourModel.getColourByLabel());
5975 if (colourModel.hasThreshold())
5977 colour.setThreshold(colourModel.getThreshold());
5979 ColourThreshTypeType ttyp = colourModel.getThreshType();
5982 if (ttyp == ColourThreshTypeType.ABOVE)
5984 colour.setAboveThreshold(true);
5986 else if (ttyp == ColourThreshTypeType.BELOW)
5988 colour.setBelowThreshold(true);
5994 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5995 colour = new FeatureColour(color);