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.AlignSeq;
24 import jalview.api.structures.JalviewStructureDisplayI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignedCodonFrame;
27 import jalview.datamodel.Alignment;
28 import jalview.datamodel.AlignmentAnnotation;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.PDBEntry;
31 import jalview.datamodel.RnaViewerModel;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.datamodel.StructureViewerModel;
35 import jalview.datamodel.StructureViewerModel.StructureData;
36 import jalview.ext.varna.RnaModel;
37 import jalview.gui.StructureViewer.ViewerType;
38 import jalview.io.AppletFormatAdapter;
39 import jalview.schemabinding.version2.AlcodMap;
40 import jalview.schemabinding.version2.AlcodonFrame;
41 import jalview.schemabinding.version2.Annotation;
42 import jalview.schemabinding.version2.AnnotationColours;
43 import jalview.schemabinding.version2.AnnotationElement;
44 import jalview.schemabinding.version2.CalcIdParam;
45 import jalview.schemabinding.version2.DBRef;
46 import jalview.schemabinding.version2.Features;
47 import jalview.schemabinding.version2.Group;
48 import jalview.schemabinding.version2.HiddenColumns;
49 import jalview.schemabinding.version2.JGroup;
50 import jalview.schemabinding.version2.JSeq;
51 import jalview.schemabinding.version2.JalviewModel;
52 import jalview.schemabinding.version2.JalviewModelSequence;
53 import jalview.schemabinding.version2.MapListFrom;
54 import jalview.schemabinding.version2.MapListTo;
55 import jalview.schemabinding.version2.Mapping;
56 import jalview.schemabinding.version2.MappingChoice;
57 import jalview.schemabinding.version2.OtherData;
58 import jalview.schemabinding.version2.PdbentryItem;
59 import jalview.schemabinding.version2.Pdbids;
60 import jalview.schemabinding.version2.Property;
61 import jalview.schemabinding.version2.RnaViewer;
62 import jalview.schemabinding.version2.SecondaryStructure;
63 import jalview.schemabinding.version2.Sequence;
64 import jalview.schemabinding.version2.SequenceSet;
65 import jalview.schemabinding.version2.SequenceSetProperties;
66 import jalview.schemabinding.version2.Setting;
67 import jalview.schemabinding.version2.StructureState;
68 import jalview.schemabinding.version2.ThresholdLine;
69 import jalview.schemabinding.version2.Tree;
70 import jalview.schemabinding.version2.UserColours;
71 import jalview.schemabinding.version2.Viewport;
72 import jalview.schemes.AnnotationColourGradient;
73 import jalview.schemes.ColourSchemeI;
74 import jalview.schemes.ColourSchemeProperty;
75 import jalview.schemes.GraduatedColor;
76 import jalview.schemes.ResidueColourScheme;
77 import jalview.schemes.ResidueProperties;
78 import jalview.schemes.UserColourScheme;
79 import jalview.structure.StructureSelectionManager;
80 import jalview.structures.models.AAStructureBindingModel;
81 import jalview.util.Comparison;
82 import jalview.util.MapList;
83 import jalview.util.MessageManager;
84 import jalview.util.Platform;
85 import jalview.util.jarInputStreamProvider;
86 import jalview.viewmodel.AlignmentViewport;
87 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
88 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
89 import jalview.ws.jws2.Jws2Discoverer;
90 import jalview.ws.jws2.dm.AAConSettings;
91 import jalview.ws.jws2.jabaws2.Jws2Instance;
92 import jalview.ws.params.ArgumentI;
93 import jalview.ws.params.AutoCalcSetting;
94 import jalview.ws.params.WsParamSetI;
96 import java.awt.Rectangle;
97 import java.io.BufferedReader;
98 import java.io.DataInputStream;
99 import java.io.DataOutputStream;
101 import java.io.FileInputStream;
102 import java.io.FileOutputStream;
103 import java.io.IOException;
104 import java.io.InputStreamReader;
105 import java.io.OutputStreamWriter;
106 import java.io.PrintWriter;
107 import java.lang.reflect.InvocationTargetException;
108 import java.net.MalformedURLException;
110 import java.util.ArrayList;
111 import java.util.Enumeration;
112 import java.util.HashMap;
113 import java.util.HashSet;
114 import java.util.Hashtable;
115 import java.util.IdentityHashMap;
116 import java.util.Iterator;
117 import java.util.LinkedHashMap;
118 import java.util.List;
119 import java.util.Map;
120 import java.util.Map.Entry;
121 import java.util.Set;
122 import java.util.StringTokenizer;
123 import java.util.Vector;
124 import java.util.jar.JarEntry;
125 import java.util.jar.JarInputStream;
126 import java.util.jar.JarOutputStream;
128 import javax.swing.JInternalFrame;
129 import javax.swing.JOptionPane;
130 import javax.swing.SwingUtilities;
132 import org.exolab.castor.xml.Marshaller;
133 import org.exolab.castor.xml.Unmarshaller;
136 * Write out the current jalview desktop state as a Jalview XML stream.
138 * Note: the vamsas objects referred to here are primitive versions of the
139 * VAMSAS project schema elements - they are not the same and most likely never
143 * @version $Revision: 1.134 $
145 public class Jalview2XML
147 private static final String VIEWER_PREFIX = "viewer_";
149 private static final String RNA_PREFIX = "rna_";
151 private static final String UTF_8 = "UTF-8";
153 // use this with nextCounter() to make unique names for entities
154 private int counter = 0;
157 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
158 * of sequence objects are created.
160 IdentityHashMap<SequenceI, String> seqsToIds = null;
163 * jalview XML Sequence ID to jalview sequence object reference (both dataset
164 * and alignment sequences. Populated as XML reps of sequence objects are
167 Map<String, SequenceI> seqRefIds = null;
169 Vector frefedSequence = null;
171 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
174 * Map of reconstructed AlignFrame objects that appear to have come from
175 * SplitFrame objects (have a dna/protein complement view).
177 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<Viewport, AlignFrame>();
180 * Map from displayed rna structure models to their saved session state jar
183 private Map<RnaModel, String> rnaSessions = new HashMap<RnaModel, String>();
186 * create/return unique hash string for sq
189 * @return new or existing unique string for sq
191 String seqHash(SequenceI sq)
193 if (seqsToIds == null)
197 if (seqsToIds.containsKey(sq))
199 return seqsToIds.get(sq);
203 // create sequential key
204 String key = "sq" + (seqsToIds.size() + 1);
205 key = makeHashCode(sq, key); // check we don't have an external reference
207 seqsToIds.put(sq, key);
216 if (seqRefIds != null)
220 if (seqsToIds != null)
230 warn("clearSeqRefs called when _cleartables was not set. Doing nothing.");
231 // seqRefIds = new Hashtable();
232 // seqsToIds = new IdentityHashMap();
238 if (seqsToIds == null)
240 seqsToIds = new IdentityHashMap<SequenceI, String>();
242 if (seqRefIds == null)
244 seqRefIds = new HashMap<String, SequenceI>();
252 public Jalview2XML(boolean raiseGUI)
254 this.raiseGUI = raiseGUI;
257 public void resolveFrefedSequences()
259 if (frefedSequence.size() > 0)
261 int r = 0, rSize = frefedSequence.size();
264 Object[] ref = (Object[]) frefedSequence.elementAt(r);
267 String sref = (String) ref[0];
268 if (seqRefIds.containsKey(sref))
270 if (ref[1] instanceof jalview.datamodel.Mapping)
272 SequenceI seq = seqRefIds.get(sref);
273 while (seq.getDatasetSequence() != null)
275 seq = seq.getDatasetSequence();
277 ((jalview.datamodel.Mapping) ref[1]).setTo(seq);
281 if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame)
283 SequenceI seq = seqRefIds.get(sref);
284 while (seq.getDatasetSequence() != null)
286 seq = seq.getDatasetSequence();
289 && ref[2] instanceof jalview.datamodel.Mapping)
291 jalview.datamodel.Mapping mp = (jalview.datamodel.Mapping) ref[2];
292 ((jalview.datamodel.AlignedCodonFrame) ref[1]).addMap(
293 seq, mp.getTo(), mp.getMap());
298 .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for AlcodonFrames involving "
299 + ref[2].getClass() + " type objects.");
305 .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for "
306 + ref[1].getClass() + " type objects.");
309 frefedSequence.remove(r);
315 .println("IMPLEMENTATION WARNING: Unresolved forward reference for hash string "
317 + " with objecttype "
318 + ref[1].getClass());
325 frefedSequence.remove(r);
333 * This maintains a map of viewports, the key being the seqSetId. Important to
334 * set historyItem and redoList for multiple views
336 Map<String, AlignViewport> viewportsAdded = new HashMap<String, AlignViewport>();
338 Map<String, AlignmentAnnotation> annotationIds = new HashMap<String, AlignmentAnnotation>();
340 String uniqueSetSuffix = "";
343 * List of pdbfiles added to Jar
345 List<String> pdbfiles = null;
347 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
348 public void saveState(File statefile)
350 FileOutputStream fos = null;
353 fos = new FileOutputStream(statefile);
354 JarOutputStream jout = new JarOutputStream(fos);
357 } catch (Exception e)
359 // TODO: inform user of the problem - they need to know if their data was
361 if (errorMessage == null)
363 errorMessage = "Couldn't write Jalview Archive to output file '"
364 + statefile + "' - See console error log for details";
368 errorMessage += "(output file was '" + statefile + "')";
378 } catch (IOException e)
388 * Writes a jalview project archive to the given Jar output stream.
392 public void saveState(JarOutputStream jout)
394 AlignFrame[] frames = Desktop.getAlignFrames();
401 Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
404 * ensure cached data is clear before starting
406 // todo tidy up seqRefIds, seqsToIds initialisation / reset
408 splitFrameCandidates.clear();
413 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
414 // //////////////////////////////////////////////////
416 List<String> shortNames = new ArrayList<String>();
417 List<String> viewIds = new ArrayList<String>();
420 for (int i = frames.length - 1; i > -1; i--)
422 AlignFrame af = frames[i];
426 .containsKey(af.getViewport().getSequenceSetId()))
431 String shortName = makeFilename(af, shortNames);
433 int ap, apSize = af.alignPanels.size();
435 for (ap = 0; ap < apSize; ap++)
437 AlignmentPanel apanel = af.alignPanels.get(ap);
438 String fileName = apSize == 1 ? shortName : ap + shortName;
439 if (!fileName.endsWith(".xml"))
441 fileName = fileName + ".xml";
444 saveState(apanel, fileName, jout, viewIds);
446 String dssid = getDatasetIdRef(af.getViewport().getAlignment()
448 if (!dsses.containsKey(dssid))
450 dsses.put(dssid, af);
455 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
461 } catch (Exception foo)
466 } catch (Exception ex)
468 // TODO: inform user of the problem - they need to know if their data was
470 if (errorMessage == null)
472 errorMessage = "Couldn't write Jalview Archive - see error output for details";
474 ex.printStackTrace();
479 * Generates a distinct file name, based on the title of the AlignFrame, by
480 * appending _n for increasing n until an unused name is generated. The new
481 * name (without its extension) is added to the list.
485 * @return the generated name, with .xml extension
487 protected String makeFilename(AlignFrame af, List<String> namesUsed)
489 String shortName = af.getTitle();
491 if (shortName.indexOf(File.separatorChar) > -1)
493 shortName = shortName.substring(shortName
494 .lastIndexOf(File.separatorChar) + 1);
499 while (namesUsed.contains(shortName))
501 if (shortName.endsWith("_" + (count - 1)))
503 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
506 shortName = shortName.concat("_" + count);
510 namesUsed.add(shortName);
512 if (!shortName.endsWith(".xml"))
514 shortName = shortName + ".xml";
519 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
520 public boolean saveAlignment(AlignFrame af, String jarFile,
526 int apSize = af.alignPanels.size();
527 FileOutputStream fos = new FileOutputStream(jarFile);
528 JarOutputStream jout = new JarOutputStream(fos);
529 Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
530 List<String> viewIds = new ArrayList<String>();
532 for (AlignmentPanel apanel : af.alignPanels)
534 String jfileName = apSize == 1 ? fileName : fileName + ap;
536 if (!jfileName.endsWith(".xml"))
538 jfileName = jfileName + ".xml";
540 saveState(apanel, jfileName, jout, viewIds);
541 String dssid = getDatasetIdRef(af.getViewport().getAlignment()
543 if (!dsses.containsKey(dssid))
545 dsses.put(dssid, af);
548 writeDatasetFor(dsses, fileName, jout);
552 } catch (Exception foo)
558 } catch (Exception ex)
560 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
561 ex.printStackTrace();
566 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
567 String fileName, JarOutputStream jout)
570 for (String dssids : dsses.keySet())
572 AlignFrame _af = dsses.get(dssids);
573 String jfileName = fileName + " Dataset for " + _af.getTitle();
574 if (!jfileName.endsWith(".xml"))
576 jfileName = jfileName + ".xml";
578 saveState(_af.alignPanel, jfileName, true, jout, null);
583 * create a JalviewModel from an alignment view and marshall it to a
587 * panel to create jalview model for
589 * name of alignment panel written to output stream
596 public JalviewModel saveState(AlignmentPanel ap, String fileName,
597 JarOutputStream jout, List<String> viewIds)
599 return saveState(ap, fileName, false, jout, viewIds);
603 * create a JalviewModel from an alignment view and marshall it to a
607 * panel to create jalview model for
609 * name of alignment panel written to output stream
611 * when true, only write the dataset for the alignment, not the data
612 * associated with the view.
618 public JalviewModel saveState(AlignmentPanel ap, String fileName,
619 boolean storeDS, JarOutputStream jout, List<String> viewIds)
623 viewIds = new ArrayList<String>();
628 List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
630 AlignViewport av = ap.av;
632 JalviewModel object = new JalviewModel();
633 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
635 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
636 object.setVersion(Cache.getDefault("VERSION",
637 "Development Build"));
639 AlignmentI jal = av.getAlignment();
641 if (av.hasHiddenRows())
643 jal = jal.getHiddenSequences().getFullAlignment();
646 SequenceSet vamsasSet = new SequenceSet();
648 JalviewModelSequence jms = new JalviewModelSequence();
650 vamsasSet.setGapChar(jal.getGapCharacter() + "");
652 if (jal.getDataset() != null)
654 // dataset id is the dataset's hashcode
655 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
658 // switch jal and the dataset
659 jal = jal.getDataset();
662 if (jal.getProperties() != null)
664 Enumeration en = jal.getProperties().keys();
665 while (en.hasMoreElements())
667 String key = en.nextElement().toString();
668 SequenceSetProperties ssp = new SequenceSetProperties();
670 ssp.setValue(jal.getProperties().get(key).toString());
671 vamsasSet.addSequenceSetProperties(ssp);
676 Set<String> calcIdSet = new HashSet<String>();
679 for (int i = 0; i < jal.getHeight(); i++)
681 final SequenceI jds = jal.getSequenceAt(i);
682 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
684 .getDatasetSequence();
685 String id = seqHash(jds);
687 if (seqRefIds.get(id) != null)
689 // This happens for two reasons: 1. multiple views are being serialised.
690 // 2. the hashCode has collided with another sequence's code. This DOES
691 // HAPPEN! (PF00072.15.stk does this)
692 // JBPNote: Uncomment to debug writing out of files that do not read
693 // back in due to ArrayOutOfBoundExceptions.
694 // System.err.println("vamsasSeq backref: "+id+"");
695 // System.err.println(jds.getName()+"
696 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
697 // System.err.println("Hashcode: "+seqHash(jds));
698 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
699 // System.err.println(rsq.getName()+"
700 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
701 // System.err.println("Hashcode: "+seqHash(rsq));
705 vamsasSeq = createVamsasSequence(id, jds);
706 vamsasSet.addSequence(vamsasSeq);
707 seqRefIds.put(id, jds);
711 jseq.setStart(jds.getStart());
712 jseq.setEnd(jds.getEnd());
713 jseq.setColour(av.getSequenceColour(jds).getRGB());
715 jseq.setId(id); // jseq id should be a string not a number
718 // Store any sequences this sequence represents
719 if (av.hasHiddenRows())
721 jseq.setHidden(av.getAlignment().getHiddenSequences()
724 if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
726 jalview.datamodel.SequenceI[] reps = av
727 .getRepresentedSequences(jal.getSequenceAt(i))
728 .getSequencesInOrder(jal);
730 for (int h = 0; h < reps.length; h++)
732 if (reps[h] != jal.getSequenceAt(i))
734 jseq.addHiddenSequences(jal.findIndex(reps[h]));
741 if (jds.getSequenceFeatures() != null)
743 jalview.datamodel.SequenceFeature[] sf = jds
744 .getSequenceFeatures();
746 while (index < sf.length)
748 Features features = new Features();
750 features.setBegin(sf[index].getBegin());
751 features.setEnd(sf[index].getEnd());
752 features.setDescription(sf[index].getDescription());
753 features.setType(sf[index].getType());
754 features.setFeatureGroup(sf[index].getFeatureGroup());
755 features.setScore(sf[index].getScore());
756 if (sf[index].links != null)
758 for (int l = 0; l < sf[index].links.size(); l++)
760 OtherData keyValue = new OtherData();
761 keyValue.setKey("LINK_" + l);
762 keyValue.setValue(sf[index].links.elementAt(l).toString());
763 features.addOtherData(keyValue);
766 if (sf[index].otherDetails != null)
769 Enumeration keys = sf[index].otherDetails.keys();
770 while (keys.hasMoreElements())
772 key = keys.nextElement().toString();
773 OtherData keyValue = new OtherData();
774 keyValue.setKey(key);
775 keyValue.setValue(sf[index].otherDetails.get(key).toString());
776 features.addOtherData(keyValue);
780 jseq.addFeatures(features);
785 if (jdatasq.getPDBId() != null)
787 Enumeration en = jdatasq.getPDBId().elements();
788 while (en.hasMoreElements())
790 Pdbids pdb = new Pdbids();
791 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
794 String pdbId = entry.getId();
796 pdb.setType(entry.getType());
799 * Store any structure views associated with this sequence. This
800 * section copes with duplicate entries in the project, so a dataset
801 * only view *should* be coped with sensibly.
803 // This must have been loaded, is it still visible?
804 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
805 String matchedFile = null;
806 for (int f = frames.length - 1; f > -1; f--)
808 if (frames[f] instanceof StructureViewerBase)
810 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
811 matchedFile = saveStructureState(ap, jds, pdb, entry,
812 viewIds, matchedFile, viewFrame);
814 * Only store each structure viewer's state once in the project
815 * jar. First time through only (storeDS==false)
817 String viewId = viewFrame.getViewId();
818 if (!storeDS && !viewIds.contains(viewId))
823 String viewerState = viewFrame.getStateInfo();
824 writeJarEntry(jout, getViewerJarEntryName(viewId),
825 viewerState.getBytes());
826 } catch (IOException e)
828 System.err.println("Error saving viewer state: "
835 if (matchedFile != null || entry.getFile() != null)
837 if (entry.getFile() != null)
840 matchedFile = entry.getFile();
842 pdb.setFile(matchedFile); // entry.getFile());
843 if (pdbfiles == null)
845 pdbfiles = new ArrayList<String>();
848 if (!pdbfiles.contains(pdbId))
851 copyFileToJar(jout, matchedFile, pdbId);
855 if (entry.getProperty() != null && !entry.getProperty().isEmpty())
857 PdbentryItem item = new PdbentryItem();
858 Hashtable properties = entry.getProperty();
859 Enumeration en2 = properties.keys();
860 while (en2.hasMoreElements())
862 Property prop = new Property();
863 String key = en2.nextElement().toString();
865 prop.setValue(properties.get(key).toString());
866 item.addProperty(prop);
868 pdb.addPdbentryItem(item);
875 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
880 if (!storeDS && av.hasHiddenRows())
882 jal = av.getAlignment();
885 if (jal.getCodonFrames() != null)
887 Set<AlignedCodonFrame> jac = jal.getCodonFrames();
888 for (AlignedCodonFrame acf : jac)
890 AlcodonFrame alc = new AlcodonFrame();
891 vamsasSet.addAlcodonFrame(alc);
892 if (acf.getProtMappings() != null
893 && acf.getProtMappings().length > 0)
895 SequenceI[] dnas = acf.getdnaSeqs();
896 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
897 for (int m = 0; m < pmaps.length; m++)
899 AlcodMap alcmap = new AlcodMap();
900 alcmap.setDnasq(seqHash(dnas[m]));
901 alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
903 alc.addAlcodMap(alcmap);
908 // AlcodonFrame alc = new AlcodonFrame();
909 // vamsasSet.addAlcodonFrame(alc);
910 // for (int p = 0; p < acf.aaWidth; p++)
912 // Alcodon cmap = new Alcodon();
913 // if (acf.codons[p] != null)
915 // // Null codons indicate a gapped column in the translated peptide
917 // cmap.setPos1(acf.codons[p][0]);
918 // cmap.setPos2(acf.codons[p][1]);
919 // cmap.setPos3(acf.codons[p][2]);
921 // alc.addAlcodon(cmap);
923 // if (acf.getProtMappings() != null
924 // && acf.getProtMappings().length > 0)
926 // SequenceI[] dnas = acf.getdnaSeqs();
927 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
928 // for (int m = 0; m < pmaps.length; m++)
930 // AlcodMap alcmap = new AlcodMap();
931 // alcmap.setDnasq(seqHash(dnas[m]));
932 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
934 // alc.addAlcodMap(alcmap);
941 // /////////////////////////////////
942 if (!storeDS && av.currentTree != null)
944 // FIND ANY ASSOCIATED TREES
945 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
946 if (Desktop.desktop != null)
948 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
950 for (int t = 0; t < frames.length; t++)
952 if (frames[t] instanceof TreePanel)
954 TreePanel tp = (TreePanel) frames[t];
956 if (tp.treeCanvas.av.getAlignment() == jal)
958 Tree tree = new Tree();
959 tree.setTitle(tp.getTitle());
960 tree.setCurrentTree((av.currentTree == tp.getTree()));
961 tree.setNewick(tp.getTree().toString());
962 tree.setThreshold(tp.treeCanvas.threshold);
964 tree.setFitToWindow(tp.fitToWindow.getState());
965 tree.setFontName(tp.getTreeFont().getName());
966 tree.setFontSize(tp.getTreeFont().getSize());
967 tree.setFontStyle(tp.getTreeFont().getStyle());
968 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
970 tree.setShowBootstrap(tp.bootstrapMenu.getState());
971 tree.setShowDistances(tp.distanceMenu.getState());
973 tree.setHeight(tp.getHeight());
974 tree.setWidth(tp.getWidth());
975 tree.setXpos(tp.getX());
976 tree.setYpos(tp.getY());
977 tree.setId(makeHashCode(tp, null));
987 * store forward refs from an annotationRow to any groups
989 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<SequenceGroup, String>();
992 for (SequenceI sq : jal.getSequences())
994 // Store annotation on dataset sequences only
995 AlignmentAnnotation[] aa = sq.getAnnotation();
996 if (aa != null && aa.length > 0)
998 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1005 if (jal.getAlignmentAnnotation() != null)
1007 // Store the annotation shown on the alignment.
1008 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1009 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1014 if (jal.getGroups() != null)
1016 JGroup[] groups = new JGroup[jal.getGroups().size()];
1018 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1020 JGroup jGroup = new JGroup();
1021 groups[++i] = jGroup;
1023 jGroup.setStart(sg.getStartRes());
1024 jGroup.setEnd(sg.getEndRes());
1025 jGroup.setName(sg.getName());
1026 if (groupRefs.containsKey(sg))
1028 // group has references so set its ID field
1029 jGroup.setId(groupRefs.get(sg));
1033 if (sg.cs.conservationApplied())
1035 jGroup.setConsThreshold(sg.cs.getConservationInc());
1037 if (sg.cs instanceof jalview.schemes.UserColourScheme)
1039 jGroup.setColour(setUserColourScheme(sg.cs, userColours,
1045 .setColour(ColourSchemeProperty.getColourName(sg.cs));
1048 else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient)
1050 jGroup.setColour("AnnotationColourGradient");
1051 jGroup.setAnnotationColours(constructAnnotationColours(
1052 (jalview.schemes.AnnotationColourGradient) sg.cs,
1055 else if (sg.cs instanceof jalview.schemes.UserColourScheme)
1058 .setColour(setUserColourScheme(sg.cs, userColours, jms));
1062 jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs));
1065 jGroup.setPidThreshold(sg.cs.getThreshold());
1068 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1069 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1070 jGroup.setDisplayText(sg.getDisplayText());
1071 jGroup.setColourText(sg.getColourText());
1072 jGroup.setTextCol1(sg.textColour.getRGB());
1073 jGroup.setTextCol2(sg.textColour2.getRGB());
1074 jGroup.setTextColThreshold(sg.thresholdTextColour);
1075 jGroup.setShowUnconserved(sg.getShowNonconserved());
1076 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1077 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1078 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1079 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1080 for (SequenceI seq : sg.getSequences())
1082 jGroup.addSeq(seqHash(seq));
1086 jms.setJGroup(groups);
1090 // /////////SAVE VIEWPORT
1091 Viewport view = new Viewport();
1092 view.setTitle(ap.alignFrame.getTitle());
1093 view.setSequenceSetId(makeHashCode(av.getSequenceSetId(),
1094 av.getSequenceSetId()));
1095 view.setId(av.getViewId());
1096 if (av.getCodingComplement() != null)
1098 view.setComplementId(av.getCodingComplement().getViewId());
1100 view.setViewName(av.viewName);
1101 view.setGatheredViews(av.isGatherViewsHere());
1103 Rectangle position = ap.av.getExplodedGeometry();
1104 if (position == null)
1106 position = ap.alignFrame.getBounds();
1108 view.setXpos(position.x);
1109 view.setYpos(position.y);
1110 view.setWidth(position.width);
1111 view.setHeight(position.height);
1113 view.setStartRes(av.startRes);
1114 view.setStartSeq(av.startSeq);
1116 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1118 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1121 else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1123 AnnotationColours ac = constructAnnotationColours(
1124 (jalview.schemes.AnnotationColourGradient) av
1125 .getGlobalColourScheme(),
1128 view.setAnnotationColours(ac);
1129 view.setBgColour("AnnotationColourGradient");
1133 view.setBgColour(ColourSchemeProperty.getColourName(av
1134 .getGlobalColourScheme()));
1137 ColourSchemeI cs = av.getGlobalColourScheme();
1141 if (cs.conservationApplied())
1143 view.setConsThreshold(cs.getConservationInc());
1144 if (cs instanceof jalview.schemes.UserColourScheme)
1146 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1150 if (cs instanceof ResidueColourScheme)
1152 view.setPidThreshold(cs.getThreshold());
1156 view.setConservationSelected(av.getConservationSelected());
1157 view.setPidSelected(av.getAbovePIDThreshold());
1158 view.setFontName(av.font.getName());
1159 view.setFontSize(av.font.getSize());
1160 view.setFontStyle(av.font.getStyle());
1161 view.setRenderGaps(av.isRenderGaps());
1162 view.setShowAnnotation(av.isShowAnnotation());
1163 view.setShowBoxes(av.getShowBoxes());
1164 view.setShowColourText(av.getColourText());
1165 view.setShowFullId(av.getShowJVSuffix());
1166 view.setRightAlignIds(av.isRightAlignIds());
1167 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1168 view.setShowText(av.getShowText());
1169 view.setShowUnconserved(av.getShowUnconserved());
1170 view.setWrapAlignment(av.getWrapAlignment());
1171 view.setTextCol1(av.getTextColour().getRGB());
1172 view.setTextCol2(av.getTextColour2().getRGB());
1173 view.setTextColThreshold(av.getThresholdTextColour());
1174 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1175 view.setShowSequenceLogo(av.isShowSequenceLogo());
1176 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1177 view.setShowGroupConsensus(av.isShowGroupConsensus());
1178 view.setShowGroupConservation(av.isShowGroupConservation());
1179 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1180 view.setShowDbRefTooltip(av.isShowDBRefs());
1181 view.setFollowHighlight(av.isFollowHighlight());
1182 view.setFollowSelection(av.followSelection);
1183 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1184 if (av.getFeaturesDisplayed() != null)
1186 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1188 String[] renderOrder = ap.getSeqPanel().seqCanvas
1189 .getFeatureRenderer().getRenderOrder()
1190 .toArray(new String[0]);
1192 Vector settingsAdded = new Vector();
1193 Object gstyle = null;
1194 GraduatedColor gcol = null;
1195 if (renderOrder != null)
1197 for (int ro = 0; ro < renderOrder.length; ro++)
1199 gstyle = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1200 .getFeatureStyle(renderOrder[ro]);
1201 Setting setting = new Setting();
1202 setting.setType(renderOrder[ro]);
1203 if (gstyle instanceof GraduatedColor)
1205 gcol = (GraduatedColor) gstyle;
1206 setting.setColour(gcol.getMaxColor().getRGB());
1207 setting.setMincolour(gcol.getMinColor().getRGB());
1208 setting.setMin(gcol.getMin());
1209 setting.setMax(gcol.getMax());
1210 setting.setColourByLabel(gcol.isColourByLabel());
1211 setting.setAutoScale(gcol.isAutoScale());
1212 setting.setThreshold(gcol.getThresh());
1213 setting.setThreshstate(gcol.getThreshType());
1217 setting.setColour(ap.getSeqPanel().seqCanvas
1218 .getFeatureRenderer()
1219 .getColour(renderOrder[ro]).getRGB());
1222 setting.setDisplay(av.getFeaturesDisplayed().isVisible(
1224 float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1225 .getOrder(renderOrder[ro]);
1228 setting.setOrder(rorder);
1230 fs.addSetting(setting);
1231 settingsAdded.addElement(renderOrder[ro]);
1235 // Make sure we save none displayed feature settings
1236 Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1237 .getFeatureColours().keySet().iterator();
1238 while (en.hasNext())
1240 String key = en.next().toString();
1241 if (settingsAdded.contains(key))
1246 Setting setting = new Setting();
1247 setting.setType(key);
1248 setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1249 .getColour(key).getRGB());
1251 setting.setDisplay(false);
1252 float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1256 setting.setOrder(rorder);
1258 fs.addSetting(setting);
1259 settingsAdded.addElement(key);
1261 // is groups actually supposed to be a map here ?
1262 en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
1263 .getFeatureGroups().iterator();
1264 Vector groupsAdded = new Vector();
1265 while (en.hasNext())
1267 String grp = en.next().toString();
1268 if (groupsAdded.contains(grp))
1272 Group g = new Group();
1274 g.setDisplay(((Boolean) ap.getSeqPanel().seqCanvas
1275 .getFeatureRenderer().checkGroupVisibility(grp, false))
1278 groupsAdded.addElement(grp);
1280 jms.setFeatureSettings(fs);
1284 if (av.hasHiddenColumns())
1286 if (av.getColumnSelection() == null
1287 || av.getColumnSelection().getHiddenColumns() == null)
1289 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1293 for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
1296 int[] region = av.getColumnSelection().getHiddenColumns()
1298 HiddenColumns hc = new HiddenColumns();
1299 hc.setStart(region[0]);
1300 hc.setEnd(region[1]);
1301 view.addHiddenColumns(hc);
1305 if (calcIdSet.size() > 0)
1307 for (String calcId : calcIdSet)
1309 if (calcId.trim().length() > 0)
1311 CalcIdParam cidp = createCalcIdParam(calcId, av);
1312 // Some calcIds have no parameters.
1315 view.addCalcIdParam(cidp);
1321 jms.addViewport(view);
1323 object.setJalviewModelSequence(jms);
1324 object.getVamsasModel().addSequenceSet(vamsasSet);
1326 if (jout != null && fileName != null)
1328 // We may not want to write the object to disk,
1329 // eg we can copy the alignViewport to a new view object
1330 // using save and then load
1333 System.out.println("Writing jar entry " + fileName);
1334 JarEntry entry = new JarEntry(fileName);
1335 jout.putNextEntry(entry);
1336 PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout,
1338 Marshaller marshaller = new Marshaller(pout);
1339 marshaller.marshal(object);
1342 } catch (Exception ex)
1344 // TODO: raise error in GUI if marshalling failed.
1345 ex.printStackTrace();
1352 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1353 * for each viewer, with
1355 * <li>viewer geometry (position, size, split pane divider location)</li>
1356 * <li>index of the selected structure in the viewer (currently shows gapped
1358 * <li>the id of the annotation holding RNA secondary structure</li>
1359 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1361 * Varna viewer state is also written out (in native Varna XML) to separate
1362 * project jar entries. A separate entry is written for each RNA structure
1363 * displayed, with the naming convention
1365 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1373 * @param storeDataset
1375 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1376 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1377 boolean storeDataset)
1379 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1380 for (int f = frames.length - 1; f > -1; f--)
1382 if (frames[f] instanceof AppVarna)
1384 AppVarna varna = (AppVarna) frames[f];
1386 * link the sequence to every viewer that is showing it and is linked to
1387 * its alignment panel
1389 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1391 String viewId = varna.getViewId();
1392 RnaViewer rna = new RnaViewer();
1393 rna.setViewId(viewId);
1394 rna.setTitle(varna.getTitle());
1395 rna.setXpos(varna.getX());
1396 rna.setYpos(varna.getY());
1397 rna.setWidth(varna.getWidth());
1398 rna.setHeight(varna.getHeight());
1399 rna.setDividerLocation(varna.getDividerLocation());
1400 rna.setSelectedRna(varna.getSelectedIndex());
1401 jseq.addRnaViewer(rna);
1404 * Store each Varna panel's state once in the project per sequence.
1405 * First time through only (storeDataset==false)
1407 // boolean storeSessions = false;
1408 // String sequenceViewId = viewId + seqsToIds.get(jds);
1409 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1411 // viewIds.add(sequenceViewId);
1412 // storeSessions = true;
1414 for (RnaModel model : varna.getModels())
1416 if (model.seq == jds)
1419 * VARNA saves each view (sequence or alignment secondary
1420 * structure, gapped or trimmed) as a separate XML file
1422 String jarEntryName = rnaSessions.get(model);
1423 if (jarEntryName == null)
1426 String varnaStateFile = varna.getStateInfo(model.rna);
1427 jarEntryName = RNA_PREFIX + viewId + "_"
1429 copyFileToJar(jout, varnaStateFile, jarEntryName);
1430 rnaSessions.put(model, jarEntryName);
1432 SecondaryStructure ss = new SecondaryStructure();
1433 String annotationId = varna.getAnnotation(jds).annotationId;
1434 ss.setAnnotationId(annotationId);
1435 ss.setViewerState(jarEntryName);
1436 ss.setGapped(model.gapped);
1437 ss.setTitle(model.title);
1438 rna.addSecondaryStructure(ss);
1447 * Copy the contents of a file to a new entry added to the output jar
1451 * @param jarEntryName
1453 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1454 String jarEntryName)
1456 DataInputStream dis = null;
1459 File file = new File(infilePath);
1460 if (file.exists() && jout != null)
1462 dis = new DataInputStream(new FileInputStream(file));
1463 byte[] data = new byte[(int) file.length()];
1464 dis.readFully(data);
1465 writeJarEntry(jout, jarEntryName, data);
1467 } catch (Exception ex)
1469 ex.printStackTrace();
1477 } catch (IOException e)
1486 * Write the data to a new entry of given name in the output jar file
1489 * @param jarEntryName
1491 * @throws IOException
1493 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1494 byte[] data) throws IOException
1498 System.out.println("Writing jar entry " + jarEntryName);
1499 jout.putNextEntry(new JarEntry(jarEntryName));
1500 DataOutputStream dout = new DataOutputStream(jout);
1501 dout.write(data, 0, data.length);
1508 * Save the state of a structure viewer
1513 * the archive XML element under which to save the state
1516 * @param matchedFile
1520 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1521 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1522 String matchedFile, StructureViewerBase viewFrame)
1524 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1527 * Look for any bindings for this viewer to the PDB file of interest
1528 * (including part matches excluding chain id)
1530 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1532 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1533 final String pdbId = pdbentry.getId();
1534 if (!pdbId.equals(entry.getId())
1535 && !(entry.getId().length() > 4 && entry.getId()
1536 .toLowerCase().startsWith(pdbId.toLowerCase())))
1539 * not interested in a binding to a different PDB entry here
1543 if (matchedFile == null)
1545 matchedFile = pdbentry.getFile();
1547 else if (!matchedFile.equals(pdbentry.getFile()))
1550 .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1551 + pdbentry.getFile());
1555 // can get at it if the ID
1556 // match is ambiguous (e.g.
1559 for (int smap = 0; smap < viewFrame.getBinding().getSequence()[peid].length; smap++)
1561 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1562 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1564 StructureState state = new StructureState();
1565 state.setVisible(true);
1566 state.setXpos(viewFrame.getX());
1567 state.setYpos(viewFrame.getY());
1568 state.setWidth(viewFrame.getWidth());
1569 state.setHeight(viewFrame.getHeight());
1570 final String viewId = viewFrame.getViewId();
1571 state.setViewId(viewId);
1572 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1573 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1574 state.setColourByJmol(viewFrame.isColouredByViewer());
1575 state.setType(viewFrame.getViewerType().toString());
1576 pdb.addStructureState(state);
1583 private AnnotationColours constructAnnotationColours(
1584 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1585 JalviewModelSequence jms)
1587 AnnotationColours ac = new AnnotationColours();
1588 ac.setAboveThreshold(acg.getAboveThreshold());
1589 ac.setThreshold(acg.getAnnotationThreshold());
1590 ac.setAnnotation(acg.getAnnotation());
1591 if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
1593 ac.setColourScheme(setUserColourScheme(acg.getBaseColour(),
1598 ac.setColourScheme(ColourSchemeProperty.getColourName(acg
1602 ac.setMaxColour(acg.getMaxColour().getRGB());
1603 ac.setMinColour(acg.getMinColour().getRGB());
1604 ac.setPerSequence(acg.isSeqAssociated());
1605 ac.setPredefinedColours(acg.isPredefinedColours());
1609 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1610 IdentityHashMap<SequenceGroup, String> groupRefs,
1611 AlignmentViewport av,
1612 Set<String> calcIdSet, boolean storeDS, SequenceSet vamsasSet)
1615 for (int i = 0; i < aa.length; i++)
1617 Annotation an = new Annotation();
1619 AlignmentAnnotation annotation = aa[i];
1620 if (annotation.annotationId != null)
1622 annotationIds.put(annotation.annotationId, annotation);
1625 an.setId(annotation.annotationId);
1627 an.setVisible(annotation.visible);
1629 an.setDescription(annotation.description);
1631 if (annotation.sequenceRef != null)
1633 // 2.9 JAL-1781 xref on sequence id rather than name
1634 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1636 if (annotation.groupRef != null)
1638 String groupIdr = groupRefs.get(annotation.groupRef);
1639 if (groupIdr == null)
1641 // make a locally unique String
1642 groupRefs.put(annotation.groupRef,
1643 groupIdr = ("" + System.currentTimeMillis()
1644 + annotation.groupRef.getName() + groupRefs.size()));
1646 an.setGroupRef(groupIdr.toString());
1649 // store all visualization attributes for annotation
1650 an.setGraphHeight(annotation.graphHeight);
1651 an.setCentreColLabels(annotation.centreColLabels);
1652 an.setScaleColLabels(annotation.scaleColLabel);
1653 an.setShowAllColLabels(annotation.showAllColLabels);
1654 an.setBelowAlignment(annotation.belowAlignment);
1656 if (annotation.graph > 0)
1659 an.setGraphType(annotation.graph);
1660 an.setGraphGroup(annotation.graphGroup);
1661 if (annotation.getThreshold() != null)
1663 ThresholdLine line = new ThresholdLine();
1664 line.setLabel(annotation.getThreshold().label);
1665 line.setValue(annotation.getThreshold().value);
1666 line.setColour(annotation.getThreshold().colour.getRGB());
1667 an.setThresholdLine(line);
1675 an.setLabel(annotation.label);
1677 if (annotation == av.getAlignmentQualityAnnot()
1678 || annotation == av.getAlignmentConservationAnnotation()
1679 || annotation == av.getAlignmentConsensusAnnotation()
1680 || annotation.autoCalculated)
1682 // new way of indicating autocalculated annotation -
1683 an.setAutoCalculated(annotation.autoCalculated);
1685 if (annotation.hasScore())
1687 an.setScore(annotation.getScore());
1690 if (annotation.getCalcId() != null)
1692 calcIdSet.add(annotation.getCalcId());
1693 an.setCalcId(annotation.getCalcId());
1695 if (annotation.hasProperties())
1697 for (String pr : annotation.getProperties())
1699 Property prop = new Property();
1701 prop.setValue(annotation.getProperty(pr));
1702 an.addProperty(prop);
1706 AnnotationElement ae;
1707 if (annotation.annotations != null)
1709 an.setScoreOnly(false);
1710 for (int a = 0; a < annotation.annotations.length; a++)
1712 if ((annotation == null) || (annotation.annotations[a] == null))
1717 ae = new AnnotationElement();
1718 if (annotation.annotations[a].description != null)
1720 ae.setDescription(annotation.annotations[a].description);
1722 if (annotation.annotations[a].displayCharacter != null)
1724 ae.setDisplayCharacter(annotation.annotations[a].displayCharacter);
1727 if (!Float.isNaN(annotation.annotations[a].value))
1729 ae.setValue(annotation.annotations[a].value);
1733 if (annotation.annotations[a].secondaryStructure > ' ')
1735 ae.setSecondaryStructure(annotation.annotations[a].secondaryStructure
1739 if (annotation.annotations[a].colour != null
1740 && annotation.annotations[a].colour != java.awt.Color.black)
1742 ae.setColour(annotation.annotations[a].colour.getRGB());
1745 an.addAnnotationElement(ae);
1746 if (annotation.autoCalculated)
1748 // only write one non-null entry into the annotation row -
1749 // sufficient to get the visualization attributes necessary to
1757 an.setScoreOnly(true);
1759 if (!storeDS || (storeDS && !annotation.autoCalculated))
1761 // skip autocalculated annotation - these are only provided for
1763 vamsasSet.addAnnotation(an);
1769 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1771 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1772 if (settings != null)
1774 CalcIdParam vCalcIdParam = new CalcIdParam();
1775 vCalcIdParam.setCalcId(calcId);
1776 vCalcIdParam.addServiceURL(settings.getServiceURI());
1777 // generic URI allowing a third party to resolve another instance of the
1778 // service used for this calculation
1779 for (String urls : settings.getServiceURLs())
1781 vCalcIdParam.addServiceURL(urls);
1783 vCalcIdParam.setVersion("1.0");
1784 if (settings.getPreset() != null)
1786 WsParamSetI setting = settings.getPreset();
1787 vCalcIdParam.setName(setting.getName());
1788 vCalcIdParam.setDescription(setting.getDescription());
1792 vCalcIdParam.setName("");
1793 vCalcIdParam.setDescription("Last used parameters");
1795 // need to be able to recover 1) settings 2) user-defined presets or
1796 // recreate settings from preset 3) predefined settings provided by
1797 // service - or settings that can be transferred (or discarded)
1798 vCalcIdParam.setParameters(settings.getWsParamFile().replace("\n",
1800 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1801 // todo - decide if updateImmediately is needed for any projects.
1803 return vCalcIdParam;
1808 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1811 if (calcIdParam.getVersion().equals("1.0"))
1813 Jws2Instance service = Jws2Discoverer.getDiscoverer()
1814 .getPreferredServiceFor(calcIdParam.getServiceURL());
1815 if (service != null)
1817 WsParamSetI parmSet = null;
1820 parmSet = service.getParamStore().parseServiceParameterFile(
1821 calcIdParam.getName(), calcIdParam.getDescription(),
1822 calcIdParam.getServiceURL(),
1823 calcIdParam.getParameters().replace("|\\n|", "\n"));
1824 } catch (IOException x)
1826 warn("Couldn't parse parameter data for "
1827 + calcIdParam.getCalcId(), x);
1830 List<ArgumentI> argList = null;
1831 if (calcIdParam.getName().length() > 0)
1833 parmSet = service.getParamStore()
1834 .getPreset(calcIdParam.getName());
1835 if (parmSet != null)
1837 // TODO : check we have a good match with settings in AACon -
1838 // otherwise we'll need to create a new preset
1843 argList = parmSet.getArguments();
1846 AAConSettings settings = new AAConSettings(
1847 calcIdParam.isAutoUpdate(), service, parmSet, argList);
1848 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
1849 calcIdParam.isNeedsUpdate());
1854 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
1858 throw new Error(MessageManager.formatMessage(
1859 "error.unsupported_version_calcIdparam", new Object[]
1860 { calcIdParam.toString() }));
1864 * External mapping between jalview objects and objects yielding a valid and
1865 * unique object ID string. This is null for normal Jalview project IO, but
1866 * non-null when a jalview project is being read or written as part of a
1869 IdentityHashMap jv2vobj = null;
1872 * Construct a unique ID for jvobj using either existing bindings or if none
1873 * exist, the result of the hashcode call for the object.
1876 * jalview data object
1877 * @return unique ID for referring to jvobj
1879 private String makeHashCode(Object jvobj, String altCode)
1881 if (jv2vobj != null)
1883 Object id = jv2vobj.get(jvobj);
1886 return id.toString();
1888 // check string ID mappings
1889 if (jvids2vobj != null && jvobj instanceof String)
1891 id = jvids2vobj.get(jvobj);
1895 return id.toString();
1897 // give up and warn that something has gone wrong
1898 warn("Cannot find ID for object in external mapping : " + jvobj);
1904 * return local jalview object mapped to ID, if it exists
1908 * @return null or object bound to idcode
1910 private Object retrieveExistingObj(String idcode)
1912 if (idcode != null && vobj2jv != null)
1914 return vobj2jv.get(idcode);
1920 * binding from ID strings from external mapping table to jalview data model
1923 private Hashtable vobj2jv;
1925 private Sequence createVamsasSequence(String id, SequenceI jds)
1927 return createVamsasSequence(true, id, jds, null);
1930 private Sequence createVamsasSequence(boolean recurse, String id,
1931 SequenceI jds, SequenceI parentseq)
1933 Sequence vamsasSeq = new Sequence();
1934 vamsasSeq.setId(id);
1935 vamsasSeq.setName(jds.getName());
1936 vamsasSeq.setSequence(jds.getSequenceAsString());
1937 vamsasSeq.setDescription(jds.getDescription());
1938 jalview.datamodel.DBRefEntry[] dbrefs = null;
1939 if (jds.getDatasetSequence() != null)
1941 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
1942 if (jds.getDatasetSequence().getDBRef() != null)
1944 dbrefs = jds.getDatasetSequence().getDBRef();
1949 vamsasSeq.setDsseqid(id); // so we can tell which sequences really are
1950 // dataset sequences only
1951 dbrefs = jds.getDBRef();
1955 for (int d = 0; d < dbrefs.length; d++)
1957 DBRef dbref = new DBRef();
1958 dbref.setSource(dbrefs[d].getSource());
1959 dbref.setVersion(dbrefs[d].getVersion());
1960 dbref.setAccessionId(dbrefs[d].getAccessionId());
1961 if (dbrefs[d].hasMap())
1963 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
1965 dbref.setMapping(mp);
1967 vamsasSeq.addDBRef(dbref);
1973 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
1974 SequenceI parentseq, SequenceI jds, boolean recurse)
1977 if (jmp.getMap() != null)
1981 MapList mlst = jmp.getMap();
1982 List<int[]> r = mlst.getFromRanges();
1983 for (int[] range : r)
1985 MapListFrom mfrom = new MapListFrom();
1986 mfrom.setStart(range[0]);
1987 mfrom.setEnd(range[1]);
1988 mp.addMapListFrom(mfrom);
1990 r = mlst.getToRanges();
1991 for (int[] range : r)
1993 MapListTo mto = new MapListTo();
1994 mto.setStart(range[0]);
1995 mto.setEnd(range[1]);
1996 mp.addMapListTo(mto);
1998 mp.setMapFromUnit(mlst.getFromRatio());
1999 mp.setMapToUnit(mlst.getToRatio());
2000 if (jmp.getTo() != null)
2002 MappingChoice mpc = new MappingChoice();
2004 && (parentseq != jmp.getTo() || parentseq
2005 .getDatasetSequence() != jmp.getTo()))
2007 mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()),
2013 SequenceI ps = null;
2014 if (parentseq != jmp.getTo()
2015 && parentseq.getDatasetSequence() != jmp.getTo())
2017 // chaining dbref rather than a handshaking one
2018 jmpid = seqHash(ps = jmp.getTo());
2022 jmpid = seqHash(ps = parentseq);
2024 mpc.setDseqFor(jmpid);
2025 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2027 Cache.log.debug("creatign new DseqFor ID");
2028 seqRefIds.put(mpc.getDseqFor(), ps);
2032 Cache.log.debug("reusing DseqFor ID");
2035 mp.setMappingChoice(mpc);
2041 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2042 List<UserColourScheme> userColours, JalviewModelSequence jms)
2045 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2046 boolean newucs = false;
2047 if (!userColours.contains(ucs))
2049 userColours.add(ucs);
2052 id = "ucs" + userColours.indexOf(ucs);
2055 // actually create the scheme's entry in the XML model
2056 java.awt.Color[] colours = ucs.getColours();
2057 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2058 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2060 for (int i = 0; i < colours.length; i++)
2062 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2063 col.setName(ResidueProperties.aa[i]);
2064 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2065 jbucs.addColour(col);
2067 if (ucs.getLowerCaseColours() != null)
2069 colours = ucs.getLowerCaseColours();
2070 for (int i = 0; i < colours.length; i++)
2072 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2073 col.setName(ResidueProperties.aa[i].toLowerCase());
2074 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2075 jbucs.addColour(col);
2080 uc.setUserColourScheme(jbucs);
2081 jms.addUserColours(uc);
2087 jalview.schemes.UserColourScheme getUserColourScheme(
2088 JalviewModelSequence jms, String id)
2090 UserColours[] uc = jms.getUserColours();
2091 UserColours colours = null;
2093 for (int i = 0; i < uc.length; i++)
2095 if (uc[i].getId().equals(id))
2103 java.awt.Color[] newColours = new java.awt.Color[24];
2105 for (int i = 0; i < 24; i++)
2107 newColours[i] = new java.awt.Color(Integer.parseInt(colours
2108 .getUserColourScheme().getColour(i).getRGB(), 16));
2111 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2114 if (colours.getUserColourScheme().getColourCount() > 24)
2116 newColours = new java.awt.Color[23];
2117 for (int i = 0; i < 23; i++)
2119 newColours[i] = new java.awt.Color(Integer.parseInt(colours
2120 .getUserColourScheme().getColour(i + 24).getRGB(), 16));
2122 ucs.setLowerCaseColours(newColours);
2129 * contains last error message (if any) encountered by XML loader.
2131 String errorMessage = null;
2134 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2135 * exceptions are raised during project XML parsing
2137 public boolean attemptversion1parse = true;
2140 * Load a jalview project archive from a jar file
2143 * - HTTP URL or filename
2145 public AlignFrame loadJalviewAlign(final String file)
2148 jalview.gui.AlignFrame af = null;
2152 // create list to store references for any new Jmol viewers created
2153 newStructureViewers = new Vector<JalviewStructureDisplayI>();
2154 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2155 // Workaround is to make sure caller implements the JarInputStreamProvider
2157 // so we can re-open the jar input stream for each entry.
2159 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2160 af = loadJalviewAlign(jprovider);
2162 } catch (MalformedURLException e)
2164 errorMessage = "Invalid URL format for '" + file + "'";
2170 SwingUtilities.invokeAndWait(new Runnable()
2174 setLoadingFinishedForNewStructureViewers();
2177 } catch (Exception x)
2179 System.err.println("Error loading alignment: " + x.getMessage());
2185 private jarInputStreamProvider createjarInputStreamProvider(
2186 final String file) throws MalformedURLException
2189 errorMessage = null;
2190 uniqueSetSuffix = null;
2192 viewportsAdded.clear();
2193 frefedSequence = null;
2195 if (file.startsWith("http://"))
2197 url = new URL(file);
2199 final URL _url = url;
2200 return new jarInputStreamProvider()
2204 public JarInputStream getJarInputStream() throws IOException
2208 return new JarInputStream(_url.openStream());
2212 return new JarInputStream(new FileInputStream(file));
2217 public String getFilename()
2225 * Recover jalview session from a jalview project archive. Caller may
2226 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2227 * themselves. Any null fields will be initialised with default values,
2228 * non-null fields are left alone.
2233 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2235 errorMessage = null;
2236 if (uniqueSetSuffix == null)
2238 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2240 if (seqRefIds == null)
2242 seqRefIds = new HashMap<String, SequenceI>();
2244 if (frefedSequence == null)
2246 frefedSequence = new Vector();
2249 AlignFrame af = null, _af = null;
2250 Map<String, AlignFrame> gatherToThisFrame = new HashMap<String, AlignFrame>();
2251 final String file = jprovider.getFilename();
2254 JarInputStream jin = null;
2255 JarEntry jarentry = null;
2260 jin = jprovider.getJarInputStream();
2261 for (int i = 0; i < entryCount; i++)
2263 jarentry = jin.getNextJarEntry();
2266 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2268 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2269 JalviewModel object = new JalviewModel();
2271 Unmarshaller unmar = new Unmarshaller(object);
2272 unmar.setValidation(false);
2273 object = (JalviewModel) unmar.unmarshal(in);
2274 if (true) // !skipViewport(object))
2276 _af = loadFromObject(object, file, true, jprovider);
2277 if (object.getJalviewModelSequence().getViewportCount() > 0)
2280 if (af.viewport.isGatherViewsHere())
2282 gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
2288 else if (jarentry != null)
2290 // Some other file here.
2293 } while (jarentry != null);
2294 resolveFrefedSequences();
2295 } catch (IOException ex)
2297 ex.printStackTrace();
2298 errorMessage = "Couldn't locate Jalview XML file : " + file;
2299 System.err.println("Exception whilst loading jalview XML file : "
2301 } catch (Exception ex)
2303 System.err.println("Parsing as Jalview Version 2 file failed.");
2304 ex.printStackTrace(System.err);
2305 if (attemptversion1parse)
2307 // Is Version 1 Jar file?
2310 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2311 } catch (Exception ex2)
2313 System.err.println("Exception whilst loading as jalviewXMLV1:");
2314 ex2.printStackTrace();
2318 if (Desktop.instance != null)
2320 Desktop.instance.stopLoading();
2324 System.out.println("Successfully loaded archive file");
2327 ex.printStackTrace();
2329 System.err.println("Exception whilst loading jalview XML file : "
2331 } catch (OutOfMemoryError e)
2333 // Don't use the OOM Window here
2334 errorMessage = "Out of memory loading jalview XML file";
2335 System.err.println("Out of memory whilst loading jalview XML file");
2336 e.printStackTrace();
2339 if (Desktop.instance != null)
2341 Desktop.instance.stopLoading();
2345 * Regather multiple views (with the same sequence set id) to the frame (if
2346 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2347 * views instead of separate frames. Note this doesn't restore a state where
2348 * some expanded views in turn have tabbed views - the last "first tab" read
2349 * in will play the role of gatherer for all.
2351 for (AlignFrame fr : gatherToThisFrame.values())
2353 Desktop.instance.gatherViews(fr);
2356 restoreSplitFrames();
2358 if (errorMessage != null)
2366 * Try to reconstruct and display SplitFrame windows, where each contains
2367 * complementary dna and protein alignments. Done by pairing up AlignFrame
2368 * objects (created earlier) which have complementary viewport ids associated.
2370 protected void restoreSplitFrames()
2372 List<SplitFrame> gatherTo = new ArrayList<SplitFrame>();
2373 List<AlignFrame> addedToSplitFrames = new ArrayList<AlignFrame>();
2374 Map<String, AlignFrame> dna = new HashMap<String, AlignFrame>();
2377 * Identify the DNA alignments
2379 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2382 AlignFrame af = candidate.getValue();
2383 if (af.getViewport().getAlignment().isNucleotide())
2385 dna.put(candidate.getKey().getId(), af);
2390 * Try to match up the protein complements
2392 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2395 AlignFrame af = candidate.getValue();
2396 if (!af.getViewport().getAlignment().isNucleotide())
2398 String complementId = candidate.getKey().getComplementId();
2399 // only non-null complements should be in the Map
2400 if (complementId != null && dna.containsKey(complementId))
2402 final AlignFrame dnaFrame = dna.get(complementId);
2403 SplitFrame sf = createSplitFrame(dnaFrame, af);
2404 addedToSplitFrames.add(dnaFrame);
2405 addedToSplitFrames.add(af);
2406 if (af.viewport.isGatherViewsHere())
2415 * Open any that we failed to pair up (which shouldn't happen!) as
2416 * standalone AlignFrame's.
2418 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2421 AlignFrame af = candidate.getValue();
2422 if (!addedToSplitFrames.contains(af)) {
2423 Viewport view = candidate.getKey();
2424 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2426 System.err.println("Failed to restore view " + view.getTitle()
2427 + " to split frame");
2432 * Gather back into tabbed views as flagged.
2434 for (SplitFrame sf : gatherTo)
2436 Desktop.instance.gatherViews(sf);
2439 splitFrameCandidates.clear();
2443 * Construct and display one SplitFrame holding DNA and protein alignments.
2446 * @param proteinFrame
2449 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2450 AlignFrame proteinFrame)
2452 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2453 String title = MessageManager.getString("label.linked_view_title");
2454 int width = (int) dnaFrame.getBounds().getWidth();
2455 int height = (int) (dnaFrame.getBounds().getHeight()
2456 + proteinFrame.getBounds().getHeight() + 50);
2457 Desktop.addInternalFrame(splitFrame, title, width, height);
2460 * And compute cDNA consensus (couldn't do earlier with consensus as
2461 * mappings were not yet present)
2463 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2469 * check errorMessage for a valid error message and raise an error box in the
2470 * GUI or write the current errorMessage to stderr and then clear the error
2473 protected void reportErrors()
2475 reportErrors(false);
2478 protected void reportErrors(final boolean saving)
2480 if (errorMessage != null)
2482 final String finalErrorMessage = errorMessage;
2485 javax.swing.SwingUtilities.invokeLater(new Runnable()
2490 JOptionPane.showInternalMessageDialog(Desktop.desktop,
2491 finalErrorMessage, "Error "
2492 + (saving ? "saving" : "loading")
2493 + " Jalview file", JOptionPane.WARNING_MESSAGE);
2499 System.err.println("Problem loading Jalview file: " + errorMessage);
2502 errorMessage = null;
2505 Map<String, String> alreadyLoadedPDB = new HashMap<String, String>();
2508 * when set, local views will be updated from view stored in JalviewXML
2509 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2510 * sync if this is set to true.
2512 private final boolean updateLocalViews = false;
2515 * Returns the path to a temporary file holding the PDB file for the given PDB
2516 * id. The first time of asking, searches for a file of that name in the
2517 * Jalview project jar, and copies it to a new temporary file. Any repeat
2518 * requests just return the path to the file previously created.
2524 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId)
2526 if (alreadyLoadedPDB.containsKey(pdbId))
2528 return alreadyLoadedPDB.get(pdbId).toString();
2531 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb");
2532 if (tempFile != null)
2534 alreadyLoadedPDB.put(pdbId, tempFile);
2540 * Copies the jar entry of given name to a new temporary file and returns the
2541 * path to the file, or null if the entry is not found.
2544 * @param jarEntryName
2546 * a prefix for the temporary file name, must be at least three
2550 protected String copyJarEntry(jarInputStreamProvider jprovider,
2551 String jarEntryName, String prefix)
2553 BufferedReader in = null;
2554 PrintWriter out = null;
2558 JarInputStream jin = jprovider.getJarInputStream();
2560 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2561 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2562 * FileInputStream(jprovider)); }
2565 JarEntry entry = null;
2568 entry = jin.getNextJarEntry();
2569 } while (entry != null && !entry.getName().equals(jarEntryName));
2572 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2573 File outFile = File.createTempFile(prefix, ".tmp");
2574 outFile.deleteOnExit();
2575 out = new PrintWriter(new FileOutputStream(outFile));
2578 while ((data = in.readLine()) != null)
2583 String t = outFile.getAbsolutePath();
2588 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2590 } catch (Exception ex)
2592 ex.printStackTrace();
2600 } catch (IOException e)
2614 private class JvAnnotRow
2616 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2623 * persisted version of annotation row from which to take vis properties
2625 public AlignmentAnnotation template;
2628 * original position of the annotation row in the alignment
2634 * Load alignment frame from jalview XML DOM object
2639 * filename source string
2640 * @param loadTreesAndStructures
2641 * when false only create Viewport
2643 * data source provider
2644 * @return alignment frame created from view stored in DOM
2646 AlignFrame loadFromObject(JalviewModel object, String file,
2647 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2649 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2650 Sequence[] vamsasSeq = vamsasSet.getSequence();
2652 JalviewModelSequence jms = object.getJalviewModelSequence();
2654 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2657 // ////////////////////////////////
2660 List<SequenceI> hiddenSeqs = null;
2661 jalview.datamodel.Sequence jseq;
2663 List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
2665 boolean multipleView = false;
2667 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2668 int vi = 0; // counter in vamsasSeq array
2669 for (int i = 0; i < jseqs.length; i++)
2671 String seqId = jseqs[i].getId();
2673 if (seqRefIds.get(seqId) != null)
2675 tmpseqs.add(seqRefIds.get(seqId));
2676 multipleView = true;
2680 jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2681 vamsasSeq[vi].getSequence());
2682 jseq.setDescription(vamsasSeq[vi].getDescription());
2683 jseq.setStart(jseqs[i].getStart());
2684 jseq.setEnd(jseqs[i].getEnd());
2685 jseq.setVamsasId(uniqueSetSuffix + seqId);
2686 seqRefIds.put(vamsasSeq[vi].getId(), jseq);
2691 if (jseqs[i].getHidden())
2693 if (hiddenSeqs == null)
2695 hiddenSeqs = new ArrayList<SequenceI>();
2698 hiddenSeqs.add(seqRefIds.get(seqId));
2704 // Create the alignment object from the sequence set
2705 // ///////////////////////////////
2706 SequenceI[] orderedSeqs = tmpseqs
2707 .toArray(new SequenceI[tmpseqs.size()]);
2709 Alignment al = new Alignment(orderedSeqs);
2711 // / Add the alignment properties
2712 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
2714 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
2715 al.setProperty(ssp.getKey(), ssp.getValue());
2719 // SequenceFeatures are added to the DatasetSequence,
2720 // so we must create or recover the dataset before loading features
2721 // ///////////////////////////////
2722 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2724 // older jalview projects do not have a dataset id.
2725 al.setDataset(null);
2729 // recover dataset - passing on flag indicating if this a 'viewless'
2730 // sequence set (a.k.a. a stored dataset for the project)
2731 recoverDatasetFor(vamsasSet, al, object.getJalviewModelSequence()
2732 .getViewportCount() == 0);
2734 // ///////////////////////////////
2736 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
2739 // load sequence features, database references and any associated PDB
2740 // structures for the alignment
2741 for (int i = 0; i < vamsasSeq.length; i++)
2743 if (jseqs[i].getFeaturesCount() > 0)
2745 Features[] features = jseqs[i].getFeatures();
2746 for (int f = 0; f < features.length; f++)
2748 jalview.datamodel.SequenceFeature sf = new jalview.datamodel.SequenceFeature(
2749 features[f].getType(), features[f].getDescription(),
2750 features[f].getStatus(), features[f].getBegin(),
2751 features[f].getEnd(), features[f].getFeatureGroup());
2753 sf.setScore(features[f].getScore());
2754 for (int od = 0; od < features[f].getOtherDataCount(); od++)
2756 OtherData keyValue = features[f].getOtherData(od);
2757 if (keyValue.getKey().startsWith("LINK"))
2759 sf.addLink(keyValue.getValue());
2763 sf.setValue(keyValue.getKey(), keyValue.getValue());
2768 al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf);
2771 if (vamsasSeq[i].getDBRefCount() > 0)
2773 addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
2775 if (jseqs[i].getPdbidsCount() > 0)
2777 Pdbids[] ids = jseqs[i].getPdbids();
2778 for (int p = 0; p < ids.length; p++)
2780 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
2781 entry.setId(ids[p].getId());
2782 if (ids[p].getType() != null)
2784 if (ids[p].getType().equalsIgnoreCase("PDB"))
2786 entry.setType(PDBEntry.Type.PDB);
2790 entry.setType(PDBEntry.Type.FILE);
2793 if (ids[p].getFile() != null)
2795 if (!pdbloaded.containsKey(ids[p].getFile()))
2797 entry.setFile(loadPDBFile(jprovider, ids[p].getId()));
2801 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
2804 StructureSelectionManager.getStructureSelectionManager(
2805 Desktop.instance).registerPDBEntry(entry);
2806 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
2810 } // end !multipleview
2812 // ///////////////////////////////
2813 // LOAD SEQUENCE MAPPINGS
2815 if (vamsasSet.getAlcodonFrameCount() > 0)
2817 // TODO Potentially this should only be done once for all views of an
2819 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
2820 for (int i = 0; i < alc.length; i++)
2822 AlignedCodonFrame cf = new AlignedCodonFrame();
2823 if (alc[i].getAlcodMapCount() > 0)
2825 AlcodMap[] maps = alc[i].getAlcodMap();
2826 for (int m = 0; m < maps.length; m++)
2828 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
2830 jalview.datamodel.Mapping mapping = null;
2831 // attach to dna sequence reference.
2832 if (maps[m].getMapping() != null)
2834 mapping = addMapping(maps[m].getMapping());
2838 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
2843 frefedSequence.add(new Object[]
2844 { maps[m].getDnasq(), cf, mapping });
2848 al.addCodonFrame(cf);
2852 // ////////////////////////////////
2854 List<JvAnnotRow> autoAlan = new ArrayList<JvAnnotRow>();
2857 * store any annotations which forward reference a group's ID
2859 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String, List<AlignmentAnnotation>>();
2861 if (vamsasSet.getAnnotationCount() > 0)
2863 Annotation[] an = vamsasSet.getAnnotation();
2865 for (int i = 0; i < an.length; i++)
2867 Annotation annotation = an[i];
2870 * test if annotation is automatically calculated for this view only
2872 boolean autoForView = false;
2873 if (annotation.getLabel().equals("Quality")
2874 || annotation.getLabel().equals("Conservation")
2875 || annotation.getLabel().equals("Consensus"))
2877 // Kludge for pre 2.5 projects which lacked the autocalculated flag
2879 if (!annotation.hasAutoCalculated())
2881 annotation.setAutoCalculated(true);
2885 || (annotation.hasAutoCalculated() && annotation
2886 .isAutoCalculated()))
2888 // remove ID - we don't recover annotation from other views for
2889 // view-specific annotation
2890 annotation.setId(null);
2893 // set visiblity for other annotation in this view
2894 String annotationId = annotation.getId();
2895 if (annotationId != null
2896 && annotationIds.containsKey(annotationId))
2898 AlignmentAnnotation jda = annotationIds.get(annotationId);
2899 // in principle Visible should always be true for annotation displayed
2900 // in multiple views
2901 if (annotation.hasVisible())
2903 jda.visible = annotation.getVisible();
2906 al.addAnnotation(jda);
2910 // Construct new annotation from model.
2911 AnnotationElement[] ae = annotation.getAnnotationElement();
2912 jalview.datamodel.Annotation[] anot = null;
2913 java.awt.Color firstColour = null;
2915 if (!annotation.getScoreOnly())
2917 anot = new jalview.datamodel.Annotation[al.getWidth()];
2918 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
2920 anpos = ae[aa].getPosition();
2922 if (anpos >= anot.length)
2927 anot[anpos] = new jalview.datamodel.Annotation(
2929 ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
2930 (ae[aa].getSecondaryStructure() == null || ae[aa]
2931 .getSecondaryStructure().length() == 0) ? ' '
2932 : ae[aa].getSecondaryStructure().charAt(0),
2936 // JBPNote: Consider verifying dataflow for IO of secondary
2937 // structure annotation read from Stockholm files
2938 // this was added to try to ensure that
2939 // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
2941 // anot[ae[aa].getPosition()].displayCharacter = "";
2943 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
2944 if (firstColour == null)
2946 firstColour = anot[anpos].colour;
2950 AlignmentAnnotation jaa = null;
2952 if (annotation.getGraph())
2954 float llim = 0, hlim = 0;
2955 // if (autoForView || an[i].isAutoCalculated()) {
2958 jaa = new AlignmentAnnotation(
2959 annotation.getLabel(), annotation.getDescription(), anot,
2960 llim, hlim, annotation.getGraphType());
2962 jaa.graphGroup = annotation.getGraphGroup();
2963 jaa._linecolour = firstColour;
2964 if (annotation.getThresholdLine() != null)
2966 jaa.setThreshold(new jalview.datamodel.GraphLine(annotation
2967 .getThresholdLine().getValue(), annotation
2968 .getThresholdLine().getLabel(), new java.awt.Color(
2969 annotation.getThresholdLine().getColour())));
2972 if (autoForView || annotation.isAutoCalculated())
2974 // Hardwire the symbol display line to ensure that labels for
2975 // histograms are displayed
2981 jaa = new AlignmentAnnotation(an[i].getLabel(),
2982 an[i].getDescription(), anot);
2983 jaa._linecolour = firstColour;
2985 // register new annotation
2986 if (an[i].getId() != null)
2988 annotationIds.put(an[i].getId(), jaa);
2989 jaa.annotationId = an[i].getId();
2991 // recover sequence association
2992 String sequenceRef = an[i].getSequenceRef();
2993 if (sequenceRef != null)
2995 // from 2.9 sequenceRef is to sequence id (JAL-1781)
2996 SequenceI sequence = seqRefIds.get(sequenceRef);
2997 if (sequence == null)
2999 // in pre-2.9 projects sequence ref is to sequence name
3000 sequence = al.findName(sequenceRef);
3002 if (sequence != null)
3004 jaa.createSequenceMapping(sequence, 1, true);
3005 sequence.addAlignmentAnnotation(jaa);
3008 // and make a note of any group association
3009 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3011 List<AlignmentAnnotation> aal = groupAnnotRefs
3012 .get(an[i].getGroupRef());
3015 aal = new ArrayList<AlignmentAnnotation>();
3016 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3021 if (an[i].hasScore())
3023 jaa.setScore(an[i].getScore());
3025 if (an[i].hasVisible())
3027 jaa.visible = an[i].getVisible();
3030 if (an[i].hasCentreColLabels())
3032 jaa.centreColLabels = an[i].getCentreColLabels();
3035 if (an[i].hasScaleColLabels())
3037 jaa.scaleColLabel = an[i].getScaleColLabels();
3039 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3041 // newer files have an 'autoCalculated' flag and store calculation
3042 // state in viewport properties
3043 jaa.autoCalculated = true; // means annotation will be marked for
3044 // update at end of load.
3046 if (an[i].hasGraphHeight())
3048 jaa.graphHeight = an[i].getGraphHeight();
3050 if (an[i].hasBelowAlignment())
3052 jaa.belowAlignment = an[i].isBelowAlignment();
3054 jaa.setCalcId(an[i].getCalcId());
3055 if (an[i].getPropertyCount() > 0)
3057 for (jalview.schemabinding.version2.Property prop : an[i]
3060 jaa.setProperty(prop.getName(), prop.getValue());
3063 if (jaa.autoCalculated)
3065 autoAlan.add(new JvAnnotRow(i, jaa));
3068 // if (!autoForView)
3070 // add autocalculated group annotation and any user created annotation
3072 al.addAnnotation(jaa);
3076 // ///////////////////////
3078 // Create alignment markup and styles for this view
3079 if (jms.getJGroupCount() > 0)
3081 JGroup[] groups = jms.getJGroup();
3082 boolean addAnnotSchemeGroup = false;
3083 for (int i = 0; i < groups.length; i++)
3085 JGroup jGroup = groups[i];
3086 ColourSchemeI cs = null;
3087 if (jGroup.getColour() != null)
3089 if (jGroup.getColour().startsWith("ucs"))
3091 cs = getUserColourScheme(jms, jGroup.getColour());
3093 else if (jGroup.getColour().equals("AnnotationColourGradient")
3094 && jGroup.getAnnotationColours() != null)
3096 addAnnotSchemeGroup = true;
3101 cs = ColourSchemeProperty.getColour(al, jGroup.getColour());
3106 cs.setThreshold(jGroup.getPidThreshold(), true);
3110 Vector<SequenceI> seqs = new Vector<SequenceI>();
3112 for (int s = 0; s < jGroup.getSeqCount(); s++)
3114 String seqId = jGroup.getSeq(s) + "";
3115 SequenceI ts = seqRefIds.get(seqId);
3119 seqs.addElement(ts);
3123 if (seqs.size() < 1)
3128 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3129 jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3130 jGroup.getColourText(), jGroup.getStart(),
3133 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3135 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3136 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3137 sg.setShowNonconserved(jGroup.hasShowUnconserved() ? jGroup
3138 .isShowUnconserved() : false);
3139 sg.thresholdTextColour = jGroup.getTextColThreshold();
3140 if (jGroup.hasShowConsensusHistogram())
3142 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3145 if (jGroup.hasShowSequenceLogo())
3147 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3149 if (jGroup.hasNormaliseSequenceLogo())
3151 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3153 if (jGroup.hasIgnoreGapsinConsensus())
3155 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3157 if (jGroup.getConsThreshold() != 0)
3159 jalview.analysis.Conservation c = new jalview.analysis.Conservation(
3160 "All", ResidueProperties.propHash, 3,
3161 sg.getSequences(null), 0, sg.getWidth() - 1);
3163 c.verdict(false, 25);
3164 sg.cs.setConservation(c);
3167 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3169 // re-instate unique group/annotation row reference
3170 List<AlignmentAnnotation> jaal = groupAnnotRefs
3171 .get(jGroup.getId());
3174 for (AlignmentAnnotation jaa : jaal)
3177 if (jaa.autoCalculated)
3179 // match up and try to set group autocalc alignment row for this
3181 if (jaa.label.startsWith("Consensus for "))
3183 sg.setConsensus(jaa);
3185 // match up and try to set group autocalc alignment row for this
3187 if (jaa.label.startsWith("Conservation for "))
3189 sg.setConservationRow(jaa);
3196 if (addAnnotSchemeGroup)
3198 // reconstruct the annotation colourscheme
3199 sg.cs = constructAnnotationColour(
3200 jGroup.getAnnotationColours(), null, al, jms, false);
3206 // only dataset in this model, so just return.
3209 // ///////////////////////////////
3212 // If we just load in the same jar file again, the sequenceSetId
3213 // will be the same, and we end up with multiple references
3214 // to the same sequenceSet. We must modify this id on load
3215 // so that each load of the file gives a unique id
3216 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3217 String viewId = (view.getId() == null ? null : view.getId()
3219 AlignFrame af = null;
3220 AlignViewport av = null;
3221 // now check to see if we really need to create a new viewport.
3222 if (multipleView && viewportsAdded.size() == 0)
3224 // We recovered an alignment for which a viewport already exists.
3225 // TODO: fix up any settings necessary for overlaying stored state onto
3226 // state recovered from another document. (may not be necessary).
3227 // we may need a binding from a viewport in memory to one recovered from
3229 // and then recover its containing af to allow the settings to be applied.
3230 // TODO: fix for vamsas demo
3232 .println("About to recover a viewport for existing alignment: Sequence set ID is "
3234 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3235 if (seqsetobj != null)
3237 if (seqsetobj instanceof String)
3239 uniqueSeqSetId = (String) seqsetobj;
3241 .println("Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3247 .println("Warning : Collision between sequence set ID string and existing jalview object mapping.");
3253 * indicate that annotation colours are applied across all groups (pre
3254 * Jalview 2.8.1 behaviour)
3256 boolean doGroupAnnColour = isVersionStringLaterThan("2.8.1",
3257 object.getVersion());
3259 AlignmentPanel ap = null;
3260 boolean isnewview = true;
3263 // Check to see if this alignment already has a view id == viewId
3264 jalview.gui.AlignmentPanel views[] = Desktop
3265 .getAlignmentPanels(uniqueSeqSetId);
3266 if (views != null && views.length > 0)
3268 for (int v = 0; v < views.length; v++)
3270 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3272 // recover the existing alignpanel, alignframe, viewport
3273 af = views[v].alignFrame;
3276 // TODO: could even skip resetting view settings if we don't want to
3277 // change the local settings from other jalview processes
3286 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3287 uniqueSeqSetId, viewId, autoAlan);
3293 * Load any trees, PDB structures and viewers
3295 * Not done if flag is false (when this method is used for New View)
3297 if (loadTreesAndStructures)
3299 loadTrees(jms, view, af, av, ap);
3300 loadPDBStructures(jprovider, jseqs, af, ap);
3301 loadRnaViewers(jprovider, jseqs, ap);
3303 // and finally return.
3308 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3309 * panel is restored from separate jar entries, two (gapped and trimmed) per
3310 * sequence and secondary structure.
3312 * Currently each viewer shows just one sequence and structure (gapped and
3313 * trimmed), however this method is designed to support multiple sequences or
3314 * structures in viewers if wanted in future.
3320 private void loadRnaViewers(jarInputStreamProvider jprovider,
3321 JSeq[] jseqs, AlignmentPanel ap)
3324 * scan the sequences for references to viewers; create each one the first
3325 * time it is referenced, add Rna models to existing viewers
3327 for (JSeq jseq : jseqs)
3329 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3331 RnaViewer viewer = jseq.getRnaViewer(i);
3332 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3335 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3337 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3338 SequenceI seq = seqRefIds.get(jseq.getId());
3339 AlignmentAnnotation ann = this.annotationIds.get(ss
3340 .getAnnotationId());
3343 * add the structure to the Varna display (with session state copied
3344 * from the jar to a temporary file)
3346 boolean gapped = ss.isGapped();
3347 String rnaTitle = ss.getTitle();
3348 String sessionState = ss.getViewerState();
3349 String tempStateFile = copyJarEntry(jprovider, sessionState,
3351 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3352 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3354 appVarna.setInitialSelection(viewer.getSelectedRna());
3360 * Locate and return an already instantiated matching AppVarna, or create one
3364 * @param viewIdSuffix
3368 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3369 String viewIdSuffix, AlignmentPanel ap)
3372 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3373 * if load is repeated
3375 String postLoadId = viewer.getViewId() + viewIdSuffix;
3376 for (JInternalFrame frame : getAllFrames())
3378 if (frame instanceof AppVarna)
3380 AppVarna varna = (AppVarna) frame;
3381 if (postLoadId.equals(varna.getViewId()))
3383 // this viewer is already instantiated
3384 // could in future here add ap as another 'parent' of the
3385 // AppVarna window; currently just 1-to-many
3392 * viewer not found - make it
3394 RnaViewerModel model = new RnaViewerModel(postLoadId,
3395 viewer.getTitle(), viewer.getXpos(),
3396 viewer.getYpos(), viewer.getWidth(), viewer.getHeight(),
3397 viewer.getDividerLocation());
3398 AppVarna varna = new AppVarna(model, ap);
3404 * Load any saved trees
3412 protected void loadTrees(JalviewModelSequence jms, Viewport view,
3413 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3415 // TODO result of automated refactoring - are all these parameters needed?
3418 for (int t = 0; t < jms.getTreeCount(); t++)
3421 Tree tree = jms.getTree(t);
3423 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3426 tp = af.ShowNewickTree(
3427 new jalview.io.NewickFile(tree.getNewick()),
3428 tree.getTitle(), tree.getWidth(), tree.getHeight(),
3429 tree.getXpos(), tree.getYpos());
3430 if (tree.getId() != null)
3432 // perhaps bind the tree id to something ?
3437 // update local tree attributes ?
3438 // TODO: should check if tp has been manipulated by user - if so its
3439 // settings shouldn't be modified
3440 tp.setTitle(tree.getTitle());
3441 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(), tree
3442 .getWidth(), tree.getHeight()));
3443 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3446 tp.treeCanvas.av = av; // af.viewport;
3447 tp.treeCanvas.ap = ap; // af.alignPanel;
3452 warn("There was a problem recovering stored Newick tree: \n"
3453 + tree.getNewick());
3457 tp.fitToWindow.setState(tree.getFitToWindow());
3458 tp.fitToWindow_actionPerformed(null);
3460 if (tree.getFontName() != null)
3462 tp.setTreeFont(new java.awt.Font(tree.getFontName(), tree
3463 .getFontStyle(), tree.getFontSize()));
3467 tp.setTreeFont(new java.awt.Font(view.getFontName(), view
3468 .getFontStyle(), tree.getFontSize()));
3471 tp.showPlaceholders(tree.getMarkUnlinked());
3472 tp.showBootstrap(tree.getShowBootstrap());
3473 tp.showDistances(tree.getShowDistances());
3475 tp.treeCanvas.threshold = tree.getThreshold();
3477 if (tree.getCurrentTree())
3479 af.viewport.setCurrentTree(tp.getTree());
3483 } catch (Exception ex)
3485 ex.printStackTrace();
3490 * Load and link any saved structure viewers.
3497 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3498 JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3501 * Run through all PDB ids on the alignment, and collect mappings between
3502 * distinct view ids and all sequences referring to that view.
3504 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<String, StructureViewerModel>();
3506 for (int i = 0; i < jseqs.length; i++)
3508 if (jseqs[i].getPdbidsCount() > 0)
3510 Pdbids[] ids = jseqs[i].getPdbids();
3511 for (int p = 0; p < ids.length; p++)
3513 final int structureStateCount = ids[p].getStructureStateCount();
3514 for (int s = 0; s < structureStateCount; s++)
3516 // check to see if we haven't already created this structure view
3517 final StructureState structureState = ids[p]
3518 .getStructureState(s);
3519 String sviewid = (structureState.getViewId() == null) ? null
3520 : structureState.getViewId() + uniqueSetSuffix;
3521 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3522 // Originally : ids[p].getFile()
3523 // : TODO: verify external PDB file recovery still works in normal
3524 // jalview project load
3525 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId()));
3526 jpdb.setId(ids[p].getId());
3528 int x = structureState.getXpos();
3529 int y = structureState.getYpos();
3530 int width = structureState.getWidth();
3531 int height = structureState.getHeight();
3533 // Probably don't need to do this anymore...
3534 // Desktop.desktop.getComponentAt(x, y);
3535 // TODO: NOW: check that this recovers the PDB file correctly.
3536 String pdbFile = loadPDBFile(jprovider, ids[p].getId());
3537 jalview.datamodel.SequenceI seq = seqRefIds.get(jseqs[i]
3539 if (sviewid == null)
3541 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
3544 if (!structureViewers.containsKey(sviewid))
3546 structureViewers.put(sviewid,
3547 new StructureViewerModel(x, y, width, height, false,
3548 false, true, structureState.getViewId(),
3549 structureState.getType()));
3550 // Legacy pre-2.7 conversion JAL-823 :
3551 // do not assume any view has to be linked for colour by
3555 // assemble String[] { pdb files }, String[] { id for each
3556 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3557 // seqs_file 2}, boolean[] {
3558 // linkAlignPanel,superposeWithAlignpanel}} from hash
3559 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3560 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3561 | (structureState.hasAlignwithAlignPanel() ? structureState
3562 .getAlignwithAlignPanel() : false));
3565 * Default colour by linked panel to false if not specified (e.g.
3566 * for pre-2.7 projects)
3568 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3569 colourWithAlignPanel |= (structureState
3570 .hasColourwithAlignPanel() ? structureState
3571 .getColourwithAlignPanel() : false);
3572 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3575 * Default colour by viewer to true if not specified (e.g. for
3578 boolean colourByViewer = jmoldat.isColourByViewer();
3579 colourByViewer &= structureState.hasColourByJmol() ? structureState
3580 .getColourByJmol() : true;
3581 jmoldat.setColourByViewer(colourByViewer);
3583 if (jmoldat.getStateData().length() < structureState
3584 .getContent().length())
3587 jmoldat.setStateData(structureState.getContent());
3590 if (ids[p].getFile() != null)
3592 File mapkey = new File(ids[p].getFile());
3593 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3594 if (seqstrmaps == null)
3596 jmoldat.getFileData().put(
3598 seqstrmaps = jmoldat.new StructureData(pdbFile,
3601 if (!seqstrmaps.getSeqList().contains(seq))
3603 seqstrmaps.getSeqList().add(seq);
3609 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");
3616 // Instantiate the associated structure views
3617 for (Entry<String, StructureViewerModel> entry : structureViewers
3622 createOrLinkStructureViewer(entry, af, ap, jprovider);
3623 } catch (Exception e)
3625 System.err.println("Error loading structure viewer: "
3627 // failed - try the next one
3639 protected void createOrLinkStructureViewer(
3640 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3641 AlignmentPanel ap, jarInputStreamProvider jprovider)
3643 final StructureViewerModel stateData = viewerData.getValue();
3646 * Search for any viewer windows already open from other alignment views
3647 * that exactly match the stored structure state
3649 StructureViewerBase comp = findMatchingViewer(viewerData);
3653 linkStructureViewer(ap, comp, stateData);
3658 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3659 * "viewer_"+stateData.viewId
3661 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
3663 createChimeraViewer(viewerData, af, jprovider);
3668 * else Jmol (if pre-2.9, stateData contains JMOL state string)
3670 createJmolViewer(viewerData, af, jprovider);
3675 * Create a new Chimera viewer.
3681 protected void createChimeraViewer(Entry<String, StructureViewerModel> viewerData,
3683 jarInputStreamProvider jprovider)
3685 StructureViewerModel data = viewerData.getValue();
3686 String chimeraSessionFile = data.getStateData();
3689 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
3691 * NB this is the 'saved' viewId as in the project file XML, _not_ the
3692 * 'uniquified' sviewid used to reconstruct the viewer here
3694 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
3695 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
3698 Set<Entry<File, StructureData>> fileData = data.getFileData()
3700 List<PDBEntry> pdbs = new ArrayList<PDBEntry>();
3701 List<SequenceI[]> allseqs = new ArrayList<SequenceI[]>();
3702 for (Entry<File, StructureData> pdb : fileData)
3704 String filePath = pdb.getValue().getFilePath();
3705 String pdbId = pdb.getValue().getPdbId();
3706 // pdbs.add(new PDBEntry(filePath, pdbId));
3707 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
3708 final List<SequenceI> seqList = pdb.getValue().getSeqList();
3709 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
3713 boolean colourByChimera = data.isColourByViewer();
3714 boolean colourBySequence = data.isColourWithAlignPanel();
3716 // TODO use StructureViewer as a factory here, see JAL-1761
3717 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
3718 final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs
3720 String newViewId = viewerData.getKey();
3722 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
3723 af.alignPanel, pdbArray,
3724 seqsArray, colourByChimera, colourBySequence, newViewId);
3725 cvf.setSize(data.getWidth(), data.getHeight());
3726 cvf.setLocation(data.getX(), data.getY());
3730 * Create a new Jmol window. First parse the Jmol state to translate filenames
3731 * loaded into the view, and record the order in which files are shown in the
3732 * Jmol view, so we can add the sequence mappings in same order.
3738 protected void createJmolViewer(
3739 final Entry<String, StructureViewerModel> viewerData,
3740 AlignFrame af, jarInputStreamProvider jprovider)
3742 final StructureViewerModel svattrib = viewerData.getValue();
3743 String state = svattrib.getStateData();
3746 * Pre-2.9: state element value is the Jmol state string
3748 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
3751 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
3753 state = readJarEntry(jprovider,
3754 getViewerJarEntryName(svattrib.getViewId()));
3757 List<String> pdbfilenames = new ArrayList<String>();
3758 List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
3759 List<String> pdbids = new ArrayList<String>();
3760 StringBuilder newFileLoc = new StringBuilder(64);
3761 int cp = 0, ncp, ecp;
3762 Map<File, StructureData> oldFiles = svattrib.getFileData();
3763 while ((ncp = state.indexOf("load ", cp)) > -1)
3767 // look for next filename in load statement
3768 newFileLoc.append(state.substring(cp,
3769 ncp = (state.indexOf("\"", ncp + 1) + 1)));
3770 String oldfilenam = state.substring(ncp,
3771 ecp = state.indexOf("\"", ncp));
3772 // recover the new mapping data for this old filename
3773 // have to normalize filename - since Jmol and jalview do
3775 // translation differently.
3776 StructureData filedat = oldFiles.get(new File(oldfilenam));
3777 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
3778 pdbfilenames.add(filedat.getFilePath());
3779 pdbids.add(filedat.getPdbId());
3780 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
3781 newFileLoc.append("\"");
3782 cp = ecp + 1; // advance beyond last \" and set cursor so we can
3783 // look for next file statement.
3784 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
3788 // just append rest of state
3789 newFileLoc.append(state.substring(cp));
3793 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
3794 newFileLoc = new StringBuilder(state);
3795 newFileLoc.append("; load append ");
3796 for (File id : oldFiles.keySet())
3798 // add this and any other pdb files that should be present in
3800 StructureData filedat = oldFiles.get(id);
3801 newFileLoc.append(filedat.getFilePath());
3802 pdbfilenames.add(filedat.getFilePath());
3803 pdbids.add(filedat.getPdbId());
3804 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
3805 newFileLoc.append(" \"");
3806 newFileLoc.append(filedat.getFilePath());
3807 newFileLoc.append("\"");
3810 newFileLoc.append(";");
3813 if (newFileLoc.length() > 0)
3815 int histbug = newFileLoc.indexOf("history = ");
3817 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
3818 String val = (diff == -1) ? null : newFileLoc
3819 .substring(histbug, diff);
3820 if (val != null && val.length() >= 4)
3822 if (val.contains("e"))
3824 if (val.trim().equals("true"))
3832 newFileLoc.replace(histbug, diff, val);
3836 final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames
3838 final String[] id = pdbids.toArray(new String[pdbids.size()]);
3839 final SequenceI[][] sq = seqmaps
3840 .toArray(new SequenceI[seqmaps.size()][]);
3841 final String fileloc = newFileLoc.toString();
3842 final String sviewid = viewerData.getKey();
3843 final AlignFrame alf = af;
3844 final Rectangle rect = new Rectangle(svattrib.getX(),
3845 svattrib.getY(), svattrib.getWidth(), svattrib.getHeight());
3848 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
3853 JalviewStructureDisplayI sview = null;
3856 sview = new StructureViewer(alf.alignPanel
3857 .getStructureSelectionManager()).createView(
3858 StructureViewer.ViewerType.JMOL, pdbf, id, sq,
3859 alf.alignPanel, svattrib, fileloc, rect, sviewid);
3860 addNewStructureViewer(sview);
3861 } catch (OutOfMemoryError ex)
3863 new OOMWarning("restoring structure view for PDB id " + id,
3864 (OutOfMemoryError) ex.getCause());
3865 if (sview != null && sview.isVisible())
3867 sview.closeViewer(false);
3868 sview.setVisible(false);
3874 } catch (InvocationTargetException ex)
3876 warn("Unexpected error when opening Jmol view.", ex);
3878 } catch (InterruptedException e)
3880 // e.printStackTrace();
3886 * Generates a name for the entry in the project jar file to hold state
3887 * information for a structure viewer
3892 protected String getViewerJarEntryName(String viewId)
3894 return VIEWER_PREFIX + viewId;
3898 * Returns any open frame that matches given structure viewer data. The match
3899 * is based on the unique viewId, or (for older project versions) the frame's
3905 protected StructureViewerBase findMatchingViewer(
3906 Entry<String, StructureViewerModel> viewerData)
3908 final String sviewid = viewerData.getKey();
3909 final StructureViewerModel svattrib = viewerData.getValue();
3910 StructureViewerBase comp = null;
3911 JInternalFrame[] frames = getAllFrames();
3912 for (JInternalFrame frame : frames)
3914 if (frame instanceof StructureViewerBase)
3917 * Post jalview 2.4 schema includes structure view id
3920 && ((StructureViewerBase) frame).getViewId()
3923 comp = (StructureViewerBase) frame;
3924 break; // break added in 2.9
3927 * Otherwise test for matching position and size of viewer frame
3929 else if (frame.getX() == svattrib.getX()
3930 && frame.getY() == svattrib.getY()
3931 && frame.getHeight() == svattrib.getHeight()
3932 && frame.getWidth() == svattrib.getWidth())
3934 comp = (StructureViewerBase) frame;
3935 // no break in faint hope of an exact match on viewId
3943 * Link an AlignmentPanel to an existing structure viewer.
3948 * @param useinViewerSuperpos
3949 * @param usetoColourbyseq
3950 * @param viewerColouring
3952 protected void linkStructureViewer(AlignmentPanel ap,
3953 StructureViewerBase viewer, StructureViewerModel stateData)
3955 // NOTE: if the jalview project is part of a shared session then
3956 // view synchronization should/could be done here.
3958 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
3959 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
3960 final boolean viewerColouring = stateData.isColourByViewer();
3961 Map<File, StructureData> oldFiles = stateData.getFileData();
3964 * Add mapping for sequences in this view to an already open viewer
3966 final AAStructureBindingModel binding = viewer.getBinding();
3967 for (File id : oldFiles.keySet())
3969 // add this and any other pdb files that should be present in the
3971 StructureData filedat = oldFiles.get(id);
3972 String pdbFile = filedat.getFilePath();
3973 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
3974 binding.getSsm().setMapping(seq, null, pdbFile,
3975 AppletFormatAdapter.FILE);
3976 binding.addSequenceForStructFile(pdbFile, seq);
3978 // and add the AlignmentPanel's reference to the view panel
3979 viewer.addAlignmentPanel(ap);
3980 if (useinViewerSuperpos)
3982 viewer.useAlignmentPanelForSuperposition(ap);
3986 viewer.excludeAlignmentPanelForSuperposition(ap);
3988 if (usetoColourbyseq)
3990 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
3994 viewer.excludeAlignmentPanelForColourbyseq(ap);
3999 * Get all frames within the Desktop.
4003 protected JInternalFrame[] getAllFrames()
4005 JInternalFrame[] frames = null;
4006 // TODO is this necessary - is it safe - risk of hanging?
4011 frames = Desktop.desktop.getAllFrames();
4012 } catch (ArrayIndexOutOfBoundsException e)
4014 // occasional No such child exceptions are thrown here...
4018 } catch (InterruptedException f)
4022 } while (frames == null);
4029 * - minimum version we are comparing against
4031 * - version of data being processsed.
4032 * @return true if version is development/null or evaluates to the same or
4033 * later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
4035 protected boolean isVersionStringLaterThan(String supported,
4038 if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4039 || version.equalsIgnoreCase("Test")
4040 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4042 System.err.println("Assuming project file with "
4043 + (version == null ? "null" : version)
4044 + " is compatible with Jalview version " + supported);
4049 StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer(
4051 while (currentV.hasMoreTokens() && fileV.hasMoreTokens())
4053 // convert b to decimal to catch bugfix releases within a series
4054 String curT = currentV.nextToken().toLowerCase().replace('b', '.');
4055 String fileT = fileV.nextToken().toLowerCase().replace('b', '.');
4058 if (Float.valueOf(curT) > Float.valueOf(fileT))
4060 // current version is newer than the version that wrote the file
4063 } catch (NumberFormatException nfe)
4066 .println("** WARNING: Version comparison failed for tokens ("
4070 + ")\n** Current: '"
4071 + supported + "' and Version: '" + version + "'");
4074 if (currentV.hasMoreElements())
4076 // fileV has no minor version but identical series to current
4083 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4085 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4087 if (newStructureViewers != null)
4089 sview.getBinding().setFinishedLoadingFromArchive(false);
4090 newStructureViewers.add(sview);
4094 protected void setLoadingFinishedForNewStructureViewers()
4096 if (newStructureViewers != null)
4098 for (JalviewStructureDisplayI sview : newStructureViewers)
4100 sview.getBinding().setFinishedLoadingFromArchive(true);
4102 newStructureViewers.clear();
4103 newStructureViewers = null;
4107 AlignFrame loadViewport(String file, JSeq[] JSEQ,
4108 List<SequenceI> hiddenSeqs, Alignment al,
4109 JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4110 String viewId, List<JvAnnotRow> autoAlan)
4112 AlignFrame af = null;
4113 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4114 uniqueSeqSetId, viewId);
4116 af.setFileName(file, "Jalview");
4118 for (int i = 0; i < JSEQ.length; i++)
4120 af.viewport.setSequenceColour(af.viewport.getAlignment()
4121 .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
4124 af.viewport.setGatherViewsHere(view.getGatheredViews());
4126 if (view.getSequenceSetId() != null)
4128 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4130 af.viewport.setSequenceSetId(uniqueSeqSetId);
4133 // propagate shared settings to this new view
4134 af.viewport.setHistoryList(av.getHistoryList());
4135 af.viewport.setRedoList(av.getRedoList());
4139 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4141 // TODO: check if this method can be called repeatedly without
4142 // side-effects if alignpanel already registered.
4143 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4145 // apply Hidden regions to view.
4146 if (hiddenSeqs != null)
4148 for (int s = 0; s < JSEQ.length; s++)
4150 jalview.datamodel.SequenceGroup hidden = new jalview.datamodel.SequenceGroup();
4152 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4155 al.getSequenceAt(JSEQ[s].getHiddenSequences(r)), false);
4157 af.viewport.hideRepSequences(al.getSequenceAt(s), hidden);
4160 // jalview.datamodel.SequenceI[] hseqs = new
4161 // jalview.datamodel.SequenceI[hiddenSeqs
4164 // for (int s = 0; s < hiddenSeqs.size(); s++)
4166 // hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s);
4169 SequenceI[] hseqs = hiddenSeqs.toArray(new SequenceI[hiddenSeqs
4171 af.viewport.hideSequence(hseqs);
4174 // recover view properties and display parameters
4175 if (view.getViewName() != null)
4177 af.viewport.viewName = view.getViewName();
4178 af.setInitialTabVisible();
4180 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4183 af.viewport.setShowAnnotation(view.getShowAnnotation());
4184 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4186 af.viewport.setColourText(view.getShowColourText());
4188 af.viewport.setConservationSelected(view.getConservationSelected());
4189 af.viewport.setShowJVSuffix(view.getShowFullId());
4190 af.viewport.setRightAlignIds(view.getRightAlignIds());
4191 af.viewport.setFont(
4192 new java.awt.Font(view.getFontName(), view.getFontStyle(), view
4193 .getFontSize()), true);
4194 // TODO: allow custom charWidth/Heights to be restored by updating them
4195 // after setting font - which means set above to false
4196 af.viewport.setRenderGaps(view.getRenderGaps());
4197 af.viewport.setWrapAlignment(view.getWrapAlignment());
4198 af.viewport.setShowAnnotation(view.getShowAnnotation());
4200 af.viewport.setShowBoxes(view.getShowBoxes());
4202 af.viewport.setShowText(view.getShowText());
4204 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4205 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4206 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4207 af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
4208 .isShowUnconserved() : false);
4209 af.viewport.setStartRes(view.getStartRes());
4210 af.viewport.setStartSeq(view.getStartSeq());
4211 af.alignPanel.updateLayout();
4212 ColourSchemeI cs = null;
4213 // apply colourschemes
4214 if (view.getBgColour() != null)
4216 if (view.getBgColour().startsWith("ucs"))
4218 cs = getUserColourScheme(jms, view.getBgColour());
4220 else if (view.getBgColour().startsWith("Annotation"))
4222 AnnotationColours viewAnnColour = view.getAnnotationColours();
4223 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4230 cs = ColourSchemeProperty.getColour(al, view.getBgColour());
4235 cs.setThreshold(view.getPidThreshold(), true);
4236 cs.setConsensus(af.viewport.getSequenceConsensusHash());
4240 af.viewport.setGlobalColourScheme(cs);
4241 af.viewport.setColourAppliesToAllGroups(false);
4243 if (view.getConservationSelected() && cs != null)
4245 cs.setConservationInc(view.getConsThreshold());
4248 af.changeColour(cs);
4250 af.viewport.setColourAppliesToAllGroups(true);
4252 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4254 if (view.hasCentreColumnLabels())
4256 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4258 if (view.hasIgnoreGapsinConsensus())
4260 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4263 if (view.hasFollowHighlight())
4265 af.viewport.setFollowHighlight(view.getFollowHighlight());
4267 if (view.hasFollowSelection())
4269 af.viewport.followSelection = view.getFollowSelection();
4271 if (view.hasShowConsensusHistogram())
4273 af.viewport.setShowConsensusHistogram(view
4274 .getShowConsensusHistogram());
4278 af.viewport.setShowConsensusHistogram(true);
4280 if (view.hasShowSequenceLogo())
4282 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4286 af.viewport.setShowSequenceLogo(false);
4288 if (view.hasNormaliseSequenceLogo())
4290 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4292 if (view.hasShowDbRefTooltip())
4294 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4296 if (view.hasShowNPfeatureTooltip())
4298 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4300 if (view.hasShowGroupConsensus())
4302 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4306 af.viewport.setShowGroupConsensus(false);
4308 if (view.hasShowGroupConservation())
4310 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4314 af.viewport.setShowGroupConservation(false);
4317 // recover featre settings
4318 if (jms.getFeatureSettings() != null)
4320 FeaturesDisplayed fdi;
4321 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4322 String[] renderOrder = new String[jms.getFeatureSettings()
4323 .getSettingCount()];
4324 Hashtable featureGroups = new Hashtable();
4325 Hashtable featureColours = new Hashtable();
4326 Hashtable featureOrder = new Hashtable();
4328 for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
4330 Setting setting = jms.getFeatureSettings().getSetting(fs);
4331 if (setting.hasMincolour())
4333 GraduatedColor gc = setting.hasMin() ? new GraduatedColor(
4334 new java.awt.Color(setting.getMincolour()),
4335 new java.awt.Color(setting.getColour()),
4336 setting.getMin(), setting.getMax()) : new GraduatedColor(
4337 new java.awt.Color(setting.getMincolour()),
4338 new java.awt.Color(setting.getColour()), 0, 1);
4339 if (setting.hasThreshold())
4341 gc.setThresh(setting.getThreshold());
4342 gc.setThreshType(setting.getThreshstate());
4344 gc.setAutoScaled(true); // default
4345 if (setting.hasAutoScale())
4347 gc.setAutoScaled(setting.getAutoScale());
4349 if (setting.hasColourByLabel())
4351 gc.setColourByLabel(setting.getColourByLabel());
4353 // and put in the feature colour table.
4354 featureColours.put(setting.getType(), gc);
4358 featureColours.put(setting.getType(),
4359 new java.awt.Color(setting.getColour()));
4361 renderOrder[fs] = setting.getType();
4362 if (setting.hasOrder())
4364 featureOrder.put(setting.getType(), setting.getOrder());
4368 featureOrder.put(setting.getType(), new Float(fs
4369 / jms.getFeatureSettings().getSettingCount()));
4371 if (setting.getDisplay())
4373 fdi.setVisible(setting.getType());
4376 Hashtable fgtable = new Hashtable();
4377 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4379 Group grp = jms.getFeatureSettings().getGroup(gs);
4380 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4382 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4383 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4384 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4385 FeatureRendererSettings frs = new FeatureRendererSettings(
4386 renderOrder, fgtable, featureColours, 1.0f, featureOrder);
4387 af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
4388 .transferSettings(frs);
4392 if (view.getHiddenColumnsCount() > 0)
4394 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4396 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(), view
4397 .getHiddenColumns(c).getEnd() // +1
4401 if (view.getCalcIdParam() != null)
4403 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4405 if (calcIdParam != null)
4407 if (recoverCalcIdParam(calcIdParam, af.viewport))
4412 warn("Couldn't recover parameters for "
4413 + calcIdParam.getCalcId());
4418 af.setMenusFromViewport(af.viewport);
4420 // TODO: we don't need to do this if the viewport is aready visible.
4422 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4423 * has a 'cdna/protein complement' view, in which case save it in order to
4424 * populate a SplitFrame once all views have been read in.
4426 String complementaryViewId = view.getComplementId();
4427 if (complementaryViewId == null)
4429 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4431 // recompute any autoannotation
4432 af.alignPanel.updateAnnotation(false, true);
4433 reorderAutoannotation(af, al, autoAlan);
4434 af.alignPanel.alignmentChanged();
4438 splitFrameCandidates.put(view, af);
4443 private ColourSchemeI constructAnnotationColour(
4444 AnnotationColours viewAnnColour, AlignFrame af, Alignment al,
4445 JalviewModelSequence jms, boolean checkGroupAnnColour)
4447 boolean propagateAnnColour = false;
4448 ColourSchemeI cs = null;
4449 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4450 if (checkGroupAnnColour && al.getGroups() != null
4451 && al.getGroups().size() > 0)
4453 // pre 2.8.1 behaviour
4454 // check to see if we should transfer annotation colours
4455 propagateAnnColour = true;
4456 for (jalview.datamodel.SequenceGroup sg : al.getGroups())
4458 if (sg.cs instanceof AnnotationColourGradient)
4460 propagateAnnColour = false;
4464 // int find annotation
4465 if (annAlignment.getAlignmentAnnotation() != null)
4467 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4469 if (annAlignment.getAlignmentAnnotation()[i].label
4470 .equals(viewAnnColour.getAnnotation()))
4472 if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null)
4474 annAlignment.getAlignmentAnnotation()[i]
4475 .setThreshold(new jalview.datamodel.GraphLine(
4476 viewAnnColour.getThreshold(), "Threshold",
4477 java.awt.Color.black)
4482 if (viewAnnColour.getColourScheme().equals("None"))
4484 cs = new AnnotationColourGradient(
4485 annAlignment.getAlignmentAnnotation()[i],
4486 new java.awt.Color(viewAnnColour.getMinColour()),
4487 new java.awt.Color(viewAnnColour.getMaxColour()),
4488 viewAnnColour.getAboveThreshold());
4490 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4492 cs = new AnnotationColourGradient(
4493 annAlignment.getAlignmentAnnotation()[i],
4494 getUserColourScheme(jms,
4495 viewAnnColour.getColourScheme()),
4496 viewAnnColour.getAboveThreshold());
4500 cs = new AnnotationColourGradient(
4501 annAlignment.getAlignmentAnnotation()[i],
4502 ColourSchemeProperty.getColour(al,
4503 viewAnnColour.getColourScheme()),
4504 viewAnnColour.getAboveThreshold());
4506 if (viewAnnColour.hasPerSequence())
4508 ((AnnotationColourGradient) cs).setSeqAssociated(viewAnnColour
4511 if (viewAnnColour.hasPredefinedColours())
4513 ((AnnotationColourGradient) cs)
4514 .setPredefinedColours(viewAnnColour
4515 .isPredefinedColours());
4517 if (propagateAnnColour && al.getGroups() != null)
4519 // Also use these settings for all the groups
4520 for (int g = 0; g < al.getGroups().size(); g++)
4522 jalview.datamodel.SequenceGroup sg = al.getGroups().get(g);
4530 * if (viewAnnColour.getColourScheme().equals("None" )) { sg.cs =
4531 * new AnnotationColourGradient(
4532 * annAlignment.getAlignmentAnnotation()[i], new
4533 * java.awt.Color(viewAnnColour. getMinColour()), new
4534 * java.awt.Color(viewAnnColour. getMaxColour()),
4535 * viewAnnColour.getAboveThreshold()); } else
4538 sg.cs = new AnnotationColourGradient(
4539 annAlignment.getAlignmentAnnotation()[i], sg.cs,
4540 viewAnnColour.getAboveThreshold());
4541 if (cs instanceof AnnotationColourGradient)
4543 if (viewAnnColour.hasPerSequence())
4545 ((AnnotationColourGradient) cs)
4546 .setSeqAssociated(viewAnnColour.isPerSequence());
4548 if (viewAnnColour.hasPredefinedColours())
4550 ((AnnotationColourGradient) cs)
4551 .setPredefinedColours(viewAnnColour
4552 .isPredefinedColours());
4568 private void reorderAutoannotation(AlignFrame af, Alignment al,
4569 List<JvAnnotRow> autoAlan)
4571 // copy over visualization settings for autocalculated annotation in the
4573 if (al.getAlignmentAnnotation() != null)
4576 * Kludge for magic autoannotation names (see JAL-811)
4578 String[] magicNames = new String[]
4579 { "Consensus", "Quality", "Conservation" };
4580 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4581 Hashtable<String, JvAnnotRow> visan = new Hashtable<String, JvAnnotRow>();
4582 for (String nm : magicNames)
4584 visan.put(nm, nullAnnot);
4586 for (JvAnnotRow auan : autoAlan)
4588 visan.put(auan.template.label
4589 + (auan.template.getCalcId() == null ? "" : "\t"
4590 + auan.template.getCalcId()), auan);
4592 int hSize = al.getAlignmentAnnotation().length;
4593 List<JvAnnotRow> reorder = new ArrayList<JvAnnotRow>();
4594 // work through any autoCalculated annotation already on the view
4595 // removing it if it should be placed in a different location on the
4596 // annotation panel.
4597 List<String> remains = new ArrayList<String>(visan.keySet());
4598 for (int h = 0; h < hSize; h++)
4600 AlignmentAnnotation jalan = al
4601 .getAlignmentAnnotation()[h];
4602 if (jalan.autoCalculated)
4605 JvAnnotRow valan = visan.get(k = jalan.label);
4606 if (jalan.getCalcId() != null)
4608 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4613 // delete the auto calculated row from the alignment
4614 al.deleteAnnotation(jalan, false);
4618 if (valan != nullAnnot)
4620 if (jalan != valan.template)
4622 // newly created autoannotation row instance
4623 // so keep a reference to the visible annotation row
4624 // and copy over all relevant attributes
4625 if (valan.template.graphHeight >= 0)
4628 jalan.graphHeight = valan.template.graphHeight;
4630 jalan.visible = valan.template.visible;
4632 reorder.add(new JvAnnotRow(valan.order, jalan));
4637 // Add any (possibly stale) autocalculated rows that were not appended to
4638 // the view during construction
4639 for (String other : remains)
4641 JvAnnotRow othera = visan.get(other);
4642 if (othera != nullAnnot && othera.template.getCalcId() != null
4643 && othera.template.getCalcId().length() > 0)
4645 reorder.add(othera);
4648 // now put the automatic annotation in its correct place
4649 int s = 0, srt[] = new int[reorder.size()];
4650 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
4651 for (JvAnnotRow jvar : reorder)
4654 srt[s++] = jvar.order;
4657 jalview.util.QuickSort.sortInt(srt, rws);
4658 // and re-insert the annotation at its correct position
4659 for (JvAnnotRow jvar : rws)
4661 al.addAnnotation(jvar.template, jvar.order);
4663 af.alignPanel.adjustAnnotationHeight();
4667 Hashtable skipList = null;
4670 * TODO remove this method
4673 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
4674 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
4675 * throw new Error("Implementation Error. No skipList defined for this
4676 * Jalview2XML instance."); } return (AlignFrame)
4677 * skipList.get(view.getSequenceSetId()); }
4681 * Check if the Jalview view contained in object should be skipped or not.
4684 * @return true if view's sequenceSetId is a key in skipList
4686 private boolean skipViewport(JalviewModel object)
4688 if (skipList == null)
4693 if (skipList.containsKey(id = object.getJalviewModelSequence()
4694 .getViewport()[0].getSequenceSetId()))
4696 if (Cache.log != null && Cache.log.isDebugEnabled())
4698 Cache.log.debug("Skipping seuqence set id " + id);
4705 public void addToSkipList(AlignFrame af)
4707 if (skipList == null)
4709 skipList = new Hashtable();
4711 skipList.put(af.getViewport().getSequenceSetId(), af);
4714 public void clearSkipList()
4716 if (skipList != null)
4723 private void recoverDatasetFor(SequenceSet vamsasSet, Alignment al,
4724 boolean ignoreUnrefed)
4726 jalview.datamodel.Alignment ds = getDatasetFor(vamsasSet.getDatasetId());
4727 Vector dseqs = null;
4730 // create a list of new dataset sequences
4731 dseqs = new Vector();
4733 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
4735 Sequence vamsasSeq = vamsasSet.getSequence(i);
4736 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed);
4738 // create a new dataset
4741 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
4742 dseqs.copyInto(dsseqs);
4743 ds = new jalview.datamodel.Alignment(dsseqs);
4744 debug("Created new dataset " + vamsasSet.getDatasetId()
4745 + " for alignment " + System.identityHashCode(al));
4746 addDatasetRef(vamsasSet.getDatasetId(), ds);
4748 // set the dataset for the newly imported alignment.
4749 if (al.getDataset() == null && !ignoreUnrefed)
4758 * sequence definition to create/merge dataset sequence for
4762 * vector to add new dataset sequence to
4764 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
4765 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed)
4767 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
4769 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
4770 SequenceI dsq = null;
4771 if (sq != null && sq.getDatasetSequence() != null)
4773 dsq = sq.getDatasetSequence();
4775 if (sq == null && ignoreUnrefed)
4779 String sqid = vamsasSeq.getDsseqid();
4782 // need to create or add a new dataset sequence reference to this sequence
4785 dsq = seqRefIds.get(sqid);
4790 // make a new dataset sequence
4791 dsq = sq.createDatasetSequence();
4794 // make up a new dataset reference for this sequence
4795 sqid = seqHash(dsq);
4797 dsq.setVamsasId(uniqueSetSuffix + sqid);
4798 seqRefIds.put(sqid, dsq);
4803 dseqs.addElement(dsq);
4808 ds.addSequence(dsq);
4814 { // make this dataset sequence sq's dataset sequence
4815 sq.setDatasetSequence(dsq);
4816 // and update the current dataset alignment
4821 if (!dseqs.contains(dsq))
4828 if (ds.findIndex(dsq) < 0)
4830 ds.addSequence(dsq);
4837 // TODO: refactor this as a merge dataset sequence function
4838 // now check that sq (the dataset sequence) sequence really is the union of
4839 // all references to it
4840 // boolean pre = sq.getStart() < dsq.getStart();
4841 // boolean post = sq.getEnd() > dsq.getEnd();
4845 // StringBuffer sb = new StringBuffer();
4846 String newres = AlignSeq.extractGaps(
4847 Comparison.GapChars, sq.getSequenceAsString());
4848 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
4849 && newres.length() > dsq.getLength())
4851 // Update with the longer sequence.
4855 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
4856 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
4857 * sb.append(newres.substring(newres.length() - sq.getEnd() -
4858 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
4860 dsq.setSequence(newres);
4862 // TODO: merges will never happen if we 'know' we have the real dataset
4863 // sequence - this should be detected when id==dssid
4865 .println("DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
4866 // + (pre ? "prepended" : "") + " "
4867 // + (post ? "appended" : ""));
4873 * TODO use AlignmentI here and in related methods - needs
4874 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
4876 Hashtable<String, Alignment> datasetIds = null;
4878 IdentityHashMap<Alignment, String> dataset2Ids = null;
4880 private Alignment getDatasetFor(String datasetId)
4882 if (datasetIds == null)
4884 datasetIds = new Hashtable<String, Alignment>();
4887 if (datasetIds.containsKey(datasetId))
4889 return datasetIds.get(datasetId);
4894 private void addDatasetRef(String datasetId, Alignment dataset)
4896 if (datasetIds == null)
4898 datasetIds = new Hashtable<String, Alignment>();
4900 datasetIds.put(datasetId, dataset);
4904 * make a new dataset ID for this jalview dataset alignment
4909 private String getDatasetIdRef(Alignment dataset)
4911 if (dataset.getDataset() != null)
4913 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
4915 String datasetId = makeHashCode(dataset, null);
4916 if (datasetId == null)
4918 // make a new datasetId and record it
4919 if (dataset2Ids == null)
4921 dataset2Ids = new IdentityHashMap<Alignment, String>();
4925 datasetId = dataset2Ids.get(dataset);
4927 if (datasetId == null)
4929 datasetId = "ds" + dataset2Ids.size() + 1;
4930 dataset2Ids.put(dataset, datasetId);
4936 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
4938 for (int d = 0; d < sequence.getDBRefCount(); d++)
4940 DBRef dr = sequence.getDBRef(d);
4941 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
4942 sequence.getDBRef(d).getSource(), sequence.getDBRef(d)
4943 .getVersion(), sequence.getDBRef(d).getAccessionId());
4944 if (dr.getMapping() != null)
4946 entry.setMap(addMapping(dr.getMapping()));
4948 datasetSequence.addDBRef(entry);
4952 private jalview.datamodel.Mapping addMapping(Mapping m)
4954 SequenceI dsto = null;
4955 // Mapping m = dr.getMapping();
4956 int fr[] = new int[m.getMapListFromCount() * 2];
4957 Enumeration f = m.enumerateMapListFrom();
4958 for (int _i = 0; f.hasMoreElements(); _i += 2)
4960 MapListFrom mf = (MapListFrom) f.nextElement();
4961 fr[_i] = mf.getStart();
4962 fr[_i + 1] = mf.getEnd();
4964 int fto[] = new int[m.getMapListToCount() * 2];
4965 f = m.enumerateMapListTo();
4966 for (int _i = 0; f.hasMoreElements(); _i += 2)
4968 MapListTo mf = (MapListTo) f.nextElement();
4969 fto[_i] = mf.getStart();
4970 fto[_i + 1] = mf.getEnd();
4972 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto,
4973 fr, fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
4974 if (m.getMappingChoice() != null)
4976 MappingChoice mc = m.getMappingChoice();
4977 if (mc.getDseqFor() != null)
4979 String dsfor = "" + mc.getDseqFor();
4980 if (seqRefIds.containsKey(dsfor))
4985 jmap.setTo(seqRefIds.get(dsfor));
4989 frefedSequence.add(new Object[]
4996 * local sequence definition
4998 Sequence ms = mc.getSequence();
4999 SequenceI djs = null;
5000 String sqid = ms.getDsseqid();
5001 if (sqid != null && sqid.length() > 0)
5004 * recover dataset sequence
5006 djs = seqRefIds.get(sqid);
5011 .println("Warning - making up dataset sequence id for DbRef sequence map reference");
5012 sqid = ((Object) ms).toString(); // make up a new hascode for
5013 // undefined dataset sequence hash
5014 // (unlikely to happen)
5020 * make a new dataset sequence and add it to refIds hash
5022 djs = new jalview.datamodel.Sequence(ms.getName(),
5024 djs.setStart(jmap.getMap().getToLowest());
5025 djs.setEnd(jmap.getMap().getToHighest());
5026 djs.setVamsasId(uniqueSetSuffix + sqid);
5028 seqRefIds.put(sqid, djs);
5031 Cache.log.debug("about to recurse on addDBRefs.");
5040 public jalview.gui.AlignmentPanel copyAlignPanel(AlignmentPanel ap,
5041 boolean keepSeqRefs)
5044 JalviewModel jm = saveState(ap, null, null, null);
5049 jm.getJalviewModelSequence().getViewport(0).setSequenceSetId(null);
5053 uniqueSetSuffix = "";
5054 jm.getJalviewModelSequence().getViewport(0).setId(null); // we don't
5059 if (this.frefedSequence == null)
5061 frefedSequence = new Vector();
5064 viewportsAdded.clear();
5066 AlignFrame af = loadFromObject(jm, null, false, null);
5067 af.alignPanels.clear();
5068 af.closeMenuItem_actionPerformed(true);
5071 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5072 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5073 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5074 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5075 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5078 return af.alignPanel;
5082 * flag indicating if hashtables should be cleared on finalization TODO this
5083 * flag may not be necessary
5085 private final boolean _cleartables = true;
5087 private Hashtable jvids2vobj;
5092 * @see java.lang.Object#finalize()
5095 protected void finalize() throws Throwable
5097 // really make sure we have no buried refs left.
5102 this.seqRefIds = null;
5103 this.seqsToIds = null;
5107 private void warn(String msg)
5112 private void warn(String msg, Exception e)
5114 if (Cache.log != null)
5118 Cache.log.warn(msg, e);
5122 Cache.log.warn(msg);
5127 System.err.println("Warning: " + msg);
5130 e.printStackTrace();
5135 private void debug(String string)
5137 debug(string, null);
5140 private void debug(String msg, Exception e)
5142 if (Cache.log != null)
5146 Cache.log.debug(msg, e);
5150 Cache.log.debug(msg);
5155 System.err.println("Warning: " + msg);
5158 e.printStackTrace();
5164 * set the object to ID mapping tables used to write/recover objects and XML
5165 * ID strings for the jalview project. If external tables are provided then
5166 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5167 * object goes out of scope. - also populates the datasetIds hashtable with
5168 * alignment objects containing dataset sequences
5171 * Map from ID strings to jalview datamodel
5173 * Map from jalview datamodel to ID strings
5177 public void setObjectMappingTables(Hashtable vobj2jv,
5178 IdentityHashMap jv2vobj)
5180 this.jv2vobj = jv2vobj;
5181 this.vobj2jv = vobj2jv;
5182 Iterator ds = jv2vobj.keySet().iterator();
5184 while (ds.hasNext())
5186 Object jvobj = ds.next();
5187 id = jv2vobj.get(jvobj).toString();
5188 if (jvobj instanceof jalview.datamodel.Alignment)
5190 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5192 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5195 else if (jvobj instanceof jalview.datamodel.Sequence)
5197 // register sequence object so the XML parser can recover it.
5198 if (seqRefIds == null)
5200 seqRefIds = new HashMap<String, SequenceI>();
5202 if (seqsToIds == null)
5204 seqsToIds = new IdentityHashMap<SequenceI, String>();
5206 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5207 seqsToIds.put((SequenceI) jvobj, id);
5209 else if (jvobj instanceof AlignmentAnnotation)
5212 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5213 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5214 if (jvann.annotationId == null)
5216 jvann.annotationId = anid;
5218 if (!jvann.annotationId.equals(anid))
5220 // TODO verify that this is the correct behaviour
5221 this.warn("Overriding Annotation ID for " + anid
5222 + " from different id : " + jvann.annotationId);
5223 jvann.annotationId = anid;
5226 else if (jvobj instanceof String)
5228 if (jvids2vobj == null)
5230 jvids2vobj = new Hashtable();
5231 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5236 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5242 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5243 * objects created from the project archive. If string is null (default for
5244 * construction) then suffix will be set automatically.
5248 public void setUniqueSetSuffix(String string)
5250 uniqueSetSuffix = string;
5255 * uses skipList2 as the skipList for skipping views on sequence sets
5256 * associated with keys in the skipList
5260 public void setSkipList(Hashtable skipList2)
5262 skipList = skipList2;
5266 * Reads the jar entry of given name and returns its contents, or null if the
5267 * entry is not found.
5270 * @param jarEntryName
5273 protected String readJarEntry(jarInputStreamProvider jprovider,
5274 String jarEntryName)
5276 String result = null;
5277 BufferedReader in = null;
5282 * Reopen the jar input stream and traverse its entries to find a matching
5285 JarInputStream jin = jprovider.getJarInputStream();
5286 JarEntry entry = null;
5289 entry = jin.getNextJarEntry();
5290 } while (entry != null && !entry.getName().equals(jarEntryName));
5294 StringBuilder out = new StringBuilder(256);
5295 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5298 while ((data = in.readLine()) != null)
5302 result = out.toString();
5306 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5308 } catch (Exception ex)
5310 ex.printStackTrace();
5318 } catch (IOException e)
5329 * Returns an incrementing counter (0, 1, 2...)
5333 private synchronized int nextCounter()