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.DBRefEntry;
33 import jalview.datamodel.GraphLine;
34 import jalview.datamodel.PDBEntry;
35 import jalview.datamodel.RnaViewerModel;
36 import jalview.datamodel.SequenceFeature;
37 import jalview.datamodel.SequenceGroup;
38 import jalview.datamodel.SequenceI;
39 import jalview.datamodel.StructureViewerModel;
40 import jalview.datamodel.StructureViewerModel.StructureData;
41 import jalview.datamodel.features.FeatureMatcher;
42 import jalview.datamodel.features.FeatureMatcherI;
43 import jalview.datamodel.features.FeatureMatcherSet;
44 import jalview.datamodel.features.FeatureMatcherSetI;
45 import jalview.ext.varna.RnaModel;
46 import jalview.gui.StructureViewer.ViewerType;
47 import jalview.io.DataSourceType;
48 import jalview.io.FileFormat;
49 import jalview.renderer.ResidueShaderI;
50 import jalview.schemabinding.version2.AlcodMap;
51 import jalview.schemabinding.version2.AlcodonFrame;
52 import jalview.schemabinding.version2.Annotation;
53 import jalview.schemabinding.version2.AnnotationColours;
54 import jalview.schemabinding.version2.AnnotationElement;
55 import jalview.schemabinding.version2.CalcIdParam;
56 import jalview.schemabinding.version2.CompoundMatcher;
57 import jalview.schemabinding.version2.DBRef;
58 import jalview.schemabinding.version2.Features;
59 import jalview.schemabinding.version2.Group;
60 import jalview.schemabinding.version2.HiddenColumns;
61 import jalview.schemabinding.version2.JGroup;
62 import jalview.schemabinding.version2.JSeq;
63 import jalview.schemabinding.version2.JalviewModel;
64 import jalview.schemabinding.version2.JalviewModelSequence;
65 import jalview.schemabinding.version2.MapListFrom;
66 import jalview.schemabinding.version2.MapListTo;
67 import jalview.schemabinding.version2.Mapping;
68 import jalview.schemabinding.version2.MappingChoice;
69 import jalview.schemabinding.version2.MatchCondition;
70 import jalview.schemabinding.version2.MatcherSet;
71 import jalview.schemabinding.version2.OtherData;
72 import jalview.schemabinding.version2.PdbentryItem;
73 import jalview.schemabinding.version2.Pdbids;
74 import jalview.schemabinding.version2.Property;
75 import jalview.schemabinding.version2.RnaViewer;
76 import jalview.schemabinding.version2.SecondaryStructure;
77 import jalview.schemabinding.version2.Sequence;
78 import jalview.schemabinding.version2.SequenceSet;
79 import jalview.schemabinding.version2.SequenceSetProperties;
80 import jalview.schemabinding.version2.Setting;
81 import jalview.schemabinding.version2.StructureState;
82 import jalview.schemabinding.version2.ThresholdLine;
83 import jalview.schemabinding.version2.Tree;
84 import jalview.schemabinding.version2.UserColours;
85 import jalview.schemabinding.version2.Viewport;
86 import jalview.schemabinding.version2.types.ColourThreshTypeType;
87 import jalview.schemabinding.version2.types.FeatureMatcherByType;
88 import jalview.schemabinding.version2.types.NoValueColour;
89 import jalview.schemes.AnnotationColourGradient;
90 import jalview.schemes.ColourSchemeI;
91 import jalview.schemes.ColourSchemeProperty;
92 import jalview.schemes.FeatureColour;
93 import jalview.schemes.ResidueProperties;
94 import jalview.schemes.UserColourScheme;
95 import jalview.structure.StructureSelectionManager;
96 import jalview.structures.models.AAStructureBindingModel;
97 import jalview.util.Format;
98 import jalview.util.MessageManager;
99 import jalview.util.Platform;
100 import jalview.util.StringUtils;
101 import jalview.util.jarInputStreamProvider;
102 import jalview.util.matcher.Condition;
103 import jalview.viewmodel.AlignmentViewport;
104 import jalview.viewmodel.ViewportRanges;
105 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
106 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
107 import jalview.ws.jws2.Jws2Discoverer;
108 import jalview.ws.jws2.dm.AAConSettings;
109 import jalview.ws.jws2.jabaws2.Jws2Instance;
110 import jalview.ws.params.ArgumentI;
111 import jalview.ws.params.AutoCalcSetting;
112 import jalview.ws.params.WsParamSetI;
114 import java.awt.Color;
115 import java.awt.Rectangle;
116 import java.io.BufferedReader;
117 import java.io.DataInputStream;
118 import java.io.DataOutputStream;
120 import java.io.FileInputStream;
121 import java.io.FileOutputStream;
122 import java.io.IOException;
123 import java.io.InputStreamReader;
124 import java.io.OutputStreamWriter;
125 import java.io.PrintWriter;
126 import java.lang.reflect.InvocationTargetException;
127 import java.net.MalformedURLException;
129 import java.util.ArrayList;
130 import java.util.Arrays;
131 import java.util.Collections;
132 import java.util.Enumeration;
133 import java.util.HashMap;
134 import java.util.HashSet;
135 import java.util.Hashtable;
136 import java.util.IdentityHashMap;
137 import java.util.Iterator;
138 import java.util.LinkedHashMap;
139 import java.util.List;
140 import java.util.Map;
141 import java.util.Map.Entry;
142 import java.util.Set;
143 import java.util.Vector;
144 import java.util.jar.JarEntry;
145 import java.util.jar.JarInputStream;
146 import java.util.jar.JarOutputStream;
148 import javax.swing.JInternalFrame;
149 import javax.swing.SwingUtilities;
151 import org.exolab.castor.xml.Marshaller;
152 import org.exolab.castor.xml.Unmarshaller;
155 * Write out the current jalview desktop state as a Jalview XML stream.
157 * Note: the vamsas objects referred to here are primitive versions of the
158 * VAMSAS project schema elements - they are not the same and most likely never
162 * @version $Revision: 1.134 $
164 public class Jalview2XML
166 private static final String VIEWER_PREFIX = "viewer_";
168 private static final String RNA_PREFIX = "rna_";
170 private static final String UTF_8 = "UTF-8";
172 // use this with nextCounter() to make unique names for entities
173 private int counter = 0;
176 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
177 * of sequence objects are created.
179 IdentityHashMap<SequenceI, String> seqsToIds = null;
182 * jalview XML Sequence ID to jalview sequence object reference (both dataset
183 * and alignment sequences. Populated as XML reps of sequence objects are
186 Map<String, SequenceI> seqRefIds = null;
188 Map<String, SequenceI> incompleteSeqs = null;
190 List<SeqFref> frefedSequence = null;
192 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
195 * Map of reconstructed AlignFrame objects that appear to have come from
196 * SplitFrame objects (have a dna/protein complement view).
198 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
201 * Map from displayed rna structure models to their saved session state jar
204 private Map<RnaModel, String> rnaSessions = new HashMap<>();
207 * create/return unique hash string for sq
210 * @return new or existing unique string for sq
212 String seqHash(SequenceI sq)
214 if (seqsToIds == null)
218 if (seqsToIds.containsKey(sq))
220 return seqsToIds.get(sq);
224 // create sequential key
225 String key = "sq" + (seqsToIds.size() + 1);
226 key = makeHashCode(sq, key); // check we don't have an external reference
228 seqsToIds.put(sq, key);
235 if (seqsToIds == null)
237 seqsToIds = new IdentityHashMap<>();
239 if (seqRefIds == null)
241 seqRefIds = new HashMap<>();
243 if (incompleteSeqs == null)
245 incompleteSeqs = new HashMap<>();
247 if (frefedSequence == null)
249 frefedSequence = new ArrayList<>();
257 public Jalview2XML(boolean raiseGUI)
259 this.raiseGUI = raiseGUI;
263 * base class for resolving forward references to sequences by their ID
268 abstract class SeqFref
274 public SeqFref(String _sref, String type)
280 public String getSref()
285 public SequenceI getSrefSeq()
287 return seqRefIds.get(sref);
290 public boolean isResolvable()
292 return seqRefIds.get(sref) != null;
295 public SequenceI getSrefDatasetSeq()
297 SequenceI sq = seqRefIds.get(sref);
300 while (sq.getDatasetSequence() != null)
302 sq = sq.getDatasetSequence();
309 * @return true if the forward reference was fully resolved
311 abstract boolean resolve();
314 public String toString()
316 return type + " reference to " + sref;
321 * create forward reference for a mapping
327 public SeqFref newMappingRef(final String sref,
328 final jalview.datamodel.Mapping _jmap)
330 SeqFref fref = new SeqFref(sref, "Mapping")
332 public jalview.datamodel.Mapping jmap = _jmap;
337 SequenceI seq = getSrefDatasetSeq();
349 public SeqFref newAlcodMapRef(final String sref,
350 final AlignedCodonFrame _cf,
351 final jalview.datamodel.Mapping _jmap)
354 SeqFref fref = new SeqFref(sref, "Codon Frame")
356 AlignedCodonFrame cf = _cf;
358 public jalview.datamodel.Mapping mp = _jmap;
361 public boolean isResolvable()
363 return super.isResolvable() && mp.getTo() != null;
369 SequenceI seq = getSrefDatasetSeq();
374 cf.addMap(seq, mp.getTo(), mp.getMap());
381 public void resolveFrefedSequences()
383 Iterator<SeqFref> nextFref = frefedSequence.iterator();
384 int toresolve = frefedSequence.size();
385 int unresolved = 0, failedtoresolve = 0;
386 while (nextFref.hasNext())
388 SeqFref ref = nextFref.next();
389 if (ref.isResolvable())
401 } catch (Exception x)
404 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
417 System.err.println("Jalview Project Import: There were " + unresolved
418 + " forward references left unresolved on the stack.");
420 if (failedtoresolve > 0)
422 System.err.println("SERIOUS! " + failedtoresolve
423 + " resolvable forward references failed to resolve.");
425 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
428 "Jalview Project Import: There are " + incompleteSeqs.size()
429 + " sequences which may have incomplete metadata.");
430 if (incompleteSeqs.size() < 10)
432 for (SequenceI s : incompleteSeqs.values())
434 System.err.println(s.toString());
440 "Too many to report. Skipping output of incomplete sequences.");
446 * This maintains a map of viewports, the key being the seqSetId. Important to
447 * set historyItem and redoList for multiple views
449 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
451 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
453 String uniqueSetSuffix = "";
456 * List of pdbfiles added to Jar
458 List<String> pdbfiles = null;
460 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
461 public void saveState(File statefile)
463 FileOutputStream fos = null;
466 fos = new FileOutputStream(statefile);
467 JarOutputStream jout = new JarOutputStream(fos);
470 } catch (Exception e)
472 // TODO: inform user of the problem - they need to know if their data was
474 if (errorMessage == null)
476 errorMessage = "Couldn't write Jalview Archive to output file '"
477 + statefile + "' - See console error log for details";
481 errorMessage += "(output file was '" + statefile + "')";
491 } catch (IOException e)
501 * Writes a jalview project archive to the given Jar output stream.
505 public void saveState(JarOutputStream jout)
507 AlignFrame[] frames = Desktop.getAlignFrames();
513 saveAllFrames(Arrays.asList(frames), jout);
517 * core method for storing state for a set of AlignFrames.
520 * - frames involving all data to be exported (including containing
523 * - project output stream
525 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
527 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
530 * ensure cached data is clear before starting
532 // todo tidy up seqRefIds, seqsToIds initialisation / reset
534 splitFrameCandidates.clear();
539 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
540 // //////////////////////////////////////////////////
542 List<String> shortNames = new ArrayList<>();
543 List<String> viewIds = new ArrayList<>();
546 for (int i = frames.size() - 1; i > -1; i--)
548 AlignFrame af = frames.get(i);
550 if (skipList != null && skipList
551 .containsKey(af.getViewport().getSequenceSetId()))
556 String shortName = makeFilename(af, shortNames);
558 int ap, apSize = af.alignPanels.size();
560 for (ap = 0; ap < apSize; ap++)
562 AlignmentPanel apanel = af.alignPanels.get(ap);
563 String fileName = apSize == 1 ? shortName : ap + shortName;
564 if (!fileName.endsWith(".xml"))
566 fileName = fileName + ".xml";
569 saveState(apanel, fileName, jout, viewIds);
571 String dssid = getDatasetIdRef(
572 af.getViewport().getAlignment().getDataset());
573 if (!dsses.containsKey(dssid))
575 dsses.put(dssid, af);
580 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
586 } catch (Exception foo)
591 } catch (Exception ex)
593 // TODO: inform user of the problem - they need to know if their data was
595 if (errorMessage == null)
597 errorMessage = "Couldn't write Jalview Archive - see error output for details";
599 ex.printStackTrace();
604 * Generates a distinct file name, based on the title of the AlignFrame, by
605 * appending _n for increasing n until an unused name is generated. The new
606 * name (without its extension) is added to the list.
610 * @return the generated name, with .xml extension
612 protected String makeFilename(AlignFrame af, List<String> namesUsed)
614 String shortName = af.getTitle();
616 if (shortName.indexOf(File.separatorChar) > -1)
618 shortName = shortName
619 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
624 while (namesUsed.contains(shortName))
626 if (shortName.endsWith("_" + (count - 1)))
628 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
631 shortName = shortName.concat("_" + count);
635 namesUsed.add(shortName);
637 if (!shortName.endsWith(".xml"))
639 shortName = shortName + ".xml";
644 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
645 public boolean saveAlignment(AlignFrame af, String jarFile,
650 FileOutputStream fos = new FileOutputStream(jarFile);
651 JarOutputStream jout = new JarOutputStream(fos);
652 List<AlignFrame> frames = new ArrayList<>();
654 // resolve splitframes
655 if (af.getViewport().getCodingComplement() != null)
657 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
663 saveAllFrames(frames, jout);
667 } catch (Exception foo)
673 } catch (Exception ex)
675 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
676 ex.printStackTrace();
681 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
682 String fileName, JarOutputStream jout)
685 for (String dssids : dsses.keySet())
687 AlignFrame _af = dsses.get(dssids);
688 String jfileName = fileName + " Dataset for " + _af.getTitle();
689 if (!jfileName.endsWith(".xml"))
691 jfileName = jfileName + ".xml";
693 saveState(_af.alignPanel, jfileName, true, jout, null);
698 * create a JalviewModel from an alignment view and marshall it to a
702 * panel to create jalview model for
704 * name of alignment panel written to output stream
711 public JalviewModel saveState(AlignmentPanel ap, String fileName,
712 JarOutputStream jout, List<String> viewIds)
714 return saveState(ap, fileName, false, jout, viewIds);
718 * create a JalviewModel from an alignment view and marshall it to a
722 * panel to create jalview model for
724 * name of alignment panel written to output stream
726 * when true, only write the dataset for the alignment, not the data
727 * associated with the view.
733 public JalviewModel saveState(AlignmentPanel ap, String fileName,
734 boolean storeDS, JarOutputStream jout, List<String> viewIds)
738 viewIds = new ArrayList<>();
743 List<UserColourScheme> userColours = new ArrayList<>();
745 AlignViewport av = ap.av;
746 ViewportRanges vpRanges = av.getRanges();
748 JalviewModel object = new JalviewModel();
749 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
751 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
753 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
756 * rjal is full height alignment, jal is actual alignment with full metadata
757 * but excludes hidden sequences.
759 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
761 if (av.hasHiddenRows())
763 rjal = jal.getHiddenSequences().getFullAlignment();
766 SequenceSet vamsasSet = new SequenceSet();
768 JalviewModelSequence jms = new JalviewModelSequence();
770 vamsasSet.setGapChar(jal.getGapCharacter() + "");
772 if (jal.getDataset() != null)
774 // dataset id is the dataset's hashcode
775 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
778 // switch jal and the dataset
779 jal = jal.getDataset();
783 if (jal.getProperties() != null)
785 Enumeration en = jal.getProperties().keys();
786 while (en.hasMoreElements())
788 String key = en.nextElement().toString();
789 SequenceSetProperties ssp = new SequenceSetProperties();
791 ssp.setValue(jal.getProperties().get(key).toString());
792 vamsasSet.addSequenceSetProperties(ssp);
797 Set<String> calcIdSet = new HashSet<>();
798 // record the set of vamsas sequence XML POJO we create.
799 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
801 for (final SequenceI jds : rjal.getSequences())
803 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
804 : jds.getDatasetSequence();
805 String id = seqHash(jds);
806 if (vamsasSetIds.get(id) == null)
808 if (seqRefIds.get(id) != null && !storeDS)
810 // This happens for two reasons: 1. multiple views are being
812 // 2. the hashCode has collided with another sequence's code. This
814 // HAPPEN! (PF00072.15.stk does this)
815 // JBPNote: Uncomment to debug writing out of files that do not read
816 // back in due to ArrayOutOfBoundExceptions.
817 // System.err.println("vamsasSeq backref: "+id+"");
818 // System.err.println(jds.getName()+"
819 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
820 // System.err.println("Hashcode: "+seqHash(jds));
821 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
822 // System.err.println(rsq.getName()+"
823 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
824 // System.err.println("Hashcode: "+seqHash(rsq));
828 vamsasSeq = createVamsasSequence(id, jds);
829 vamsasSet.addSequence(vamsasSeq);
830 vamsasSetIds.put(id, vamsasSeq);
831 seqRefIds.put(id, jds);
835 jseq.setStart(jds.getStart());
836 jseq.setEnd(jds.getEnd());
837 jseq.setColour(av.getSequenceColour(jds).getRGB());
839 jseq.setId(id); // jseq id should be a string not a number
842 // Store any sequences this sequence represents
843 if (av.hasHiddenRows())
845 // use rjal, contains the full height alignment
847 av.getAlignment().getHiddenSequences().isHidden(jds));
849 if (av.isHiddenRepSequence(jds))
851 jalview.datamodel.SequenceI[] reps = av
852 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
854 for (int h = 0; h < reps.length; h++)
858 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
863 // mark sequence as reference - if it is the reference for this view
866 jseq.setViewreference(jds == jal.getSeqrep());
870 // TODO: omit sequence features from each alignment view's XML dump if we
871 // are storing dataset
872 List<jalview.datamodel.SequenceFeature> sfs = jds
873 .getSequenceFeatures();
874 for (SequenceFeature sf : sfs)
876 Features features = new Features();
878 features.setBegin(sf.getBegin());
879 features.setEnd(sf.getEnd());
880 features.setDescription(sf.getDescription());
881 features.setType(sf.getType());
882 features.setFeatureGroup(sf.getFeatureGroup());
883 features.setScore(sf.getScore());
884 if (sf.links != null)
886 for (int l = 0; l < sf.links.size(); l++)
888 OtherData keyValue = new OtherData();
889 keyValue.setKey("LINK_" + l);
890 keyValue.setValue(sf.links.elementAt(l).toString());
891 features.addOtherData(keyValue);
894 if (sf.otherDetails != null)
897 * save feature attributes, which may be simple strings or
898 * map valued (have sub-attributes)
900 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
902 String key = entry.getKey();
903 Object value = entry.getValue();
904 if (value instanceof Map<?, ?>)
906 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
909 OtherData otherData = new OtherData();
910 otherData.setKey(key);
911 otherData.setKey2(subAttribute.getKey());
912 otherData.setValue(subAttribute.getValue().toString());
913 features.addOtherData(otherData);
918 OtherData otherData = new OtherData();
919 otherData.setKey(key);
920 otherData.setValue(value.toString());
921 features.addOtherData(otherData);
926 jseq.addFeatures(features);
929 if (jdatasq.getAllPDBEntries() != null)
931 Enumeration en = jdatasq.getAllPDBEntries().elements();
932 while (en.hasMoreElements())
934 Pdbids pdb = new Pdbids();
935 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
938 String pdbId = entry.getId();
940 pdb.setType(entry.getType());
943 * Store any structure views associated with this sequence. This
944 * section copes with duplicate entries in the project, so a dataset
945 * only view *should* be coped with sensibly.
947 // This must have been loaded, is it still visible?
948 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
949 String matchedFile = null;
950 for (int f = frames.length - 1; f > -1; f--)
952 if (frames[f] instanceof StructureViewerBase)
954 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
955 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
956 matchedFile, viewFrame);
958 * Only store each structure viewer's state once in the project
959 * jar. First time through only (storeDS==false)
961 String viewId = viewFrame.getViewId();
962 if (!storeDS && !viewIds.contains(viewId))
967 String viewerState = viewFrame.getStateInfo();
968 writeJarEntry(jout, getViewerJarEntryName(viewId),
969 viewerState.getBytes());
970 } catch (IOException e)
973 "Error saving viewer state: " + e.getMessage());
979 if (matchedFile != null || entry.getFile() != null)
981 if (entry.getFile() != null)
984 matchedFile = entry.getFile();
986 pdb.setFile(matchedFile); // entry.getFile());
987 if (pdbfiles == null)
989 pdbfiles = new ArrayList<>();
992 if (!pdbfiles.contains(pdbId))
995 copyFileToJar(jout, matchedFile, pdbId);
999 Enumeration<String> props = entry.getProperties();
1000 if (props.hasMoreElements())
1002 PdbentryItem item = new PdbentryItem();
1003 while (props.hasMoreElements())
1005 Property prop = new Property();
1006 String key = props.nextElement();
1008 prop.setValue(entry.getProperty(key).toString());
1009 item.addProperty(prop);
1011 pdb.addPdbentryItem(item);
1014 jseq.addPdbids(pdb);
1018 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1023 if (!storeDS && av.hasHiddenRows())
1025 jal = av.getAlignment();
1029 if (storeDS && jal.getCodonFrames() != null)
1031 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1032 for (AlignedCodonFrame acf : jac)
1034 AlcodonFrame alc = new AlcodonFrame();
1035 if (acf.getProtMappings() != null
1036 && acf.getProtMappings().length > 0)
1038 boolean hasMap = false;
1039 SequenceI[] dnas = acf.getdnaSeqs();
1040 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1041 for (int m = 0; m < pmaps.length; m++)
1043 AlcodMap alcmap = new AlcodMap();
1044 alcmap.setDnasq(seqHash(dnas[m]));
1046 createVamsasMapping(pmaps[m], dnas[m], null, false));
1047 alc.addAlcodMap(alcmap);
1052 vamsasSet.addAlcodonFrame(alc);
1055 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1057 // AlcodonFrame alc = new AlcodonFrame();
1058 // vamsasSet.addAlcodonFrame(alc);
1059 // for (int p = 0; p < acf.aaWidth; p++)
1061 // Alcodon cmap = new Alcodon();
1062 // if (acf.codons[p] != null)
1064 // // Null codons indicate a gapped column in the translated peptide
1066 // cmap.setPos1(acf.codons[p][0]);
1067 // cmap.setPos2(acf.codons[p][1]);
1068 // cmap.setPos3(acf.codons[p][2]);
1070 // alc.addAlcodon(cmap);
1072 // if (acf.getProtMappings() != null
1073 // && acf.getProtMappings().length > 0)
1075 // SequenceI[] dnas = acf.getdnaSeqs();
1076 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1077 // for (int m = 0; m < pmaps.length; m++)
1079 // AlcodMap alcmap = new AlcodMap();
1080 // alcmap.setDnasq(seqHash(dnas[m]));
1081 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1083 // alc.addAlcodMap(alcmap);
1090 // /////////////////////////////////
1091 if (!storeDS && av.getCurrentTree() != null)
1093 // FIND ANY ASSOCIATED TREES
1094 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1095 if (Desktop.desktop != null)
1097 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1099 for (int t = 0; t < frames.length; t++)
1101 if (frames[t] instanceof TreePanel)
1103 TreePanel tp = (TreePanel) frames[t];
1105 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1107 Tree tree = new Tree();
1108 tree.setTitle(tp.getTitle());
1109 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1110 tree.setNewick(tp.getTree().print());
1111 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1113 tree.setFitToWindow(tp.fitToWindow.getState());
1114 tree.setFontName(tp.getTreeFont().getName());
1115 tree.setFontSize(tp.getTreeFont().getSize());
1116 tree.setFontStyle(tp.getTreeFont().getStyle());
1117 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1119 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1120 tree.setShowDistances(tp.distanceMenu.getState());
1122 tree.setHeight(tp.getHeight());
1123 tree.setWidth(tp.getWidth());
1124 tree.setXpos(tp.getX());
1125 tree.setYpos(tp.getY());
1126 tree.setId(makeHashCode(tp, null));
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.getViewName());
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 List<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, n = dbrefs.size(); d < n; d++)
2133 DBRef dbref = new DBRef();
2134 DBRefEntry e = dbrefs.get(d);
2135 dbref.setSource(e.getSource());
2136 dbref.setVersion(e.getVersion());
2137 dbref.setAccessionId(e.getAccessionId());
2140 Mapping mp = createVamsasMapping(e.getMap(), parentseq,
2142 dbref.setMapping(mp);
2144 vamsasSeq.addDBRef(dbref);
2150 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2151 SequenceI parentseq, SequenceI jds, boolean recurse)
2154 if (jmp.getMap() != null)
2158 jalview.util.MapList mlst = jmp.getMap();
2159 List<int[]> r = mlst.getFromRanges();
2160 for (int[] range : r)
2162 MapListFrom mfrom = new MapListFrom();
2163 mfrom.setStart(range[0]);
2164 mfrom.setEnd(range[1]);
2165 mp.addMapListFrom(mfrom);
2167 r = mlst.getToRanges();
2168 for (int[] range : r)
2170 MapListTo mto = new MapListTo();
2171 mto.setStart(range[0]);
2172 mto.setEnd(range[1]);
2173 mp.addMapListTo(mto);
2175 mp.setMapFromUnit(mlst.getFromRatio());
2176 mp.setMapToUnit(mlst.getToRatio());
2177 if (jmp.getTo() != null)
2179 MappingChoice mpc = new MappingChoice();
2181 // check/create ID for the sequence referenced by getTo()
2184 SequenceI ps = null;
2185 if (parentseq != jmp.getTo()
2186 && parentseq.getDatasetSequence() != jmp.getTo())
2188 // chaining dbref rather than a handshaking one
2189 jmpid = seqHash(ps = jmp.getTo());
2193 jmpid = seqHash(ps = parentseq);
2195 mpc.setDseqFor(jmpid);
2196 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2198 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2199 seqRefIds.put(mpc.getDseqFor(), ps);
2203 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2206 mp.setMappingChoice(mpc);
2212 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2213 List<UserColourScheme> userColours, JalviewModelSequence jms)
2216 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2217 boolean newucs = false;
2218 if (!userColours.contains(ucs))
2220 userColours.add(ucs);
2223 id = "ucs" + userColours.indexOf(ucs);
2226 // actually create the scheme's entry in the XML model
2227 java.awt.Color[] colours = ucs.getColours();
2228 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2229 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2231 for (int i = 0; i < colours.length; i++)
2233 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2234 col.setName(ResidueProperties.aa[i]);
2235 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2236 jbucs.addColour(col);
2238 if (ucs.getLowerCaseColours() != null)
2240 colours = ucs.getLowerCaseColours();
2241 for (int i = 0; i < colours.length; i++)
2243 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2244 col.setName(ResidueProperties.aa[i].toLowerCase());
2245 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2246 jbucs.addColour(col);
2251 uc.setUserColourScheme(jbucs);
2252 jms.addUserColours(uc);
2258 jalview.schemes.UserColourScheme getUserColourScheme(
2259 JalviewModelSequence jms, String id)
2261 UserColours[] uc = jms.getUserColours();
2262 UserColours colours = null;
2264 for (int i = 0; i < uc.length; i++)
2266 if (uc[i].getId().equals(id))
2274 java.awt.Color[] newColours = new java.awt.Color[24];
2276 for (int i = 0; i < 24; i++)
2278 newColours[i] = new java.awt.Color(Integer.parseInt(
2279 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2282 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2285 if (colours.getUserColourScheme().getColourCount() > 24)
2287 newColours = new java.awt.Color[23];
2288 for (int i = 0; i < 23; i++)
2290 newColours[i] = new java.awt.Color(Integer.parseInt(
2291 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2294 ucs.setLowerCaseColours(newColours);
2301 * contains last error message (if any) encountered by XML loader.
2303 String errorMessage = null;
2306 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2307 * exceptions are raised during project XML parsing
2309 public boolean attemptversion1parse = true;
2312 * Load a jalview project archive from a jar file
2315 * - HTTP URL or filename
2317 public AlignFrame loadJalviewAlign(final String file)
2320 jalview.gui.AlignFrame af = null;
2324 // create list to store references for any new Jmol viewers created
2325 newStructureViewers = new Vector<>();
2326 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2327 // Workaround is to make sure caller implements the JarInputStreamProvider
2329 // so we can re-open the jar input stream for each entry.
2331 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2332 af = loadJalviewAlign(jprovider);
2333 af.setMenusForViewport();
2335 } catch (MalformedURLException e)
2337 errorMessage = "Invalid URL format for '" + file + "'";
2343 SwingUtilities.invokeAndWait(new Runnable()
2348 setLoadingFinishedForNewStructureViewers();
2351 } catch (Exception x)
2353 System.err.println("Error loading alignment: " + x.getMessage());
2359 private jarInputStreamProvider createjarInputStreamProvider(
2360 final String file) throws MalformedURLException
2363 errorMessage = null;
2364 uniqueSetSuffix = null;
2366 viewportsAdded.clear();
2367 frefedSequence = null;
2369 if (file.startsWith("http://"))
2371 url = new URL(file);
2373 final URL _url = url;
2374 return new jarInputStreamProvider()
2378 public JarInputStream getJarInputStream() throws IOException
2382 return new JarInputStream(_url.openStream());
2386 return new JarInputStream(new FileInputStream(file));
2391 public String getFilename()
2399 * Recover jalview session from a jalview project archive. Caller may
2400 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2401 * themselves. Any null fields will be initialised with default values,
2402 * non-null fields are left alone.
2407 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2409 errorMessage = null;
2410 if (uniqueSetSuffix == null)
2412 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2414 if (seqRefIds == null)
2418 AlignFrame af = null, _af = null;
2419 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2420 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2421 final String file = jprovider.getFilename();
2424 JarInputStream jin = null;
2425 JarEntry jarentry = null;
2430 jin = jprovider.getJarInputStream();
2431 for (int i = 0; i < entryCount; i++)
2433 jarentry = jin.getNextJarEntry();
2436 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2438 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2439 JalviewModel object = new JalviewModel();
2441 Unmarshaller unmar = new Unmarshaller(object);
2442 unmar.setValidation(false);
2443 object = (JalviewModel) unmar.unmarshal(in);
2444 if (true) // !skipViewport(object))
2446 _af = loadFromObject(object, file, true, jprovider);
2447 if (_af != null && object.getJalviewModelSequence()
2448 .getViewportCount() > 0)
2452 // store a reference to the first view
2455 if (_af.viewport.isGatherViewsHere())
2457 // if this is a gathered view, keep its reference since
2458 // after gathering views, only this frame will remain
2460 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2462 // Save dataset to register mappings once all resolved
2463 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2464 af.viewport.getAlignment().getDataset());
2469 else if (jarentry != null)
2471 // Some other file here.
2474 } while (jarentry != null);
2475 resolveFrefedSequences();
2476 } catch (IOException ex)
2478 ex.printStackTrace();
2479 errorMessage = "Couldn't locate Jalview XML file : " + file;
2481 "Exception whilst loading jalview XML file : " + ex + "\n");
2482 } catch (Exception ex)
2484 System.err.println("Parsing as Jalview Version 2 file failed.");
2485 ex.printStackTrace(System.err);
2486 if (attemptversion1parse)
2488 // Is Version 1 Jar file?
2491 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2492 } catch (Exception ex2)
2494 System.err.println("Exception whilst loading as jalviewXMLV1:");
2495 ex2.printStackTrace();
2499 if (Desktop.instance != null)
2501 Desktop.instance.stopLoading();
2505 System.out.println("Successfully loaded archive file");
2508 ex.printStackTrace();
2511 "Exception whilst loading jalview XML file : " + ex + "\n");
2512 } catch (OutOfMemoryError e)
2514 // Don't use the OOM Window here
2515 errorMessage = "Out of memory loading jalview XML file";
2516 System.err.println("Out of memory whilst loading jalview XML file");
2517 e.printStackTrace();
2521 * Regather multiple views (with the same sequence set id) to the frame (if
2522 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2523 * views instead of separate frames. Note this doesn't restore a state where
2524 * some expanded views in turn have tabbed views - the last "first tab" read
2525 * in will play the role of gatherer for all.
2527 for (AlignFrame fr : gatherToThisFrame.values())
2529 Desktop.instance.gatherViews(fr);
2532 restoreSplitFrames();
2533 for (AlignmentI ds : importedDatasets.keySet())
2535 if (ds.getCodonFrames() != null)
2537 StructureSelectionManager
2538 .getStructureSelectionManager(Desktop.instance)
2539 .registerMappings(ds.getCodonFrames());
2542 if (errorMessage != null)
2547 if (Desktop.instance != null)
2549 Desktop.instance.stopLoading();
2556 * Try to reconstruct and display SplitFrame windows, where each contains
2557 * complementary dna and protein alignments. Done by pairing up AlignFrame
2558 * objects (created earlier) which have complementary viewport ids associated.
2560 protected void restoreSplitFrames()
2562 List<SplitFrame> gatherTo = new ArrayList<>();
2563 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2564 Map<String, AlignFrame> dna = new HashMap<>();
2567 * Identify the DNA alignments
2569 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2572 AlignFrame af = candidate.getValue();
2573 if (af.getViewport().getAlignment().isNucleotide())
2575 dna.put(candidate.getKey().getId(), af);
2580 * Try to match up the protein complements
2582 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2585 AlignFrame af = candidate.getValue();
2586 if (!af.getViewport().getAlignment().isNucleotide())
2588 String complementId = candidate.getKey().getComplementId();
2589 // only non-null complements should be in the Map
2590 if (complementId != null && dna.containsKey(complementId))
2592 final AlignFrame dnaFrame = dna.get(complementId);
2593 SplitFrame sf = createSplitFrame(dnaFrame, af);
2594 addedToSplitFrames.add(dnaFrame);
2595 addedToSplitFrames.add(af);
2596 dnaFrame.setMenusForViewport();
2597 af.setMenusForViewport();
2598 if (af.viewport.isGatherViewsHere())
2607 * Open any that we failed to pair up (which shouldn't happen!) as
2608 * standalone AlignFrame's.
2610 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2613 AlignFrame af = candidate.getValue();
2614 if (!addedToSplitFrames.contains(af))
2616 Viewport view = candidate.getKey();
2617 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2619 af.setMenusForViewport();
2620 System.err.println("Failed to restore view " + view.getTitle()
2621 + " to split frame");
2626 * Gather back into tabbed views as flagged.
2628 for (SplitFrame sf : gatherTo)
2630 Desktop.instance.gatherViews(sf);
2633 splitFrameCandidates.clear();
2637 * Construct and display one SplitFrame holding DNA and protein alignments.
2640 * @param proteinFrame
2643 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2644 AlignFrame proteinFrame)
2646 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2647 String title = MessageManager.getString("label.linked_view_title");
2648 int width = (int) dnaFrame.getBounds().getWidth();
2649 int height = (int) (dnaFrame.getBounds().getHeight()
2650 + proteinFrame.getBounds().getHeight() + 50);
2653 * SplitFrame location is saved to both enclosed frames
2655 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2656 Desktop.addInternalFrame(splitFrame, title, width, height);
2659 * And compute cDNA consensus (couldn't do earlier with consensus as
2660 * mappings were not yet present)
2662 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2668 * check errorMessage for a valid error message and raise an error box in the
2669 * GUI or write the current errorMessage to stderr and then clear the error
2672 protected void reportErrors()
2674 reportErrors(false);
2677 protected void reportErrors(final boolean saving)
2679 if (errorMessage != null)
2681 final String finalErrorMessage = errorMessage;
2682 errorMessage = null;
2685 javax.swing.SwingUtilities.invokeLater(new Runnable()
2690 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2692 "Error " + (saving ? "saving" : "loading")
2694 JvOptionPane.WARNING_MESSAGE);
2701 "Problem loading Jalview file: " + finalErrorMessage);
2706 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2709 * when set, local views will be updated from view stored in JalviewXML
2710 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2711 * sync if this is set to true.
2713 private final boolean updateLocalViews = false;
2716 * Returns the path to a temporary file holding the PDB file for the given PDB
2717 * id. The first time of asking, searches for a file of that name in the
2718 * Jalview project jar, and copies it to a new temporary file. Any repeat
2719 * requests just return the path to the file previously created.
2725 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2728 if (alreadyLoadedPDB.containsKey(pdbId))
2730 return alreadyLoadedPDB.get(pdbId).toString();
2733 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2735 if (tempFile != null)
2737 alreadyLoadedPDB.put(pdbId, tempFile);
2743 * Copies the jar entry of given name to a new temporary file and returns the
2744 * path to the file, or null if the entry is not found.
2747 * @param jarEntryName
2749 * a prefix for the temporary file name, must be at least three
2752 * null or original file - so new file can be given the same suffix
2756 protected String copyJarEntry(jarInputStreamProvider jprovider,
2757 String jarEntryName, String prefix, String origFile)
2759 BufferedReader in = null;
2760 PrintWriter out = null;
2761 String suffix = ".tmp";
2762 if (origFile == null)
2764 origFile = jarEntryName;
2766 int sfpos = origFile.lastIndexOf(".");
2767 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2769 suffix = "." + origFile.substring(sfpos + 1);
2773 JarInputStream jin = jprovider.getJarInputStream();
2775 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2776 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2777 * FileInputStream(jprovider)); }
2780 JarEntry entry = null;
2783 entry = jin.getNextJarEntry();
2784 } while (entry != null && !entry.getName().equals(jarEntryName));
2787 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2788 File outFile = File.createTempFile(prefix, suffix);
2789 outFile.deleteOnExit();
2790 out = new PrintWriter(new FileOutputStream(outFile));
2793 while ((data = in.readLine()) != null)
2798 String t = outFile.getAbsolutePath();
2803 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2805 } catch (Exception ex)
2807 ex.printStackTrace();
2815 } catch (IOException e)
2829 private class JvAnnotRow
2831 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2838 * persisted version of annotation row from which to take vis properties
2840 public jalview.datamodel.AlignmentAnnotation template;
2843 * original position of the annotation row in the alignment
2849 * Load alignment frame from jalview XML DOM object
2854 * filename source string
2855 * @param loadTreesAndStructures
2856 * when false only create Viewport
2858 * data source provider
2859 * @return alignment frame created from view stored in DOM
2861 AlignFrame loadFromObject(JalviewModel object, String file,
2862 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2864 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2865 Sequence[] vamsasSeq = vamsasSet.getSequence();
2867 JalviewModelSequence jms = object.getJalviewModelSequence();
2869 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2872 // ////////////////////////////////
2875 List<SequenceI> hiddenSeqs = null;
2877 List<SequenceI> tmpseqs = new ArrayList<>();
2879 boolean multipleView = false;
2880 SequenceI referenceseqForView = null;
2881 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2882 int vi = 0; // counter in vamsasSeq array
2883 for (int i = 0; i < jseqs.length; i++)
2885 String seqId = jseqs[i].getId();
2887 SequenceI tmpSeq = seqRefIds.get(seqId);
2890 if (!incompleteSeqs.containsKey(seqId))
2892 // may not need this check, but keep it for at least 2.9,1 release
2893 if (tmpSeq.getStart() != jseqs[i].getStart()
2894 || tmpSeq.getEnd() != jseqs[i].getEnd())
2897 "Warning JAL-2154 regression: updating start/end for sequence "
2898 + tmpSeq.toString() + " to " + jseqs[i]);
2903 incompleteSeqs.remove(seqId);
2905 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2907 // most likely we are reading a dataset XML document so
2908 // update from vamsasSeq section of XML for this sequence
2909 tmpSeq.setName(vamsasSeq[vi].getName());
2910 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2911 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2916 // reading multiple views, so vamsasSeq set is a subset of JSeq
2917 multipleView = true;
2919 tmpSeq.setStart(jseqs[i].getStart());
2920 tmpSeq.setEnd(jseqs[i].getEnd());
2921 tmpseqs.add(tmpSeq);
2925 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2926 vamsasSeq[vi].getSequence());
2927 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2928 tmpSeq.setStart(jseqs[i].getStart());
2929 tmpSeq.setEnd(jseqs[i].getEnd());
2930 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2931 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2932 tmpseqs.add(tmpSeq);
2936 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2938 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2941 if (jseqs[i].getHidden())
2943 if (hiddenSeqs == null)
2945 hiddenSeqs = new ArrayList<>();
2948 hiddenSeqs.add(tmpSeq);
2953 // Create the alignment object from the sequence set
2954 // ///////////////////////////////
2955 SequenceI[] orderedSeqs = tmpseqs
2956 .toArray(new SequenceI[tmpseqs.size()]);
2958 AlignmentI al = null;
2959 // so we must create or recover the dataset alignment before going further
2960 // ///////////////////////////////
2961 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2963 // older jalview projects do not have a dataset - so creat alignment and
2965 al = new Alignment(orderedSeqs);
2966 al.setDataset(null);
2970 boolean isdsal = object.getJalviewModelSequence()
2971 .getViewportCount() == 0;
2974 // we are importing a dataset record, so
2975 // recover reference to an alignment already materialsed as dataset
2976 al = getDatasetFor(vamsasSet.getDatasetId());
2980 // materialse the alignment
2981 al = new Alignment(orderedSeqs);
2985 addDatasetRef(vamsasSet.getDatasetId(), al);
2988 // finally, verify all data in vamsasSet is actually present in al
2989 // passing on flag indicating if it is actually a stored dataset
2990 recoverDatasetFor(vamsasSet, al, isdsal);
2993 if (referenceseqForView != null)
2995 al.setSeqrep(referenceseqForView);
2997 // / Add the alignment properties
2998 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3000 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3001 al.setProperty(ssp.getKey(), ssp.getValue());
3004 // ///////////////////////////////
3006 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3009 // load sequence features, database references and any associated PDB
3010 // structures for the alignment
3012 // prior to 2.10, this part would only be executed the first time a
3013 // sequence was encountered, but not afterwards.
3014 // now, for 2.10 projects, this is also done if the xml doc includes
3015 // dataset sequences not actually present in any particular view.
3017 for (int i = 0; i < vamsasSeq.length; i++)
3019 if (jseqs[i].getFeaturesCount() > 0)
3021 Features[] features = jseqs[i].getFeatures();
3022 for (int f = 0; f < features.length; f++)
3024 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3025 features[f].getDescription(), features[f].getBegin(),
3026 features[f].getEnd(), features[f].getScore(),
3027 features[f].getFeatureGroup());
3028 sf.setStatus(features[f].getStatus());
3031 * load any feature attributes - include map-valued attributes
3033 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3034 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3036 OtherData keyValue = features[f].getOtherData(od);
3037 String attributeName = keyValue.getKey();
3038 String attributeValue = keyValue.getValue();
3039 if (attributeName.startsWith("LINK"))
3041 sf.addLink(attributeValue);
3045 String subAttribute = keyValue.getKey2();
3046 if (subAttribute == null)
3048 // simple string-valued attribute
3049 sf.setValue(attributeName, attributeValue);
3053 // attribute 'key' has sub-attribute 'key2'
3054 if (!mapAttributes.containsKey(attributeName))
3056 mapAttributes.put(attributeName, new HashMap<>());
3058 mapAttributes.get(attributeName).put(subAttribute,
3063 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3066 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3069 // adds feature to datasequence's feature set (since Jalview 2.10)
3070 al.getSequenceAt(i).addSequenceFeature(sf);
3073 if (vamsasSeq[i].getDBRefCount() > 0)
3075 // adds dbrefs to datasequence's set (since Jalview 2.10)
3077 al.getSequenceAt(i).getDatasetSequence() == null
3078 ? al.getSequenceAt(i)
3079 : al.getSequenceAt(i).getDatasetSequence(),
3082 if (jseqs[i].getPdbidsCount() > 0)
3084 Pdbids[] ids = jseqs[i].getPdbids();
3085 for (int p = 0; p < ids.length; p++)
3087 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3088 entry.setId(ids[p].getId());
3089 if (ids[p].getType() != null)
3091 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3093 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3097 entry.setType(PDBEntry.Type.FILE);
3100 // jprovider is null when executing 'New View'
3101 if (ids[p].getFile() != null && jprovider != null)
3103 if (!pdbloaded.containsKey(ids[p].getFile()))
3105 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3110 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3113 if (ids[p].getPdbentryItem() != null)
3115 for (PdbentryItem item : ids[p].getPdbentryItem())
3117 for (Property pr : item.getProperty())
3119 entry.setProperty(pr.getName(), pr.getValue());
3123 StructureSelectionManager
3124 .getStructureSelectionManager(Desktop.instance)
3125 .registerPDBEntry(entry);
3126 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3127 if (al.getSequenceAt(i).getDatasetSequence() != null)
3129 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3133 al.getSequenceAt(i).addPDBId(entry);
3138 } // end !multipleview
3140 // ///////////////////////////////
3141 // LOAD SEQUENCE MAPPINGS
3143 if (vamsasSet.getAlcodonFrameCount() > 0)
3145 // TODO Potentially this should only be done once for all views of an
3147 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3148 for (int i = 0; i < alc.length; i++)
3150 AlignedCodonFrame cf = new AlignedCodonFrame();
3151 if (alc[i].getAlcodMapCount() > 0)
3153 AlcodMap[] maps = alc[i].getAlcodMap();
3154 for (int m = 0; m < maps.length; m++)
3156 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3158 jalview.datamodel.Mapping mapping = null;
3159 // attach to dna sequence reference.
3160 if (maps[m].getMapping() != null)
3162 mapping = addMapping(maps[m].getMapping());
3163 if (dnaseq != null && mapping.getTo() != null)
3165 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3171 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3175 al.addCodonFrame(cf);
3180 // ////////////////////////////////
3182 List<JvAnnotRow> autoAlan = new ArrayList<>();
3185 * store any annotations which forward reference a group's ID
3187 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3189 if (vamsasSet.getAnnotationCount() > 0)
3191 Annotation[] an = vamsasSet.getAnnotation();
3193 for (int i = 0; i < an.length; i++)
3195 Annotation annotation = an[i];
3198 * test if annotation is automatically calculated for this view only
3200 boolean autoForView = false;
3201 if (annotation.getLabel().equals("Quality")
3202 || annotation.getLabel().equals("Conservation")
3203 || annotation.getLabel().equals("Consensus"))
3205 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3207 if (!annotation.hasAutoCalculated())
3209 annotation.setAutoCalculated(true);
3212 if (autoForView || (annotation.hasAutoCalculated()
3213 && annotation.isAutoCalculated()))
3215 // remove ID - we don't recover annotation from other views for
3216 // view-specific annotation
3217 annotation.setId(null);
3220 // set visiblity for other annotation in this view
3221 String annotationId = annotation.getId();
3222 if (annotationId != null && annotationIds.containsKey(annotationId))
3224 AlignmentAnnotation jda = annotationIds.get(annotationId);
3225 // in principle Visible should always be true for annotation displayed
3226 // in multiple views
3227 if (annotation.hasVisible())
3229 jda.visible = annotation.getVisible();
3232 al.addAnnotation(jda);
3236 // Construct new annotation from model.
3237 AnnotationElement[] ae = annotation.getAnnotationElement();
3238 jalview.datamodel.Annotation[] anot = null;
3239 java.awt.Color firstColour = null;
3241 if (!annotation.getScoreOnly())
3243 anot = new jalview.datamodel.Annotation[al.getWidth()];
3244 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3246 anpos = ae[aa].getPosition();
3248 if (anpos >= anot.length)
3253 anot[anpos] = new jalview.datamodel.Annotation(
3255 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3256 (ae[aa].getSecondaryStructure() == null
3257 || ae[aa].getSecondaryStructure().length() == 0)
3259 : ae[aa].getSecondaryStructure()
3264 // JBPNote: Consider verifying dataflow for IO of secondary
3265 // structure annotation read from Stockholm files
3266 // this was added to try to ensure that
3267 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3269 // anot[ae[aa].getPosition()].displayCharacter = "";
3271 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3272 if (firstColour == null)
3274 firstColour = anot[anpos].colour;
3278 jalview.datamodel.AlignmentAnnotation jaa = null;
3280 if (annotation.getGraph())
3282 float llim = 0, hlim = 0;
3283 // if (autoForView || an[i].isAutoCalculated()) {
3286 jaa = new jalview.datamodel.AlignmentAnnotation(
3287 annotation.getLabel(), annotation.getDescription(), anot,
3288 llim, hlim, annotation.getGraphType());
3290 jaa.graphGroup = annotation.getGraphGroup();
3291 jaa._linecolour = firstColour;
3292 if (annotation.getThresholdLine() != null)
3294 jaa.setThreshold(new jalview.datamodel.GraphLine(
3295 annotation.getThresholdLine().getValue(),
3296 annotation.getThresholdLine().getLabel(),
3298 annotation.getThresholdLine().getColour())));
3301 if (autoForView || annotation.isAutoCalculated())
3303 // Hardwire the symbol display line to ensure that labels for
3304 // histograms are displayed
3310 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3311 an[i].getDescription(), anot);
3312 jaa._linecolour = firstColour;
3314 // register new annotation
3315 if (an[i].getId() != null)
3317 annotationIds.put(an[i].getId(), jaa);
3318 jaa.annotationId = an[i].getId();
3320 // recover sequence association
3321 String sequenceRef = an[i].getSequenceRef();
3322 if (sequenceRef != null)
3324 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3325 SequenceI sequence = seqRefIds.get(sequenceRef);
3326 if (sequence == null)
3328 // in pre-2.9 projects sequence ref is to sequence name
3329 sequence = al.findName(sequenceRef);
3331 if (sequence != null)
3333 jaa.createSequenceMapping(sequence, 1, true);
3334 sequence.addAlignmentAnnotation(jaa);
3337 // and make a note of any group association
3338 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3340 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3341 .get(an[i].getGroupRef());
3344 aal = new ArrayList<>();
3345 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3350 if (an[i].hasScore())
3352 jaa.setScore(an[i].getScore());
3354 if (an[i].hasVisible())
3356 jaa.visible = an[i].getVisible();
3359 if (an[i].hasCentreColLabels())
3361 jaa.centreColLabels = an[i].getCentreColLabels();
3364 if (an[i].hasScaleColLabels())
3366 jaa.scaleColLabel = an[i].getScaleColLabels();
3368 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3370 // newer files have an 'autoCalculated' flag and store calculation
3371 // state in viewport properties
3372 jaa.autoCalculated = true; // means annotation will be marked for
3373 // update at end of load.
3375 if (an[i].hasGraphHeight())
3377 jaa.graphHeight = an[i].getGraphHeight();
3379 if (an[i].hasBelowAlignment())
3381 jaa.belowAlignment = an[i].isBelowAlignment();
3383 jaa.setCalcId(an[i].getCalcId());
3384 if (an[i].getPropertyCount() > 0)
3386 for (jalview.schemabinding.version2.Property prop : an[i]
3389 jaa.setProperty(prop.getName(), prop.getValue());
3392 if (jaa.autoCalculated)
3394 autoAlan.add(new JvAnnotRow(i, jaa));
3397 // if (!autoForView)
3399 // add autocalculated group annotation and any user created annotation
3401 al.addAnnotation(jaa);
3405 // ///////////////////////
3407 // Create alignment markup and styles for this view
3408 if (jms.getJGroupCount() > 0)
3410 JGroup[] groups = jms.getJGroup();
3411 boolean addAnnotSchemeGroup = false;
3412 for (int i = 0; i < groups.length; i++)
3414 JGroup jGroup = groups[i];
3415 ColourSchemeI cs = null;
3416 if (jGroup.getColour() != null)
3418 if (jGroup.getColour().startsWith("ucs"))
3420 cs = getUserColourScheme(jms, jGroup.getColour());
3422 else if (jGroup.getColour().equals("AnnotationColourGradient")
3423 && jGroup.getAnnotationColours() != null)
3425 addAnnotSchemeGroup = true;
3429 cs = ColourSchemeProperty.getColourScheme(al,
3430 jGroup.getColour());
3433 int pidThreshold = jGroup.getPidThreshold();
3435 Vector<SequenceI> seqs = new Vector<>();
3437 for (int s = 0; s < jGroup.getSeqCount(); s++)
3439 String seqId = jGroup.getSeq(s) + "";
3440 SequenceI ts = seqRefIds.get(seqId);
3444 seqs.addElement(ts);
3448 if (seqs.size() < 1)
3453 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3454 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3455 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3456 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3457 sg.getGroupColourScheme()
3458 .setConservationInc(jGroup.getConsThreshold());
3459 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3461 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3462 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3463 sg.setShowNonconserved(
3464 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3466 sg.thresholdTextColour = jGroup.getTextColThreshold();
3467 if (jGroup.hasShowConsensusHistogram())
3469 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3472 if (jGroup.hasShowSequenceLogo())
3474 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3476 if (jGroup.hasNormaliseSequenceLogo())
3478 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3480 if (jGroup.hasIgnoreGapsinConsensus())
3482 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3484 if (jGroup.getConsThreshold() != 0)
3486 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3489 c.verdict(false, 25);
3490 sg.cs.setConservation(c);
3493 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3495 // re-instate unique group/annotation row reference
3496 List<AlignmentAnnotation> jaal = groupAnnotRefs
3497 .get(jGroup.getId());
3500 for (AlignmentAnnotation jaa : jaal)
3503 if (jaa.autoCalculated)
3505 // match up and try to set group autocalc alignment row for this
3507 if (jaa.label.startsWith("Consensus for "))
3509 sg.setConsensus(jaa);
3511 // match up and try to set group autocalc alignment row for this
3513 if (jaa.label.startsWith("Conservation for "))
3515 sg.setConservationRow(jaa);
3522 if (addAnnotSchemeGroup)
3524 // reconstruct the annotation colourscheme
3525 sg.setColourScheme(constructAnnotationColour(
3526 jGroup.getAnnotationColours(), null, al, jms, false));
3532 // only dataset in this model, so just return.
3535 // ///////////////////////////////
3538 // If we just load in the same jar file again, the sequenceSetId
3539 // will be the same, and we end up with multiple references
3540 // to the same sequenceSet. We must modify this id on load
3541 // so that each load of the file gives a unique id
3542 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3543 String viewId = (view.getId() == null ? null
3544 : view.getId() + uniqueSetSuffix);
3545 AlignFrame af = null;
3546 AlignViewport av = null;
3547 // now check to see if we really need to create a new viewport.
3548 if (multipleView && viewportsAdded.size() == 0)
3550 // We recovered an alignment for which a viewport already exists.
3551 // TODO: fix up any settings necessary for overlaying stored state onto
3552 // state recovered from another document. (may not be necessary).
3553 // we may need a binding from a viewport in memory to one recovered from
3555 // and then recover its containing af to allow the settings to be applied.
3556 // TODO: fix for vamsas demo
3558 "About to recover a viewport for existing alignment: Sequence set ID is "
3560 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3561 if (seqsetobj != null)
3563 if (seqsetobj instanceof String)
3565 uniqueSeqSetId = (String) seqsetobj;
3567 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3573 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3579 * indicate that annotation colours are applied across all groups (pre
3580 * Jalview 2.8.1 behaviour)
3582 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3583 object.getVersion());
3585 AlignmentPanel ap = null;
3586 boolean isnewview = true;
3589 // Check to see if this alignment already has a view id == viewId
3590 jalview.gui.AlignmentPanel views[] = Desktop
3591 .getAlignmentPanels(uniqueSeqSetId);
3592 if (views != null && views.length > 0)
3594 for (int v = 0; v < views.length; v++)
3596 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3598 // recover the existing alignpanel, alignframe, viewport
3599 af = views[v].alignFrame;
3602 // TODO: could even skip resetting view settings if we don't want to
3603 // change the local settings from other jalview processes
3612 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3613 uniqueSeqSetId, viewId, autoAlan);
3619 * Load any trees, PDB structures and viewers
3621 * Not done if flag is false (when this method is used for New View)
3623 if (loadTreesAndStructures)
3625 loadTrees(jms, view, af, av, ap);
3626 loadPDBStructures(jprovider, jseqs, af, ap);
3627 loadRnaViewers(jprovider, jseqs, ap);
3629 // and finally return.
3634 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3635 * panel is restored from separate jar entries, two (gapped and trimmed) per
3636 * sequence and secondary structure.
3638 * Currently each viewer shows just one sequence and structure (gapped and
3639 * trimmed), however this method is designed to support multiple sequences or
3640 * structures in viewers if wanted in future.
3646 private void loadRnaViewers(jarInputStreamProvider jprovider,
3647 JSeq[] jseqs, AlignmentPanel ap)
3650 * scan the sequences for references to viewers; create each one the first
3651 * time it is referenced, add Rna models to existing viewers
3653 for (JSeq jseq : jseqs)
3655 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3657 RnaViewer viewer = jseq.getRnaViewer(i);
3658 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3661 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3663 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3664 SequenceI seq = seqRefIds.get(jseq.getId());
3665 AlignmentAnnotation ann = this.annotationIds
3666 .get(ss.getAnnotationId());
3669 * add the structure to the Varna display (with session state copied
3670 * from the jar to a temporary file)
3672 boolean gapped = ss.isGapped();
3673 String rnaTitle = ss.getTitle();
3674 String sessionState = ss.getViewerState();
3675 String tempStateFile = copyJarEntry(jprovider, sessionState,
3677 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3678 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3680 appVarna.setInitialSelection(viewer.getSelectedRna());
3686 * Locate and return an already instantiated matching AppVarna, or create one
3690 * @param viewIdSuffix
3694 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3695 String viewIdSuffix, AlignmentPanel ap)
3698 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3699 * if load is repeated
3701 String postLoadId = viewer.getViewId() + viewIdSuffix;
3702 for (JInternalFrame frame : getAllFrames())
3704 if (frame instanceof AppVarna)
3706 AppVarna varna = (AppVarna) frame;
3707 if (postLoadId.equals(varna.getViewId()))
3709 // this viewer is already instantiated
3710 // could in future here add ap as another 'parent' of the
3711 // AppVarna window; currently just 1-to-many
3718 * viewer not found - make it
3720 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3721 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3722 viewer.getHeight(), viewer.getDividerLocation());
3723 AppVarna varna = new AppVarna(model, ap);
3729 * Load any saved trees
3737 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3738 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3740 // TODO result of automated refactoring - are all these parameters needed?
3743 for (int t = 0; t < jms.getTreeCount(); t++)
3746 Tree tree = jms.getTree(t);
3748 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3751 tp = af.showNewickTree(
3752 new jalview.io.NewickFile(tree.getNewick()),
3753 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3754 tree.getXpos(), tree.getYpos());
3755 if (tree.getId() != null)
3757 // perhaps bind the tree id to something ?
3762 // update local tree attributes ?
3763 // TODO: should check if tp has been manipulated by user - if so its
3764 // settings shouldn't be modified
3765 tp.setTitle(tree.getTitle());
3766 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3767 tree.getWidth(), tree.getHeight()));
3768 tp.setViewport(av); // af.viewport; // TODO: verify 'associate with all
3771 tp.getTreeCanvas().setViewport(av); // af.viewport;
3772 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
3777 warn("There was a problem recovering stored Newick tree: \n"
3778 + tree.getNewick());
3782 tp.fitToWindow.setState(tree.getFitToWindow());
3783 tp.fitToWindow_actionPerformed(null);
3785 if (tree.getFontName() != null)
3787 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3788 tree.getFontStyle(), tree.getFontSize()));
3792 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3793 view.getFontStyle(), tree.getFontSize()));
3796 tp.showPlaceholders(tree.getMarkUnlinked());
3797 tp.showBootstrap(tree.getShowBootstrap());
3798 tp.showDistances(tree.getShowDistances());
3800 tp.getTreeCanvas().setThreshold(tree.getThreshold());
3802 if (tree.getCurrentTree())
3804 af.viewport.setCurrentTree(tp.getTree());
3808 } catch (Exception ex)
3810 ex.printStackTrace();
3815 * Load and link any saved structure viewers.
3822 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3823 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3826 * Run through all PDB ids on the alignment, and collect mappings between
3827 * distinct view ids and all sequences referring to that view.
3829 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3831 for (int i = 0; i < jseqs.length; i++)
3833 if (jseqs[i].getPdbidsCount() > 0)
3835 Pdbids[] ids = jseqs[i].getPdbids();
3836 for (int p = 0; p < ids.length; p++)
3838 final int structureStateCount = ids[p].getStructureStateCount();
3839 for (int s = 0; s < structureStateCount; s++)
3841 // check to see if we haven't already created this structure view
3842 final StructureState structureState = ids[p]
3843 .getStructureState(s);
3844 String sviewid = (structureState.getViewId() == null) ? null
3845 : structureState.getViewId() + uniqueSetSuffix;
3846 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3847 // Originally : ids[p].getFile()
3848 // : TODO: verify external PDB file recovery still works in normal
3849 // jalview project load
3850 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3852 jpdb.setId(ids[p].getId());
3854 int x = structureState.getXpos();
3855 int y = structureState.getYpos();
3856 int width = structureState.getWidth();
3857 int height = structureState.getHeight();
3859 // Probably don't need to do this anymore...
3860 // Desktop.desktop.getComponentAt(x, y);
3861 // TODO: NOW: check that this recovers the PDB file correctly.
3862 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3864 jalview.datamodel.SequenceI seq = seqRefIds
3865 .get(jseqs[i].getId() + "");
3866 if (sviewid == null)
3868 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3871 if (!structureViewers.containsKey(sviewid))
3873 structureViewers.put(sviewid,
3874 new StructureViewerModel(x, y, width, height, false,
3875 false, true, structureState.getViewId(),
3876 structureState.getType()));
3877 // Legacy pre-2.7 conversion JAL-823 :
3878 // do not assume any view has to be linked for colour by
3882 // assemble String[] { pdb files }, String[] { id for each
3883 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3884 // seqs_file 2}, boolean[] {
3885 // linkAlignPanel,superposeWithAlignpanel}} from hash
3886 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3887 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3888 | (structureState.hasAlignwithAlignPanel()
3889 ? structureState.getAlignwithAlignPanel()
3893 * Default colour by linked panel to false if not specified (e.g.
3894 * for pre-2.7 projects)
3896 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3897 colourWithAlignPanel |= (structureState
3898 .hasColourwithAlignPanel()
3899 ? structureState.getColourwithAlignPanel()
3901 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3904 * Default colour by viewer to true if not specified (e.g. for
3907 boolean colourByViewer = jmoldat.isColourByViewer();
3908 colourByViewer &= structureState.hasColourByJmol()
3909 ? structureState.getColourByJmol()
3911 jmoldat.setColourByViewer(colourByViewer);
3913 if (jmoldat.getStateData().length() < structureState
3914 .getContent().length())
3917 jmoldat.setStateData(structureState.getContent());
3920 if (ids[p].getFile() != null)
3922 File mapkey = new File(ids[p].getFile());
3923 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3924 if (seqstrmaps == null)
3926 jmoldat.getFileData().put(mapkey,
3927 seqstrmaps = jmoldat.new StructureData(pdbFile,
3930 if (!seqstrmaps.getSeqList().contains(seq))
3932 seqstrmaps.getSeqList().add(seq);
3938 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");
3945 // Instantiate the associated structure views
3946 for (Entry<String, StructureViewerModel> entry : structureViewers
3951 createOrLinkStructureViewer(entry, af, ap, jprovider);
3952 } catch (Exception e)
3955 "Error loading structure viewer: " + e.getMessage());
3956 // failed - try the next one
3968 protected void createOrLinkStructureViewer(
3969 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3970 AlignmentPanel ap, jarInputStreamProvider jprovider)
3972 final StructureViewerModel stateData = viewerData.getValue();
3975 * Search for any viewer windows already open from other alignment views
3976 * that exactly match the stored structure state
3978 StructureViewerBase comp = findMatchingViewer(viewerData);
3982 linkStructureViewer(ap, comp, stateData);
3987 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3988 * "viewer_"+stateData.viewId
3990 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
3992 createChimeraViewer(viewerData, af, jprovider);
3997 * else Jmol (if pre-2.9, stateData contains JMOL state string)
3999 createJmolViewer(viewerData, af, jprovider);
4004 * Create a new Chimera viewer.
4010 protected void createChimeraViewer(
4011 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4012 jarInputStreamProvider jprovider)
4014 StructureViewerModel data = viewerData.getValue();
4015 String chimeraSessionFile = data.getStateData();
4018 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4020 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4021 * 'uniquified' sviewid used to reconstruct the viewer here
4023 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4024 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4027 Set<Entry<File, StructureData>> fileData = data.getFileData()
4029 List<PDBEntry> pdbs = new ArrayList<>();
4030 List<SequenceI[]> allseqs = new ArrayList<>();
4031 for (Entry<File, StructureData> pdb : fileData)
4033 String filePath = pdb.getValue().getFilePath();
4034 String pdbId = pdb.getValue().getPdbId();
4035 // pdbs.add(new PDBEntry(filePath, pdbId));
4036 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4037 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4038 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4042 boolean colourByChimera = data.isColourByViewer();
4043 boolean colourBySequence = data.isColourWithAlignPanel();
4045 // TODO use StructureViewer as a factory here, see JAL-1761
4046 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4047 final SequenceI[][] seqsArray = allseqs
4048 .toArray(new SequenceI[allseqs.size()][]);
4049 String newViewId = viewerData.getKey();
4051 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4052 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4053 colourBySequence, newViewId);
4054 cvf.setSize(data.getWidth(), data.getHeight());
4055 cvf.setLocation(data.getX(), data.getY());
4059 * Create a new Jmol window. First parse the Jmol state to translate filenames
4060 * loaded into the view, and record the order in which files are shown in the
4061 * Jmol view, so we can add the sequence mappings in same order.
4067 protected void createJmolViewer(
4068 final Entry<String, StructureViewerModel> viewerData,
4069 AlignFrame af, jarInputStreamProvider jprovider)
4071 final StructureViewerModel svattrib = viewerData.getValue();
4072 String state = svattrib.getStateData();
4075 * Pre-2.9: state element value is the Jmol state string
4077 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4080 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4082 state = readJarEntry(jprovider,
4083 getViewerJarEntryName(svattrib.getViewId()));
4086 List<String> pdbfilenames = new ArrayList<>();
4087 List<SequenceI[]> seqmaps = new ArrayList<>();
4088 List<String> pdbids = new ArrayList<>();
4089 StringBuilder newFileLoc = new StringBuilder(64);
4090 int cp = 0, ncp, ecp;
4091 Map<File, StructureData> oldFiles = svattrib.getFileData();
4092 while ((ncp = state.indexOf("load ", cp)) > -1)
4096 // look for next filename in load statement
4097 newFileLoc.append(state.substring(cp,
4098 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4099 String oldfilenam = state.substring(ncp,
4100 ecp = state.indexOf("\"", ncp));
4101 // recover the new mapping data for this old filename
4102 // have to normalize filename - since Jmol and jalview do
4104 // translation differently.
4105 StructureData filedat = oldFiles.get(new File(oldfilenam));
4106 if (filedat == null)
4108 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4109 filedat = oldFiles.get(new File(reformatedOldFilename));
4111 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4112 pdbfilenames.add(filedat.getFilePath());
4113 pdbids.add(filedat.getPdbId());
4114 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4115 newFileLoc.append("\"");
4116 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4117 // look for next file statement.
4118 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4122 // just append rest of state
4123 newFileLoc.append(state.substring(cp));
4127 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4128 newFileLoc = new StringBuilder(state);
4129 newFileLoc.append("; load append ");
4130 for (File id : oldFiles.keySet())
4132 // add this and any other pdb files that should be present in
4134 StructureData filedat = oldFiles.get(id);
4135 newFileLoc.append(filedat.getFilePath());
4136 pdbfilenames.add(filedat.getFilePath());
4137 pdbids.add(filedat.getPdbId());
4138 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4139 newFileLoc.append(" \"");
4140 newFileLoc.append(filedat.getFilePath());
4141 newFileLoc.append("\"");
4144 newFileLoc.append(";");
4147 if (newFileLoc.length() == 0)
4151 int histbug = newFileLoc.indexOf("history = ");
4155 * change "history = [true|false];" to "history = [1|0];"
4158 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4159 String val = (diff == -1) ? null
4160 : newFileLoc.substring(histbug, diff);
4161 if (val != null && val.length() >= 4)
4163 if (val.contains("e")) // eh? what can it be?
4165 if (val.trim().equals("true"))
4173 newFileLoc.replace(histbug, diff, val);
4178 final String[] pdbf = pdbfilenames
4179 .toArray(new String[pdbfilenames.size()]);
4180 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4181 final SequenceI[][] sq = seqmaps
4182 .toArray(new SequenceI[seqmaps.size()][]);
4183 final String fileloc = newFileLoc.toString();
4184 final String sviewid = viewerData.getKey();
4185 final AlignFrame alf = af;
4186 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4187 svattrib.getWidth(), svattrib.getHeight());
4190 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4195 JalviewStructureDisplayI sview = null;
4198 sview = new StructureViewer(
4199 alf.alignPanel.getStructureSelectionManager())
4200 .createView(StructureViewer.ViewerType.JMOL,
4201 pdbf, id, sq, alf.alignPanel, svattrib,
4202 fileloc, rect, sviewid);
4203 addNewStructureViewer(sview);
4204 } catch (OutOfMemoryError ex)
4206 new OOMWarning("restoring structure view for PDB id " + id,
4207 (OutOfMemoryError) ex.getCause());
4208 if (sview != null && sview.isVisible())
4210 sview.closeViewer(false);
4211 sview.setVisible(false);
4217 } catch (InvocationTargetException ex)
4219 warn("Unexpected error when opening Jmol view.", ex);
4221 } catch (InterruptedException e)
4223 // e.printStackTrace();
4229 * Generates a name for the entry in the project jar file to hold state
4230 * information for a structure viewer
4235 protected String getViewerJarEntryName(String viewId)
4237 return VIEWER_PREFIX + viewId;
4241 * Returns any open frame that matches given structure viewer data. The match
4242 * is based on the unique viewId, or (for older project versions) the frame's
4248 protected StructureViewerBase findMatchingViewer(
4249 Entry<String, StructureViewerModel> viewerData)
4251 final String sviewid = viewerData.getKey();
4252 final StructureViewerModel svattrib = viewerData.getValue();
4253 StructureViewerBase comp = null;
4254 JInternalFrame[] frames = getAllFrames();
4255 for (JInternalFrame frame : frames)
4257 if (frame instanceof StructureViewerBase)
4260 * Post jalview 2.4 schema includes structure view id
4262 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4265 comp = (StructureViewerBase) frame;
4266 break; // break added in 2.9
4269 * Otherwise test for matching position and size of viewer frame
4271 else if (frame.getX() == svattrib.getX()
4272 && frame.getY() == svattrib.getY()
4273 && frame.getHeight() == svattrib.getHeight()
4274 && frame.getWidth() == svattrib.getWidth())
4276 comp = (StructureViewerBase) frame;
4277 // no break in faint hope of an exact match on viewId
4285 * Link an AlignmentPanel to an existing structure viewer.
4290 * @param useinViewerSuperpos
4291 * @param usetoColourbyseq
4292 * @param viewerColouring
4294 protected void linkStructureViewer(AlignmentPanel ap,
4295 StructureViewerBase viewer, StructureViewerModel stateData)
4297 // NOTE: if the jalview project is part of a shared session then
4298 // view synchronization should/could be done here.
4300 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4301 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4302 final boolean viewerColouring = stateData.isColourByViewer();
4303 Map<File, StructureData> oldFiles = stateData.getFileData();
4306 * Add mapping for sequences in this view to an already open viewer
4308 final AAStructureBindingModel binding = viewer.getBinding();
4309 for (File id : oldFiles.keySet())
4311 // add this and any other pdb files that should be present in the
4313 StructureData filedat = oldFiles.get(id);
4314 String pdbFile = filedat.getFilePath();
4315 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4316 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4318 binding.addSequenceForStructFile(pdbFile, seq);
4320 // and add the AlignmentPanel's reference to the view panel
4321 viewer.addAlignmentPanel(ap);
4322 if (useinViewerSuperpos)
4324 viewer.useAlignmentPanelForSuperposition(ap);
4328 viewer.excludeAlignmentPanelForSuperposition(ap);
4330 if (usetoColourbyseq)
4332 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4336 viewer.excludeAlignmentPanelForColourbyseq(ap);
4341 * Get all frames within the Desktop.
4345 protected JInternalFrame[] getAllFrames()
4347 JInternalFrame[] frames = null;
4348 // TODO is this necessary - is it safe - risk of hanging?
4353 frames = Desktop.desktop.getAllFrames();
4354 } catch (ArrayIndexOutOfBoundsException e)
4356 // occasional No such child exceptions are thrown here...
4360 } catch (InterruptedException f)
4364 } while (frames == null);
4369 * Answers true if 'version' is equal to or later than 'supported', where each
4370 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4371 * changes. Development and test values for 'version' are leniently treated
4375 * - minimum version we are comparing against
4377 * - version of data being processsed
4380 public static boolean isVersionStringLaterThan(String supported,
4383 if (supported == null || version == null
4384 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4385 || version.equalsIgnoreCase("Test")
4386 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4388 System.err.println("Assuming project file with "
4389 + (version == null ? "null" : version)
4390 + " is compatible with Jalview version " + supported);
4395 return StringUtils.compareVersions(version, supported, "b") >= 0;
4399 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4401 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4403 if (newStructureViewers != null)
4405 sview.getBinding().setFinishedLoadingFromArchive(false);
4406 newStructureViewers.add(sview);
4410 protected void setLoadingFinishedForNewStructureViewers()
4412 if (newStructureViewers != null)
4414 for (JalviewStructureDisplayI sview : newStructureViewers)
4416 sview.getBinding().setFinishedLoadingFromArchive(true);
4418 newStructureViewers.clear();
4419 newStructureViewers = null;
4423 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4424 List<SequenceI> hiddenSeqs, AlignmentI al,
4425 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4426 String viewId, List<JvAnnotRow> autoAlan)
4428 AlignFrame af = null;
4429 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4430 uniqueSeqSetId, viewId);
4432 af.setFileName(file, FileFormat.Jalview);
4434 for (int i = 0; i < JSEQ.length; i++)
4436 af.viewport.setSequenceColour(
4437 af.viewport.getAlignment().getSequenceAt(i),
4438 new java.awt.Color(JSEQ[i].getColour()));
4443 af.getViewport().setColourByReferenceSeq(true);
4444 af.getViewport().setDisplayReferenceSeq(true);
4447 af.viewport.setGatherViewsHere(view.getGatheredViews());
4449 if (view.getSequenceSetId() != null)
4451 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4453 af.viewport.setSequenceSetId(uniqueSeqSetId);
4456 // propagate shared settings to this new view
4457 af.viewport.setHistoryList(av.getHistoryList());
4458 af.viewport.setRedoList(av.getRedoList());
4462 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4464 // TODO: check if this method can be called repeatedly without
4465 // side-effects if alignpanel already registered.
4466 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4468 // apply Hidden regions to view.
4469 if (hiddenSeqs != null)
4471 for (int s = 0; s < JSEQ.length; s++)
4473 SequenceGroup hidden = new SequenceGroup();
4474 boolean isRepresentative = false;
4475 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4477 isRepresentative = true;
4478 SequenceI sequenceToHide = al
4479 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4480 hidden.addSequence(sequenceToHide, false);
4481 // remove from hiddenSeqs list so we don't try to hide it twice
4482 hiddenSeqs.remove(sequenceToHide);
4484 if (isRepresentative)
4486 SequenceI representativeSequence = al.getSequenceAt(s);
4487 hidden.addSequence(representativeSequence, false);
4488 af.viewport.hideRepSequences(representativeSequence, hidden);
4492 SequenceI[] hseqs = hiddenSeqs
4493 .toArray(new SequenceI[hiddenSeqs.size()]);
4494 af.viewport.hideSequence(hseqs);
4497 // recover view properties and display parameters
4499 af.viewport.setShowAnnotation(view.getShowAnnotation());
4500 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4501 af.viewport.setThreshold(view.getPidThreshold());
4503 af.viewport.setColourText(view.getShowColourText());
4505 af.viewport.setConservationSelected(view.getConservationSelected());
4506 af.viewport.setIncrement(view.getConsThreshold());
4507 af.viewport.setShowJVSuffix(view.getShowFullId());
4508 af.viewport.setRightAlignIds(view.getRightAlignIds());
4509 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4510 view.getFontStyle(), view.getFontSize()), true);
4511 ViewStyleI vs = af.viewport.getViewStyle();
4512 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4513 af.viewport.setViewStyle(vs);
4514 // TODO: allow custom charWidth/Heights to be restored by updating them
4515 // after setting font - which means set above to false
4516 af.viewport.setRenderGaps(view.getRenderGaps());
4517 af.viewport.setWrapAlignment(view.getWrapAlignment());
4518 af.viewport.setShowAnnotation(view.getShowAnnotation());
4520 af.viewport.setShowBoxes(view.getShowBoxes());
4522 af.viewport.setShowText(view.getShowText());
4524 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4525 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4526 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4527 af.viewport.setShowUnconserved(
4528 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4529 af.viewport.getRanges().setStartRes(view.getStartRes());
4531 if (view.getViewName() != null)
4533 af.viewport.setViewName(view.getViewName());
4534 af.setInitialTabVisible();
4536 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4538 // startSeq set in af.alignPanel.updateLayout below
4539 af.alignPanel.updateLayout();
4540 ColourSchemeI cs = null;
4541 // apply colourschemes
4542 if (view.getBgColour() != null)
4544 if (view.getBgColour().startsWith("ucs"))
4546 cs = getUserColourScheme(jms, view.getBgColour());
4548 else if (view.getBgColour().startsWith("Annotation"))
4550 AnnotationColours viewAnnColour = view.getAnnotationColours();
4551 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4558 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4562 af.viewport.setGlobalColourScheme(cs);
4563 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4564 view.getIgnoreGapsinConsensus());
4565 af.viewport.getResidueShading()
4566 .setConsensus(af.viewport.getSequenceConsensusHash());
4567 af.viewport.setColourAppliesToAllGroups(false);
4569 if (view.getConservationSelected() && cs != null)
4571 af.viewport.getResidueShading()
4572 .setConservationInc(view.getConsThreshold());
4575 af.changeColour(cs);
4577 af.viewport.setColourAppliesToAllGroups(true);
4579 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4581 if (view.hasCentreColumnLabels())
4583 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4585 if (view.hasIgnoreGapsinConsensus())
4587 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4590 if (view.hasFollowHighlight())
4592 af.viewport.setFollowHighlight(view.getFollowHighlight());
4594 if (view.hasFollowSelection())
4596 af.viewport.followSelection = view.getFollowSelection();
4598 if (view.hasShowConsensusHistogram())
4601 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4605 af.viewport.setShowConsensusHistogram(true);
4607 if (view.hasShowSequenceLogo())
4609 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4613 af.viewport.setShowSequenceLogo(false);
4615 if (view.hasNormaliseSequenceLogo())
4617 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4619 if (view.hasShowDbRefTooltip())
4621 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4623 if (view.hasShowNPfeatureTooltip())
4625 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4627 if (view.hasShowGroupConsensus())
4629 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4633 af.viewport.setShowGroupConsensus(false);
4635 if (view.hasShowGroupConservation())
4637 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4641 af.viewport.setShowGroupConservation(false);
4644 // recover feature settings
4645 if (jms.getFeatureSettings() != null)
4647 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4648 .getFeatureRenderer();
4649 FeaturesDisplayed fdi;
4650 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4651 String[] renderOrder = new String[jms.getFeatureSettings()
4652 .getSettingCount()];
4653 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4654 Map<String, Float> featureOrder = new Hashtable<>();
4656 for (int fs = 0; fs < jms.getFeatureSettings()
4657 .getSettingCount(); fs++)
4659 Setting setting = jms.getFeatureSettings().getSetting(fs);
4660 String featureType = setting.getType();
4663 * restore feature filters (if any)
4665 MatcherSet filters = setting.getMatcherSet();
4666 if (filters != null)
4668 FeatureMatcherSetI filter = Jalview2XML
4669 .unmarshalFilter(featureType, filters);
4670 if (!filter.isEmpty())
4672 fr.setFeatureFilter(featureType, filter);
4677 * restore feature colour scheme
4679 Color maxColour = new Color(setting.getColour());
4680 if (setting.hasMincolour())
4683 * minColour is always set unless a simple colour
4684 * (including for colour by label though it doesn't use it)
4686 Color minColour = new Color(setting.getMincolour());
4687 Color noValueColour = minColour;
4688 NoValueColour noColour = setting.getNoValueColour();
4689 if (noColour == NoValueColour.NONE)
4691 noValueColour = null;
4693 else if (noColour == NoValueColour.MAX)
4695 noValueColour = maxColour;
4697 float min = setting.hasMin() ? setting.getMin() : 0f;
4698 float max = setting.hasMin() ? setting.getMax() : 1f;
4699 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4700 noValueColour, min, max);
4701 if (setting.getAttributeNameCount() > 0)
4703 gc.setAttributeName(setting.getAttributeName());
4705 if (setting.hasThreshold())
4707 gc.setThreshold(setting.getThreshold());
4708 int threshstate = setting.getThreshstate();
4709 // -1 = None, 0 = Below, 1 = Above threshold
4710 if (threshstate == 0)
4712 gc.setBelowThreshold(true);
4714 else if (threshstate == 1)
4716 gc.setAboveThreshold(true);
4719 gc.setAutoScaled(true); // default
4720 if (setting.hasAutoScale())
4722 gc.setAutoScaled(setting.getAutoScale());
4724 if (setting.hasColourByLabel())
4726 gc.setColourByLabel(setting.getColourByLabel());
4728 // and put in the feature colour table.
4729 featureColours.put(featureType, gc);
4733 featureColours.put(featureType,
4734 new FeatureColour(maxColour));
4736 renderOrder[fs] = featureType;
4737 if (setting.hasOrder())
4739 featureOrder.put(featureType, setting.getOrder());
4743 featureOrder.put(featureType, new Float(
4744 fs / jms.getFeatureSettings().getSettingCount()));
4746 if (setting.getDisplay())
4748 fdi.setVisible(featureType);
4751 Map<String, Boolean> fgtable = new Hashtable<>();
4752 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4754 Group grp = jms.getFeatureSettings().getGroup(gs);
4755 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4757 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4758 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4759 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4760 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4761 fgtable, featureColours, 1.0f, featureOrder);
4762 fr.transferSettings(frs);
4765 if (view.getHiddenColumnsCount() > 0)
4767 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4769 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4770 view.getHiddenColumns(c).getEnd() // +1
4774 if (view.getCalcIdParam() != null)
4776 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4778 if (calcIdParam != null)
4780 if (recoverCalcIdParam(calcIdParam, af.viewport))
4785 warn("Couldn't recover parameters for "
4786 + calcIdParam.getCalcId());
4791 af.setMenusFromViewport(af.viewport);
4792 af.setTitle(view.getTitle());
4793 // TODO: we don't need to do this if the viewport is aready visible.
4795 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4796 * has a 'cdna/protein complement' view, in which case save it in order to
4797 * populate a SplitFrame once all views have been read in.
4799 String complementaryViewId = view.getComplementId();
4800 if (complementaryViewId == null)
4802 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4804 // recompute any autoannotation
4805 af.alignPanel.updateAnnotation(false, true);
4806 reorderAutoannotation(af, al, autoAlan);
4807 af.alignPanel.alignmentChanged();
4811 splitFrameCandidates.put(view, af);
4817 * Reads saved data to restore Colour by Annotation settings
4819 * @param viewAnnColour
4823 * @param checkGroupAnnColour
4826 private ColourSchemeI constructAnnotationColour(
4827 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4828 JalviewModelSequence jms, boolean checkGroupAnnColour)
4830 boolean propagateAnnColour = false;
4831 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4832 if (checkGroupAnnColour && al.getGroups() != null
4833 && al.getGroups().size() > 0)
4835 // pre 2.8.1 behaviour
4836 // check to see if we should transfer annotation colours
4837 propagateAnnColour = true;
4838 for (SequenceGroup sg : al.getGroups())
4840 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4842 propagateAnnColour = false;
4848 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4850 String annotationId = viewAnnColour.getAnnotation();
4851 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4854 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4856 if (matchedAnnotation == null
4857 && annAlignment.getAlignmentAnnotation() != null)
4859 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4862 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4864 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4869 if (matchedAnnotation == null)
4871 System.err.println("Failed to match annotation colour scheme for "
4875 if (matchedAnnotation.getThreshold() == null)
4877 matchedAnnotation.setThreshold(new GraphLine(
4878 viewAnnColour.getThreshold(), "Threshold", Color.black));
4881 AnnotationColourGradient cs = null;
4882 if (viewAnnColour.getColourScheme().equals("None"))
4884 cs = new AnnotationColourGradient(matchedAnnotation,
4885 new Color(viewAnnColour.getMinColour()),
4886 new Color(viewAnnColour.getMaxColour()),
4887 viewAnnColour.getAboveThreshold());
4889 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4891 cs = new AnnotationColourGradient(matchedAnnotation,
4892 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4893 viewAnnColour.getAboveThreshold());
4897 cs = new AnnotationColourGradient(matchedAnnotation,
4898 ColourSchemeProperty.getColourScheme(al,
4899 viewAnnColour.getColourScheme()),
4900 viewAnnColour.getAboveThreshold());
4903 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4904 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4905 cs.setSeqAssociated(perSequenceOnly);
4906 cs.setPredefinedColours(useOriginalColours);
4908 if (propagateAnnColour && al.getGroups() != null)
4910 // Also use these settings for all the groups
4911 for (int g = 0; g < al.getGroups().size(); g++)
4913 SequenceGroup sg = al.getGroups().get(g);
4914 if (sg.getGroupColourScheme() == null)
4919 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4920 matchedAnnotation, sg.getColourScheme(),
4921 viewAnnColour.getAboveThreshold());
4922 sg.setColourScheme(groupScheme);
4923 groupScheme.setSeqAssociated(perSequenceOnly);
4924 groupScheme.setPredefinedColours(useOriginalColours);
4930 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4931 List<JvAnnotRow> autoAlan)
4933 // copy over visualization settings for autocalculated annotation in the
4935 if (al.getAlignmentAnnotation() != null)
4938 * Kludge for magic autoannotation names (see JAL-811)
4940 String[] magicNames = new String[] { "Consensus", "Quality",
4942 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4943 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4944 for (String nm : magicNames)
4946 visan.put(nm, nullAnnot);
4948 for (JvAnnotRow auan : autoAlan)
4950 visan.put(auan.template.label
4951 + (auan.template.getCalcId() == null ? ""
4952 : "\t" + auan.template.getCalcId()),
4955 int hSize = al.getAlignmentAnnotation().length;
4956 List<JvAnnotRow> reorder = new ArrayList<>();
4957 // work through any autoCalculated annotation already on the view
4958 // removing it if it should be placed in a different location on the
4959 // annotation panel.
4960 List<String> remains = new ArrayList<>(visan.keySet());
4961 for (int h = 0; h < hSize; h++)
4963 jalview.datamodel.AlignmentAnnotation jalan = al
4964 .getAlignmentAnnotation()[h];
4965 if (jalan.autoCalculated)
4968 JvAnnotRow valan = visan.get(k = jalan.label);
4969 if (jalan.getCalcId() != null)
4971 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4976 // delete the auto calculated row from the alignment
4977 al.deleteAnnotation(jalan, false);
4981 if (valan != nullAnnot)
4983 if (jalan != valan.template)
4985 // newly created autoannotation row instance
4986 // so keep a reference to the visible annotation row
4987 // and copy over all relevant attributes
4988 if (valan.template.graphHeight >= 0)
4991 jalan.graphHeight = valan.template.graphHeight;
4993 jalan.visible = valan.template.visible;
4995 reorder.add(new JvAnnotRow(valan.order, jalan));
5000 // Add any (possibly stale) autocalculated rows that were not appended to
5001 // the view during construction
5002 for (String other : remains)
5004 JvAnnotRow othera = visan.get(other);
5005 if (othera != nullAnnot && othera.template.getCalcId() != null
5006 && othera.template.getCalcId().length() > 0)
5008 reorder.add(othera);
5011 // now put the automatic annotation in its correct place
5012 int s = 0, srt[] = new int[reorder.size()];
5013 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5014 for (JvAnnotRow jvar : reorder)
5017 srt[s++] = jvar.order;
5020 jalview.util.QuickSort.sort(srt, rws);
5021 // and re-insert the annotation at its correct position
5022 for (JvAnnotRow jvar : rws)
5024 al.addAnnotation(jvar.template, jvar.order);
5026 af.alignPanel.adjustAnnotationHeight();
5030 Hashtable skipList = null;
5033 * TODO remove this method
5036 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5037 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5038 * throw new Error("Implementation Error. No skipList defined for this
5039 * Jalview2XML instance."); } return (AlignFrame)
5040 * skipList.get(view.getSequenceSetId()); }
5044 * Check if the Jalview view contained in object should be skipped or not.
5047 * @return true if view's sequenceSetId is a key in skipList
5049 private boolean skipViewport(JalviewModel object)
5051 if (skipList == null)
5056 if (skipList.containsKey(
5057 id = object.getJalviewModelSequence().getViewport()[0]
5058 .getSequenceSetId()))
5060 if (Cache.log != null && Cache.log.isDebugEnabled())
5062 Cache.log.debug("Skipping seuqence set id " + id);
5069 public void addToSkipList(AlignFrame af)
5071 if (skipList == null)
5073 skipList = new Hashtable();
5075 skipList.put(af.getViewport().getSequenceSetId(), af);
5078 public void clearSkipList()
5080 if (skipList != null)
5087 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5088 boolean ignoreUnrefed)
5090 jalview.datamodel.AlignmentI ds = getDatasetFor(
5091 vamsasSet.getDatasetId());
5092 Vector dseqs = null;
5095 // create a list of new dataset sequences
5096 dseqs = new Vector();
5098 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5100 Sequence vamsasSeq = vamsasSet.getSequence(i);
5101 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5103 // create a new dataset
5106 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5107 dseqs.copyInto(dsseqs);
5108 ds = new jalview.datamodel.Alignment(dsseqs);
5109 debug("Created new dataset " + vamsasSet.getDatasetId()
5110 + " for alignment " + System.identityHashCode(al));
5111 addDatasetRef(vamsasSet.getDatasetId(), ds);
5113 // set the dataset for the newly imported alignment.
5114 if (al.getDataset() == null && !ignoreUnrefed)
5123 * sequence definition to create/merge dataset sequence for
5127 * vector to add new dataset sequence to
5128 * @param ignoreUnrefed
5129 * - when true, don't create new sequences from vamsasSeq if it's id
5130 * doesn't already have an asssociated Jalview sequence.
5132 * - used to reorder the sequence in the alignment according to the
5133 * vamsasSeq array ordering, to preserve ordering of dataset
5135 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5136 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5138 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5140 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5141 boolean reorder = false;
5142 SequenceI dsq = null;
5143 if (sq != null && sq.getDatasetSequence() != null)
5145 dsq = sq.getDatasetSequence();
5151 if (sq == null && ignoreUnrefed)
5155 String sqid = vamsasSeq.getDsseqid();
5158 // need to create or add a new dataset sequence reference to this sequence
5161 dsq = seqRefIds.get(sqid);
5166 // make a new dataset sequence
5167 dsq = sq.createDatasetSequence();
5170 // make up a new dataset reference for this sequence
5171 sqid = seqHash(dsq);
5173 dsq.setVamsasId(uniqueSetSuffix + sqid);
5174 seqRefIds.put(sqid, dsq);
5179 dseqs.addElement(dsq);
5184 ds.addSequence(dsq);
5190 { // make this dataset sequence sq's dataset sequence
5191 sq.setDatasetSequence(dsq);
5192 // and update the current dataset alignment
5197 if (!dseqs.contains(dsq))
5204 if (ds.findIndex(dsq) < 0)
5206 ds.addSequence(dsq);
5213 // TODO: refactor this as a merge dataset sequence function
5214 // now check that sq (the dataset sequence) sequence really is the union of
5215 // all references to it
5216 // boolean pre = sq.getStart() < dsq.getStart();
5217 // boolean post = sq.getEnd() > dsq.getEnd();
5221 // StringBuffer sb = new StringBuffer();
5222 String newres = jalview.analysis.AlignSeq.extractGaps(
5223 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5224 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5225 && newres.length() > dsq.getLength())
5227 // Update with the longer sequence.
5231 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5232 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5233 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5234 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5236 dsq.setSequence(newres);
5238 // TODO: merges will never happen if we 'know' we have the real dataset
5239 // sequence - this should be detected when id==dssid
5241 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5242 // + (pre ? "prepended" : "") + " "
5243 // + (post ? "appended" : ""));
5248 // sequence refs are identical. We may need to update the existing dataset
5249 // alignment with this one, though.
5250 if (ds != null && dseqs == null)
5252 int opos = ds.findIndex(dsq);
5253 SequenceI tseq = null;
5254 if (opos != -1 && vseqpos != opos)
5256 // remove from old position
5257 ds.deleteSequence(dsq);
5259 if (vseqpos < ds.getHeight())
5261 if (vseqpos != opos)
5263 // save sequence at destination position
5264 tseq = ds.getSequenceAt(vseqpos);
5265 ds.replaceSequenceAt(vseqpos, dsq);
5266 ds.addSequence(tseq);
5271 ds.addSequence(dsq);
5278 * TODO use AlignmentI here and in related methods - needs
5279 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5281 Hashtable<String, AlignmentI> datasetIds = null;
5283 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5285 private AlignmentI getDatasetFor(String datasetId)
5287 if (datasetIds == null)
5289 datasetIds = new Hashtable<>();
5292 if (datasetIds.containsKey(datasetId))
5294 return datasetIds.get(datasetId);
5299 private void addDatasetRef(String datasetId, AlignmentI dataset)
5301 if (datasetIds == null)
5303 datasetIds = new Hashtable<>();
5305 datasetIds.put(datasetId, dataset);
5309 * make a new dataset ID for this jalview dataset alignment
5314 private String getDatasetIdRef(AlignmentI dataset)
5316 if (dataset.getDataset() != null)
5318 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5320 String datasetId = makeHashCode(dataset, null);
5321 if (datasetId == null)
5323 // make a new datasetId and record it
5324 if (dataset2Ids == null)
5326 dataset2Ids = new IdentityHashMap<>();
5330 datasetId = dataset2Ids.get(dataset);
5332 if (datasetId == null)
5334 datasetId = "ds" + dataset2Ids.size() + 1;
5335 dataset2Ids.put(dataset, datasetId);
5341 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5343 for (int d = 0; d < sequence.getDBRefCount(); d++)
5345 DBRef dr = sequence.getDBRef(d);
5346 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5347 sequence.getDBRef(d).getSource(),
5348 sequence.getDBRef(d).getVersion(),
5349 sequence.getDBRef(d).getAccessionId());
5350 if (dr.getMapping() != null)
5352 entry.setMap(addMapping(dr.getMapping()));
5354 datasetSequence.addDBRef(entry);
5358 private jalview.datamodel.Mapping addMapping(Mapping m)
5360 SequenceI dsto = null;
5361 // Mapping m = dr.getMapping();
5362 int fr[] = new int[m.getMapListFromCount() * 2];
5363 Enumeration f = m.enumerateMapListFrom();
5364 for (int _i = 0; f.hasMoreElements(); _i += 2)
5366 MapListFrom mf = (MapListFrom) f.nextElement();
5367 fr[_i] = mf.getStart();
5368 fr[_i + 1] = mf.getEnd();
5370 int fto[] = new int[m.getMapListToCount() * 2];
5371 f = m.enumerateMapListTo();
5372 for (int _i = 0; f.hasMoreElements(); _i += 2)
5374 MapListTo mf = (MapListTo) f.nextElement();
5375 fto[_i] = mf.getStart();
5376 fto[_i + 1] = mf.getEnd();
5378 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5379 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5380 if (m.getMappingChoice() != null)
5382 MappingChoice mc = m.getMappingChoice();
5383 if (mc.getDseqFor() != null)
5385 String dsfor = "" + mc.getDseqFor();
5386 if (seqRefIds.containsKey(dsfor))
5391 jmap.setTo(seqRefIds.get(dsfor));
5395 frefedSequence.add(newMappingRef(dsfor, jmap));
5401 * local sequence definition
5403 Sequence ms = mc.getSequence();
5404 SequenceI djs = null;
5405 String sqid = ms.getDsseqid();
5406 if (sqid != null && sqid.length() > 0)
5409 * recover dataset sequence
5411 djs = seqRefIds.get(sqid);
5416 "Warning - making up dataset sequence id for DbRef sequence map reference");
5417 sqid = ((Object) ms).toString(); // make up a new hascode for
5418 // undefined dataset sequence hash
5419 // (unlikely to happen)
5425 * make a new dataset sequence and add it to refIds hash
5427 djs = new jalview.datamodel.Sequence(ms.getName(),
5429 djs.setStart(jmap.getMap().getToLowest());
5430 djs.setEnd(jmap.getMap().getToHighest());
5431 djs.setVamsasId(uniqueSetSuffix + sqid);
5433 incompleteSeqs.put(sqid, djs);
5434 seqRefIds.put(sqid, djs);
5437 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5447 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5448 * view as XML (but not to file), and then reloading it
5453 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5456 JalviewModel jm = saveState(ap, null, null, null);
5458 uniqueSetSuffix = "";
5459 jm.getJalviewModelSequence().getViewport(0).setId(null);
5460 // we don't overwrite the view we just copied
5462 if (this.frefedSequence == null)
5464 frefedSequence = new Vector<>();
5467 viewportsAdded.clear();
5469 AlignFrame af = loadFromObject(jm, null, false, null);
5470 af.alignPanels.clear();
5471 af.closeMenuItem_actionPerformed(true);
5474 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5475 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5476 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5477 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5478 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5481 return af.alignPanel;
5484 private Hashtable jvids2vobj;
5486 private void warn(String msg)
5491 private void warn(String msg, Exception e)
5493 if (Cache.log != null)
5497 Cache.log.warn(msg, e);
5501 Cache.log.warn(msg);
5506 System.err.println("Warning: " + msg);
5509 e.printStackTrace();
5514 private void debug(String string)
5516 debug(string, null);
5519 private void debug(String msg, Exception e)
5521 if (Cache.log != null)
5525 Cache.log.debug(msg, e);
5529 Cache.log.debug(msg);
5534 System.err.println("Warning: " + msg);
5537 e.printStackTrace();
5543 * set the object to ID mapping tables used to write/recover objects and XML
5544 * ID strings for the jalview project. If external tables are provided then
5545 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5546 * object goes out of scope. - also populates the datasetIds hashtable with
5547 * alignment objects containing dataset sequences
5550 * Map from ID strings to jalview datamodel
5552 * Map from jalview datamodel to ID strings
5556 public void setObjectMappingTables(Hashtable vobj2jv,
5557 IdentityHashMap jv2vobj)
5559 this.jv2vobj = jv2vobj;
5560 this.vobj2jv = vobj2jv;
5561 Iterator ds = jv2vobj.keySet().iterator();
5563 while (ds.hasNext())
5565 Object jvobj = ds.next();
5566 id = jv2vobj.get(jvobj).toString();
5567 if (jvobj instanceof jalview.datamodel.Alignment)
5569 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5571 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5574 else if (jvobj instanceof jalview.datamodel.Sequence)
5576 // register sequence object so the XML parser can recover it.
5577 if (seqRefIds == null)
5579 seqRefIds = new HashMap<>();
5581 if (seqsToIds == null)
5583 seqsToIds = new IdentityHashMap<>();
5585 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5586 seqsToIds.put((SequenceI) jvobj, id);
5588 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5591 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5592 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5593 if (jvann.annotationId == null)
5595 jvann.annotationId = anid;
5597 if (!jvann.annotationId.equals(anid))
5599 // TODO verify that this is the correct behaviour
5600 this.warn("Overriding Annotation ID for " + anid
5601 + " from different id : " + jvann.annotationId);
5602 jvann.annotationId = anid;
5605 else if (jvobj instanceof String)
5607 if (jvids2vobj == null)
5609 jvids2vobj = new Hashtable();
5610 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5615 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5621 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5622 * objects created from the project archive. If string is null (default for
5623 * construction) then suffix will be set automatically.
5627 public void setUniqueSetSuffix(String string)
5629 uniqueSetSuffix = string;
5634 * uses skipList2 as the skipList for skipping views on sequence sets
5635 * associated with keys in the skipList
5639 public void setSkipList(Hashtable skipList2)
5641 skipList = skipList2;
5645 * Reads the jar entry of given name and returns its contents, or null if the
5646 * entry is not found.
5649 * @param jarEntryName
5652 protected String readJarEntry(jarInputStreamProvider jprovider,
5653 String jarEntryName)
5655 String result = null;
5656 BufferedReader in = null;
5661 * Reopen the jar input stream and traverse its entries to find a matching
5664 JarInputStream jin = jprovider.getJarInputStream();
5665 JarEntry entry = null;
5668 entry = jin.getNextJarEntry();
5669 } while (entry != null && !entry.getName().equals(jarEntryName));
5673 StringBuilder out = new StringBuilder(256);
5674 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5677 while ((data = in.readLine()) != null)
5681 result = out.toString();
5685 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5687 } catch (Exception ex)
5689 ex.printStackTrace();
5697 } catch (IOException e)
5708 * Returns an incrementing counter (0, 1, 2...)
5712 private synchronized int nextCounter()
5718 * Populates an XML model of the feature colour scheme for one feature type
5720 * @param featureType
5724 protected static jalview.schemabinding.version2.Colour marshalColour(
5725 String featureType, FeatureColourI fcol)
5727 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5728 if (fcol.isSimpleColour())
5730 col.setRGB(Format.getHexString(fcol.getColour()));
5734 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5735 col.setMin(fcol.getMin());
5736 col.setMax(fcol.getMax());
5737 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5738 col.setAutoScale(fcol.isAutoScaled());
5739 col.setThreshold(fcol.getThreshold());
5740 col.setColourByLabel(fcol.isColourByLabel());
5741 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5742 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5743 : ColourThreshTypeType.NONE));
5744 if (fcol.isColourByAttribute())
5746 col.setAttributeName(fcol.getAttributeName());
5748 Color noColour = fcol.getNoColour();
5749 if (noColour == null)
5751 col.setNoValueColour(NoValueColour.NONE);
5753 else if (noColour == fcol.getMaxColour())
5755 col.setNoValueColour(NoValueColour.MAX);
5759 col.setNoValueColour(NoValueColour.MIN);
5762 col.setName(featureType);
5767 * Populates an XML model of the feature filter(s) for one feature type
5769 * @param firstMatcher
5770 * the first (or only) match condition)
5772 * remaining match conditions (if any)
5774 * if true, conditions are and-ed, else or-ed
5776 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5777 Iterator<FeatureMatcherI> filters, boolean and)
5779 MatcherSet result = new MatcherSet();
5781 if (filters.hasNext())
5786 CompoundMatcher compound = new CompoundMatcher();
5787 compound.setAnd(and);
5788 MatcherSet matcher1 = marshalFilter(firstMatcher,
5789 Collections.emptyIterator(), and);
5790 compound.addMatcherSet(matcher1);
5791 FeatureMatcherI nextMatcher = filters.next();
5792 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5793 compound.addMatcherSet(matcher2);
5794 result.setCompoundMatcher(compound);
5799 * single condition matcher
5801 MatchCondition matcherModel = new MatchCondition();
5802 matcherModel.setCondition(
5803 firstMatcher.getMatcher().getCondition().getStableName());
5804 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5805 if (firstMatcher.isByAttribute())
5807 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5808 matcherModel.setAttributeName(firstMatcher.getAttribute());
5810 else if (firstMatcher.isByLabel())
5812 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5814 else if (firstMatcher.isByScore())
5816 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5818 result.setMatchCondition(matcherModel);
5825 * Loads one XML model of a feature filter to a Jalview object
5827 * @param featureType
5828 * @param matcherSetModel
5831 protected static FeatureMatcherSetI unmarshalFilter(
5832 String featureType, MatcherSet matcherSetModel)
5834 FeatureMatcherSetI result = new FeatureMatcherSet();
5837 unmarshalFilterConditions(result, matcherSetModel, true);
5838 } catch (IllegalStateException e)
5840 // mixing AND and OR conditions perhaps
5842 String.format("Error reading filter conditions for '%s': %s",
5843 featureType, e.getMessage()));
5844 // return as much as was parsed up to the error
5851 * Adds feature match conditions to matcherSet as unmarshalled from XML
5852 * (possibly recursively for compound conditions)
5855 * @param matcherSetModel
5857 * if true, multiple conditions are AND-ed, else they are OR-ed
5858 * @throws IllegalStateException
5859 * if AND and OR conditions are mixed
5861 protected static void unmarshalFilterConditions(
5862 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5865 MatchCondition mc = matcherSetModel.getMatchCondition();
5871 FeatureMatcherByType filterBy = mc.getBy();
5872 Condition cond = Condition.fromString(mc.getCondition());
5873 String pattern = mc.getValue();
5874 FeatureMatcherI matchCondition = null;
5875 if (filterBy == FeatureMatcherByType.BYLABEL)
5877 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5879 else if (filterBy == FeatureMatcherByType.BYSCORE)
5881 matchCondition = FeatureMatcher.byScore(cond, pattern);
5884 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5886 String[] attNames = mc.getAttributeName();
5887 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5892 * note this throws IllegalStateException if AND-ing to a
5893 * previously OR-ed compound condition, or vice versa
5897 matcherSet.and(matchCondition);
5901 matcherSet.or(matchCondition);
5907 * compound condition
5909 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5911 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5912 if (matchers.length == 2)
5914 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5915 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5919 System.err.println("Malformed compound filter condition");
5925 * Loads one XML model of a feature colour to a Jalview object
5927 * @param colourModel
5930 protected static FeatureColourI unmarshalColour(
5931 jalview.schemabinding.version2.Colour colourModel)
5933 FeatureColourI colour = null;
5935 if (colourModel.hasMax())
5937 Color mincol = null;
5938 Color maxcol = null;
5939 Color noValueColour = null;
5943 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5944 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5945 } catch (Exception e)
5947 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5950 NoValueColour noCol = colourModel.getNoValueColour();
5951 if (noCol == NoValueColour.MIN)
5953 noValueColour = mincol;
5955 else if (noCol == NoValueColour.MAX)
5957 noValueColour = maxcol;
5960 colour = new FeatureColour(mincol, maxcol, noValueColour,
5961 colourModel.getMin(),
5962 colourModel.getMax());
5963 String[] attributes = colourModel.getAttributeName();
5964 if (attributes != null && attributes.length > 0)
5966 colour.setAttributeName(attributes);
5968 if (colourModel.hasAutoScale())
5970 colour.setAutoScaled(colourModel.getAutoScale());
5972 if (colourModel.hasColourByLabel())
5974 colour.setColourByLabel(colourModel.getColourByLabel());
5976 if (colourModel.hasThreshold())
5978 colour.setThreshold(colourModel.getThreshold());
5980 ColourThreshTypeType ttyp = colourModel.getThreshType();
5983 if (ttyp == ColourThreshTypeType.ABOVE)
5985 colour.setAboveThreshold(true);
5987 else if (ttyp == ColourThreshTypeType.BELOW)
5989 colour.setBelowThreshold(true);
5995 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5996 colour = new FeatureColour(color);