2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.analysis.Conservation;
24 import jalview.api.FeatureColourI;
25 import jalview.api.ViewStyleI;
26 import jalview.api.structures.JalviewStructureDisplayI;
27 import jalview.bin.Cache;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.GraphLine;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.RnaViewerModel;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.datamodel.StructureViewerModel;
39 import jalview.datamodel.StructureViewerModel.StructureData;
40 import jalview.datamodel.features.FeatureMatcher;
41 import jalview.datamodel.features.FeatureMatcherI;
42 import jalview.datamodel.features.FeatureMatcherSet;
43 import jalview.datamodel.features.FeatureMatcherSetI;
44 import jalview.ext.varna.RnaModel;
45 import jalview.gui.StructureViewer.ViewerType;
46 import jalview.io.DataSourceType;
47 import jalview.io.FileFormat;
48 import jalview.renderer.ResidueShaderI;
49 import jalview.schemabinding.version2.AlcodMap;
50 import jalview.schemabinding.version2.AlcodonFrame;
51 import jalview.schemabinding.version2.Annotation;
52 import jalview.schemabinding.version2.AnnotationColours;
53 import jalview.schemabinding.version2.AnnotationElement;
54 import jalview.schemabinding.version2.CalcIdParam;
55 import jalview.schemabinding.version2.Colour;
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.treeCanvas.av.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.treeCanvas.threshold);
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.viewName);
1251 view.setGatheredViews(av.isGatherViewsHere());
1253 Rectangle size = ap.av.getExplodedGeometry();
1254 Rectangle position = size;
1257 size = ap.alignFrame.getBounds();
1258 if (av.getCodingComplement() != null)
1260 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1268 view.setXpos(position.x);
1269 view.setYpos(position.y);
1271 view.setWidth(size.width);
1272 view.setHeight(size.height);
1274 view.setStartRes(vpRanges.getStartRes());
1275 view.setStartSeq(vpRanges.getStartSeq());
1277 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1279 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1283 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1285 AnnotationColours ac = constructAnnotationColours(
1286 (jalview.schemes.AnnotationColourGradient) av
1287 .getGlobalColourScheme(),
1290 view.setAnnotationColours(ac);
1291 view.setBgColour("AnnotationColourGradient");
1295 view.setBgColour(ColourSchemeProperty
1296 .getColourName(av.getGlobalColourScheme()));
1299 ResidueShaderI vcs = av.getResidueShading();
1300 ColourSchemeI cs = av.getGlobalColourScheme();
1304 if (vcs.conservationApplied())
1306 view.setConsThreshold(vcs.getConservationInc());
1307 if (cs instanceof jalview.schemes.UserColourScheme)
1309 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1312 view.setPidThreshold(vcs.getThreshold());
1315 view.setConservationSelected(av.getConservationSelected());
1316 view.setPidSelected(av.getAbovePIDThreshold());
1317 view.setFontName(av.font.getName());
1318 view.setFontSize(av.font.getSize());
1319 view.setFontStyle(av.font.getStyle());
1320 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1321 view.setRenderGaps(av.isRenderGaps());
1322 view.setShowAnnotation(av.isShowAnnotation());
1323 view.setShowBoxes(av.getShowBoxes());
1324 view.setShowColourText(av.getColourText());
1325 view.setShowFullId(av.getShowJVSuffix());
1326 view.setRightAlignIds(av.isRightAlignIds());
1327 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1328 view.setShowText(av.getShowText());
1329 view.setShowUnconserved(av.getShowUnconserved());
1330 view.setWrapAlignment(av.getWrapAlignment());
1331 view.setTextCol1(av.getTextColour().getRGB());
1332 view.setTextCol2(av.getTextColour2().getRGB());
1333 view.setTextColThreshold(av.getThresholdTextColour());
1334 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1335 view.setShowSequenceLogo(av.isShowSequenceLogo());
1336 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1337 view.setShowGroupConsensus(av.isShowGroupConsensus());
1338 view.setShowGroupConservation(av.isShowGroupConservation());
1339 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1340 view.setShowDbRefTooltip(av.isShowDBRefs());
1341 view.setFollowHighlight(av.isFollowHighlight());
1342 view.setFollowSelection(av.followSelection);
1343 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1344 if (av.getFeaturesDisplayed() != null)
1346 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1348 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1349 .getFeatureRenderer();
1350 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1352 Vector<String> settingsAdded = new Vector<>();
1353 if (renderOrder != null)
1355 for (String featureType : renderOrder)
1357 Setting setting = new Setting();
1358 setting.setType(featureType);
1361 * save any filter for the feature type
1363 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1364 if (filter != null) {
1365 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1366 FeatureMatcherI firstFilter = filters.next();
1367 setting.setMatcherSet(Jalview2XML.marshalFilter(
1368 firstFilter, filters, filter.isAnded()));
1372 * save colour scheme for the feature type
1374 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1375 if (!fcol.isSimpleColour())
1377 setting.setColour(fcol.getMaxColour().getRGB());
1378 setting.setMincolour(fcol.getMinColour().getRGB());
1379 setting.setMin(fcol.getMin());
1380 setting.setMax(fcol.getMax());
1381 setting.setColourByLabel(fcol.isColourByLabel());
1382 if (fcol.isColourByAttribute())
1384 setting.setAttributeName(fcol.getAttributeName());
1386 setting.setAutoScale(fcol.isAutoScaled());
1387 setting.setThreshold(fcol.getThreshold());
1388 Color noColour = fcol.getNoColour();
1389 if (noColour == null)
1391 setting.setNoValueColour(NoValueColour.NONE);
1393 else if (noColour.equals(fcol.getMaxColour()))
1395 setting.setNoValueColour(NoValueColour.MAX);
1399 setting.setNoValueColour(NoValueColour.MIN);
1401 // -1 = No threshold, 0 = Below, 1 = Above
1402 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1403 : (fcol.isBelowThreshold() ? 0 : -1));
1407 setting.setColour(fcol.getColour().getRGB());
1411 av.getFeaturesDisplayed().isVisible(featureType));
1413 .getOrder(featureType);
1416 setting.setOrder(rorder);
1418 fs.addSetting(setting);
1419 settingsAdded.addElement(featureType);
1423 // is groups actually supposed to be a map here ?
1424 Iterator<String> en = fr.getFeatureGroups().iterator();
1425 Vector<String> groupsAdded = new Vector<>();
1426 while (en.hasNext())
1428 String grp = en.next();
1429 if (groupsAdded.contains(grp))
1433 Group g = new Group();
1435 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1438 groupsAdded.addElement(grp);
1440 jms.setFeatureSettings(fs);
1443 if (av.hasHiddenColumns())
1445 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1446 .getHiddenColumns();
1449 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1453 ArrayList<int[]> hiddenRegions = hidden.getHiddenColumnsCopy();
1454 for (int[] region : hiddenRegions)
1456 HiddenColumns hc = new HiddenColumns();
1457 hc.setStart(region[0]);
1458 hc.setEnd(region[1]);
1459 view.addHiddenColumns(hc);
1463 if (calcIdSet.size() > 0)
1465 for (String calcId : calcIdSet)
1467 if (calcId.trim().length() > 0)
1469 CalcIdParam cidp = createCalcIdParam(calcId, av);
1470 // Some calcIds have no parameters.
1473 view.addCalcIdParam(cidp);
1479 jms.addViewport(view);
1481 object.setJalviewModelSequence(jms);
1482 object.getVamsasModel().addSequenceSet(vamsasSet);
1484 if (jout != null && fileName != null)
1486 // We may not want to write the object to disk,
1487 // eg we can copy the alignViewport to a new view object
1488 // using save and then load
1491 System.out.println("Writing jar entry " + fileName);
1492 JarEntry entry = new JarEntry(fileName);
1493 jout.putNextEntry(entry);
1494 PrintWriter pout = new PrintWriter(
1495 new OutputStreamWriter(jout, UTF_8));
1496 Marshaller marshaller = new Marshaller(pout);
1497 marshaller.marshal(object);
1500 } catch (Exception ex)
1502 // TODO: raise error in GUI if marshalling failed.
1503 ex.printStackTrace();
1510 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1511 * for each viewer, with
1513 * <li>viewer geometry (position, size, split pane divider location)</li>
1514 * <li>index of the selected structure in the viewer (currently shows gapped
1516 * <li>the id of the annotation holding RNA secondary structure</li>
1517 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1519 * Varna viewer state is also written out (in native Varna XML) to separate
1520 * project jar entries. A separate entry is written for each RNA structure
1521 * displayed, with the naming convention
1523 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1531 * @param storeDataset
1533 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1534 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1535 boolean storeDataset)
1537 if (Desktop.desktop == null)
1541 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1542 for (int f = frames.length - 1; f > -1; f--)
1544 if (frames[f] instanceof AppVarna)
1546 AppVarna varna = (AppVarna) frames[f];
1548 * link the sequence to every viewer that is showing it and is linked to
1549 * its alignment panel
1551 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1553 String viewId = varna.getViewId();
1554 RnaViewer rna = new RnaViewer();
1555 rna.setViewId(viewId);
1556 rna.setTitle(varna.getTitle());
1557 rna.setXpos(varna.getX());
1558 rna.setYpos(varna.getY());
1559 rna.setWidth(varna.getWidth());
1560 rna.setHeight(varna.getHeight());
1561 rna.setDividerLocation(varna.getDividerLocation());
1562 rna.setSelectedRna(varna.getSelectedIndex());
1563 jseq.addRnaViewer(rna);
1566 * Store each Varna panel's state once in the project per sequence.
1567 * First time through only (storeDataset==false)
1569 // boolean storeSessions = false;
1570 // String sequenceViewId = viewId + seqsToIds.get(jds);
1571 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1573 // viewIds.add(sequenceViewId);
1574 // storeSessions = true;
1576 for (RnaModel model : varna.getModels())
1578 if (model.seq == jds)
1581 * VARNA saves each view (sequence or alignment secondary
1582 * structure, gapped or trimmed) as a separate XML file
1584 String jarEntryName = rnaSessions.get(model);
1585 if (jarEntryName == null)
1588 String varnaStateFile = varna.getStateInfo(model.rna);
1589 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1590 copyFileToJar(jout, varnaStateFile, jarEntryName);
1591 rnaSessions.put(model, jarEntryName);
1593 SecondaryStructure ss = new SecondaryStructure();
1594 String annotationId = varna.getAnnotation(jds).annotationId;
1595 ss.setAnnotationId(annotationId);
1596 ss.setViewerState(jarEntryName);
1597 ss.setGapped(model.gapped);
1598 ss.setTitle(model.title);
1599 rna.addSecondaryStructure(ss);
1608 * Copy the contents of a file to a new entry added to the output jar
1612 * @param jarEntryName
1614 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1615 String jarEntryName)
1617 DataInputStream dis = null;
1620 File file = new File(infilePath);
1621 if (file.exists() && jout != null)
1623 dis = new DataInputStream(new FileInputStream(file));
1624 byte[] data = new byte[(int) file.length()];
1625 dis.readFully(data);
1626 writeJarEntry(jout, jarEntryName, data);
1628 } catch (Exception ex)
1630 ex.printStackTrace();
1638 } catch (IOException e)
1647 * Write the data to a new entry of given name in the output jar file
1650 * @param jarEntryName
1652 * @throws IOException
1654 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1655 byte[] data) throws IOException
1659 System.out.println("Writing jar entry " + jarEntryName);
1660 jout.putNextEntry(new JarEntry(jarEntryName));
1661 DataOutputStream dout = new DataOutputStream(jout);
1662 dout.write(data, 0, data.length);
1669 * Save the state of a structure viewer
1674 * the archive XML element under which to save the state
1677 * @param matchedFile
1681 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1682 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1683 String matchedFile, StructureViewerBase viewFrame)
1685 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1688 * Look for any bindings for this viewer to the PDB file of interest
1689 * (including part matches excluding chain id)
1691 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1693 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1694 final String pdbId = pdbentry.getId();
1695 if (!pdbId.equals(entry.getId())
1696 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1697 .startsWith(pdbId.toLowerCase())))
1700 * not interested in a binding to a different PDB entry here
1704 if (matchedFile == null)
1706 matchedFile = pdbentry.getFile();
1708 else if (!matchedFile.equals(pdbentry.getFile()))
1711 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1712 + pdbentry.getFile());
1716 // can get at it if the ID
1717 // match is ambiguous (e.g.
1720 for (int smap = 0; smap < viewFrame.getBinding()
1721 .getSequence()[peid].length; smap++)
1723 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1724 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1726 StructureState state = new StructureState();
1727 state.setVisible(true);
1728 state.setXpos(viewFrame.getX());
1729 state.setYpos(viewFrame.getY());
1730 state.setWidth(viewFrame.getWidth());
1731 state.setHeight(viewFrame.getHeight());
1732 final String viewId = viewFrame.getViewId();
1733 state.setViewId(viewId);
1734 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1735 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1736 state.setColourByJmol(viewFrame.isColouredByViewer());
1737 state.setType(viewFrame.getViewerType().toString());
1738 pdb.addStructureState(state);
1746 * Populates the AnnotationColours xml for save. This captures the settings of
1747 * the options in the 'Colour by Annotation' dialog.
1750 * @param userColours
1754 private AnnotationColours constructAnnotationColours(
1755 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1756 JalviewModelSequence jms)
1758 AnnotationColours ac = new AnnotationColours();
1759 ac.setAboveThreshold(acg.getAboveThreshold());
1760 ac.setThreshold(acg.getAnnotationThreshold());
1761 // 2.10.2 save annotationId (unique) not annotation label
1762 ac.setAnnotation(acg.getAnnotation().annotationId);
1763 if (acg.getBaseColour() instanceof UserColourScheme)
1766 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1771 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1774 ac.setMaxColour(acg.getMaxColour().getRGB());
1775 ac.setMinColour(acg.getMinColour().getRGB());
1776 ac.setPerSequence(acg.isSeqAssociated());
1777 ac.setPredefinedColours(acg.isPredefinedColours());
1781 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1782 IdentityHashMap<SequenceGroup, String> groupRefs,
1783 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1784 SequenceSet vamsasSet)
1787 for (int i = 0; i < aa.length; i++)
1789 Annotation an = new Annotation();
1791 AlignmentAnnotation annotation = aa[i];
1792 if (annotation.annotationId != null)
1794 annotationIds.put(annotation.annotationId, annotation);
1797 an.setId(annotation.annotationId);
1799 an.setVisible(annotation.visible);
1801 an.setDescription(annotation.description);
1803 if (annotation.sequenceRef != null)
1805 // 2.9 JAL-1781 xref on sequence id rather than name
1806 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1808 if (annotation.groupRef != null)
1810 String groupIdr = groupRefs.get(annotation.groupRef);
1811 if (groupIdr == null)
1813 // make a locally unique String
1814 groupRefs.put(annotation.groupRef,
1815 groupIdr = ("" + System.currentTimeMillis()
1816 + annotation.groupRef.getName()
1817 + groupRefs.size()));
1819 an.setGroupRef(groupIdr.toString());
1822 // store all visualization attributes for annotation
1823 an.setGraphHeight(annotation.graphHeight);
1824 an.setCentreColLabels(annotation.centreColLabels);
1825 an.setScaleColLabels(annotation.scaleColLabel);
1826 an.setShowAllColLabels(annotation.showAllColLabels);
1827 an.setBelowAlignment(annotation.belowAlignment);
1829 if (annotation.graph > 0)
1832 an.setGraphType(annotation.graph);
1833 an.setGraphGroup(annotation.graphGroup);
1834 if (annotation.getThreshold() != null)
1836 ThresholdLine line = new ThresholdLine();
1837 line.setLabel(annotation.getThreshold().label);
1838 line.setValue(annotation.getThreshold().value);
1839 line.setColour(annotation.getThreshold().colour.getRGB());
1840 an.setThresholdLine(line);
1848 an.setLabel(annotation.label);
1850 if (annotation == av.getAlignmentQualityAnnot()
1851 || annotation == av.getAlignmentConservationAnnotation()
1852 || annotation == av.getAlignmentConsensusAnnotation()
1853 || annotation.autoCalculated)
1855 // new way of indicating autocalculated annotation -
1856 an.setAutoCalculated(annotation.autoCalculated);
1858 if (annotation.hasScore())
1860 an.setScore(annotation.getScore());
1863 if (annotation.getCalcId() != null)
1865 calcIdSet.add(annotation.getCalcId());
1866 an.setCalcId(annotation.getCalcId());
1868 if (annotation.hasProperties())
1870 for (String pr : annotation.getProperties())
1872 Property prop = new Property();
1874 prop.setValue(annotation.getProperty(pr));
1875 an.addProperty(prop);
1879 AnnotationElement ae;
1880 if (annotation.annotations != null)
1882 an.setScoreOnly(false);
1883 for (int a = 0; a < annotation.annotations.length; a++)
1885 if ((annotation == null) || (annotation.annotations[a] == null))
1890 ae = new AnnotationElement();
1891 if (annotation.annotations[a].description != null)
1893 ae.setDescription(annotation.annotations[a].description);
1895 if (annotation.annotations[a].displayCharacter != null)
1897 ae.setDisplayCharacter(
1898 annotation.annotations[a].displayCharacter);
1901 if (!Float.isNaN(annotation.annotations[a].value))
1903 ae.setValue(annotation.annotations[a].value);
1907 if (annotation.annotations[a].secondaryStructure > ' ')
1909 ae.setSecondaryStructure(
1910 annotation.annotations[a].secondaryStructure + "");
1913 if (annotation.annotations[a].colour != null
1914 && annotation.annotations[a].colour != java.awt.Color.black)
1916 ae.setColour(annotation.annotations[a].colour.getRGB());
1919 an.addAnnotationElement(ae);
1920 if (annotation.autoCalculated)
1922 // only write one non-null entry into the annotation row -
1923 // sufficient to get the visualization attributes necessary to
1931 an.setScoreOnly(true);
1933 if (!storeDS || (storeDS && !annotation.autoCalculated))
1935 // skip autocalculated annotation - these are only provided for
1937 vamsasSet.addAnnotation(an);
1943 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1945 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1946 if (settings != null)
1948 CalcIdParam vCalcIdParam = new CalcIdParam();
1949 vCalcIdParam.setCalcId(calcId);
1950 vCalcIdParam.addServiceURL(settings.getServiceURI());
1951 // generic URI allowing a third party to resolve another instance of the
1952 // service used for this calculation
1953 for (String urls : settings.getServiceURLs())
1955 vCalcIdParam.addServiceURL(urls);
1957 vCalcIdParam.setVersion("1.0");
1958 if (settings.getPreset() != null)
1960 WsParamSetI setting = settings.getPreset();
1961 vCalcIdParam.setName(setting.getName());
1962 vCalcIdParam.setDescription(setting.getDescription());
1966 vCalcIdParam.setName("");
1967 vCalcIdParam.setDescription("Last used parameters");
1969 // need to be able to recover 1) settings 2) user-defined presets or
1970 // recreate settings from preset 3) predefined settings provided by
1971 // service - or settings that can be transferred (or discarded)
1972 vCalcIdParam.setParameters(
1973 settings.getWsParamFile().replace("\n", "|\\n|"));
1974 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1975 // todo - decide if updateImmediately is needed for any projects.
1977 return vCalcIdParam;
1982 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1985 if (calcIdParam.getVersion().equals("1.0"))
1987 Jws2Instance service = Jws2Discoverer.getDiscoverer()
1988 .getPreferredServiceFor(calcIdParam.getServiceURL());
1989 if (service != null)
1991 WsParamSetI parmSet = null;
1994 parmSet = service.getParamStore().parseServiceParameterFile(
1995 calcIdParam.getName(), calcIdParam.getDescription(),
1996 calcIdParam.getServiceURL(),
1997 calcIdParam.getParameters().replace("|\\n|", "\n"));
1998 } catch (IOException x)
2000 warn("Couldn't parse parameter data for "
2001 + calcIdParam.getCalcId(), x);
2004 List<ArgumentI> argList = null;
2005 if (calcIdParam.getName().length() > 0)
2007 parmSet = service.getParamStore()
2008 .getPreset(calcIdParam.getName());
2009 if (parmSet != null)
2011 // TODO : check we have a good match with settings in AACon -
2012 // otherwise we'll need to create a new preset
2017 argList = parmSet.getArguments();
2020 AAConSettings settings = new AAConSettings(
2021 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2022 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2023 calcIdParam.isNeedsUpdate());
2028 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2032 throw new Error(MessageManager.formatMessage(
2033 "error.unsupported_version_calcIdparam", new Object[]
2034 { calcIdParam.toString() }));
2038 * External mapping between jalview objects and objects yielding a valid and
2039 * unique object ID string. This is null for normal Jalview project IO, but
2040 * non-null when a jalview project is being read or written as part of a
2043 IdentityHashMap jv2vobj = null;
2046 * Construct a unique ID for jvobj using either existing bindings or if none
2047 * exist, the result of the hashcode call for the object.
2050 * jalview data object
2051 * @return unique ID for referring to jvobj
2053 private String makeHashCode(Object jvobj, String altCode)
2055 if (jv2vobj != null)
2057 Object id = jv2vobj.get(jvobj);
2060 return id.toString();
2062 // check string ID mappings
2063 if (jvids2vobj != null && jvobj instanceof String)
2065 id = jvids2vobj.get(jvobj);
2069 return id.toString();
2071 // give up and warn that something has gone wrong
2072 warn("Cannot find ID for object in external mapping : " + jvobj);
2078 * return local jalview object mapped to ID, if it exists
2082 * @return null or object bound to idcode
2084 private Object retrieveExistingObj(String idcode)
2086 if (idcode != null && vobj2jv != null)
2088 return vobj2jv.get(idcode);
2094 * binding from ID strings from external mapping table to jalview data model
2097 private Hashtable vobj2jv;
2099 private Sequence createVamsasSequence(String id, SequenceI jds)
2101 return createVamsasSequence(true, id, jds, null);
2104 private Sequence createVamsasSequence(boolean recurse, String id,
2105 SequenceI jds, SequenceI parentseq)
2107 Sequence vamsasSeq = new Sequence();
2108 vamsasSeq.setId(id);
2109 vamsasSeq.setName(jds.getName());
2110 vamsasSeq.setSequence(jds.getSequenceAsString());
2111 vamsasSeq.setDescription(jds.getDescription());
2112 jalview.datamodel.DBRefEntry[] dbrefs = null;
2113 if (jds.getDatasetSequence() != null)
2115 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2119 // seqId==dsseqid so we can tell which sequences really are
2120 // dataset sequences only
2121 vamsasSeq.setDsseqid(id);
2122 dbrefs = jds.getDBRefs();
2123 if (parentseq == null)
2130 for (int d = 0; d < dbrefs.length; d++)
2132 DBRef dbref = new DBRef();
2133 dbref.setSource(dbrefs[d].getSource());
2134 dbref.setVersion(dbrefs[d].getVersion());
2135 dbref.setAccessionId(dbrefs[d].getAccessionId());
2136 if (dbrefs[d].hasMap())
2138 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2140 dbref.setMapping(mp);
2142 vamsasSeq.addDBRef(dbref);
2148 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2149 SequenceI parentseq, SequenceI jds, boolean recurse)
2152 if (jmp.getMap() != null)
2156 jalview.util.MapList mlst = jmp.getMap();
2157 List<int[]> r = mlst.getFromRanges();
2158 for (int[] range : r)
2160 MapListFrom mfrom = new MapListFrom();
2161 mfrom.setStart(range[0]);
2162 mfrom.setEnd(range[1]);
2163 mp.addMapListFrom(mfrom);
2165 r = mlst.getToRanges();
2166 for (int[] range : r)
2168 MapListTo mto = new MapListTo();
2169 mto.setStart(range[0]);
2170 mto.setEnd(range[1]);
2171 mp.addMapListTo(mto);
2173 mp.setMapFromUnit(mlst.getFromRatio());
2174 mp.setMapToUnit(mlst.getToRatio());
2175 if (jmp.getTo() != null)
2177 MappingChoice mpc = new MappingChoice();
2179 // check/create ID for the sequence referenced by getTo()
2182 SequenceI ps = null;
2183 if (parentseq != jmp.getTo()
2184 && parentseq.getDatasetSequence() != jmp.getTo())
2186 // chaining dbref rather than a handshaking one
2187 jmpid = seqHash(ps = jmp.getTo());
2191 jmpid = seqHash(ps = parentseq);
2193 mpc.setDseqFor(jmpid);
2194 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2196 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2197 seqRefIds.put(mpc.getDseqFor(), ps);
2201 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2204 mp.setMappingChoice(mpc);
2210 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2211 List<UserColourScheme> userColours, JalviewModelSequence jms)
2214 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2215 boolean newucs = false;
2216 if (!userColours.contains(ucs))
2218 userColours.add(ucs);
2221 id = "ucs" + userColours.indexOf(ucs);
2224 // actually create the scheme's entry in the XML model
2225 java.awt.Color[] colours = ucs.getColours();
2226 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2227 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2229 for (int i = 0; i < colours.length; i++)
2231 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2232 col.setName(ResidueProperties.aa[i]);
2233 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2234 jbucs.addColour(col);
2236 if (ucs.getLowerCaseColours() != null)
2238 colours = ucs.getLowerCaseColours();
2239 for (int i = 0; i < colours.length; i++)
2241 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2242 col.setName(ResidueProperties.aa[i].toLowerCase());
2243 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2244 jbucs.addColour(col);
2249 uc.setUserColourScheme(jbucs);
2250 jms.addUserColours(uc);
2256 jalview.schemes.UserColourScheme getUserColourScheme(
2257 JalviewModelSequence jms, String id)
2259 UserColours[] uc = jms.getUserColours();
2260 UserColours colours = null;
2262 for (int i = 0; i < uc.length; i++)
2264 if (uc[i].getId().equals(id))
2272 java.awt.Color[] newColours = new java.awt.Color[24];
2274 for (int i = 0; i < 24; i++)
2276 newColours[i] = new java.awt.Color(Integer.parseInt(
2277 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2280 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2283 if (colours.getUserColourScheme().getColourCount() > 24)
2285 newColours = new java.awt.Color[23];
2286 for (int i = 0; i < 23; i++)
2288 newColours[i] = new java.awt.Color(Integer.parseInt(
2289 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2292 ucs.setLowerCaseColours(newColours);
2299 * contains last error message (if any) encountered by XML loader.
2301 String errorMessage = null;
2304 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2305 * exceptions are raised during project XML parsing
2307 public boolean attemptversion1parse = true;
2310 * Load a jalview project archive from a jar file
2313 * - HTTP URL or filename
2315 public AlignFrame loadJalviewAlign(final String file)
2318 jalview.gui.AlignFrame af = null;
2322 // create list to store references for any new Jmol viewers created
2323 newStructureViewers = new Vector<>();
2324 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2325 // Workaround is to make sure caller implements the JarInputStreamProvider
2327 // so we can re-open the jar input stream for each entry.
2329 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2330 af = loadJalviewAlign(jprovider);
2331 af.setMenusForViewport();
2333 } catch (MalformedURLException e)
2335 errorMessage = "Invalid URL format for '" + file + "'";
2341 SwingUtilities.invokeAndWait(new Runnable()
2346 setLoadingFinishedForNewStructureViewers();
2349 } catch (Exception x)
2351 System.err.println("Error loading alignment: " + x.getMessage());
2357 private jarInputStreamProvider createjarInputStreamProvider(
2358 final String file) throws MalformedURLException
2361 errorMessage = null;
2362 uniqueSetSuffix = null;
2364 viewportsAdded.clear();
2365 frefedSequence = null;
2367 if (file.startsWith("http://"))
2369 url = new URL(file);
2371 final URL _url = url;
2372 return new jarInputStreamProvider()
2376 public JarInputStream getJarInputStream() throws IOException
2380 return new JarInputStream(_url.openStream());
2384 return new JarInputStream(new FileInputStream(file));
2389 public String getFilename()
2397 * Recover jalview session from a jalview project archive. Caller may
2398 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2399 * themselves. Any null fields will be initialised with default values,
2400 * non-null fields are left alone.
2405 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2407 errorMessage = null;
2408 if (uniqueSetSuffix == null)
2410 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2412 if (seqRefIds == null)
2416 AlignFrame af = null, _af = null;
2417 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2418 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2419 final String file = jprovider.getFilename();
2422 JarInputStream jin = null;
2423 JarEntry jarentry = null;
2428 jin = jprovider.getJarInputStream();
2429 for (int i = 0; i < entryCount; i++)
2431 jarentry = jin.getNextJarEntry();
2434 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2436 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2437 JalviewModel object = new JalviewModel();
2439 Unmarshaller unmar = new Unmarshaller(object);
2440 unmar.setValidation(false);
2441 object = (JalviewModel) unmar.unmarshal(in);
2442 if (true) // !skipViewport(object))
2444 _af = loadFromObject(object, file, true, jprovider);
2445 if (_af != null && object.getJalviewModelSequence()
2446 .getViewportCount() > 0)
2450 // store a reference to the first view
2453 if (_af.viewport.isGatherViewsHere())
2455 // if this is a gathered view, keep its reference since
2456 // after gathering views, only this frame will remain
2458 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2460 // Save dataset to register mappings once all resolved
2461 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2462 af.viewport.getAlignment().getDataset());
2467 else if (jarentry != null)
2469 // Some other file here.
2472 } while (jarentry != null);
2473 resolveFrefedSequences();
2474 } catch (IOException ex)
2476 ex.printStackTrace();
2477 errorMessage = "Couldn't locate Jalview XML file : " + file;
2479 "Exception whilst loading jalview XML file : " + ex + "\n");
2480 } catch (Exception ex)
2482 System.err.println("Parsing as Jalview Version 2 file failed.");
2483 ex.printStackTrace(System.err);
2484 if (attemptversion1parse)
2486 // Is Version 1 Jar file?
2489 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2490 } catch (Exception ex2)
2492 System.err.println("Exception whilst loading as jalviewXMLV1:");
2493 ex2.printStackTrace();
2497 if (Desktop.instance != null)
2499 Desktop.instance.stopLoading();
2503 System.out.println("Successfully loaded archive file");
2506 ex.printStackTrace();
2509 "Exception whilst loading jalview XML file : " + ex + "\n");
2510 } catch (OutOfMemoryError e)
2512 // Don't use the OOM Window here
2513 errorMessage = "Out of memory loading jalview XML file";
2514 System.err.println("Out of memory whilst loading jalview XML file");
2515 e.printStackTrace();
2519 * Regather multiple views (with the same sequence set id) to the frame (if
2520 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2521 * views instead of separate frames. Note this doesn't restore a state where
2522 * some expanded views in turn have tabbed views - the last "first tab" read
2523 * in will play the role of gatherer for all.
2525 for (AlignFrame fr : gatherToThisFrame.values())
2527 Desktop.instance.gatherViews(fr);
2530 restoreSplitFrames();
2531 for (AlignmentI ds : importedDatasets.keySet())
2533 if (ds.getCodonFrames() != null)
2535 StructureSelectionManager
2536 .getStructureSelectionManager(Desktop.instance)
2537 .registerMappings(ds.getCodonFrames());
2540 if (errorMessage != null)
2545 if (Desktop.instance != null)
2547 Desktop.instance.stopLoading();
2554 * Try to reconstruct and display SplitFrame windows, where each contains
2555 * complementary dna and protein alignments. Done by pairing up AlignFrame
2556 * objects (created earlier) which have complementary viewport ids associated.
2558 protected void restoreSplitFrames()
2560 List<SplitFrame> gatherTo = new ArrayList<>();
2561 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2562 Map<String, AlignFrame> dna = new HashMap<>();
2565 * Identify the DNA alignments
2567 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2570 AlignFrame af = candidate.getValue();
2571 if (af.getViewport().getAlignment().isNucleotide())
2573 dna.put(candidate.getKey().getId(), af);
2578 * Try to match up the protein complements
2580 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2583 AlignFrame af = candidate.getValue();
2584 if (!af.getViewport().getAlignment().isNucleotide())
2586 String complementId = candidate.getKey().getComplementId();
2587 // only non-null complements should be in the Map
2588 if (complementId != null && dna.containsKey(complementId))
2590 final AlignFrame dnaFrame = dna.get(complementId);
2591 SplitFrame sf = createSplitFrame(dnaFrame, af);
2592 addedToSplitFrames.add(dnaFrame);
2593 addedToSplitFrames.add(af);
2594 dnaFrame.setMenusForViewport();
2595 af.setMenusForViewport();
2596 if (af.viewport.isGatherViewsHere())
2605 * Open any that we failed to pair up (which shouldn't happen!) as
2606 * standalone AlignFrame's.
2608 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2611 AlignFrame af = candidate.getValue();
2612 if (!addedToSplitFrames.contains(af))
2614 Viewport view = candidate.getKey();
2615 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2617 af.setMenusForViewport();
2618 System.err.println("Failed to restore view " + view.getTitle()
2619 + " to split frame");
2624 * Gather back into tabbed views as flagged.
2626 for (SplitFrame sf : gatherTo)
2628 Desktop.instance.gatherViews(sf);
2631 splitFrameCandidates.clear();
2635 * Construct and display one SplitFrame holding DNA and protein alignments.
2638 * @param proteinFrame
2641 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2642 AlignFrame proteinFrame)
2644 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2645 String title = MessageManager.getString("label.linked_view_title");
2646 int width = (int) dnaFrame.getBounds().getWidth();
2647 int height = (int) (dnaFrame.getBounds().getHeight()
2648 + proteinFrame.getBounds().getHeight() + 50);
2651 * SplitFrame location is saved to both enclosed frames
2653 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2654 Desktop.addInternalFrame(splitFrame, title, width, height);
2657 * And compute cDNA consensus (couldn't do earlier with consensus as
2658 * mappings were not yet present)
2660 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2666 * check errorMessage for a valid error message and raise an error box in the
2667 * GUI or write the current errorMessage to stderr and then clear the error
2670 protected void reportErrors()
2672 reportErrors(false);
2675 protected void reportErrors(final boolean saving)
2677 if (errorMessage != null)
2679 final String finalErrorMessage = errorMessage;
2682 javax.swing.SwingUtilities.invokeLater(new Runnable()
2687 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2689 "Error " + (saving ? "saving" : "loading")
2691 JvOptionPane.WARNING_MESSAGE);
2697 System.err.println("Problem loading Jalview file: " + errorMessage);
2700 errorMessage = null;
2703 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2706 * when set, local views will be updated from view stored in JalviewXML
2707 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2708 * sync if this is set to true.
2710 private final boolean updateLocalViews = false;
2713 * Returns the path to a temporary file holding the PDB file for the given PDB
2714 * id. The first time of asking, searches for a file of that name in the
2715 * Jalview project jar, and copies it to a new temporary file. Any repeat
2716 * requests just return the path to the file previously created.
2722 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2725 if (alreadyLoadedPDB.containsKey(pdbId))
2727 return alreadyLoadedPDB.get(pdbId).toString();
2730 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2732 if (tempFile != null)
2734 alreadyLoadedPDB.put(pdbId, tempFile);
2740 * Copies the jar entry of given name to a new temporary file and returns the
2741 * path to the file, or null if the entry is not found.
2744 * @param jarEntryName
2746 * a prefix for the temporary file name, must be at least three
2749 * null or original file - so new file can be given the same suffix
2753 protected String copyJarEntry(jarInputStreamProvider jprovider,
2754 String jarEntryName, String prefix, String origFile)
2756 BufferedReader in = null;
2757 PrintWriter out = null;
2758 String suffix = ".tmp";
2759 if (origFile == null)
2761 origFile = jarEntryName;
2763 int sfpos = origFile.lastIndexOf(".");
2764 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2766 suffix = "." + origFile.substring(sfpos + 1);
2770 JarInputStream jin = jprovider.getJarInputStream();
2772 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2773 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2774 * FileInputStream(jprovider)); }
2777 JarEntry entry = null;
2780 entry = jin.getNextJarEntry();
2781 } while (entry != null && !entry.getName().equals(jarEntryName));
2784 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2785 File outFile = File.createTempFile(prefix, suffix);
2786 outFile.deleteOnExit();
2787 out = new PrintWriter(new FileOutputStream(outFile));
2790 while ((data = in.readLine()) != null)
2795 String t = outFile.getAbsolutePath();
2800 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2802 } catch (Exception ex)
2804 ex.printStackTrace();
2812 } catch (IOException e)
2826 private class JvAnnotRow
2828 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2835 * persisted version of annotation row from which to take vis properties
2837 public jalview.datamodel.AlignmentAnnotation template;
2840 * original position of the annotation row in the alignment
2846 * Load alignment frame from jalview XML DOM object
2851 * filename source string
2852 * @param loadTreesAndStructures
2853 * when false only create Viewport
2855 * data source provider
2856 * @return alignment frame created from view stored in DOM
2858 AlignFrame loadFromObject(JalviewModel object, String file,
2859 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2861 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2862 Sequence[] vamsasSeq = vamsasSet.getSequence();
2864 JalviewModelSequence jms = object.getJalviewModelSequence();
2866 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2869 // ////////////////////////////////
2872 List<SequenceI> hiddenSeqs = null;
2874 List<SequenceI> tmpseqs = new ArrayList<>();
2876 boolean multipleView = false;
2877 SequenceI referenceseqForView = null;
2878 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2879 int vi = 0; // counter in vamsasSeq array
2880 for (int i = 0; i < jseqs.length; i++)
2882 String seqId = jseqs[i].getId();
2884 SequenceI tmpSeq = seqRefIds.get(seqId);
2887 if (!incompleteSeqs.containsKey(seqId))
2889 // may not need this check, but keep it for at least 2.9,1 release
2890 if (tmpSeq.getStart() != jseqs[i].getStart()
2891 || tmpSeq.getEnd() != jseqs[i].getEnd())
2894 "Warning JAL-2154 regression: updating start/end for sequence "
2895 + tmpSeq.toString() + " to " + jseqs[i]);
2900 incompleteSeqs.remove(seqId);
2902 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2904 // most likely we are reading a dataset XML document so
2905 // update from vamsasSeq section of XML for this sequence
2906 tmpSeq.setName(vamsasSeq[vi].getName());
2907 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2908 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2913 // reading multiple views, so vamsasSeq set is a subset of JSeq
2914 multipleView = true;
2916 tmpSeq.setStart(jseqs[i].getStart());
2917 tmpSeq.setEnd(jseqs[i].getEnd());
2918 tmpseqs.add(tmpSeq);
2922 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2923 vamsasSeq[vi].getSequence());
2924 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2925 tmpSeq.setStart(jseqs[i].getStart());
2926 tmpSeq.setEnd(jseqs[i].getEnd());
2927 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2928 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2929 tmpseqs.add(tmpSeq);
2933 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2935 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2938 if (jseqs[i].getHidden())
2940 if (hiddenSeqs == null)
2942 hiddenSeqs = new ArrayList<>();
2945 hiddenSeqs.add(tmpSeq);
2950 // Create the alignment object from the sequence set
2951 // ///////////////////////////////
2952 SequenceI[] orderedSeqs = tmpseqs
2953 .toArray(new SequenceI[tmpseqs.size()]);
2955 AlignmentI al = null;
2956 // so we must create or recover the dataset alignment before going further
2957 // ///////////////////////////////
2958 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2960 // older jalview projects do not have a dataset - so creat alignment and
2962 al = new Alignment(orderedSeqs);
2963 al.setDataset(null);
2967 boolean isdsal = object.getJalviewModelSequence()
2968 .getViewportCount() == 0;
2971 // we are importing a dataset record, so
2972 // recover reference to an alignment already materialsed as dataset
2973 al = getDatasetFor(vamsasSet.getDatasetId());
2977 // materialse the alignment
2978 al = new Alignment(orderedSeqs);
2982 addDatasetRef(vamsasSet.getDatasetId(), al);
2985 // finally, verify all data in vamsasSet is actually present in al
2986 // passing on flag indicating if it is actually a stored dataset
2987 recoverDatasetFor(vamsasSet, al, isdsal);
2990 if (referenceseqForView != null)
2992 al.setSeqrep(referenceseqForView);
2994 // / Add the alignment properties
2995 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
2997 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
2998 al.setProperty(ssp.getKey(), ssp.getValue());
3001 // ///////////////////////////////
3003 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3006 // load sequence features, database references and any associated PDB
3007 // structures for the alignment
3009 // prior to 2.10, this part would only be executed the first time a
3010 // sequence was encountered, but not afterwards.
3011 // now, for 2.10 projects, this is also done if the xml doc includes
3012 // dataset sequences not actually present in any particular view.
3014 for (int i = 0; i < vamsasSeq.length; i++)
3016 if (jseqs[i].getFeaturesCount() > 0)
3018 Features[] features = jseqs[i].getFeatures();
3019 for (int f = 0; f < features.length; f++)
3021 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3022 features[f].getDescription(), features[f].getBegin(),
3023 features[f].getEnd(), features[f].getScore(),
3024 features[f].getFeatureGroup());
3025 sf.setStatus(features[f].getStatus());
3028 * load any feature attributes - include map-valued attributes
3030 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3031 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3033 OtherData keyValue = features[f].getOtherData(od);
3034 String attributeName = keyValue.getKey();
3035 String attributeValue = keyValue.getValue();
3036 if (attributeName.startsWith("LINK"))
3038 sf.addLink(attributeValue);
3042 String subAttribute = keyValue.getKey2();
3043 if (subAttribute == null)
3045 // simple string-valued attribute
3046 sf.setValue(attributeName, attributeValue);
3050 // attribute 'key' has sub-attribute 'key2'
3051 if (!mapAttributes.containsKey(attributeName))
3053 mapAttributes.put(attributeName, new HashMap<>());
3055 mapAttributes.get(attributeName).put(subAttribute,
3060 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3063 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3066 // adds feature to datasequence's feature set (since Jalview 2.10)
3067 al.getSequenceAt(i).addSequenceFeature(sf);
3070 if (vamsasSeq[i].getDBRefCount() > 0)
3072 // adds dbrefs to datasequence's set (since Jalview 2.10)
3074 al.getSequenceAt(i).getDatasetSequence() == null
3075 ? al.getSequenceAt(i)
3076 : al.getSequenceAt(i).getDatasetSequence(),
3079 if (jseqs[i].getPdbidsCount() > 0)
3081 Pdbids[] ids = jseqs[i].getPdbids();
3082 for (int p = 0; p < ids.length; p++)
3084 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3085 entry.setId(ids[p].getId());
3086 if (ids[p].getType() != null)
3088 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3090 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3094 entry.setType(PDBEntry.Type.FILE);
3097 // jprovider is null when executing 'New View'
3098 if (ids[p].getFile() != null && jprovider != null)
3100 if (!pdbloaded.containsKey(ids[p].getFile()))
3102 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3107 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3110 if (ids[p].getPdbentryItem() != null)
3112 for (PdbentryItem item : ids[p].getPdbentryItem())
3114 for (Property pr : item.getProperty())
3116 entry.setProperty(pr.getName(), pr.getValue());
3120 StructureSelectionManager
3121 .getStructureSelectionManager(Desktop.instance)
3122 .registerPDBEntry(entry);
3123 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3124 if (al.getSequenceAt(i).getDatasetSequence() != null)
3126 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3130 al.getSequenceAt(i).addPDBId(entry);
3135 } // end !multipleview
3137 // ///////////////////////////////
3138 // LOAD SEQUENCE MAPPINGS
3140 if (vamsasSet.getAlcodonFrameCount() > 0)
3142 // TODO Potentially this should only be done once for all views of an
3144 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3145 for (int i = 0; i < alc.length; i++)
3147 AlignedCodonFrame cf = new AlignedCodonFrame();
3148 if (alc[i].getAlcodMapCount() > 0)
3150 AlcodMap[] maps = alc[i].getAlcodMap();
3151 for (int m = 0; m < maps.length; m++)
3153 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3155 jalview.datamodel.Mapping mapping = null;
3156 // attach to dna sequence reference.
3157 if (maps[m].getMapping() != null)
3159 mapping = addMapping(maps[m].getMapping());
3160 if (dnaseq != null && mapping.getTo() != null)
3162 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3168 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3172 al.addCodonFrame(cf);
3177 // ////////////////////////////////
3179 List<JvAnnotRow> autoAlan = new ArrayList<>();
3182 * store any annotations which forward reference a group's ID
3184 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3186 if (vamsasSet.getAnnotationCount() > 0)
3188 Annotation[] an = vamsasSet.getAnnotation();
3190 for (int i = 0; i < an.length; i++)
3192 Annotation annotation = an[i];
3195 * test if annotation is automatically calculated for this view only
3197 boolean autoForView = false;
3198 if (annotation.getLabel().equals("Quality")
3199 || annotation.getLabel().equals("Conservation")
3200 || annotation.getLabel().equals("Consensus"))
3202 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3204 if (!annotation.hasAutoCalculated())
3206 annotation.setAutoCalculated(true);
3209 if (autoForView || (annotation.hasAutoCalculated()
3210 && annotation.isAutoCalculated()))
3212 // remove ID - we don't recover annotation from other views for
3213 // view-specific annotation
3214 annotation.setId(null);
3217 // set visiblity for other annotation in this view
3218 String annotationId = annotation.getId();
3219 if (annotationId != null && annotationIds.containsKey(annotationId))
3221 AlignmentAnnotation jda = annotationIds.get(annotationId);
3222 // in principle Visible should always be true for annotation displayed
3223 // in multiple views
3224 if (annotation.hasVisible())
3226 jda.visible = annotation.getVisible();
3229 al.addAnnotation(jda);
3233 // Construct new annotation from model.
3234 AnnotationElement[] ae = annotation.getAnnotationElement();
3235 jalview.datamodel.Annotation[] anot = null;
3236 java.awt.Color firstColour = null;
3238 if (!annotation.getScoreOnly())
3240 anot = new jalview.datamodel.Annotation[al.getWidth()];
3241 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3243 anpos = ae[aa].getPosition();
3245 if (anpos >= anot.length)
3250 anot[anpos] = new jalview.datamodel.Annotation(
3252 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3253 (ae[aa].getSecondaryStructure() == null
3254 || ae[aa].getSecondaryStructure().length() == 0)
3256 : ae[aa].getSecondaryStructure()
3261 // JBPNote: Consider verifying dataflow for IO of secondary
3262 // structure annotation read from Stockholm files
3263 // this was added to try to ensure that
3264 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3266 // anot[ae[aa].getPosition()].displayCharacter = "";
3268 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3269 if (firstColour == null)
3271 firstColour = anot[anpos].colour;
3275 jalview.datamodel.AlignmentAnnotation jaa = null;
3277 if (annotation.getGraph())
3279 float llim = 0, hlim = 0;
3280 // if (autoForView || an[i].isAutoCalculated()) {
3283 jaa = new jalview.datamodel.AlignmentAnnotation(
3284 annotation.getLabel(), annotation.getDescription(), anot,
3285 llim, hlim, annotation.getGraphType());
3287 jaa.graphGroup = annotation.getGraphGroup();
3288 jaa._linecolour = firstColour;
3289 if (annotation.getThresholdLine() != null)
3291 jaa.setThreshold(new jalview.datamodel.GraphLine(
3292 annotation.getThresholdLine().getValue(),
3293 annotation.getThresholdLine().getLabel(),
3295 annotation.getThresholdLine().getColour())));
3298 if (autoForView || annotation.isAutoCalculated())
3300 // Hardwire the symbol display line to ensure that labels for
3301 // histograms are displayed
3307 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3308 an[i].getDescription(), anot);
3309 jaa._linecolour = firstColour;
3311 // register new annotation
3312 if (an[i].getId() != null)
3314 annotationIds.put(an[i].getId(), jaa);
3315 jaa.annotationId = an[i].getId();
3317 // recover sequence association
3318 String sequenceRef = an[i].getSequenceRef();
3319 if (sequenceRef != null)
3321 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3322 SequenceI sequence = seqRefIds.get(sequenceRef);
3323 if (sequence == null)
3325 // in pre-2.9 projects sequence ref is to sequence name
3326 sequence = al.findName(sequenceRef);
3328 if (sequence != null)
3330 jaa.createSequenceMapping(sequence, 1, true);
3331 sequence.addAlignmentAnnotation(jaa);
3334 // and make a note of any group association
3335 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3337 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3338 .get(an[i].getGroupRef());
3341 aal = new ArrayList<>();
3342 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3347 if (an[i].hasScore())
3349 jaa.setScore(an[i].getScore());
3351 if (an[i].hasVisible())
3353 jaa.visible = an[i].getVisible();
3356 if (an[i].hasCentreColLabels())
3358 jaa.centreColLabels = an[i].getCentreColLabels();
3361 if (an[i].hasScaleColLabels())
3363 jaa.scaleColLabel = an[i].getScaleColLabels();
3365 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3367 // newer files have an 'autoCalculated' flag and store calculation
3368 // state in viewport properties
3369 jaa.autoCalculated = true; // means annotation will be marked for
3370 // update at end of load.
3372 if (an[i].hasGraphHeight())
3374 jaa.graphHeight = an[i].getGraphHeight();
3376 if (an[i].hasBelowAlignment())
3378 jaa.belowAlignment = an[i].isBelowAlignment();
3380 jaa.setCalcId(an[i].getCalcId());
3381 if (an[i].getPropertyCount() > 0)
3383 for (jalview.schemabinding.version2.Property prop : an[i]
3386 jaa.setProperty(prop.getName(), prop.getValue());
3389 if (jaa.autoCalculated)
3391 autoAlan.add(new JvAnnotRow(i, jaa));
3394 // if (!autoForView)
3396 // add autocalculated group annotation and any user created annotation
3398 al.addAnnotation(jaa);
3402 // ///////////////////////
3404 // Create alignment markup and styles for this view
3405 if (jms.getJGroupCount() > 0)
3407 JGroup[] groups = jms.getJGroup();
3408 boolean addAnnotSchemeGroup = false;
3409 for (int i = 0; i < groups.length; i++)
3411 JGroup jGroup = groups[i];
3412 ColourSchemeI cs = null;
3413 if (jGroup.getColour() != null)
3415 if (jGroup.getColour().startsWith("ucs"))
3417 cs = getUserColourScheme(jms, jGroup.getColour());
3419 else if (jGroup.getColour().equals("AnnotationColourGradient")
3420 && jGroup.getAnnotationColours() != null)
3422 addAnnotSchemeGroup = true;
3426 cs = ColourSchemeProperty.getColourScheme(al,
3427 jGroup.getColour());
3430 int pidThreshold = jGroup.getPidThreshold();
3432 Vector<SequenceI> seqs = new Vector<>();
3434 for (int s = 0; s < jGroup.getSeqCount(); s++)
3436 String seqId = jGroup.getSeq(s) + "";
3437 SequenceI ts = seqRefIds.get(seqId);
3441 seqs.addElement(ts);
3445 if (seqs.size() < 1)
3450 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3451 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3452 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3453 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3454 sg.getGroupColourScheme()
3455 .setConservationInc(jGroup.getConsThreshold());
3456 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3458 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3459 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3460 sg.setShowNonconserved(
3461 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3463 sg.thresholdTextColour = jGroup.getTextColThreshold();
3464 if (jGroup.hasShowConsensusHistogram())
3466 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3469 if (jGroup.hasShowSequenceLogo())
3471 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3473 if (jGroup.hasNormaliseSequenceLogo())
3475 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3477 if (jGroup.hasIgnoreGapsinConsensus())
3479 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3481 if (jGroup.getConsThreshold() != 0)
3483 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3486 c.verdict(false, 25);
3487 sg.cs.setConservation(c);
3490 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3492 // re-instate unique group/annotation row reference
3493 List<AlignmentAnnotation> jaal = groupAnnotRefs
3494 .get(jGroup.getId());
3497 for (AlignmentAnnotation jaa : jaal)
3500 if (jaa.autoCalculated)
3502 // match up and try to set group autocalc alignment row for this
3504 if (jaa.label.startsWith("Consensus for "))
3506 sg.setConsensus(jaa);
3508 // match up and try to set group autocalc alignment row for this
3510 if (jaa.label.startsWith("Conservation for "))
3512 sg.setConservationRow(jaa);
3519 if (addAnnotSchemeGroup)
3521 // reconstruct the annotation colourscheme
3522 sg.setColourScheme(constructAnnotationColour(
3523 jGroup.getAnnotationColours(), null, al, jms, false));
3529 // only dataset in this model, so just return.
3532 // ///////////////////////////////
3535 // If we just load in the same jar file again, the sequenceSetId
3536 // will be the same, and we end up with multiple references
3537 // to the same sequenceSet. We must modify this id on load
3538 // so that each load of the file gives a unique id
3539 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3540 String viewId = (view.getId() == null ? null
3541 : view.getId() + uniqueSetSuffix);
3542 AlignFrame af = null;
3543 AlignViewport av = null;
3544 // now check to see if we really need to create a new viewport.
3545 if (multipleView && viewportsAdded.size() == 0)
3547 // We recovered an alignment for which a viewport already exists.
3548 // TODO: fix up any settings necessary for overlaying stored state onto
3549 // state recovered from another document. (may not be necessary).
3550 // we may need a binding from a viewport in memory to one recovered from
3552 // and then recover its containing af to allow the settings to be applied.
3553 // TODO: fix for vamsas demo
3555 "About to recover a viewport for existing alignment: Sequence set ID is "
3557 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3558 if (seqsetobj != null)
3560 if (seqsetobj instanceof String)
3562 uniqueSeqSetId = (String) seqsetobj;
3564 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3570 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3576 * indicate that annotation colours are applied across all groups (pre
3577 * Jalview 2.8.1 behaviour)
3579 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3580 object.getVersion());
3582 AlignmentPanel ap = null;
3583 boolean isnewview = true;
3586 // Check to see if this alignment already has a view id == viewId
3587 jalview.gui.AlignmentPanel views[] = Desktop
3588 .getAlignmentPanels(uniqueSeqSetId);
3589 if (views != null && views.length > 0)
3591 for (int v = 0; v < views.length; v++)
3593 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3595 // recover the existing alignpanel, alignframe, viewport
3596 af = views[v].alignFrame;
3599 // TODO: could even skip resetting view settings if we don't want to
3600 // change the local settings from other jalview processes
3609 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3610 uniqueSeqSetId, viewId, autoAlan);
3616 * Load any trees, PDB structures and viewers
3618 * Not done if flag is false (when this method is used for New View)
3620 if (loadTreesAndStructures)
3622 loadTrees(jms, view, af, av, ap);
3623 loadPDBStructures(jprovider, jseqs, af, ap);
3624 loadRnaViewers(jprovider, jseqs, ap);
3626 // and finally return.
3631 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3632 * panel is restored from separate jar entries, two (gapped and trimmed) per
3633 * sequence and secondary structure.
3635 * Currently each viewer shows just one sequence and structure (gapped and
3636 * trimmed), however this method is designed to support multiple sequences or
3637 * structures in viewers if wanted in future.
3643 private void loadRnaViewers(jarInputStreamProvider jprovider,
3644 JSeq[] jseqs, AlignmentPanel ap)
3647 * scan the sequences for references to viewers; create each one the first
3648 * time it is referenced, add Rna models to existing viewers
3650 for (JSeq jseq : jseqs)
3652 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3654 RnaViewer viewer = jseq.getRnaViewer(i);
3655 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3658 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3660 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3661 SequenceI seq = seqRefIds.get(jseq.getId());
3662 AlignmentAnnotation ann = this.annotationIds
3663 .get(ss.getAnnotationId());
3666 * add the structure to the Varna display (with session state copied
3667 * from the jar to a temporary file)
3669 boolean gapped = ss.isGapped();
3670 String rnaTitle = ss.getTitle();
3671 String sessionState = ss.getViewerState();
3672 String tempStateFile = copyJarEntry(jprovider, sessionState,
3674 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3675 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3677 appVarna.setInitialSelection(viewer.getSelectedRna());
3683 * Locate and return an already instantiated matching AppVarna, or create one
3687 * @param viewIdSuffix
3691 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3692 String viewIdSuffix, AlignmentPanel ap)
3695 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3696 * if load is repeated
3698 String postLoadId = viewer.getViewId() + viewIdSuffix;
3699 for (JInternalFrame frame : getAllFrames())
3701 if (frame instanceof AppVarna)
3703 AppVarna varna = (AppVarna) frame;
3704 if (postLoadId.equals(varna.getViewId()))
3706 // this viewer is already instantiated
3707 // could in future here add ap as another 'parent' of the
3708 // AppVarna window; currently just 1-to-many
3715 * viewer not found - make it
3717 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3718 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3719 viewer.getHeight(), viewer.getDividerLocation());
3720 AppVarna varna = new AppVarna(model, ap);
3726 * Load any saved trees
3734 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3735 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3737 // TODO result of automated refactoring - are all these parameters needed?
3740 for (int t = 0; t < jms.getTreeCount(); t++)
3743 Tree tree = jms.getTree(t);
3745 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3748 tp = af.showNewickTree(
3749 new jalview.io.NewickFile(tree.getNewick()),
3750 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3751 tree.getXpos(), tree.getYpos());
3752 if (tree.getId() != null)
3754 // perhaps bind the tree id to something ?
3759 // update local tree attributes ?
3760 // TODO: should check if tp has been manipulated by user - if so its
3761 // settings shouldn't be modified
3762 tp.setTitle(tree.getTitle());
3763 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3764 tree.getWidth(), tree.getHeight()));
3765 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3768 tp.treeCanvas.av = av; // af.viewport;
3769 tp.treeCanvas.ap = ap; // af.alignPanel;
3774 warn("There was a problem recovering stored Newick tree: \n"
3775 + tree.getNewick());
3779 tp.fitToWindow.setState(tree.getFitToWindow());
3780 tp.fitToWindow_actionPerformed(null);
3782 if (tree.getFontName() != null)
3784 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3785 tree.getFontStyle(), tree.getFontSize()));
3789 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3790 view.getFontStyle(), tree.getFontSize()));
3793 tp.showPlaceholders(tree.getMarkUnlinked());
3794 tp.showBootstrap(tree.getShowBootstrap());
3795 tp.showDistances(tree.getShowDistances());
3797 tp.treeCanvas.threshold = tree.getThreshold();
3799 if (tree.getCurrentTree())
3801 af.viewport.setCurrentTree(tp.getTree());
3805 } catch (Exception ex)
3807 ex.printStackTrace();
3812 * Load and link any saved structure viewers.
3819 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3820 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3823 * Run through all PDB ids on the alignment, and collect mappings between
3824 * distinct view ids and all sequences referring to that view.
3826 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3828 for (int i = 0; i < jseqs.length; i++)
3830 if (jseqs[i].getPdbidsCount() > 0)
3832 Pdbids[] ids = jseqs[i].getPdbids();
3833 for (int p = 0; p < ids.length; p++)
3835 final int structureStateCount = ids[p].getStructureStateCount();
3836 for (int s = 0; s < structureStateCount; s++)
3838 // check to see if we haven't already created this structure view
3839 final StructureState structureState = ids[p]
3840 .getStructureState(s);
3841 String sviewid = (structureState.getViewId() == null) ? null
3842 : structureState.getViewId() + uniqueSetSuffix;
3843 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3844 // Originally : ids[p].getFile()
3845 // : TODO: verify external PDB file recovery still works in normal
3846 // jalview project load
3847 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3849 jpdb.setId(ids[p].getId());
3851 int x = structureState.getXpos();
3852 int y = structureState.getYpos();
3853 int width = structureState.getWidth();
3854 int height = structureState.getHeight();
3856 // Probably don't need to do this anymore...
3857 // Desktop.desktop.getComponentAt(x, y);
3858 // TODO: NOW: check that this recovers the PDB file correctly.
3859 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3861 jalview.datamodel.SequenceI seq = seqRefIds
3862 .get(jseqs[i].getId() + "");
3863 if (sviewid == null)
3865 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3868 if (!structureViewers.containsKey(sviewid))
3870 structureViewers.put(sviewid,
3871 new StructureViewerModel(x, y, width, height, false,
3872 false, true, structureState.getViewId(),
3873 structureState.getType()));
3874 // Legacy pre-2.7 conversion JAL-823 :
3875 // do not assume any view has to be linked for colour by
3879 // assemble String[] { pdb files }, String[] { id for each
3880 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3881 // seqs_file 2}, boolean[] {
3882 // linkAlignPanel,superposeWithAlignpanel}} from hash
3883 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3884 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3885 | (structureState.hasAlignwithAlignPanel()
3886 ? structureState.getAlignwithAlignPanel()
3890 * Default colour by linked panel to false if not specified (e.g.
3891 * for pre-2.7 projects)
3893 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3894 colourWithAlignPanel |= (structureState
3895 .hasColourwithAlignPanel()
3896 ? structureState.getColourwithAlignPanel()
3898 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3901 * Default colour by viewer to true if not specified (e.g. for
3904 boolean colourByViewer = jmoldat.isColourByViewer();
3905 colourByViewer &= structureState.hasColourByJmol()
3906 ? structureState.getColourByJmol()
3908 jmoldat.setColourByViewer(colourByViewer);
3910 if (jmoldat.getStateData().length() < structureState
3911 .getContent().length())
3914 jmoldat.setStateData(structureState.getContent());
3917 if (ids[p].getFile() != null)
3919 File mapkey = new File(ids[p].getFile());
3920 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3921 if (seqstrmaps == null)
3923 jmoldat.getFileData().put(mapkey,
3924 seqstrmaps = jmoldat.new StructureData(pdbFile,
3927 if (!seqstrmaps.getSeqList().contains(seq))
3929 seqstrmaps.getSeqList().add(seq);
3935 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");
3942 // Instantiate the associated structure views
3943 for (Entry<String, StructureViewerModel> entry : structureViewers
3948 createOrLinkStructureViewer(entry, af, ap, jprovider);
3949 } catch (Exception e)
3952 "Error loading structure viewer: " + e.getMessage());
3953 // failed - try the next one
3965 protected void createOrLinkStructureViewer(
3966 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3967 AlignmentPanel ap, jarInputStreamProvider jprovider)
3969 final StructureViewerModel stateData = viewerData.getValue();
3972 * Search for any viewer windows already open from other alignment views
3973 * that exactly match the stored structure state
3975 StructureViewerBase comp = findMatchingViewer(viewerData);
3979 linkStructureViewer(ap, comp, stateData);
3984 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3985 * "viewer_"+stateData.viewId
3987 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
3989 createChimeraViewer(viewerData, af, jprovider);
3994 * else Jmol (if pre-2.9, stateData contains JMOL state string)
3996 createJmolViewer(viewerData, af, jprovider);
4001 * Create a new Chimera viewer.
4007 protected void createChimeraViewer(
4008 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4009 jarInputStreamProvider jprovider)
4011 StructureViewerModel data = viewerData.getValue();
4012 String chimeraSessionFile = data.getStateData();
4015 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4017 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4018 * 'uniquified' sviewid used to reconstruct the viewer here
4020 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4021 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4024 Set<Entry<File, StructureData>> fileData = data.getFileData()
4026 List<PDBEntry> pdbs = new ArrayList<>();
4027 List<SequenceI[]> allseqs = new ArrayList<>();
4028 for (Entry<File, StructureData> pdb : fileData)
4030 String filePath = pdb.getValue().getFilePath();
4031 String pdbId = pdb.getValue().getPdbId();
4032 // pdbs.add(new PDBEntry(filePath, pdbId));
4033 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4034 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4035 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4039 boolean colourByChimera = data.isColourByViewer();
4040 boolean colourBySequence = data.isColourWithAlignPanel();
4042 // TODO use StructureViewer as a factory here, see JAL-1761
4043 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4044 final SequenceI[][] seqsArray = allseqs
4045 .toArray(new SequenceI[allseqs.size()][]);
4046 String newViewId = viewerData.getKey();
4048 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4049 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4050 colourBySequence, newViewId);
4051 cvf.setSize(data.getWidth(), data.getHeight());
4052 cvf.setLocation(data.getX(), data.getY());
4056 * Create a new Jmol window. First parse the Jmol state to translate filenames
4057 * loaded into the view, and record the order in which files are shown in the
4058 * Jmol view, so we can add the sequence mappings in same order.
4064 protected void createJmolViewer(
4065 final Entry<String, StructureViewerModel> viewerData,
4066 AlignFrame af, jarInputStreamProvider jprovider)
4068 final StructureViewerModel svattrib = viewerData.getValue();
4069 String state = svattrib.getStateData();
4072 * Pre-2.9: state element value is the Jmol state string
4074 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4077 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4079 state = readJarEntry(jprovider,
4080 getViewerJarEntryName(svattrib.getViewId()));
4083 List<String> pdbfilenames = new ArrayList<>();
4084 List<SequenceI[]> seqmaps = new ArrayList<>();
4085 List<String> pdbids = new ArrayList<>();
4086 StringBuilder newFileLoc = new StringBuilder(64);
4087 int cp = 0, ncp, ecp;
4088 Map<File, StructureData> oldFiles = svattrib.getFileData();
4089 while ((ncp = state.indexOf("load ", cp)) > -1)
4093 // look for next filename in load statement
4094 newFileLoc.append(state.substring(cp,
4095 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4096 String oldfilenam = state.substring(ncp,
4097 ecp = state.indexOf("\"", ncp));
4098 // recover the new mapping data for this old filename
4099 // have to normalize filename - since Jmol and jalview do
4101 // translation differently.
4102 StructureData filedat = oldFiles.get(new File(oldfilenam));
4103 if (filedat == null)
4105 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4106 filedat = oldFiles.get(new File(reformatedOldFilename));
4108 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4109 pdbfilenames.add(filedat.getFilePath());
4110 pdbids.add(filedat.getPdbId());
4111 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4112 newFileLoc.append("\"");
4113 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4114 // look for next file statement.
4115 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4119 // just append rest of state
4120 newFileLoc.append(state.substring(cp));
4124 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4125 newFileLoc = new StringBuilder(state);
4126 newFileLoc.append("; load append ");
4127 for (File id : oldFiles.keySet())
4129 // add this and any other pdb files that should be present in
4131 StructureData filedat = oldFiles.get(id);
4132 newFileLoc.append(filedat.getFilePath());
4133 pdbfilenames.add(filedat.getFilePath());
4134 pdbids.add(filedat.getPdbId());
4135 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4136 newFileLoc.append(" \"");
4137 newFileLoc.append(filedat.getFilePath());
4138 newFileLoc.append("\"");
4141 newFileLoc.append(";");
4144 if (newFileLoc.length() == 0)
4148 int histbug = newFileLoc.indexOf("history = ");
4152 * change "history = [true|false];" to "history = [1|0];"
4155 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4156 String val = (diff == -1) ? null
4157 : newFileLoc.substring(histbug, diff);
4158 if (val != null && val.length() >= 4)
4160 if (val.contains("e")) // eh? what can it be?
4162 if (val.trim().equals("true"))
4170 newFileLoc.replace(histbug, diff, val);
4175 final String[] pdbf = pdbfilenames
4176 .toArray(new String[pdbfilenames.size()]);
4177 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4178 final SequenceI[][] sq = seqmaps
4179 .toArray(new SequenceI[seqmaps.size()][]);
4180 final String fileloc = newFileLoc.toString();
4181 final String sviewid = viewerData.getKey();
4182 final AlignFrame alf = af;
4183 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4184 svattrib.getWidth(), svattrib.getHeight());
4187 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4192 JalviewStructureDisplayI sview = null;
4195 sview = new StructureViewer(
4196 alf.alignPanel.getStructureSelectionManager())
4197 .createView(StructureViewer.ViewerType.JMOL,
4198 pdbf, id, sq, alf.alignPanel, svattrib,
4199 fileloc, rect, sviewid);
4200 addNewStructureViewer(sview);
4201 } catch (OutOfMemoryError ex)
4203 new OOMWarning("restoring structure view for PDB id " + id,
4204 (OutOfMemoryError) ex.getCause());
4205 if (sview != null && sview.isVisible())
4207 sview.closeViewer(false);
4208 sview.setVisible(false);
4214 } catch (InvocationTargetException ex)
4216 warn("Unexpected error when opening Jmol view.", ex);
4218 } catch (InterruptedException e)
4220 // e.printStackTrace();
4226 * Generates a name for the entry in the project jar file to hold state
4227 * information for a structure viewer
4232 protected String getViewerJarEntryName(String viewId)
4234 return VIEWER_PREFIX + viewId;
4238 * Returns any open frame that matches given structure viewer data. The match
4239 * is based on the unique viewId, or (for older project versions) the frame's
4245 protected StructureViewerBase findMatchingViewer(
4246 Entry<String, StructureViewerModel> viewerData)
4248 final String sviewid = viewerData.getKey();
4249 final StructureViewerModel svattrib = viewerData.getValue();
4250 StructureViewerBase comp = null;
4251 JInternalFrame[] frames = getAllFrames();
4252 for (JInternalFrame frame : frames)
4254 if (frame instanceof StructureViewerBase)
4257 * Post jalview 2.4 schema includes structure view id
4259 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4262 comp = (StructureViewerBase) frame;
4263 break; // break added in 2.9
4266 * Otherwise test for matching position and size of viewer frame
4268 else if (frame.getX() == svattrib.getX()
4269 && frame.getY() == svattrib.getY()
4270 && frame.getHeight() == svattrib.getHeight()
4271 && frame.getWidth() == svattrib.getWidth())
4273 comp = (StructureViewerBase) frame;
4274 // no break in faint hope of an exact match on viewId
4282 * Link an AlignmentPanel to an existing structure viewer.
4287 * @param useinViewerSuperpos
4288 * @param usetoColourbyseq
4289 * @param viewerColouring
4291 protected void linkStructureViewer(AlignmentPanel ap,
4292 StructureViewerBase viewer, StructureViewerModel stateData)
4294 // NOTE: if the jalview project is part of a shared session then
4295 // view synchronization should/could be done here.
4297 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4298 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4299 final boolean viewerColouring = stateData.isColourByViewer();
4300 Map<File, StructureData> oldFiles = stateData.getFileData();
4303 * Add mapping for sequences in this view to an already open viewer
4305 final AAStructureBindingModel binding = viewer.getBinding();
4306 for (File id : oldFiles.keySet())
4308 // add this and any other pdb files that should be present in the
4310 StructureData filedat = oldFiles.get(id);
4311 String pdbFile = filedat.getFilePath();
4312 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4313 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4315 binding.addSequenceForStructFile(pdbFile, seq);
4317 // and add the AlignmentPanel's reference to the view panel
4318 viewer.addAlignmentPanel(ap);
4319 if (useinViewerSuperpos)
4321 viewer.useAlignmentPanelForSuperposition(ap);
4325 viewer.excludeAlignmentPanelForSuperposition(ap);
4327 if (usetoColourbyseq)
4329 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4333 viewer.excludeAlignmentPanelForColourbyseq(ap);
4338 * Get all frames within the Desktop.
4342 protected JInternalFrame[] getAllFrames()
4344 JInternalFrame[] frames = null;
4345 // TODO is this necessary - is it safe - risk of hanging?
4350 frames = Desktop.desktop.getAllFrames();
4351 } catch (ArrayIndexOutOfBoundsException e)
4353 // occasional No such child exceptions are thrown here...
4357 } catch (InterruptedException f)
4361 } while (frames == null);
4366 * Answers true if 'version' is equal to or later than 'supported', where each
4367 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4368 * changes. Development and test values for 'version' are leniently treated
4372 * - minimum version we are comparing against
4374 * - version of data being processsed
4377 public static boolean isVersionStringLaterThan(String supported,
4380 if (supported == null || version == null
4381 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4382 || version.equalsIgnoreCase("Test")
4383 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4385 System.err.println("Assuming project file with "
4386 + (version == null ? "null" : version)
4387 + " is compatible with Jalview version " + supported);
4392 return StringUtils.compareVersions(version, supported, "b") >= 0;
4396 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4398 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4400 if (newStructureViewers != null)
4402 sview.getBinding().setFinishedLoadingFromArchive(false);
4403 newStructureViewers.add(sview);
4407 protected void setLoadingFinishedForNewStructureViewers()
4409 if (newStructureViewers != null)
4411 for (JalviewStructureDisplayI sview : newStructureViewers)
4413 sview.getBinding().setFinishedLoadingFromArchive(true);
4415 newStructureViewers.clear();
4416 newStructureViewers = null;
4420 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4421 List<SequenceI> hiddenSeqs, AlignmentI al,
4422 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4423 String viewId, List<JvAnnotRow> autoAlan)
4425 AlignFrame af = null;
4426 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4427 uniqueSeqSetId, viewId);
4429 af.setFileName(file, FileFormat.Jalview);
4431 for (int i = 0; i < JSEQ.length; i++)
4433 af.viewport.setSequenceColour(
4434 af.viewport.getAlignment().getSequenceAt(i),
4435 new java.awt.Color(JSEQ[i].getColour()));
4440 af.getViewport().setColourByReferenceSeq(true);
4441 af.getViewport().setDisplayReferenceSeq(true);
4444 af.viewport.setGatherViewsHere(view.getGatheredViews());
4446 if (view.getSequenceSetId() != null)
4448 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4450 af.viewport.setSequenceSetId(uniqueSeqSetId);
4453 // propagate shared settings to this new view
4454 af.viewport.setHistoryList(av.getHistoryList());
4455 af.viewport.setRedoList(av.getRedoList());
4459 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4461 // TODO: check if this method can be called repeatedly without
4462 // side-effects if alignpanel already registered.
4463 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4465 // apply Hidden regions to view.
4466 if (hiddenSeqs != null)
4468 for (int s = 0; s < JSEQ.length; s++)
4470 SequenceGroup hidden = new SequenceGroup();
4471 boolean isRepresentative = false;
4472 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4474 isRepresentative = true;
4475 SequenceI sequenceToHide = al
4476 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4477 hidden.addSequence(sequenceToHide, false);
4478 // remove from hiddenSeqs list so we don't try to hide it twice
4479 hiddenSeqs.remove(sequenceToHide);
4481 if (isRepresentative)
4483 SequenceI representativeSequence = al.getSequenceAt(s);
4484 hidden.addSequence(representativeSequence, false);
4485 af.viewport.hideRepSequences(representativeSequence, hidden);
4489 SequenceI[] hseqs = hiddenSeqs
4490 .toArray(new SequenceI[hiddenSeqs.size()]);
4491 af.viewport.hideSequence(hseqs);
4494 // recover view properties and display parameters
4496 af.viewport.setShowAnnotation(view.getShowAnnotation());
4497 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4498 af.viewport.setThreshold(view.getPidThreshold());
4500 af.viewport.setColourText(view.getShowColourText());
4502 af.viewport.setConservationSelected(view.getConservationSelected());
4503 af.viewport.setIncrement(view.getConsThreshold());
4504 af.viewport.setShowJVSuffix(view.getShowFullId());
4505 af.viewport.setRightAlignIds(view.getRightAlignIds());
4506 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4507 view.getFontStyle(), view.getFontSize()), true);
4508 ViewStyleI vs = af.viewport.getViewStyle();
4509 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4510 af.viewport.setViewStyle(vs);
4511 // TODO: allow custom charWidth/Heights to be restored by updating them
4512 // after setting font - which means set above to false
4513 af.viewport.setRenderGaps(view.getRenderGaps());
4514 af.viewport.setWrapAlignment(view.getWrapAlignment());
4515 af.viewport.setShowAnnotation(view.getShowAnnotation());
4517 af.viewport.setShowBoxes(view.getShowBoxes());
4519 af.viewport.setShowText(view.getShowText());
4521 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4522 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4523 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4524 af.viewport.setShowUnconserved(
4525 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4526 af.viewport.getRanges().setStartRes(view.getStartRes());
4528 if (view.getViewName() != null)
4530 af.viewport.viewName = view.getViewName();
4531 af.setInitialTabVisible();
4533 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4535 // startSeq set in af.alignPanel.updateLayout below
4536 af.alignPanel.updateLayout();
4537 ColourSchemeI cs = null;
4538 // apply colourschemes
4539 if (view.getBgColour() != null)
4541 if (view.getBgColour().startsWith("ucs"))
4543 cs = getUserColourScheme(jms, view.getBgColour());
4545 else if (view.getBgColour().startsWith("Annotation"))
4547 AnnotationColours viewAnnColour = view.getAnnotationColours();
4548 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4555 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4559 af.viewport.setGlobalColourScheme(cs);
4560 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4561 view.getIgnoreGapsinConsensus());
4562 af.viewport.getResidueShading()
4563 .setConsensus(af.viewport.getSequenceConsensusHash());
4564 af.viewport.setColourAppliesToAllGroups(false);
4566 if (view.getConservationSelected() && cs != null)
4568 af.viewport.getResidueShading()
4569 .setConservationInc(view.getConsThreshold());
4572 af.changeColour(cs);
4574 af.viewport.setColourAppliesToAllGroups(true);
4576 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4578 if (view.hasCentreColumnLabels())
4580 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4582 if (view.hasIgnoreGapsinConsensus())
4584 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4587 if (view.hasFollowHighlight())
4589 af.viewport.setFollowHighlight(view.getFollowHighlight());
4591 if (view.hasFollowSelection())
4593 af.viewport.followSelection = view.getFollowSelection();
4595 if (view.hasShowConsensusHistogram())
4598 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4602 af.viewport.setShowConsensusHistogram(true);
4604 if (view.hasShowSequenceLogo())
4606 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4610 af.viewport.setShowSequenceLogo(false);
4612 if (view.hasNormaliseSequenceLogo())
4614 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4616 if (view.hasShowDbRefTooltip())
4618 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4620 if (view.hasShowNPfeatureTooltip())
4622 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4624 if (view.hasShowGroupConsensus())
4626 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4630 af.viewport.setShowGroupConsensus(false);
4632 if (view.hasShowGroupConservation())
4634 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4638 af.viewport.setShowGroupConservation(false);
4641 // recover feature settings
4642 if (jms.getFeatureSettings() != null)
4644 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4645 .getFeatureRenderer();
4646 FeaturesDisplayed fdi;
4647 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4648 String[] renderOrder = new String[jms.getFeatureSettings()
4649 .getSettingCount()];
4650 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4651 Map<String, Float> featureOrder = new Hashtable<>();
4653 for (int fs = 0; fs < jms.getFeatureSettings()
4654 .getSettingCount(); fs++)
4656 Setting setting = jms.getFeatureSettings().getSetting(fs);
4657 String featureType = setting.getType();
4660 * restore feature filters (if any)
4662 MatcherSet filters = setting.getMatcherSet();
4663 if (filters != null)
4665 FeatureMatcherSetI filter = Jalview2XML
4666 .unmarshalFilter(featureType, filters);
4667 if (!filter.isEmpty())
4669 fr.setFeatureFilter(featureType, filter);
4674 * restore feature colour scheme
4676 Color maxColour = new Color(setting.getColour());
4677 if (setting.hasMincolour())
4680 * minColour is always set unless a simple colour
4681 * (including for colour by label though it doesn't use it)
4683 Color minColour = new Color(setting.getMincolour());
4684 Color noValueColour = minColour;
4685 NoValueColour noColour = setting.getNoValueColour();
4686 if (noColour == NoValueColour.NONE)
4688 noValueColour = null;
4690 else if (noColour == NoValueColour.MAX)
4692 noValueColour = maxColour;
4694 float min = setting.hasMin() ? setting.getMin() : 0f;
4695 float max = setting.hasMin() ? setting.getMax() : 1f;
4696 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4697 noValueColour, min, max);
4698 if (setting.getAttributeNameCount() > 0)
4700 gc.setAttributeName(setting.getAttributeName());
4702 if (setting.hasThreshold())
4704 gc.setThreshold(setting.getThreshold());
4705 int threshstate = setting.getThreshstate();
4706 // -1 = None, 0 = Below, 1 = Above threshold
4707 if (threshstate == 0)
4709 gc.setBelowThreshold(true);
4711 else if (threshstate == 1)
4713 gc.setAboveThreshold(true);
4716 gc.setAutoScaled(true); // default
4717 if (setting.hasAutoScale())
4719 gc.setAutoScaled(setting.getAutoScale());
4721 if (setting.hasColourByLabel())
4723 gc.setColourByLabel(setting.getColourByLabel());
4725 // and put in the feature colour table.
4726 featureColours.put(featureType, gc);
4730 featureColours.put(featureType,
4731 new FeatureColour(maxColour));
4733 renderOrder[fs] = featureType;
4734 if (setting.hasOrder())
4736 featureOrder.put(featureType, setting.getOrder());
4740 featureOrder.put(featureType, new Float(
4741 fs / jms.getFeatureSettings().getSettingCount()));
4743 if (setting.getDisplay())
4745 fdi.setVisible(featureType);
4748 Map<String, Boolean> fgtable = new Hashtable<>();
4749 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4751 Group grp = jms.getFeatureSettings().getGroup(gs);
4752 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4754 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4755 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4756 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4757 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4758 fgtable, featureColours, 1.0f, featureOrder);
4759 fr.transferSettings(frs);
4762 if (view.getHiddenColumnsCount() > 0)
4764 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4766 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4767 view.getHiddenColumns(c).getEnd() // +1
4771 if (view.getCalcIdParam() != null)
4773 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4775 if (calcIdParam != null)
4777 if (recoverCalcIdParam(calcIdParam, af.viewport))
4782 warn("Couldn't recover parameters for "
4783 + calcIdParam.getCalcId());
4788 af.setMenusFromViewport(af.viewport);
4789 af.setTitle(view.getTitle());
4790 // TODO: we don't need to do this if the viewport is aready visible.
4792 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4793 * has a 'cdna/protein complement' view, in which case save it in order to
4794 * populate a SplitFrame once all views have been read in.
4796 String complementaryViewId = view.getComplementId();
4797 if (complementaryViewId == null)
4799 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4801 // recompute any autoannotation
4802 af.alignPanel.updateAnnotation(false, true);
4803 reorderAutoannotation(af, al, autoAlan);
4804 af.alignPanel.alignmentChanged();
4808 splitFrameCandidates.put(view, af);
4814 * Reads saved data to restore Colour by Annotation settings
4816 * @param viewAnnColour
4820 * @param checkGroupAnnColour
4823 private ColourSchemeI constructAnnotationColour(
4824 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4825 JalviewModelSequence jms, boolean checkGroupAnnColour)
4827 boolean propagateAnnColour = false;
4828 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4829 if (checkGroupAnnColour && al.getGroups() != null
4830 && al.getGroups().size() > 0)
4832 // pre 2.8.1 behaviour
4833 // check to see if we should transfer annotation colours
4834 propagateAnnColour = true;
4835 for (SequenceGroup sg : al.getGroups())
4837 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4839 propagateAnnColour = false;
4845 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4847 String annotationId = viewAnnColour.getAnnotation();
4848 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4851 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4853 if (matchedAnnotation == null
4854 && annAlignment.getAlignmentAnnotation() != null)
4856 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4859 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4861 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4866 if (matchedAnnotation == null)
4868 System.err.println("Failed to match annotation colour scheme for "
4872 if (matchedAnnotation.getThreshold() == null)
4874 matchedAnnotation.setThreshold(new GraphLine(
4875 viewAnnColour.getThreshold(), "Threshold", Color.black));
4878 AnnotationColourGradient cs = null;
4879 if (viewAnnColour.getColourScheme().equals("None"))
4881 cs = new AnnotationColourGradient(matchedAnnotation,
4882 new Color(viewAnnColour.getMinColour()),
4883 new Color(viewAnnColour.getMaxColour()),
4884 viewAnnColour.getAboveThreshold());
4886 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4888 cs = new AnnotationColourGradient(matchedAnnotation,
4889 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4890 viewAnnColour.getAboveThreshold());
4894 cs = new AnnotationColourGradient(matchedAnnotation,
4895 ColourSchemeProperty.getColourScheme(al,
4896 viewAnnColour.getColourScheme()),
4897 viewAnnColour.getAboveThreshold());
4900 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4901 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4902 cs.setSeqAssociated(perSequenceOnly);
4903 cs.setPredefinedColours(useOriginalColours);
4905 if (propagateAnnColour && al.getGroups() != null)
4907 // Also use these settings for all the groups
4908 for (int g = 0; g < al.getGroups().size(); g++)
4910 SequenceGroup sg = al.getGroups().get(g);
4911 if (sg.getGroupColourScheme() == null)
4916 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4917 matchedAnnotation, sg.getColourScheme(),
4918 viewAnnColour.getAboveThreshold());
4919 sg.setColourScheme(groupScheme);
4920 groupScheme.setSeqAssociated(perSequenceOnly);
4921 groupScheme.setPredefinedColours(useOriginalColours);
4927 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4928 List<JvAnnotRow> autoAlan)
4930 // copy over visualization settings for autocalculated annotation in the
4932 if (al.getAlignmentAnnotation() != null)
4935 * Kludge for magic autoannotation names (see JAL-811)
4937 String[] magicNames = new String[] { "Consensus", "Quality",
4939 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4940 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4941 for (String nm : magicNames)
4943 visan.put(nm, nullAnnot);
4945 for (JvAnnotRow auan : autoAlan)
4947 visan.put(auan.template.label
4948 + (auan.template.getCalcId() == null ? ""
4949 : "\t" + auan.template.getCalcId()),
4952 int hSize = al.getAlignmentAnnotation().length;
4953 List<JvAnnotRow> reorder = new ArrayList<>();
4954 // work through any autoCalculated annotation already on the view
4955 // removing it if it should be placed in a different location on the
4956 // annotation panel.
4957 List<String> remains = new ArrayList<>(visan.keySet());
4958 for (int h = 0; h < hSize; h++)
4960 jalview.datamodel.AlignmentAnnotation jalan = al
4961 .getAlignmentAnnotation()[h];
4962 if (jalan.autoCalculated)
4965 JvAnnotRow valan = visan.get(k = jalan.label);
4966 if (jalan.getCalcId() != null)
4968 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4973 // delete the auto calculated row from the alignment
4974 al.deleteAnnotation(jalan, false);
4978 if (valan != nullAnnot)
4980 if (jalan != valan.template)
4982 // newly created autoannotation row instance
4983 // so keep a reference to the visible annotation row
4984 // and copy over all relevant attributes
4985 if (valan.template.graphHeight >= 0)
4988 jalan.graphHeight = valan.template.graphHeight;
4990 jalan.visible = valan.template.visible;
4992 reorder.add(new JvAnnotRow(valan.order, jalan));
4997 // Add any (possibly stale) autocalculated rows that were not appended to
4998 // the view during construction
4999 for (String other : remains)
5001 JvAnnotRow othera = visan.get(other);
5002 if (othera != nullAnnot && othera.template.getCalcId() != null
5003 && othera.template.getCalcId().length() > 0)
5005 reorder.add(othera);
5008 // now put the automatic annotation in its correct place
5009 int s = 0, srt[] = new int[reorder.size()];
5010 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5011 for (JvAnnotRow jvar : reorder)
5014 srt[s++] = jvar.order;
5017 jalview.util.QuickSort.sort(srt, rws);
5018 // and re-insert the annotation at its correct position
5019 for (JvAnnotRow jvar : rws)
5021 al.addAnnotation(jvar.template, jvar.order);
5023 af.alignPanel.adjustAnnotationHeight();
5027 Hashtable skipList = null;
5030 * TODO remove this method
5033 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5034 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5035 * throw new Error("Implementation Error. No skipList defined for this
5036 * Jalview2XML instance."); } return (AlignFrame)
5037 * skipList.get(view.getSequenceSetId()); }
5041 * Check if the Jalview view contained in object should be skipped or not.
5044 * @return true if view's sequenceSetId is a key in skipList
5046 private boolean skipViewport(JalviewModel object)
5048 if (skipList == null)
5053 if (skipList.containsKey(
5054 id = object.getJalviewModelSequence().getViewport()[0]
5055 .getSequenceSetId()))
5057 if (Cache.log != null && Cache.log.isDebugEnabled())
5059 Cache.log.debug("Skipping seuqence set id " + id);
5066 public void addToSkipList(AlignFrame af)
5068 if (skipList == null)
5070 skipList = new Hashtable();
5072 skipList.put(af.getViewport().getSequenceSetId(), af);
5075 public void clearSkipList()
5077 if (skipList != null)
5084 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5085 boolean ignoreUnrefed)
5087 jalview.datamodel.AlignmentI ds = getDatasetFor(
5088 vamsasSet.getDatasetId());
5089 Vector dseqs = null;
5092 // create a list of new dataset sequences
5093 dseqs = new Vector();
5095 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5097 Sequence vamsasSeq = vamsasSet.getSequence(i);
5098 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5100 // create a new dataset
5103 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5104 dseqs.copyInto(dsseqs);
5105 ds = new jalview.datamodel.Alignment(dsseqs);
5106 debug("Created new dataset " + vamsasSet.getDatasetId()
5107 + " for alignment " + System.identityHashCode(al));
5108 addDatasetRef(vamsasSet.getDatasetId(), ds);
5110 // set the dataset for the newly imported alignment.
5111 if (al.getDataset() == null && !ignoreUnrefed)
5120 * sequence definition to create/merge dataset sequence for
5124 * vector to add new dataset sequence to
5125 * @param ignoreUnrefed
5126 * - when true, don't create new sequences from vamsasSeq if it's id
5127 * doesn't already have an asssociated Jalview sequence.
5129 * - used to reorder the sequence in the alignment according to the
5130 * vamsasSeq array ordering, to preserve ordering of dataset
5132 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5133 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5135 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5137 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5138 boolean reorder = false;
5139 SequenceI dsq = null;
5140 if (sq != null && sq.getDatasetSequence() != null)
5142 dsq = sq.getDatasetSequence();
5148 if (sq == null && ignoreUnrefed)
5152 String sqid = vamsasSeq.getDsseqid();
5155 // need to create or add a new dataset sequence reference to this sequence
5158 dsq = seqRefIds.get(sqid);
5163 // make a new dataset sequence
5164 dsq = sq.createDatasetSequence();
5167 // make up a new dataset reference for this sequence
5168 sqid = seqHash(dsq);
5170 dsq.setVamsasId(uniqueSetSuffix + sqid);
5171 seqRefIds.put(sqid, dsq);
5176 dseqs.addElement(dsq);
5181 ds.addSequence(dsq);
5187 { // make this dataset sequence sq's dataset sequence
5188 sq.setDatasetSequence(dsq);
5189 // and update the current dataset alignment
5194 if (!dseqs.contains(dsq))
5201 if (ds.findIndex(dsq) < 0)
5203 ds.addSequence(dsq);
5210 // TODO: refactor this as a merge dataset sequence function
5211 // now check that sq (the dataset sequence) sequence really is the union of
5212 // all references to it
5213 // boolean pre = sq.getStart() < dsq.getStart();
5214 // boolean post = sq.getEnd() > dsq.getEnd();
5218 // StringBuffer sb = new StringBuffer();
5219 String newres = jalview.analysis.AlignSeq.extractGaps(
5220 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5221 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5222 && newres.length() > dsq.getLength())
5224 // Update with the longer sequence.
5228 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5229 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5230 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5231 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5233 dsq.setSequence(newres);
5235 // TODO: merges will never happen if we 'know' we have the real dataset
5236 // sequence - this should be detected when id==dssid
5238 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5239 // + (pre ? "prepended" : "") + " "
5240 // + (post ? "appended" : ""));
5245 // sequence refs are identical. We may need to update the existing dataset
5246 // alignment with this one, though.
5247 if (ds != null && dseqs == null)
5249 int opos = ds.findIndex(dsq);
5250 SequenceI tseq = null;
5251 if (opos != -1 && vseqpos != opos)
5253 // remove from old position
5254 ds.deleteSequence(dsq);
5256 if (vseqpos < ds.getHeight())
5258 if (vseqpos != opos)
5260 // save sequence at destination position
5261 tseq = ds.getSequenceAt(vseqpos);
5262 ds.replaceSequenceAt(vseqpos, dsq);
5263 ds.addSequence(tseq);
5268 ds.addSequence(dsq);
5275 * TODO use AlignmentI here and in related methods - needs
5276 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5278 Hashtable<String, AlignmentI> datasetIds = null;
5280 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5282 private AlignmentI getDatasetFor(String datasetId)
5284 if (datasetIds == null)
5286 datasetIds = new Hashtable<>();
5289 if (datasetIds.containsKey(datasetId))
5291 return datasetIds.get(datasetId);
5296 private void addDatasetRef(String datasetId, AlignmentI dataset)
5298 if (datasetIds == null)
5300 datasetIds = new Hashtable<>();
5302 datasetIds.put(datasetId, dataset);
5306 * make a new dataset ID for this jalview dataset alignment
5311 private String getDatasetIdRef(AlignmentI dataset)
5313 if (dataset.getDataset() != null)
5315 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5317 String datasetId = makeHashCode(dataset, null);
5318 if (datasetId == null)
5320 // make a new datasetId and record it
5321 if (dataset2Ids == null)
5323 dataset2Ids = new IdentityHashMap<>();
5327 datasetId = dataset2Ids.get(dataset);
5329 if (datasetId == null)
5331 datasetId = "ds" + dataset2Ids.size() + 1;
5332 dataset2Ids.put(dataset, datasetId);
5338 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5340 for (int d = 0; d < sequence.getDBRefCount(); d++)
5342 DBRef dr = sequence.getDBRef(d);
5343 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5344 sequence.getDBRef(d).getSource(),
5345 sequence.getDBRef(d).getVersion(),
5346 sequence.getDBRef(d).getAccessionId());
5347 if (dr.getMapping() != null)
5349 entry.setMap(addMapping(dr.getMapping()));
5351 datasetSequence.addDBRef(entry);
5355 private jalview.datamodel.Mapping addMapping(Mapping m)
5357 SequenceI dsto = null;
5358 // Mapping m = dr.getMapping();
5359 int fr[] = new int[m.getMapListFromCount() * 2];
5360 Enumeration f = m.enumerateMapListFrom();
5361 for (int _i = 0; f.hasMoreElements(); _i += 2)
5363 MapListFrom mf = (MapListFrom) f.nextElement();
5364 fr[_i] = mf.getStart();
5365 fr[_i + 1] = mf.getEnd();
5367 int fto[] = new int[m.getMapListToCount() * 2];
5368 f = m.enumerateMapListTo();
5369 for (int _i = 0; f.hasMoreElements(); _i += 2)
5371 MapListTo mf = (MapListTo) f.nextElement();
5372 fto[_i] = mf.getStart();
5373 fto[_i + 1] = mf.getEnd();
5375 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5376 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5377 if (m.getMappingChoice() != null)
5379 MappingChoice mc = m.getMappingChoice();
5380 if (mc.getDseqFor() != null)
5382 String dsfor = "" + mc.getDseqFor();
5383 if (seqRefIds.containsKey(dsfor))
5388 jmap.setTo(seqRefIds.get(dsfor));
5392 frefedSequence.add(newMappingRef(dsfor, jmap));
5398 * local sequence definition
5400 Sequence ms = mc.getSequence();
5401 SequenceI djs = null;
5402 String sqid = ms.getDsseqid();
5403 if (sqid != null && sqid.length() > 0)
5406 * recover dataset sequence
5408 djs = seqRefIds.get(sqid);
5413 "Warning - making up dataset sequence id for DbRef sequence map reference");
5414 sqid = ((Object) ms).toString(); // make up a new hascode for
5415 // undefined dataset sequence hash
5416 // (unlikely to happen)
5422 * make a new dataset sequence and add it to refIds hash
5424 djs = new jalview.datamodel.Sequence(ms.getName(),
5426 djs.setStart(jmap.getMap().getToLowest());
5427 djs.setEnd(jmap.getMap().getToHighest());
5428 djs.setVamsasId(uniqueSetSuffix + sqid);
5430 incompleteSeqs.put(sqid, djs);
5431 seqRefIds.put(sqid, djs);
5434 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5444 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5445 * view as XML (but not to file), and then reloading it
5450 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5453 JalviewModel jm = saveState(ap, null, null, null);
5455 uniqueSetSuffix = "";
5456 jm.getJalviewModelSequence().getViewport(0).setId(null);
5457 // we don't overwrite the view we just copied
5459 if (this.frefedSequence == null)
5461 frefedSequence = new Vector<>();
5464 viewportsAdded.clear();
5466 AlignFrame af = loadFromObject(jm, null, false, null);
5467 af.alignPanels.clear();
5468 af.closeMenuItem_actionPerformed(true);
5471 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5472 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5473 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5474 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5475 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5478 return af.alignPanel;
5481 private Hashtable jvids2vobj;
5483 private void warn(String msg)
5488 private void warn(String msg, Exception e)
5490 if (Cache.log != null)
5494 Cache.log.warn(msg, e);
5498 Cache.log.warn(msg);
5503 System.err.println("Warning: " + msg);
5506 e.printStackTrace();
5511 private void debug(String string)
5513 debug(string, null);
5516 private void debug(String msg, Exception e)
5518 if (Cache.log != null)
5522 Cache.log.debug(msg, e);
5526 Cache.log.debug(msg);
5531 System.err.println("Warning: " + msg);
5534 e.printStackTrace();
5540 * set the object to ID mapping tables used to write/recover objects and XML
5541 * ID strings for the jalview project. If external tables are provided then
5542 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5543 * object goes out of scope. - also populates the datasetIds hashtable with
5544 * alignment objects containing dataset sequences
5547 * Map from ID strings to jalview datamodel
5549 * Map from jalview datamodel to ID strings
5553 public void setObjectMappingTables(Hashtable vobj2jv,
5554 IdentityHashMap jv2vobj)
5556 this.jv2vobj = jv2vobj;
5557 this.vobj2jv = vobj2jv;
5558 Iterator ds = jv2vobj.keySet().iterator();
5560 while (ds.hasNext())
5562 Object jvobj = ds.next();
5563 id = jv2vobj.get(jvobj).toString();
5564 if (jvobj instanceof jalview.datamodel.Alignment)
5566 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5568 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5571 else if (jvobj instanceof jalview.datamodel.Sequence)
5573 // register sequence object so the XML parser can recover it.
5574 if (seqRefIds == null)
5576 seqRefIds = new HashMap<>();
5578 if (seqsToIds == null)
5580 seqsToIds = new IdentityHashMap<>();
5582 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5583 seqsToIds.put((SequenceI) jvobj, id);
5585 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5588 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5589 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5590 if (jvann.annotationId == null)
5592 jvann.annotationId = anid;
5594 if (!jvann.annotationId.equals(anid))
5596 // TODO verify that this is the correct behaviour
5597 this.warn("Overriding Annotation ID for " + anid
5598 + " from different id : " + jvann.annotationId);
5599 jvann.annotationId = anid;
5602 else if (jvobj instanceof String)
5604 if (jvids2vobj == null)
5606 jvids2vobj = new Hashtable();
5607 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5612 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5618 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5619 * objects created from the project archive. If string is null (default for
5620 * construction) then suffix will be set automatically.
5624 public void setUniqueSetSuffix(String string)
5626 uniqueSetSuffix = string;
5631 * uses skipList2 as the skipList for skipping views on sequence sets
5632 * associated with keys in the skipList
5636 public void setSkipList(Hashtable skipList2)
5638 skipList = skipList2;
5642 * Reads the jar entry of given name and returns its contents, or null if the
5643 * entry is not found.
5646 * @param jarEntryName
5649 protected String readJarEntry(jarInputStreamProvider jprovider,
5650 String jarEntryName)
5652 String result = null;
5653 BufferedReader in = null;
5658 * Reopen the jar input stream and traverse its entries to find a matching
5661 JarInputStream jin = jprovider.getJarInputStream();
5662 JarEntry entry = null;
5665 entry = jin.getNextJarEntry();
5666 } while (entry != null && !entry.getName().equals(jarEntryName));
5670 StringBuilder out = new StringBuilder(256);
5671 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5674 while ((data = in.readLine()) != null)
5678 result = out.toString();
5682 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5684 } catch (Exception ex)
5686 ex.printStackTrace();
5694 } catch (IOException e)
5705 * Returns an incrementing counter (0, 1, 2...)
5709 private synchronized int nextCounter()
5715 * Populates an XML model of the feature colour scheme for one feature type
5717 * @param featureType
5721 protected static jalview.schemabinding.version2.Colour marshalColour(
5722 String featureType, FeatureColourI fcol)
5724 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5725 if (fcol.isSimpleColour())
5727 col.setRGB(Format.getHexString(fcol.getColour()));
5731 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5732 col.setMin(fcol.getMin());
5733 col.setMax(fcol.getMax());
5734 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5735 col.setAutoScale(fcol.isAutoScaled());
5736 col.setThreshold(fcol.getThreshold());
5737 col.setColourByLabel(fcol.isColourByLabel());
5738 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5739 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5740 : ColourThreshTypeType.NONE));
5741 if (fcol.isColourByAttribute())
5743 col.setAttributeName(fcol.getAttributeName());
5745 Color noColour = fcol.getNoColour();
5746 if (noColour == null)
5748 col.setNoValueColour(NoValueColour.NONE);
5750 else if (noColour == fcol.getMaxColour())
5752 col.setNoValueColour(NoValueColour.MAX);
5756 col.setNoValueColour(NoValueColour.MIN);
5759 col.setName(featureType);
5764 * Populates an XML model of the feature filter(s) for one feature type
5766 * @param firstMatcher
5767 * the first (or only) match condition)
5769 * remaining match conditions (if any)
5771 * if true, conditions are and-ed, else or-ed
5773 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5774 Iterator<FeatureMatcherI> filters, boolean and)
5776 MatcherSet result = new MatcherSet();
5778 if (filters.hasNext())
5783 CompoundMatcher compound = new CompoundMatcher();
5784 compound.setAnd(and);
5785 MatcherSet matcher1 = marshalFilter(firstMatcher,
5786 Collections.emptyIterator(), and);
5787 compound.addMatcherSet(matcher1);
5788 FeatureMatcherI nextMatcher = filters.next();
5789 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5790 compound.addMatcherSet(matcher2);
5791 result.setCompoundMatcher(compound);
5796 * single condition matcher
5798 MatchCondition matcherModel = new MatchCondition();
5799 matcherModel.setCondition(
5800 firstMatcher.getMatcher().getCondition().getStableName());
5801 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5802 if (firstMatcher.isByAttribute())
5804 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5805 matcherModel.setAttributeName(firstMatcher.getAttribute());
5807 else if (firstMatcher.isByLabel())
5809 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5811 else if (firstMatcher.isByScore())
5813 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5815 result.setMatchCondition(matcherModel);
5822 * Loads one XML model of a feature filter to a Jalview object
5824 * @param featureType
5825 * @param matcherSetModel
5828 protected static FeatureMatcherSetI unmarshalFilter(
5829 String featureType, MatcherSet matcherSetModel)
5831 FeatureMatcherSetI result = new FeatureMatcherSet();
5834 unmarshalFilterConditions(result, matcherSetModel, true);
5835 } catch (IllegalStateException e)
5837 // mixing AND and OR conditions perhaps
5839 String.format("Error reading filter conditions for '%s': %s",
5840 featureType, e.getMessage()));
5841 // return as much as was parsed up to the error
5848 * Adds feature match conditions to matcherSet as unmarshalled from XML
5849 * (possibly recursively for compound conditions)
5852 * @param matcherSetModel
5854 * if true, multiple conditions are AND-ed, else they are OR-ed
5855 * @throws IllegalStateException
5856 * if AND and OR conditions are mixed
5858 protected static void unmarshalFilterConditions(
5859 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5862 MatchCondition mc = matcherSetModel.getMatchCondition();
5868 FeatureMatcherByType filterBy = mc.getBy();
5869 Condition cond = Condition.fromString(mc.getCondition());
5870 String pattern = mc.getValue();
5871 FeatureMatcherI matchCondition = null;
5872 if (filterBy == FeatureMatcherByType.BYLABEL)
5874 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5876 else if (filterBy == FeatureMatcherByType.BYSCORE)
5878 matchCondition = FeatureMatcher.byScore(cond, pattern);
5881 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5883 String[] attNames = mc.getAttributeName();
5884 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5889 * note this throws IllegalStateException if AND-ing to a
5890 * previously OR-ed compound condition, or vice versa
5894 matcherSet.and(matchCondition);
5898 matcherSet.or(matchCondition);
5904 * compound condition
5906 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5908 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5909 if (matchers.length == 2)
5911 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5912 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5916 System.err.println("Malformed compound filter condition");
5922 * Loads one XML model of a feature colour to a Jalview object
5924 * @param colourModel
5927 protected static FeatureColourI unmarshalColour(
5928 jalview.schemabinding.version2.Colour colourModel)
5930 FeatureColourI colour = null;
5932 if (colourModel.hasMax())
5934 Color mincol = null;
5935 Color maxcol = null;
5936 Color noValueColour = null;
5940 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5941 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5942 } catch (Exception e)
5944 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5947 NoValueColour noCol = colourModel.getNoValueColour();
5948 if (noCol == NoValueColour.MIN)
5950 noValueColour = mincol;
5952 else if (noCol == NoValueColour.MAX)
5954 noValueColour = maxcol;
5957 colour = new FeatureColour(mincol, maxcol, noValueColour,
5958 colourModel.getMin(),
5959 colourModel.getMax());
5960 String[] attributes = colourModel.getAttributeName();
5961 if (attributes != null && attributes.length > 0)
5963 colour.setAttributeName(attributes);
5965 if (colourModel.hasAutoScale())
5967 colour.setAutoScaled(colourModel.getAutoScale());
5969 if (colourModel.hasColourByLabel())
5971 colour.setColourByLabel(colourModel.getColourByLabel());
5973 if (colourModel.hasThreshold())
5975 colour.setThreshold(colourModel.getThreshold());
5977 ColourThreshTypeType ttyp = colourModel.getThreshType();
5980 if (ttyp == ColourThreshTypeType.ABOVE)
5982 colour.setAboveThreshold(true);
5984 else if (ttyp == ColourThreshTypeType.BELOW)
5986 colour.setBelowThreshold(true);
5992 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5993 colour = new FeatureColour(color);