2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.analysis.Conservation;
24 import jalview.api.FeatureColourI;
25 import jalview.api.ViewStyleI;
26 import jalview.api.structures.JalviewStructureDisplayI;
27 import jalview.bin.Cache;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.GraphLine;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.RnaViewerModel;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.datamodel.StructureViewerModel;
39 import jalview.datamodel.StructureViewerModel.StructureData;
40 import jalview.datamodel.features.FeatureMatcher;
41 import jalview.datamodel.features.FeatureMatcherI;
42 import jalview.datamodel.features.FeatureMatcherSet;
43 import jalview.datamodel.features.FeatureMatcherSetI;
44 import jalview.ext.varna.RnaModel;
45 import jalview.gui.StructureViewer.ViewerType;
46 import jalview.io.BackupFiles;
47 import jalview.io.DataSourceType;
48 import jalview.io.FileFormat;
49 import jalview.renderer.ResidueShaderI;
50 import jalview.schemabinding.version2.AlcodMap;
51 import jalview.schemabinding.version2.AlcodonFrame;
52 import jalview.schemabinding.version2.Annotation;
53 import jalview.schemabinding.version2.AnnotationColours;
54 import jalview.schemabinding.version2.AnnotationElement;
55 import jalview.schemabinding.version2.CalcIdParam;
56 import jalview.schemabinding.version2.CompoundMatcher;
57 import jalview.schemabinding.version2.DBRef;
58 import jalview.schemabinding.version2.Features;
59 import jalview.schemabinding.version2.Group;
60 import jalview.schemabinding.version2.HiddenColumns;
61 import jalview.schemabinding.version2.JGroup;
62 import jalview.schemabinding.version2.JSeq;
63 import jalview.schemabinding.version2.JalviewModel;
64 import jalview.schemabinding.version2.JalviewModelSequence;
65 import jalview.schemabinding.version2.MapListFrom;
66 import jalview.schemabinding.version2.MapListTo;
67 import jalview.schemabinding.version2.Mapping;
68 import jalview.schemabinding.version2.MappingChoice;
69 import jalview.schemabinding.version2.MatchCondition;
70 import jalview.schemabinding.version2.MatcherSet;
71 import jalview.schemabinding.version2.OtherData;
72 import jalview.schemabinding.version2.PdbentryItem;
73 import jalview.schemabinding.version2.Pdbids;
74 import jalview.schemabinding.version2.Property;
75 import jalview.schemabinding.version2.RnaViewer;
76 import jalview.schemabinding.version2.SecondaryStructure;
77 import jalview.schemabinding.version2.Sequence;
78 import jalview.schemabinding.version2.SequenceSet;
79 import jalview.schemabinding.version2.SequenceSetProperties;
80 import jalview.schemabinding.version2.Setting;
81 import jalview.schemabinding.version2.StructureState;
82 import jalview.schemabinding.version2.ThresholdLine;
83 import jalview.schemabinding.version2.Tree;
84 import jalview.schemabinding.version2.UserColours;
85 import jalview.schemabinding.version2.Viewport;
86 import jalview.schemabinding.version2.types.ColourThreshTypeType;
87 import jalview.schemabinding.version2.types.FeatureMatcherByType;
88 import jalview.schemabinding.version2.types.NoValueColour;
89 import jalview.schemes.AnnotationColourGradient;
90 import jalview.schemes.ColourSchemeI;
91 import jalview.schemes.ColourSchemeProperty;
92 import jalview.schemes.FeatureColour;
93 import jalview.schemes.ResidueProperties;
94 import jalview.schemes.UserColourScheme;
95 import jalview.structure.StructureSelectionManager;
96 import jalview.structures.models.AAStructureBindingModel;
97 import jalview.util.Format;
98 import jalview.util.MessageManager;
99 import jalview.util.Platform;
100 import jalview.util.StringUtils;
101 import jalview.util.jarInputStreamProvider;
102 import jalview.util.matcher.Condition;
103 import jalview.viewmodel.AlignmentViewport;
104 import jalview.viewmodel.ViewportRanges;
105 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
106 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
107 import jalview.ws.jws2.Jws2Discoverer;
108 import jalview.ws.jws2.dm.AAConSettings;
109 import jalview.ws.jws2.jabaws2.Jws2Instance;
110 import jalview.ws.params.ArgumentI;
111 import jalview.ws.params.AutoCalcSetting;
112 import jalview.ws.params.WsParamSetI;
114 import java.awt.Color;
115 import java.awt.Rectangle;
116 import java.io.BufferedReader;
117 import java.io.DataInputStream;
118 import java.io.DataOutputStream;
120 import java.io.FileInputStream;
121 import java.io.FileOutputStream;
122 import java.io.IOException;
123 import java.io.InputStreamReader;
124 import java.io.OutputStreamWriter;
125 import java.io.PrintWriter;
126 import java.lang.reflect.InvocationTargetException;
127 import java.net.MalformedURLException;
129 import java.util.ArrayList;
130 import java.util.Arrays;
131 import java.util.Collections;
132 import java.util.Enumeration;
133 import java.util.HashMap;
134 import java.util.HashSet;
135 import java.util.Hashtable;
136 import java.util.IdentityHashMap;
137 import java.util.Iterator;
138 import java.util.LinkedHashMap;
139 import java.util.List;
140 import java.util.Map;
141 import java.util.Map.Entry;
142 import java.util.Set;
143 import java.util.Vector;
144 import java.util.jar.JarEntry;
145 import java.util.jar.JarInputStream;
146 import java.util.jar.JarOutputStream;
148 import javax.swing.JInternalFrame;
149 import javax.swing.SwingUtilities;
151 import org.exolab.castor.xml.Marshaller;
152 import org.exolab.castor.xml.Unmarshaller;
155 * Write out the current jalview desktop state as a Jalview XML stream.
157 * Note: the vamsas objects referred to here are primitive versions of the
158 * VAMSAS project schema elements - they are not the same and most likely never
162 * @version $Revision: 1.134 $
164 public class Jalview2XML
166 private static final String VIEWER_PREFIX = "viewer_";
168 private static final String RNA_PREFIX = "rna_";
170 private static final String UTF_8 = "UTF-8";
172 // use this with nextCounter() to make unique names for entities
173 private int counter = 0;
176 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
177 * of sequence objects are created.
179 IdentityHashMap<SequenceI, String> seqsToIds = null;
182 * jalview XML Sequence ID to jalview sequence object reference (both dataset
183 * and alignment sequences. Populated as XML reps of sequence objects are
186 Map<String, SequenceI> seqRefIds = null;
188 Map<String, SequenceI> incompleteSeqs = null;
190 List<SeqFref> frefedSequence = null;
192 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
195 * Map of reconstructed AlignFrame objects that appear to have come from
196 * SplitFrame objects (have a dna/protein complement view).
198 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
201 * Map from displayed rna structure models to their saved session state jar
204 private Map<RnaModel, String> rnaSessions = new HashMap<>();
207 * create/return unique hash string for sq
210 * @return new or existing unique string for sq
212 String seqHash(SequenceI sq)
214 if (seqsToIds == null)
218 if (seqsToIds.containsKey(sq))
220 return seqsToIds.get(sq);
224 // create sequential key
225 String key = "sq" + (seqsToIds.size() + 1);
226 key = makeHashCode(sq, key); // check we don't have an external reference
228 seqsToIds.put(sq, key);
235 if (seqsToIds == null)
237 seqsToIds = new IdentityHashMap<>();
239 if (seqRefIds == null)
241 seqRefIds = new HashMap<>();
243 if (incompleteSeqs == null)
245 incompleteSeqs = new HashMap<>();
247 if (frefedSequence == null)
249 frefedSequence = new ArrayList<>();
257 public Jalview2XML(boolean raiseGUI)
259 this.raiseGUI = raiseGUI;
263 * base class for resolving forward references to sequences by their ID
268 abstract class SeqFref
274 public SeqFref(String _sref, String type)
280 public String getSref()
285 public SequenceI getSrefSeq()
287 return seqRefIds.get(sref);
290 public boolean isResolvable()
292 return seqRefIds.get(sref) != null;
295 public SequenceI getSrefDatasetSeq()
297 SequenceI sq = seqRefIds.get(sref);
300 while (sq.getDatasetSequence() != null)
302 sq = sq.getDatasetSequence();
309 * @return true if the forward reference was fully resolved
311 abstract boolean resolve();
314 public String toString()
316 return type + " reference to " + sref;
321 * create forward reference for a mapping
327 public SeqFref newMappingRef(final String sref,
328 final jalview.datamodel.Mapping _jmap)
330 SeqFref fref = new SeqFref(sref, "Mapping")
332 public jalview.datamodel.Mapping jmap = _jmap;
337 SequenceI seq = getSrefDatasetSeq();
349 public SeqFref newAlcodMapRef(final String sref,
350 final AlignedCodonFrame _cf,
351 final jalview.datamodel.Mapping _jmap)
354 SeqFref fref = new SeqFref(sref, "Codon Frame")
356 AlignedCodonFrame cf = _cf;
358 public jalview.datamodel.Mapping mp = _jmap;
361 public boolean isResolvable()
363 return super.isResolvable() && mp.getTo() != null;
369 SequenceI seq = getSrefDatasetSeq();
374 cf.addMap(seq, mp.getTo(), mp.getMap());
381 public void resolveFrefedSequences()
383 Iterator<SeqFref> nextFref = frefedSequence.iterator();
384 int toresolve = frefedSequence.size();
385 int unresolved = 0, failedtoresolve = 0;
386 while (nextFref.hasNext())
388 SeqFref ref = nextFref.next();
389 if (ref.isResolvable())
401 } catch (Exception x)
404 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
417 System.err.println("Jalview Project Import: There were " + unresolved
418 + " forward references left unresolved on the stack.");
420 if (failedtoresolve > 0)
422 System.err.println("SERIOUS! " + failedtoresolve
423 + " resolvable forward references failed to resolve.");
425 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
428 "Jalview Project Import: There are " + incompleteSeqs.size()
429 + " sequences which may have incomplete metadata.");
430 if (incompleteSeqs.size() < 10)
432 for (SequenceI s : incompleteSeqs.values())
434 System.err.println(s.toString());
440 "Too many to report. Skipping output of incomplete sequences.");
446 * This maintains a map of viewports, the key being the seqSetId. Important to
447 * set historyItem and redoList for multiple views
449 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
451 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
453 String uniqueSetSuffix = "";
456 * List of pdbfiles added to Jar
458 List<String> pdbfiles = null;
460 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
461 public void saveState(File statefile)
463 FileOutputStream fos = null;
467 //BackupFiles backupfiles = new BackupFiles(statefile);
468 //fos = new FileOutputStream(backupfiles.getTempFile());
469 fos = new FileOutputStream(statefile);
471 JarOutputStream jout = new JarOutputStream(fos);
474 //backupfiles.setWriteSuccess(true);
475 //backupfiles.rollBackupsAndRenameTempFile();
477 } catch (Exception e)
479 // TODO: inform user of the problem - they need to know if their data was
481 if (errorMessage == null)
483 errorMessage = "Couldn't write Jalview Archive to output file '"
484 + statefile + "' - See console error log for details";
488 errorMessage += "(output file was '" + statefile + "')";
498 } catch (IOException e)
508 * Writes a jalview project archive to the given Jar output stream.
512 public void saveState(JarOutputStream jout)
514 AlignFrame[] frames = Desktop.getAlignFrames();
520 saveAllFrames(Arrays.asList(frames), jout);
524 * core method for storing state for a set of AlignFrames.
527 * - frames involving all data to be exported (including containing
530 * - project output stream
532 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
534 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
537 * ensure cached data is clear before starting
539 // todo tidy up seqRefIds, seqsToIds initialisation / reset
541 splitFrameCandidates.clear();
546 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
547 // //////////////////////////////////////////////////
549 List<String> shortNames = new ArrayList<>();
550 List<String> viewIds = new ArrayList<>();
553 for (int i = frames.size() - 1; i > -1; i--)
555 AlignFrame af = frames.get(i);
557 if (skipList != null && skipList
558 .containsKey(af.getViewport().getSequenceSetId()))
563 String shortName = makeFilename(af, shortNames);
565 int ap, apSize = af.alignPanels.size();
567 for (ap = 0; ap < apSize; ap++)
569 AlignmentPanel apanel = af.alignPanels.get(ap);
570 String fileName = apSize == 1 ? shortName : ap + shortName;
571 if (!fileName.endsWith(".xml"))
573 fileName = fileName + ".xml";
576 saveState(apanel, fileName, jout, viewIds);
578 String dssid = getDatasetIdRef(
579 af.getViewport().getAlignment().getDataset());
580 if (!dsses.containsKey(dssid))
582 dsses.put(dssid, af);
587 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
593 } catch (Exception foo)
598 } catch (Exception ex)
600 // TODO: inform user of the problem - they need to know if their data was
602 if (errorMessage == null)
604 errorMessage = "Couldn't write Jalview Archive - see error output for details";
606 ex.printStackTrace();
611 * Generates a distinct file name, based on the title of the AlignFrame, by
612 * appending _n for increasing n until an unused name is generated. The new
613 * name (without its extension) is added to the list.
617 * @return the generated name, with .xml extension
619 protected String makeFilename(AlignFrame af, List<String> namesUsed)
621 String shortName = af.getTitle();
623 if (shortName.indexOf(File.separatorChar) > -1)
625 shortName = shortName
626 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
631 while (namesUsed.contains(shortName))
633 if (shortName.endsWith("_" + (count - 1)))
635 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
638 shortName = shortName.concat("_" + count);
642 namesUsed.add(shortName);
644 if (!shortName.endsWith(".xml"))
646 shortName = shortName + ".xml";
651 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
652 public boolean saveAlignment(AlignFrame af, String jarFile,
657 // create backupfiles object and get new temp filename destination
658 BackupFiles backupfiles = new BackupFiles(jarFile);
659 FileOutputStream fos = new FileOutputStream(
660 backupfiles.getTempFilePath());
662 JarOutputStream jout = new JarOutputStream(fos);
663 List<AlignFrame> frames = new ArrayList<>();
665 // resolve splitframes
666 if (af.getViewport().getCodingComplement() != null)
668 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
674 saveAllFrames(frames, jout);
678 } catch (Exception foo)
683 boolean success = true;
685 backupfiles.setWriteSuccess(success);
686 success = backupfiles.rollBackupsAndRenameTempFile();
689 } catch (Exception ex)
691 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
692 ex.printStackTrace();
697 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
698 String fileName, JarOutputStream jout)
701 for (String dssids : dsses.keySet())
703 AlignFrame _af = dsses.get(dssids);
704 String jfileName = fileName + " Dataset for " + _af.getTitle();
705 if (!jfileName.endsWith(".xml"))
707 jfileName = jfileName + ".xml";
709 saveState(_af.alignPanel, jfileName, true, jout, null);
714 * create a JalviewModel from an alignment view and marshall it to a
718 * panel to create jalview model for
720 * name of alignment panel written to output stream
727 public JalviewModel saveState(AlignmentPanel ap, String fileName,
728 JarOutputStream jout, List<String> viewIds)
730 return saveState(ap, fileName, false, jout, viewIds);
734 * create a JalviewModel from an alignment view and marshall it to a
738 * panel to create jalview model for
740 * name of alignment panel written to output stream
742 * when true, only write the dataset for the alignment, not the data
743 * associated with the view.
749 public JalviewModel saveState(AlignmentPanel ap, String fileName,
750 boolean storeDS, JarOutputStream jout, List<String> viewIds)
754 viewIds = new ArrayList<>();
759 List<UserColourScheme> userColours = new ArrayList<>();
761 AlignViewport av = ap.av;
762 ViewportRanges vpRanges = av.getRanges();
764 JalviewModel object = new JalviewModel();
765 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
767 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
769 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
772 * rjal is full height alignment, jal is actual alignment with full metadata
773 * but excludes hidden sequences.
775 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
777 if (av.hasHiddenRows())
779 rjal = jal.getHiddenSequences().getFullAlignment();
782 SequenceSet vamsasSet = new SequenceSet();
784 JalviewModelSequence jms = new JalviewModelSequence();
786 vamsasSet.setGapChar(jal.getGapCharacter() + "");
788 if (jal.getDataset() != null)
790 // dataset id is the dataset's hashcode
791 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
794 // switch jal and the dataset
795 jal = jal.getDataset();
799 if (jal.getProperties() != null)
801 Enumeration en = jal.getProperties().keys();
802 while (en.hasMoreElements())
804 String key = en.nextElement().toString();
805 SequenceSetProperties ssp = new SequenceSetProperties();
807 ssp.setValue(jal.getProperties().get(key).toString());
808 vamsasSet.addSequenceSetProperties(ssp);
813 Set<String> calcIdSet = new HashSet<>();
814 // record the set of vamsas sequence XML POJO we create.
815 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
817 for (final SequenceI jds : rjal.getSequences())
819 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
820 : jds.getDatasetSequence();
821 String id = seqHash(jds);
822 if (vamsasSetIds.get(id) == null)
824 if (seqRefIds.get(id) != null && !storeDS)
826 // This happens for two reasons: 1. multiple views are being
828 // 2. the hashCode has collided with another sequence's code. This
830 // HAPPEN! (PF00072.15.stk does this)
831 // JBPNote: Uncomment to debug writing out of files that do not read
832 // back in due to ArrayOutOfBoundExceptions.
833 // System.err.println("vamsasSeq backref: "+id+"");
834 // System.err.println(jds.getName()+"
835 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
836 // System.err.println("Hashcode: "+seqHash(jds));
837 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
838 // System.err.println(rsq.getName()+"
839 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
840 // System.err.println("Hashcode: "+seqHash(rsq));
844 vamsasSeq = createVamsasSequence(id, jds);
845 vamsasSet.addSequence(vamsasSeq);
846 vamsasSetIds.put(id, vamsasSeq);
847 seqRefIds.put(id, jds);
851 jseq.setStart(jds.getStart());
852 jseq.setEnd(jds.getEnd());
853 jseq.setColour(av.getSequenceColour(jds).getRGB());
855 jseq.setId(id); // jseq id should be a string not a number
858 // Store any sequences this sequence represents
859 if (av.hasHiddenRows())
861 // use rjal, contains the full height alignment
863 av.getAlignment().getHiddenSequences().isHidden(jds));
865 if (av.isHiddenRepSequence(jds))
867 jalview.datamodel.SequenceI[] reps = av
868 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
870 for (int h = 0; h < reps.length; h++)
874 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
879 // mark sequence as reference - if it is the reference for this view
882 jseq.setViewreference(jds == jal.getSeqrep());
886 // TODO: omit sequence features from each alignment view's XML dump if we
887 // are storing dataset
888 List<jalview.datamodel.SequenceFeature> sfs = jds
889 .getSequenceFeatures();
890 for (SequenceFeature sf : sfs)
892 Features features = new Features();
894 features.setBegin(sf.getBegin());
895 features.setEnd(sf.getEnd());
896 features.setDescription(sf.getDescription());
897 features.setType(sf.getType());
898 features.setFeatureGroup(sf.getFeatureGroup());
899 features.setScore(sf.getScore());
900 if (sf.links != null)
902 for (int l = 0; l < sf.links.size(); l++)
904 OtherData keyValue = new OtherData();
905 keyValue.setKey("LINK_" + l);
906 keyValue.setValue(sf.links.elementAt(l).toString());
907 features.addOtherData(keyValue);
910 if (sf.otherDetails != null)
913 * save feature attributes, which may be simple strings or
914 * map valued (have sub-attributes)
916 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
918 String key = entry.getKey();
919 Object value = entry.getValue();
920 if (value instanceof Map<?, ?>)
922 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
925 OtherData otherData = new OtherData();
926 otherData.setKey(key);
927 otherData.setKey2(subAttribute.getKey());
928 otherData.setValue(subAttribute.getValue().toString());
929 features.addOtherData(otherData);
934 OtherData otherData = new OtherData();
935 otherData.setKey(key);
936 otherData.setValue(value.toString());
937 features.addOtherData(otherData);
942 jseq.addFeatures(features);
945 if (jdatasq.getAllPDBEntries() != null)
947 Enumeration en = jdatasq.getAllPDBEntries().elements();
948 while (en.hasMoreElements())
950 Pdbids pdb = new Pdbids();
951 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
954 String pdbId = entry.getId();
956 pdb.setType(entry.getType());
959 * Store any structure views associated with this sequence. This
960 * section copes with duplicate entries in the project, so a dataset
961 * only view *should* be coped with sensibly.
963 // This must have been loaded, is it still visible?
964 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
965 String matchedFile = null;
966 for (int f = frames.length - 1; f > -1; f--)
968 if (frames[f] instanceof StructureViewerBase)
970 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
971 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
972 matchedFile, viewFrame);
974 * Only store each structure viewer's state once in the project
975 * jar. First time through only (storeDS==false)
977 String viewId = viewFrame.getViewId();
978 if (!storeDS && !viewIds.contains(viewId))
983 String viewerState = viewFrame.getStateInfo();
984 writeJarEntry(jout, getViewerJarEntryName(viewId),
985 viewerState.getBytes());
986 } catch (IOException e)
989 "Error saving viewer state: " + e.getMessage());
995 if (matchedFile != null || entry.getFile() != null)
997 if (entry.getFile() != null)
1000 matchedFile = entry.getFile();
1002 pdb.setFile(matchedFile); // entry.getFile());
1003 if (pdbfiles == null)
1005 pdbfiles = new ArrayList<>();
1008 if (!pdbfiles.contains(pdbId))
1010 pdbfiles.add(pdbId);
1011 copyFileToJar(jout, matchedFile, pdbId);
1015 Enumeration<String> props = entry.getProperties();
1016 if (props.hasMoreElements())
1018 PdbentryItem item = new PdbentryItem();
1019 while (props.hasMoreElements())
1021 Property prop = new Property();
1022 String key = props.nextElement();
1024 prop.setValue(entry.getProperty(key).toString());
1025 item.addProperty(prop);
1027 pdb.addPdbentryItem(item);
1030 jseq.addPdbids(pdb);
1034 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1039 if (!storeDS && av.hasHiddenRows())
1041 jal = av.getAlignment();
1045 if (storeDS && jal.getCodonFrames() != null)
1047 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1048 for (AlignedCodonFrame acf : jac)
1050 AlcodonFrame alc = new AlcodonFrame();
1051 if (acf.getProtMappings() != null
1052 && acf.getProtMappings().length > 0)
1054 boolean hasMap = false;
1055 SequenceI[] dnas = acf.getdnaSeqs();
1056 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1057 for (int m = 0; m < pmaps.length; m++)
1059 AlcodMap alcmap = new AlcodMap();
1060 alcmap.setDnasq(seqHash(dnas[m]));
1062 createVamsasMapping(pmaps[m], dnas[m], null, false));
1063 alc.addAlcodMap(alcmap);
1068 vamsasSet.addAlcodonFrame(alc);
1071 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1073 // AlcodonFrame alc = new AlcodonFrame();
1074 // vamsasSet.addAlcodonFrame(alc);
1075 // for (int p = 0; p < acf.aaWidth; p++)
1077 // Alcodon cmap = new Alcodon();
1078 // if (acf.codons[p] != null)
1080 // // Null codons indicate a gapped column in the translated peptide
1082 // cmap.setPos1(acf.codons[p][0]);
1083 // cmap.setPos2(acf.codons[p][1]);
1084 // cmap.setPos3(acf.codons[p][2]);
1086 // alc.addAlcodon(cmap);
1088 // if (acf.getProtMappings() != null
1089 // && acf.getProtMappings().length > 0)
1091 // SequenceI[] dnas = acf.getdnaSeqs();
1092 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1093 // for (int m = 0; m < pmaps.length; m++)
1095 // AlcodMap alcmap = new AlcodMap();
1096 // alcmap.setDnasq(seqHash(dnas[m]));
1097 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1099 // alc.addAlcodMap(alcmap);
1106 // /////////////////////////////////
1107 if (!storeDS && av.getCurrentTree() != null)
1109 // FIND ANY ASSOCIATED TREES
1110 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1111 if (Desktop.desktop != null)
1113 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1115 for (int t = 0; t < frames.length; t++)
1117 if (frames[t] instanceof TreePanel)
1119 TreePanel tp = (TreePanel) frames[t];
1121 if (tp.treeCanvas.av.getAlignment() == jal)
1123 Tree tree = new Tree();
1124 tree.setTitle(tp.getTitle());
1125 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1126 tree.setNewick(tp.getTree().print());
1127 tree.setThreshold(tp.treeCanvas.threshold);
1129 tree.setFitToWindow(tp.fitToWindow.getState());
1130 tree.setFontName(tp.getTreeFont().getName());
1131 tree.setFontSize(tp.getTreeFont().getSize());
1132 tree.setFontStyle(tp.getTreeFont().getStyle());
1133 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1135 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1136 tree.setShowDistances(tp.distanceMenu.getState());
1138 tree.setHeight(tp.getHeight());
1139 tree.setWidth(tp.getWidth());
1140 tree.setXpos(tp.getX());
1141 tree.setYpos(tp.getY());
1142 tree.setId(makeHashCode(tp, null));
1152 * store forward refs from an annotationRow to any groups
1154 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1157 for (SequenceI sq : jal.getSequences())
1159 // Store annotation on dataset sequences only
1160 AlignmentAnnotation[] aa = sq.getAnnotation();
1161 if (aa != null && aa.length > 0)
1163 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1170 if (jal.getAlignmentAnnotation() != null)
1172 // Store the annotation shown on the alignment.
1173 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1174 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1179 if (jal.getGroups() != null)
1181 JGroup[] groups = new JGroup[jal.getGroups().size()];
1183 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1185 JGroup jGroup = new JGroup();
1186 groups[++i] = jGroup;
1188 jGroup.setStart(sg.getStartRes());
1189 jGroup.setEnd(sg.getEndRes());
1190 jGroup.setName(sg.getName());
1191 if (groupRefs.containsKey(sg))
1193 // group has references so set its ID field
1194 jGroup.setId(groupRefs.get(sg));
1196 ColourSchemeI colourScheme = sg.getColourScheme();
1197 if (colourScheme != null)
1199 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1200 if (groupColourScheme.conservationApplied())
1202 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1204 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1207 setUserColourScheme(colourScheme, userColours, jms));
1211 jGroup.setColour(colourScheme.getSchemeName());
1214 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1216 jGroup.setColour("AnnotationColourGradient");
1217 jGroup.setAnnotationColours(constructAnnotationColours(
1218 (jalview.schemes.AnnotationColourGradient) colourScheme,
1221 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1224 setUserColourScheme(colourScheme, userColours, jms));
1228 jGroup.setColour(colourScheme.getSchemeName());
1231 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1234 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1235 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1236 jGroup.setDisplayText(sg.getDisplayText());
1237 jGroup.setColourText(sg.getColourText());
1238 jGroup.setTextCol1(sg.textColour.getRGB());
1239 jGroup.setTextCol2(sg.textColour2.getRGB());
1240 jGroup.setTextColThreshold(sg.thresholdTextColour);
1241 jGroup.setShowUnconserved(sg.getShowNonconserved());
1242 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1243 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1244 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1245 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1246 for (SequenceI seq : sg.getSequences())
1248 jGroup.addSeq(seqHash(seq));
1252 jms.setJGroup(groups);
1256 // /////////SAVE VIEWPORT
1257 Viewport view = new Viewport();
1258 view.setTitle(ap.alignFrame.getTitle());
1259 view.setSequenceSetId(
1260 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1261 view.setId(av.getViewId());
1262 if (av.getCodingComplement() != null)
1264 view.setComplementId(av.getCodingComplement().getViewId());
1266 view.setViewName(av.viewName);
1267 view.setGatheredViews(av.isGatherViewsHere());
1269 Rectangle size = ap.av.getExplodedGeometry();
1270 Rectangle position = size;
1273 size = ap.alignFrame.getBounds();
1274 if (av.getCodingComplement() != null)
1276 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1284 view.setXpos(position.x);
1285 view.setYpos(position.y);
1287 view.setWidth(size.width);
1288 view.setHeight(size.height);
1290 view.setStartRes(vpRanges.getStartRes());
1291 view.setStartSeq(vpRanges.getStartSeq());
1293 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1295 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1299 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1301 AnnotationColours ac = constructAnnotationColours(
1302 (jalview.schemes.AnnotationColourGradient) av
1303 .getGlobalColourScheme(),
1306 view.setAnnotationColours(ac);
1307 view.setBgColour("AnnotationColourGradient");
1311 view.setBgColour(ColourSchemeProperty
1312 .getColourName(av.getGlobalColourScheme()));
1315 ResidueShaderI vcs = av.getResidueShading();
1316 ColourSchemeI cs = av.getGlobalColourScheme();
1320 if (vcs.conservationApplied())
1322 view.setConsThreshold(vcs.getConservationInc());
1323 if (cs instanceof jalview.schemes.UserColourScheme)
1325 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1328 view.setPidThreshold(vcs.getThreshold());
1331 view.setConservationSelected(av.getConservationSelected());
1332 view.setPidSelected(av.getAbovePIDThreshold());
1333 view.setFontName(av.font.getName());
1334 view.setFontSize(av.font.getSize());
1335 view.setFontStyle(av.font.getStyle());
1336 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1337 view.setRenderGaps(av.isRenderGaps());
1338 view.setShowAnnotation(av.isShowAnnotation());
1339 view.setShowBoxes(av.getShowBoxes());
1340 view.setShowColourText(av.getColourText());
1341 view.setShowFullId(av.getShowJVSuffix());
1342 view.setRightAlignIds(av.isRightAlignIds());
1343 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1344 view.setShowText(av.getShowText());
1345 view.setShowUnconserved(av.getShowUnconserved());
1346 view.setWrapAlignment(av.getWrapAlignment());
1347 view.setTextCol1(av.getTextColour().getRGB());
1348 view.setTextCol2(av.getTextColour2().getRGB());
1349 view.setTextColThreshold(av.getThresholdTextColour());
1350 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1351 view.setShowSequenceLogo(av.isShowSequenceLogo());
1352 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1353 view.setShowGroupConsensus(av.isShowGroupConsensus());
1354 view.setShowGroupConservation(av.isShowGroupConservation());
1355 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1356 view.setShowDbRefTooltip(av.isShowDBRefs());
1357 view.setFollowHighlight(av.isFollowHighlight());
1358 view.setFollowSelection(av.followSelection);
1359 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1360 if (av.getFeaturesDisplayed() != null)
1362 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1364 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1365 .getFeatureRenderer();
1366 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1368 Vector<String> settingsAdded = new Vector<>();
1369 if (renderOrder != null)
1371 for (String featureType : renderOrder)
1373 Setting setting = new Setting();
1374 setting.setType(featureType);
1377 * save any filter for the feature type
1379 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1380 if (filter != null) {
1381 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1382 FeatureMatcherI firstFilter = filters.next();
1383 setting.setMatcherSet(Jalview2XML.marshalFilter(
1384 firstFilter, filters, filter.isAnded()));
1388 * save colour scheme for the feature type
1390 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1391 if (!fcol.isSimpleColour())
1393 setting.setColour(fcol.getMaxColour().getRGB());
1394 setting.setMincolour(fcol.getMinColour().getRGB());
1395 setting.setMin(fcol.getMin());
1396 setting.setMax(fcol.getMax());
1397 setting.setColourByLabel(fcol.isColourByLabel());
1398 if (fcol.isColourByAttribute())
1400 setting.setAttributeName(fcol.getAttributeName());
1402 setting.setAutoScale(fcol.isAutoScaled());
1403 setting.setThreshold(fcol.getThreshold());
1404 Color noColour = fcol.getNoColour();
1405 if (noColour == null)
1407 setting.setNoValueColour(NoValueColour.NONE);
1409 else if (noColour.equals(fcol.getMaxColour()))
1411 setting.setNoValueColour(NoValueColour.MAX);
1415 setting.setNoValueColour(NoValueColour.MIN);
1417 // -1 = No threshold, 0 = Below, 1 = Above
1418 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1419 : (fcol.isBelowThreshold() ? 0 : -1));
1423 setting.setColour(fcol.getColour().getRGB());
1427 av.getFeaturesDisplayed().isVisible(featureType));
1429 .getOrder(featureType);
1432 setting.setOrder(rorder);
1434 fs.addSetting(setting);
1435 settingsAdded.addElement(featureType);
1439 // is groups actually supposed to be a map here ?
1440 Iterator<String> en = fr.getFeatureGroups().iterator();
1441 Vector<String> groupsAdded = new Vector<>();
1442 while (en.hasNext())
1444 String grp = en.next();
1445 if (groupsAdded.contains(grp))
1449 Group g = new Group();
1451 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1454 groupsAdded.addElement(grp);
1456 jms.setFeatureSettings(fs);
1459 if (av.hasHiddenColumns())
1461 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1462 .getHiddenColumns();
1465 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1469 Iterator<int[]> hiddenRegions = hidden.iterator();
1470 while (hiddenRegions.hasNext())
1472 int[] region = hiddenRegions.next();
1473 HiddenColumns hc = new HiddenColumns();
1474 hc.setStart(region[0]);
1475 hc.setEnd(region[1]);
1476 view.addHiddenColumns(hc);
1480 if (calcIdSet.size() > 0)
1482 for (String calcId : calcIdSet)
1484 if (calcId.trim().length() > 0)
1486 CalcIdParam cidp = createCalcIdParam(calcId, av);
1487 // Some calcIds have no parameters.
1490 view.addCalcIdParam(cidp);
1496 jms.addViewport(view);
1498 object.setJalviewModelSequence(jms);
1499 object.getVamsasModel().addSequenceSet(vamsasSet);
1501 if (jout != null && fileName != null)
1503 // We may not want to write the object to disk,
1504 // eg we can copy the alignViewport to a new view object
1505 // using save and then load
1508 System.out.println("Writing jar entry " + fileName);
1509 JarEntry entry = new JarEntry(fileName);
1510 jout.putNextEntry(entry);
1511 PrintWriter pout = new PrintWriter(
1512 new OutputStreamWriter(jout, UTF_8));
1513 Marshaller marshaller = new Marshaller(pout);
1514 marshaller.marshal(object);
1517 } catch (Exception ex)
1519 // TODO: raise error in GUI if marshalling failed.
1520 ex.printStackTrace();
1527 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1528 * for each viewer, with
1530 * <li>viewer geometry (position, size, split pane divider location)</li>
1531 * <li>index of the selected structure in the viewer (currently shows gapped
1533 * <li>the id of the annotation holding RNA secondary structure</li>
1534 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1536 * Varna viewer state is also written out (in native Varna XML) to separate
1537 * project jar entries. A separate entry is written for each RNA structure
1538 * displayed, with the naming convention
1540 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1548 * @param storeDataset
1550 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1551 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1552 boolean storeDataset)
1554 if (Desktop.desktop == null)
1558 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1559 for (int f = frames.length - 1; f > -1; f--)
1561 if (frames[f] instanceof AppVarna)
1563 AppVarna varna = (AppVarna) frames[f];
1565 * link the sequence to every viewer that is showing it and is linked to
1566 * its alignment panel
1568 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1570 String viewId = varna.getViewId();
1571 RnaViewer rna = new RnaViewer();
1572 rna.setViewId(viewId);
1573 rna.setTitle(varna.getTitle());
1574 rna.setXpos(varna.getX());
1575 rna.setYpos(varna.getY());
1576 rna.setWidth(varna.getWidth());
1577 rna.setHeight(varna.getHeight());
1578 rna.setDividerLocation(varna.getDividerLocation());
1579 rna.setSelectedRna(varna.getSelectedIndex());
1580 jseq.addRnaViewer(rna);
1583 * Store each Varna panel's state once in the project per sequence.
1584 * First time through only (storeDataset==false)
1586 // boolean storeSessions = false;
1587 // String sequenceViewId = viewId + seqsToIds.get(jds);
1588 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1590 // viewIds.add(sequenceViewId);
1591 // storeSessions = true;
1593 for (RnaModel model : varna.getModels())
1595 if (model.seq == jds)
1598 * VARNA saves each view (sequence or alignment secondary
1599 * structure, gapped or trimmed) as a separate XML file
1601 String jarEntryName = rnaSessions.get(model);
1602 if (jarEntryName == null)
1605 String varnaStateFile = varna.getStateInfo(model.rna);
1606 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1607 copyFileToJar(jout, varnaStateFile, jarEntryName);
1608 rnaSessions.put(model, jarEntryName);
1610 SecondaryStructure ss = new SecondaryStructure();
1611 String annotationId = varna.getAnnotation(jds).annotationId;
1612 ss.setAnnotationId(annotationId);
1613 ss.setViewerState(jarEntryName);
1614 ss.setGapped(model.gapped);
1615 ss.setTitle(model.title);
1616 rna.addSecondaryStructure(ss);
1625 * Copy the contents of a file to a new entry added to the output jar
1629 * @param jarEntryName
1631 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1632 String jarEntryName)
1634 DataInputStream dis = null;
1637 File file = new File(infilePath);
1638 if (file.exists() && jout != null)
1640 dis = new DataInputStream(new FileInputStream(file));
1641 byte[] data = new byte[(int) file.length()];
1642 dis.readFully(data);
1643 writeJarEntry(jout, jarEntryName, data);
1645 } catch (Exception ex)
1647 ex.printStackTrace();
1655 } catch (IOException e)
1664 * Write the data to a new entry of given name in the output jar file
1667 * @param jarEntryName
1669 * @throws IOException
1671 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1672 byte[] data) throws IOException
1676 System.out.println("Writing jar entry " + jarEntryName);
1677 jout.putNextEntry(new JarEntry(jarEntryName));
1678 DataOutputStream dout = new DataOutputStream(jout);
1679 dout.write(data, 0, data.length);
1686 * Save the state of a structure viewer
1691 * the archive XML element under which to save the state
1694 * @param matchedFile
1698 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1699 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1700 String matchedFile, StructureViewerBase viewFrame)
1702 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1705 * Look for any bindings for this viewer to the PDB file of interest
1706 * (including part matches excluding chain id)
1708 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1710 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1711 final String pdbId = pdbentry.getId();
1712 if (!pdbId.equals(entry.getId())
1713 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1714 .startsWith(pdbId.toLowerCase())))
1717 * not interested in a binding to a different PDB entry here
1721 if (matchedFile == null)
1723 matchedFile = pdbentry.getFile();
1725 else if (!matchedFile.equals(pdbentry.getFile()))
1728 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1729 + pdbentry.getFile());
1733 // can get at it if the ID
1734 // match is ambiguous (e.g.
1737 for (int smap = 0; smap < viewFrame.getBinding()
1738 .getSequence()[peid].length; smap++)
1740 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1741 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1743 StructureState state = new StructureState();
1744 state.setVisible(true);
1745 state.setXpos(viewFrame.getX());
1746 state.setYpos(viewFrame.getY());
1747 state.setWidth(viewFrame.getWidth());
1748 state.setHeight(viewFrame.getHeight());
1749 final String viewId = viewFrame.getViewId();
1750 state.setViewId(viewId);
1751 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1752 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1753 state.setColourByJmol(viewFrame.isColouredByViewer());
1754 state.setType(viewFrame.getViewerType().toString());
1755 pdb.addStructureState(state);
1763 * Populates the AnnotationColours xml for save. This captures the settings of
1764 * the options in the 'Colour by Annotation' dialog.
1767 * @param userColours
1771 private AnnotationColours constructAnnotationColours(
1772 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1773 JalviewModelSequence jms)
1775 AnnotationColours ac = new AnnotationColours();
1776 ac.setAboveThreshold(acg.getAboveThreshold());
1777 ac.setThreshold(acg.getAnnotationThreshold());
1778 // 2.10.2 save annotationId (unique) not annotation label
1779 ac.setAnnotation(acg.getAnnotation().annotationId);
1780 if (acg.getBaseColour() instanceof UserColourScheme)
1783 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1788 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1791 ac.setMaxColour(acg.getMaxColour().getRGB());
1792 ac.setMinColour(acg.getMinColour().getRGB());
1793 ac.setPerSequence(acg.isSeqAssociated());
1794 ac.setPredefinedColours(acg.isPredefinedColours());
1798 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1799 IdentityHashMap<SequenceGroup, String> groupRefs,
1800 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1801 SequenceSet vamsasSet)
1804 for (int i = 0; i < aa.length; i++)
1806 Annotation an = new Annotation();
1808 AlignmentAnnotation annotation = aa[i];
1809 if (annotation.annotationId != null)
1811 annotationIds.put(annotation.annotationId, annotation);
1814 an.setId(annotation.annotationId);
1816 an.setVisible(annotation.visible);
1818 an.setDescription(annotation.description);
1820 if (annotation.sequenceRef != null)
1822 // 2.9 JAL-1781 xref on sequence id rather than name
1823 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1825 if (annotation.groupRef != null)
1827 String groupIdr = groupRefs.get(annotation.groupRef);
1828 if (groupIdr == null)
1830 // make a locally unique String
1831 groupRefs.put(annotation.groupRef,
1832 groupIdr = ("" + System.currentTimeMillis()
1833 + annotation.groupRef.getName()
1834 + groupRefs.size()));
1836 an.setGroupRef(groupIdr.toString());
1839 // store all visualization attributes for annotation
1840 an.setGraphHeight(annotation.graphHeight);
1841 an.setCentreColLabels(annotation.centreColLabels);
1842 an.setScaleColLabels(annotation.scaleColLabel);
1843 an.setShowAllColLabels(annotation.showAllColLabels);
1844 an.setBelowAlignment(annotation.belowAlignment);
1846 if (annotation.graph > 0)
1849 an.setGraphType(annotation.graph);
1850 an.setGraphGroup(annotation.graphGroup);
1851 if (annotation.getThreshold() != null)
1853 ThresholdLine line = new ThresholdLine();
1854 line.setLabel(annotation.getThreshold().label);
1855 line.setValue(annotation.getThreshold().value);
1856 line.setColour(annotation.getThreshold().colour.getRGB());
1857 an.setThresholdLine(line);
1865 an.setLabel(annotation.label);
1867 if (annotation == av.getAlignmentQualityAnnot()
1868 || annotation == av.getAlignmentConservationAnnotation()
1869 || annotation == av.getAlignmentConsensusAnnotation()
1870 || annotation.autoCalculated)
1872 // new way of indicating autocalculated annotation -
1873 an.setAutoCalculated(annotation.autoCalculated);
1875 if (annotation.hasScore())
1877 an.setScore(annotation.getScore());
1880 if (annotation.getCalcId() != null)
1882 calcIdSet.add(annotation.getCalcId());
1883 an.setCalcId(annotation.getCalcId());
1885 if (annotation.hasProperties())
1887 for (String pr : annotation.getProperties())
1889 Property prop = new Property();
1891 prop.setValue(annotation.getProperty(pr));
1892 an.addProperty(prop);
1896 AnnotationElement ae;
1897 if (annotation.annotations != null)
1899 an.setScoreOnly(false);
1900 for (int a = 0; a < annotation.annotations.length; a++)
1902 if ((annotation == null) || (annotation.annotations[a] == null))
1907 ae = new AnnotationElement();
1908 if (annotation.annotations[a].description != null)
1910 ae.setDescription(annotation.annotations[a].description);
1912 if (annotation.annotations[a].displayCharacter != null)
1914 ae.setDisplayCharacter(
1915 annotation.annotations[a].displayCharacter);
1918 if (!Float.isNaN(annotation.annotations[a].value))
1920 ae.setValue(annotation.annotations[a].value);
1924 if (annotation.annotations[a].secondaryStructure > ' ')
1926 ae.setSecondaryStructure(
1927 annotation.annotations[a].secondaryStructure + "");
1930 if (annotation.annotations[a].colour != null
1931 && annotation.annotations[a].colour != java.awt.Color.black)
1933 ae.setColour(annotation.annotations[a].colour.getRGB());
1936 an.addAnnotationElement(ae);
1937 if (annotation.autoCalculated)
1939 // only write one non-null entry into the annotation row -
1940 // sufficient to get the visualization attributes necessary to
1948 an.setScoreOnly(true);
1950 if (!storeDS || (storeDS && !annotation.autoCalculated))
1952 // skip autocalculated annotation - these are only provided for
1954 vamsasSet.addAnnotation(an);
1960 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1962 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1963 if (settings != null)
1965 CalcIdParam vCalcIdParam = new CalcIdParam();
1966 vCalcIdParam.setCalcId(calcId);
1967 vCalcIdParam.addServiceURL(settings.getServiceURI());
1968 // generic URI allowing a third party to resolve another instance of the
1969 // service used for this calculation
1970 for (String urls : settings.getServiceURLs())
1972 vCalcIdParam.addServiceURL(urls);
1974 vCalcIdParam.setVersion("1.0");
1975 if (settings.getPreset() != null)
1977 WsParamSetI setting = settings.getPreset();
1978 vCalcIdParam.setName(setting.getName());
1979 vCalcIdParam.setDescription(setting.getDescription());
1983 vCalcIdParam.setName("");
1984 vCalcIdParam.setDescription("Last used parameters");
1986 // need to be able to recover 1) settings 2) user-defined presets or
1987 // recreate settings from preset 3) predefined settings provided by
1988 // service - or settings that can be transferred (or discarded)
1989 vCalcIdParam.setParameters(
1990 settings.getWsParamFile().replace("\n", "|\\n|"));
1991 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1992 // todo - decide if updateImmediately is needed for any projects.
1994 return vCalcIdParam;
1999 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2002 if (calcIdParam.getVersion().equals("1.0"))
2004 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2005 .getPreferredServiceFor(calcIdParam.getServiceURL());
2006 if (service != null)
2008 WsParamSetI parmSet = null;
2011 parmSet = service.getParamStore().parseServiceParameterFile(
2012 calcIdParam.getName(), calcIdParam.getDescription(),
2013 calcIdParam.getServiceURL(),
2014 calcIdParam.getParameters().replace("|\\n|", "\n"));
2015 } catch (IOException x)
2017 warn("Couldn't parse parameter data for "
2018 + calcIdParam.getCalcId(), x);
2021 List<ArgumentI> argList = null;
2022 if (calcIdParam.getName().length() > 0)
2024 parmSet = service.getParamStore()
2025 .getPreset(calcIdParam.getName());
2026 if (parmSet != null)
2028 // TODO : check we have a good match with settings in AACon -
2029 // otherwise we'll need to create a new preset
2034 argList = parmSet.getArguments();
2037 AAConSettings settings = new AAConSettings(
2038 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2039 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2040 calcIdParam.isNeedsUpdate());
2045 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2049 throw new Error(MessageManager.formatMessage(
2050 "error.unsupported_version_calcIdparam", new Object[]
2051 { calcIdParam.toString() }));
2055 * External mapping between jalview objects and objects yielding a valid and
2056 * unique object ID string. This is null for normal Jalview project IO, but
2057 * non-null when a jalview project is being read or written as part of a
2060 IdentityHashMap jv2vobj = null;
2063 * Construct a unique ID for jvobj using either existing bindings or if none
2064 * exist, the result of the hashcode call for the object.
2067 * jalview data object
2068 * @return unique ID for referring to jvobj
2070 private String makeHashCode(Object jvobj, String altCode)
2072 if (jv2vobj != null)
2074 Object id = jv2vobj.get(jvobj);
2077 return id.toString();
2079 // check string ID mappings
2080 if (jvids2vobj != null && jvobj instanceof String)
2082 id = jvids2vobj.get(jvobj);
2086 return id.toString();
2088 // give up and warn that something has gone wrong
2089 warn("Cannot find ID for object in external mapping : " + jvobj);
2095 * return local jalview object mapped to ID, if it exists
2099 * @return null or object bound to idcode
2101 private Object retrieveExistingObj(String idcode)
2103 if (idcode != null && vobj2jv != null)
2105 return vobj2jv.get(idcode);
2111 * binding from ID strings from external mapping table to jalview data model
2114 private Hashtable vobj2jv;
2116 private Sequence createVamsasSequence(String id, SequenceI jds)
2118 return createVamsasSequence(true, id, jds, null);
2121 private Sequence createVamsasSequence(boolean recurse, String id,
2122 SequenceI jds, SequenceI parentseq)
2124 Sequence vamsasSeq = new Sequence();
2125 vamsasSeq.setId(id);
2126 vamsasSeq.setName(jds.getName());
2127 vamsasSeq.setSequence(jds.getSequenceAsString());
2128 vamsasSeq.setDescription(jds.getDescription());
2129 jalview.datamodel.DBRefEntry[] dbrefs = null;
2130 if (jds.getDatasetSequence() != null)
2132 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2136 // seqId==dsseqid so we can tell which sequences really are
2137 // dataset sequences only
2138 vamsasSeq.setDsseqid(id);
2139 dbrefs = jds.getDBRefs();
2140 if (parentseq == null)
2147 for (int d = 0; d < dbrefs.length; d++)
2149 DBRef dbref = new DBRef();
2150 dbref.setSource(dbrefs[d].getSource());
2151 dbref.setVersion(dbrefs[d].getVersion());
2152 dbref.setAccessionId(dbrefs[d].getAccessionId());
2153 if (dbrefs[d].hasMap())
2155 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2157 dbref.setMapping(mp);
2159 vamsasSeq.addDBRef(dbref);
2165 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2166 SequenceI parentseq, SequenceI jds, boolean recurse)
2169 if (jmp.getMap() != null)
2173 jalview.util.MapList mlst = jmp.getMap();
2174 List<int[]> r = mlst.getFromRanges();
2175 for (int[] range : r)
2177 MapListFrom mfrom = new MapListFrom();
2178 mfrom.setStart(range[0]);
2179 mfrom.setEnd(range[1]);
2180 mp.addMapListFrom(mfrom);
2182 r = mlst.getToRanges();
2183 for (int[] range : r)
2185 MapListTo mto = new MapListTo();
2186 mto.setStart(range[0]);
2187 mto.setEnd(range[1]);
2188 mp.addMapListTo(mto);
2190 mp.setMapFromUnit(mlst.getFromRatio());
2191 mp.setMapToUnit(mlst.getToRatio());
2192 if (jmp.getTo() != null)
2194 MappingChoice mpc = new MappingChoice();
2196 // check/create ID for the sequence referenced by getTo()
2199 SequenceI ps = null;
2200 if (parentseq != jmp.getTo()
2201 && parentseq.getDatasetSequence() != jmp.getTo())
2203 // chaining dbref rather than a handshaking one
2204 jmpid = seqHash(ps = jmp.getTo());
2208 jmpid = seqHash(ps = parentseq);
2210 mpc.setDseqFor(jmpid);
2211 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2213 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2214 seqRefIds.put(mpc.getDseqFor(), ps);
2218 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2221 mp.setMappingChoice(mpc);
2227 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2228 List<UserColourScheme> userColours, JalviewModelSequence jms)
2231 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2232 boolean newucs = false;
2233 if (!userColours.contains(ucs))
2235 userColours.add(ucs);
2238 id = "ucs" + userColours.indexOf(ucs);
2241 // actually create the scheme's entry in the XML model
2242 java.awt.Color[] colours = ucs.getColours();
2243 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2244 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
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]);
2250 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2251 jbucs.addColour(col);
2253 if (ucs.getLowerCaseColours() != null)
2255 colours = ucs.getLowerCaseColours();
2256 for (int i = 0; i < colours.length; i++)
2258 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2259 col.setName(ResidueProperties.aa[i].toLowerCase());
2260 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2261 jbucs.addColour(col);
2266 uc.setUserColourScheme(jbucs);
2267 jms.addUserColours(uc);
2273 jalview.schemes.UserColourScheme getUserColourScheme(
2274 JalviewModelSequence jms, String id)
2276 UserColours[] uc = jms.getUserColours();
2277 UserColours colours = null;
2279 for (int i = 0; i < uc.length; i++)
2281 if (uc[i].getId().equals(id))
2289 java.awt.Color[] newColours = new java.awt.Color[24];
2291 for (int i = 0; i < 24; i++)
2293 newColours[i] = new java.awt.Color(Integer.parseInt(
2294 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2297 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2300 if (colours.getUserColourScheme().getColourCount() > 24)
2302 newColours = new java.awt.Color[23];
2303 for (int i = 0; i < 23; i++)
2305 newColours[i] = new java.awt.Color(Integer.parseInt(
2306 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2309 ucs.setLowerCaseColours(newColours);
2316 * contains last error message (if any) encountered by XML loader.
2318 String errorMessage = null;
2321 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2322 * exceptions are raised during project XML parsing
2324 public boolean attemptversion1parse = true;
2327 * Load a jalview project archive from a jar file
2330 * - HTTP URL or filename
2332 public AlignFrame loadJalviewAlign(final String file)
2335 jalview.gui.AlignFrame af = null;
2339 // create list to store references for any new Jmol viewers created
2340 newStructureViewers = new Vector<>();
2341 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2342 // Workaround is to make sure caller implements the JarInputStreamProvider
2344 // so we can re-open the jar input stream for each entry.
2346 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2347 af = loadJalviewAlign(jprovider);
2348 af.setMenusForViewport();
2350 } catch (MalformedURLException e)
2352 errorMessage = "Invalid URL format for '" + file + "'";
2358 SwingUtilities.invokeAndWait(new Runnable()
2363 setLoadingFinishedForNewStructureViewers();
2366 } catch (Exception x)
2368 System.err.println("Error loading alignment: " + x.getMessage());
2374 private jarInputStreamProvider createjarInputStreamProvider(
2375 final String file) throws MalformedURLException
2378 errorMessage = null;
2379 uniqueSetSuffix = null;
2381 viewportsAdded.clear();
2382 frefedSequence = null;
2384 if (file.startsWith("http://"))
2386 url = new URL(file);
2388 final URL _url = url;
2389 return new jarInputStreamProvider()
2393 public JarInputStream getJarInputStream() throws IOException
2397 return new JarInputStream(_url.openStream());
2401 return new JarInputStream(new FileInputStream(file));
2406 public String getFilename()
2414 * Recover jalview session from a jalview project archive. Caller may
2415 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2416 * themselves. Any null fields will be initialised with default values,
2417 * non-null fields are left alone.
2422 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2424 errorMessage = null;
2425 if (uniqueSetSuffix == null)
2427 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2429 if (seqRefIds == null)
2433 AlignFrame af = null, _af = null;
2434 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2435 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2436 final String file = jprovider.getFilename();
2439 JarInputStream jin = null;
2440 JarEntry jarentry = null;
2445 jin = jprovider.getJarInputStream();
2446 for (int i = 0; i < entryCount; i++)
2448 jarentry = jin.getNextJarEntry();
2451 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2453 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2454 JalviewModel object = new JalviewModel();
2456 Unmarshaller unmar = new Unmarshaller(object);
2457 unmar.setValidation(false);
2458 object = (JalviewModel) unmar.unmarshal(in);
2459 if (true) // !skipViewport(object))
2461 _af = loadFromObject(object, file, true, jprovider);
2462 if (_af != null && object.getJalviewModelSequence()
2463 .getViewportCount() > 0)
2467 // store a reference to the first view
2470 if (_af.viewport.isGatherViewsHere())
2472 // if this is a gathered view, keep its reference since
2473 // after gathering views, only this frame will remain
2475 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2477 // Save dataset to register mappings once all resolved
2478 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2479 af.viewport.getAlignment().getDataset());
2484 else if (jarentry != null)
2486 // Some other file here.
2489 } while (jarentry != null);
2490 resolveFrefedSequences();
2491 } catch (IOException ex)
2493 ex.printStackTrace();
2494 errorMessage = "Couldn't locate Jalview XML file : " + file;
2496 "Exception whilst loading jalview XML file : " + ex + "\n");
2497 } catch (Exception ex)
2499 System.err.println("Parsing as Jalview Version 2 file failed.");
2500 ex.printStackTrace(System.err);
2501 if (attemptversion1parse)
2503 // Is Version 1 Jar file?
2506 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2507 } catch (Exception ex2)
2509 System.err.println("Exception whilst loading as jalviewXMLV1:");
2510 ex2.printStackTrace();
2514 if (Desktop.instance != null)
2516 Desktop.instance.stopLoading();
2520 System.out.println("Successfully loaded archive file");
2523 ex.printStackTrace();
2526 "Exception whilst loading jalview XML file : " + ex + "\n");
2527 } catch (OutOfMemoryError e)
2529 // Don't use the OOM Window here
2530 errorMessage = "Out of memory loading jalview XML file";
2531 System.err.println("Out of memory whilst loading jalview XML file");
2532 e.printStackTrace();
2536 * Regather multiple views (with the same sequence set id) to the frame (if
2537 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2538 * views instead of separate frames. Note this doesn't restore a state where
2539 * some expanded views in turn have tabbed views - the last "first tab" read
2540 * in will play the role of gatherer for all.
2542 for (AlignFrame fr : gatherToThisFrame.values())
2544 Desktop.instance.gatherViews(fr);
2547 restoreSplitFrames();
2548 for (AlignmentI ds : importedDatasets.keySet())
2550 if (ds.getCodonFrames() != null)
2552 StructureSelectionManager
2553 .getStructureSelectionManager(Desktop.instance)
2554 .registerMappings(ds.getCodonFrames());
2557 if (errorMessage != null)
2562 if (Desktop.instance != null)
2564 Desktop.instance.stopLoading();
2571 * Try to reconstruct and display SplitFrame windows, where each contains
2572 * complementary dna and protein alignments. Done by pairing up AlignFrame
2573 * objects (created earlier) which have complementary viewport ids associated.
2575 protected void restoreSplitFrames()
2577 List<SplitFrame> gatherTo = new ArrayList<>();
2578 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2579 Map<String, AlignFrame> dna = new HashMap<>();
2582 * Identify the DNA alignments
2584 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2587 AlignFrame af = candidate.getValue();
2588 if (af.getViewport().getAlignment().isNucleotide())
2590 dna.put(candidate.getKey().getId(), af);
2595 * Try to match up the protein complements
2597 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2600 AlignFrame af = candidate.getValue();
2601 if (!af.getViewport().getAlignment().isNucleotide())
2603 String complementId = candidate.getKey().getComplementId();
2604 // only non-null complements should be in the Map
2605 if (complementId != null && dna.containsKey(complementId))
2607 final AlignFrame dnaFrame = dna.get(complementId);
2608 SplitFrame sf = createSplitFrame(dnaFrame, af);
2609 addedToSplitFrames.add(dnaFrame);
2610 addedToSplitFrames.add(af);
2611 dnaFrame.setMenusForViewport();
2612 af.setMenusForViewport();
2613 if (af.viewport.isGatherViewsHere())
2622 * Open any that we failed to pair up (which shouldn't happen!) as
2623 * standalone AlignFrame's.
2625 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2628 AlignFrame af = candidate.getValue();
2629 if (!addedToSplitFrames.contains(af))
2631 Viewport view = candidate.getKey();
2632 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2634 af.setMenusForViewport();
2635 System.err.println("Failed to restore view " + view.getTitle()
2636 + " to split frame");
2641 * Gather back into tabbed views as flagged.
2643 for (SplitFrame sf : gatherTo)
2645 Desktop.instance.gatherViews(sf);
2648 splitFrameCandidates.clear();
2652 * Construct and display one SplitFrame holding DNA and protein alignments.
2655 * @param proteinFrame
2658 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2659 AlignFrame proteinFrame)
2661 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2662 String title = MessageManager.getString("label.linked_view_title");
2663 int width = (int) dnaFrame.getBounds().getWidth();
2664 int height = (int) (dnaFrame.getBounds().getHeight()
2665 + proteinFrame.getBounds().getHeight() + 50);
2668 * SplitFrame location is saved to both enclosed frames
2670 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2671 Desktop.addInternalFrame(splitFrame, title, width, height);
2674 * And compute cDNA consensus (couldn't do earlier with consensus as
2675 * mappings were not yet present)
2677 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2683 * check errorMessage for a valid error message and raise an error box in the
2684 * GUI or write the current errorMessage to stderr and then clear the error
2687 protected void reportErrors()
2689 reportErrors(false);
2692 protected void reportErrors(final boolean saving)
2694 if (errorMessage != null)
2696 final String finalErrorMessage = errorMessage;
2699 javax.swing.SwingUtilities.invokeLater(new Runnable()
2704 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2706 "Error " + (saving ? "saving" : "loading")
2708 JvOptionPane.WARNING_MESSAGE);
2714 System.err.println("Problem loading Jalview file: " + errorMessage);
2717 errorMessage = null;
2720 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2723 * when set, local views will be updated from view stored in JalviewXML
2724 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2725 * sync if this is set to true.
2727 private final boolean updateLocalViews = false;
2730 * Returns the path to a temporary file holding the PDB file for the given PDB
2731 * id. The first time of asking, searches for a file of that name in the
2732 * Jalview project jar, and copies it to a new temporary file. Any repeat
2733 * requests just return the path to the file previously created.
2739 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2742 if (alreadyLoadedPDB.containsKey(pdbId))
2744 return alreadyLoadedPDB.get(pdbId).toString();
2747 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2749 if (tempFile != null)
2751 alreadyLoadedPDB.put(pdbId, tempFile);
2757 * Copies the jar entry of given name to a new temporary file and returns the
2758 * path to the file, or null if the entry is not found.
2761 * @param jarEntryName
2763 * a prefix for the temporary file name, must be at least three
2766 * null or original file - so new file can be given the same suffix
2770 protected String copyJarEntry(jarInputStreamProvider jprovider,
2771 String jarEntryName, String prefix, String origFile)
2773 BufferedReader in = null;
2774 PrintWriter out = null;
2775 String suffix = ".tmp";
2776 if (origFile == null)
2778 origFile = jarEntryName;
2780 int sfpos = origFile.lastIndexOf(".");
2781 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2783 suffix = "." + origFile.substring(sfpos + 1);
2787 JarInputStream jin = jprovider.getJarInputStream();
2789 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2790 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2791 * FileInputStream(jprovider)); }
2794 JarEntry entry = null;
2797 entry = jin.getNextJarEntry();
2798 } while (entry != null && !entry.getName().equals(jarEntryName));
2801 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2802 File outFile = File.createTempFile(prefix, suffix);
2803 outFile.deleteOnExit();
2804 out = new PrintWriter(new FileOutputStream(outFile));
2807 while ((data = in.readLine()) != null)
2812 String t = outFile.getAbsolutePath();
2817 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2819 } catch (Exception ex)
2821 ex.printStackTrace();
2829 } catch (IOException e)
2843 private class JvAnnotRow
2845 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2852 * persisted version of annotation row from which to take vis properties
2854 public jalview.datamodel.AlignmentAnnotation template;
2857 * original position of the annotation row in the alignment
2863 * Load alignment frame from jalview XML DOM object
2868 * filename source string
2869 * @param loadTreesAndStructures
2870 * when false only create Viewport
2872 * data source provider
2873 * @return alignment frame created from view stored in DOM
2875 AlignFrame loadFromObject(JalviewModel object, String file,
2876 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2878 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2879 Sequence[] vamsasSeq = vamsasSet.getSequence();
2881 JalviewModelSequence jms = object.getJalviewModelSequence();
2883 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2886 // ////////////////////////////////
2889 List<SequenceI> hiddenSeqs = null;
2891 List<SequenceI> tmpseqs = new ArrayList<>();
2893 boolean multipleView = false;
2894 SequenceI referenceseqForView = null;
2895 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2896 int vi = 0; // counter in vamsasSeq array
2897 for (int i = 0; i < jseqs.length; i++)
2899 String seqId = jseqs[i].getId();
2901 SequenceI tmpSeq = seqRefIds.get(seqId);
2904 if (!incompleteSeqs.containsKey(seqId))
2906 // may not need this check, but keep it for at least 2.9,1 release
2907 if (tmpSeq.getStart() != jseqs[i].getStart()
2908 || tmpSeq.getEnd() != jseqs[i].getEnd())
2911 "Warning JAL-2154 regression: updating start/end for sequence "
2912 + tmpSeq.toString() + " to " + jseqs[i]);
2917 incompleteSeqs.remove(seqId);
2919 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2921 // most likely we are reading a dataset XML document so
2922 // update from vamsasSeq section of XML for this sequence
2923 tmpSeq.setName(vamsasSeq[vi].getName());
2924 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2925 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2930 // reading multiple views, so vamsasSeq set is a subset of JSeq
2931 multipleView = true;
2933 tmpSeq.setStart(jseqs[i].getStart());
2934 tmpSeq.setEnd(jseqs[i].getEnd());
2935 tmpseqs.add(tmpSeq);
2939 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2940 vamsasSeq[vi].getSequence());
2941 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2942 tmpSeq.setStart(jseqs[i].getStart());
2943 tmpSeq.setEnd(jseqs[i].getEnd());
2944 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2945 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2946 tmpseqs.add(tmpSeq);
2950 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2952 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2955 if (jseqs[i].getHidden())
2957 if (hiddenSeqs == null)
2959 hiddenSeqs = new ArrayList<>();
2962 hiddenSeqs.add(tmpSeq);
2967 // Create the alignment object from the sequence set
2968 // ///////////////////////////////
2969 SequenceI[] orderedSeqs = tmpseqs
2970 .toArray(new SequenceI[tmpseqs.size()]);
2972 AlignmentI al = null;
2973 // so we must create or recover the dataset alignment before going further
2974 // ///////////////////////////////
2975 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2977 // older jalview projects do not have a dataset - so creat alignment and
2979 al = new Alignment(orderedSeqs);
2980 al.setDataset(null);
2984 boolean isdsal = object.getJalviewModelSequence()
2985 .getViewportCount() == 0;
2988 // we are importing a dataset record, so
2989 // recover reference to an alignment already materialsed as dataset
2990 al = getDatasetFor(vamsasSet.getDatasetId());
2994 // materialse the alignment
2995 al = new Alignment(orderedSeqs);
2999 addDatasetRef(vamsasSet.getDatasetId(), al);
3002 // finally, verify all data in vamsasSet is actually present in al
3003 // passing on flag indicating if it is actually a stored dataset
3004 recoverDatasetFor(vamsasSet, al, isdsal);
3007 if (referenceseqForView != null)
3009 al.setSeqrep(referenceseqForView);
3011 // / Add the alignment properties
3012 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3014 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3015 al.setProperty(ssp.getKey(), ssp.getValue());
3018 // ///////////////////////////////
3020 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3023 // load sequence features, database references and any associated PDB
3024 // structures for the alignment
3026 // prior to 2.10, this part would only be executed the first time a
3027 // sequence was encountered, but not afterwards.
3028 // now, for 2.10 projects, this is also done if the xml doc includes
3029 // dataset sequences not actually present in any particular view.
3031 for (int i = 0; i < vamsasSeq.length; i++)
3033 if (jseqs[i].getFeaturesCount() > 0)
3035 Features[] features = jseqs[i].getFeatures();
3036 for (int f = 0; f < features.length; f++)
3038 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3039 features[f].getDescription(), features[f].getBegin(),
3040 features[f].getEnd(), features[f].getScore(),
3041 features[f].getFeatureGroup());
3042 sf.setStatus(features[f].getStatus());
3045 * load any feature attributes - include map-valued attributes
3047 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3048 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3050 OtherData keyValue = features[f].getOtherData(od);
3051 String attributeName = keyValue.getKey();
3052 String attributeValue = keyValue.getValue();
3053 if (attributeName.startsWith("LINK"))
3055 sf.addLink(attributeValue);
3059 String subAttribute = keyValue.getKey2();
3060 if (subAttribute == null)
3062 // simple string-valued attribute
3063 sf.setValue(attributeName, attributeValue);
3067 // attribute 'key' has sub-attribute 'key2'
3068 if (!mapAttributes.containsKey(attributeName))
3070 mapAttributes.put(attributeName, new HashMap<>());
3072 mapAttributes.get(attributeName).put(subAttribute,
3077 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3080 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3083 // adds feature to datasequence's feature set (since Jalview 2.10)
3084 al.getSequenceAt(i).addSequenceFeature(sf);
3087 if (vamsasSeq[i].getDBRefCount() > 0)
3089 // adds dbrefs to datasequence's set (since Jalview 2.10)
3091 al.getSequenceAt(i).getDatasetSequence() == null
3092 ? al.getSequenceAt(i)
3093 : al.getSequenceAt(i).getDatasetSequence(),
3096 if (jseqs[i].getPdbidsCount() > 0)
3098 Pdbids[] ids = jseqs[i].getPdbids();
3099 for (int p = 0; p < ids.length; p++)
3101 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3102 entry.setId(ids[p].getId());
3103 if (ids[p].getType() != null)
3105 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3107 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3111 entry.setType(PDBEntry.Type.FILE);
3114 // jprovider is null when executing 'New View'
3115 if (ids[p].getFile() != null && jprovider != null)
3117 if (!pdbloaded.containsKey(ids[p].getFile()))
3119 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3124 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3127 if (ids[p].getPdbentryItem() != null)
3129 for (PdbentryItem item : ids[p].getPdbentryItem())
3131 for (Property pr : item.getProperty())
3133 entry.setProperty(pr.getName(), pr.getValue());
3137 StructureSelectionManager
3138 .getStructureSelectionManager(Desktop.instance)
3139 .registerPDBEntry(entry);
3140 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3141 if (al.getSequenceAt(i).getDatasetSequence() != null)
3143 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3147 al.getSequenceAt(i).addPDBId(entry);
3152 } // end !multipleview
3154 // ///////////////////////////////
3155 // LOAD SEQUENCE MAPPINGS
3157 if (vamsasSet.getAlcodonFrameCount() > 0)
3159 // TODO Potentially this should only be done once for all views of an
3161 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3162 for (int i = 0; i < alc.length; i++)
3164 AlignedCodonFrame cf = new AlignedCodonFrame();
3165 if (alc[i].getAlcodMapCount() > 0)
3167 AlcodMap[] maps = alc[i].getAlcodMap();
3168 for (int m = 0; m < maps.length; m++)
3170 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3172 jalview.datamodel.Mapping mapping = null;
3173 // attach to dna sequence reference.
3174 if (maps[m].getMapping() != null)
3176 mapping = addMapping(maps[m].getMapping());
3177 if (dnaseq != null && mapping.getTo() != null)
3179 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3185 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3189 al.addCodonFrame(cf);
3194 // ////////////////////////////////
3196 List<JvAnnotRow> autoAlan = new ArrayList<>();
3199 * store any annotations which forward reference a group's ID
3201 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3203 if (vamsasSet.getAnnotationCount() > 0)
3205 Annotation[] an = vamsasSet.getAnnotation();
3207 for (int i = 0; i < an.length; i++)
3209 Annotation annotation = an[i];
3212 * test if annotation is automatically calculated for this view only
3214 boolean autoForView = false;
3215 if (annotation.getLabel().equals("Quality")
3216 || annotation.getLabel().equals("Conservation")
3217 || annotation.getLabel().equals("Consensus"))
3219 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3221 if (!annotation.hasAutoCalculated())
3223 annotation.setAutoCalculated(true);
3226 if (autoForView || (annotation.hasAutoCalculated()
3227 && annotation.isAutoCalculated()))
3229 // remove ID - we don't recover annotation from other views for
3230 // view-specific annotation
3231 annotation.setId(null);
3234 // set visiblity for other annotation in this view
3235 String annotationId = annotation.getId();
3236 if (annotationId != null && annotationIds.containsKey(annotationId))
3238 AlignmentAnnotation jda = annotationIds.get(annotationId);
3239 // in principle Visible should always be true for annotation displayed
3240 // in multiple views
3241 if (annotation.hasVisible())
3243 jda.visible = annotation.getVisible();
3246 al.addAnnotation(jda);
3250 // Construct new annotation from model.
3251 AnnotationElement[] ae = annotation.getAnnotationElement();
3252 jalview.datamodel.Annotation[] anot = null;
3253 java.awt.Color firstColour = null;
3255 if (!annotation.getScoreOnly())
3257 anot = new jalview.datamodel.Annotation[al.getWidth()];
3258 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3260 anpos = ae[aa].getPosition();
3262 if (anpos >= anot.length)
3267 anot[anpos] = new jalview.datamodel.Annotation(
3269 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3270 (ae[aa].getSecondaryStructure() == null
3271 || ae[aa].getSecondaryStructure().length() == 0)
3273 : ae[aa].getSecondaryStructure()
3278 // JBPNote: Consider verifying dataflow for IO of secondary
3279 // structure annotation read from Stockholm files
3280 // this was added to try to ensure that
3281 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3283 // anot[ae[aa].getPosition()].displayCharacter = "";
3285 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3286 if (firstColour == null)
3288 firstColour = anot[anpos].colour;
3292 jalview.datamodel.AlignmentAnnotation jaa = null;
3294 if (annotation.getGraph())
3296 float llim = 0, hlim = 0;
3297 // if (autoForView || an[i].isAutoCalculated()) {
3300 jaa = new jalview.datamodel.AlignmentAnnotation(
3301 annotation.getLabel(), annotation.getDescription(), anot,
3302 llim, hlim, annotation.getGraphType());
3304 jaa.graphGroup = annotation.getGraphGroup();
3305 jaa._linecolour = firstColour;
3306 if (annotation.getThresholdLine() != null)
3308 jaa.setThreshold(new jalview.datamodel.GraphLine(
3309 annotation.getThresholdLine().getValue(),
3310 annotation.getThresholdLine().getLabel(),
3312 annotation.getThresholdLine().getColour())));
3315 if (autoForView || annotation.isAutoCalculated())
3317 // Hardwire the symbol display line to ensure that labels for
3318 // histograms are displayed
3324 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3325 an[i].getDescription(), anot);
3326 jaa._linecolour = firstColour;
3328 // register new annotation
3329 if (an[i].getId() != null)
3331 annotationIds.put(an[i].getId(), jaa);
3332 jaa.annotationId = an[i].getId();
3334 // recover sequence association
3335 String sequenceRef = an[i].getSequenceRef();
3336 if (sequenceRef != null)
3338 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3339 SequenceI sequence = seqRefIds.get(sequenceRef);
3340 if (sequence == null)
3342 // in pre-2.9 projects sequence ref is to sequence name
3343 sequence = al.findName(sequenceRef);
3345 if (sequence != null)
3347 jaa.createSequenceMapping(sequence, 1, true);
3348 sequence.addAlignmentAnnotation(jaa);
3351 // and make a note of any group association
3352 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3354 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3355 .get(an[i].getGroupRef());
3358 aal = new ArrayList<>();
3359 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3364 if (an[i].hasScore())
3366 jaa.setScore(an[i].getScore());
3368 if (an[i].hasVisible())
3370 jaa.visible = an[i].getVisible();
3373 if (an[i].hasCentreColLabels())
3375 jaa.centreColLabels = an[i].getCentreColLabels();
3378 if (an[i].hasScaleColLabels())
3380 jaa.scaleColLabel = an[i].getScaleColLabels();
3382 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3384 // newer files have an 'autoCalculated' flag and store calculation
3385 // state in viewport properties
3386 jaa.autoCalculated = true; // means annotation will be marked for
3387 // update at end of load.
3389 if (an[i].hasGraphHeight())
3391 jaa.graphHeight = an[i].getGraphHeight();
3393 if (an[i].hasBelowAlignment())
3395 jaa.belowAlignment = an[i].isBelowAlignment();
3397 jaa.setCalcId(an[i].getCalcId());
3398 if (an[i].getPropertyCount() > 0)
3400 for (jalview.schemabinding.version2.Property prop : an[i]
3403 jaa.setProperty(prop.getName(), prop.getValue());
3406 if (jaa.autoCalculated)
3408 autoAlan.add(new JvAnnotRow(i, jaa));
3411 // if (!autoForView)
3413 // add autocalculated group annotation and any user created annotation
3415 al.addAnnotation(jaa);
3419 // ///////////////////////
3421 // Create alignment markup and styles for this view
3422 if (jms.getJGroupCount() > 0)
3424 JGroup[] groups = jms.getJGroup();
3425 boolean addAnnotSchemeGroup = false;
3426 for (int i = 0; i < groups.length; i++)
3428 JGroup jGroup = groups[i];
3429 ColourSchemeI cs = null;
3430 if (jGroup.getColour() != null)
3432 if (jGroup.getColour().startsWith("ucs"))
3434 cs = getUserColourScheme(jms, jGroup.getColour());
3436 else if (jGroup.getColour().equals("AnnotationColourGradient")
3437 && jGroup.getAnnotationColours() != null)
3439 addAnnotSchemeGroup = true;
3443 cs = ColourSchemeProperty.getColourScheme(al,
3444 jGroup.getColour());
3447 int pidThreshold = jGroup.getPidThreshold();
3449 Vector<SequenceI> seqs = new Vector<>();
3451 for (int s = 0; s < jGroup.getSeqCount(); s++)
3453 String seqId = jGroup.getSeq(s) + "";
3454 SequenceI ts = seqRefIds.get(seqId);
3458 seqs.addElement(ts);
3462 if (seqs.size() < 1)
3467 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3468 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3469 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3470 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3471 sg.getGroupColourScheme()
3472 .setConservationInc(jGroup.getConsThreshold());
3473 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3475 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3476 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3477 sg.setShowNonconserved(
3478 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3480 sg.thresholdTextColour = jGroup.getTextColThreshold();
3481 if (jGroup.hasShowConsensusHistogram())
3483 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3486 if (jGroup.hasShowSequenceLogo())
3488 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3490 if (jGroup.hasNormaliseSequenceLogo())
3492 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3494 if (jGroup.hasIgnoreGapsinConsensus())
3496 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3498 if (jGroup.getConsThreshold() != 0)
3500 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3503 c.verdict(false, 25);
3504 sg.cs.setConservation(c);
3507 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3509 // re-instate unique group/annotation row reference
3510 List<AlignmentAnnotation> jaal = groupAnnotRefs
3511 .get(jGroup.getId());
3514 for (AlignmentAnnotation jaa : jaal)
3517 if (jaa.autoCalculated)
3519 // match up and try to set group autocalc alignment row for this
3521 if (jaa.label.startsWith("Consensus for "))
3523 sg.setConsensus(jaa);
3525 // match up and try to set group autocalc alignment row for this
3527 if (jaa.label.startsWith("Conservation for "))
3529 sg.setConservationRow(jaa);
3536 if (addAnnotSchemeGroup)
3538 // reconstruct the annotation colourscheme
3539 sg.setColourScheme(constructAnnotationColour(
3540 jGroup.getAnnotationColours(), null, al, jms, false));
3546 // only dataset in this model, so just return.
3549 // ///////////////////////////////
3552 // If we just load in the same jar file again, the sequenceSetId
3553 // will be the same, and we end up with multiple references
3554 // to the same sequenceSet. We must modify this id on load
3555 // so that each load of the file gives a unique id
3556 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3557 String viewId = (view.getId() == null ? null
3558 : view.getId() + uniqueSetSuffix);
3559 AlignFrame af = null;
3560 AlignViewport av = null;
3561 // now check to see if we really need to create a new viewport.
3562 if (multipleView && viewportsAdded.size() == 0)
3564 // We recovered an alignment for which a viewport already exists.
3565 // TODO: fix up any settings necessary for overlaying stored state onto
3566 // state recovered from another document. (may not be necessary).
3567 // we may need a binding from a viewport in memory to one recovered from
3569 // and then recover its containing af to allow the settings to be applied.
3570 // TODO: fix for vamsas demo
3572 "About to recover a viewport for existing alignment: Sequence set ID is "
3574 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3575 if (seqsetobj != null)
3577 if (seqsetobj instanceof String)
3579 uniqueSeqSetId = (String) seqsetobj;
3581 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3587 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3593 * indicate that annotation colours are applied across all groups (pre
3594 * Jalview 2.8.1 behaviour)
3596 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3597 object.getVersion());
3599 AlignmentPanel ap = null;
3600 boolean isnewview = true;
3603 // Check to see if this alignment already has a view id == viewId
3604 jalview.gui.AlignmentPanel views[] = Desktop
3605 .getAlignmentPanels(uniqueSeqSetId);
3606 if (views != null && views.length > 0)
3608 for (int v = 0; v < views.length; v++)
3610 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3612 // recover the existing alignpanel, alignframe, viewport
3613 af = views[v].alignFrame;
3616 // TODO: could even skip resetting view settings if we don't want to
3617 // change the local settings from other jalview processes
3626 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3627 uniqueSeqSetId, viewId, autoAlan);
3633 * Load any trees, PDB structures and viewers
3635 * Not done if flag is false (when this method is used for New View)
3637 if (loadTreesAndStructures)
3639 loadTrees(jms, view, af, av, ap);
3640 loadPDBStructures(jprovider, jseqs, af, ap);
3641 loadRnaViewers(jprovider, jseqs, ap);
3643 // and finally return.
3648 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3649 * panel is restored from separate jar entries, two (gapped and trimmed) per
3650 * sequence and secondary structure.
3652 * Currently each viewer shows just one sequence and structure (gapped and
3653 * trimmed), however this method is designed to support multiple sequences or
3654 * structures in viewers if wanted in future.
3660 private void loadRnaViewers(jarInputStreamProvider jprovider,
3661 JSeq[] jseqs, AlignmentPanel ap)
3664 * scan the sequences for references to viewers; create each one the first
3665 * time it is referenced, add Rna models to existing viewers
3667 for (JSeq jseq : jseqs)
3669 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3671 RnaViewer viewer = jseq.getRnaViewer(i);
3672 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3675 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3677 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3678 SequenceI seq = seqRefIds.get(jseq.getId());
3679 AlignmentAnnotation ann = this.annotationIds
3680 .get(ss.getAnnotationId());
3683 * add the structure to the Varna display (with session state copied
3684 * from the jar to a temporary file)
3686 boolean gapped = ss.isGapped();
3687 String rnaTitle = ss.getTitle();
3688 String sessionState = ss.getViewerState();
3689 String tempStateFile = copyJarEntry(jprovider, sessionState,
3691 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3692 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3694 appVarna.setInitialSelection(viewer.getSelectedRna());
3700 * Locate and return an already instantiated matching AppVarna, or create one
3704 * @param viewIdSuffix
3708 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3709 String viewIdSuffix, AlignmentPanel ap)
3712 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3713 * if load is repeated
3715 String postLoadId = viewer.getViewId() + viewIdSuffix;
3716 for (JInternalFrame frame : getAllFrames())
3718 if (frame instanceof AppVarna)
3720 AppVarna varna = (AppVarna) frame;
3721 if (postLoadId.equals(varna.getViewId()))
3723 // this viewer is already instantiated
3724 // could in future here add ap as another 'parent' of the
3725 // AppVarna window; currently just 1-to-many
3732 * viewer not found - make it
3734 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3735 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3736 viewer.getHeight(), viewer.getDividerLocation());
3737 AppVarna varna = new AppVarna(model, ap);
3743 * Load any saved trees
3751 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3752 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3754 // TODO result of automated refactoring - are all these parameters needed?
3757 for (int t = 0; t < jms.getTreeCount(); t++)
3760 Tree tree = jms.getTree(t);
3762 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3765 tp = af.showNewickTree(
3766 new jalview.io.NewickFile(tree.getNewick()),
3767 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3768 tree.getXpos(), tree.getYpos());
3769 if (tree.getId() != null)
3771 // perhaps bind the tree id to something ?
3776 // update local tree attributes ?
3777 // TODO: should check if tp has been manipulated by user - if so its
3778 // settings shouldn't be modified
3779 tp.setTitle(tree.getTitle());
3780 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3781 tree.getWidth(), tree.getHeight()));
3782 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3785 tp.treeCanvas.av = av; // af.viewport;
3786 tp.treeCanvas.ap = ap; // af.alignPanel;
3791 warn("There was a problem recovering stored Newick tree: \n"
3792 + tree.getNewick());
3796 tp.fitToWindow.setState(tree.getFitToWindow());
3797 tp.fitToWindow_actionPerformed(null);
3799 if (tree.getFontName() != null)
3801 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3802 tree.getFontStyle(), tree.getFontSize()));
3806 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3807 view.getFontStyle(), tree.getFontSize()));
3810 tp.showPlaceholders(tree.getMarkUnlinked());
3811 tp.showBootstrap(tree.getShowBootstrap());
3812 tp.showDistances(tree.getShowDistances());
3814 tp.treeCanvas.threshold = tree.getThreshold();
3816 if (tree.getCurrentTree())
3818 af.viewport.setCurrentTree(tp.getTree());
3822 } catch (Exception ex)
3824 ex.printStackTrace();
3829 * Load and link any saved structure viewers.
3836 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3837 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3840 * Run through all PDB ids on the alignment, and collect mappings between
3841 * distinct view ids and all sequences referring to that view.
3843 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3845 for (int i = 0; i < jseqs.length; i++)
3847 if (jseqs[i].getPdbidsCount() > 0)
3849 Pdbids[] ids = jseqs[i].getPdbids();
3850 for (int p = 0; p < ids.length; p++)
3852 final int structureStateCount = ids[p].getStructureStateCount();
3853 for (int s = 0; s < structureStateCount; s++)
3855 // check to see if we haven't already created this structure view
3856 final StructureState structureState = ids[p]
3857 .getStructureState(s);
3858 String sviewid = (structureState.getViewId() == null) ? null
3859 : structureState.getViewId() + uniqueSetSuffix;
3860 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3861 // Originally : ids[p].getFile()
3862 // : TODO: verify external PDB file recovery still works in normal
3863 // jalview project load
3864 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3866 jpdb.setId(ids[p].getId());
3868 int x = structureState.getXpos();
3869 int y = structureState.getYpos();
3870 int width = structureState.getWidth();
3871 int height = structureState.getHeight();
3873 // Probably don't need to do this anymore...
3874 // Desktop.desktop.getComponentAt(x, y);
3875 // TODO: NOW: check that this recovers the PDB file correctly.
3876 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3878 jalview.datamodel.SequenceI seq = seqRefIds
3879 .get(jseqs[i].getId() + "");
3880 if (sviewid == null)
3882 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3885 if (!structureViewers.containsKey(sviewid))
3887 structureViewers.put(sviewid,
3888 new StructureViewerModel(x, y, width, height, false,
3889 false, true, structureState.getViewId(),
3890 structureState.getType()));
3891 // Legacy pre-2.7 conversion JAL-823 :
3892 // do not assume any view has to be linked for colour by
3896 // assemble String[] { pdb files }, String[] { id for each
3897 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3898 // seqs_file 2}, boolean[] {
3899 // linkAlignPanel,superposeWithAlignpanel}} from hash
3900 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3901 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3902 | (structureState.hasAlignwithAlignPanel()
3903 ? structureState.getAlignwithAlignPanel()
3907 * Default colour by linked panel to false if not specified (e.g.
3908 * for pre-2.7 projects)
3910 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3911 colourWithAlignPanel |= (structureState
3912 .hasColourwithAlignPanel()
3913 ? structureState.getColourwithAlignPanel()
3915 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3918 * Default colour by viewer to true if not specified (e.g. for
3921 boolean colourByViewer = jmoldat.isColourByViewer();
3922 colourByViewer &= structureState.hasColourByJmol()
3923 ? structureState.getColourByJmol()
3925 jmoldat.setColourByViewer(colourByViewer);
3927 if (jmoldat.getStateData().length() < structureState
3928 .getContent().length())
3931 jmoldat.setStateData(structureState.getContent());
3934 if (ids[p].getFile() != null)
3936 File mapkey = new File(ids[p].getFile());
3937 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3938 if (seqstrmaps == null)
3940 jmoldat.getFileData().put(mapkey,
3941 seqstrmaps = jmoldat.new StructureData(pdbFile,
3944 if (!seqstrmaps.getSeqList().contains(seq))
3946 seqstrmaps.getSeqList().add(seq);
3952 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");
3959 // Instantiate the associated structure views
3960 for (Entry<String, StructureViewerModel> entry : structureViewers
3965 createOrLinkStructureViewer(entry, af, ap, jprovider);
3966 } catch (Exception e)
3969 "Error loading structure viewer: " + e.getMessage());
3970 // failed - try the next one
3982 protected void createOrLinkStructureViewer(
3983 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3984 AlignmentPanel ap, jarInputStreamProvider jprovider)
3986 final StructureViewerModel stateData = viewerData.getValue();
3989 * Search for any viewer windows already open from other alignment views
3990 * that exactly match the stored structure state
3992 StructureViewerBase comp = findMatchingViewer(viewerData);
3996 linkStructureViewer(ap, comp, stateData);
4001 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4002 * "viewer_"+stateData.viewId
4004 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4006 createChimeraViewer(viewerData, af, jprovider);
4011 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4013 createJmolViewer(viewerData, af, jprovider);
4018 * Create a new Chimera viewer.
4024 protected void createChimeraViewer(
4025 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4026 jarInputStreamProvider jprovider)
4028 StructureViewerModel data = viewerData.getValue();
4029 String chimeraSessionFile = data.getStateData();
4032 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4034 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4035 * 'uniquified' sviewid used to reconstruct the viewer here
4037 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4038 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4041 Set<Entry<File, StructureData>> fileData = data.getFileData()
4043 List<PDBEntry> pdbs = new ArrayList<>();
4044 List<SequenceI[]> allseqs = new ArrayList<>();
4045 for (Entry<File, StructureData> pdb : fileData)
4047 String filePath = pdb.getValue().getFilePath();
4048 String pdbId = pdb.getValue().getPdbId();
4049 // pdbs.add(new PDBEntry(filePath, pdbId));
4050 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4051 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4052 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4056 boolean colourByChimera = data.isColourByViewer();
4057 boolean colourBySequence = data.isColourWithAlignPanel();
4059 // TODO use StructureViewer as a factory here, see JAL-1761
4060 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4061 final SequenceI[][] seqsArray = allseqs
4062 .toArray(new SequenceI[allseqs.size()][]);
4063 String newViewId = viewerData.getKey();
4065 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4066 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4067 colourBySequence, newViewId);
4068 cvf.setSize(data.getWidth(), data.getHeight());
4069 cvf.setLocation(data.getX(), data.getY());
4073 * Create a new Jmol window. First parse the Jmol state to translate filenames
4074 * loaded into the view, and record the order in which files are shown in the
4075 * Jmol view, so we can add the sequence mappings in same order.
4081 protected void createJmolViewer(
4082 final Entry<String, StructureViewerModel> viewerData,
4083 AlignFrame af, jarInputStreamProvider jprovider)
4085 final StructureViewerModel svattrib = viewerData.getValue();
4086 String state = svattrib.getStateData();
4089 * Pre-2.9: state element value is the Jmol state string
4091 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4094 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4096 state = readJarEntry(jprovider,
4097 getViewerJarEntryName(svattrib.getViewId()));
4100 List<String> pdbfilenames = new ArrayList<>();
4101 List<SequenceI[]> seqmaps = new ArrayList<>();
4102 List<String> pdbids = new ArrayList<>();
4103 StringBuilder newFileLoc = new StringBuilder(64);
4104 int cp = 0, ncp, ecp;
4105 Map<File, StructureData> oldFiles = svattrib.getFileData();
4106 while ((ncp = state.indexOf("load ", cp)) > -1)
4110 // look for next filename in load statement
4111 newFileLoc.append(state.substring(cp,
4112 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4113 String oldfilenam = state.substring(ncp,
4114 ecp = state.indexOf("\"", ncp));
4115 // recover the new mapping data for this old filename
4116 // have to normalize filename - since Jmol and jalview do
4118 // translation differently.
4119 StructureData filedat = oldFiles.get(new File(oldfilenam));
4120 if (filedat == null)
4122 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4123 filedat = oldFiles.get(new File(reformatedOldFilename));
4125 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4126 pdbfilenames.add(filedat.getFilePath());
4127 pdbids.add(filedat.getPdbId());
4128 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4129 newFileLoc.append("\"");
4130 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4131 // look for next file statement.
4132 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4136 // just append rest of state
4137 newFileLoc.append(state.substring(cp));
4141 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4142 newFileLoc = new StringBuilder(state);
4143 newFileLoc.append("; load append ");
4144 for (File id : oldFiles.keySet())
4146 // add this and any other pdb files that should be present in
4148 StructureData filedat = oldFiles.get(id);
4149 newFileLoc.append(filedat.getFilePath());
4150 pdbfilenames.add(filedat.getFilePath());
4151 pdbids.add(filedat.getPdbId());
4152 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4153 newFileLoc.append(" \"");
4154 newFileLoc.append(filedat.getFilePath());
4155 newFileLoc.append("\"");
4158 newFileLoc.append(";");
4161 if (newFileLoc.length() == 0)
4165 int histbug = newFileLoc.indexOf("history = ");
4169 * change "history = [true|false];" to "history = [1|0];"
4172 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4173 String val = (diff == -1) ? null
4174 : newFileLoc.substring(histbug, diff);
4175 if (val != null && val.length() >= 4)
4177 if (val.contains("e")) // eh? what can it be?
4179 if (val.trim().equals("true"))
4187 newFileLoc.replace(histbug, diff, val);
4192 final String[] pdbf = pdbfilenames
4193 .toArray(new String[pdbfilenames.size()]);
4194 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4195 final SequenceI[][] sq = seqmaps
4196 .toArray(new SequenceI[seqmaps.size()][]);
4197 final String fileloc = newFileLoc.toString();
4198 final String sviewid = viewerData.getKey();
4199 final AlignFrame alf = af;
4200 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4201 svattrib.getWidth(), svattrib.getHeight());
4204 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4209 JalviewStructureDisplayI sview = null;
4212 sview = new StructureViewer(
4213 alf.alignPanel.getStructureSelectionManager())
4214 .createView(StructureViewer.ViewerType.JMOL,
4215 pdbf, id, sq, alf.alignPanel, svattrib,
4216 fileloc, rect, sviewid);
4217 addNewStructureViewer(sview);
4218 } catch (OutOfMemoryError ex)
4220 new OOMWarning("restoring structure view for PDB id " + id,
4221 (OutOfMemoryError) ex.getCause());
4222 if (sview != null && sview.isVisible())
4224 sview.closeViewer(false);
4225 sview.setVisible(false);
4231 } catch (InvocationTargetException ex)
4233 warn("Unexpected error when opening Jmol view.", ex);
4235 } catch (InterruptedException e)
4237 // e.printStackTrace();
4243 * Generates a name for the entry in the project jar file to hold state
4244 * information for a structure viewer
4249 protected String getViewerJarEntryName(String viewId)
4251 return VIEWER_PREFIX + viewId;
4255 * Returns any open frame that matches given structure viewer data. The match
4256 * is based on the unique viewId, or (for older project versions) the frame's
4262 protected StructureViewerBase findMatchingViewer(
4263 Entry<String, StructureViewerModel> viewerData)
4265 final String sviewid = viewerData.getKey();
4266 final StructureViewerModel svattrib = viewerData.getValue();
4267 StructureViewerBase comp = null;
4268 JInternalFrame[] frames = getAllFrames();
4269 for (JInternalFrame frame : frames)
4271 if (frame instanceof StructureViewerBase)
4274 * Post jalview 2.4 schema includes structure view id
4276 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4279 comp = (StructureViewerBase) frame;
4280 break; // break added in 2.9
4283 * Otherwise test for matching position and size of viewer frame
4285 else if (frame.getX() == svattrib.getX()
4286 && frame.getY() == svattrib.getY()
4287 && frame.getHeight() == svattrib.getHeight()
4288 && frame.getWidth() == svattrib.getWidth())
4290 comp = (StructureViewerBase) frame;
4291 // no break in faint hope of an exact match on viewId
4299 * Link an AlignmentPanel to an existing structure viewer.
4304 * @param useinViewerSuperpos
4305 * @param usetoColourbyseq
4306 * @param viewerColouring
4308 protected void linkStructureViewer(AlignmentPanel ap,
4309 StructureViewerBase viewer, StructureViewerModel stateData)
4311 // NOTE: if the jalview project is part of a shared session then
4312 // view synchronization should/could be done here.
4314 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4315 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4316 final boolean viewerColouring = stateData.isColourByViewer();
4317 Map<File, StructureData> oldFiles = stateData.getFileData();
4320 * Add mapping for sequences in this view to an already open viewer
4322 final AAStructureBindingModel binding = viewer.getBinding();
4323 for (File id : oldFiles.keySet())
4325 // add this and any other pdb files that should be present in the
4327 StructureData filedat = oldFiles.get(id);
4328 String pdbFile = filedat.getFilePath();
4329 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4330 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4332 binding.addSequenceForStructFile(pdbFile, seq);
4334 // and add the AlignmentPanel's reference to the view panel
4335 viewer.addAlignmentPanel(ap);
4336 if (useinViewerSuperpos)
4338 viewer.useAlignmentPanelForSuperposition(ap);
4342 viewer.excludeAlignmentPanelForSuperposition(ap);
4344 if (usetoColourbyseq)
4346 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4350 viewer.excludeAlignmentPanelForColourbyseq(ap);
4355 * Get all frames within the Desktop.
4359 protected JInternalFrame[] getAllFrames()
4361 JInternalFrame[] frames = null;
4362 // TODO is this necessary - is it safe - risk of hanging?
4367 frames = Desktop.desktop.getAllFrames();
4368 } catch (ArrayIndexOutOfBoundsException e)
4370 // occasional No such child exceptions are thrown here...
4374 } catch (InterruptedException f)
4378 } while (frames == null);
4383 * Answers true if 'version' is equal to or later than 'supported', where each
4384 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4385 * changes. Development and test values for 'version' are leniently treated
4389 * - minimum version we are comparing against
4391 * - version of data being processsed
4394 public static boolean isVersionStringLaterThan(String supported,
4397 if (supported == null || version == null
4398 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4399 || version.equalsIgnoreCase("Test")
4400 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4402 System.err.println("Assuming project file with "
4403 + (version == null ? "null" : version)
4404 + " is compatible with Jalview version " + supported);
4409 return StringUtils.compareVersions(version, supported, "b") >= 0;
4413 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4415 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4417 if (newStructureViewers != null)
4419 sview.getBinding().setFinishedLoadingFromArchive(false);
4420 newStructureViewers.add(sview);
4424 protected void setLoadingFinishedForNewStructureViewers()
4426 if (newStructureViewers != null)
4428 for (JalviewStructureDisplayI sview : newStructureViewers)
4430 sview.getBinding().setFinishedLoadingFromArchive(true);
4432 newStructureViewers.clear();
4433 newStructureViewers = null;
4437 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4438 List<SequenceI> hiddenSeqs, AlignmentI al,
4439 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4440 String viewId, List<JvAnnotRow> autoAlan)
4442 AlignFrame af = null;
4443 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4444 uniqueSeqSetId, viewId);
4446 af.setFileName(file, FileFormat.Jalview);
4448 for (int i = 0; i < JSEQ.length; i++)
4450 af.viewport.setSequenceColour(
4451 af.viewport.getAlignment().getSequenceAt(i),
4452 new java.awt.Color(JSEQ[i].getColour()));
4457 af.getViewport().setColourByReferenceSeq(true);
4458 af.getViewport().setDisplayReferenceSeq(true);
4461 af.viewport.setGatherViewsHere(view.getGatheredViews());
4463 if (view.getSequenceSetId() != null)
4465 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4467 af.viewport.setSequenceSetId(uniqueSeqSetId);
4470 // propagate shared settings to this new view
4471 af.viewport.setHistoryList(av.getHistoryList());
4472 af.viewport.setRedoList(av.getRedoList());
4476 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4478 // TODO: check if this method can be called repeatedly without
4479 // side-effects if alignpanel already registered.
4480 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4482 // apply Hidden regions to view.
4483 if (hiddenSeqs != null)
4485 for (int s = 0; s < JSEQ.length; s++)
4487 SequenceGroup hidden = new SequenceGroup();
4488 boolean isRepresentative = false;
4489 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4491 isRepresentative = true;
4492 SequenceI sequenceToHide = al
4493 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4494 hidden.addSequence(sequenceToHide, false);
4495 // remove from hiddenSeqs list so we don't try to hide it twice
4496 hiddenSeqs.remove(sequenceToHide);
4498 if (isRepresentative)
4500 SequenceI representativeSequence = al.getSequenceAt(s);
4501 hidden.addSequence(representativeSequence, false);
4502 af.viewport.hideRepSequences(representativeSequence, hidden);
4506 SequenceI[] hseqs = hiddenSeqs
4507 .toArray(new SequenceI[hiddenSeqs.size()]);
4508 af.viewport.hideSequence(hseqs);
4511 // recover view properties and display parameters
4513 af.viewport.setShowAnnotation(view.getShowAnnotation());
4514 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4515 af.viewport.setThreshold(view.getPidThreshold());
4517 af.viewport.setColourText(view.getShowColourText());
4519 af.viewport.setConservationSelected(view.getConservationSelected());
4520 af.viewport.setIncrement(view.getConsThreshold());
4521 af.viewport.setShowJVSuffix(view.getShowFullId());
4522 af.viewport.setRightAlignIds(view.getRightAlignIds());
4523 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4524 view.getFontStyle(), view.getFontSize()), true);
4525 ViewStyleI vs = af.viewport.getViewStyle();
4526 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4527 af.viewport.setViewStyle(vs);
4528 // TODO: allow custom charWidth/Heights to be restored by updating them
4529 // after setting font - which means set above to false
4530 af.viewport.setRenderGaps(view.getRenderGaps());
4531 af.viewport.setWrapAlignment(view.getWrapAlignment());
4532 af.viewport.setShowAnnotation(view.getShowAnnotation());
4534 af.viewport.setShowBoxes(view.getShowBoxes());
4536 af.viewport.setShowText(view.getShowText());
4538 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4539 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4540 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4541 af.viewport.setShowUnconserved(
4542 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4543 af.viewport.getRanges().setStartRes(view.getStartRes());
4545 if (view.getViewName() != null)
4547 af.viewport.viewName = view.getViewName();
4548 af.setInitialTabVisible();
4550 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4552 // startSeq set in af.alignPanel.updateLayout below
4553 af.alignPanel.updateLayout();
4554 ColourSchemeI cs = null;
4555 // apply colourschemes
4556 if (view.getBgColour() != null)
4558 if (view.getBgColour().startsWith("ucs"))
4560 cs = getUserColourScheme(jms, view.getBgColour());
4562 else if (view.getBgColour().startsWith("Annotation"))
4564 AnnotationColours viewAnnColour = view.getAnnotationColours();
4565 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4572 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4576 af.viewport.setGlobalColourScheme(cs);
4577 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4578 view.getIgnoreGapsinConsensus());
4579 af.viewport.getResidueShading()
4580 .setConsensus(af.viewport.getSequenceConsensusHash());
4581 af.viewport.setColourAppliesToAllGroups(false);
4583 if (view.getConservationSelected() && cs != null)
4585 af.viewport.getResidueShading()
4586 .setConservationInc(view.getConsThreshold());
4589 af.changeColour(cs);
4591 af.viewport.setColourAppliesToAllGroups(true);
4593 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4595 if (view.hasCentreColumnLabels())
4597 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4599 if (view.hasIgnoreGapsinConsensus())
4601 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4604 if (view.hasFollowHighlight())
4606 af.viewport.setFollowHighlight(view.getFollowHighlight());
4608 if (view.hasFollowSelection())
4610 af.viewport.followSelection = view.getFollowSelection();
4612 if (view.hasShowConsensusHistogram())
4615 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4619 af.viewport.setShowConsensusHistogram(true);
4621 if (view.hasShowSequenceLogo())
4623 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4627 af.viewport.setShowSequenceLogo(false);
4629 if (view.hasNormaliseSequenceLogo())
4631 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4633 if (view.hasShowDbRefTooltip())
4635 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4637 if (view.hasShowNPfeatureTooltip())
4639 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4641 if (view.hasShowGroupConsensus())
4643 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4647 af.viewport.setShowGroupConsensus(false);
4649 if (view.hasShowGroupConservation())
4651 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4655 af.viewport.setShowGroupConservation(false);
4658 // recover feature settings
4659 if (jms.getFeatureSettings() != null)
4661 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4662 .getFeatureRenderer();
4663 FeaturesDisplayed fdi;
4664 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4665 String[] renderOrder = new String[jms.getFeatureSettings()
4666 .getSettingCount()];
4667 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4668 Map<String, Float> featureOrder = new Hashtable<>();
4670 for (int fs = 0; fs < jms.getFeatureSettings()
4671 .getSettingCount(); fs++)
4673 Setting setting = jms.getFeatureSettings().getSetting(fs);
4674 String featureType = setting.getType();
4677 * restore feature filters (if any)
4679 MatcherSet filters = setting.getMatcherSet();
4680 if (filters != null)
4682 FeatureMatcherSetI filter = Jalview2XML
4683 .unmarshalFilter(featureType, filters);
4684 if (!filter.isEmpty())
4686 fr.setFeatureFilter(featureType, filter);
4691 * restore feature colour scheme
4693 Color maxColour = new Color(setting.getColour());
4694 if (setting.hasMincolour())
4697 * minColour is always set unless a simple colour
4698 * (including for colour by label though it doesn't use it)
4700 Color minColour = new Color(setting.getMincolour());
4701 Color noValueColour = minColour;
4702 NoValueColour noColour = setting.getNoValueColour();
4703 if (noColour == NoValueColour.NONE)
4705 noValueColour = null;
4707 else if (noColour == NoValueColour.MAX)
4709 noValueColour = maxColour;
4711 float min = setting.hasMin() ? setting.getMin() : 0f;
4712 float max = setting.hasMin() ? setting.getMax() : 1f;
4713 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4714 noValueColour, min, max);
4715 if (setting.getAttributeNameCount() > 0)
4717 gc.setAttributeName(setting.getAttributeName());
4719 if (setting.hasThreshold())
4721 gc.setThreshold(setting.getThreshold());
4722 int threshstate = setting.getThreshstate();
4723 // -1 = None, 0 = Below, 1 = Above threshold
4724 if (threshstate == 0)
4726 gc.setBelowThreshold(true);
4728 else if (threshstate == 1)
4730 gc.setAboveThreshold(true);
4733 gc.setAutoScaled(true); // default
4734 if (setting.hasAutoScale())
4736 gc.setAutoScaled(setting.getAutoScale());
4738 if (setting.hasColourByLabel())
4740 gc.setColourByLabel(setting.getColourByLabel());
4742 // and put in the feature colour table.
4743 featureColours.put(featureType, gc);
4747 featureColours.put(featureType,
4748 new FeatureColour(maxColour));
4750 renderOrder[fs] = featureType;
4751 if (setting.hasOrder())
4753 featureOrder.put(featureType, setting.getOrder());
4757 featureOrder.put(featureType, new Float(
4758 fs / jms.getFeatureSettings().getSettingCount()));
4760 if (setting.getDisplay())
4762 fdi.setVisible(featureType);
4765 Map<String, Boolean> fgtable = new Hashtable<>();
4766 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4768 Group grp = jms.getFeatureSettings().getGroup(gs);
4769 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4771 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4772 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4773 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4774 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4775 fgtable, featureColours, 1.0f, featureOrder);
4776 fr.transferSettings(frs);
4779 if (view.getHiddenColumnsCount() > 0)
4781 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4783 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4784 view.getHiddenColumns(c).getEnd() // +1
4788 if (view.getCalcIdParam() != null)
4790 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4792 if (calcIdParam != null)
4794 if (recoverCalcIdParam(calcIdParam, af.viewport))
4799 warn("Couldn't recover parameters for "
4800 + calcIdParam.getCalcId());
4805 af.setMenusFromViewport(af.viewport);
4806 af.setTitle(view.getTitle());
4807 // TODO: we don't need to do this if the viewport is aready visible.
4809 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4810 * has a 'cdna/protein complement' view, in which case save it in order to
4811 * populate a SplitFrame once all views have been read in.
4813 String complementaryViewId = view.getComplementId();
4814 if (complementaryViewId == null)
4816 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4818 // recompute any autoannotation
4819 af.alignPanel.updateAnnotation(false, true);
4820 reorderAutoannotation(af, al, autoAlan);
4821 af.alignPanel.alignmentChanged();
4825 splitFrameCandidates.put(view, af);
4831 * Reads saved data to restore Colour by Annotation settings
4833 * @param viewAnnColour
4837 * @param checkGroupAnnColour
4840 private ColourSchemeI constructAnnotationColour(
4841 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4842 JalviewModelSequence jms, boolean checkGroupAnnColour)
4844 boolean propagateAnnColour = false;
4845 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4846 if (checkGroupAnnColour && al.getGroups() != null
4847 && al.getGroups().size() > 0)
4849 // pre 2.8.1 behaviour
4850 // check to see if we should transfer annotation colours
4851 propagateAnnColour = true;
4852 for (SequenceGroup sg : al.getGroups())
4854 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4856 propagateAnnColour = false;
4862 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4864 String annotationId = viewAnnColour.getAnnotation();
4865 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4868 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4870 if (matchedAnnotation == null
4871 && annAlignment.getAlignmentAnnotation() != null)
4873 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4876 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4878 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4883 if (matchedAnnotation == null)
4885 System.err.println("Failed to match annotation colour scheme for "
4889 if (matchedAnnotation.getThreshold() == null)
4891 matchedAnnotation.setThreshold(new GraphLine(
4892 viewAnnColour.getThreshold(), "Threshold", Color.black));
4895 AnnotationColourGradient cs = null;
4896 if (viewAnnColour.getColourScheme().equals("None"))
4898 cs = new AnnotationColourGradient(matchedAnnotation,
4899 new Color(viewAnnColour.getMinColour()),
4900 new Color(viewAnnColour.getMaxColour()),
4901 viewAnnColour.getAboveThreshold());
4903 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4905 cs = new AnnotationColourGradient(matchedAnnotation,
4906 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4907 viewAnnColour.getAboveThreshold());
4911 cs = new AnnotationColourGradient(matchedAnnotation,
4912 ColourSchemeProperty.getColourScheme(al,
4913 viewAnnColour.getColourScheme()),
4914 viewAnnColour.getAboveThreshold());
4917 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4918 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4919 cs.setSeqAssociated(perSequenceOnly);
4920 cs.setPredefinedColours(useOriginalColours);
4922 if (propagateAnnColour && al.getGroups() != null)
4924 // Also use these settings for all the groups
4925 for (int g = 0; g < al.getGroups().size(); g++)
4927 SequenceGroup sg = al.getGroups().get(g);
4928 if (sg.getGroupColourScheme() == null)
4933 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4934 matchedAnnotation, sg.getColourScheme(),
4935 viewAnnColour.getAboveThreshold());
4936 sg.setColourScheme(groupScheme);
4937 groupScheme.setSeqAssociated(perSequenceOnly);
4938 groupScheme.setPredefinedColours(useOriginalColours);
4944 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4945 List<JvAnnotRow> autoAlan)
4947 // copy over visualization settings for autocalculated annotation in the
4949 if (al.getAlignmentAnnotation() != null)
4952 * Kludge for magic autoannotation names (see JAL-811)
4954 String[] magicNames = new String[] { "Consensus", "Quality",
4956 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4957 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4958 for (String nm : magicNames)
4960 visan.put(nm, nullAnnot);
4962 for (JvAnnotRow auan : autoAlan)
4964 visan.put(auan.template.label
4965 + (auan.template.getCalcId() == null ? ""
4966 : "\t" + auan.template.getCalcId()),
4969 int hSize = al.getAlignmentAnnotation().length;
4970 List<JvAnnotRow> reorder = new ArrayList<>();
4971 // work through any autoCalculated annotation already on the view
4972 // removing it if it should be placed in a different location on the
4973 // annotation panel.
4974 List<String> remains = new ArrayList<>(visan.keySet());
4975 for (int h = 0; h < hSize; h++)
4977 jalview.datamodel.AlignmentAnnotation jalan = al
4978 .getAlignmentAnnotation()[h];
4979 if (jalan.autoCalculated)
4982 JvAnnotRow valan = visan.get(k = jalan.label);
4983 if (jalan.getCalcId() != null)
4985 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4990 // delete the auto calculated row from the alignment
4991 al.deleteAnnotation(jalan, false);
4995 if (valan != nullAnnot)
4997 if (jalan != valan.template)
4999 // newly created autoannotation row instance
5000 // so keep a reference to the visible annotation row
5001 // and copy over all relevant attributes
5002 if (valan.template.graphHeight >= 0)
5005 jalan.graphHeight = valan.template.graphHeight;
5007 jalan.visible = valan.template.visible;
5009 reorder.add(new JvAnnotRow(valan.order, jalan));
5014 // Add any (possibly stale) autocalculated rows that were not appended to
5015 // the view during construction
5016 for (String other : remains)
5018 JvAnnotRow othera = visan.get(other);
5019 if (othera != nullAnnot && othera.template.getCalcId() != null
5020 && othera.template.getCalcId().length() > 0)
5022 reorder.add(othera);
5025 // now put the automatic annotation in its correct place
5026 int s = 0, srt[] = new int[reorder.size()];
5027 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5028 for (JvAnnotRow jvar : reorder)
5031 srt[s++] = jvar.order;
5034 jalview.util.QuickSort.sort(srt, rws);
5035 // and re-insert the annotation at its correct position
5036 for (JvAnnotRow jvar : rws)
5038 al.addAnnotation(jvar.template, jvar.order);
5040 af.alignPanel.adjustAnnotationHeight();
5044 Hashtable skipList = null;
5047 * TODO remove this method
5050 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5051 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5052 * throw new Error("Implementation Error. No skipList defined for this
5053 * Jalview2XML instance."); } return (AlignFrame)
5054 * skipList.get(view.getSequenceSetId()); }
5058 * Check if the Jalview view contained in object should be skipped or not.
5061 * @return true if view's sequenceSetId is a key in skipList
5063 private boolean skipViewport(JalviewModel object)
5065 if (skipList == null)
5070 if (skipList.containsKey(
5071 id = object.getJalviewModelSequence().getViewport()[0]
5072 .getSequenceSetId()))
5074 if (Cache.log != null && Cache.log.isDebugEnabled())
5076 Cache.log.debug("Skipping seuqence set id " + id);
5083 public void addToSkipList(AlignFrame af)
5085 if (skipList == null)
5087 skipList = new Hashtable();
5089 skipList.put(af.getViewport().getSequenceSetId(), af);
5092 public void clearSkipList()
5094 if (skipList != null)
5101 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5102 boolean ignoreUnrefed)
5104 jalview.datamodel.AlignmentI ds = getDatasetFor(
5105 vamsasSet.getDatasetId());
5106 Vector dseqs = null;
5109 // create a list of new dataset sequences
5110 dseqs = new Vector();
5112 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5114 Sequence vamsasSeq = vamsasSet.getSequence(i);
5115 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5117 // create a new dataset
5120 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5121 dseqs.copyInto(dsseqs);
5122 ds = new jalview.datamodel.Alignment(dsseqs);
5123 debug("Created new dataset " + vamsasSet.getDatasetId()
5124 + " for alignment " + System.identityHashCode(al));
5125 addDatasetRef(vamsasSet.getDatasetId(), ds);
5127 // set the dataset for the newly imported alignment.
5128 if (al.getDataset() == null && !ignoreUnrefed)
5137 * sequence definition to create/merge dataset sequence for
5141 * vector to add new dataset sequence to
5142 * @param ignoreUnrefed
5143 * - when true, don't create new sequences from vamsasSeq if it's id
5144 * doesn't already have an asssociated Jalview sequence.
5146 * - used to reorder the sequence in the alignment according to the
5147 * vamsasSeq array ordering, to preserve ordering of dataset
5149 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5150 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5152 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5154 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5155 boolean reorder = false;
5156 SequenceI dsq = null;
5157 if (sq != null && sq.getDatasetSequence() != null)
5159 dsq = sq.getDatasetSequence();
5165 if (sq == null && ignoreUnrefed)
5169 String sqid = vamsasSeq.getDsseqid();
5172 // need to create or add a new dataset sequence reference to this sequence
5175 dsq = seqRefIds.get(sqid);
5180 // make a new dataset sequence
5181 dsq = sq.createDatasetSequence();
5184 // make up a new dataset reference for this sequence
5185 sqid = seqHash(dsq);
5187 dsq.setVamsasId(uniqueSetSuffix + sqid);
5188 seqRefIds.put(sqid, dsq);
5193 dseqs.addElement(dsq);
5198 ds.addSequence(dsq);
5204 { // make this dataset sequence sq's dataset sequence
5205 sq.setDatasetSequence(dsq);
5206 // and update the current dataset alignment
5211 if (!dseqs.contains(dsq))
5218 if (ds.findIndex(dsq) < 0)
5220 ds.addSequence(dsq);
5227 // TODO: refactor this as a merge dataset sequence function
5228 // now check that sq (the dataset sequence) sequence really is the union of
5229 // all references to it
5230 // boolean pre = sq.getStart() < dsq.getStart();
5231 // boolean post = sq.getEnd() > dsq.getEnd();
5235 // StringBuffer sb = new StringBuffer();
5236 String newres = jalview.analysis.AlignSeq.extractGaps(
5237 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5238 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5239 && newres.length() > dsq.getLength())
5241 // Update with the longer sequence.
5245 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5246 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5247 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5248 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5250 dsq.setSequence(newres);
5252 // TODO: merges will never happen if we 'know' we have the real dataset
5253 // sequence - this should be detected when id==dssid
5255 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5256 // + (pre ? "prepended" : "") + " "
5257 // + (post ? "appended" : ""));
5262 // sequence refs are identical. We may need to update the existing dataset
5263 // alignment with this one, though.
5264 if (ds != null && dseqs == null)
5266 int opos = ds.findIndex(dsq);
5267 SequenceI tseq = null;
5268 if (opos != -1 && vseqpos != opos)
5270 // remove from old position
5271 ds.deleteSequence(dsq);
5273 if (vseqpos < ds.getHeight())
5275 if (vseqpos != opos)
5277 // save sequence at destination position
5278 tseq = ds.getSequenceAt(vseqpos);
5279 ds.replaceSequenceAt(vseqpos, dsq);
5280 ds.addSequence(tseq);
5285 ds.addSequence(dsq);
5292 * TODO use AlignmentI here and in related methods - needs
5293 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5295 Hashtable<String, AlignmentI> datasetIds = null;
5297 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5299 private AlignmentI getDatasetFor(String datasetId)
5301 if (datasetIds == null)
5303 datasetIds = new Hashtable<>();
5306 if (datasetIds.containsKey(datasetId))
5308 return datasetIds.get(datasetId);
5313 private void addDatasetRef(String datasetId, AlignmentI dataset)
5315 if (datasetIds == null)
5317 datasetIds = new Hashtable<>();
5319 datasetIds.put(datasetId, dataset);
5323 * make a new dataset ID for this jalview dataset alignment
5328 private String getDatasetIdRef(AlignmentI dataset)
5330 if (dataset.getDataset() != null)
5332 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5334 String datasetId = makeHashCode(dataset, null);
5335 if (datasetId == null)
5337 // make a new datasetId and record it
5338 if (dataset2Ids == null)
5340 dataset2Ids = new IdentityHashMap<>();
5344 datasetId = dataset2Ids.get(dataset);
5346 if (datasetId == null)
5348 datasetId = "ds" + dataset2Ids.size() + 1;
5349 dataset2Ids.put(dataset, datasetId);
5355 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5357 for (int d = 0; d < sequence.getDBRefCount(); d++)
5359 DBRef dr = sequence.getDBRef(d);
5360 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5361 sequence.getDBRef(d).getSource(),
5362 sequence.getDBRef(d).getVersion(),
5363 sequence.getDBRef(d).getAccessionId());
5364 if (dr.getMapping() != null)
5366 entry.setMap(addMapping(dr.getMapping()));
5368 datasetSequence.addDBRef(entry);
5372 private jalview.datamodel.Mapping addMapping(Mapping m)
5374 SequenceI dsto = null;
5375 // Mapping m = dr.getMapping();
5376 int fr[] = new int[m.getMapListFromCount() * 2];
5377 Enumeration f = m.enumerateMapListFrom();
5378 for (int _i = 0; f.hasMoreElements(); _i += 2)
5380 MapListFrom mf = (MapListFrom) f.nextElement();
5381 fr[_i] = mf.getStart();
5382 fr[_i + 1] = mf.getEnd();
5384 int fto[] = new int[m.getMapListToCount() * 2];
5385 f = m.enumerateMapListTo();
5386 for (int _i = 0; f.hasMoreElements(); _i += 2)
5388 MapListTo mf = (MapListTo) f.nextElement();
5389 fto[_i] = mf.getStart();
5390 fto[_i + 1] = mf.getEnd();
5392 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5393 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5394 if (m.getMappingChoice() != null)
5396 MappingChoice mc = m.getMappingChoice();
5397 if (mc.getDseqFor() != null)
5399 String dsfor = "" + mc.getDseqFor();
5400 if (seqRefIds.containsKey(dsfor))
5405 jmap.setTo(seqRefIds.get(dsfor));
5409 frefedSequence.add(newMappingRef(dsfor, jmap));
5415 * local sequence definition
5417 Sequence ms = mc.getSequence();
5418 SequenceI djs = null;
5419 String sqid = ms.getDsseqid();
5420 if (sqid != null && sqid.length() > 0)
5423 * recover dataset sequence
5425 djs = seqRefIds.get(sqid);
5430 "Warning - making up dataset sequence id for DbRef sequence map reference");
5431 sqid = ((Object) ms).toString(); // make up a new hascode for
5432 // undefined dataset sequence hash
5433 // (unlikely to happen)
5439 * make a new dataset sequence and add it to refIds hash
5441 djs = new jalview.datamodel.Sequence(ms.getName(),
5443 djs.setStart(jmap.getMap().getToLowest());
5444 djs.setEnd(jmap.getMap().getToHighest());
5445 djs.setVamsasId(uniqueSetSuffix + sqid);
5447 incompleteSeqs.put(sqid, djs);
5448 seqRefIds.put(sqid, djs);
5451 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5461 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5462 * view as XML (but not to file), and then reloading it
5467 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5470 JalviewModel jm = saveState(ap, null, null, null);
5472 uniqueSetSuffix = "";
5473 jm.getJalviewModelSequence().getViewport(0).setId(null);
5474 // we don't overwrite the view we just copied
5476 if (this.frefedSequence == null)
5478 frefedSequence = new Vector<>();
5481 viewportsAdded.clear();
5483 AlignFrame af = loadFromObject(jm, null, false, null);
5484 af.alignPanels.clear();
5485 af.closeMenuItem_actionPerformed(true);
5488 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5489 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5490 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5491 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5492 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5495 return af.alignPanel;
5498 private Hashtable jvids2vobj;
5500 private void warn(String msg)
5505 private void warn(String msg, Exception e)
5507 if (Cache.log != null)
5511 Cache.log.warn(msg, e);
5515 Cache.log.warn(msg);
5520 System.err.println("Warning: " + msg);
5523 e.printStackTrace();
5528 private void debug(String string)
5530 debug(string, null);
5533 private void debug(String msg, Exception e)
5535 if (Cache.log != null)
5539 Cache.log.debug(msg, e);
5543 Cache.log.debug(msg);
5548 System.err.println("Warning: " + msg);
5551 e.printStackTrace();
5557 * set the object to ID mapping tables used to write/recover objects and XML
5558 * ID strings for the jalview project. If external tables are provided then
5559 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5560 * object goes out of scope. - also populates the datasetIds hashtable with
5561 * alignment objects containing dataset sequences
5564 * Map from ID strings to jalview datamodel
5566 * Map from jalview datamodel to ID strings
5570 public void setObjectMappingTables(Hashtable vobj2jv,
5571 IdentityHashMap jv2vobj)
5573 this.jv2vobj = jv2vobj;
5574 this.vobj2jv = vobj2jv;
5575 Iterator ds = jv2vobj.keySet().iterator();
5577 while (ds.hasNext())
5579 Object jvobj = ds.next();
5580 id = jv2vobj.get(jvobj).toString();
5581 if (jvobj instanceof jalview.datamodel.Alignment)
5583 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5585 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5588 else if (jvobj instanceof jalview.datamodel.Sequence)
5590 // register sequence object so the XML parser can recover it.
5591 if (seqRefIds == null)
5593 seqRefIds = new HashMap<>();
5595 if (seqsToIds == null)
5597 seqsToIds = new IdentityHashMap<>();
5599 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5600 seqsToIds.put((SequenceI) jvobj, id);
5602 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5605 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5606 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5607 if (jvann.annotationId == null)
5609 jvann.annotationId = anid;
5611 if (!jvann.annotationId.equals(anid))
5613 // TODO verify that this is the correct behaviour
5614 this.warn("Overriding Annotation ID for " + anid
5615 + " from different id : " + jvann.annotationId);
5616 jvann.annotationId = anid;
5619 else if (jvobj instanceof String)
5621 if (jvids2vobj == null)
5623 jvids2vobj = new Hashtable();
5624 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5629 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5635 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5636 * objects created from the project archive. If string is null (default for
5637 * construction) then suffix will be set automatically.
5641 public void setUniqueSetSuffix(String string)
5643 uniqueSetSuffix = string;
5648 * uses skipList2 as the skipList for skipping views on sequence sets
5649 * associated with keys in the skipList
5653 public void setSkipList(Hashtable skipList2)
5655 skipList = skipList2;
5659 * Reads the jar entry of given name and returns its contents, or null if the
5660 * entry is not found.
5663 * @param jarEntryName
5666 protected String readJarEntry(jarInputStreamProvider jprovider,
5667 String jarEntryName)
5669 String result = null;
5670 BufferedReader in = null;
5675 * Reopen the jar input stream and traverse its entries to find a matching
5678 JarInputStream jin = jprovider.getJarInputStream();
5679 JarEntry entry = null;
5682 entry = jin.getNextJarEntry();
5683 } while (entry != null && !entry.getName().equals(jarEntryName));
5687 StringBuilder out = new StringBuilder(256);
5688 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5691 while ((data = in.readLine()) != null)
5695 result = out.toString();
5699 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5701 } catch (Exception ex)
5703 ex.printStackTrace();
5711 } catch (IOException e)
5722 * Returns an incrementing counter (0, 1, 2...)
5726 private synchronized int nextCounter()
5732 * Populates an XML model of the feature colour scheme for one feature type
5734 * @param featureType
5738 protected static jalview.schemabinding.version2.Colour marshalColour(
5739 String featureType, FeatureColourI fcol)
5741 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5742 if (fcol.isSimpleColour())
5744 col.setRGB(Format.getHexString(fcol.getColour()));
5748 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5749 col.setMin(fcol.getMin());
5750 col.setMax(fcol.getMax());
5751 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5752 col.setAutoScale(fcol.isAutoScaled());
5753 col.setThreshold(fcol.getThreshold());
5754 col.setColourByLabel(fcol.isColourByLabel());
5755 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5756 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5757 : ColourThreshTypeType.NONE));
5758 if (fcol.isColourByAttribute())
5760 col.setAttributeName(fcol.getAttributeName());
5762 Color noColour = fcol.getNoColour();
5763 if (noColour == null)
5765 col.setNoValueColour(NoValueColour.NONE);
5767 else if (noColour == fcol.getMaxColour())
5769 col.setNoValueColour(NoValueColour.MAX);
5773 col.setNoValueColour(NoValueColour.MIN);
5776 col.setName(featureType);
5781 * Populates an XML model of the feature filter(s) for one feature type
5783 * @param firstMatcher
5784 * the first (or only) match condition)
5786 * remaining match conditions (if any)
5788 * if true, conditions are and-ed, else or-ed
5790 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5791 Iterator<FeatureMatcherI> filters, boolean and)
5793 MatcherSet result = new MatcherSet();
5795 if (filters.hasNext())
5800 CompoundMatcher compound = new CompoundMatcher();
5801 compound.setAnd(and);
5802 MatcherSet matcher1 = marshalFilter(firstMatcher,
5803 Collections.emptyIterator(), and);
5804 compound.addMatcherSet(matcher1);
5805 FeatureMatcherI nextMatcher = filters.next();
5806 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5807 compound.addMatcherSet(matcher2);
5808 result.setCompoundMatcher(compound);
5813 * single condition matcher
5815 MatchCondition matcherModel = new MatchCondition();
5816 matcherModel.setCondition(
5817 firstMatcher.getMatcher().getCondition().getStableName());
5818 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5819 if (firstMatcher.isByAttribute())
5821 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5822 matcherModel.setAttributeName(firstMatcher.getAttribute());
5824 else if (firstMatcher.isByLabel())
5826 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5828 else if (firstMatcher.isByScore())
5830 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5832 result.setMatchCondition(matcherModel);
5839 * Loads one XML model of a feature filter to a Jalview object
5841 * @param featureType
5842 * @param matcherSetModel
5845 protected static FeatureMatcherSetI unmarshalFilter(
5846 String featureType, MatcherSet matcherSetModel)
5848 FeatureMatcherSetI result = new FeatureMatcherSet();
5851 unmarshalFilterConditions(result, matcherSetModel, true);
5852 } catch (IllegalStateException e)
5854 // mixing AND and OR conditions perhaps
5856 String.format("Error reading filter conditions for '%s': %s",
5857 featureType, e.getMessage()));
5858 // return as much as was parsed up to the error
5865 * Adds feature match conditions to matcherSet as unmarshalled from XML
5866 * (possibly recursively for compound conditions)
5869 * @param matcherSetModel
5871 * if true, multiple conditions are AND-ed, else they are OR-ed
5872 * @throws IllegalStateException
5873 * if AND and OR conditions are mixed
5875 protected static void unmarshalFilterConditions(
5876 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5879 MatchCondition mc = matcherSetModel.getMatchCondition();
5885 FeatureMatcherByType filterBy = mc.getBy();
5886 Condition cond = Condition.fromString(mc.getCondition());
5887 String pattern = mc.getValue();
5888 FeatureMatcherI matchCondition = null;
5889 if (filterBy == FeatureMatcherByType.BYLABEL)
5891 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5893 else if (filterBy == FeatureMatcherByType.BYSCORE)
5895 matchCondition = FeatureMatcher.byScore(cond, pattern);
5898 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5900 String[] attNames = mc.getAttributeName();
5901 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5906 * note this throws IllegalStateException if AND-ing to a
5907 * previously OR-ed compound condition, or vice versa
5911 matcherSet.and(matchCondition);
5915 matcherSet.or(matchCondition);
5921 * compound condition
5923 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5925 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5926 if (matchers.length == 2)
5928 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5929 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5933 System.err.println("Malformed compound filter condition");
5939 * Loads one XML model of a feature colour to a Jalview object
5941 * @param colourModel
5944 protected static FeatureColourI unmarshalColour(
5945 jalview.schemabinding.version2.Colour colourModel)
5947 FeatureColourI colour = null;
5949 if (colourModel.hasMax())
5951 Color mincol = null;
5952 Color maxcol = null;
5953 Color noValueColour = null;
5957 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5958 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5959 } catch (Exception e)
5961 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5964 NoValueColour noCol = colourModel.getNoValueColour();
5965 if (noCol == NoValueColour.MIN)
5967 noValueColour = mincol;
5969 else if (noCol == NoValueColour.MAX)
5971 noValueColour = maxcol;
5974 colour = new FeatureColour(mincol, maxcol, noValueColour,
5975 colourModel.getMin(),
5976 colourModel.getMax());
5977 String[] attributes = colourModel.getAttributeName();
5978 if (attributes != null && attributes.length > 0)
5980 colour.setAttributeName(attributes);
5982 if (colourModel.hasAutoScale())
5984 colour.setAutoScaled(colourModel.getAutoScale());
5986 if (colourModel.hasColourByLabel())
5988 colour.setColourByLabel(colourModel.getColourByLabel());
5990 if (colourModel.hasThreshold())
5992 colour.setThreshold(colourModel.getThreshold());
5994 ColourThreshTypeType ttyp = colourModel.getThreshType();
5997 if (ttyp == ColourThreshTypeType.ABOVE)
5999 colour.setAboveThreshold(true);
6001 else if (ttyp == ColourThreshTypeType.BELOW)
6003 colour.setBelowThreshold(true);
6009 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6010 colour = new FeatureColour(color);