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";
173 * prefix for recovering datasets for alignments with multiple views where
174 * non-existent dataset IDs were written for some views
176 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
178 // use this with nextCounter() to make unique names for entities
179 private int counter = 0;
182 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
183 * of sequence objects are created.
185 IdentityHashMap<SequenceI, String> seqsToIds = null;
188 * jalview XML Sequence ID to jalview sequence object reference (both dataset
189 * and alignment sequences. Populated as XML reps of sequence objects are
192 Map<String, SequenceI> seqRefIds = null;
194 Map<String, SequenceI> incompleteSeqs = null;
196 List<SeqFref> frefedSequence = null;
198 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
201 * Map of reconstructed AlignFrame objects that appear to have come from
202 * SplitFrame objects (have a dna/protein complement view).
204 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
207 * Map from displayed rna structure models to their saved session state jar
210 private Map<RnaModel, String> rnaSessions = new HashMap<>();
213 * create/return unique hash string for sq
216 * @return new or existing unique string for sq
218 String seqHash(SequenceI sq)
220 if (seqsToIds == null)
224 if (seqsToIds.containsKey(sq))
226 return seqsToIds.get(sq);
230 // create sequential key
231 String key = "sq" + (seqsToIds.size() + 1);
232 key = makeHashCode(sq, key); // check we don't have an external reference
234 seqsToIds.put(sq, key);
241 if (seqsToIds == null)
243 seqsToIds = new IdentityHashMap<>();
245 if (seqRefIds == null)
247 seqRefIds = new HashMap<>();
249 if (incompleteSeqs == null)
251 incompleteSeqs = new HashMap<>();
253 if (frefedSequence == null)
255 frefedSequence = new ArrayList<>();
263 public Jalview2XML(boolean raiseGUI)
265 this.raiseGUI = raiseGUI;
269 * base class for resolving forward references to sequences by their ID
274 abstract class SeqFref
280 public SeqFref(String _sref, String type)
286 public String getSref()
291 public SequenceI getSrefSeq()
293 return seqRefIds.get(sref);
296 public boolean isResolvable()
298 return seqRefIds.get(sref) != null;
301 public SequenceI getSrefDatasetSeq()
303 SequenceI sq = seqRefIds.get(sref);
306 while (sq.getDatasetSequence() != null)
308 sq = sq.getDatasetSequence();
315 * @return true if the forward reference was fully resolved
317 abstract boolean resolve();
320 public String toString()
322 return type + " reference to " + sref;
327 * create forward reference for a mapping
333 public SeqFref newMappingRef(final String sref,
334 final jalview.datamodel.Mapping _jmap)
336 SeqFref fref = new SeqFref(sref, "Mapping")
338 public jalview.datamodel.Mapping jmap = _jmap;
343 SequenceI seq = getSrefDatasetSeq();
355 public SeqFref newAlcodMapRef(final String sref,
356 final AlignedCodonFrame _cf,
357 final jalview.datamodel.Mapping _jmap)
360 SeqFref fref = new SeqFref(sref, "Codon Frame")
362 AlignedCodonFrame cf = _cf;
364 public jalview.datamodel.Mapping mp = _jmap;
367 public boolean isResolvable()
369 return super.isResolvable() && mp.getTo() != null;
375 SequenceI seq = getSrefDatasetSeq();
380 cf.addMap(seq, mp.getTo(), mp.getMap());
387 public void resolveFrefedSequences()
389 Iterator<SeqFref> nextFref = frefedSequence.iterator();
390 int toresolve = frefedSequence.size();
391 int unresolved = 0, failedtoresolve = 0;
392 while (nextFref.hasNext())
394 SeqFref ref = nextFref.next();
395 if (ref.isResolvable())
407 } catch (Exception x)
410 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
423 System.err.println("Jalview Project Import: There were " + unresolved
424 + " forward references left unresolved on the stack.");
426 if (failedtoresolve > 0)
428 System.err.println("SERIOUS! " + failedtoresolve
429 + " resolvable forward references failed to resolve.");
431 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
434 "Jalview Project Import: There are " + incompleteSeqs.size()
435 + " sequences which may have incomplete metadata.");
436 if (incompleteSeqs.size() < 10)
438 for (SequenceI s : incompleteSeqs.values())
440 System.err.println(s.toString());
446 "Too many to report. Skipping output of incomplete sequences.");
452 * This maintains a map of viewports, the key being the seqSetId. Important to
453 * set historyItem and redoList for multiple views
455 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
457 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
459 String uniqueSetSuffix = "";
462 * List of pdbfiles added to Jar
464 List<String> pdbfiles = null;
466 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
467 public void saveState(File statefile)
469 FileOutputStream fos = null;
472 fos = new FileOutputStream(statefile);
473 JarOutputStream jout = new JarOutputStream(fos);
476 } catch (Exception e)
478 // TODO: inform user of the problem - they need to know if their data was
480 if (errorMessage == null)
482 errorMessage = "Couldn't write Jalview Archive to output file '"
483 + statefile + "' - See console error log for details";
487 errorMessage += "(output file was '" + statefile + "')";
497 } catch (IOException e)
507 * Writes a jalview project archive to the given Jar output stream.
511 public void saveState(JarOutputStream jout)
513 AlignFrame[] frames = Desktop.getAlignFrames();
519 saveAllFrames(Arrays.asList(frames), jout);
523 * core method for storing state for a set of AlignFrames.
526 * - frames involving all data to be exported (including containing
529 * - project output stream
531 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
533 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
536 * ensure cached data is clear before starting
538 // todo tidy up seqRefIds, seqsToIds initialisation / reset
540 splitFrameCandidates.clear();
545 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
546 // //////////////////////////////////////////////////
548 List<String> shortNames = new ArrayList<>();
549 List<String> viewIds = new ArrayList<>();
552 for (int i = frames.size() - 1; i > -1; i--)
554 AlignFrame af = frames.get(i);
556 if (skipList != null && skipList
557 .containsKey(af.getViewport().getSequenceSetId()))
562 String shortName = makeFilename(af, shortNames);
564 int ap, apSize = af.alignPanels.size();
566 for (ap = 0; ap < apSize; ap++)
568 AlignmentPanel apanel = af.alignPanels.get(ap);
569 String fileName = apSize == 1 ? shortName : ap + shortName;
570 if (!fileName.endsWith(".xml"))
572 fileName = fileName + ".xml";
575 saveState(apanel, fileName, jout, viewIds);
577 String dssid = getDatasetIdRef(
578 af.getViewport().getAlignment().getDataset());
579 if (!dsses.containsKey(dssid))
581 dsses.put(dssid, af);
586 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
592 } catch (Exception foo)
597 } catch (Exception ex)
599 // TODO: inform user of the problem - they need to know if their data was
601 if (errorMessage == null)
603 errorMessage = "Couldn't write Jalview Archive - see error output for details";
605 ex.printStackTrace();
610 * Generates a distinct file name, based on the title of the AlignFrame, by
611 * appending _n for increasing n until an unused name is generated. The new
612 * name (without its extension) is added to the list.
616 * @return the generated name, with .xml extension
618 protected String makeFilename(AlignFrame af, List<String> namesUsed)
620 String shortName = af.getTitle();
622 if (shortName.indexOf(File.separatorChar) > -1)
624 shortName = shortName
625 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
630 while (namesUsed.contains(shortName))
632 if (shortName.endsWith("_" + (count - 1)))
634 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
637 shortName = shortName.concat("_" + count);
641 namesUsed.add(shortName);
643 if (!shortName.endsWith(".xml"))
645 shortName = shortName + ".xml";
650 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
651 public boolean saveAlignment(AlignFrame af, String jarFile,
656 FileOutputStream fos = new FileOutputStream(jarFile);
657 JarOutputStream jout = new JarOutputStream(fos);
658 List<AlignFrame> frames = new ArrayList<>();
660 // resolve splitframes
661 if (af.getViewport().getCodingComplement() != null)
663 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
669 saveAllFrames(frames, jout);
673 } catch (Exception foo)
679 } catch (Exception ex)
681 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
682 ex.printStackTrace();
687 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
688 String fileName, JarOutputStream jout)
691 for (String dssids : dsses.keySet())
693 AlignFrame _af = dsses.get(dssids);
694 String jfileName = fileName + " Dataset for " + _af.getTitle();
695 if (!jfileName.endsWith(".xml"))
697 jfileName = jfileName + ".xml";
699 saveState(_af.alignPanel, jfileName, true, jout, null);
704 * create a JalviewModel from an alignment view and marshall it to a
708 * panel to create jalview model for
710 * name of alignment panel written to output stream
717 public JalviewModel saveState(AlignmentPanel ap, String fileName,
718 JarOutputStream jout, List<String> viewIds)
720 return saveState(ap, fileName, false, jout, viewIds);
724 * create a JalviewModel from an alignment view and marshall it to a
728 * panel to create jalview model for
730 * name of alignment panel written to output stream
732 * when true, only write the dataset for the alignment, not the data
733 * associated with the view.
739 public JalviewModel saveState(AlignmentPanel ap, String fileName,
740 boolean storeDS, JarOutputStream jout, List<String> viewIds)
744 viewIds = new ArrayList<>();
749 List<UserColourScheme> userColours = new ArrayList<>();
751 AlignViewport av = ap.av;
752 ViewportRanges vpRanges = av.getRanges();
754 JalviewModel object = new JalviewModel();
755 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
757 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
759 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
762 * rjal is full height alignment, jal is actual alignment with full metadata
763 * but excludes hidden sequences.
765 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
767 if (av.hasHiddenRows())
769 rjal = jal.getHiddenSequences().getFullAlignment();
772 SequenceSet vamsasSet = new SequenceSet();
774 JalviewModelSequence jms = new JalviewModelSequence();
776 vamsasSet.setGapChar(jal.getGapCharacter() + "");
778 if (jal.getDataset() != null)
780 // dataset id is the dataset's hashcode
781 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
784 // switch jal and the dataset
785 jal = jal.getDataset();
789 if (jal.getProperties() != null)
791 Enumeration en = jal.getProperties().keys();
792 while (en.hasMoreElements())
794 String key = en.nextElement().toString();
795 SequenceSetProperties ssp = new SequenceSetProperties();
797 ssp.setValue(jal.getProperties().get(key).toString());
798 vamsasSet.addSequenceSetProperties(ssp);
803 Set<String> calcIdSet = new HashSet<>();
804 // record the set of vamsas sequence XML POJO we create.
805 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
807 for (final SequenceI jds : rjal.getSequences())
809 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
810 : jds.getDatasetSequence();
811 String id = seqHash(jds);
812 if (vamsasSetIds.get(id) == null)
814 if (seqRefIds.get(id) != null && !storeDS)
816 // This happens for two reasons: 1. multiple views are being
818 // 2. the hashCode has collided with another sequence's code. This
820 // HAPPEN! (PF00072.15.stk does this)
821 // JBPNote: Uncomment to debug writing out of files that do not read
822 // back in due to ArrayOutOfBoundExceptions.
823 // System.err.println("vamsasSeq backref: "+id+"");
824 // System.err.println(jds.getName()+"
825 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
826 // System.err.println("Hashcode: "+seqHash(jds));
827 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
828 // System.err.println(rsq.getName()+"
829 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
830 // System.err.println("Hashcode: "+seqHash(rsq));
834 vamsasSeq = createVamsasSequence(id, jds);
835 vamsasSet.addSequence(vamsasSeq);
836 vamsasSetIds.put(id, vamsasSeq);
837 seqRefIds.put(id, jds);
841 jseq.setStart(jds.getStart());
842 jseq.setEnd(jds.getEnd());
843 jseq.setColour(av.getSequenceColour(jds).getRGB());
845 jseq.setId(id); // jseq id should be a string not a number
848 // Store any sequences this sequence represents
849 if (av.hasHiddenRows())
851 // use rjal, contains the full height alignment
853 av.getAlignment().getHiddenSequences().isHidden(jds));
855 if (av.isHiddenRepSequence(jds))
857 jalview.datamodel.SequenceI[] reps = av
858 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
860 for (int h = 0; h < reps.length; h++)
864 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
869 // mark sequence as reference - if it is the reference for this view
872 jseq.setViewreference(jds == jal.getSeqrep());
876 // TODO: omit sequence features from each alignment view's XML dump if we
877 // are storing dataset
878 List<jalview.datamodel.SequenceFeature> sfs = jds
879 .getSequenceFeatures();
880 for (SequenceFeature sf : sfs)
882 Features features = new Features();
884 features.setBegin(sf.getBegin());
885 features.setEnd(sf.getEnd());
886 features.setDescription(sf.getDescription());
887 features.setType(sf.getType());
888 features.setFeatureGroup(sf.getFeatureGroup());
889 features.setScore(sf.getScore());
890 if (sf.links != null)
892 for (int l = 0; l < sf.links.size(); l++)
894 OtherData keyValue = new OtherData();
895 keyValue.setKey("LINK_" + l);
896 keyValue.setValue(sf.links.elementAt(l).toString());
897 features.addOtherData(keyValue);
900 if (sf.otherDetails != null)
903 * save feature attributes, which may be simple strings or
904 * map valued (have sub-attributes)
906 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
908 String key = entry.getKey();
909 Object value = entry.getValue();
910 if (value instanceof Map<?, ?>)
912 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
915 OtherData otherData = new OtherData();
916 otherData.setKey(key);
917 otherData.setKey2(subAttribute.getKey());
918 otherData.setValue(subAttribute.getValue().toString());
919 features.addOtherData(otherData);
924 OtherData otherData = new OtherData();
925 otherData.setKey(key);
926 otherData.setValue(value.toString());
927 features.addOtherData(otherData);
932 jseq.addFeatures(features);
935 if (jdatasq.getAllPDBEntries() != null)
937 Enumeration en = jdatasq.getAllPDBEntries().elements();
938 while (en.hasMoreElements())
940 Pdbids pdb = new Pdbids();
941 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
944 String pdbId = entry.getId();
946 pdb.setType(entry.getType());
949 * Store any structure views associated with this sequence. This
950 * section copes with duplicate entries in the project, so a dataset
951 * only view *should* be coped with sensibly.
953 // This must have been loaded, is it still visible?
954 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
955 String matchedFile = null;
956 for (int f = frames.length - 1; f > -1; f--)
958 if (frames[f] instanceof StructureViewerBase)
960 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
961 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
962 matchedFile, viewFrame);
964 * Only store each structure viewer's state once in the project
965 * jar. First time through only (storeDS==false)
967 String viewId = viewFrame.getViewId();
968 if (!storeDS && !viewIds.contains(viewId))
973 String viewerState = viewFrame.getStateInfo();
974 writeJarEntry(jout, getViewerJarEntryName(viewId),
975 viewerState.getBytes());
976 } catch (IOException e)
979 "Error saving viewer state: " + e.getMessage());
985 if (matchedFile != null || entry.getFile() != null)
987 if (entry.getFile() != null)
990 matchedFile = entry.getFile();
992 pdb.setFile(matchedFile); // entry.getFile());
993 if (pdbfiles == null)
995 pdbfiles = new ArrayList<>();
998 if (!pdbfiles.contains(pdbId))
1000 pdbfiles.add(pdbId);
1001 copyFileToJar(jout, matchedFile, pdbId);
1005 Enumeration<String> props = entry.getProperties();
1006 if (props.hasMoreElements())
1008 PdbentryItem item = new PdbentryItem();
1009 while (props.hasMoreElements())
1011 Property prop = new Property();
1012 String key = props.nextElement();
1014 prop.setValue(entry.getProperty(key).toString());
1015 item.addProperty(prop);
1017 pdb.addPdbentryItem(item);
1020 jseq.addPdbids(pdb);
1024 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1029 if (!storeDS && av.hasHiddenRows())
1031 jal = av.getAlignment();
1035 if (storeDS && jal.getCodonFrames() != null)
1037 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1038 for (AlignedCodonFrame acf : jac)
1040 AlcodonFrame alc = new AlcodonFrame();
1041 if (acf.getProtMappings() != null
1042 && acf.getProtMappings().length > 0)
1044 boolean hasMap = false;
1045 SequenceI[] dnas = acf.getdnaSeqs();
1046 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1047 for (int m = 0; m < pmaps.length; m++)
1049 AlcodMap alcmap = new AlcodMap();
1050 alcmap.setDnasq(seqHash(dnas[m]));
1052 createVamsasMapping(pmaps[m], dnas[m], null, false));
1053 alc.addAlcodMap(alcmap);
1058 vamsasSet.addAlcodonFrame(alc);
1061 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1063 // AlcodonFrame alc = new AlcodonFrame();
1064 // vamsasSet.addAlcodonFrame(alc);
1065 // for (int p = 0; p < acf.aaWidth; p++)
1067 // Alcodon cmap = new Alcodon();
1068 // if (acf.codons[p] != null)
1070 // // Null codons indicate a gapped column in the translated peptide
1072 // cmap.setPos1(acf.codons[p][0]);
1073 // cmap.setPos2(acf.codons[p][1]);
1074 // cmap.setPos3(acf.codons[p][2]);
1076 // alc.addAlcodon(cmap);
1078 // if (acf.getProtMappings() != null
1079 // && acf.getProtMappings().length > 0)
1081 // SequenceI[] dnas = acf.getdnaSeqs();
1082 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1083 // for (int m = 0; m < pmaps.length; m++)
1085 // AlcodMap alcmap = new AlcodMap();
1086 // alcmap.setDnasq(seqHash(dnas[m]));
1087 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1089 // alc.addAlcodMap(alcmap);
1096 // /////////////////////////////////
1097 if (!storeDS && av.getCurrentTree() != null)
1099 // FIND ANY ASSOCIATED TREES
1100 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1101 if (Desktop.desktop != null)
1103 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1105 for (int t = 0; t < frames.length; t++)
1107 if (frames[t] instanceof TreePanel)
1109 TreePanel tp = (TreePanel) frames[t];
1111 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1113 Tree tree = new Tree();
1114 tree.setTitle(tp.getTitle());
1115 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1116 tree.setNewick(tp.getTree().print());
1117 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1119 tree.setFitToWindow(tp.fitToWindow.getState());
1120 tree.setFontName(tp.getTreeFont().getName());
1121 tree.setFontSize(tp.getTreeFont().getSize());
1122 tree.setFontStyle(tp.getTreeFont().getStyle());
1123 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1125 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1126 tree.setShowDistances(tp.distanceMenu.getState());
1128 tree.setHeight(tp.getHeight());
1129 tree.setWidth(tp.getWidth());
1130 tree.setXpos(tp.getX());
1131 tree.setYpos(tp.getY());
1132 tree.setId(makeHashCode(tp, null));
1142 * store forward refs from an annotationRow to any groups
1144 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1147 for (SequenceI sq : jal.getSequences())
1149 // Store annotation on dataset sequences only
1150 AlignmentAnnotation[] aa = sq.getAnnotation();
1151 if (aa != null && aa.length > 0)
1153 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1160 if (jal.getAlignmentAnnotation() != null)
1162 // Store the annotation shown on the alignment.
1163 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1164 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1169 if (jal.getGroups() != null)
1171 JGroup[] groups = new JGroup[jal.getGroups().size()];
1173 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1175 JGroup jGroup = new JGroup();
1176 groups[++i] = jGroup;
1178 jGroup.setStart(sg.getStartRes());
1179 jGroup.setEnd(sg.getEndRes());
1180 jGroup.setName(sg.getName());
1181 if (groupRefs.containsKey(sg))
1183 // group has references so set its ID field
1184 jGroup.setId(groupRefs.get(sg));
1186 ColourSchemeI colourScheme = sg.getColourScheme();
1187 if (colourScheme != null)
1189 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1190 if (groupColourScheme.conservationApplied())
1192 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1194 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1197 setUserColourScheme(colourScheme, userColours, jms));
1201 jGroup.setColour(colourScheme.getSchemeName());
1204 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1206 jGroup.setColour("AnnotationColourGradient");
1207 jGroup.setAnnotationColours(constructAnnotationColours(
1208 (jalview.schemes.AnnotationColourGradient) colourScheme,
1211 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1214 setUserColourScheme(colourScheme, userColours, jms));
1218 jGroup.setColour(colourScheme.getSchemeName());
1221 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1224 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1225 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1226 jGroup.setDisplayText(sg.getDisplayText());
1227 jGroup.setColourText(sg.getColourText());
1228 jGroup.setTextCol1(sg.textColour.getRGB());
1229 jGroup.setTextCol2(sg.textColour2.getRGB());
1230 jGroup.setTextColThreshold(sg.thresholdTextColour);
1231 jGroup.setShowUnconserved(sg.getShowNonconserved());
1232 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1233 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1234 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1235 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1236 for (SequenceI seq : sg.getSequences())
1238 jGroup.addSeq(seqHash(seq));
1242 jms.setJGroup(groups);
1246 // /////////SAVE VIEWPORT
1247 Viewport view = new Viewport();
1248 view.setTitle(ap.alignFrame.getTitle());
1249 view.setSequenceSetId(
1250 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1251 view.setId(av.getViewId());
1252 if (av.getCodingComplement() != null)
1254 view.setComplementId(av.getCodingComplement().getViewId());
1256 view.setViewName(av.getViewName());
1257 view.setGatheredViews(av.isGatherViewsHere());
1259 Rectangle size = ap.av.getExplodedGeometry();
1260 Rectangle position = size;
1263 size = ap.alignFrame.getBounds();
1264 if (av.getCodingComplement() != null)
1266 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1274 view.setXpos(position.x);
1275 view.setYpos(position.y);
1277 view.setWidth(size.width);
1278 view.setHeight(size.height);
1280 view.setStartRes(vpRanges.getStartRes());
1281 view.setStartSeq(vpRanges.getStartSeq());
1283 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1285 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1289 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1291 AnnotationColours ac = constructAnnotationColours(
1292 (jalview.schemes.AnnotationColourGradient) av
1293 .getGlobalColourScheme(),
1296 view.setAnnotationColours(ac);
1297 view.setBgColour("AnnotationColourGradient");
1301 view.setBgColour(ColourSchemeProperty
1302 .getColourName(av.getGlobalColourScheme()));
1305 ResidueShaderI vcs = av.getResidueShading();
1306 ColourSchemeI cs = av.getGlobalColourScheme();
1310 if (vcs.conservationApplied())
1312 view.setConsThreshold(vcs.getConservationInc());
1313 if (cs instanceof jalview.schemes.UserColourScheme)
1315 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1318 view.setPidThreshold(vcs.getThreshold());
1321 view.setConservationSelected(av.getConservationSelected());
1322 view.setPidSelected(av.getAbovePIDThreshold());
1323 view.setFontName(av.font.getName());
1324 view.setFontSize(av.font.getSize());
1325 view.setFontStyle(av.font.getStyle());
1326 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1327 view.setRenderGaps(av.isRenderGaps());
1328 view.setShowAnnotation(av.isShowAnnotation());
1329 view.setShowBoxes(av.getShowBoxes());
1330 view.setShowColourText(av.getColourText());
1331 view.setShowFullId(av.getShowJVSuffix());
1332 view.setRightAlignIds(av.isRightAlignIds());
1333 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1334 view.setShowText(av.getShowText());
1335 view.setShowUnconserved(av.getShowUnconserved());
1336 view.setWrapAlignment(av.getWrapAlignment());
1337 view.setTextCol1(av.getTextColour().getRGB());
1338 view.setTextCol2(av.getTextColour2().getRGB());
1339 view.setTextColThreshold(av.getThresholdTextColour());
1340 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1341 view.setShowSequenceLogo(av.isShowSequenceLogo());
1342 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1343 view.setShowGroupConsensus(av.isShowGroupConsensus());
1344 view.setShowGroupConservation(av.isShowGroupConservation());
1345 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1346 view.setShowDbRefTooltip(av.isShowDBRefs());
1347 view.setFollowHighlight(av.isFollowHighlight());
1348 view.setFollowSelection(av.followSelection);
1349 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1350 if (av.getFeaturesDisplayed() != null)
1352 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1354 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1355 .getFeatureRenderer();
1356 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1358 Vector<String> settingsAdded = new Vector<>();
1359 if (renderOrder != null)
1361 for (String featureType : renderOrder)
1363 Setting setting = new Setting();
1364 setting.setType(featureType);
1367 * save any filter for the feature type
1369 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1370 if (filter != null) {
1371 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1372 FeatureMatcherI firstFilter = filters.next();
1373 setting.setMatcherSet(Jalview2XML.marshalFilter(
1374 firstFilter, filters, filter.isAnded()));
1378 * save colour scheme for the feature type
1380 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1381 if (!fcol.isSimpleColour())
1383 setting.setColour(fcol.getMaxColour().getRGB());
1384 setting.setMincolour(fcol.getMinColour().getRGB());
1385 setting.setMin(fcol.getMin());
1386 setting.setMax(fcol.getMax());
1387 setting.setColourByLabel(fcol.isColourByLabel());
1388 if (fcol.isColourByAttribute())
1390 setting.setAttributeName(fcol.getAttributeName());
1392 setting.setAutoScale(fcol.isAutoScaled());
1393 setting.setThreshold(fcol.getThreshold());
1394 Color noColour = fcol.getNoColour();
1395 if (noColour == null)
1397 setting.setNoValueColour(NoValueColour.NONE);
1399 else if (noColour.equals(fcol.getMaxColour()))
1401 setting.setNoValueColour(NoValueColour.MAX);
1405 setting.setNoValueColour(NoValueColour.MIN);
1407 // -1 = No threshold, 0 = Below, 1 = Above
1408 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1409 : (fcol.isBelowThreshold() ? 0 : -1));
1413 setting.setColour(fcol.getColour().getRGB());
1417 av.getFeaturesDisplayed().isVisible(featureType));
1419 .getOrder(featureType);
1422 setting.setOrder(rorder);
1424 fs.addSetting(setting);
1425 settingsAdded.addElement(featureType);
1429 // is groups actually supposed to be a map here ?
1430 Iterator<String> en = fr.getFeatureGroups().iterator();
1431 Vector<String> groupsAdded = new Vector<>();
1432 while (en.hasNext())
1434 String grp = en.next();
1435 if (groupsAdded.contains(grp))
1439 Group g = new Group();
1441 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1444 groupsAdded.addElement(grp);
1446 jms.setFeatureSettings(fs);
1449 if (av.hasHiddenColumns())
1451 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1452 .getHiddenColumns();
1455 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1459 Iterator<int[]> hiddenRegions = hidden.iterator();
1460 while (hiddenRegions.hasNext())
1462 int[] region = hiddenRegions.next();
1463 HiddenColumns hc = new HiddenColumns();
1464 hc.setStart(region[0]);
1465 hc.setEnd(region[1]);
1466 view.addHiddenColumns(hc);
1470 if (calcIdSet.size() > 0)
1472 for (String calcId : calcIdSet)
1474 if (calcId.trim().length() > 0)
1476 CalcIdParam cidp = createCalcIdParam(calcId, av);
1477 // Some calcIds have no parameters.
1480 view.addCalcIdParam(cidp);
1486 jms.addViewport(view);
1488 object.setJalviewModelSequence(jms);
1489 object.getVamsasModel().addSequenceSet(vamsasSet);
1491 if (jout != null && fileName != null)
1493 // We may not want to write the object to disk,
1494 // eg we can copy the alignViewport to a new view object
1495 // using save and then load
1498 System.out.println("Writing jar entry " + fileName);
1499 JarEntry entry = new JarEntry(fileName);
1500 jout.putNextEntry(entry);
1501 PrintWriter pout = new PrintWriter(
1502 new OutputStreamWriter(jout, UTF_8));
1503 Marshaller marshaller = new Marshaller(pout);
1504 marshaller.marshal(object);
1507 } catch (Exception ex)
1509 // TODO: raise error in GUI if marshalling failed.
1510 ex.printStackTrace();
1517 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1518 * for each viewer, with
1520 * <li>viewer geometry (position, size, split pane divider location)</li>
1521 * <li>index of the selected structure in the viewer (currently shows gapped
1523 * <li>the id of the annotation holding RNA secondary structure</li>
1524 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1526 * Varna viewer state is also written out (in native Varna XML) to separate
1527 * project jar entries. A separate entry is written for each RNA structure
1528 * displayed, with the naming convention
1530 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1538 * @param storeDataset
1540 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1541 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1542 boolean storeDataset)
1544 if (Desktop.desktop == null)
1548 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1549 for (int f = frames.length - 1; f > -1; f--)
1551 if (frames[f] instanceof AppVarna)
1553 AppVarna varna = (AppVarna) frames[f];
1555 * link the sequence to every viewer that is showing it and is linked to
1556 * its alignment panel
1558 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1560 String viewId = varna.getViewId();
1561 RnaViewer rna = new RnaViewer();
1562 rna.setViewId(viewId);
1563 rna.setTitle(varna.getTitle());
1564 rna.setXpos(varna.getX());
1565 rna.setYpos(varna.getY());
1566 rna.setWidth(varna.getWidth());
1567 rna.setHeight(varna.getHeight());
1568 rna.setDividerLocation(varna.getDividerLocation());
1569 rna.setSelectedRna(varna.getSelectedIndex());
1570 jseq.addRnaViewer(rna);
1573 * Store each Varna panel's state once in the project per sequence.
1574 * First time through only (storeDataset==false)
1576 // boolean storeSessions = false;
1577 // String sequenceViewId = viewId + seqsToIds.get(jds);
1578 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1580 // viewIds.add(sequenceViewId);
1581 // storeSessions = true;
1583 for (RnaModel model : varna.getModels())
1585 if (model.seq == jds)
1588 * VARNA saves each view (sequence or alignment secondary
1589 * structure, gapped or trimmed) as a separate XML file
1591 String jarEntryName = rnaSessions.get(model);
1592 if (jarEntryName == null)
1595 String varnaStateFile = varna.getStateInfo(model.rna);
1596 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1597 copyFileToJar(jout, varnaStateFile, jarEntryName);
1598 rnaSessions.put(model, jarEntryName);
1600 SecondaryStructure ss = new SecondaryStructure();
1601 String annotationId = varna.getAnnotation(jds).annotationId;
1602 ss.setAnnotationId(annotationId);
1603 ss.setViewerState(jarEntryName);
1604 ss.setGapped(model.gapped);
1605 ss.setTitle(model.title);
1606 rna.addSecondaryStructure(ss);
1615 * Copy the contents of a file to a new entry added to the output jar
1619 * @param jarEntryName
1621 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1622 String jarEntryName)
1624 DataInputStream dis = null;
1627 File file = new File(infilePath);
1628 if (file.exists() && jout != null)
1630 dis = new DataInputStream(new FileInputStream(file));
1631 byte[] data = new byte[(int) file.length()];
1632 dis.readFully(data);
1633 writeJarEntry(jout, jarEntryName, data);
1635 } catch (Exception ex)
1637 ex.printStackTrace();
1645 } catch (IOException e)
1654 * Write the data to a new entry of given name in the output jar file
1657 * @param jarEntryName
1659 * @throws IOException
1661 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1662 byte[] data) throws IOException
1666 System.out.println("Writing jar entry " + jarEntryName);
1667 jout.putNextEntry(new JarEntry(jarEntryName));
1668 DataOutputStream dout = new DataOutputStream(jout);
1669 dout.write(data, 0, data.length);
1676 * Save the state of a structure viewer
1681 * the archive XML element under which to save the state
1684 * @param matchedFile
1688 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1689 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1690 String matchedFile, StructureViewerBase viewFrame)
1692 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1695 * Look for any bindings for this viewer to the PDB file of interest
1696 * (including part matches excluding chain id)
1698 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1700 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1701 final String pdbId = pdbentry.getId();
1702 if (!pdbId.equals(entry.getId())
1703 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1704 .startsWith(pdbId.toLowerCase())))
1707 * not interested in a binding to a different PDB entry here
1711 if (matchedFile == null)
1713 matchedFile = pdbentry.getFile();
1715 else if (!matchedFile.equals(pdbentry.getFile()))
1718 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1719 + pdbentry.getFile());
1723 // can get at it if the ID
1724 // match is ambiguous (e.g.
1727 for (int smap = 0; smap < viewFrame.getBinding()
1728 .getSequence()[peid].length; smap++)
1730 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1731 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1733 StructureState state = new StructureState();
1734 state.setVisible(true);
1735 state.setXpos(viewFrame.getX());
1736 state.setYpos(viewFrame.getY());
1737 state.setWidth(viewFrame.getWidth());
1738 state.setHeight(viewFrame.getHeight());
1739 final String viewId = viewFrame.getViewId();
1740 state.setViewId(viewId);
1741 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1742 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1743 state.setColourByJmol(viewFrame.isColouredByViewer());
1744 state.setType(viewFrame.getViewerType().toString());
1745 pdb.addStructureState(state);
1753 * Populates the AnnotationColours xml for save. This captures the settings of
1754 * the options in the 'Colour by Annotation' dialog.
1757 * @param userColours
1761 private AnnotationColours constructAnnotationColours(
1762 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1763 JalviewModelSequence jms)
1765 AnnotationColours ac = new AnnotationColours();
1766 ac.setAboveThreshold(acg.getAboveThreshold());
1767 ac.setThreshold(acg.getAnnotationThreshold());
1768 // 2.10.2 save annotationId (unique) not annotation label
1769 ac.setAnnotation(acg.getAnnotation().annotationId);
1770 if (acg.getBaseColour() instanceof UserColourScheme)
1773 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1778 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1781 ac.setMaxColour(acg.getMaxColour().getRGB());
1782 ac.setMinColour(acg.getMinColour().getRGB());
1783 ac.setPerSequence(acg.isSeqAssociated());
1784 ac.setPredefinedColours(acg.isPredefinedColours());
1788 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1789 IdentityHashMap<SequenceGroup, String> groupRefs,
1790 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1791 SequenceSet vamsasSet)
1794 for (int i = 0; i < aa.length; i++)
1796 Annotation an = new Annotation();
1798 AlignmentAnnotation annotation = aa[i];
1799 if (annotation.annotationId != null)
1801 annotationIds.put(annotation.annotationId, annotation);
1804 an.setId(annotation.annotationId);
1806 an.setVisible(annotation.visible);
1808 an.setDescription(annotation.description);
1810 if (annotation.sequenceRef != null)
1812 // 2.9 JAL-1781 xref on sequence id rather than name
1813 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1815 if (annotation.groupRef != null)
1817 String groupIdr = groupRefs.get(annotation.groupRef);
1818 if (groupIdr == null)
1820 // make a locally unique String
1821 groupRefs.put(annotation.groupRef,
1822 groupIdr = ("" + System.currentTimeMillis()
1823 + annotation.groupRef.getName()
1824 + groupRefs.size()));
1826 an.setGroupRef(groupIdr.toString());
1829 // store all visualization attributes for annotation
1830 an.setGraphHeight(annotation.graphHeight);
1831 an.setCentreColLabels(annotation.centreColLabels);
1832 an.setScaleColLabels(annotation.scaleColLabel);
1833 an.setShowAllColLabels(annotation.showAllColLabels);
1834 an.setBelowAlignment(annotation.belowAlignment);
1836 if (annotation.graph > 0)
1839 an.setGraphType(annotation.graph);
1840 an.setGraphGroup(annotation.graphGroup);
1841 if (annotation.getThreshold() != null)
1843 ThresholdLine line = new ThresholdLine();
1844 line.setLabel(annotation.getThreshold().label);
1845 line.setValue(annotation.getThreshold().value);
1846 line.setColour(annotation.getThreshold().colour.getRGB());
1847 an.setThresholdLine(line);
1855 an.setLabel(annotation.label);
1857 if (annotation == av.getAlignmentQualityAnnot()
1858 || annotation == av.getAlignmentConservationAnnotation()
1859 || annotation == av.getAlignmentConsensusAnnotation()
1860 || annotation.autoCalculated)
1862 // new way of indicating autocalculated annotation -
1863 an.setAutoCalculated(annotation.autoCalculated);
1865 if (annotation.hasScore())
1867 an.setScore(annotation.getScore());
1870 if (annotation.getCalcId() != null)
1872 calcIdSet.add(annotation.getCalcId());
1873 an.setCalcId(annotation.getCalcId());
1875 if (annotation.hasProperties())
1877 for (String pr : annotation.getProperties())
1879 Property prop = new Property();
1881 prop.setValue(annotation.getProperty(pr));
1882 an.addProperty(prop);
1886 AnnotationElement ae;
1887 if (annotation.annotations != null)
1889 an.setScoreOnly(false);
1890 for (int a = 0; a < annotation.annotations.length; a++)
1892 if ((annotation == null) || (annotation.annotations[a] == null))
1897 ae = new AnnotationElement();
1898 if (annotation.annotations[a].description != null)
1900 ae.setDescription(annotation.annotations[a].description);
1902 if (annotation.annotations[a].displayCharacter != null)
1904 ae.setDisplayCharacter(
1905 annotation.annotations[a].displayCharacter);
1908 if (!Float.isNaN(annotation.annotations[a].value))
1910 ae.setValue(annotation.annotations[a].value);
1914 if (annotation.annotations[a].secondaryStructure > ' ')
1916 ae.setSecondaryStructure(
1917 annotation.annotations[a].secondaryStructure + "");
1920 if (annotation.annotations[a].colour != null
1921 && annotation.annotations[a].colour != java.awt.Color.black)
1923 ae.setColour(annotation.annotations[a].colour.getRGB());
1926 an.addAnnotationElement(ae);
1927 if (annotation.autoCalculated)
1929 // only write one non-null entry into the annotation row -
1930 // sufficient to get the visualization attributes necessary to
1938 an.setScoreOnly(true);
1940 if (!storeDS || (storeDS && !annotation.autoCalculated))
1942 // skip autocalculated annotation - these are only provided for
1944 vamsasSet.addAnnotation(an);
1950 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1952 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1953 if (settings != null)
1955 CalcIdParam vCalcIdParam = new CalcIdParam();
1956 vCalcIdParam.setCalcId(calcId);
1957 vCalcIdParam.addServiceURL(settings.getServiceURI());
1958 // generic URI allowing a third party to resolve another instance of the
1959 // service used for this calculation
1960 for (String urls : settings.getServiceURLs())
1962 vCalcIdParam.addServiceURL(urls);
1964 vCalcIdParam.setVersion("1.0");
1965 if (settings.getPreset() != null)
1967 WsParamSetI setting = settings.getPreset();
1968 vCalcIdParam.setName(setting.getName());
1969 vCalcIdParam.setDescription(setting.getDescription());
1973 vCalcIdParam.setName("");
1974 vCalcIdParam.setDescription("Last used parameters");
1976 // need to be able to recover 1) settings 2) user-defined presets or
1977 // recreate settings from preset 3) predefined settings provided by
1978 // service - or settings that can be transferred (or discarded)
1979 vCalcIdParam.setParameters(
1980 settings.getWsParamFile().replace("\n", "|\\n|"));
1981 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1982 // todo - decide if updateImmediately is needed for any projects.
1984 return vCalcIdParam;
1989 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1992 if (calcIdParam.getVersion().equals("1.0"))
1994 Jws2Instance service = Jws2Discoverer.getDiscoverer()
1995 .getPreferredServiceFor(calcIdParam.getServiceURL());
1996 if (service != null)
1998 WsParamSetI parmSet = null;
2001 parmSet = service.getParamStore().parseServiceParameterFile(
2002 calcIdParam.getName(), calcIdParam.getDescription(),
2003 calcIdParam.getServiceURL(),
2004 calcIdParam.getParameters().replace("|\\n|", "\n"));
2005 } catch (IOException x)
2007 warn("Couldn't parse parameter data for "
2008 + calcIdParam.getCalcId(), x);
2011 List<ArgumentI> argList = null;
2012 if (calcIdParam.getName().length() > 0)
2014 parmSet = service.getParamStore()
2015 .getPreset(calcIdParam.getName());
2016 if (parmSet != null)
2018 // TODO : check we have a good match with settings in AACon -
2019 // otherwise we'll need to create a new preset
2024 argList = parmSet.getArguments();
2027 AAConSettings settings = new AAConSettings(
2028 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2029 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2030 calcIdParam.isNeedsUpdate());
2035 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2039 throw new Error(MessageManager.formatMessage(
2040 "error.unsupported_version_calcIdparam", new Object[]
2041 { calcIdParam.toString() }));
2045 * External mapping between jalview objects and objects yielding a valid and
2046 * unique object ID string. This is null for normal Jalview project IO, but
2047 * non-null when a jalview project is being read or written as part of a
2050 IdentityHashMap jv2vobj = null;
2053 * Construct a unique ID for jvobj using either existing bindings or if none
2054 * exist, the result of the hashcode call for the object.
2057 * jalview data object
2058 * @return unique ID for referring to jvobj
2060 private String makeHashCode(Object jvobj, String altCode)
2062 if (jv2vobj != null)
2064 Object id = jv2vobj.get(jvobj);
2067 return id.toString();
2069 // check string ID mappings
2070 if (jvids2vobj != null && jvobj instanceof String)
2072 id = jvids2vobj.get(jvobj);
2076 return id.toString();
2078 // give up and warn that something has gone wrong
2079 warn("Cannot find ID for object in external mapping : " + jvobj);
2085 * return local jalview object mapped to ID, if it exists
2089 * @return null or object bound to idcode
2091 private Object retrieveExistingObj(String idcode)
2093 if (idcode != null && vobj2jv != null)
2095 return vobj2jv.get(idcode);
2101 * binding from ID strings from external mapping table to jalview data model
2104 private Hashtable vobj2jv;
2106 private Sequence createVamsasSequence(String id, SequenceI jds)
2108 return createVamsasSequence(true, id, jds, null);
2111 private Sequence createVamsasSequence(boolean recurse, String id,
2112 SequenceI jds, SequenceI parentseq)
2114 Sequence vamsasSeq = new Sequence();
2115 vamsasSeq.setId(id);
2116 vamsasSeq.setName(jds.getName());
2117 vamsasSeq.setSequence(jds.getSequenceAsString());
2118 vamsasSeq.setDescription(jds.getDescription());
2119 jalview.datamodel.DBRefEntry[] dbrefs = null;
2120 if (jds.getDatasetSequence() != null)
2122 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2126 // seqId==dsseqid so we can tell which sequences really are
2127 // dataset sequences only
2128 vamsasSeq.setDsseqid(id);
2129 dbrefs = jds.getDBRefs();
2130 if (parentseq == null)
2137 for (int d = 0; d < dbrefs.length; d++)
2139 DBRef dbref = new DBRef();
2140 dbref.setSource(dbrefs[d].getSource());
2141 dbref.setVersion(dbrefs[d].getVersion());
2142 dbref.setAccessionId(dbrefs[d].getAccessionId());
2143 if (dbrefs[d].hasMap())
2145 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2147 dbref.setMapping(mp);
2149 vamsasSeq.addDBRef(dbref);
2155 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2156 SequenceI parentseq, SequenceI jds, boolean recurse)
2159 if (jmp.getMap() != null)
2163 jalview.util.MapList mlst = jmp.getMap();
2164 List<int[]> r = mlst.getFromRanges();
2165 for (int[] range : r)
2167 MapListFrom mfrom = new MapListFrom();
2168 mfrom.setStart(range[0]);
2169 mfrom.setEnd(range[1]);
2170 mp.addMapListFrom(mfrom);
2172 r = mlst.getToRanges();
2173 for (int[] range : r)
2175 MapListTo mto = new MapListTo();
2176 mto.setStart(range[0]);
2177 mto.setEnd(range[1]);
2178 mp.addMapListTo(mto);
2180 mp.setMapFromUnit(mlst.getFromRatio());
2181 mp.setMapToUnit(mlst.getToRatio());
2182 if (jmp.getTo() != null)
2184 MappingChoice mpc = new MappingChoice();
2186 // check/create ID for the sequence referenced by getTo()
2189 SequenceI ps = null;
2190 if (parentseq != jmp.getTo()
2191 && parentseq.getDatasetSequence() != jmp.getTo())
2193 // chaining dbref rather than a handshaking one
2194 jmpid = seqHash(ps = jmp.getTo());
2198 jmpid = seqHash(ps = parentseq);
2200 mpc.setDseqFor(jmpid);
2201 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2203 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2204 seqRefIds.put(mpc.getDseqFor(), ps);
2208 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2211 mp.setMappingChoice(mpc);
2217 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2218 List<UserColourScheme> userColours, JalviewModelSequence jms)
2221 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2222 boolean newucs = false;
2223 if (!userColours.contains(ucs))
2225 userColours.add(ucs);
2228 id = "ucs" + userColours.indexOf(ucs);
2231 // actually create the scheme's entry in the XML model
2232 java.awt.Color[] colours = ucs.getColours();
2233 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2234 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2236 for (int i = 0; i < colours.length; i++)
2238 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2239 col.setName(ResidueProperties.aa[i]);
2240 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2241 jbucs.addColour(col);
2243 if (ucs.getLowerCaseColours() != null)
2245 colours = ucs.getLowerCaseColours();
2246 for (int i = 0; i < colours.length; i++)
2248 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2249 col.setName(ResidueProperties.aa[i].toLowerCase());
2250 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2251 jbucs.addColour(col);
2256 uc.setUserColourScheme(jbucs);
2257 jms.addUserColours(uc);
2263 jalview.schemes.UserColourScheme getUserColourScheme(
2264 JalviewModelSequence jms, String id)
2266 UserColours[] uc = jms.getUserColours();
2267 UserColours colours = null;
2269 for (int i = 0; i < uc.length; i++)
2271 if (uc[i].getId().equals(id))
2279 java.awt.Color[] newColours = new java.awt.Color[24];
2281 for (int i = 0; i < 24; i++)
2283 newColours[i] = new java.awt.Color(Integer.parseInt(
2284 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2287 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2290 if (colours.getUserColourScheme().getColourCount() > 24)
2292 newColours = new java.awt.Color[23];
2293 for (int i = 0; i < 23; i++)
2295 newColours[i] = new java.awt.Color(Integer.parseInt(
2296 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2299 ucs.setLowerCaseColours(newColours);
2306 * contains last error message (if any) encountered by XML loader.
2308 String errorMessage = null;
2311 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2312 * exceptions are raised during project XML parsing
2314 public boolean attemptversion1parse = true;
2317 * Load a jalview project archive from a jar file
2320 * - HTTP URL or filename
2322 public AlignFrame loadJalviewAlign(final String file)
2325 jalview.gui.AlignFrame af = null;
2329 // create list to store references for any new Jmol viewers created
2330 newStructureViewers = new Vector<>();
2331 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2332 // Workaround is to make sure caller implements the JarInputStreamProvider
2334 // so we can re-open the jar input stream for each entry.
2336 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2337 af = loadJalviewAlign(jprovider);
2338 af.setMenusForViewport();
2340 } catch (MalformedURLException e)
2342 errorMessage = "Invalid URL format for '" + file + "'";
2348 SwingUtilities.invokeAndWait(new Runnable()
2353 setLoadingFinishedForNewStructureViewers();
2356 } catch (Exception x)
2358 System.err.println("Error loading alignment: " + x.getMessage());
2364 private jarInputStreamProvider createjarInputStreamProvider(
2365 final String file) throws MalformedURLException
2368 errorMessage = null;
2369 uniqueSetSuffix = null;
2371 viewportsAdded.clear();
2372 frefedSequence = null;
2374 if (file.startsWith("http://"))
2376 url = new URL(file);
2378 final URL _url = url;
2379 return new jarInputStreamProvider()
2383 public JarInputStream getJarInputStream() throws IOException
2387 return new JarInputStream(_url.openStream());
2391 return new JarInputStream(new FileInputStream(file));
2396 public String getFilename()
2404 * Recover jalview session from a jalview project archive. Caller may
2405 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2406 * themselves. Any null fields will be initialised with default values,
2407 * non-null fields are left alone.
2412 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2414 errorMessage = null;
2415 if (uniqueSetSuffix == null)
2417 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2419 if (seqRefIds == null)
2423 AlignFrame af = null, _af = null;
2424 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2425 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2426 final String file = jprovider.getFilename();
2429 JarInputStream jin = null;
2430 JarEntry jarentry = null;
2435 jin = jprovider.getJarInputStream();
2436 for (int i = 0; i < entryCount; i++)
2438 jarentry = jin.getNextJarEntry();
2441 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2443 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2444 JalviewModel object = new JalviewModel();
2446 Unmarshaller unmar = new Unmarshaller(object);
2447 unmar.setValidation(false);
2448 object = (JalviewModel) unmar.unmarshal(in);
2449 if (true) // !skipViewport(object))
2451 _af = loadFromObject(object, file, true, jprovider);
2452 if (_af != null && object.getJalviewModelSequence()
2453 .getViewportCount() > 0)
2457 // store a reference to the first view
2460 if (_af.viewport.isGatherViewsHere())
2462 // if this is a gathered view, keep its reference since
2463 // after gathering views, only this frame will remain
2465 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2467 // Save dataset to register mappings once all resolved
2468 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2469 af.viewport.getAlignment().getDataset());
2474 else if (jarentry != null)
2476 // Some other file here.
2479 } while (jarentry != null);
2480 resolveFrefedSequences();
2481 } catch (IOException ex)
2483 ex.printStackTrace();
2484 errorMessage = "Couldn't locate Jalview XML file : " + file;
2486 "Exception whilst loading jalview XML file : " + ex + "\n");
2487 } catch (Exception ex)
2489 System.err.println("Parsing as Jalview Version 2 file failed.");
2490 ex.printStackTrace(System.err);
2491 if (attemptversion1parse)
2493 // Is Version 1 Jar file?
2496 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2497 } catch (Exception ex2)
2499 System.err.println("Exception whilst loading as jalviewXMLV1:");
2500 ex2.printStackTrace();
2504 if (Desktop.instance != null)
2506 Desktop.instance.stopLoading();
2510 System.out.println("Successfully loaded archive file");
2513 ex.printStackTrace();
2516 "Exception whilst loading jalview XML file : " + ex + "\n");
2517 } catch (OutOfMemoryError e)
2519 // Don't use the OOM Window here
2520 errorMessage = "Out of memory loading jalview XML file";
2521 System.err.println("Out of memory whilst loading jalview XML file");
2522 e.printStackTrace();
2526 * Regather multiple views (with the same sequence set id) to the frame (if
2527 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2528 * views instead of separate frames. Note this doesn't restore a state where
2529 * some expanded views in turn have tabbed views - the last "first tab" read
2530 * in will play the role of gatherer for all.
2532 for (AlignFrame fr : gatherToThisFrame.values())
2534 Desktop.instance.gatherViews(fr);
2537 restoreSplitFrames();
2538 for (AlignmentI ds : importedDatasets.keySet())
2540 if (ds.getCodonFrames() != null)
2542 StructureSelectionManager
2543 .getStructureSelectionManager(Desktop.instance)
2544 .registerMappings(ds.getCodonFrames());
2547 if (errorMessage != null)
2552 if (Desktop.instance != null)
2554 Desktop.instance.stopLoading();
2561 * Try to reconstruct and display SplitFrame windows, where each contains
2562 * complementary dna and protein alignments. Done by pairing up AlignFrame
2563 * objects (created earlier) which have complementary viewport ids associated.
2565 protected void restoreSplitFrames()
2567 List<SplitFrame> gatherTo = new ArrayList<>();
2568 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2569 Map<String, AlignFrame> dna = new HashMap<>();
2572 * Identify the DNA alignments
2574 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2577 AlignFrame af = candidate.getValue();
2578 if (af.getViewport().getAlignment().isNucleotide())
2580 dna.put(candidate.getKey().getId(), af);
2585 * Try to match up the protein complements
2587 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2590 AlignFrame af = candidate.getValue();
2591 if (!af.getViewport().getAlignment().isNucleotide())
2593 String complementId = candidate.getKey().getComplementId();
2594 // only non-null complements should be in the Map
2595 if (complementId != null && dna.containsKey(complementId))
2597 final AlignFrame dnaFrame = dna.get(complementId);
2598 SplitFrame sf = createSplitFrame(dnaFrame, af);
2599 addedToSplitFrames.add(dnaFrame);
2600 addedToSplitFrames.add(af);
2601 dnaFrame.setMenusForViewport();
2602 af.setMenusForViewport();
2603 if (af.viewport.isGatherViewsHere())
2612 * Open any that we failed to pair up (which shouldn't happen!) as
2613 * standalone AlignFrame's.
2615 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2618 AlignFrame af = candidate.getValue();
2619 if (!addedToSplitFrames.contains(af))
2621 Viewport view = candidate.getKey();
2622 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2624 af.setMenusForViewport();
2625 System.err.println("Failed to restore view " + view.getTitle()
2626 + " to split frame");
2631 * Gather back into tabbed views as flagged.
2633 for (SplitFrame sf : gatherTo)
2635 Desktop.instance.gatherViews(sf);
2638 splitFrameCandidates.clear();
2642 * Construct and display one SplitFrame holding DNA and protein alignments.
2645 * @param proteinFrame
2648 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2649 AlignFrame proteinFrame)
2651 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2652 String title = MessageManager.getString("label.linked_view_title");
2653 int width = (int) dnaFrame.getBounds().getWidth();
2654 int height = (int) (dnaFrame.getBounds().getHeight()
2655 + proteinFrame.getBounds().getHeight() + 50);
2658 * SplitFrame location is saved to both enclosed frames
2660 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2661 Desktop.addInternalFrame(splitFrame, title, width, height);
2664 * And compute cDNA consensus (couldn't do earlier with consensus as
2665 * mappings were not yet present)
2667 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2673 * check errorMessage for a valid error message and raise an error box in the
2674 * GUI or write the current errorMessage to stderr and then clear the error
2677 protected void reportErrors()
2679 reportErrors(false);
2682 protected void reportErrors(final boolean saving)
2684 if (errorMessage != null)
2686 final String finalErrorMessage = errorMessage;
2689 javax.swing.SwingUtilities.invokeLater(new Runnable()
2694 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2696 "Error " + (saving ? "saving" : "loading")
2698 JvOptionPane.WARNING_MESSAGE);
2704 System.err.println("Problem loading Jalview file: " + errorMessage);
2707 errorMessage = null;
2710 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2713 * when set, local views will be updated from view stored in JalviewXML
2714 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2715 * sync if this is set to true.
2717 private final boolean updateLocalViews = false;
2720 * Returns the path to a temporary file holding the PDB file for the given PDB
2721 * id. The first time of asking, searches for a file of that name in the
2722 * Jalview project jar, and copies it to a new temporary file. Any repeat
2723 * requests just return the path to the file previously created.
2729 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2732 if (alreadyLoadedPDB.containsKey(pdbId))
2734 return alreadyLoadedPDB.get(pdbId).toString();
2737 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2739 if (tempFile != null)
2741 alreadyLoadedPDB.put(pdbId, tempFile);
2747 * Copies the jar entry of given name to a new temporary file and returns the
2748 * path to the file, or null if the entry is not found.
2751 * @param jarEntryName
2753 * a prefix for the temporary file name, must be at least three
2756 * null or original file - so new file can be given the same suffix
2760 protected String copyJarEntry(jarInputStreamProvider jprovider,
2761 String jarEntryName, String prefix, String origFile)
2763 BufferedReader in = null;
2764 PrintWriter out = null;
2765 String suffix = ".tmp";
2766 if (origFile == null)
2768 origFile = jarEntryName;
2770 int sfpos = origFile.lastIndexOf(".");
2771 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2773 suffix = "." + origFile.substring(sfpos + 1);
2777 JarInputStream jin = jprovider.getJarInputStream();
2779 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2780 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2781 * FileInputStream(jprovider)); }
2784 JarEntry entry = null;
2787 entry = jin.getNextJarEntry();
2788 } while (entry != null && !entry.getName().equals(jarEntryName));
2791 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2792 File outFile = File.createTempFile(prefix, suffix);
2793 outFile.deleteOnExit();
2794 out = new PrintWriter(new FileOutputStream(outFile));
2797 while ((data = in.readLine()) != null)
2802 String t = outFile.getAbsolutePath();
2807 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2809 } catch (Exception ex)
2811 ex.printStackTrace();
2819 } catch (IOException e)
2833 private class JvAnnotRow
2835 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2842 * persisted version of annotation row from which to take vis properties
2844 public jalview.datamodel.AlignmentAnnotation template;
2847 * original position of the annotation row in the alignment
2853 * Load alignment frame from jalview XML DOM object
2858 * filename source string
2859 * @param loadTreesAndStructures
2860 * when false only create Viewport
2862 * data source provider
2863 * @return alignment frame created from view stored in DOM
2865 AlignFrame loadFromObject(JalviewModel object, String file,
2866 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2868 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2869 Sequence[] vamsasSeq = vamsasSet.getSequence();
2871 JalviewModelSequence jms = object.getJalviewModelSequence();
2873 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2876 // ////////////////////////////////
2877 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
2880 // If we just load in the same jar file again, the sequenceSetId
2881 // will be the same, and we end up with multiple references
2882 // to the same sequenceSet. We must modify this id on load
2883 // so that each load of the file gives a unique id
2886 * used to resolve correct alignment dataset for alignments with multiple
2889 String uniqueSeqSetId = null;
2890 String viewId = null;
2893 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
2894 viewId = (view.getId() == null ? null
2895 : view.getId() + uniqueSetSuffix);
2898 // ////////////////////////////////
2901 List<SequenceI> hiddenSeqs = null;
2903 List<SequenceI> tmpseqs = new ArrayList<>();
2905 boolean multipleView = false;
2906 SequenceI referenceseqForView = null;
2907 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2908 int vi = 0; // counter in vamsasSeq array
2909 for (int i = 0; i < jseqs.length; i++)
2911 String seqId = jseqs[i].getId();
2913 SequenceI tmpSeq = seqRefIds.get(seqId);
2916 if (!incompleteSeqs.containsKey(seqId))
2918 // may not need this check, but keep it for at least 2.9,1 release
2919 if (tmpSeq.getStart() != jseqs[i].getStart()
2920 || tmpSeq.getEnd() != jseqs[i].getEnd())
2923 "Warning JAL-2154 regression: updating start/end for sequence "
2924 + tmpSeq.toString() + " to " + jseqs[i]);
2929 incompleteSeqs.remove(seqId);
2931 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2933 // most likely we are reading a dataset XML document so
2934 // update from vamsasSeq section of XML for this sequence
2935 tmpSeq.setName(vamsasSeq[vi].getName());
2936 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2937 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2942 // reading multiple views, so vamsasSeq set is a subset of JSeq
2943 multipleView = true;
2945 tmpSeq.setStart(jseqs[i].getStart());
2946 tmpSeq.setEnd(jseqs[i].getEnd());
2947 tmpseqs.add(tmpSeq);
2951 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2952 vamsasSeq[vi].getSequence());
2953 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2954 tmpSeq.setStart(jseqs[i].getStart());
2955 tmpSeq.setEnd(jseqs[i].getEnd());
2956 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2957 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2958 tmpseqs.add(tmpSeq);
2962 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2964 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2967 if (jseqs[i].getHidden())
2969 if (hiddenSeqs == null)
2971 hiddenSeqs = new ArrayList<>();
2974 hiddenSeqs.add(tmpSeq);
2979 // Create the alignment object from the sequence set
2980 // ///////////////////////////////
2981 SequenceI[] orderedSeqs = tmpseqs
2982 .toArray(new SequenceI[tmpseqs.size()]);
2984 AlignmentI al = null;
2985 // so we must create or recover the dataset alignment before going further
2986 // ///////////////////////////////
2987 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2989 // older jalview projects do not have a dataset - so creat alignment and
2991 al = new Alignment(orderedSeqs);
2992 al.setDataset(null);
2996 boolean isdsal = object.getJalviewModelSequence()
2997 .getViewportCount() == 0;
3000 // we are importing a dataset record, so
3001 // recover reference to an alignment already materialsed as dataset
3002 al = getDatasetFor(vamsasSet.getDatasetId());
3006 // materialse the alignment
3007 al = new Alignment(orderedSeqs);
3011 addDatasetRef(vamsasSet.getDatasetId(), al);
3014 // finally, verify all data in vamsasSet is actually present in al
3015 // passing on flag indicating if it is actually a stored dataset
3016 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3019 if (referenceseqForView != null)
3021 al.setSeqrep(referenceseqForView);
3023 // / Add the alignment properties
3024 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3026 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3027 al.setProperty(ssp.getKey(), ssp.getValue());
3030 // ///////////////////////////////
3032 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3035 // load sequence features, database references and any associated PDB
3036 // structures for the alignment
3038 // prior to 2.10, this part would only be executed the first time a
3039 // sequence was encountered, but not afterwards.
3040 // now, for 2.10 projects, this is also done if the xml doc includes
3041 // dataset sequences not actually present in any particular view.
3043 for (int i = 0; i < vamsasSeq.length; i++)
3045 if (jseqs[i].getFeaturesCount() > 0)
3047 Features[] features = jseqs[i].getFeatures();
3048 for (int f = 0; f < features.length; f++)
3050 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3051 features[f].getDescription(), features[f].getBegin(),
3052 features[f].getEnd(), features[f].getScore(),
3053 features[f].getFeatureGroup());
3054 sf.setStatus(features[f].getStatus());
3057 * load any feature attributes - include map-valued attributes
3059 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3060 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3062 OtherData keyValue = features[f].getOtherData(od);
3063 String attributeName = keyValue.getKey();
3064 String attributeValue = keyValue.getValue();
3065 if (attributeName.startsWith("LINK"))
3067 sf.addLink(attributeValue);
3071 String subAttribute = keyValue.getKey2();
3072 if (subAttribute == null)
3074 // simple string-valued attribute
3075 sf.setValue(attributeName, attributeValue);
3079 // attribute 'key' has sub-attribute 'key2'
3080 if (!mapAttributes.containsKey(attributeName))
3082 mapAttributes.put(attributeName, new HashMap<>());
3084 mapAttributes.get(attributeName).put(subAttribute,
3089 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3092 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3095 // adds feature to datasequence's feature set (since Jalview 2.10)
3096 al.getSequenceAt(i).addSequenceFeature(sf);
3099 if (vamsasSeq[i].getDBRefCount() > 0)
3101 // adds dbrefs to datasequence's set (since Jalview 2.10)
3103 al.getSequenceAt(i).getDatasetSequence() == null
3104 ? al.getSequenceAt(i)
3105 : al.getSequenceAt(i).getDatasetSequence(),
3108 if (jseqs[i].getPdbidsCount() > 0)
3110 Pdbids[] ids = jseqs[i].getPdbids();
3111 for (int p = 0; p < ids.length; p++)
3113 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3114 entry.setId(ids[p].getId());
3115 if (ids[p].getType() != null)
3117 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3119 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3123 entry.setType(PDBEntry.Type.FILE);
3126 // jprovider is null when executing 'New View'
3127 if (ids[p].getFile() != null && jprovider != null)
3129 if (!pdbloaded.containsKey(ids[p].getFile()))
3131 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3136 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3139 if (ids[p].getPdbentryItem() != null)
3141 for (PdbentryItem item : ids[p].getPdbentryItem())
3143 for (Property pr : item.getProperty())
3145 entry.setProperty(pr.getName(), pr.getValue());
3149 StructureSelectionManager
3150 .getStructureSelectionManager(Desktop.instance)
3151 .registerPDBEntry(entry);
3152 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3153 if (al.getSequenceAt(i).getDatasetSequence() != null)
3155 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3159 al.getSequenceAt(i).addPDBId(entry);
3164 } // end !multipleview
3166 // ///////////////////////////////
3167 // LOAD SEQUENCE MAPPINGS
3169 if (vamsasSet.getAlcodonFrameCount() > 0)
3171 // TODO Potentially this should only be done once for all views of an
3173 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3174 for (int i = 0; i < alc.length; i++)
3176 AlignedCodonFrame cf = new AlignedCodonFrame();
3177 if (alc[i].getAlcodMapCount() > 0)
3179 AlcodMap[] maps = alc[i].getAlcodMap();
3180 for (int m = 0; m < maps.length; m++)
3182 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3184 jalview.datamodel.Mapping mapping = null;
3185 // attach to dna sequence reference.
3186 if (maps[m].getMapping() != null)
3188 mapping = addMapping(maps[m].getMapping());
3189 if (dnaseq != null && mapping.getTo() != null)
3191 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3197 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3201 al.addCodonFrame(cf);
3206 // ////////////////////////////////
3208 List<JvAnnotRow> autoAlan = new ArrayList<>();
3211 * store any annotations which forward reference a group's ID
3213 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3215 if (vamsasSet.getAnnotationCount() > 0)
3217 Annotation[] an = vamsasSet.getAnnotation();
3219 for (int i = 0; i < an.length; i++)
3221 Annotation annotation = an[i];
3224 * test if annotation is automatically calculated for this view only
3226 boolean autoForView = false;
3227 if (annotation.getLabel().equals("Quality")
3228 || annotation.getLabel().equals("Conservation")
3229 || annotation.getLabel().equals("Consensus"))
3231 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3233 if (!annotation.hasAutoCalculated())
3235 annotation.setAutoCalculated(true);
3238 if (autoForView || (annotation.hasAutoCalculated()
3239 && annotation.isAutoCalculated()))
3241 // remove ID - we don't recover annotation from other views for
3242 // view-specific annotation
3243 annotation.setId(null);
3246 // set visiblity for other annotation in this view
3247 String annotationId = annotation.getId();
3248 if (annotationId != null && annotationIds.containsKey(annotationId))
3250 AlignmentAnnotation jda = annotationIds.get(annotationId);
3251 // in principle Visible should always be true for annotation displayed
3252 // in multiple views
3253 if (annotation.hasVisible())
3255 jda.visible = annotation.getVisible();
3258 al.addAnnotation(jda);
3262 // Construct new annotation from model.
3263 AnnotationElement[] ae = annotation.getAnnotationElement();
3264 jalview.datamodel.Annotation[] anot = null;
3265 java.awt.Color firstColour = null;
3267 if (!annotation.getScoreOnly())
3269 anot = new jalview.datamodel.Annotation[al.getWidth()];
3270 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3272 anpos = ae[aa].getPosition();
3274 if (anpos >= anot.length)
3279 anot[anpos] = new jalview.datamodel.Annotation(
3281 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3282 (ae[aa].getSecondaryStructure() == null
3283 || ae[aa].getSecondaryStructure().length() == 0)
3285 : ae[aa].getSecondaryStructure()
3290 // JBPNote: Consider verifying dataflow for IO of secondary
3291 // structure annotation read from Stockholm files
3292 // this was added to try to ensure that
3293 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3295 // anot[ae[aa].getPosition()].displayCharacter = "";
3297 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3298 if (firstColour == null)
3300 firstColour = anot[anpos].colour;
3304 jalview.datamodel.AlignmentAnnotation jaa = null;
3306 if (annotation.getGraph())
3308 float llim = 0, hlim = 0;
3309 // if (autoForView || an[i].isAutoCalculated()) {
3312 jaa = new jalview.datamodel.AlignmentAnnotation(
3313 annotation.getLabel(), annotation.getDescription(), anot,
3314 llim, hlim, annotation.getGraphType());
3316 jaa.graphGroup = annotation.getGraphGroup();
3317 jaa._linecolour = firstColour;
3318 if (annotation.getThresholdLine() != null)
3320 jaa.setThreshold(new jalview.datamodel.GraphLine(
3321 annotation.getThresholdLine().getValue(),
3322 annotation.getThresholdLine().getLabel(),
3324 annotation.getThresholdLine().getColour())));
3327 if (autoForView || annotation.isAutoCalculated())
3329 // Hardwire the symbol display line to ensure that labels for
3330 // histograms are displayed
3336 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3337 an[i].getDescription(), anot);
3338 jaa._linecolour = firstColour;
3340 // register new annotation
3341 if (an[i].getId() != null)
3343 annotationIds.put(an[i].getId(), jaa);
3344 jaa.annotationId = an[i].getId();
3346 // recover sequence association
3347 String sequenceRef = an[i].getSequenceRef();
3348 if (sequenceRef != null)
3350 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3351 SequenceI sequence = seqRefIds.get(sequenceRef);
3352 if (sequence == null)
3354 // in pre-2.9 projects sequence ref is to sequence name
3355 sequence = al.findName(sequenceRef);
3357 if (sequence != null)
3359 jaa.createSequenceMapping(sequence, 1, true);
3360 sequence.addAlignmentAnnotation(jaa);
3363 // and make a note of any group association
3364 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3366 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3367 .get(an[i].getGroupRef());
3370 aal = new ArrayList<>();
3371 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3376 if (an[i].hasScore())
3378 jaa.setScore(an[i].getScore());
3380 if (an[i].hasVisible())
3382 jaa.visible = an[i].getVisible();
3385 if (an[i].hasCentreColLabels())
3387 jaa.centreColLabels = an[i].getCentreColLabels();
3390 if (an[i].hasScaleColLabels())
3392 jaa.scaleColLabel = an[i].getScaleColLabels();
3394 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3396 // newer files have an 'autoCalculated' flag and store calculation
3397 // state in viewport properties
3398 jaa.autoCalculated = true; // means annotation will be marked for
3399 // update at end of load.
3401 if (an[i].hasGraphHeight())
3403 jaa.graphHeight = an[i].getGraphHeight();
3405 if (an[i].hasBelowAlignment())
3407 jaa.belowAlignment = an[i].isBelowAlignment();
3409 jaa.setCalcId(an[i].getCalcId());
3410 if (an[i].getPropertyCount() > 0)
3412 for (jalview.schemabinding.version2.Property prop : an[i]
3415 jaa.setProperty(prop.getName(), prop.getValue());
3418 if (jaa.autoCalculated)
3420 autoAlan.add(new JvAnnotRow(i, jaa));
3423 // if (!autoForView)
3425 // add autocalculated group annotation and any user created annotation
3427 al.addAnnotation(jaa);
3431 // ///////////////////////
3433 // Create alignment markup and styles for this view
3434 if (jms.getJGroupCount() > 0)
3436 JGroup[] groups = jms.getJGroup();
3437 boolean addAnnotSchemeGroup = false;
3438 for (int i = 0; i < groups.length; i++)
3440 JGroup jGroup = groups[i];
3441 ColourSchemeI cs = null;
3442 if (jGroup.getColour() != null)
3444 if (jGroup.getColour().startsWith("ucs"))
3446 cs = getUserColourScheme(jms, jGroup.getColour());
3448 else if (jGroup.getColour().equals("AnnotationColourGradient")
3449 && jGroup.getAnnotationColours() != null)
3451 addAnnotSchemeGroup = true;
3455 cs = ColourSchemeProperty.getColourScheme(al,
3456 jGroup.getColour());
3459 int pidThreshold = jGroup.getPidThreshold();
3461 Vector<SequenceI> seqs = new Vector<>();
3463 for (int s = 0; s < jGroup.getSeqCount(); s++)
3465 String seqId = jGroup.getSeq(s) + "";
3466 SequenceI ts = seqRefIds.get(seqId);
3470 seqs.addElement(ts);
3474 if (seqs.size() < 1)
3479 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3480 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3481 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3482 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3483 sg.getGroupColourScheme()
3484 .setConservationInc(jGroup.getConsThreshold());
3485 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3487 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3488 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3489 sg.setShowNonconserved(
3490 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3492 sg.thresholdTextColour = jGroup.getTextColThreshold();
3493 if (jGroup.hasShowConsensusHistogram())
3495 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3498 if (jGroup.hasShowSequenceLogo())
3500 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3502 if (jGroup.hasNormaliseSequenceLogo())
3504 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3506 if (jGroup.hasIgnoreGapsinConsensus())
3508 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3510 if (jGroup.getConsThreshold() != 0)
3512 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3515 c.verdict(false, 25);
3516 sg.cs.setConservation(c);
3519 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3521 // re-instate unique group/annotation row reference
3522 List<AlignmentAnnotation> jaal = groupAnnotRefs
3523 .get(jGroup.getId());
3526 for (AlignmentAnnotation jaa : jaal)
3529 if (jaa.autoCalculated)
3531 // match up and try to set group autocalc alignment row for this
3533 if (jaa.label.startsWith("Consensus for "))
3535 sg.setConsensus(jaa);
3537 // match up and try to set group autocalc alignment row for this
3539 if (jaa.label.startsWith("Conservation for "))
3541 sg.setConservationRow(jaa);
3548 if (addAnnotSchemeGroup)
3550 // reconstruct the annotation colourscheme
3551 sg.setColourScheme(constructAnnotationColour(
3552 jGroup.getAnnotationColours(), null, al, jms, false));
3558 // only dataset in this model, so just return.
3561 // ///////////////////////////////
3564 AlignFrame af = null;
3565 AlignViewport av = null;
3566 // now check to see if we really need to create a new viewport.
3567 if (multipleView && viewportsAdded.size() == 0)
3569 // We recovered an alignment for which a viewport already exists.
3570 // TODO: fix up any settings necessary for overlaying stored state onto
3571 // state recovered from another document. (may not be necessary).
3572 // we may need a binding from a viewport in memory to one recovered from
3574 // and then recover its containing af to allow the settings to be applied.
3575 // TODO: fix for vamsas demo
3577 "About to recover a viewport for existing alignment: Sequence set ID is "
3579 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3580 if (seqsetobj != null)
3582 if (seqsetobj instanceof String)
3584 uniqueSeqSetId = (String) seqsetobj;
3586 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3592 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3598 * indicate that annotation colours are applied across all groups (pre
3599 * Jalview 2.8.1 behaviour)
3601 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3602 object.getVersion());
3604 AlignmentPanel ap = null;
3605 boolean isnewview = true;
3608 // Check to see if this alignment already has a view id == viewId
3609 jalview.gui.AlignmentPanel views[] = Desktop
3610 .getAlignmentPanels(uniqueSeqSetId);
3611 if (views != null && views.length > 0)
3613 for (int v = 0; v < views.length; v++)
3615 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3617 // recover the existing alignpanel, alignframe, viewport
3618 af = views[v].alignFrame;
3621 // TODO: could even skip resetting view settings if we don't want to
3622 // change the local settings from other jalview processes
3631 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3632 uniqueSeqSetId, viewId, autoAlan);
3638 * Load any trees, PDB structures and viewers
3640 * Not done if flag is false (when this method is used for New View)
3642 if (loadTreesAndStructures)
3644 loadTrees(jms, view, af, av, ap);
3645 loadPDBStructures(jprovider, jseqs, af, ap);
3646 loadRnaViewers(jprovider, jseqs, ap);
3648 // and finally return.
3653 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3654 * panel is restored from separate jar entries, two (gapped and trimmed) per
3655 * sequence and secondary structure.
3657 * Currently each viewer shows just one sequence and structure (gapped and
3658 * trimmed), however this method is designed to support multiple sequences or
3659 * structures in viewers if wanted in future.
3665 private void loadRnaViewers(jarInputStreamProvider jprovider,
3666 JSeq[] jseqs, AlignmentPanel ap)
3669 * scan the sequences for references to viewers; create each one the first
3670 * time it is referenced, add Rna models to existing viewers
3672 for (JSeq jseq : jseqs)
3674 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3676 RnaViewer viewer = jseq.getRnaViewer(i);
3677 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3680 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3682 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3683 SequenceI seq = seqRefIds.get(jseq.getId());
3684 AlignmentAnnotation ann = this.annotationIds
3685 .get(ss.getAnnotationId());
3688 * add the structure to the Varna display (with session state copied
3689 * from the jar to a temporary file)
3691 boolean gapped = ss.isGapped();
3692 String rnaTitle = ss.getTitle();
3693 String sessionState = ss.getViewerState();
3694 String tempStateFile = copyJarEntry(jprovider, sessionState,
3696 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3697 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3699 appVarna.setInitialSelection(viewer.getSelectedRna());
3705 * Locate and return an already instantiated matching AppVarna, or create one
3709 * @param viewIdSuffix
3713 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3714 String viewIdSuffix, AlignmentPanel ap)
3717 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3718 * if load is repeated
3720 String postLoadId = viewer.getViewId() + viewIdSuffix;
3721 for (JInternalFrame frame : getAllFrames())
3723 if (frame instanceof AppVarna)
3725 AppVarna varna = (AppVarna) frame;
3726 if (postLoadId.equals(varna.getViewId()))
3728 // this viewer is already instantiated
3729 // could in future here add ap as another 'parent' of the
3730 // AppVarna window; currently just 1-to-many
3737 * viewer not found - make it
3739 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3740 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3741 viewer.getHeight(), viewer.getDividerLocation());
3742 AppVarna varna = new AppVarna(model, ap);
3748 * Load any saved trees
3756 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3757 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3759 // TODO result of automated refactoring - are all these parameters needed?
3762 for (int t = 0; t < jms.getTreeCount(); t++)
3765 Tree tree = jms.getTree(t);
3767 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3770 tp = af.showNewickTree(
3771 new jalview.io.NewickFile(tree.getNewick()),
3772 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3773 tree.getXpos(), tree.getYpos());
3774 if (tree.getId() != null)
3776 // perhaps bind the tree id to something ?
3781 // update local tree attributes ?
3782 // TODO: should check if tp has been manipulated by user - if so its
3783 // settings shouldn't be modified
3784 tp.setTitle(tree.getTitle());
3785 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3786 tree.getWidth(), tree.getHeight()));
3787 tp.setViewport(av); // af.viewport; // TODO: verify 'associate with all
3790 tp.getTreeCanvas().setViewport(av); // af.viewport;
3791 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
3796 warn("There was a problem recovering stored Newick tree: \n"
3797 + tree.getNewick());
3801 tp.fitToWindow.setState(tree.getFitToWindow());
3802 tp.fitToWindow_actionPerformed(null);
3804 if (tree.getFontName() != null)
3806 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3807 tree.getFontStyle(), tree.getFontSize()));
3811 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3812 view.getFontStyle(), tree.getFontSize()));
3815 tp.showPlaceholders(tree.getMarkUnlinked());
3816 tp.showBootstrap(tree.getShowBootstrap());
3817 tp.showDistances(tree.getShowDistances());
3819 tp.getTreeCanvas().setThreshold(tree.getThreshold());
3821 if (tree.getCurrentTree())
3823 af.viewport.setCurrentTree(tp.getTree());
3827 } catch (Exception ex)
3829 ex.printStackTrace();
3834 * Load and link any saved structure viewers.
3841 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3842 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3845 * Run through all PDB ids on the alignment, and collect mappings between
3846 * distinct view ids and all sequences referring to that view.
3848 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3850 for (int i = 0; i < jseqs.length; i++)
3852 if (jseqs[i].getPdbidsCount() > 0)
3854 Pdbids[] ids = jseqs[i].getPdbids();
3855 for (int p = 0; p < ids.length; p++)
3857 final int structureStateCount = ids[p].getStructureStateCount();
3858 for (int s = 0; s < structureStateCount; s++)
3860 // check to see if we haven't already created this structure view
3861 final StructureState structureState = ids[p]
3862 .getStructureState(s);
3863 String sviewid = (structureState.getViewId() == null) ? null
3864 : structureState.getViewId() + uniqueSetSuffix;
3865 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3866 // Originally : ids[p].getFile()
3867 // : TODO: verify external PDB file recovery still works in normal
3868 // jalview project load
3869 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3871 jpdb.setId(ids[p].getId());
3873 int x = structureState.getXpos();
3874 int y = structureState.getYpos();
3875 int width = structureState.getWidth();
3876 int height = structureState.getHeight();
3878 // Probably don't need to do this anymore...
3879 // Desktop.desktop.getComponentAt(x, y);
3880 // TODO: NOW: check that this recovers the PDB file correctly.
3881 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3883 jalview.datamodel.SequenceI seq = seqRefIds
3884 .get(jseqs[i].getId() + "");
3885 if (sviewid == null)
3887 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3890 if (!structureViewers.containsKey(sviewid))
3892 structureViewers.put(sviewid,
3893 new StructureViewerModel(x, y, width, height, false,
3894 false, true, structureState.getViewId(),
3895 structureState.getType()));
3896 // Legacy pre-2.7 conversion JAL-823 :
3897 // do not assume any view has to be linked for colour by
3901 // assemble String[] { pdb files }, String[] { id for each
3902 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3903 // seqs_file 2}, boolean[] {
3904 // linkAlignPanel,superposeWithAlignpanel}} from hash
3905 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3906 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3907 | (structureState.hasAlignwithAlignPanel()
3908 ? structureState.getAlignwithAlignPanel()
3912 * Default colour by linked panel to false if not specified (e.g.
3913 * for pre-2.7 projects)
3915 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3916 colourWithAlignPanel |= (structureState
3917 .hasColourwithAlignPanel()
3918 ? structureState.getColourwithAlignPanel()
3920 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3923 * Default colour by viewer to true if not specified (e.g. for
3926 boolean colourByViewer = jmoldat.isColourByViewer();
3927 colourByViewer &= structureState.hasColourByJmol()
3928 ? structureState.getColourByJmol()
3930 jmoldat.setColourByViewer(colourByViewer);
3932 if (jmoldat.getStateData().length() < structureState
3933 .getContent().length())
3936 jmoldat.setStateData(structureState.getContent());
3939 if (ids[p].getFile() != null)
3941 File mapkey = new File(ids[p].getFile());
3942 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3943 if (seqstrmaps == null)
3945 jmoldat.getFileData().put(mapkey,
3946 seqstrmaps = jmoldat.new StructureData(pdbFile,
3949 if (!seqstrmaps.getSeqList().contains(seq))
3951 seqstrmaps.getSeqList().add(seq);
3957 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");
3964 // Instantiate the associated structure views
3965 for (Entry<String, StructureViewerModel> entry : structureViewers
3970 createOrLinkStructureViewer(entry, af, ap, jprovider);
3971 } catch (Exception e)
3974 "Error loading structure viewer: " + e.getMessage());
3975 // failed - try the next one
3987 protected void createOrLinkStructureViewer(
3988 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3989 AlignmentPanel ap, jarInputStreamProvider jprovider)
3991 final StructureViewerModel stateData = viewerData.getValue();
3994 * Search for any viewer windows already open from other alignment views
3995 * that exactly match the stored structure state
3997 StructureViewerBase comp = findMatchingViewer(viewerData);
4001 linkStructureViewer(ap, comp, stateData);
4006 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4007 * "viewer_"+stateData.viewId
4009 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4011 createChimeraViewer(viewerData, af, jprovider);
4016 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4018 createJmolViewer(viewerData, af, jprovider);
4023 * Create a new Chimera viewer.
4029 protected void createChimeraViewer(
4030 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4031 jarInputStreamProvider jprovider)
4033 StructureViewerModel data = viewerData.getValue();
4034 String chimeraSessionFile = data.getStateData();
4037 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4039 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4040 * 'uniquified' sviewid used to reconstruct the viewer here
4042 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4043 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4046 Set<Entry<File, StructureData>> fileData = data.getFileData()
4048 List<PDBEntry> pdbs = new ArrayList<>();
4049 List<SequenceI[]> allseqs = new ArrayList<>();
4050 for (Entry<File, StructureData> pdb : fileData)
4052 String filePath = pdb.getValue().getFilePath();
4053 String pdbId = pdb.getValue().getPdbId();
4054 // pdbs.add(new PDBEntry(filePath, pdbId));
4055 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4056 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4057 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4061 boolean colourByChimera = data.isColourByViewer();
4062 boolean colourBySequence = data.isColourWithAlignPanel();
4064 // TODO use StructureViewer as a factory here, see JAL-1761
4065 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4066 final SequenceI[][] seqsArray = allseqs
4067 .toArray(new SequenceI[allseqs.size()][]);
4068 String newViewId = viewerData.getKey();
4070 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4071 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4072 colourBySequence, newViewId);
4073 cvf.setSize(data.getWidth(), data.getHeight());
4074 cvf.setLocation(data.getX(), data.getY());
4078 * Create a new Jmol window. First parse the Jmol state to translate filenames
4079 * loaded into the view, and record the order in which files are shown in the
4080 * Jmol view, so we can add the sequence mappings in same order.
4086 protected void createJmolViewer(
4087 final Entry<String, StructureViewerModel> viewerData,
4088 AlignFrame af, jarInputStreamProvider jprovider)
4090 final StructureViewerModel svattrib = viewerData.getValue();
4091 String state = svattrib.getStateData();
4094 * Pre-2.9: state element value is the Jmol state string
4096 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4099 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4101 state = readJarEntry(jprovider,
4102 getViewerJarEntryName(svattrib.getViewId()));
4105 List<String> pdbfilenames = new ArrayList<>();
4106 List<SequenceI[]> seqmaps = new ArrayList<>();
4107 List<String> pdbids = new ArrayList<>();
4108 StringBuilder newFileLoc = new StringBuilder(64);
4109 int cp = 0, ncp, ecp;
4110 Map<File, StructureData> oldFiles = svattrib.getFileData();
4111 while ((ncp = state.indexOf("load ", cp)) > -1)
4115 // look for next filename in load statement
4116 newFileLoc.append(state.substring(cp,
4117 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4118 String oldfilenam = state.substring(ncp,
4119 ecp = state.indexOf("\"", ncp));
4120 // recover the new mapping data for this old filename
4121 // have to normalize filename - since Jmol and jalview do
4123 // translation differently.
4124 StructureData filedat = oldFiles.get(new File(oldfilenam));
4125 if (filedat == null)
4127 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4128 filedat = oldFiles.get(new File(reformatedOldFilename));
4130 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4131 pdbfilenames.add(filedat.getFilePath());
4132 pdbids.add(filedat.getPdbId());
4133 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4134 newFileLoc.append("\"");
4135 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4136 // look for next file statement.
4137 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4141 // just append rest of state
4142 newFileLoc.append(state.substring(cp));
4146 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4147 newFileLoc = new StringBuilder(state);
4148 newFileLoc.append("; load append ");
4149 for (File id : oldFiles.keySet())
4151 // add this and any other pdb files that should be present in
4153 StructureData filedat = oldFiles.get(id);
4154 newFileLoc.append(filedat.getFilePath());
4155 pdbfilenames.add(filedat.getFilePath());
4156 pdbids.add(filedat.getPdbId());
4157 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4158 newFileLoc.append(" \"");
4159 newFileLoc.append(filedat.getFilePath());
4160 newFileLoc.append("\"");
4163 newFileLoc.append(";");
4166 if (newFileLoc.length() == 0)
4170 int histbug = newFileLoc.indexOf("history = ");
4174 * change "history = [true|false];" to "history = [1|0];"
4177 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4178 String val = (diff == -1) ? null
4179 : newFileLoc.substring(histbug, diff);
4180 if (val != null && val.length() >= 4)
4182 if (val.contains("e")) // eh? what can it be?
4184 if (val.trim().equals("true"))
4192 newFileLoc.replace(histbug, diff, val);
4197 final String[] pdbf = pdbfilenames
4198 .toArray(new String[pdbfilenames.size()]);
4199 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4200 final SequenceI[][] sq = seqmaps
4201 .toArray(new SequenceI[seqmaps.size()][]);
4202 final String fileloc = newFileLoc.toString();
4203 final String sviewid = viewerData.getKey();
4204 final AlignFrame alf = af;
4205 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4206 svattrib.getWidth(), svattrib.getHeight());
4209 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4214 JalviewStructureDisplayI sview = null;
4217 sview = new StructureViewer(
4218 alf.alignPanel.getStructureSelectionManager())
4219 .createView(StructureViewer.ViewerType.JMOL,
4220 pdbf, id, sq, alf.alignPanel, svattrib,
4221 fileloc, rect, sviewid);
4222 addNewStructureViewer(sview);
4223 } catch (OutOfMemoryError ex)
4225 new OOMWarning("restoring structure view for PDB id " + id,
4226 (OutOfMemoryError) ex.getCause());
4227 if (sview != null && sview.isVisible())
4229 sview.closeViewer(false);
4230 sview.setVisible(false);
4236 } catch (InvocationTargetException ex)
4238 warn("Unexpected error when opening Jmol view.", ex);
4240 } catch (InterruptedException e)
4242 // e.printStackTrace();
4248 * Generates a name for the entry in the project jar file to hold state
4249 * information for a structure viewer
4254 protected String getViewerJarEntryName(String viewId)
4256 return VIEWER_PREFIX + viewId;
4260 * Returns any open frame that matches given structure viewer data. The match
4261 * is based on the unique viewId, or (for older project versions) the frame's
4267 protected StructureViewerBase findMatchingViewer(
4268 Entry<String, StructureViewerModel> viewerData)
4270 final String sviewid = viewerData.getKey();
4271 final StructureViewerModel svattrib = viewerData.getValue();
4272 StructureViewerBase comp = null;
4273 JInternalFrame[] frames = getAllFrames();
4274 for (JInternalFrame frame : frames)
4276 if (frame instanceof StructureViewerBase)
4279 * Post jalview 2.4 schema includes structure view id
4281 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4284 comp = (StructureViewerBase) frame;
4285 break; // break added in 2.9
4288 * Otherwise test for matching position and size of viewer frame
4290 else if (frame.getX() == svattrib.getX()
4291 && frame.getY() == svattrib.getY()
4292 && frame.getHeight() == svattrib.getHeight()
4293 && frame.getWidth() == svattrib.getWidth())
4295 comp = (StructureViewerBase) frame;
4296 // no break in faint hope of an exact match on viewId
4304 * Link an AlignmentPanel to an existing structure viewer.
4309 * @param useinViewerSuperpos
4310 * @param usetoColourbyseq
4311 * @param viewerColouring
4313 protected void linkStructureViewer(AlignmentPanel ap,
4314 StructureViewerBase viewer, StructureViewerModel stateData)
4316 // NOTE: if the jalview project is part of a shared session then
4317 // view synchronization should/could be done here.
4319 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4320 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4321 final boolean viewerColouring = stateData.isColourByViewer();
4322 Map<File, StructureData> oldFiles = stateData.getFileData();
4325 * Add mapping for sequences in this view to an already open viewer
4327 final AAStructureBindingModel binding = viewer.getBinding();
4328 for (File id : oldFiles.keySet())
4330 // add this and any other pdb files that should be present in the
4332 StructureData filedat = oldFiles.get(id);
4333 String pdbFile = filedat.getFilePath();
4334 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4335 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4337 binding.addSequenceForStructFile(pdbFile, seq);
4339 // and add the AlignmentPanel's reference to the view panel
4340 viewer.addAlignmentPanel(ap);
4341 if (useinViewerSuperpos)
4343 viewer.useAlignmentPanelForSuperposition(ap);
4347 viewer.excludeAlignmentPanelForSuperposition(ap);
4349 if (usetoColourbyseq)
4351 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4355 viewer.excludeAlignmentPanelForColourbyseq(ap);
4360 * Get all frames within the Desktop.
4364 protected JInternalFrame[] getAllFrames()
4366 JInternalFrame[] frames = null;
4367 // TODO is this necessary - is it safe - risk of hanging?
4372 frames = Desktop.desktop.getAllFrames();
4373 } catch (ArrayIndexOutOfBoundsException e)
4375 // occasional No such child exceptions are thrown here...
4379 } catch (InterruptedException f)
4383 } while (frames == null);
4388 * Answers true if 'version' is equal to or later than 'supported', where each
4389 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4390 * changes. Development and test values for 'version' are leniently treated
4394 * - minimum version we are comparing against
4396 * - version of data being processsed
4399 public static boolean isVersionStringLaterThan(String supported,
4402 if (supported == null || version == null
4403 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4404 || version.equalsIgnoreCase("Test")
4405 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4407 System.err.println("Assuming project file with "
4408 + (version == null ? "null" : version)
4409 + " is compatible with Jalview version " + supported);
4414 return StringUtils.compareVersions(version, supported, "b") >= 0;
4418 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4420 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4422 if (newStructureViewers != null)
4424 sview.getBinding().setFinishedLoadingFromArchive(false);
4425 newStructureViewers.add(sview);
4429 protected void setLoadingFinishedForNewStructureViewers()
4431 if (newStructureViewers != null)
4433 for (JalviewStructureDisplayI sview : newStructureViewers)
4435 sview.getBinding().setFinishedLoadingFromArchive(true);
4437 newStructureViewers.clear();
4438 newStructureViewers = null;
4442 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4443 List<SequenceI> hiddenSeqs, AlignmentI al,
4444 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4445 String viewId, List<JvAnnotRow> autoAlan)
4447 AlignFrame af = null;
4448 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4449 uniqueSeqSetId, viewId);
4451 af.setFileName(file, FileFormat.Jalview);
4453 for (int i = 0; i < JSEQ.length; i++)
4455 af.viewport.setSequenceColour(
4456 af.viewport.getAlignment().getSequenceAt(i),
4457 new java.awt.Color(JSEQ[i].getColour()));
4462 af.getViewport().setColourByReferenceSeq(true);
4463 af.getViewport().setDisplayReferenceSeq(true);
4466 af.viewport.setGatherViewsHere(view.getGatheredViews());
4468 if (view.getSequenceSetId() != null)
4470 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4472 af.viewport.setSequenceSetId(uniqueSeqSetId);
4475 // propagate shared settings to this new view
4476 af.viewport.setHistoryList(av.getHistoryList());
4477 af.viewport.setRedoList(av.getRedoList());
4481 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4483 // TODO: check if this method can be called repeatedly without
4484 // side-effects if alignpanel already registered.
4485 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4487 // apply Hidden regions to view.
4488 if (hiddenSeqs != null)
4490 for (int s = 0; s < JSEQ.length; s++)
4492 SequenceGroup hidden = new SequenceGroup();
4493 boolean isRepresentative = false;
4494 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4496 isRepresentative = true;
4497 SequenceI sequenceToHide = al
4498 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4499 hidden.addSequence(sequenceToHide, false);
4500 // remove from hiddenSeqs list so we don't try to hide it twice
4501 hiddenSeqs.remove(sequenceToHide);
4503 if (isRepresentative)
4505 SequenceI representativeSequence = al.getSequenceAt(s);
4506 hidden.addSequence(representativeSequence, false);
4507 af.viewport.hideRepSequences(representativeSequence, hidden);
4511 SequenceI[] hseqs = hiddenSeqs
4512 .toArray(new SequenceI[hiddenSeqs.size()]);
4513 af.viewport.hideSequence(hseqs);
4516 // recover view properties and display parameters
4518 af.viewport.setShowAnnotation(view.getShowAnnotation());
4519 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4520 af.viewport.setThreshold(view.getPidThreshold());
4522 af.viewport.setColourText(view.getShowColourText());
4524 af.viewport.setConservationSelected(view.getConservationSelected());
4525 af.viewport.setIncrement(view.getConsThreshold());
4526 af.viewport.setShowJVSuffix(view.getShowFullId());
4527 af.viewport.setRightAlignIds(view.getRightAlignIds());
4528 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4529 view.getFontStyle(), view.getFontSize()), true);
4530 ViewStyleI vs = af.viewport.getViewStyle();
4531 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4532 af.viewport.setViewStyle(vs);
4533 // TODO: allow custom charWidth/Heights to be restored by updating them
4534 // after setting font - which means set above to false
4535 af.viewport.setRenderGaps(view.getRenderGaps());
4536 af.viewport.setWrapAlignment(view.getWrapAlignment());
4537 af.viewport.setShowAnnotation(view.getShowAnnotation());
4539 af.viewport.setShowBoxes(view.getShowBoxes());
4541 af.viewport.setShowText(view.getShowText());
4543 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4544 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4545 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4546 af.viewport.setShowUnconserved(
4547 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4548 af.viewport.getRanges().setStartRes(view.getStartRes());
4550 if (view.getViewName() != null)
4552 af.viewport.setViewName(view.getViewName());
4553 af.setInitialTabVisible();
4555 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4557 // startSeq set in af.alignPanel.updateLayout below
4558 af.alignPanel.updateLayout();
4559 ColourSchemeI cs = null;
4560 // apply colourschemes
4561 if (view.getBgColour() != null)
4563 if (view.getBgColour().startsWith("ucs"))
4565 cs = getUserColourScheme(jms, view.getBgColour());
4567 else if (view.getBgColour().startsWith("Annotation"))
4569 AnnotationColours viewAnnColour = view.getAnnotationColours();
4570 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4577 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4581 af.viewport.setGlobalColourScheme(cs);
4582 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4583 view.getIgnoreGapsinConsensus());
4584 af.viewport.getResidueShading()
4585 .setConsensus(af.viewport.getSequenceConsensusHash());
4586 af.viewport.setColourAppliesToAllGroups(false);
4588 if (view.getConservationSelected() && cs != null)
4590 af.viewport.getResidueShading()
4591 .setConservationInc(view.getConsThreshold());
4594 af.changeColour(cs);
4596 af.viewport.setColourAppliesToAllGroups(true);
4598 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4600 if (view.hasCentreColumnLabels())
4602 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4604 if (view.hasIgnoreGapsinConsensus())
4606 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4609 if (view.hasFollowHighlight())
4611 af.viewport.setFollowHighlight(view.getFollowHighlight());
4613 if (view.hasFollowSelection())
4615 af.viewport.followSelection = view.getFollowSelection();
4617 if (view.hasShowConsensusHistogram())
4620 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4624 af.viewport.setShowConsensusHistogram(true);
4626 if (view.hasShowSequenceLogo())
4628 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4632 af.viewport.setShowSequenceLogo(false);
4634 if (view.hasNormaliseSequenceLogo())
4636 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4638 if (view.hasShowDbRefTooltip())
4640 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4642 if (view.hasShowNPfeatureTooltip())
4644 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4646 if (view.hasShowGroupConsensus())
4648 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4652 af.viewport.setShowGroupConsensus(false);
4654 if (view.hasShowGroupConservation())
4656 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4660 af.viewport.setShowGroupConservation(false);
4663 // recover feature settings
4664 if (jms.getFeatureSettings() != null)
4666 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4667 .getFeatureRenderer();
4668 FeaturesDisplayed fdi;
4669 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4670 String[] renderOrder = new String[jms.getFeatureSettings()
4671 .getSettingCount()];
4672 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4673 Map<String, Float> featureOrder = new Hashtable<>();
4675 for (int fs = 0; fs < jms.getFeatureSettings()
4676 .getSettingCount(); fs++)
4678 Setting setting = jms.getFeatureSettings().getSetting(fs);
4679 String featureType = setting.getType();
4682 * restore feature filters (if any)
4684 MatcherSet filters = setting.getMatcherSet();
4685 if (filters != null)
4687 FeatureMatcherSetI filter = Jalview2XML
4688 .unmarshalFilter(featureType, filters);
4689 if (!filter.isEmpty())
4691 fr.setFeatureFilter(featureType, filter);
4696 * restore feature colour scheme
4698 Color maxColour = new Color(setting.getColour());
4699 if (setting.hasMincolour())
4702 * minColour is always set unless a simple colour
4703 * (including for colour by label though it doesn't use it)
4705 Color minColour = new Color(setting.getMincolour());
4706 Color noValueColour = minColour;
4707 NoValueColour noColour = setting.getNoValueColour();
4708 if (noColour == NoValueColour.NONE)
4710 noValueColour = null;
4712 else if (noColour == NoValueColour.MAX)
4714 noValueColour = maxColour;
4716 float min = setting.hasMin() ? setting.getMin() : 0f;
4717 float max = setting.hasMin() ? setting.getMax() : 1f;
4718 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4719 noValueColour, min, max);
4720 if (setting.getAttributeNameCount() > 0)
4722 gc.setAttributeName(setting.getAttributeName());
4724 if (setting.hasThreshold())
4726 gc.setThreshold(setting.getThreshold());
4727 int threshstate = setting.getThreshstate();
4728 // -1 = None, 0 = Below, 1 = Above threshold
4729 if (threshstate == 0)
4731 gc.setBelowThreshold(true);
4733 else if (threshstate == 1)
4735 gc.setAboveThreshold(true);
4738 gc.setAutoScaled(true); // default
4739 if (setting.hasAutoScale())
4741 gc.setAutoScaled(setting.getAutoScale());
4743 if (setting.hasColourByLabel())
4745 gc.setColourByLabel(setting.getColourByLabel());
4747 // and put in the feature colour table.
4748 featureColours.put(featureType, gc);
4752 featureColours.put(featureType,
4753 new FeatureColour(maxColour));
4755 renderOrder[fs] = featureType;
4756 if (setting.hasOrder())
4758 featureOrder.put(featureType, setting.getOrder());
4762 featureOrder.put(featureType, new Float(
4763 fs / jms.getFeatureSettings().getSettingCount()));
4765 if (setting.getDisplay())
4767 fdi.setVisible(featureType);
4770 Map<String, Boolean> fgtable = new Hashtable<>();
4771 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4773 Group grp = jms.getFeatureSettings().getGroup(gs);
4774 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4776 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4777 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4778 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4779 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4780 fgtable, featureColours, 1.0f, featureOrder);
4781 fr.transferSettings(frs);
4784 if (view.getHiddenColumnsCount() > 0)
4786 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4788 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4789 view.getHiddenColumns(c).getEnd() // +1
4793 if (view.getCalcIdParam() != null)
4795 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4797 if (calcIdParam != null)
4799 if (recoverCalcIdParam(calcIdParam, af.viewport))
4804 warn("Couldn't recover parameters for "
4805 + calcIdParam.getCalcId());
4810 af.setMenusFromViewport(af.viewport);
4811 af.setTitle(view.getTitle());
4812 // TODO: we don't need to do this if the viewport is aready visible.
4814 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4815 * has a 'cdna/protein complement' view, in which case save it in order to
4816 * populate a SplitFrame once all views have been read in.
4818 String complementaryViewId = view.getComplementId();
4819 if (complementaryViewId == null)
4821 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4823 // recompute any autoannotation
4824 af.alignPanel.updateAnnotation(false, true);
4825 reorderAutoannotation(af, al, autoAlan);
4826 af.alignPanel.alignmentChanged();
4830 splitFrameCandidates.put(view, af);
4836 * Reads saved data to restore Colour by Annotation settings
4838 * @param viewAnnColour
4842 * @param checkGroupAnnColour
4845 private ColourSchemeI constructAnnotationColour(
4846 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4847 JalviewModelSequence jms, boolean checkGroupAnnColour)
4849 boolean propagateAnnColour = false;
4850 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4851 if (checkGroupAnnColour && al.getGroups() != null
4852 && al.getGroups().size() > 0)
4854 // pre 2.8.1 behaviour
4855 // check to see if we should transfer annotation colours
4856 propagateAnnColour = true;
4857 for (SequenceGroup sg : al.getGroups())
4859 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4861 propagateAnnColour = false;
4867 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4869 String annotationId = viewAnnColour.getAnnotation();
4870 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4873 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4875 if (matchedAnnotation == null
4876 && annAlignment.getAlignmentAnnotation() != null)
4878 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4881 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4883 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4888 if (matchedAnnotation == null)
4890 System.err.println("Failed to match annotation colour scheme for "
4894 if (matchedAnnotation.getThreshold() == null)
4896 matchedAnnotation.setThreshold(new GraphLine(
4897 viewAnnColour.getThreshold(), "Threshold", Color.black));
4900 AnnotationColourGradient cs = null;
4901 if (viewAnnColour.getColourScheme().equals("None"))
4903 cs = new AnnotationColourGradient(matchedAnnotation,
4904 new Color(viewAnnColour.getMinColour()),
4905 new Color(viewAnnColour.getMaxColour()),
4906 viewAnnColour.getAboveThreshold());
4908 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4910 cs = new AnnotationColourGradient(matchedAnnotation,
4911 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4912 viewAnnColour.getAboveThreshold());
4916 cs = new AnnotationColourGradient(matchedAnnotation,
4917 ColourSchemeProperty.getColourScheme(al,
4918 viewAnnColour.getColourScheme()),
4919 viewAnnColour.getAboveThreshold());
4922 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4923 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4924 cs.setSeqAssociated(perSequenceOnly);
4925 cs.setPredefinedColours(useOriginalColours);
4927 if (propagateAnnColour && al.getGroups() != null)
4929 // Also use these settings for all the groups
4930 for (int g = 0; g < al.getGroups().size(); g++)
4932 SequenceGroup sg = al.getGroups().get(g);
4933 if (sg.getGroupColourScheme() == null)
4938 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4939 matchedAnnotation, sg.getColourScheme(),
4940 viewAnnColour.getAboveThreshold());
4941 sg.setColourScheme(groupScheme);
4942 groupScheme.setSeqAssociated(perSequenceOnly);
4943 groupScheme.setPredefinedColours(useOriginalColours);
4949 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4950 List<JvAnnotRow> autoAlan)
4952 // copy over visualization settings for autocalculated annotation in the
4954 if (al.getAlignmentAnnotation() != null)
4957 * Kludge for magic autoannotation names (see JAL-811)
4959 String[] magicNames = new String[] { "Consensus", "Quality",
4961 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4962 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4963 for (String nm : magicNames)
4965 visan.put(nm, nullAnnot);
4967 for (JvAnnotRow auan : autoAlan)
4969 visan.put(auan.template.label
4970 + (auan.template.getCalcId() == null ? ""
4971 : "\t" + auan.template.getCalcId()),
4974 int hSize = al.getAlignmentAnnotation().length;
4975 List<JvAnnotRow> reorder = new ArrayList<>();
4976 // work through any autoCalculated annotation already on the view
4977 // removing it if it should be placed in a different location on the
4978 // annotation panel.
4979 List<String> remains = new ArrayList<>(visan.keySet());
4980 for (int h = 0; h < hSize; h++)
4982 jalview.datamodel.AlignmentAnnotation jalan = al
4983 .getAlignmentAnnotation()[h];
4984 if (jalan.autoCalculated)
4987 JvAnnotRow valan = visan.get(k = jalan.label);
4988 if (jalan.getCalcId() != null)
4990 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4995 // delete the auto calculated row from the alignment
4996 al.deleteAnnotation(jalan, false);
5000 if (valan != nullAnnot)
5002 if (jalan != valan.template)
5004 // newly created autoannotation row instance
5005 // so keep a reference to the visible annotation row
5006 // and copy over all relevant attributes
5007 if (valan.template.graphHeight >= 0)
5010 jalan.graphHeight = valan.template.graphHeight;
5012 jalan.visible = valan.template.visible;
5014 reorder.add(new JvAnnotRow(valan.order, jalan));
5019 // Add any (possibly stale) autocalculated rows that were not appended to
5020 // the view during construction
5021 for (String other : remains)
5023 JvAnnotRow othera = visan.get(other);
5024 if (othera != nullAnnot && othera.template.getCalcId() != null
5025 && othera.template.getCalcId().length() > 0)
5027 reorder.add(othera);
5030 // now put the automatic annotation in its correct place
5031 int s = 0, srt[] = new int[reorder.size()];
5032 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5033 for (JvAnnotRow jvar : reorder)
5036 srt[s++] = jvar.order;
5039 jalview.util.QuickSort.sort(srt, rws);
5040 // and re-insert the annotation at its correct position
5041 for (JvAnnotRow jvar : rws)
5043 al.addAnnotation(jvar.template, jvar.order);
5045 af.alignPanel.adjustAnnotationHeight();
5049 Hashtable skipList = null;
5052 * TODO remove this method
5055 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5056 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5057 * throw new Error("Implementation Error. No skipList defined for this
5058 * Jalview2XML instance."); } return (AlignFrame)
5059 * skipList.get(view.getSequenceSetId()); }
5063 * Check if the Jalview view contained in object should be skipped or not.
5066 * @return true if view's sequenceSetId is a key in skipList
5068 private boolean skipViewport(JalviewModel object)
5070 if (skipList == null)
5075 if (skipList.containsKey(
5076 id = object.getJalviewModelSequence().getViewport()[0]
5077 .getSequenceSetId()))
5079 if (Cache.log != null && Cache.log.isDebugEnabled())
5081 Cache.log.debug("Skipping seuqence set id " + id);
5088 public void addToSkipList(AlignFrame af)
5090 if (skipList == null)
5092 skipList = new Hashtable();
5094 skipList.put(af.getViewport().getSequenceSetId(), af);
5097 public void clearSkipList()
5099 if (skipList != null)
5106 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5107 boolean ignoreUnrefed, String uniqueSeqSetId)
5109 jalview.datamodel.AlignmentI ds = getDatasetFor(
5110 vamsasSet.getDatasetId());
5111 Vector dseqs = null;
5116 // try to resolve the dataset via uniqueSeqSetId
5117 ds = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5120 addDatasetRef(vamsasSet.getDatasetId(), ds);
5126 // create a list of new dataset sequences
5127 dseqs = new Vector();
5129 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5131 Sequence vamsasSeq = vamsasSet.getSequence(i);
5132 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5134 // create a new dataset
5137 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5138 dseqs.copyInto(dsseqs);
5139 ds = new jalview.datamodel.Alignment(dsseqs);
5140 debug("Created new dataset " + vamsasSet.getDatasetId()
5141 + " for alignment " + System.identityHashCode(al));
5142 addDatasetRef(vamsasSet.getDatasetId(), ds);
5144 // set the dataset for the newly imported alignment.
5145 if (al.getDataset() == null && !ignoreUnrefed)
5148 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5149 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5156 * sequence definition to create/merge dataset sequence for
5160 * vector to add new dataset sequence to
5161 * @param ignoreUnrefed
5162 * - when true, don't create new sequences from vamsasSeq if it's id
5163 * doesn't already have an asssociated Jalview sequence.
5165 * - used to reorder the sequence in the alignment according to the
5166 * vamsasSeq array ordering, to preserve ordering of dataset
5168 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5169 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5171 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5173 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5174 boolean reorder = false;
5175 SequenceI dsq = null;
5176 if (sq != null && sq.getDatasetSequence() != null)
5178 dsq = sq.getDatasetSequence();
5184 if (sq == null && ignoreUnrefed)
5188 String sqid = vamsasSeq.getDsseqid();
5191 // need to create or add a new dataset sequence reference to this sequence
5194 dsq = seqRefIds.get(sqid);
5199 // make a new dataset sequence
5200 dsq = sq.createDatasetSequence();
5203 // make up a new dataset reference for this sequence
5204 sqid = seqHash(dsq);
5206 dsq.setVamsasId(uniqueSetSuffix + sqid);
5207 seqRefIds.put(sqid, dsq);
5212 dseqs.addElement(dsq);
5217 ds.addSequence(dsq);
5223 { // make this dataset sequence sq's dataset sequence
5224 sq.setDatasetSequence(dsq);
5225 // and update the current dataset alignment
5230 if (!dseqs.contains(dsq))
5237 if (ds.findIndex(dsq) < 0)
5239 ds.addSequence(dsq);
5246 // TODO: refactor this as a merge dataset sequence function
5247 // now check that sq (the dataset sequence) sequence really is the union of
5248 // all references to it
5249 // boolean pre = sq.getStart() < dsq.getStart();
5250 // boolean post = sq.getEnd() > dsq.getEnd();
5254 // StringBuffer sb = new StringBuffer();
5255 String newres = jalview.analysis.AlignSeq.extractGaps(
5256 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5257 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5258 && newres.length() > dsq.getLength())
5260 // Update with the longer sequence.
5264 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5265 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5266 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5267 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5269 dsq.setSequence(newres);
5271 // TODO: merges will never happen if we 'know' we have the real dataset
5272 // sequence - this should be detected when id==dssid
5274 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5275 // + (pre ? "prepended" : "") + " "
5276 // + (post ? "appended" : ""));
5281 // sequence refs are identical. We may need to update the existing dataset
5282 // alignment with this one, though.
5283 if (ds != null && dseqs == null)
5285 int opos = ds.findIndex(dsq);
5286 SequenceI tseq = null;
5287 if (opos != -1 && vseqpos != opos)
5289 // remove from old position
5290 ds.deleteSequence(dsq);
5292 if (vseqpos < ds.getHeight())
5294 if (vseqpos != opos)
5296 // save sequence at destination position
5297 tseq = ds.getSequenceAt(vseqpos);
5298 ds.replaceSequenceAt(vseqpos, dsq);
5299 ds.addSequence(tseq);
5304 ds.addSequence(dsq);
5311 * TODO use AlignmentI here and in related methods - needs
5312 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5314 Hashtable<String, AlignmentI> datasetIds = null;
5316 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5318 private AlignmentI getDatasetFor(String datasetId)
5320 if (datasetIds == null)
5322 datasetIds = new Hashtable<>();
5325 if (datasetIds.containsKey(datasetId))
5327 return datasetIds.get(datasetId);
5332 private void addDatasetRef(String datasetId, AlignmentI dataset)
5334 if (datasetIds == null)
5336 datasetIds = new Hashtable<>();
5338 datasetIds.put(datasetId, dataset);
5342 * make a new dataset ID for this jalview dataset alignment
5347 private String getDatasetIdRef(AlignmentI dataset)
5349 if (dataset.getDataset() != null)
5351 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5353 String datasetId = makeHashCode(dataset, null);
5354 if (datasetId == null)
5356 // make a new datasetId and record it
5357 if (dataset2Ids == null)
5359 dataset2Ids = new IdentityHashMap<>();
5363 datasetId = dataset2Ids.get(dataset);
5365 if (datasetId == null)
5367 datasetId = "ds" + dataset2Ids.size() + 1;
5368 dataset2Ids.put(dataset, datasetId);
5374 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5376 for (int d = 0; d < sequence.getDBRefCount(); d++)
5378 DBRef dr = sequence.getDBRef(d);
5379 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5380 sequence.getDBRef(d).getSource(),
5381 sequence.getDBRef(d).getVersion(),
5382 sequence.getDBRef(d).getAccessionId());
5383 if (dr.getMapping() != null)
5385 entry.setMap(addMapping(dr.getMapping()));
5387 datasetSequence.addDBRef(entry);
5391 private jalview.datamodel.Mapping addMapping(Mapping m)
5393 SequenceI dsto = null;
5394 // Mapping m = dr.getMapping();
5395 int fr[] = new int[m.getMapListFromCount() * 2];
5396 Enumeration f = m.enumerateMapListFrom();
5397 for (int _i = 0; f.hasMoreElements(); _i += 2)
5399 MapListFrom mf = (MapListFrom) f.nextElement();
5400 fr[_i] = mf.getStart();
5401 fr[_i + 1] = mf.getEnd();
5403 int fto[] = new int[m.getMapListToCount() * 2];
5404 f = m.enumerateMapListTo();
5405 for (int _i = 0; f.hasMoreElements(); _i += 2)
5407 MapListTo mf = (MapListTo) f.nextElement();
5408 fto[_i] = mf.getStart();
5409 fto[_i + 1] = mf.getEnd();
5411 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5412 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5413 if (m.getMappingChoice() != null)
5415 MappingChoice mc = m.getMappingChoice();
5416 if (mc.getDseqFor() != null)
5418 String dsfor = "" + mc.getDseqFor();
5419 if (seqRefIds.containsKey(dsfor))
5424 jmap.setTo(seqRefIds.get(dsfor));
5428 frefedSequence.add(newMappingRef(dsfor, jmap));
5434 * local sequence definition
5436 Sequence ms = mc.getSequence();
5437 SequenceI djs = null;
5438 String sqid = ms.getDsseqid();
5439 if (sqid != null && sqid.length() > 0)
5442 * recover dataset sequence
5444 djs = seqRefIds.get(sqid);
5449 "Warning - making up dataset sequence id for DbRef sequence map reference");
5450 sqid = ((Object) ms).toString(); // make up a new hascode for
5451 // undefined dataset sequence hash
5452 // (unlikely to happen)
5458 * make a new dataset sequence and add it to refIds hash
5460 djs = new jalview.datamodel.Sequence(ms.getName(),
5462 djs.setStart(jmap.getMap().getToLowest());
5463 djs.setEnd(jmap.getMap().getToHighest());
5464 djs.setVamsasId(uniqueSetSuffix + sqid);
5466 incompleteSeqs.put(sqid, djs);
5467 seqRefIds.put(sqid, djs);
5470 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5480 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5481 * view as XML (but not to file), and then reloading it
5486 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5489 JalviewModel jm = saveState(ap, null, null, null);
5491 addDatasetRef(jm.getVamsasModel().getSequenceSet()[0].getDatasetId(),
5492 ap.getAlignment().getDataset());
5494 uniqueSetSuffix = "";
5495 jm.getJalviewModelSequence().getViewport(0).setId(null);
5496 // we don't overwrite the view we just copied
5498 if (this.frefedSequence == null)
5500 frefedSequence = new Vector<>();
5503 viewportsAdded.clear();
5505 AlignFrame af = loadFromObject(jm, null, false, null);
5506 af.alignPanels.clear();
5507 af.closeMenuItem_actionPerformed(true);
5510 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5511 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5512 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5513 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5514 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5517 return af.alignPanel;
5520 private Hashtable jvids2vobj;
5522 private void warn(String msg)
5527 private void warn(String msg, Exception e)
5529 if (Cache.log != null)
5533 Cache.log.warn(msg, e);
5537 Cache.log.warn(msg);
5542 System.err.println("Warning: " + msg);
5545 e.printStackTrace();
5550 private void debug(String string)
5552 debug(string, null);
5555 private void debug(String msg, Exception e)
5557 if (Cache.log != null)
5561 Cache.log.debug(msg, e);
5565 Cache.log.debug(msg);
5570 System.err.println("Warning: " + msg);
5573 e.printStackTrace();
5579 * set the object to ID mapping tables used to write/recover objects and XML
5580 * ID strings for the jalview project. If external tables are provided then
5581 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5582 * object goes out of scope. - also populates the datasetIds hashtable with
5583 * alignment objects containing dataset sequences
5586 * Map from ID strings to jalview datamodel
5588 * Map from jalview datamodel to ID strings
5592 public void setObjectMappingTables(Hashtable vobj2jv,
5593 IdentityHashMap jv2vobj)
5595 this.jv2vobj = jv2vobj;
5596 this.vobj2jv = vobj2jv;
5597 Iterator ds = jv2vobj.keySet().iterator();
5599 while (ds.hasNext())
5601 Object jvobj = ds.next();
5602 id = jv2vobj.get(jvobj).toString();
5603 if (jvobj instanceof jalview.datamodel.Alignment)
5605 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5607 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5610 else if (jvobj instanceof jalview.datamodel.Sequence)
5612 // register sequence object so the XML parser can recover it.
5613 if (seqRefIds == null)
5615 seqRefIds = new HashMap<>();
5617 if (seqsToIds == null)
5619 seqsToIds = new IdentityHashMap<>();
5621 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5622 seqsToIds.put((SequenceI) jvobj, id);
5624 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5627 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5628 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5629 if (jvann.annotationId == null)
5631 jvann.annotationId = anid;
5633 if (!jvann.annotationId.equals(anid))
5635 // TODO verify that this is the correct behaviour
5636 this.warn("Overriding Annotation ID for " + anid
5637 + " from different id : " + jvann.annotationId);
5638 jvann.annotationId = anid;
5641 else if (jvobj instanceof String)
5643 if (jvids2vobj == null)
5645 jvids2vobj = new Hashtable();
5646 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5651 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5657 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5658 * objects created from the project archive. If string is null (default for
5659 * construction) then suffix will be set automatically.
5663 public void setUniqueSetSuffix(String string)
5665 uniqueSetSuffix = string;
5670 * uses skipList2 as the skipList for skipping views on sequence sets
5671 * associated with keys in the skipList
5675 public void setSkipList(Hashtable skipList2)
5677 skipList = skipList2;
5681 * Reads the jar entry of given name and returns its contents, or null if the
5682 * entry is not found.
5685 * @param jarEntryName
5688 protected String readJarEntry(jarInputStreamProvider jprovider,
5689 String jarEntryName)
5691 String result = null;
5692 BufferedReader in = null;
5697 * Reopen the jar input stream and traverse its entries to find a matching
5700 JarInputStream jin = jprovider.getJarInputStream();
5701 JarEntry entry = null;
5704 entry = jin.getNextJarEntry();
5705 } while (entry != null && !entry.getName().equals(jarEntryName));
5709 StringBuilder out = new StringBuilder(256);
5710 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5713 while ((data = in.readLine()) != null)
5717 result = out.toString();
5721 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5723 } catch (Exception ex)
5725 ex.printStackTrace();
5733 } catch (IOException e)
5744 * Returns an incrementing counter (0, 1, 2...)
5748 private synchronized int nextCounter()
5754 * Populates an XML model of the feature colour scheme for one feature type
5756 * @param featureType
5760 protected static jalview.schemabinding.version2.Colour marshalColour(
5761 String featureType, FeatureColourI fcol)
5763 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5764 if (fcol.isSimpleColour())
5766 col.setRGB(Format.getHexString(fcol.getColour()));
5770 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5771 col.setMin(fcol.getMin());
5772 col.setMax(fcol.getMax());
5773 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5774 col.setAutoScale(fcol.isAutoScaled());
5775 col.setThreshold(fcol.getThreshold());
5776 col.setColourByLabel(fcol.isColourByLabel());
5777 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5778 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5779 : ColourThreshTypeType.NONE));
5780 if (fcol.isColourByAttribute())
5782 col.setAttributeName(fcol.getAttributeName());
5784 Color noColour = fcol.getNoColour();
5785 if (noColour == null)
5787 col.setNoValueColour(NoValueColour.NONE);
5789 else if (noColour == fcol.getMaxColour())
5791 col.setNoValueColour(NoValueColour.MAX);
5795 col.setNoValueColour(NoValueColour.MIN);
5798 col.setName(featureType);
5803 * Populates an XML model of the feature filter(s) for one feature type
5805 * @param firstMatcher
5806 * the first (or only) match condition)
5808 * remaining match conditions (if any)
5810 * if true, conditions are and-ed, else or-ed
5812 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5813 Iterator<FeatureMatcherI> filters, boolean and)
5815 MatcherSet result = new MatcherSet();
5817 if (filters.hasNext())
5822 CompoundMatcher compound = new CompoundMatcher();
5823 compound.setAnd(and);
5824 MatcherSet matcher1 = marshalFilter(firstMatcher,
5825 Collections.emptyIterator(), and);
5826 compound.addMatcherSet(matcher1);
5827 FeatureMatcherI nextMatcher = filters.next();
5828 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5829 compound.addMatcherSet(matcher2);
5830 result.setCompoundMatcher(compound);
5835 * single condition matcher
5837 MatchCondition matcherModel = new MatchCondition();
5838 matcherModel.setCondition(
5839 firstMatcher.getMatcher().getCondition().getStableName());
5840 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5841 if (firstMatcher.isByAttribute())
5843 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5844 matcherModel.setAttributeName(firstMatcher.getAttribute());
5846 else if (firstMatcher.isByLabel())
5848 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5850 else if (firstMatcher.isByScore())
5852 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5854 result.setMatchCondition(matcherModel);
5861 * Loads one XML model of a feature filter to a Jalview object
5863 * @param featureType
5864 * @param matcherSetModel
5867 protected static FeatureMatcherSetI unmarshalFilter(
5868 String featureType, MatcherSet matcherSetModel)
5870 FeatureMatcherSetI result = new FeatureMatcherSet();
5873 unmarshalFilterConditions(result, matcherSetModel, true);
5874 } catch (IllegalStateException e)
5876 // mixing AND and OR conditions perhaps
5878 String.format("Error reading filter conditions for '%s': %s",
5879 featureType, e.getMessage()));
5880 // return as much as was parsed up to the error
5887 * Adds feature match conditions to matcherSet as unmarshalled from XML
5888 * (possibly recursively for compound conditions)
5891 * @param matcherSetModel
5893 * if true, multiple conditions are AND-ed, else they are OR-ed
5894 * @throws IllegalStateException
5895 * if AND and OR conditions are mixed
5897 protected static void unmarshalFilterConditions(
5898 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5901 MatchCondition mc = matcherSetModel.getMatchCondition();
5907 FeatureMatcherByType filterBy = mc.getBy();
5908 Condition cond = Condition.fromString(mc.getCondition());
5909 String pattern = mc.getValue();
5910 FeatureMatcherI matchCondition = null;
5911 if (filterBy == FeatureMatcherByType.BYLABEL)
5913 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5915 else if (filterBy == FeatureMatcherByType.BYSCORE)
5917 matchCondition = FeatureMatcher.byScore(cond, pattern);
5920 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5922 String[] attNames = mc.getAttributeName();
5923 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5928 * note this throws IllegalStateException if AND-ing to a
5929 * previously OR-ed compound condition, or vice versa
5933 matcherSet.and(matchCondition);
5937 matcherSet.or(matchCondition);
5943 * compound condition
5945 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5947 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5948 if (matchers.length == 2)
5950 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5951 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5955 System.err.println("Malformed compound filter condition");
5961 * Loads one XML model of a feature colour to a Jalview object
5963 * @param colourModel
5966 protected static FeatureColourI unmarshalColour(
5967 jalview.schemabinding.version2.Colour colourModel)
5969 FeatureColourI colour = null;
5971 if (colourModel.hasMax())
5973 Color mincol = null;
5974 Color maxcol = null;
5975 Color noValueColour = null;
5979 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5980 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5981 } catch (Exception e)
5983 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5986 NoValueColour noCol = colourModel.getNoValueColour();
5987 if (noCol == NoValueColour.MIN)
5989 noValueColour = mincol;
5991 else if (noCol == NoValueColour.MAX)
5993 noValueColour = maxcol;
5996 colour = new FeatureColour(mincol, maxcol, noValueColour,
5997 colourModel.getMin(),
5998 colourModel.getMax());
5999 String[] attributes = colourModel.getAttributeName();
6000 if (attributes != null && attributes.length > 0)
6002 colour.setAttributeName(attributes);
6004 if (colourModel.hasAutoScale())
6006 colour.setAutoScaled(colourModel.getAutoScale());
6008 if (colourModel.hasColourByLabel())
6010 colour.setColourByLabel(colourModel.getColourByLabel());
6012 if (colourModel.hasThreshold())
6014 colour.setThreshold(colourModel.getThreshold());
6016 ColourThreshTypeType ttyp = colourModel.getThreshType();
6019 if (ttyp == ColourThreshTypeType.ABOVE)
6021 colour.setAboveThreshold(true);
6023 else if (ttyp == ColourThreshTypeType.BELOW)
6025 colour.setBelowThreshold(true);
6031 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6032 colour = new FeatureColour(color);