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.HiddenMarkovModel;
34 import jalview.datamodel.PDBEntry;
35 import jalview.datamodel.RnaViewerModel;
36 import jalview.datamodel.SequenceFeature;
37 import jalview.datamodel.SequenceGroup;
38 import jalview.datamodel.SequenceI;
39 import jalview.datamodel.StructureViewerModel;
40 import jalview.datamodel.StructureViewerModel.StructureData;
41 import jalview.datamodel.features.FeatureMatcher;
42 import jalview.datamodel.features.FeatureMatcherI;
43 import jalview.datamodel.features.FeatureMatcherSet;
44 import jalview.datamodel.features.FeatureMatcherSetI;
45 import jalview.ext.varna.RnaModel;
46 import jalview.gui.StructureViewer.ViewerType;
47 import jalview.io.DataSourceType;
48 import jalview.io.FileFormat;
49 import jalview.io.HMMFile;
50 import jalview.renderer.ResidueShaderI;
51 import jalview.schemabinding.version2.AlcodMap;
52 import jalview.schemabinding.version2.AlcodonFrame;
53 import jalview.schemabinding.version2.Annotation;
54 import jalview.schemabinding.version2.AnnotationColours;
55 import jalview.schemabinding.version2.AnnotationElement;
56 import jalview.schemabinding.version2.CalcIdParam;
57 import jalview.schemabinding.version2.CompoundMatcher;
58 import jalview.schemabinding.version2.DBRef;
59 import jalview.schemabinding.version2.Features;
60 import jalview.schemabinding.version2.Group;
61 import jalview.schemabinding.version2.HiddenColumns;
62 import jalview.schemabinding.version2.JGroup;
63 import jalview.schemabinding.version2.JSeq;
64 import jalview.schemabinding.version2.JalviewModel;
65 import jalview.schemabinding.version2.JalviewModelSequence;
66 import jalview.schemabinding.version2.MapListFrom;
67 import jalview.schemabinding.version2.MapListTo;
68 import jalview.schemabinding.version2.Mapping;
69 import jalview.schemabinding.version2.MappingChoice;
70 import jalview.schemabinding.version2.MatchCondition;
71 import jalview.schemabinding.version2.MatcherSet;
72 import jalview.schemabinding.version2.OtherData;
73 import jalview.schemabinding.version2.PdbentryItem;
74 import jalview.schemabinding.version2.Pdbids;
75 import jalview.schemabinding.version2.Property;
76 import jalview.schemabinding.version2.RnaViewer;
77 import jalview.schemabinding.version2.SecondaryStructure;
78 import jalview.schemabinding.version2.Sequence;
79 import jalview.schemabinding.version2.SequenceSet;
80 import jalview.schemabinding.version2.SequenceSetProperties;
81 import jalview.schemabinding.version2.Setting;
82 import jalview.schemabinding.version2.StructureState;
83 import jalview.schemabinding.version2.ThresholdLine;
84 import jalview.schemabinding.version2.Tree;
85 import jalview.schemabinding.version2.UserColours;
86 import jalview.schemabinding.version2.Viewport;
87 import jalview.schemabinding.version2.types.ColourThreshTypeType;
88 import jalview.schemabinding.version2.types.FeatureMatcherByType;
89 import jalview.schemabinding.version2.types.NoValueColour;
90 import jalview.schemes.AnnotationColourGradient;
91 import jalview.schemes.ColourSchemeI;
92 import jalview.schemes.ColourSchemeProperty;
93 import jalview.schemes.FeatureColour;
94 import jalview.schemes.ResidueProperties;
95 import jalview.schemes.UserColourScheme;
96 import jalview.structure.StructureSelectionManager;
97 import jalview.structures.models.AAStructureBindingModel;
98 import jalview.util.Format;
99 import jalview.util.MessageManager;
100 import jalview.util.Platform;
101 import jalview.util.StringUtils;
102 import jalview.util.jarInputStreamProvider;
103 import jalview.util.matcher.Condition;
104 import jalview.viewmodel.AlignmentViewport;
105 import jalview.viewmodel.ViewportRanges;
106 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
107 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
108 import jalview.ws.jws2.Jws2Discoverer;
109 import jalview.ws.jws2.dm.AAConSettings;
110 import jalview.ws.jws2.jabaws2.Jws2Instance;
111 import jalview.ws.params.ArgumentI;
112 import jalview.ws.params.AutoCalcSetting;
113 import jalview.ws.params.WsParamSetI;
115 import java.awt.Color;
116 import java.awt.Rectangle;
117 import java.io.BufferedReader;
118 import java.io.DataInputStream;
119 import java.io.DataOutputStream;
121 import java.io.FileInputStream;
122 import java.io.FileOutputStream;
123 import java.io.IOException;
124 import java.io.InputStreamReader;
125 import java.io.OutputStreamWriter;
126 import java.io.PrintWriter;
127 import java.lang.reflect.InvocationTargetException;
128 import java.net.MalformedURLException;
130 import java.util.ArrayList;
131 import java.util.Arrays;
132 import java.util.Collections;
133 import java.util.Enumeration;
134 import java.util.HashMap;
135 import java.util.HashSet;
136 import java.util.Hashtable;
137 import java.util.IdentityHashMap;
138 import java.util.Iterator;
139 import java.util.LinkedHashMap;
140 import java.util.List;
141 import java.util.Map;
142 import java.util.Map.Entry;
143 import java.util.Set;
144 import java.util.Vector;
145 import java.util.jar.JarEntry;
146 import java.util.jar.JarInputStream;
147 import java.util.jar.JarOutputStream;
149 import javax.swing.JInternalFrame;
150 import javax.swing.SwingUtilities;
152 import org.exolab.castor.xml.Marshaller;
153 import org.exolab.castor.xml.Unmarshaller;
156 * Write out the current jalview desktop state as a Jalview XML stream.
158 * Note: the vamsas objects referred to here are primitive versions of the
159 * VAMSAS project schema elements - they are not the same and most likely never
163 * @version $Revision: 1.134 $
165 public class Jalview2XML
167 private static final String VIEWER_PREFIX = "viewer_";
169 private static final String RNA_PREFIX = "rna_";
171 private static final String HMMER_PREFIX = "hmmer_";
173 private static final String UTF_8 = "UTF-8";
175 // use this with nextCounter() to make unique names for entities
176 private int counter = 0;
179 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
180 * of sequence objects are created.
182 IdentityHashMap<SequenceI, String> seqsToIds = null;
185 * jalview XML Sequence ID to jalview sequence object reference (both dataset
186 * and alignment sequences. Populated as XML reps of sequence objects are
189 Map<String, SequenceI> seqRefIds = null;
191 Map<String, SequenceI> incompleteSeqs = null;
193 List<SeqFref> frefedSequence = null;
195 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
198 * Map of reconstructed AlignFrame objects that appear to have come from
199 * SplitFrame objects (have a dna/protein complement view).
201 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
204 * Map from displayed rna structure models to their saved session state jar
207 private Map<RnaModel, String> rnaSessions = new HashMap<>();
210 * create/return unique hash string for sq
213 * @return new or existing unique string for sq
215 String seqHash(SequenceI sq)
217 if (seqsToIds == null)
221 if (seqsToIds.containsKey(sq))
223 return seqsToIds.get(sq);
227 // create sequential key
228 String key = "sq" + (seqsToIds.size() + 1);
229 key = makeHashCode(sq, key); // check we don't have an external reference
231 seqsToIds.put(sq, key);
238 if (seqsToIds == null)
240 seqsToIds = new IdentityHashMap<>();
242 if (seqRefIds == null)
244 seqRefIds = new HashMap<>();
246 if (incompleteSeqs == null)
248 incompleteSeqs = new HashMap<>();
250 if (frefedSequence == null)
252 frefedSequence = new ArrayList<>();
260 public Jalview2XML(boolean raiseGUI)
262 this.raiseGUI = raiseGUI;
266 * base class for resolving forward references to sequences by their ID
271 abstract class SeqFref
277 public SeqFref(String _sref, String type)
283 public String getSref()
288 public SequenceI getSrefSeq()
290 return seqRefIds.get(sref);
293 public boolean isResolvable()
295 return seqRefIds.get(sref) != null;
298 public SequenceI getSrefDatasetSeq()
300 SequenceI sq = seqRefIds.get(sref);
303 while (sq.getDatasetSequence() != null)
305 sq = sq.getDatasetSequence();
312 * @return true if the forward reference was fully resolved
314 abstract boolean resolve();
317 public String toString()
319 return type + " reference to " + sref;
324 * create forward reference for a mapping
330 public SeqFref newMappingRef(final String sref,
331 final jalview.datamodel.Mapping _jmap)
333 SeqFref fref = new SeqFref(sref, "Mapping")
335 public jalview.datamodel.Mapping jmap = _jmap;
340 SequenceI seq = getSrefDatasetSeq();
352 public SeqFref newAlcodMapRef(final String sref,
353 final AlignedCodonFrame _cf,
354 final jalview.datamodel.Mapping _jmap)
357 SeqFref fref = new SeqFref(sref, "Codon Frame")
359 AlignedCodonFrame cf = _cf;
361 public jalview.datamodel.Mapping mp = _jmap;
364 public boolean isResolvable()
366 return super.isResolvable() && mp.getTo() != null;
372 SequenceI seq = getSrefDatasetSeq();
377 cf.addMap(seq, mp.getTo(), mp.getMap());
384 public void resolveFrefedSequences()
386 Iterator<SeqFref> nextFref = frefedSequence.iterator();
387 int toresolve = frefedSequence.size();
388 int unresolved = 0, failedtoresolve = 0;
389 while (nextFref.hasNext())
391 SeqFref ref = nextFref.next();
392 if (ref.isResolvable())
404 } catch (Exception x)
407 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
420 System.err.println("Jalview Project Import: There were " + unresolved
421 + " forward references left unresolved on the stack.");
423 if (failedtoresolve > 0)
425 System.err.println("SERIOUS! " + failedtoresolve
426 + " resolvable forward references failed to resolve.");
428 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
431 "Jalview Project Import: There are " + incompleteSeqs.size()
432 + " sequences which may have incomplete metadata.");
433 if (incompleteSeqs.size() < 10)
435 for (SequenceI s : incompleteSeqs.values())
437 System.err.println(s.toString());
443 "Too many to report. Skipping output of incomplete sequences.");
449 * This maintains a map of viewports, the key being the seqSetId. Important to
450 * set historyItem and redoList for multiple views
452 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
454 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
456 String uniqueSetSuffix = "";
459 * List of pdbfiles added to Jar
461 List<String> pdbfiles = null;
463 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
464 public void saveState(File statefile)
466 FileOutputStream fos = null;
469 fos = new FileOutputStream(statefile);
470 JarOutputStream jout = new JarOutputStream(fos);
473 } catch (Exception e)
475 // TODO: inform user of the problem - they need to know if their data was
477 if (errorMessage == null)
479 errorMessage = "Couldn't write Jalview Archive to output file '"
480 + statefile + "' - See console error log for details";
484 errorMessage += "(output file was '" + statefile + "')";
494 } catch (IOException e)
504 * Writes a jalview project archive to the given Jar output stream.
508 public void saveState(JarOutputStream jout)
510 AlignFrame[] frames = Desktop.getAlignFrames();
516 saveAllFrames(Arrays.asList(frames), jout);
520 * core method for storing state for a set of AlignFrames.
523 * - frames involving all data to be exported (including containing
526 * - project output stream
528 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
530 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
533 * ensure cached data is clear before starting
535 // todo tidy up seqRefIds, seqsToIds initialisation / reset
537 splitFrameCandidates.clear();
542 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
543 // //////////////////////////////////////////////////
545 List<String> shortNames = new ArrayList<>();
546 List<String> viewIds = new ArrayList<>();
549 for (int i = frames.size() - 1; i > -1; i--)
551 AlignFrame af = frames.get(i);
553 if (skipList != null && skipList
554 .containsKey(af.getViewport().getSequenceSetId()))
559 String shortName = makeFilename(af, shortNames);
561 int ap, apSize = af.alignPanels.size();
563 for (ap = 0; ap < apSize; ap++)
565 AlignmentPanel apanel = af.alignPanels.get(ap);
566 String fileName = apSize == 1 ? shortName : ap + shortName;
567 if (!fileName.endsWith(".xml"))
569 fileName = fileName + ".xml";
572 saveState(apanel, fileName, jout, viewIds);
574 String dssid = getDatasetIdRef(
575 af.getViewport().getAlignment().getDataset());
576 if (!dsses.containsKey(dssid))
578 dsses.put(dssid, af);
583 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
589 } catch (Exception foo)
594 } catch (Exception ex)
596 // TODO: inform user of the problem - they need to know if their data was
598 if (errorMessage == null)
600 errorMessage = "Couldn't write Jalview Archive - see error output for details";
602 ex.printStackTrace();
607 * Generates a distinct file name, based on the title of the AlignFrame, by
608 * appending _n for increasing n until an unused name is generated. The new
609 * name (without its extension) is added to the list.
613 * @return the generated name, with .xml extension
615 protected String makeFilename(AlignFrame af, List<String> namesUsed)
617 String shortName = af.getTitle();
619 if (shortName.indexOf(File.separatorChar) > -1)
621 shortName = shortName
622 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
627 while (namesUsed.contains(shortName))
629 if (shortName.endsWith("_" + (count - 1)))
631 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
634 shortName = shortName.concat("_" + count);
638 namesUsed.add(shortName);
640 if (!shortName.endsWith(".xml"))
642 shortName = shortName + ".xml";
647 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
648 public boolean saveAlignment(AlignFrame af, String jarFile,
653 FileOutputStream fos = new FileOutputStream(jarFile);
654 JarOutputStream jout = new JarOutputStream(fos);
655 List<AlignFrame> frames = new ArrayList<>();
657 // resolve splitframes
658 if (af.getViewport().getCodingComplement() != null)
660 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
666 saveAllFrames(frames, jout);
670 } catch (Exception foo)
676 } catch (Exception ex)
678 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
679 ex.printStackTrace();
684 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
685 String fileName, JarOutputStream jout)
688 for (String dssids : dsses.keySet())
690 AlignFrame _af = dsses.get(dssids);
691 String jfileName = fileName + " Dataset for " + _af.getTitle();
692 if (!jfileName.endsWith(".xml"))
694 jfileName = jfileName + ".xml";
696 saveState(_af.alignPanel, jfileName, true, jout, null);
701 * create a JalviewModel from an alignment view and marshall it to a
705 * panel to create jalview model for
707 * name of alignment panel written to output stream
714 public JalviewModel saveState(AlignmentPanel ap, String fileName,
715 JarOutputStream jout, List<String> viewIds)
717 return saveState(ap, fileName, false, jout, viewIds);
721 * create a JalviewModel from an alignment view and marshall it to a
725 * panel to create jalview model for
727 * name of alignment panel written to output stream
729 * when true, only write the dataset for the alignment, not the data
730 * associated with the view.
736 public JalviewModel saveState(AlignmentPanel ap, String fileName,
737 boolean storeDS, JarOutputStream jout, List<String> viewIds)
741 viewIds = new ArrayList<>();
746 List<UserColourScheme> userColours = new ArrayList<>();
748 AlignViewport av = ap.av;
749 ViewportRanges vpRanges = av.getRanges();
751 JalviewModel object = new JalviewModel();
752 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
754 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
756 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
759 * rjal is full height alignment, jal is actual alignment with full metadata
760 * but excludes hidden sequences.
762 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
764 if (av.hasHiddenRows())
766 rjal = jal.getHiddenSequences().getFullAlignment();
769 SequenceSet vamsasSet = new SequenceSet();
771 JalviewModelSequence jms = new JalviewModelSequence();
773 vamsasSet.setGapChar(jal.getGapCharacter() + "");
775 if (jal.getDataset() != null)
777 // dataset id is the dataset's hashcode
778 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
781 // switch jal and the dataset
782 jal = jal.getDataset();
786 if (jal.getProperties() != null)
788 Enumeration en = jal.getProperties().keys();
789 while (en.hasMoreElements())
791 String key = en.nextElement().toString();
792 SequenceSetProperties ssp = new SequenceSetProperties();
794 ssp.setValue(jal.getProperties().get(key).toString());
795 vamsasSet.addSequenceSetProperties(ssp);
800 Set<String> calcIdSet = new HashSet<>();
801 // record the set of vamsas sequence XML POJO we create.
802 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
804 for (final SequenceI jds : rjal.getSequences())
806 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
807 : jds.getDatasetSequence();
808 String id = seqHash(jds);
809 if (vamsasSetIds.get(id) == null)
811 if (seqRefIds.get(id) != null && !storeDS)
813 // This happens for two reasons: 1. multiple views are being
815 // 2. the hashCode has collided with another sequence's code. This
817 // HAPPEN! (PF00072.15.stk does this)
818 // JBPNote: Uncomment to debug writing out of files that do not read
819 // back in due to ArrayOutOfBoundExceptions.
820 // System.err.println("vamsasSeq backref: "+id+"");
821 // System.err.println(jds.getName()+"
822 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
823 // System.err.println("Hashcode: "+seqHash(jds));
824 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
825 // System.err.println(rsq.getName()+"
826 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
827 // System.err.println("Hashcode: "+seqHash(rsq));
831 vamsasSeq = createVamsasSequence(id, jds);
832 vamsasSet.addSequence(vamsasSeq);
833 vamsasSetIds.put(id, vamsasSeq);
834 seqRefIds.put(id, jds);
838 jseq.setStart(jds.getStart());
839 jseq.setEnd(jds.getEnd());
840 jseq.setColour(av.getSequenceColour(jds).getRGB());
842 jseq.setId(id); // jseq id should be a string not a number
845 // Store any sequences this sequence represents
846 if (av.hasHiddenRows())
848 // use rjal, contains the full height alignment
850 av.getAlignment().getHiddenSequences().isHidden(jds));
852 if (av.isHiddenRepSequence(jds))
854 jalview.datamodel.SequenceI[] reps = av
855 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
857 for (int h = 0; h < reps.length; h++)
861 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
866 // mark sequence as reference - if it is the reference for this view
869 jseq.setViewreference(jds == jal.getSeqrep());
874 * save sequence features
875 * TODO: omit sequence features from each alignment view's
876 * XML dump if we are storing dataset
878 List<SequenceFeature> sfs = jds.getSequenceFeatures();
879 for (SequenceFeature sf : sfs)
881 Features features = saveFeature(sf);
882 jseq.addFeatures(features);
886 * save PDB entries for sequence
888 if (jdatasq.getAllPDBEntries() != null)
890 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
891 while (en.hasMoreElements())
893 Pdbids pdb = new Pdbids();
894 PDBEntry entry = en.nextElement();
896 String pdbId = entry.getId();
898 pdb.setType(entry.getType());
901 * Store any structure views associated with this sequence. This
902 * section copes with duplicate entries in the project, so a dataset
903 * only view *should* be coped with sensibly.
905 // This must have been loaded, is it still visible?
906 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
907 String matchedFile = null;
908 for (int f = frames.length - 1; f > -1; f--)
910 if (frames[f] instanceof StructureViewerBase)
912 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
913 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
914 matchedFile, viewFrame);
916 * Only store each structure viewer's state once in the project
917 * jar. First time through only (storeDS==false)
919 String viewId = viewFrame.getViewId();
920 if (!storeDS && !viewIds.contains(viewId))
925 String viewerState = viewFrame.getStateInfo();
926 writeJarEntry(jout, getViewerJarEntryName(viewId),
927 viewerState.getBytes());
928 } catch (IOException e)
931 "Error saving viewer state: " + e.getMessage());
937 if (matchedFile != null || entry.getFile() != null)
939 if (entry.getFile() != null)
942 matchedFile = entry.getFile();
944 pdb.setFile(matchedFile); // entry.getFile());
945 if (pdbfiles == null)
947 pdbfiles = new ArrayList<>();
950 if (!pdbfiles.contains(pdbId))
953 copyFileToJar(jout, matchedFile, pdbId);
957 Enumeration<String> props = entry.getProperties();
958 if (props.hasMoreElements())
960 PdbentryItem item = new PdbentryItem();
961 while (props.hasMoreElements())
963 Property prop = new Property();
964 String key = props.nextElement();
966 prop.setValue(entry.getProperty(key).toString());
967 item.addProperty(prop);
969 pdb.addPdbentryItem(item);
976 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
978 if (jds.hasHMMProfile())
980 saveHmmerProfile(jout, jseq, jds);
986 if (!storeDS && av.hasHiddenRows())
988 jal = av.getAlignment();
992 if (storeDS && jal.getCodonFrames() != null)
994 List<AlignedCodonFrame> jac = jal.getCodonFrames();
995 for (AlignedCodonFrame acf : jac)
997 AlcodonFrame alc = new AlcodonFrame();
998 if (acf.getProtMappings() != null
999 && acf.getProtMappings().length > 0)
1001 boolean hasMap = false;
1002 SequenceI[] dnas = acf.getdnaSeqs();
1003 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1004 for (int m = 0; m < pmaps.length; m++)
1006 AlcodMap alcmap = new AlcodMap();
1007 alcmap.setDnasq(seqHash(dnas[m]));
1009 createVamsasMapping(pmaps[m], dnas[m], null, false));
1010 alc.addAlcodMap(alcmap);
1015 vamsasSet.addAlcodonFrame(alc);
1018 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1020 // AlcodonFrame alc = new AlcodonFrame();
1021 // vamsasSet.addAlcodonFrame(alc);
1022 // for (int p = 0; p < acf.aaWidth; p++)
1024 // Alcodon cmap = new Alcodon();
1025 // if (acf.codons[p] != null)
1027 // // Null codons indicate a gapped column in the translated peptide
1029 // cmap.setPos1(acf.codons[p][0]);
1030 // cmap.setPos2(acf.codons[p][1]);
1031 // cmap.setPos3(acf.codons[p][2]);
1033 // alc.addAlcodon(cmap);
1035 // if (acf.getProtMappings() != null
1036 // && acf.getProtMappings().length > 0)
1038 // SequenceI[] dnas = acf.getdnaSeqs();
1039 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1040 // for (int m = 0; m < pmaps.length; m++)
1042 // AlcodMap alcmap = new AlcodMap();
1043 // alcmap.setDnasq(seqHash(dnas[m]));
1044 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1046 // alc.addAlcodMap(alcmap);
1053 // /////////////////////////////////
1054 if (!storeDS && av.getCurrentTree() != null)
1056 // FIND ANY ASSOCIATED TREES
1057 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1058 if (Desktop.desktop != null)
1060 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1062 for (int t = 0; t < frames.length; t++)
1064 if (frames[t] instanceof TreePanel)
1066 TreePanel tp = (TreePanel) frames[t];
1068 if (tp.treeCanvas.av.getAlignment() == jal)
1070 Tree tree = new Tree();
1071 tree.setTitle(tp.getTitle());
1072 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1073 tree.setNewick(tp.getTree().print());
1074 tree.setThreshold(tp.treeCanvas.threshold);
1076 tree.setFitToWindow(tp.fitToWindow.getState());
1077 tree.setFontName(tp.getTreeFont().getName());
1078 tree.setFontSize(tp.getTreeFont().getSize());
1079 tree.setFontStyle(tp.getTreeFont().getStyle());
1080 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1082 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1083 tree.setShowDistances(tp.distanceMenu.getState());
1085 tree.setHeight(tp.getHeight());
1086 tree.setWidth(tp.getWidth());
1087 tree.setXpos(tp.getX());
1088 tree.setYpos(tp.getY());
1089 tree.setId(makeHashCode(tp, null));
1099 * store forward refs from an annotationRow to any groups
1101 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1104 for (SequenceI sq : jal.getSequences())
1106 // Store annotation on dataset sequences only
1107 AlignmentAnnotation[] aa = sq.getAnnotation();
1108 if (aa != null && aa.length > 0)
1110 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1117 if (jal.getAlignmentAnnotation() != null)
1119 // Store the annotation shown on the alignment.
1120 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1121 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1126 if (jal.getGroups() != null)
1128 JGroup[] groups = new JGroup[jal.getGroups().size()];
1130 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1132 JGroup jGroup = new JGroup();
1133 groups[++i] = jGroup;
1135 jGroup.setStart(sg.getStartRes());
1136 jGroup.setEnd(sg.getEndRes());
1137 jGroup.setName(sg.getName());
1138 if (groupRefs.containsKey(sg))
1140 // group has references so set its ID field
1141 jGroup.setId(groupRefs.get(sg));
1143 ColourSchemeI colourScheme = sg.getColourScheme();
1144 if (colourScheme != null)
1146 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1147 if (groupColourScheme.conservationApplied())
1149 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1151 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1154 setUserColourScheme(colourScheme, userColours, jms));
1158 jGroup.setColour(colourScheme.getSchemeName());
1161 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1163 jGroup.setColour("AnnotationColourGradient");
1164 jGroup.setAnnotationColours(constructAnnotationColours(
1165 (jalview.schemes.AnnotationColourGradient) colourScheme,
1168 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1171 setUserColourScheme(colourScheme, userColours, jms));
1175 jGroup.setColour(colourScheme.getSchemeName());
1178 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1181 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1182 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1183 jGroup.setDisplayText(sg.getDisplayText());
1184 jGroup.setColourText(sg.getColourText());
1185 jGroup.setTextCol1(sg.textColour.getRGB());
1186 jGroup.setTextCol2(sg.textColour2.getRGB());
1187 jGroup.setTextColThreshold(sg.thresholdTextColour);
1188 jGroup.setShowUnconserved(sg.getShowNonconserved());
1189 jGroup.setIgnoreGapsinConsensus(sg.isIgnoreGapsConsensus());
1190 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1191 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1192 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1193 for (SequenceI seq : sg.getSequences())
1195 jGroup.addSeq(seqHash(seq));
1199 jms.setJGroup(groups);
1203 // /////////SAVE VIEWPORT
1204 Viewport view = new Viewport();
1205 view.setTitle(ap.alignFrame.getTitle());
1206 view.setSequenceSetId(
1207 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1208 view.setId(av.getViewId());
1209 if (av.getCodingComplement() != null)
1211 view.setComplementId(av.getCodingComplement().getViewId());
1213 view.setViewName(av.viewName);
1214 view.setGatheredViews(av.isGatherViewsHere());
1216 Rectangle size = ap.av.getExplodedGeometry();
1217 Rectangle position = size;
1220 size = ap.alignFrame.getBounds();
1221 if (av.getCodingComplement() != null)
1223 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1231 view.setXpos(position.x);
1232 view.setYpos(position.y);
1234 view.setWidth(size.width);
1235 view.setHeight(size.height);
1237 view.setStartRes(vpRanges.getStartRes());
1238 view.setStartSeq(vpRanges.getStartSeq());
1240 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1242 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1246 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1248 AnnotationColours ac = constructAnnotationColours(
1249 (jalview.schemes.AnnotationColourGradient) av
1250 .getGlobalColourScheme(),
1253 view.setAnnotationColours(ac);
1254 view.setBgColour("AnnotationColourGradient");
1258 view.setBgColour(ColourSchemeProperty
1259 .getColourName(av.getGlobalColourScheme()));
1262 ResidueShaderI vcs = av.getResidueShading();
1263 ColourSchemeI cs = av.getGlobalColourScheme();
1267 if (vcs.conservationApplied())
1269 view.setConsThreshold(vcs.getConservationInc());
1270 if (cs instanceof jalview.schemes.UserColourScheme)
1272 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1275 view.setPidThreshold(vcs.getThreshold());
1278 view.setConservationSelected(av.getConservationSelected());
1279 view.setPidSelected(av.getAbovePIDThreshold());
1280 view.setFontName(av.font.getName());
1281 view.setFontSize(av.font.getSize());
1282 view.setFontStyle(av.font.getStyle());
1283 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1284 view.setRenderGaps(av.isRenderGaps());
1285 view.setShowAnnotation(av.isShowAnnotation());
1286 view.setShowBoxes(av.getShowBoxes());
1287 view.setShowColourText(av.getColourText());
1288 view.setShowFullId(av.getShowJVSuffix());
1289 view.setRightAlignIds(av.isRightAlignIds());
1290 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1291 view.setShowText(av.getShowText());
1292 view.setShowUnconserved(av.getShowUnconserved());
1293 view.setWrapAlignment(av.getWrapAlignment());
1294 view.setTextCol1(av.getTextColour().getRGB());
1295 view.setTextCol2(av.getTextColour2().getRGB());
1296 view.setTextColThreshold(av.getThresholdTextColour());
1297 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1298 view.setShowSequenceLogo(av.isShowSequenceLogo());
1299 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1300 view.setShowGroupConsensus(av.isShowGroupConsensus());
1301 view.setShowGroupConservation(av.isShowGroupConservation());
1302 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1303 view.setShowDbRefTooltip(av.isShowDBRefs());
1304 view.setFollowHighlight(av.isFollowHighlight());
1305 view.setFollowSelection(av.followSelection);
1306 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1307 if (av.getFeaturesDisplayed() != null)
1309 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1311 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1312 .getFeatureRenderer();
1313 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1315 Vector<String> settingsAdded = new Vector<>();
1316 if (renderOrder != null)
1318 for (String featureType : renderOrder)
1320 Setting setting = new Setting();
1321 setting.setType(featureType);
1324 * save any filter for the feature type
1326 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1327 if (filter != null) {
1328 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1329 FeatureMatcherI firstFilter = filters.next();
1330 setting.setMatcherSet(Jalview2XML.marshalFilter(
1331 firstFilter, filters, filter.isAnded()));
1335 * save colour scheme for the feature type
1337 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1338 if (!fcol.isSimpleColour())
1340 setting.setColour(fcol.getMaxColour().getRGB());
1341 setting.setMincolour(fcol.getMinColour().getRGB());
1342 setting.setMin(fcol.getMin());
1343 setting.setMax(fcol.getMax());
1344 setting.setColourByLabel(fcol.isColourByLabel());
1345 if (fcol.isColourByAttribute())
1347 setting.setAttributeName(fcol.getAttributeName());
1349 setting.setAutoScale(fcol.isAutoScaled());
1350 setting.setThreshold(fcol.getThreshold());
1351 Color noColour = fcol.getNoColour();
1352 if (noColour == null)
1354 setting.setNoValueColour(NoValueColour.NONE);
1356 else if (noColour.equals(fcol.getMaxColour()))
1358 setting.setNoValueColour(NoValueColour.MAX);
1362 setting.setNoValueColour(NoValueColour.MIN);
1364 // -1 = No threshold, 0 = Below, 1 = Above
1365 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1366 : (fcol.isBelowThreshold() ? 0 : -1));
1370 setting.setColour(fcol.getColour().getRGB());
1374 av.getFeaturesDisplayed().isVisible(featureType));
1376 .getOrder(featureType);
1379 setting.setOrder(rorder);
1381 fs.addSetting(setting);
1382 settingsAdded.addElement(featureType);
1386 // is groups actually supposed to be a map here ?
1387 Iterator<String> en = fr.getFeatureGroups().iterator();
1388 Vector<String> groupsAdded = new Vector<>();
1389 while (en.hasNext())
1391 String grp = en.next();
1392 if (groupsAdded.contains(grp))
1396 Group g = new Group();
1398 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1401 groupsAdded.addElement(grp);
1403 jms.setFeatureSettings(fs);
1406 if (av.hasHiddenColumns())
1408 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1409 .getHiddenColumns();
1412 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1416 Iterator<int[]> hiddenRegions = hidden.iterator();
1417 while (hiddenRegions.hasNext())
1419 int[] region = hiddenRegions.next();
1420 HiddenColumns hc = new HiddenColumns();
1421 hc.setStart(region[0]);
1422 hc.setEnd(region[1]);
1423 view.addHiddenColumns(hc);
1427 if (calcIdSet.size() > 0)
1429 for (String calcId : calcIdSet)
1431 if (calcId.trim().length() > 0)
1433 CalcIdParam cidp = createCalcIdParam(calcId, av);
1434 // Some calcIds have no parameters.
1437 view.addCalcIdParam(cidp);
1443 jms.addViewport(view);
1445 object.setJalviewModelSequence(jms);
1446 object.getVamsasModel().addSequenceSet(vamsasSet);
1448 if (jout != null && fileName != null)
1450 // We may not want to write the object to disk,
1451 // eg we can copy the alignViewport to a new view object
1452 // using save and then load
1455 System.out.println("Writing jar entry " + fileName);
1456 JarEntry entry = new JarEntry(fileName);
1457 jout.putNextEntry(entry);
1458 PrintWriter pout = new PrintWriter(
1459 new OutputStreamWriter(jout, UTF_8));
1460 Marshaller marshaller = new Marshaller(pout);
1461 marshaller.marshal(object);
1464 } catch (Exception ex)
1466 // TODO: raise error in GUI if marshalling failed.
1467 ex.printStackTrace();
1474 * Saves the HMMER profile associated with the sequence as a file in the jar,
1475 * in HMMER format, and saves the name of the file as a child element of the
1476 * XML sequence element
1482 protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
1485 HiddenMarkovModel profile = seq.getHMM();
1486 if (profile == null)
1488 warn("Want to save HMM profile for " + seq.getName()
1489 + " but none found");
1492 HMMFile hmmFile = new HMMFile(profile);
1493 String hmmAsString = hmmFile.print();
1494 String jarEntryName = HMMER_PREFIX + nextCounter();
1497 writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
1498 xmlSeq.setHmmerProfile(jarEntryName);
1499 } catch (IOException e)
1501 warn("Error saving HMM profile: " + e.getMessage());
1506 * Converts a Jalview SequenceFeature into the XML model of it to save
1511 protected Features saveFeature(SequenceFeature sf)
1513 Features features = new Features();
1515 features.setBegin(sf.getBegin());
1516 features.setEnd(sf.getEnd());
1517 features.setDescription(sf.getDescription());
1518 features.setType(sf.getType());
1519 features.setFeatureGroup(sf.getFeatureGroup());
1520 features.setScore(sf.getScore());
1521 if (sf.links != null)
1523 for (int l = 0; l < sf.links.size(); l++)
1525 OtherData keyValue = new OtherData();
1526 keyValue.setKey("LINK_" + l);
1527 keyValue.setValue(sf.links.elementAt(l).toString());
1528 features.addOtherData(keyValue);
1531 if (sf.otherDetails != null)
1534 * save feature attributes, which may be simple strings or
1535 * map valued (have sub-attributes)
1537 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1539 String key = entry.getKey();
1540 Object value = entry.getValue();
1541 if (value instanceof Map<?, ?>)
1543 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1546 OtherData otherData = new OtherData();
1547 otherData.setKey(key);
1548 otherData.setKey2(subAttribute.getKey());
1549 otherData.setValue(subAttribute.getValue().toString());
1550 features.addOtherData(otherData);
1555 OtherData otherData = new OtherData();
1556 otherData.setKey(key);
1557 otherData.setValue(value.toString());
1558 features.addOtherData(otherData);
1566 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1567 * for each viewer, with
1569 * <li>viewer geometry (position, size, split pane divider location)</li>
1570 * <li>index of the selected structure in the viewer (currently shows gapped
1572 * <li>the id of the annotation holding RNA secondary structure</li>
1573 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1575 * Varna viewer state is also written out (in native Varna XML) to separate
1576 * project jar entries. A separate entry is written for each RNA structure
1577 * displayed, with the naming convention
1579 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1587 * @param storeDataset
1589 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1590 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1591 boolean storeDataset)
1593 if (Desktop.desktop == null)
1597 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1598 for (int f = frames.length - 1; f > -1; f--)
1600 if (frames[f] instanceof AppVarna)
1602 AppVarna varna = (AppVarna) frames[f];
1604 * link the sequence to every viewer that is showing it and is linked to
1605 * its alignment panel
1607 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1609 String viewId = varna.getViewId();
1610 RnaViewer rna = new RnaViewer();
1611 rna.setViewId(viewId);
1612 rna.setTitle(varna.getTitle());
1613 rna.setXpos(varna.getX());
1614 rna.setYpos(varna.getY());
1615 rna.setWidth(varna.getWidth());
1616 rna.setHeight(varna.getHeight());
1617 rna.setDividerLocation(varna.getDividerLocation());
1618 rna.setSelectedRna(varna.getSelectedIndex());
1619 jseq.addRnaViewer(rna);
1622 * Store each Varna panel's state once in the project per sequence.
1623 * First time through only (storeDataset==false)
1625 // boolean storeSessions = false;
1626 // String sequenceViewId = viewId + seqsToIds.get(jds);
1627 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1629 // viewIds.add(sequenceViewId);
1630 // storeSessions = true;
1632 for (RnaModel model : varna.getModels())
1634 if (model.seq == jds)
1637 * VARNA saves each view (sequence or alignment secondary
1638 * structure, gapped or trimmed) as a separate XML file
1640 String jarEntryName = rnaSessions.get(model);
1641 if (jarEntryName == null)
1644 String varnaStateFile = varna.getStateInfo(model.rna);
1645 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1646 copyFileToJar(jout, varnaStateFile, jarEntryName);
1647 rnaSessions.put(model, jarEntryName);
1649 SecondaryStructure ss = new SecondaryStructure();
1650 String annotationId = varna.getAnnotation(jds).annotationId;
1651 ss.setAnnotationId(annotationId);
1652 ss.setViewerState(jarEntryName);
1653 ss.setGapped(model.gapped);
1654 ss.setTitle(model.title);
1655 rna.addSecondaryStructure(ss);
1664 * Copy the contents of a file to a new entry added to the output jar
1668 * @param jarEntryName
1670 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1671 String jarEntryName)
1673 DataInputStream dis = null;
1676 File file = new File(infilePath);
1677 if (file.exists() && jout != null)
1679 dis = new DataInputStream(new FileInputStream(file));
1680 byte[] data = new byte[(int) file.length()];
1681 dis.readFully(data);
1682 writeJarEntry(jout, jarEntryName, data);
1684 } catch (Exception ex)
1686 ex.printStackTrace();
1694 } catch (IOException e)
1703 * Write the data to a new entry of given name in the output jar file
1706 * @param jarEntryName
1708 * @throws IOException
1710 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1711 byte[] data) throws IOException
1715 System.out.println("Writing jar entry " + jarEntryName);
1716 jout.putNextEntry(new JarEntry(jarEntryName));
1717 DataOutputStream dout = new DataOutputStream(jout);
1718 dout.write(data, 0, data.length);
1725 * Save the state of a structure viewer
1730 * the archive XML element under which to save the state
1733 * @param matchedFile
1737 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1738 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1739 String matchedFile, StructureViewerBase viewFrame)
1741 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1744 * Look for any bindings for this viewer to the PDB file of interest
1745 * (including part matches excluding chain id)
1747 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1749 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1750 final String pdbId = pdbentry.getId();
1751 if (!pdbId.equals(entry.getId())
1752 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1753 .startsWith(pdbId.toLowerCase())))
1756 * not interested in a binding to a different PDB entry here
1760 if (matchedFile == null)
1762 matchedFile = pdbentry.getFile();
1764 else if (!matchedFile.equals(pdbentry.getFile()))
1766 warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1767 + pdbentry.getFile());
1771 // can get at it if the ID
1772 // match is ambiguous (e.g.
1775 for (int smap = 0; smap < viewFrame.getBinding()
1776 .getSequence()[peid].length; smap++)
1778 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1779 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1781 StructureState state = new StructureState();
1782 state.setVisible(true);
1783 state.setXpos(viewFrame.getX());
1784 state.setYpos(viewFrame.getY());
1785 state.setWidth(viewFrame.getWidth());
1786 state.setHeight(viewFrame.getHeight());
1787 final String viewId = viewFrame.getViewId();
1788 state.setViewId(viewId);
1789 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1790 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1791 state.setColourByJmol(viewFrame.isColouredByViewer());
1792 state.setType(viewFrame.getViewerType().toString());
1793 pdb.addStructureState(state);
1801 * Populates the AnnotationColours xml for save. This captures the settings of
1802 * the options in the 'Colour by Annotation' dialog.
1805 * @param userColours
1809 private AnnotationColours constructAnnotationColours(
1810 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1811 JalviewModelSequence jms)
1813 AnnotationColours ac = new AnnotationColours();
1814 ac.setAboveThreshold(acg.getAboveThreshold());
1815 ac.setThreshold(acg.getAnnotationThreshold());
1816 // 2.10.2 save annotationId (unique) not annotation label
1817 ac.setAnnotation(acg.getAnnotation().annotationId);
1818 if (acg.getBaseColour() instanceof UserColourScheme)
1821 setUserColourScheme(acg.getBaseColour(), userColours, jms));
1826 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1829 ac.setMaxColour(acg.getMaxColour().getRGB());
1830 ac.setMinColour(acg.getMinColour().getRGB());
1831 ac.setPerSequence(acg.isSeqAssociated());
1832 ac.setPredefinedColours(acg.isPredefinedColours());
1836 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1837 IdentityHashMap<SequenceGroup, String> groupRefs,
1838 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1839 SequenceSet vamsasSet)
1842 for (int i = 0; i < aa.length; i++)
1844 Annotation an = new Annotation();
1846 AlignmentAnnotation annotation = aa[i];
1847 if (annotation.annotationId != null)
1849 annotationIds.put(annotation.annotationId, annotation);
1852 an.setId(annotation.annotationId);
1854 an.setVisible(annotation.visible);
1856 an.setDescription(annotation.description);
1858 if (annotation.sequenceRef != null)
1860 // 2.9 JAL-1781 xref on sequence id rather than name
1861 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1863 if (annotation.groupRef != null)
1865 String groupIdr = groupRefs.get(annotation.groupRef);
1866 if (groupIdr == null)
1868 // make a locally unique String
1869 groupRefs.put(annotation.groupRef,
1870 groupIdr = ("" + System.currentTimeMillis()
1871 + annotation.groupRef.getName()
1872 + groupRefs.size()));
1874 an.setGroupRef(groupIdr.toString());
1877 // store all visualization attributes for annotation
1878 an.setGraphHeight(annotation.graphHeight);
1879 an.setCentreColLabels(annotation.centreColLabels);
1880 an.setScaleColLabels(annotation.scaleColLabel);
1881 an.setShowAllColLabels(annotation.showAllColLabels);
1882 an.setBelowAlignment(annotation.belowAlignment);
1884 if (annotation.graph > 0)
1887 an.setGraphType(annotation.graph);
1888 an.setGraphGroup(annotation.graphGroup);
1889 if (annotation.getThreshold() != null)
1891 ThresholdLine line = new ThresholdLine();
1892 line.setLabel(annotation.getThreshold().label);
1893 line.setValue(annotation.getThreshold().value);
1894 line.setColour(annotation.getThreshold().colour.getRGB());
1895 an.setThresholdLine(line);
1903 an.setLabel(annotation.label);
1905 if (annotation == av.getAlignmentQualityAnnot()
1906 || annotation == av.getAlignmentConservationAnnotation()
1907 || annotation == av.getAlignmentConsensusAnnotation()
1908 || annotation.autoCalculated)
1910 // new way of indicating autocalculated annotation -
1911 an.setAutoCalculated(annotation.autoCalculated);
1913 if (annotation.hasScore())
1915 an.setScore(annotation.getScore());
1918 if (annotation.getCalcId() != null)
1920 calcIdSet.add(annotation.getCalcId());
1921 an.setCalcId(annotation.getCalcId());
1923 if (annotation.hasProperties())
1925 for (String pr : annotation.getProperties())
1927 Property prop = new Property();
1929 prop.setValue(annotation.getProperty(pr));
1930 an.addProperty(prop);
1934 AnnotationElement ae;
1935 if (annotation.annotations != null)
1937 an.setScoreOnly(false);
1938 for (int a = 0; a < annotation.annotations.length; a++)
1940 if ((annotation == null) || (annotation.annotations[a] == null))
1945 ae = new AnnotationElement();
1946 if (annotation.annotations[a].description != null)
1948 ae.setDescription(annotation.annotations[a].description);
1950 if (annotation.annotations[a].displayCharacter != null)
1952 ae.setDisplayCharacter(
1953 annotation.annotations[a].displayCharacter);
1956 if (!Float.isNaN(annotation.annotations[a].value))
1958 ae.setValue(annotation.annotations[a].value);
1962 if (annotation.annotations[a].secondaryStructure > ' ')
1964 ae.setSecondaryStructure(
1965 annotation.annotations[a].secondaryStructure + "");
1968 if (annotation.annotations[a].colour != null
1969 && annotation.annotations[a].colour != java.awt.Color.black)
1971 ae.setColour(annotation.annotations[a].colour.getRGB());
1974 an.addAnnotationElement(ae);
1975 if (annotation.autoCalculated)
1977 // only write one non-null entry into the annotation row -
1978 // sufficient to get the visualization attributes necessary to
1986 an.setScoreOnly(true);
1988 if (!storeDS || (storeDS && !annotation.autoCalculated))
1990 // skip autocalculated annotation - these are only provided for
1992 vamsasSet.addAnnotation(an);
1998 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2000 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2001 if (settings != null)
2003 CalcIdParam vCalcIdParam = new CalcIdParam();
2004 vCalcIdParam.setCalcId(calcId);
2005 vCalcIdParam.addServiceURL(settings.getServiceURI());
2006 // generic URI allowing a third party to resolve another instance of the
2007 // service used for this calculation
2008 for (String urls : settings.getServiceURLs())
2010 vCalcIdParam.addServiceURL(urls);
2012 vCalcIdParam.setVersion("1.0");
2013 if (settings.getPreset() != null)
2015 WsParamSetI setting = settings.getPreset();
2016 vCalcIdParam.setName(setting.getName());
2017 vCalcIdParam.setDescription(setting.getDescription());
2021 vCalcIdParam.setName("");
2022 vCalcIdParam.setDescription("Last used parameters");
2024 // need to be able to recover 1) settings 2) user-defined presets or
2025 // recreate settings from preset 3) predefined settings provided by
2026 // service - or settings that can be transferred (or discarded)
2027 vCalcIdParam.setParameters(
2028 settings.getWsParamFile().replace("\n", "|\\n|"));
2029 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2030 // todo - decide if updateImmediately is needed for any projects.
2032 return vCalcIdParam;
2037 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2040 if (calcIdParam.getVersion().equals("1.0"))
2042 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2043 .getPreferredServiceFor(calcIdParam.getServiceURL());
2044 if (service != null)
2046 WsParamSetI parmSet = null;
2049 parmSet = service.getParamStore().parseServiceParameterFile(
2050 calcIdParam.getName(), calcIdParam.getDescription(),
2051 calcIdParam.getServiceURL(),
2052 calcIdParam.getParameters().replace("|\\n|", "\n"));
2053 } catch (IOException x)
2055 warn("Couldn't parse parameter data for "
2056 + calcIdParam.getCalcId(), x);
2059 List<ArgumentI> argList = null;
2060 if (calcIdParam.getName().length() > 0)
2062 parmSet = service.getParamStore()
2063 .getPreset(calcIdParam.getName());
2064 if (parmSet != null)
2066 // TODO : check we have a good match with settings in AACon -
2067 // otherwise we'll need to create a new preset
2072 argList = parmSet.getArguments();
2075 AAConSettings settings = new AAConSettings(
2076 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2077 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2078 calcIdParam.isNeedsUpdate());
2083 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2087 throw new Error(MessageManager.formatMessage(
2088 "error.unsupported_version_calcIdparam", new Object[]
2089 { calcIdParam.toString() }));
2093 * External mapping between jalview objects and objects yielding a valid and
2094 * unique object ID string. This is null for normal Jalview project IO, but
2095 * non-null when a jalview project is being read or written as part of a
2098 IdentityHashMap jv2vobj = null;
2101 * Construct a unique ID for jvobj using either existing bindings or if none
2102 * exist, the result of the hashcode call for the object.
2105 * jalview data object
2106 * @return unique ID for referring to jvobj
2108 private String makeHashCode(Object jvobj, String altCode)
2110 if (jv2vobj != null)
2112 Object id = jv2vobj.get(jvobj);
2115 return id.toString();
2117 // check string ID mappings
2118 if (jvids2vobj != null && jvobj instanceof String)
2120 id = jvids2vobj.get(jvobj);
2124 return id.toString();
2126 // give up and warn that something has gone wrong
2127 warn("Cannot find ID for object in external mapping : " + jvobj);
2133 * return local jalview object mapped to ID, if it exists
2137 * @return null or object bound to idcode
2139 private Object retrieveExistingObj(String idcode)
2141 if (idcode != null && vobj2jv != null)
2143 return vobj2jv.get(idcode);
2149 * binding from ID strings from external mapping table to jalview data model
2152 private Hashtable vobj2jv;
2154 private Sequence createVamsasSequence(String id, SequenceI jds)
2156 return createVamsasSequence(true, id, jds, null);
2159 private Sequence createVamsasSequence(boolean recurse, String id,
2160 SequenceI jds, SequenceI parentseq)
2162 Sequence vamsasSeq = new Sequence();
2163 vamsasSeq.setId(id);
2164 vamsasSeq.setName(jds.getName());
2165 vamsasSeq.setSequence(jds.getSequenceAsString());
2166 vamsasSeq.setDescription(jds.getDescription());
2167 jalview.datamodel.DBRefEntry[] dbrefs = null;
2168 if (jds.getDatasetSequence() != null)
2170 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2174 // seqId==dsseqid so we can tell which sequences really are
2175 // dataset sequences only
2176 vamsasSeq.setDsseqid(id);
2177 dbrefs = jds.getDBRefs();
2178 if (parentseq == null)
2185 for (int d = 0; d < dbrefs.length; d++)
2187 DBRef dbref = new DBRef();
2188 dbref.setSource(dbrefs[d].getSource());
2189 dbref.setVersion(dbrefs[d].getVersion());
2190 dbref.setAccessionId(dbrefs[d].getAccessionId());
2191 if (dbrefs[d].hasMap())
2193 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2195 dbref.setMapping(mp);
2197 vamsasSeq.addDBRef(dbref);
2203 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2204 SequenceI parentseq, SequenceI jds, boolean recurse)
2207 if (jmp.getMap() != null)
2211 jalview.util.MapList mlst = jmp.getMap();
2212 List<int[]> r = mlst.getFromRanges();
2213 for (int[] range : r)
2215 MapListFrom mfrom = new MapListFrom();
2216 mfrom.setStart(range[0]);
2217 mfrom.setEnd(range[1]);
2218 mp.addMapListFrom(mfrom);
2220 r = mlst.getToRanges();
2221 for (int[] range : r)
2223 MapListTo mto = new MapListTo();
2224 mto.setStart(range[0]);
2225 mto.setEnd(range[1]);
2226 mp.addMapListTo(mto);
2228 mp.setMapFromUnit(mlst.getFromRatio());
2229 mp.setMapToUnit(mlst.getToRatio());
2230 if (jmp.getTo() != null)
2232 MappingChoice mpc = new MappingChoice();
2234 // check/create ID for the sequence referenced by getTo()
2237 SequenceI ps = null;
2238 if (parentseq != jmp.getTo()
2239 && parentseq.getDatasetSequence() != jmp.getTo())
2241 // chaining dbref rather than a handshaking one
2242 jmpid = seqHash(ps = jmp.getTo());
2246 jmpid = seqHash(ps = parentseq);
2248 mpc.setDseqFor(jmpid);
2249 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2251 debug("creating new DseqFor ID");
2252 seqRefIds.put(mpc.getDseqFor(), ps);
2256 debug("reusing DseqFor ID");
2259 mp.setMappingChoice(mpc);
2265 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2266 List<UserColourScheme> userColours, JalviewModelSequence jms)
2269 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2270 boolean newucs = false;
2271 if (!userColours.contains(ucs))
2273 userColours.add(ucs);
2276 id = "ucs" + userColours.indexOf(ucs);
2279 // actually create the scheme's entry in the XML model
2280 java.awt.Color[] colours = ucs.getColours();
2281 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2282 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2284 for (int i = 0; i < colours.length; i++)
2286 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2287 col.setName(ResidueProperties.aa[i]);
2288 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2289 jbucs.addColour(col);
2291 if (ucs.getLowerCaseColours() != null)
2293 colours = ucs.getLowerCaseColours();
2294 for (int i = 0; i < colours.length; i++)
2296 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2297 col.setName(ResidueProperties.aa[i].toLowerCase());
2298 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2299 jbucs.addColour(col);
2304 uc.setUserColourScheme(jbucs);
2305 jms.addUserColours(uc);
2311 jalview.schemes.UserColourScheme getUserColourScheme(
2312 JalviewModelSequence jms, String id)
2314 UserColours[] uc = jms.getUserColours();
2315 UserColours colours = null;
2317 for (int i = 0; i < uc.length; i++)
2319 if (uc[i].getId().equals(id))
2327 java.awt.Color[] newColours = new java.awt.Color[24];
2329 for (int i = 0; i < 24; i++)
2331 newColours[i] = new java.awt.Color(Integer.parseInt(
2332 colours.getUserColourScheme().getColour(i).getRGB(), 16));
2335 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2338 if (colours.getUserColourScheme().getColourCount() > 24)
2340 newColours = new java.awt.Color[23];
2341 for (int i = 0; i < 23; i++)
2343 newColours[i] = new java.awt.Color(Integer.parseInt(
2344 colours.getUserColourScheme().getColour(i + 24).getRGB(),
2347 ucs.setLowerCaseColours(newColours);
2354 * contains last error message (if any) encountered by XML loader.
2356 String errorMessage = null;
2359 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2360 * exceptions are raised during project XML parsing
2362 public boolean attemptversion1parse = true;
2365 * Load a jalview project archive from a jar file
2368 * - HTTP URL or filename
2370 public AlignFrame loadJalviewAlign(final String file)
2373 jalview.gui.AlignFrame af = null;
2377 // create list to store references for any new Jmol viewers created
2378 newStructureViewers = new Vector<>();
2379 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2380 // Workaround is to make sure caller implements the JarInputStreamProvider
2382 // so we can re-open the jar input stream for each entry.
2384 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2385 af = loadJalviewAlign(jprovider);
2386 af.setMenusForViewport();
2388 } catch (MalformedURLException e)
2390 errorMessage = "Invalid URL format for '" + file + "'";
2396 SwingUtilities.invokeAndWait(new Runnable()
2401 setLoadingFinishedForNewStructureViewers();
2404 } catch (Exception x)
2406 System.err.println("Error loading alignment: " + x.getMessage());
2412 private jarInputStreamProvider createjarInputStreamProvider(
2413 final String file) throws MalformedURLException
2416 errorMessage = null;
2417 uniqueSetSuffix = null;
2419 viewportsAdded.clear();
2420 frefedSequence = null;
2422 if (file.startsWith("http://"))
2424 url = new URL(file);
2426 final URL _url = url;
2427 return new jarInputStreamProvider()
2431 public JarInputStream getJarInputStream() throws IOException
2435 return new JarInputStream(_url.openStream());
2439 return new JarInputStream(new FileInputStream(file));
2444 public String getFilename()
2452 * Recover jalview session from a jalview project archive. Caller may
2453 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2454 * themselves. Any null fields will be initialised with default values,
2455 * non-null fields are left alone.
2460 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2462 errorMessage = null;
2463 if (uniqueSetSuffix == null)
2465 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2467 if (seqRefIds == null)
2471 AlignFrame af = null, _af = null;
2472 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2473 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2474 final String file = jprovider.getFilename();
2477 JarInputStream jin = null;
2478 JarEntry jarentry = null;
2483 jin = jprovider.getJarInputStream();
2484 for (int i = 0; i < entryCount; i++)
2486 jarentry = jin.getNextJarEntry();
2489 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2491 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2492 JalviewModel object = new JalviewModel();
2494 Unmarshaller unmar = new Unmarshaller(object);
2495 unmar.setValidation(false);
2496 object = (JalviewModel) unmar.unmarshal(in);
2497 if (true) // !skipViewport(object))
2499 _af = loadFromObject(object, file, true, jprovider);
2500 if (_af != null && object.getJalviewModelSequence()
2501 .getViewportCount() > 0)
2505 // store a reference to the first view
2508 if (_af.viewport.isGatherViewsHere())
2510 // if this is a gathered view, keep its reference since
2511 // after gathering views, only this frame will remain
2513 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2515 // Save dataset to register mappings once all resolved
2516 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2517 af.viewport.getAlignment().getDataset());
2522 else if (jarentry != null)
2524 // Some other file here.
2527 } while (jarentry != null);
2528 resolveFrefedSequences();
2529 } catch (IOException ex)
2531 ex.printStackTrace();
2532 errorMessage = "Couldn't locate Jalview XML file : " + file;
2534 "Exception whilst loading jalview XML file : " + ex + "\n");
2535 } catch (Exception ex)
2537 System.err.println("Parsing as Jalview Version 2 file failed.");
2538 ex.printStackTrace(System.err);
2539 if (attemptversion1parse)
2541 // Is Version 1 Jar file?
2544 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2545 } catch (Exception ex2)
2547 System.err.println("Exception whilst loading as jalviewXMLV1:");
2548 ex2.printStackTrace();
2552 if (Desktop.instance != null)
2554 Desktop.instance.stopLoading();
2558 System.out.println("Successfully loaded archive file");
2561 ex.printStackTrace();
2564 "Exception whilst loading jalview XML file : " + ex + "\n");
2565 } catch (OutOfMemoryError e)
2567 // Don't use the OOM Window here
2568 errorMessage = "Out of memory loading jalview XML file";
2569 System.err.println("Out of memory whilst loading jalview XML file");
2570 e.printStackTrace();
2574 * Regather multiple views (with the same sequence set id) to the frame (if
2575 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2576 * views instead of separate frames. Note this doesn't restore a state where
2577 * some expanded views in turn have tabbed views - the last "first tab" read
2578 * in will play the role of gatherer for all.
2580 for (AlignFrame fr : gatherToThisFrame.values())
2582 Desktop.instance.gatherViews(fr);
2585 restoreSplitFrames();
2586 for (AlignmentI ds : importedDatasets.keySet())
2588 if (ds.getCodonFrames() != null)
2590 StructureSelectionManager
2591 .getStructureSelectionManager(Desktop.instance)
2592 .registerMappings(ds.getCodonFrames());
2595 if (errorMessage != null)
2600 if (Desktop.instance != null)
2602 Desktop.instance.stopLoading();
2609 * Try to reconstruct and display SplitFrame windows, where each contains
2610 * complementary dna and protein alignments. Done by pairing up AlignFrame
2611 * objects (created earlier) which have complementary viewport ids associated.
2613 protected void restoreSplitFrames()
2615 List<SplitFrame> gatherTo = new ArrayList<>();
2616 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2617 Map<String, AlignFrame> dna = new HashMap<>();
2620 * Identify the DNA alignments
2622 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2625 AlignFrame af = candidate.getValue();
2626 if (af.getViewport().getAlignment().isNucleotide())
2628 dna.put(candidate.getKey().getId(), af);
2633 * Try to match up the protein complements
2635 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2638 AlignFrame af = candidate.getValue();
2639 if (!af.getViewport().getAlignment().isNucleotide())
2641 String complementId = candidate.getKey().getComplementId();
2642 // only non-null complements should be in the Map
2643 if (complementId != null && dna.containsKey(complementId))
2645 final AlignFrame dnaFrame = dna.get(complementId);
2646 SplitFrame sf = createSplitFrame(dnaFrame, af);
2647 addedToSplitFrames.add(dnaFrame);
2648 addedToSplitFrames.add(af);
2649 dnaFrame.setMenusForViewport();
2650 af.setMenusForViewport();
2651 if (af.viewport.isGatherViewsHere())
2660 * Open any that we failed to pair up (which shouldn't happen!) as
2661 * standalone AlignFrame's.
2663 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2666 AlignFrame af = candidate.getValue();
2667 if (!addedToSplitFrames.contains(af))
2669 Viewport view = candidate.getKey();
2670 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2672 af.setMenusForViewport();
2673 System.err.println("Failed to restore view " + view.getTitle()
2674 + " to split frame");
2679 * Gather back into tabbed views as flagged.
2681 for (SplitFrame sf : gatherTo)
2683 Desktop.instance.gatherViews(sf);
2686 splitFrameCandidates.clear();
2690 * Construct and display one SplitFrame holding DNA and protein alignments.
2693 * @param proteinFrame
2696 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2697 AlignFrame proteinFrame)
2699 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2700 String title = MessageManager.getString("label.linked_view_title");
2701 int width = (int) dnaFrame.getBounds().getWidth();
2702 int height = (int) (dnaFrame.getBounds().getHeight()
2703 + proteinFrame.getBounds().getHeight() + 50);
2706 * SplitFrame location is saved to both enclosed frames
2708 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2709 Desktop.addInternalFrame(splitFrame, title, width, height);
2712 * And compute cDNA consensus (couldn't do earlier with consensus as
2713 * mappings were not yet present)
2715 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2721 * check errorMessage for a valid error message and raise an error box in the
2722 * GUI or write the current errorMessage to stderr and then clear the error
2725 protected void reportErrors()
2727 reportErrors(false);
2730 protected void reportErrors(final boolean saving)
2732 if (errorMessage != null)
2734 final String finalErrorMessage = errorMessage;
2737 javax.swing.SwingUtilities.invokeLater(new Runnable()
2742 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2744 "Error " + (saving ? "saving" : "loading")
2746 JvOptionPane.WARNING_MESSAGE);
2752 System.err.println("Problem loading Jalview file: " + errorMessage);
2755 errorMessage = null;
2758 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2761 * when set, local views will be updated from view stored in JalviewXML
2762 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2763 * sync if this is set to true.
2765 private final boolean updateLocalViews = false;
2768 * Returns the path to a temporary file holding the PDB file for the given PDB
2769 * id. The first time of asking, searches for a file of that name in the
2770 * Jalview project jar, and copies it to a new temporary file. Any repeat
2771 * requests just return the path to the file previously created.
2777 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2780 if (alreadyLoadedPDB.containsKey(pdbId))
2782 return alreadyLoadedPDB.get(pdbId).toString();
2785 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2787 if (tempFile != null)
2789 alreadyLoadedPDB.put(pdbId, tempFile);
2795 * Copies the jar entry of given name to a new temporary file and returns the
2796 * path to the file, or null if the entry is not found.
2799 * @param jarEntryName
2801 * a prefix for the temporary file name, must be at least three
2804 * null or original file - so new file can be given the same suffix
2808 protected String copyJarEntry(jarInputStreamProvider jprovider,
2809 String jarEntryName, String prefix, String origFile)
2811 BufferedReader in = null;
2812 PrintWriter out = null;
2813 String suffix = ".tmp";
2814 if (origFile == null)
2816 origFile = jarEntryName;
2818 int sfpos = origFile.lastIndexOf(".");
2819 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2821 suffix = "." + origFile.substring(sfpos + 1);
2825 JarInputStream jin = jprovider.getJarInputStream();
2827 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2828 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2829 * FileInputStream(jprovider)); }
2832 JarEntry entry = null;
2835 entry = jin.getNextJarEntry();
2836 } while (entry != null && !entry.getName().equals(jarEntryName));
2839 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2840 File outFile = File.createTempFile(prefix, suffix);
2841 outFile.deleteOnExit();
2842 out = new PrintWriter(new FileOutputStream(outFile));
2845 while ((data = in.readLine()) != null)
2850 String t = outFile.getAbsolutePath();
2855 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2857 } catch (Exception ex)
2859 ex.printStackTrace();
2867 } catch (IOException e)
2881 private class JvAnnotRow
2883 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2890 * persisted version of annotation row from which to take vis properties
2892 public jalview.datamodel.AlignmentAnnotation template;
2895 * original position of the annotation row in the alignment
2901 * Load alignment frame from jalview XML DOM object
2906 * filename source string
2907 * @param loadTreesAndStructures
2908 * when false only create Viewport
2910 * data source provider
2911 * @return alignment frame created from view stored in DOM
2913 AlignFrame loadFromObject(JalviewModel object, String file,
2914 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2916 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2917 Sequence[] vamsasSeq = vamsasSet.getSequence();
2919 JalviewModelSequence jms = object.getJalviewModelSequence();
2921 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2924 // ////////////////////////////////
2927 List<SequenceI> hiddenSeqs = null;
2929 List<SequenceI> tmpseqs = new ArrayList<>();
2931 boolean multipleView = false;
2932 SequenceI referenceseqForView = null;
2933 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2934 int vi = 0; // counter in vamsasSeq array
2935 for (int i = 0; i < jseqs.length; i++)
2937 String seqId = jseqs[i].getId();
2939 SequenceI tmpSeq = seqRefIds.get(seqId);
2942 if (!incompleteSeqs.containsKey(seqId))
2944 // may not need this check, but keep it for at least 2.9,1 release
2945 if (tmpSeq.getStart() != jseqs[i].getStart()
2946 || tmpSeq.getEnd() != jseqs[i].getEnd())
2949 "Warning JAL-2154 regression: updating start/end for sequence "
2950 + tmpSeq.toString() + " to " + jseqs[i]);
2955 incompleteSeqs.remove(seqId);
2957 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2959 // most likely we are reading a dataset XML document so
2960 // update from vamsasSeq section of XML for this sequence
2961 tmpSeq.setName(vamsasSeq[vi].getName());
2962 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2963 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2968 // reading multiple views, so vamsasSeq set is a subset of JSeq
2969 multipleView = true;
2971 tmpSeq.setStart(jseqs[i].getStart());
2972 tmpSeq.setEnd(jseqs[i].getEnd());
2973 tmpseqs.add(tmpSeq);
2977 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2978 vamsasSeq[vi].getSequence());
2979 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2980 tmpSeq.setStart(jseqs[i].getStart());
2981 tmpSeq.setEnd(jseqs[i].getEnd());
2982 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2983 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2984 tmpseqs.add(tmpSeq);
2988 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2990 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2993 if (jseqs[i].getHidden())
2995 if (hiddenSeqs == null)
2997 hiddenSeqs = new ArrayList<>();
3000 hiddenSeqs.add(tmpSeq);
3005 // Create the alignment object from the sequence set
3006 // ///////////////////////////////
3007 SequenceI[] orderedSeqs = tmpseqs
3008 .toArray(new SequenceI[tmpseqs.size()]);
3010 AlignmentI al = null;
3011 // so we must create or recover the dataset alignment before going further
3012 // ///////////////////////////////
3013 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3015 // older jalview projects do not have a dataset - so creat alignment and
3017 al = new Alignment(orderedSeqs);
3018 al.setDataset(null);
3022 boolean isdsal = object.getJalviewModelSequence()
3023 .getViewportCount() == 0;
3026 // we are importing a dataset record, so
3027 // recover reference to an alignment already materialsed as dataset
3028 al = getDatasetFor(vamsasSet.getDatasetId());
3032 // materialse the alignment
3033 al = new Alignment(orderedSeqs);
3037 addDatasetRef(vamsasSet.getDatasetId(), al);
3040 // finally, verify all data in vamsasSet is actually present in al
3041 // passing on flag indicating if it is actually a stored dataset
3042 recoverDatasetFor(vamsasSet, al, isdsal);
3045 if (referenceseqForView != null)
3047 al.setSeqrep(referenceseqForView);
3049 // / Add the alignment properties
3050 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
3052 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
3053 al.setProperty(ssp.getKey(), ssp.getValue());
3056 // ///////////////////////////////
3058 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3061 // load sequence features, database references and any associated PDB
3062 // structures for the alignment
3064 // prior to 2.10, this part would only be executed the first time a
3065 // sequence was encountered, but not afterwards.
3066 // now, for 2.10 projects, this is also done if the xml doc includes
3067 // dataset sequences not actually present in any particular view.
3069 for (int i = 0; i < vamsasSeq.length; i++)
3071 SequenceI alignmentSeq = al.getSequenceAt(i);
3072 if (jseqs[i].getFeaturesCount() > 0)
3074 Features[] features = jseqs[i].getFeatures();
3075 for (int f = 0; f < features.length; f++)
3077 Features feature = features[f];
3078 SequenceFeature sf = new SequenceFeature(feature.getType(),
3079 feature.getDescription(), feature.getBegin(),
3080 feature.getEnd(), feature.getScore(),
3081 feature.getFeatureGroup());
3082 sf.setStatus(feature.getStatus());
3085 * load any feature attributes - include map-valued attributes
3087 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3088 for (int od = 0; od < feature.getOtherDataCount(); od++)
3090 OtherData keyValue = feature.getOtherData(od);
3091 String attributeName = keyValue.getKey();
3092 String attributeValue = keyValue.getValue();
3093 if (attributeName.startsWith("LINK"))
3095 sf.addLink(attributeValue);
3099 String subAttribute = keyValue.getKey2();
3100 if (subAttribute == null)
3102 // simple string-valued attribute
3103 sf.setValue(attributeName, attributeValue);
3107 // attribute 'key' has sub-attribute 'key2'
3108 if (!mapAttributes.containsKey(attributeName))
3110 mapAttributes.put(attributeName, new HashMap<>());
3112 mapAttributes.get(attributeName).put(subAttribute,
3117 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3120 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3123 // adds feature to datasequence's feature set (since Jalview 2.10)
3124 alignmentSeq.addSequenceFeature(sf);
3127 if (vamsasSeq[i].getDBRefCount() > 0)
3129 // adds dbrefs to datasequence's set (since Jalview 2.10)
3131 alignmentSeq.getDatasetSequence() == null ? alignmentSeq
3132 : alignmentSeq.getDatasetSequence(),
3135 if (jseqs[i].getPdbidsCount() > 0)
3137 Pdbids[] ids = jseqs[i].getPdbids();
3138 for (int p = 0; p < ids.length; p++)
3140 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3141 entry.setId(ids[p].getId());
3142 if (ids[p].getType() != null)
3144 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3146 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3150 entry.setType(PDBEntry.Type.FILE);
3153 // jprovider is null when executing 'New View'
3154 if (ids[p].getFile() != null && jprovider != null)
3156 if (!pdbloaded.containsKey(ids[p].getFile()))
3158 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3163 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3166 if (ids[p].getPdbentryItem() != null)
3168 for (PdbentryItem item : ids[p].getPdbentryItem())
3170 for (Property pr : item.getProperty())
3172 entry.setProperty(pr.getName(), pr.getValue());
3176 StructureSelectionManager
3177 .getStructureSelectionManager(Desktop.instance)
3178 .registerPDBEntry(entry);
3179 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3180 if (alignmentSeq.getDatasetSequence() != null)
3182 alignmentSeq.getDatasetSequence().addPDBId(entry);
3186 alignmentSeq.addPDBId(entry);
3192 * load any HMMER profile
3194 String hmmJarFile = jseqs[i].getHmmerProfile();
3195 if (hmmJarFile != null && jprovider != null)
3197 loadHmmerProfile(jprovider, hmmJarFile, alignmentSeq);
3200 } // end !multipleview
3202 // ///////////////////////////////
3203 // LOAD SEQUENCE MAPPINGS
3205 if (vamsasSet.getAlcodonFrameCount() > 0)
3207 // TODO Potentially this should only be done once for all views of an
3209 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3210 for (int i = 0; i < alc.length; i++)
3212 AlignedCodonFrame cf = new AlignedCodonFrame();
3213 if (alc[i].getAlcodMapCount() > 0)
3215 AlcodMap[] maps = alc[i].getAlcodMap();
3216 for (int m = 0; m < maps.length; m++)
3218 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3220 jalview.datamodel.Mapping mapping = null;
3221 // attach to dna sequence reference.
3222 if (maps[m].getMapping() != null)
3224 mapping = addMapping(maps[m].getMapping());
3225 if (dnaseq != null && mapping.getTo() != null)
3227 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3233 newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3237 al.addCodonFrame(cf);
3242 // ////////////////////////////////
3244 List<JvAnnotRow> autoAlan = new ArrayList<>();
3247 * store any annotations which forward reference a group's ID
3249 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3251 if (vamsasSet.getAnnotationCount() > 0)
3253 Annotation[] an = vamsasSet.getAnnotation();
3255 for (int i = 0; i < an.length; i++)
3257 Annotation annotation = an[i];
3260 * test if annotation is automatically calculated for this view only
3262 boolean autoForView = false;
3263 if (annotation.getLabel().equals("Quality")
3264 || annotation.getLabel().equals("Conservation")
3265 || annotation.getLabel().equals("Consensus"))
3267 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3269 if (!annotation.hasAutoCalculated())
3271 annotation.setAutoCalculated(true);
3274 if (autoForView || (annotation.hasAutoCalculated()
3275 && annotation.isAutoCalculated()))
3277 // remove ID - we don't recover annotation from other views for
3278 // view-specific annotation
3279 annotation.setId(null);
3282 // set visiblity for other annotation in this view
3283 String annotationId = annotation.getId();
3284 if (annotationId != null && annotationIds.containsKey(annotationId))
3286 AlignmentAnnotation jda = annotationIds.get(annotationId);
3287 // in principle Visible should always be true for annotation displayed
3288 // in multiple views
3289 if (annotation.hasVisible())
3291 jda.visible = annotation.getVisible();
3294 al.addAnnotation(jda);
3298 // Construct new annotation from model.
3299 AnnotationElement[] ae = annotation.getAnnotationElement();
3300 jalview.datamodel.Annotation[] anot = null;
3301 java.awt.Color firstColour = null;
3303 if (!annotation.getScoreOnly())
3305 anot = new jalview.datamodel.Annotation[al.getWidth()];
3306 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3308 anpos = ae[aa].getPosition();
3310 if (anpos >= anot.length)
3315 anot[anpos] = new jalview.datamodel.Annotation(
3317 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3318 (ae[aa].getSecondaryStructure() == null
3319 || ae[aa].getSecondaryStructure().length() == 0)
3321 : ae[aa].getSecondaryStructure()
3326 // JBPNote: Consider verifying dataflow for IO of secondary
3327 // structure annotation read from Stockholm files
3328 // this was added to try to ensure that
3329 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3331 // anot[ae[aa].getPosition()].displayCharacter = "";
3333 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3334 if (firstColour == null)
3336 firstColour = anot[anpos].colour;
3340 jalview.datamodel.AlignmentAnnotation jaa = null;
3342 if (annotation.getGraph())
3344 float llim = 0, hlim = 0;
3345 // if (autoForView || an[i].isAutoCalculated()) {
3348 jaa = new jalview.datamodel.AlignmentAnnotation(
3349 annotation.getLabel(), annotation.getDescription(), anot,
3350 llim, hlim, annotation.getGraphType());
3352 jaa.graphGroup = annotation.getGraphGroup();
3353 jaa._linecolour = firstColour;
3354 if (annotation.getThresholdLine() != null)
3356 jaa.setThreshold(new jalview.datamodel.GraphLine(
3357 annotation.getThresholdLine().getValue(),
3358 annotation.getThresholdLine().getLabel(),
3360 annotation.getThresholdLine().getColour())));
3363 if (autoForView || annotation.isAutoCalculated())
3365 // Hardwire the symbol display line to ensure that labels for
3366 // histograms are displayed
3372 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3373 an[i].getDescription(), anot);
3374 jaa._linecolour = firstColour;
3376 // register new annotation
3377 if (an[i].getId() != null)
3379 annotationIds.put(an[i].getId(), jaa);
3380 jaa.annotationId = an[i].getId();
3382 // recover sequence association
3383 String sequenceRef = an[i].getSequenceRef();
3384 if (sequenceRef != null)
3386 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3387 SequenceI sequence = seqRefIds.get(sequenceRef);
3388 if (sequence == null)
3390 // in pre-2.9 projects sequence ref is to sequence name
3391 sequence = al.findName(sequenceRef);
3393 if (sequence != null)
3395 jaa.createSequenceMapping(sequence, 1, true);
3396 sequence.addAlignmentAnnotation(jaa);
3399 // and make a note of any group association
3400 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3402 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3403 .get(an[i].getGroupRef());
3406 aal = new ArrayList<>();
3407 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3412 if (an[i].hasScore())
3414 jaa.setScore(an[i].getScore());
3416 if (an[i].hasVisible())
3418 jaa.visible = an[i].getVisible();
3421 if (an[i].hasCentreColLabels())
3423 jaa.centreColLabels = an[i].getCentreColLabels();
3426 if (an[i].hasScaleColLabels())
3428 jaa.scaleColLabel = an[i].getScaleColLabels();
3430 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3432 // newer files have an 'autoCalculated' flag and store calculation
3433 // state in viewport properties
3434 jaa.autoCalculated = true; // means annotation will be marked for
3435 // update at end of load.
3437 if (an[i].hasGraphHeight())
3439 jaa.graphHeight = an[i].getGraphHeight();
3441 if (an[i].hasBelowAlignment())
3443 jaa.belowAlignment = an[i].isBelowAlignment();
3445 jaa.setCalcId(an[i].getCalcId());
3446 if (an[i].getPropertyCount() > 0)
3448 for (jalview.schemabinding.version2.Property prop : an[i]
3451 jaa.setProperty(prop.getName(), prop.getValue());
3454 if (jaa.autoCalculated)
3456 autoAlan.add(new JvAnnotRow(i, jaa));
3459 // if (!autoForView)
3461 // add autocalculated group annotation and any user created annotation
3463 al.addAnnotation(jaa);
3467 // ///////////////////////
3469 // Create alignment markup and styles for this view
3470 if (jms.getJGroupCount() > 0)
3472 JGroup[] groups = jms.getJGroup();
3473 boolean addAnnotSchemeGroup = false;
3474 for (int i = 0; i < groups.length; i++)
3476 JGroup jGroup = groups[i];
3477 ColourSchemeI cs = null;
3478 if (jGroup.getColour() != null)
3480 if (jGroup.getColour().startsWith("ucs"))
3482 cs = getUserColourScheme(jms, jGroup.getColour());
3484 else if (jGroup.getColour().equals("AnnotationColourGradient")
3485 && jGroup.getAnnotationColours() != null)
3487 addAnnotSchemeGroup = true;
3491 cs = ColourSchemeProperty.getColourScheme(al,
3492 jGroup.getColour());
3495 int pidThreshold = jGroup.getPidThreshold();
3497 Vector<SequenceI> seqs = new Vector<>();
3499 for (int s = 0; s < jGroup.getSeqCount(); s++)
3501 String seqId = jGroup.getSeq(s) + "";
3502 SequenceI ts = seqRefIds.get(seqId);
3506 seqs.addElement(ts);
3510 if (seqs.size() < 1)
3515 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3516 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3517 jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3518 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3519 sg.getGroupColourScheme()
3520 .setConservationInc(jGroup.getConsThreshold());
3521 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3523 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3524 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3525 sg.setShowNonconserved(
3526 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3528 sg.thresholdTextColour = jGroup.getTextColThreshold();
3529 if (jGroup.hasShowConsensusHistogram())
3531 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3534 if (jGroup.hasShowSequenceLogo())
3536 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3538 if (jGroup.hasNormaliseSequenceLogo())
3540 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3542 if (jGroup.hasIgnoreGapsinConsensus())
3544 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3546 if (jGroup.getConsThreshold() != 0)
3548 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3551 c.verdict(false, 25);
3552 sg.cs.setConservation(c);
3555 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3557 // re-instate unique group/annotation row reference
3558 List<AlignmentAnnotation> jaal = groupAnnotRefs
3559 .get(jGroup.getId());
3562 for (AlignmentAnnotation jaa : jaal)
3565 if (jaa.autoCalculated)
3567 // match up and try to set group autocalc alignment row for this
3569 if (jaa.label.startsWith("Consensus for "))
3571 sg.setConsensus(jaa);
3573 // match up and try to set group autocalc alignment row for this
3575 if (jaa.label.startsWith("Conservation for "))
3577 sg.setConservationRow(jaa);
3584 if (addAnnotSchemeGroup)
3586 // reconstruct the annotation colourscheme
3587 sg.setColourScheme(constructAnnotationColour(
3588 jGroup.getAnnotationColours(), null, al, jms, false));
3594 // only dataset in this model, so just return.
3597 // ///////////////////////////////
3600 // If we just load in the same jar file again, the sequenceSetId
3601 // will be the same, and we end up with multiple references
3602 // to the same sequenceSet. We must modify this id on load
3603 // so that each load of the file gives a unique id
3604 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3605 String viewId = (view.getId() == null ? null
3606 : view.getId() + uniqueSetSuffix);
3607 AlignFrame af = null;
3608 AlignViewport av = null;
3609 // now check to see if we really need to create a new viewport.
3610 if (multipleView && viewportsAdded.size() == 0)
3612 // We recovered an alignment for which a viewport already exists.
3613 // TODO: fix up any settings necessary for overlaying stored state onto
3614 // state recovered from another document. (may not be necessary).
3615 // we may need a binding from a viewport in memory to one recovered from
3617 // and then recover its containing af to allow the settings to be applied.
3618 // TODO: fix for vamsas demo
3620 "About to recover a viewport for existing alignment: Sequence set ID is "
3622 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3623 if (seqsetobj != null)
3625 if (seqsetobj instanceof String)
3627 uniqueSeqSetId = (String) seqsetobj;
3629 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3635 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3641 * indicate that annotation colours are applied across all groups (pre
3642 * Jalview 2.8.1 behaviour)
3644 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3645 object.getVersion());
3647 AlignmentPanel ap = null;
3648 boolean isnewview = true;
3651 // Check to see if this alignment already has a view id == viewId
3652 jalview.gui.AlignmentPanel views[] = Desktop
3653 .getAlignmentPanels(uniqueSeqSetId);
3654 if (views != null && views.length > 0)
3656 for (int v = 0; v < views.length; v++)
3658 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3660 // recover the existing alignpanel, alignframe, viewport
3661 af = views[v].alignFrame;
3664 // TODO: could even skip resetting view settings if we don't want to
3665 // change the local settings from other jalview processes
3674 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3675 uniqueSeqSetId, viewId, autoAlan);
3681 * Load any trees, PDB structures and viewers
3683 * Not done if flag is false (when this method is used for New View)
3685 if (loadTreesAndStructures)
3687 loadTrees(jms, view, af, av, ap);
3688 loadPDBStructures(jprovider, jseqs, af, ap);
3689 loadRnaViewers(jprovider, jseqs, ap);
3691 // and finally return.
3696 * Loads a HMMER profile from a file stored in the project, and associates it
3697 * with the specified sequence
3703 protected void loadHmmerProfile(jarInputStreamProvider jprovider,
3704 String hmmJarFile, SequenceI seq)
3708 String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
3709 HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
3710 HiddenMarkovModel hmmModel = parser.getHMM();
3711 hmmModel = new HiddenMarkovModel(hmmModel, seq);
3712 seq.setHMM(hmmModel);
3713 } catch (IOException e)
3715 warn("Error loading HMM profile for " + seq.getName() + ": "
3721 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3722 * panel is restored from separate jar entries, two (gapped and trimmed) per
3723 * sequence and secondary structure.
3725 * Currently each viewer shows just one sequence and structure (gapped and
3726 * trimmed), however this method is designed to support multiple sequences or
3727 * structures in viewers if wanted in future.
3733 private void loadRnaViewers(jarInputStreamProvider jprovider,
3734 JSeq[] jseqs, AlignmentPanel ap)
3737 * scan the sequences for references to viewers; create each one the first
3738 * time it is referenced, add Rna models to existing viewers
3740 for (JSeq jseq : jseqs)
3742 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3744 RnaViewer viewer = jseq.getRnaViewer(i);
3745 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3748 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3750 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3751 SequenceI seq = seqRefIds.get(jseq.getId());
3752 AlignmentAnnotation ann = this.annotationIds
3753 .get(ss.getAnnotationId());
3756 * add the structure to the Varna display (with session state copied
3757 * from the jar to a temporary file)
3759 boolean gapped = ss.isGapped();
3760 String rnaTitle = ss.getTitle();
3761 String sessionState = ss.getViewerState();
3762 String tempStateFile = copyJarEntry(jprovider, sessionState,
3764 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3765 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3767 appVarna.setInitialSelection(viewer.getSelectedRna());
3773 * Locate and return an already instantiated matching AppVarna, or create one
3777 * @param viewIdSuffix
3781 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3782 String viewIdSuffix, AlignmentPanel ap)
3785 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3786 * if load is repeated
3788 String postLoadId = viewer.getViewId() + viewIdSuffix;
3789 for (JInternalFrame frame : getAllFrames())
3791 if (frame instanceof AppVarna)
3793 AppVarna varna = (AppVarna) frame;
3794 if (postLoadId.equals(varna.getViewId()))
3796 // this viewer is already instantiated
3797 // could in future here add ap as another 'parent' of the
3798 // AppVarna window; currently just 1-to-many
3805 * viewer not found - make it
3807 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3808 viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3809 viewer.getHeight(), viewer.getDividerLocation());
3810 AppVarna varna = new AppVarna(model, ap);
3816 * Load any saved trees
3824 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3825 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3827 // TODO result of automated refactoring - are all these parameters needed?
3830 for (int t = 0; t < jms.getTreeCount(); t++)
3833 Tree tree = jms.getTree(t);
3835 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3838 tp = af.showNewickTree(
3839 new jalview.io.NewickFile(tree.getNewick()),
3840 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3841 tree.getXpos(), tree.getYpos());
3842 if (tree.getId() != null)
3844 // perhaps bind the tree id to something ?
3849 // update local tree attributes ?
3850 // TODO: should check if tp has been manipulated by user - if so its
3851 // settings shouldn't be modified
3852 tp.setTitle(tree.getTitle());
3853 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3854 tree.getWidth(), tree.getHeight()));
3855 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3858 tp.treeCanvas.av = av; // af.viewport;
3859 tp.treeCanvas.ap = ap; // af.alignPanel;
3864 warn("There was a problem recovering stored Newick tree: \n"
3865 + tree.getNewick());
3869 tp.fitToWindow.setState(tree.getFitToWindow());
3870 tp.fitToWindow_actionPerformed(null);
3872 if (tree.getFontName() != null)
3874 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3875 tree.getFontStyle(), tree.getFontSize()));
3879 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3880 view.getFontStyle(), tree.getFontSize()));
3883 tp.showPlaceholders(tree.getMarkUnlinked());
3884 tp.showBootstrap(tree.getShowBootstrap());
3885 tp.showDistances(tree.getShowDistances());
3887 tp.treeCanvas.threshold = tree.getThreshold();
3889 if (tree.getCurrentTree())
3891 af.viewport.setCurrentTree(tp.getTree());
3895 } catch (Exception ex)
3897 ex.printStackTrace();
3902 * Load and link any saved structure viewers.
3909 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3910 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3913 * Run through all PDB ids on the alignment, and collect mappings between
3914 * distinct view ids and all sequences referring to that view.
3916 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3918 for (int i = 0; i < jseqs.length; i++)
3920 if (jseqs[i].getPdbidsCount() > 0)
3922 Pdbids[] ids = jseqs[i].getPdbids();
3923 for (int p = 0; p < ids.length; p++)
3925 final int structureStateCount = ids[p].getStructureStateCount();
3926 for (int s = 0; s < structureStateCount; s++)
3928 // check to see if we haven't already created this structure view
3929 final StructureState structureState = ids[p]
3930 .getStructureState(s);
3931 String sviewid = (structureState.getViewId() == null) ? null
3932 : structureState.getViewId() + uniqueSetSuffix;
3933 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3934 // Originally : ids[p].getFile()
3935 // : TODO: verify external PDB file recovery still works in normal
3936 // jalview project load
3937 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3939 jpdb.setId(ids[p].getId());
3941 int x = structureState.getXpos();
3942 int y = structureState.getYpos();
3943 int width = structureState.getWidth();
3944 int height = structureState.getHeight();
3946 // Probably don't need to do this anymore...
3947 // Desktop.desktop.getComponentAt(x, y);
3948 // TODO: NOW: check that this recovers the PDB file correctly.
3949 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3951 jalview.datamodel.SequenceI seq = seqRefIds
3952 .get(jseqs[i].getId() + "");
3953 if (sviewid == null)
3955 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3958 if (!structureViewers.containsKey(sviewid))
3960 structureViewers.put(sviewid,
3961 new StructureViewerModel(x, y, width, height, false,
3962 false, true, structureState.getViewId(),
3963 structureState.getType()));
3964 // Legacy pre-2.7 conversion JAL-823 :
3965 // do not assume any view has to be linked for colour by
3969 // assemble String[] { pdb files }, String[] { id for each
3970 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3971 // seqs_file 2}, boolean[] {
3972 // linkAlignPanel,superposeWithAlignpanel}} from hash
3973 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3974 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3975 | (structureState.hasAlignwithAlignPanel()
3976 ? structureState.getAlignwithAlignPanel()
3980 * Default colour by linked panel to false if not specified (e.g.
3981 * for pre-2.7 projects)
3983 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3984 colourWithAlignPanel |= (structureState
3985 .hasColourwithAlignPanel()
3986 ? structureState.getColourwithAlignPanel()
3988 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3991 * Default colour by viewer to true if not specified (e.g. for
3994 boolean colourByViewer = jmoldat.isColourByViewer();
3995 colourByViewer &= structureState.hasColourByJmol()
3996 ? structureState.getColourByJmol()
3998 jmoldat.setColourByViewer(colourByViewer);
4000 if (jmoldat.getStateData().length() < structureState
4001 .getContent().length())
4004 jmoldat.setStateData(structureState.getContent());
4007 if (ids[p].getFile() != null)
4009 File mapkey = new File(ids[p].getFile());
4010 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4011 if (seqstrmaps == null)
4013 jmoldat.getFileData().put(mapkey,
4014 seqstrmaps = jmoldat.new StructureData(pdbFile,
4017 if (!seqstrmaps.getSeqList().contains(seq))
4019 seqstrmaps.getSeqList().add(seq);
4025 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");
4032 // Instantiate the associated structure views
4033 for (Entry<String, StructureViewerModel> entry : structureViewers
4038 createOrLinkStructureViewer(entry, af, ap, jprovider);
4039 } catch (Exception e)
4042 "Error loading structure viewer: " + e.getMessage());
4043 // failed - try the next one
4055 protected void createOrLinkStructureViewer(
4056 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4057 AlignmentPanel ap, jarInputStreamProvider jprovider)
4059 final StructureViewerModel stateData = viewerData.getValue();
4062 * Search for any viewer windows already open from other alignment views
4063 * that exactly match the stored structure state
4065 StructureViewerBase comp = findMatchingViewer(viewerData);
4069 linkStructureViewer(ap, comp, stateData);
4074 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4075 * "viewer_"+stateData.viewId
4077 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4079 createChimeraViewer(viewerData, af, jprovider);
4084 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4086 createJmolViewer(viewerData, af, jprovider);
4091 * Create a new Chimera viewer.
4097 protected void createChimeraViewer(
4098 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4099 jarInputStreamProvider jprovider)
4101 StructureViewerModel data = viewerData.getValue();
4102 String chimeraSessionFile = data.getStateData();
4105 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4107 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4108 * 'uniquified' sviewid used to reconstruct the viewer here
4110 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4111 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4114 Set<Entry<File, StructureData>> fileData = data.getFileData()
4116 List<PDBEntry> pdbs = new ArrayList<>();
4117 List<SequenceI[]> allseqs = new ArrayList<>();
4118 for (Entry<File, StructureData> pdb : fileData)
4120 String filePath = pdb.getValue().getFilePath();
4121 String pdbId = pdb.getValue().getPdbId();
4122 // pdbs.add(new PDBEntry(filePath, pdbId));
4123 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4124 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4125 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4129 boolean colourByChimera = data.isColourByViewer();
4130 boolean colourBySequence = data.isColourWithAlignPanel();
4132 // TODO use StructureViewer as a factory here, see JAL-1761
4133 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4134 final SequenceI[][] seqsArray = allseqs
4135 .toArray(new SequenceI[allseqs.size()][]);
4136 String newViewId = viewerData.getKey();
4138 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4139 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4140 colourBySequence, newViewId);
4141 cvf.setSize(data.getWidth(), data.getHeight());
4142 cvf.setLocation(data.getX(), data.getY());
4146 * Create a new Jmol window. First parse the Jmol state to translate filenames
4147 * loaded into the view, and record the order in which files are shown in the
4148 * Jmol view, so we can add the sequence mappings in same order.
4154 protected void createJmolViewer(
4155 final Entry<String, StructureViewerModel> viewerData,
4156 AlignFrame af, jarInputStreamProvider jprovider)
4158 final StructureViewerModel svattrib = viewerData.getValue();
4159 String state = svattrib.getStateData();
4162 * Pre-2.9: state element value is the Jmol state string
4164 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4167 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4169 state = readJarEntry(jprovider,
4170 getViewerJarEntryName(svattrib.getViewId()));
4173 List<String> pdbfilenames = new ArrayList<>();
4174 List<SequenceI[]> seqmaps = new ArrayList<>();
4175 List<String> pdbids = new ArrayList<>();
4176 StringBuilder newFileLoc = new StringBuilder(64);
4177 int cp = 0, ncp, ecp;
4178 Map<File, StructureData> oldFiles = svattrib.getFileData();
4179 while ((ncp = state.indexOf("load ", cp)) > -1)
4183 // look for next filename in load statement
4184 newFileLoc.append(state.substring(cp,
4185 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4186 String oldfilenam = state.substring(ncp,
4187 ecp = state.indexOf("\"", ncp));
4188 // recover the new mapping data for this old filename
4189 // have to normalize filename - since Jmol and jalview do
4191 // translation differently.
4192 StructureData filedat = oldFiles.get(new File(oldfilenam));
4193 if (filedat == null)
4195 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4196 filedat = oldFiles.get(new File(reformatedOldFilename));
4198 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4199 pdbfilenames.add(filedat.getFilePath());
4200 pdbids.add(filedat.getPdbId());
4201 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4202 newFileLoc.append("\"");
4203 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4204 // look for next file statement.
4205 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4209 // just append rest of state
4210 newFileLoc.append(state.substring(cp));
4214 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4215 newFileLoc = new StringBuilder(state);
4216 newFileLoc.append("; load append ");
4217 for (File id : oldFiles.keySet())
4219 // add this and any other pdb files that should be present in
4221 StructureData filedat = oldFiles.get(id);
4222 newFileLoc.append(filedat.getFilePath());
4223 pdbfilenames.add(filedat.getFilePath());
4224 pdbids.add(filedat.getPdbId());
4225 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4226 newFileLoc.append(" \"");
4227 newFileLoc.append(filedat.getFilePath());
4228 newFileLoc.append("\"");
4231 newFileLoc.append(";");
4234 if (newFileLoc.length() == 0)
4238 int histbug = newFileLoc.indexOf("history = ");
4242 * change "history = [true|false];" to "history = [1|0];"
4245 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4246 String val = (diff == -1) ? null
4247 : newFileLoc.substring(histbug, diff);
4248 if (val != null && val.length() >= 4)
4250 if (val.contains("e")) // eh? what can it be?
4252 if (val.trim().equals("true"))
4260 newFileLoc.replace(histbug, diff, val);
4265 final String[] pdbf = pdbfilenames
4266 .toArray(new String[pdbfilenames.size()]);
4267 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4268 final SequenceI[][] sq = seqmaps
4269 .toArray(new SequenceI[seqmaps.size()][]);
4270 final String fileloc = newFileLoc.toString();
4271 final String sviewid = viewerData.getKey();
4272 final AlignFrame alf = af;
4273 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4274 svattrib.getWidth(), svattrib.getHeight());
4277 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4282 JalviewStructureDisplayI sview = null;
4285 sview = new StructureViewer(
4286 alf.alignPanel.getStructureSelectionManager())
4287 .createView(StructureViewer.ViewerType.JMOL,
4288 pdbf, id, sq, alf.alignPanel, svattrib,
4289 fileloc, rect, sviewid);
4290 addNewStructureViewer(sview);
4291 } catch (OutOfMemoryError ex)
4293 new OOMWarning("restoring structure view for PDB id " + id,
4294 (OutOfMemoryError) ex.getCause());
4295 if (sview != null && sview.isVisible())
4297 sview.closeViewer(false);
4298 sview.setVisible(false);
4304 } catch (InvocationTargetException ex)
4306 warn("Unexpected error when opening Jmol view.", ex);
4308 } catch (InterruptedException e)
4310 // e.printStackTrace();
4316 * Generates a name for the entry in the project jar file to hold state
4317 * information for a structure viewer
4322 protected String getViewerJarEntryName(String viewId)
4324 return VIEWER_PREFIX + viewId;
4328 * Returns any open frame that matches given structure viewer data. The match
4329 * is based on the unique viewId, or (for older project versions) the frame's
4335 protected StructureViewerBase findMatchingViewer(
4336 Entry<String, StructureViewerModel> viewerData)
4338 final String sviewid = viewerData.getKey();
4339 final StructureViewerModel svattrib = viewerData.getValue();
4340 StructureViewerBase comp = null;
4341 JInternalFrame[] frames = getAllFrames();
4342 for (JInternalFrame frame : frames)
4344 if (frame instanceof StructureViewerBase)
4347 * Post jalview 2.4 schema includes structure view id
4349 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4352 comp = (StructureViewerBase) frame;
4353 break; // break added in 2.9
4356 * Otherwise test for matching position and size of viewer frame
4358 else if (frame.getX() == svattrib.getX()
4359 && frame.getY() == svattrib.getY()
4360 && frame.getHeight() == svattrib.getHeight()
4361 && frame.getWidth() == svattrib.getWidth())
4363 comp = (StructureViewerBase) frame;
4364 // no break in faint hope of an exact match on viewId
4372 * Link an AlignmentPanel to an existing structure viewer.
4377 * @param useinViewerSuperpos
4378 * @param usetoColourbyseq
4379 * @param viewerColouring
4381 protected void linkStructureViewer(AlignmentPanel ap,
4382 StructureViewerBase viewer, StructureViewerModel stateData)
4384 // NOTE: if the jalview project is part of a shared session then
4385 // view synchronization should/could be done here.
4387 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4388 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4389 final boolean viewerColouring = stateData.isColourByViewer();
4390 Map<File, StructureData> oldFiles = stateData.getFileData();
4393 * Add mapping for sequences in this view to an already open viewer
4395 final AAStructureBindingModel binding = viewer.getBinding();
4396 for (File id : oldFiles.keySet())
4398 // add this and any other pdb files that should be present in the
4400 StructureData filedat = oldFiles.get(id);
4401 String pdbFile = filedat.getFilePath();
4402 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4403 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4405 binding.addSequenceForStructFile(pdbFile, seq);
4407 // and add the AlignmentPanel's reference to the view panel
4408 viewer.addAlignmentPanel(ap);
4409 if (useinViewerSuperpos)
4411 viewer.useAlignmentPanelForSuperposition(ap);
4415 viewer.excludeAlignmentPanelForSuperposition(ap);
4417 if (usetoColourbyseq)
4419 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4423 viewer.excludeAlignmentPanelForColourbyseq(ap);
4428 * Get all frames within the Desktop.
4432 protected JInternalFrame[] getAllFrames()
4434 JInternalFrame[] frames = null;
4435 // TODO is this necessary - is it safe - risk of hanging?
4440 frames = Desktop.desktop.getAllFrames();
4441 } catch (ArrayIndexOutOfBoundsException e)
4443 // occasional No such child exceptions are thrown here...
4447 } catch (InterruptedException f)
4451 } while (frames == null);
4456 * Answers true if 'version' is equal to or later than 'supported', where each
4457 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4458 * changes. Development and test values for 'version' are leniently treated
4462 * - minimum version we are comparing against
4464 * - version of data being processsed
4467 public static boolean isVersionStringLaterThan(String supported,
4470 if (supported == null || version == null
4471 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4472 || version.equalsIgnoreCase("Test")
4473 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4475 System.err.println("Assuming project file with "
4476 + (version == null ? "null" : version)
4477 + " is compatible with Jalview version " + supported);
4482 return StringUtils.compareVersions(version, supported, "b") >= 0;
4486 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4488 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4490 if (newStructureViewers != null)
4492 sview.getBinding().setFinishedLoadingFromArchive(false);
4493 newStructureViewers.add(sview);
4497 protected void setLoadingFinishedForNewStructureViewers()
4499 if (newStructureViewers != null)
4501 for (JalviewStructureDisplayI sview : newStructureViewers)
4503 sview.getBinding().setFinishedLoadingFromArchive(true);
4505 newStructureViewers.clear();
4506 newStructureViewers = null;
4510 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4511 List<SequenceI> hiddenSeqs, AlignmentI al,
4512 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4513 String viewId, List<JvAnnotRow> autoAlan)
4515 AlignFrame af = null;
4516 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4517 uniqueSeqSetId, viewId);
4519 af.setFileName(file, FileFormat.Jalview);
4521 for (int i = 0; i < JSEQ.length; i++)
4523 af.viewport.setSequenceColour(
4524 af.viewport.getAlignment().getSequenceAt(i),
4525 new java.awt.Color(JSEQ[i].getColour()));
4530 af.getViewport().setColourByReferenceSeq(true);
4531 af.getViewport().setDisplayReferenceSeq(true);
4534 af.viewport.setGatherViewsHere(view.getGatheredViews());
4536 if (view.getSequenceSetId() != null)
4538 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4540 af.viewport.setSequenceSetId(uniqueSeqSetId);
4543 // propagate shared settings to this new view
4544 af.viewport.setHistoryList(av.getHistoryList());
4545 af.viewport.setRedoList(av.getRedoList());
4549 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4551 // TODO: check if this method can be called repeatedly without
4552 // side-effects if alignpanel already registered.
4553 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4555 // apply Hidden regions to view.
4556 if (hiddenSeqs != null)
4558 for (int s = 0; s < JSEQ.length; s++)
4560 SequenceGroup hidden = new SequenceGroup();
4561 boolean isRepresentative = false;
4562 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4564 isRepresentative = true;
4565 SequenceI sequenceToHide = al
4566 .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4567 hidden.addSequence(sequenceToHide, false);
4568 // remove from hiddenSeqs list so we don't try to hide it twice
4569 hiddenSeqs.remove(sequenceToHide);
4571 if (isRepresentative)
4573 SequenceI representativeSequence = al.getSequenceAt(s);
4574 hidden.addSequence(representativeSequence, false);
4575 af.viewport.hideRepSequences(representativeSequence, hidden);
4579 SequenceI[] hseqs = hiddenSeqs
4580 .toArray(new SequenceI[hiddenSeqs.size()]);
4581 af.viewport.hideSequence(hseqs);
4584 // recover view properties and display parameters
4586 af.viewport.setShowAnnotation(view.getShowAnnotation());
4587 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4588 af.viewport.setThreshold(view.getPidThreshold());
4590 af.viewport.setColourText(view.getShowColourText());
4592 af.viewport.setConservationSelected(view.getConservationSelected());
4593 af.viewport.setIncrement(view.getConsThreshold());
4594 af.viewport.setShowJVSuffix(view.getShowFullId());
4595 af.viewport.setRightAlignIds(view.getRightAlignIds());
4596 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4597 view.getFontStyle(), view.getFontSize()), true);
4598 ViewStyleI vs = af.viewport.getViewStyle();
4599 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4600 af.viewport.setViewStyle(vs);
4601 // TODO: allow custom charWidth/Heights to be restored by updating them
4602 // after setting font - which means set above to false
4603 af.viewport.setRenderGaps(view.getRenderGaps());
4604 af.viewport.setWrapAlignment(view.getWrapAlignment());
4605 af.viewport.setShowAnnotation(view.getShowAnnotation());
4607 af.viewport.setShowBoxes(view.getShowBoxes());
4609 af.viewport.setShowText(view.getShowText());
4611 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4612 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4613 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4614 af.viewport.setShowUnconserved(
4615 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4616 af.viewport.getRanges().setStartRes(view.getStartRes());
4618 if (view.getViewName() != null)
4620 af.viewport.viewName = view.getViewName();
4621 af.setInitialTabVisible();
4623 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4625 // startSeq set in af.alignPanel.updateLayout below
4626 af.alignPanel.updateLayout();
4627 ColourSchemeI cs = null;
4628 // apply colourschemes
4629 if (view.getBgColour() != null)
4631 if (view.getBgColour().startsWith("ucs"))
4633 cs = getUserColourScheme(jms, view.getBgColour());
4635 else if (view.getBgColour().startsWith("Annotation"))
4637 AnnotationColours viewAnnColour = view.getAnnotationColours();
4638 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4645 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4649 af.viewport.setGlobalColourScheme(cs);
4650 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4651 view.getIgnoreGapsinConsensus());
4652 af.viewport.getResidueShading()
4653 .setConsensus(af.viewport.getConsensusProfiles());
4654 af.viewport.setColourAppliesToAllGroups(false);
4656 if (view.getConservationSelected() && cs != null)
4658 af.viewport.getResidueShading()
4659 .setConservationInc(view.getConsThreshold());
4662 af.changeColour(cs);
4664 af.viewport.setColourAppliesToAllGroups(true);
4666 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4668 if (view.hasCentreColumnLabels())
4670 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4672 if (view.hasIgnoreGapsinConsensus())
4674 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4677 if (view.hasFollowHighlight())
4679 af.viewport.setFollowHighlight(view.getFollowHighlight());
4681 if (view.hasFollowSelection())
4683 af.viewport.followSelection = view.getFollowSelection();
4685 if (view.hasShowConsensusHistogram())
4688 .setShowConsensusHistogram(view.getShowConsensusHistogram());
4692 af.viewport.setShowConsensusHistogram(true);
4694 if (view.hasShowSequenceLogo())
4696 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4700 af.viewport.setShowSequenceLogo(false);
4702 if (view.hasNormaliseSequenceLogo())
4704 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4706 if (view.hasShowDbRefTooltip())
4708 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4710 if (view.hasShowNPfeatureTooltip())
4712 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4714 if (view.hasShowGroupConsensus())
4716 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4720 af.viewport.setShowGroupConsensus(false);
4722 if (view.hasShowGroupConservation())
4724 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4728 af.viewport.setShowGroupConservation(false);
4731 // recover feature settings
4732 if (jms.getFeatureSettings() != null)
4734 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4735 .getFeatureRenderer();
4736 FeaturesDisplayed fdi;
4737 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4738 String[] renderOrder = new String[jms.getFeatureSettings()
4739 .getSettingCount()];
4740 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4741 Map<String, Float> featureOrder = new Hashtable<>();
4743 for (int fs = 0; fs < jms.getFeatureSettings()
4744 .getSettingCount(); fs++)
4746 Setting setting = jms.getFeatureSettings().getSetting(fs);
4747 String featureType = setting.getType();
4750 * restore feature filters (if any)
4752 MatcherSet filters = setting.getMatcherSet();
4753 if (filters != null)
4755 FeatureMatcherSetI filter = Jalview2XML
4756 .unmarshalFilter(featureType, filters);
4757 if (!filter.isEmpty())
4759 fr.setFeatureFilter(featureType, filter);
4764 * restore feature colour scheme
4766 Color maxColour = new Color(setting.getColour());
4767 if (setting.hasMincolour())
4770 * minColour is always set unless a simple colour
4771 * (including for colour by label though it doesn't use it)
4773 Color minColour = new Color(setting.getMincolour());
4774 Color noValueColour = minColour;
4775 NoValueColour noColour = setting.getNoValueColour();
4776 if (noColour == NoValueColour.NONE)
4778 noValueColour = null;
4780 else if (noColour == NoValueColour.MAX)
4782 noValueColour = maxColour;
4784 float min = setting.hasMin() ? setting.getMin() : 0f;
4785 float max = setting.hasMin() ? setting.getMax() : 1f;
4786 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4787 noValueColour, min, max);
4788 if (setting.getAttributeNameCount() > 0)
4790 gc.setAttributeName(setting.getAttributeName());
4792 if (setting.hasThreshold())
4794 gc.setThreshold(setting.getThreshold());
4795 int threshstate = setting.getThreshstate();
4796 // -1 = None, 0 = Below, 1 = Above threshold
4797 if (threshstate == 0)
4799 gc.setBelowThreshold(true);
4801 else if (threshstate == 1)
4803 gc.setAboveThreshold(true);
4806 gc.setAutoScaled(true); // default
4807 if (setting.hasAutoScale())
4809 gc.setAutoScaled(setting.getAutoScale());
4811 if (setting.hasColourByLabel())
4813 gc.setColourByLabel(setting.getColourByLabel());
4815 // and put in the feature colour table.
4816 featureColours.put(featureType, gc);
4820 featureColours.put(featureType,
4821 new FeatureColour(maxColour));
4823 renderOrder[fs] = featureType;
4824 if (setting.hasOrder())
4826 featureOrder.put(featureType, setting.getOrder());
4830 featureOrder.put(featureType, new Float(
4831 fs / jms.getFeatureSettings().getSettingCount()));
4833 if (setting.getDisplay())
4835 fdi.setVisible(featureType);
4838 Map<String, Boolean> fgtable = new Hashtable<>();
4839 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4841 Group grp = jms.getFeatureSettings().getGroup(gs);
4842 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4844 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4845 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4846 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4847 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4848 fgtable, featureColours, 1.0f, featureOrder);
4849 fr.transferSettings(frs);
4852 if (view.getHiddenColumnsCount() > 0)
4854 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4856 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4857 view.getHiddenColumns(c).getEnd() // +1
4861 if (view.getCalcIdParam() != null)
4863 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4865 if (calcIdParam != null)
4867 if (recoverCalcIdParam(calcIdParam, af.viewport))
4872 warn("Couldn't recover parameters for "
4873 + calcIdParam.getCalcId());
4878 af.setMenusFromViewport(af.viewport);
4879 af.setTitle(view.getTitle());
4880 // TODO: we don't need to do this if the viewport is aready visible.
4882 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4883 * has a 'cdna/protein complement' view, in which case save it in order to
4884 * populate a SplitFrame once all views have been read in.
4886 String complementaryViewId = view.getComplementId();
4887 if (complementaryViewId == null)
4889 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4891 // recompute any autoannotation
4892 af.alignPanel.updateAnnotation(false, true);
4893 reorderAutoannotation(af, al, autoAlan);
4894 af.alignPanel.alignmentChanged();
4898 splitFrameCandidates.put(view, af);
4904 * Reads saved data to restore Colour by Annotation settings
4906 * @param viewAnnColour
4910 * @param checkGroupAnnColour
4913 private ColourSchemeI constructAnnotationColour(
4914 AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4915 JalviewModelSequence jms, boolean checkGroupAnnColour)
4917 boolean propagateAnnColour = false;
4918 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4919 if (checkGroupAnnColour && al.getGroups() != null
4920 && al.getGroups().size() > 0)
4922 // pre 2.8.1 behaviour
4923 // check to see if we should transfer annotation colours
4924 propagateAnnColour = true;
4925 for (SequenceGroup sg : al.getGroups())
4927 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4929 propagateAnnColour = false;
4935 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4937 String annotationId = viewAnnColour.getAnnotation();
4938 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4941 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4943 if (matchedAnnotation == null
4944 && annAlignment.getAlignmentAnnotation() != null)
4946 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4949 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4951 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4956 if (matchedAnnotation == null)
4958 System.err.println("Failed to match annotation colour scheme for "
4962 if (matchedAnnotation.getThreshold() == null)
4964 matchedAnnotation.setThreshold(new GraphLine(
4965 viewAnnColour.getThreshold(), "Threshold", Color.black));
4968 AnnotationColourGradient cs = null;
4969 if (viewAnnColour.getColourScheme().equals("None"))
4971 cs = new AnnotationColourGradient(matchedAnnotation,
4972 new Color(viewAnnColour.getMinColour()),
4973 new Color(viewAnnColour.getMaxColour()),
4974 viewAnnColour.getAboveThreshold());
4976 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4978 cs = new AnnotationColourGradient(matchedAnnotation,
4979 getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4980 viewAnnColour.getAboveThreshold());
4984 cs = new AnnotationColourGradient(matchedAnnotation,
4985 ColourSchemeProperty.getColourScheme(al,
4986 viewAnnColour.getColourScheme()),
4987 viewAnnColour.getAboveThreshold());
4990 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4991 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4992 cs.setSeqAssociated(perSequenceOnly);
4993 cs.setPredefinedColours(useOriginalColours);
4995 if (propagateAnnColour && al.getGroups() != null)
4997 // Also use these settings for all the groups
4998 for (int g = 0; g < al.getGroups().size(); g++)
5000 SequenceGroup sg = al.getGroups().get(g);
5001 if (sg.getGroupColourScheme() == null)
5006 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5007 matchedAnnotation, sg.getColourScheme(),
5008 viewAnnColour.getAboveThreshold());
5009 sg.setColourScheme(groupScheme);
5010 groupScheme.setSeqAssociated(perSequenceOnly);
5011 groupScheme.setPredefinedColours(useOriginalColours);
5017 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5018 List<JvAnnotRow> autoAlan)
5020 // copy over visualization settings for autocalculated annotation in the
5022 if (al.getAlignmentAnnotation() != null)
5025 * Kludge for magic autoannotation names (see JAL-811)
5027 String[] magicNames = new String[] { "Consensus", "Quality",
5029 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5030 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5031 for (String nm : magicNames)
5033 visan.put(nm, nullAnnot);
5035 for (JvAnnotRow auan : autoAlan)
5037 visan.put(auan.template.label
5038 + (auan.template.getCalcId() == null ? ""
5039 : "\t" + auan.template.getCalcId()),
5042 int hSize = al.getAlignmentAnnotation().length;
5043 List<JvAnnotRow> reorder = new ArrayList<>();
5044 // work through any autoCalculated annotation already on the view
5045 // removing it if it should be placed in a different location on the
5046 // annotation panel.
5047 List<String> remains = new ArrayList<>(visan.keySet());
5048 for (int h = 0; h < hSize; h++)
5050 jalview.datamodel.AlignmentAnnotation jalan = al
5051 .getAlignmentAnnotation()[h];
5052 if (jalan.autoCalculated)
5055 JvAnnotRow valan = visan.get(k = jalan.label);
5056 if (jalan.getCalcId() != null)
5058 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5063 // delete the auto calculated row from the alignment
5064 al.deleteAnnotation(jalan, false);
5068 if (valan != nullAnnot)
5070 if (jalan != valan.template)
5072 // newly created autoannotation row instance
5073 // so keep a reference to the visible annotation row
5074 // and copy over all relevant attributes
5075 if (valan.template.graphHeight >= 0)
5078 jalan.graphHeight = valan.template.graphHeight;
5080 jalan.visible = valan.template.visible;
5082 reorder.add(new JvAnnotRow(valan.order, jalan));
5087 // Add any (possibly stale) autocalculated rows that were not appended to
5088 // the view during construction
5089 for (String other : remains)
5091 JvAnnotRow othera = visan.get(other);
5092 if (othera != nullAnnot && othera.template.getCalcId() != null
5093 && othera.template.getCalcId().length() > 0)
5095 reorder.add(othera);
5098 // now put the automatic annotation in its correct place
5099 int s = 0, srt[] = new int[reorder.size()];
5100 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5101 for (JvAnnotRow jvar : reorder)
5104 srt[s++] = jvar.order;
5107 jalview.util.QuickSort.sort(srt, rws);
5108 // and re-insert the annotation at its correct position
5109 for (JvAnnotRow jvar : rws)
5111 al.addAnnotation(jvar.template, jvar.order);
5113 af.alignPanel.adjustAnnotationHeight();
5117 Hashtable skipList = null;
5120 * TODO remove this method
5123 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5124 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5125 * throw new Error("Implementation Error. No skipList defined for this
5126 * Jalview2XML instance."); } return (AlignFrame)
5127 * skipList.get(view.getSequenceSetId()); }
5131 * Check if the Jalview view contained in object should be skipped or not.
5134 * @return true if view's sequenceSetId is a key in skipList
5136 private boolean skipViewport(JalviewModel object)
5138 if (skipList == null)
5143 if (skipList.containsKey(
5144 id = object.getJalviewModelSequence().getViewport()[0]
5145 .getSequenceSetId()))
5147 debug("Skipping sequence set id " + id);
5153 public void addToSkipList(AlignFrame af)
5155 if (skipList == null)
5157 skipList = new Hashtable();
5159 skipList.put(af.getViewport().getSequenceSetId(), af);
5162 public void clearSkipList()
5164 if (skipList != null)
5171 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5172 boolean ignoreUnrefed)
5174 jalview.datamodel.AlignmentI ds = getDatasetFor(
5175 vamsasSet.getDatasetId());
5176 Vector dseqs = null;
5179 // create a list of new dataset sequences
5180 dseqs = new Vector();
5182 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5184 Sequence vamsasSeq = vamsasSet.getSequence(i);
5185 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5187 // create a new dataset
5190 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5191 dseqs.copyInto(dsseqs);
5192 ds = new jalview.datamodel.Alignment(dsseqs);
5193 debug("Created new dataset " + vamsasSet.getDatasetId()
5194 + " for alignment " + System.identityHashCode(al));
5195 addDatasetRef(vamsasSet.getDatasetId(), ds);
5197 // set the dataset for the newly imported alignment.
5198 if (al.getDataset() == null && !ignoreUnrefed)
5207 * sequence definition to create/merge dataset sequence for
5211 * vector to add new dataset sequence to
5212 * @param ignoreUnrefed
5213 * - when true, don't create new sequences from vamsasSeq if it's id
5214 * doesn't already have an asssociated Jalview sequence.
5216 * - used to reorder the sequence in the alignment according to the
5217 * vamsasSeq array ordering, to preserve ordering of dataset
5219 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5220 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5222 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5224 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5225 boolean reorder = false;
5226 SequenceI dsq = null;
5227 if (sq != null && sq.getDatasetSequence() != null)
5229 dsq = sq.getDatasetSequence();
5235 if (sq == null && ignoreUnrefed)
5239 String sqid = vamsasSeq.getDsseqid();
5242 // need to create or add a new dataset sequence reference to this sequence
5245 dsq = seqRefIds.get(sqid);
5250 // make a new dataset sequence
5251 dsq = sq.createDatasetSequence();
5254 // make up a new dataset reference for this sequence
5255 sqid = seqHash(dsq);
5257 dsq.setVamsasId(uniqueSetSuffix + sqid);
5258 seqRefIds.put(sqid, dsq);
5263 dseqs.addElement(dsq);
5268 ds.addSequence(dsq);
5274 { // make this dataset sequence sq's dataset sequence
5275 sq.setDatasetSequence(dsq);
5276 // and update the current dataset alignment
5281 if (!dseqs.contains(dsq))
5288 if (ds.findIndex(dsq) < 0)
5290 ds.addSequence(dsq);
5297 // TODO: refactor this as a merge dataset sequence function
5298 // now check that sq (the dataset sequence) sequence really is the union of
5299 // all references to it
5300 // boolean pre = sq.getStart() < dsq.getStart();
5301 // boolean post = sq.getEnd() > dsq.getEnd();
5305 // StringBuffer sb = new StringBuffer();
5306 String newres = jalview.analysis.AlignSeq.extractGaps(
5307 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5308 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5309 && newres.length() > dsq.getLength())
5311 // Update with the longer sequence.
5315 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5316 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5317 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5318 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5320 dsq.setSequence(newres);
5322 // TODO: merges will never happen if we 'know' we have the real dataset
5323 // sequence - this should be detected when id==dssid
5325 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5326 // + (pre ? "prepended" : "") + " "
5327 // + (post ? "appended" : ""));
5332 // sequence refs are identical. We may need to update the existing dataset
5333 // alignment with this one, though.
5334 if (ds != null && dseqs == null)
5336 int opos = ds.findIndex(dsq);
5337 SequenceI tseq = null;
5338 if (opos != -1 && vseqpos != opos)
5340 // remove from old position
5341 ds.deleteSequence(dsq);
5343 if (vseqpos < ds.getHeight())
5345 if (vseqpos != opos)
5347 // save sequence at destination position
5348 tseq = ds.getSequenceAt(vseqpos);
5349 ds.replaceSequenceAt(vseqpos, dsq);
5350 ds.addSequence(tseq);
5355 ds.addSequence(dsq);
5362 * TODO use AlignmentI here and in related methods - needs
5363 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5365 Hashtable<String, AlignmentI> datasetIds = null;
5367 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5369 private AlignmentI getDatasetFor(String datasetId)
5371 if (datasetIds == null)
5373 datasetIds = new Hashtable<>();
5376 if (datasetIds.containsKey(datasetId))
5378 return datasetIds.get(datasetId);
5383 private void addDatasetRef(String datasetId, AlignmentI dataset)
5385 if (datasetIds == null)
5387 datasetIds = new Hashtable<>();
5389 datasetIds.put(datasetId, dataset);
5393 * make a new dataset ID for this jalview dataset alignment
5398 private String getDatasetIdRef(AlignmentI dataset)
5400 if (dataset.getDataset() != null)
5402 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5404 String datasetId = makeHashCode(dataset, null);
5405 if (datasetId == null)
5407 // make a new datasetId and record it
5408 if (dataset2Ids == null)
5410 dataset2Ids = new IdentityHashMap<>();
5414 datasetId = dataset2Ids.get(dataset);
5416 if (datasetId == null)
5418 datasetId = "ds" + dataset2Ids.size() + 1;
5419 dataset2Ids.put(dataset, datasetId);
5425 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5427 for (int d = 0; d < sequence.getDBRefCount(); d++)
5429 DBRef dr = sequence.getDBRef(d);
5430 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5431 sequence.getDBRef(d).getSource(),
5432 sequence.getDBRef(d).getVersion(),
5433 sequence.getDBRef(d).getAccessionId());
5434 if (dr.getMapping() != null)
5436 entry.setMap(addMapping(dr.getMapping()));
5438 datasetSequence.addDBRef(entry);
5442 private jalview.datamodel.Mapping addMapping(Mapping m)
5444 SequenceI dsto = null;
5445 // Mapping m = dr.getMapping();
5446 int fr[] = new int[m.getMapListFromCount() * 2];
5447 Enumeration f = m.enumerateMapListFrom();
5448 for (int _i = 0; f.hasMoreElements(); _i += 2)
5450 MapListFrom mf = (MapListFrom) f.nextElement();
5451 fr[_i] = mf.getStart();
5452 fr[_i + 1] = mf.getEnd();
5454 int fto[] = new int[m.getMapListToCount() * 2];
5455 f = m.enumerateMapListTo();
5456 for (int _i = 0; f.hasMoreElements(); _i += 2)
5458 MapListTo mf = (MapListTo) f.nextElement();
5459 fto[_i] = mf.getStart();
5460 fto[_i + 1] = mf.getEnd();
5462 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5463 fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5464 if (m.getMappingChoice() != null)
5466 MappingChoice mc = m.getMappingChoice();
5467 if (mc.getDseqFor() != null)
5469 String dsfor = "" + mc.getDseqFor();
5470 if (seqRefIds.containsKey(dsfor))
5475 jmap.setTo(seqRefIds.get(dsfor));
5479 frefedSequence.add(newMappingRef(dsfor, jmap));
5485 * local sequence definition
5487 Sequence ms = mc.getSequence();
5488 SequenceI djs = null;
5489 String sqid = ms.getDsseqid();
5490 if (sqid != null && sqid.length() > 0)
5493 * recover dataset sequence
5495 djs = seqRefIds.get(sqid);
5500 "Warning - making up dataset sequence id for DbRef sequence map reference");
5501 sqid = ((Object) ms).toString(); // make up a new hascode for
5502 // undefined dataset sequence hash
5503 // (unlikely to happen)
5509 * make a new dataset sequence and add it to refIds hash
5511 djs = new jalview.datamodel.Sequence(ms.getName(),
5513 djs.setStart(jmap.getMap().getToLowest());
5514 djs.setEnd(jmap.getMap().getToHighest());
5515 djs.setVamsasId(uniqueSetSuffix + sqid);
5517 incompleteSeqs.put(sqid, djs);
5518 seqRefIds.put(sqid, djs);
5521 debug("about to recurse on addDBRefs.");
5531 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5532 * view as XML (but not to file), and then reloading it
5537 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5540 JalviewModel jm = saveState(ap, null, null, null);
5542 uniqueSetSuffix = "";
5543 jm.getJalviewModelSequence().getViewport(0).setId(null);
5544 // we don't overwrite the view we just copied
5546 if (this.frefedSequence == null)
5548 frefedSequence = new Vector<>();
5551 viewportsAdded.clear();
5553 AlignFrame af = loadFromObject(jm, null, false, null);
5554 af.alignPanels.clear();
5555 af.closeMenuItem_actionPerformed(true);
5558 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5559 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5560 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5561 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5562 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5565 return af.alignPanel;
5568 private Hashtable jvids2vobj;
5570 private void warn(String msg)
5575 private void warn(String msg, Exception e)
5577 if (Cache.log != null)
5581 Cache.log.warn(msg, e);
5585 Cache.log.warn(msg);
5590 System.err.println("Warning: " + msg);
5593 e.printStackTrace();
5598 private void debug(String string)
5600 debug(string, null);
5603 private void debug(String msg, Exception e)
5605 if (Cache.log != null)
5609 Cache.log.debug(msg, e);
5613 Cache.log.debug(msg);
5618 System.err.println("Warning: " + msg);
5621 e.printStackTrace();
5627 * set the object to ID mapping tables used to write/recover objects and XML
5628 * ID strings for the jalview project. If external tables are provided then
5629 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5630 * object goes out of scope. - also populates the datasetIds hashtable with
5631 * alignment objects containing dataset sequences
5634 * Map from ID strings to jalview datamodel
5636 * Map from jalview datamodel to ID strings
5640 public void setObjectMappingTables(Hashtable vobj2jv,
5641 IdentityHashMap jv2vobj)
5643 this.jv2vobj = jv2vobj;
5644 this.vobj2jv = vobj2jv;
5645 Iterator ds = jv2vobj.keySet().iterator();
5647 while (ds.hasNext())
5649 Object jvobj = ds.next();
5650 id = jv2vobj.get(jvobj).toString();
5651 if (jvobj instanceof jalview.datamodel.Alignment)
5653 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5655 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5658 else if (jvobj instanceof jalview.datamodel.Sequence)
5660 // register sequence object so the XML parser can recover it.
5661 if (seqRefIds == null)
5663 seqRefIds = new HashMap<>();
5665 if (seqsToIds == null)
5667 seqsToIds = new IdentityHashMap<>();
5669 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5670 seqsToIds.put((SequenceI) jvobj, id);
5672 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5675 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5676 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5677 if (jvann.annotationId == null)
5679 jvann.annotationId = anid;
5681 if (!jvann.annotationId.equals(anid))
5683 // TODO verify that this is the correct behaviour
5684 this.warn("Overriding Annotation ID for " + anid
5685 + " from different id : " + jvann.annotationId);
5686 jvann.annotationId = anid;
5689 else if (jvobj instanceof String)
5691 if (jvids2vobj == null)
5693 jvids2vobj = new Hashtable();
5694 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5699 debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5705 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5706 * objects created from the project archive. If string is null (default for
5707 * construction) then suffix will be set automatically.
5711 public void setUniqueSetSuffix(String string)
5713 uniqueSetSuffix = string;
5718 * uses skipList2 as the skipList for skipping views on sequence sets
5719 * associated with keys in the skipList
5723 public void setSkipList(Hashtable skipList2)
5725 skipList = skipList2;
5729 * Reads the jar entry of given name and returns its contents, or null if the
5730 * entry is not found.
5733 * @param jarEntryName
5736 protected String readJarEntry(jarInputStreamProvider jprovider,
5737 String jarEntryName)
5739 String result = null;
5740 BufferedReader in = null;
5745 * Reopen the jar input stream and traverse its entries to find a matching
5748 JarInputStream jin = jprovider.getJarInputStream();
5749 JarEntry entry = null;
5752 entry = jin.getNextJarEntry();
5753 } while (entry != null && !entry.getName().equals(jarEntryName));
5757 StringBuilder out = new StringBuilder(256);
5758 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5761 while ((data = in.readLine()) != null)
5765 result = out.toString();
5769 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5771 } catch (Exception ex)
5773 ex.printStackTrace();
5781 } catch (IOException e)
5792 * Returns an incrementing counter (0, 1, 2...)
5796 private synchronized int nextCounter()
5802 * Populates an XML model of the feature colour scheme for one feature type
5804 * @param featureType
5808 protected static jalview.schemabinding.version2.Colour marshalColour(
5809 String featureType, FeatureColourI fcol)
5811 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5812 if (fcol.isSimpleColour())
5814 col.setRGB(Format.getHexString(fcol.getColour()));
5818 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5819 col.setMin(fcol.getMin());
5820 col.setMax(fcol.getMax());
5821 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5822 col.setAutoScale(fcol.isAutoScaled());
5823 col.setThreshold(fcol.getThreshold());
5824 col.setColourByLabel(fcol.isColourByLabel());
5825 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5826 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5827 : ColourThreshTypeType.NONE));
5828 if (fcol.isColourByAttribute())
5830 col.setAttributeName(fcol.getAttributeName());
5832 Color noColour = fcol.getNoColour();
5833 if (noColour == null)
5835 col.setNoValueColour(NoValueColour.NONE);
5837 else if (noColour == fcol.getMaxColour())
5839 col.setNoValueColour(NoValueColour.MAX);
5843 col.setNoValueColour(NoValueColour.MIN);
5846 col.setName(featureType);
5851 * Populates an XML model of the feature filter(s) for one feature type
5853 * @param firstMatcher
5854 * the first (or only) match condition)
5856 * remaining match conditions (if any)
5858 * if true, conditions are and-ed, else or-ed
5860 protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5861 Iterator<FeatureMatcherI> filters, boolean and)
5863 MatcherSet result = new MatcherSet();
5865 if (filters.hasNext())
5870 CompoundMatcher compound = new CompoundMatcher();
5871 compound.setAnd(and);
5872 MatcherSet matcher1 = marshalFilter(firstMatcher,
5873 Collections.emptyIterator(), and);
5874 compound.addMatcherSet(matcher1);
5875 FeatureMatcherI nextMatcher = filters.next();
5876 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5877 compound.addMatcherSet(matcher2);
5878 result.setCompoundMatcher(compound);
5883 * single condition matcher
5885 MatchCondition matcherModel = new MatchCondition();
5886 matcherModel.setCondition(
5887 firstMatcher.getMatcher().getCondition().getStableName());
5888 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5889 if (firstMatcher.isByAttribute())
5891 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5892 matcherModel.setAttributeName(firstMatcher.getAttribute());
5894 else if (firstMatcher.isByLabel())
5896 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5898 else if (firstMatcher.isByScore())
5900 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5902 result.setMatchCondition(matcherModel);
5909 * Loads one XML model of a feature filter to a Jalview object
5911 * @param featureType
5912 * @param matcherSetModel
5915 protected static FeatureMatcherSetI unmarshalFilter(
5916 String featureType, MatcherSet matcherSetModel)
5918 FeatureMatcherSetI result = new FeatureMatcherSet();
5921 unmarshalFilterConditions(result, matcherSetModel, true);
5922 } catch (IllegalStateException e)
5924 // mixing AND and OR conditions perhaps
5926 String.format("Error reading filter conditions for '%s': %s",
5927 featureType, e.getMessage()));
5928 // return as much as was parsed up to the error
5935 * Adds feature match conditions to matcherSet as unmarshalled from XML
5936 * (possibly recursively for compound conditions)
5939 * @param matcherSetModel
5941 * if true, multiple conditions are AND-ed, else they are OR-ed
5942 * @throws IllegalStateException
5943 * if AND and OR conditions are mixed
5945 protected static void unmarshalFilterConditions(
5946 FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5949 MatchCondition mc = matcherSetModel.getMatchCondition();
5955 FeatureMatcherByType filterBy = mc.getBy();
5956 Condition cond = Condition.fromString(mc.getCondition());
5957 String pattern = mc.getValue();
5958 FeatureMatcherI matchCondition = null;
5959 if (filterBy == FeatureMatcherByType.BYLABEL)
5961 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5963 else if (filterBy == FeatureMatcherByType.BYSCORE)
5965 matchCondition = FeatureMatcher.byScore(cond, pattern);
5968 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5970 String[] attNames = mc.getAttributeName();
5971 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5976 * note this throws IllegalStateException if AND-ing to a
5977 * previously OR-ed compound condition, or vice versa
5981 matcherSet.and(matchCondition);
5985 matcherSet.or(matchCondition);
5991 * compound condition
5993 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5995 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5996 if (matchers.length == 2)
5998 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5999 unmarshalFilterConditions(matcherSet, matchers[1], anded);
6003 System.err.println("Malformed compound filter condition");
6009 * Loads one XML model of a feature colour to a Jalview object
6011 * @param colourModel
6014 protected static FeatureColourI unmarshalColour(
6015 jalview.schemabinding.version2.Colour colourModel)
6017 FeatureColourI colour = null;
6019 if (colourModel.hasMax())
6021 Color mincol = null;
6022 Color maxcol = null;
6023 Color noValueColour = null;
6027 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6028 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6029 } catch (Exception e)
6031 if (Cache.log != null)
6033 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6037 NoValueColour noCol = colourModel.getNoValueColour();
6038 if (noCol == NoValueColour.MIN)
6040 noValueColour = mincol;
6042 else if (noCol == NoValueColour.MAX)
6044 noValueColour = maxcol;
6047 colour = new FeatureColour(mincol, maxcol, noValueColour,
6048 colourModel.getMin(),
6049 colourModel.getMax());
6050 String[] attributes = colourModel.getAttributeName();
6051 if (attributes != null && attributes.length > 0)
6053 colour.setAttributeName(attributes);
6055 if (colourModel.hasAutoScale())
6057 colour.setAutoScaled(colourModel.getAutoScale());
6059 if (colourModel.hasColourByLabel())
6061 colour.setColourByLabel(colourModel.getColourByLabel());
6063 if (colourModel.hasThreshold())
6065 colour.setThreshold(colourModel.getThreshold());
6067 ColourThreshTypeType ttyp = colourModel.getThreshType();
6070 if (ttyp == ColourThreshTypeType.ABOVE)
6072 colour.setAboveThreshold(true);
6074 else if (ttyp == ColourThreshTypeType.BELOW)
6076 colour.setBelowThreshold(true);
6082 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6083 colour = new FeatureColour(color);