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.
21 package jalview.project;
23 import jalview.analysis.Conservation;
24 import jalview.api.FeatureColourI;
25 import jalview.api.ViewStyleI;
26 import jalview.api.structures.JalviewStructureDisplayI;
27 import jalview.bin.Cache;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.GraphLine;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.RnaViewerModel;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.datamodel.StructureViewerModel;
39 import jalview.datamodel.StructureViewerModel.StructureData;
40 import jalview.datamodel.features.FeatureMatcher;
41 import jalview.datamodel.features.FeatureMatcherI;
42 import jalview.datamodel.features.FeatureMatcherSet;
43 import jalview.datamodel.features.FeatureMatcherSetI;
44 import jalview.ext.varna.RnaModel;
45 import jalview.gui.AlignFrame;
46 import jalview.gui.AlignViewport;
47 import jalview.gui.AlignmentPanel;
48 import jalview.gui.AppVarna;
49 import jalview.gui.ChimeraViewFrame;
50 import jalview.gui.Desktop;
51 import jalview.gui.FeatureRenderer;
52 import jalview.gui.JvOptionPane;
53 import jalview.gui.OOMWarning;
54 import jalview.gui.PaintRefresher;
55 import jalview.gui.SplitFrame;
56 import jalview.gui.StructureViewer;
57 import jalview.gui.StructureViewer.ViewerType;
58 import jalview.gui.StructureViewerBase;
59 import jalview.gui.TreePanel;
60 import jalview.io.DataSourceType;
61 import jalview.io.FileFormat;
62 import jalview.io.NewickFile;
63 import jalview.renderer.ResidueShaderI;
64 import jalview.schemes.AnnotationColourGradient;
65 import jalview.schemes.ColourSchemeI;
66 import jalview.schemes.ColourSchemeProperty;
67 import jalview.schemes.FeatureColour;
68 import jalview.schemes.ResidueProperties;
69 import jalview.schemes.UserColourScheme;
70 import jalview.structure.StructureSelectionManager;
71 import jalview.structures.models.AAStructureBindingModel;
72 import jalview.util.Format;
73 import jalview.util.MessageManager;
74 import jalview.util.Platform;
75 import jalview.util.StringUtils;
76 import jalview.util.jarInputStreamProvider;
77 import jalview.util.matcher.Condition;
78 import jalview.viewmodel.AlignmentViewport;
79 import jalview.viewmodel.ViewportRanges;
80 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
81 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
82 import jalview.ws.jws2.Jws2Discoverer;
83 import jalview.ws.jws2.dm.AAConSettings;
84 import jalview.ws.jws2.jabaws2.Jws2Instance;
85 import jalview.ws.params.ArgumentI;
86 import jalview.ws.params.AutoCalcSetting;
87 import jalview.ws.params.WsParamSetI;
88 import jalview.xml.binding.jalview.AlcodonFrame;
89 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
90 import jalview.xml.binding.jalview.Annotation;
91 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
92 import jalview.xml.binding.jalview.AnnotationColourScheme;
93 import jalview.xml.binding.jalview.AnnotationElement;
94 import jalview.xml.binding.jalview.Feature;
95 import jalview.xml.binding.jalview.Feature.OtherData;
96 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
97 import jalview.xml.binding.jalview.FilterBy;
98 import jalview.xml.binding.jalview.JalviewModel;
99 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
100 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
101 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
102 import jalview.xml.binding.jalview.JalviewModel.JGroup;
103 import jalview.xml.binding.jalview.JalviewModel.JSeq;
104 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
105 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
106 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
107 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
108 import jalview.xml.binding.jalview.JalviewModel.Tree;
109 import jalview.xml.binding.jalview.JalviewModel.UserColours;
110 import jalview.xml.binding.jalview.JalviewModel.Viewport;
111 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
112 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
113 import jalview.xml.binding.jalview.JalviewUserColours;
114 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
115 import jalview.xml.binding.jalview.MapListType.MapListFrom;
116 import jalview.xml.binding.jalview.MapListType.MapListTo;
117 import jalview.xml.binding.jalview.Mapping;
118 import jalview.xml.binding.jalview.NoValueColour;
119 import jalview.xml.binding.jalview.ObjectFactory;
120 import jalview.xml.binding.jalview.Pdbentry.Property;
121 import jalview.xml.binding.jalview.Sequence;
122 import jalview.xml.binding.jalview.Sequence.DBRef;
123 import jalview.xml.binding.jalview.SequenceSet;
124 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
125 import jalview.xml.binding.jalview.ThresholdType;
126 import jalview.xml.binding.jalview.VAMSAS;
128 import java.awt.Color;
129 import java.awt.Font;
130 import java.awt.Rectangle;
131 import java.io.BufferedReader;
132 import java.io.DataInputStream;
133 import java.io.DataOutputStream;
135 import java.io.FileInputStream;
136 import java.io.FileOutputStream;
137 import java.io.IOException;
138 import java.io.InputStreamReader;
139 import java.io.OutputStreamWriter;
140 import java.io.PrintWriter;
141 import java.lang.reflect.InvocationTargetException;
142 import java.math.BigInteger;
143 import java.net.MalformedURLException;
145 import java.util.ArrayList;
146 import java.util.Arrays;
147 import java.util.Collections;
148 import java.util.Enumeration;
149 import java.util.GregorianCalendar;
150 import java.util.HashMap;
151 import java.util.HashSet;
152 import java.util.Hashtable;
153 import java.util.IdentityHashMap;
154 import java.util.Iterator;
155 import java.util.LinkedHashMap;
156 import java.util.List;
157 import java.util.Map;
158 import java.util.Map.Entry;
159 import java.util.Set;
160 import java.util.Vector;
161 import java.util.jar.JarEntry;
162 import java.util.jar.JarInputStream;
163 import java.util.jar.JarOutputStream;
165 import javax.swing.JInternalFrame;
166 import javax.swing.SwingUtilities;
167 import javax.xml.bind.JAXBContext;
168 import javax.xml.bind.JAXBElement;
169 import javax.xml.bind.Marshaller;
170 import javax.xml.datatype.DatatypeConfigurationException;
171 import javax.xml.datatype.DatatypeFactory;
172 import javax.xml.datatype.XMLGregorianCalendar;
173 import javax.xml.stream.XMLInputFactory;
174 import javax.xml.stream.XMLStreamReader;
177 * Write out the current jalview desktop state as a Jalview XML stream.
179 * Note: the vamsas objects referred to here are primitive versions of the
180 * VAMSAS project schema elements - they are not the same and most likely never
184 * @version $Revision: 1.134 $
186 public class Jalview2XML
188 private static final String VIEWER_PREFIX = "viewer_";
190 private static final String RNA_PREFIX = "rna_";
192 private static final String UTF_8 = "UTF-8";
194 // use this with nextCounter() to make unique names for entities
195 private int counter = 0;
198 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
199 * of sequence objects are created.
201 IdentityHashMap<SequenceI, String> seqsToIds = null;
204 * jalview XML Sequence ID to jalview sequence object reference (both dataset
205 * and alignment sequences. Populated as XML reps of sequence objects are
208 Map<String, SequenceI> seqRefIds = null;
210 Map<String, SequenceI> incompleteSeqs = null;
212 List<SeqFref> frefedSequence = null;
214 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
217 * Map of reconstructed AlignFrame objects that appear to have come from
218 * SplitFrame objects (have a dna/protein complement view).
220 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
223 * Map from displayed rna structure models to their saved session state jar
226 private Map<RnaModel, String> rnaSessions = new HashMap<>();
229 * A helper method for safely using the value of an optional attribute that
230 * may be null if not present in the XML. Answers the boolean value, or false
236 public static boolean safeBoolean(Boolean b)
238 return b == null ? false : b.booleanValue();
242 * A helper method for safely using the value of an optional attribute that
243 * may be null if not present in the XML. Answers the integer value, or zero
249 public static int safeInt(Integer i)
251 return i == null ? 0 : i.intValue();
255 * A helper method for safely using the value of an optional attribute that
256 * may be null if not present in the XML. Answers the float value, or zero if
262 public static float safeFloat(Float f)
264 return f == null ? 0f : f.floatValue();
268 * create/return unique hash string for sq
271 * @return new or existing unique string for sq
273 String seqHash(SequenceI sq)
275 if (seqsToIds == null)
279 if (seqsToIds.containsKey(sq))
281 return seqsToIds.get(sq);
285 // create sequential key
286 String key = "sq" + (seqsToIds.size() + 1);
287 key = makeHashCode(sq, key); // check we don't have an external reference
289 seqsToIds.put(sq, key);
296 if (seqsToIds == null)
298 seqsToIds = new IdentityHashMap<>();
300 if (seqRefIds == null)
302 seqRefIds = new HashMap<>();
304 if (incompleteSeqs == null)
306 incompleteSeqs = new HashMap<>();
308 if (frefedSequence == null)
310 frefedSequence = new ArrayList<>();
318 public Jalview2XML(boolean raiseGUI)
320 this.raiseGUI = raiseGUI;
324 * base class for resolving forward references to sequences by their ID
329 abstract class SeqFref
335 public SeqFref(String _sref, String type)
341 public String getSref()
346 public SequenceI getSrefSeq()
348 return seqRefIds.get(sref);
351 public boolean isResolvable()
353 return seqRefIds.get(sref) != null;
356 public SequenceI getSrefDatasetSeq()
358 SequenceI sq = seqRefIds.get(sref);
361 while (sq.getDatasetSequence() != null)
363 sq = sq.getDatasetSequence();
370 * @return true if the forward reference was fully resolved
372 abstract boolean resolve();
375 public String toString()
377 return type + " reference to " + sref;
382 * create forward reference for a mapping
388 public SeqFref newMappingRef(final String sref,
389 final jalview.datamodel.Mapping _jmap)
391 SeqFref fref = new SeqFref(sref, "Mapping")
393 public jalview.datamodel.Mapping jmap = _jmap;
398 SequenceI seq = getSrefDatasetSeq();
410 public SeqFref newAlcodMapRef(final String sref,
411 final AlignedCodonFrame _cf,
412 final jalview.datamodel.Mapping _jmap)
415 SeqFref fref = new SeqFref(sref, "Codon Frame")
417 AlignedCodonFrame cf = _cf;
419 public jalview.datamodel.Mapping mp = _jmap;
422 public boolean isResolvable()
424 return super.isResolvable() && mp.getTo() != null;
430 SequenceI seq = getSrefDatasetSeq();
435 cf.addMap(seq, mp.getTo(), mp.getMap());
442 public void resolveFrefedSequences()
444 Iterator<SeqFref> nextFref = frefedSequence.iterator();
445 int toresolve = frefedSequence.size();
446 int unresolved = 0, failedtoresolve = 0;
447 while (nextFref.hasNext())
449 SeqFref ref = nextFref.next();
450 if (ref.isResolvable())
462 } catch (Exception x)
465 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
478 System.err.println("Jalview Project Import: There were " + unresolved
479 + " forward references left unresolved on the stack.");
481 if (failedtoresolve > 0)
483 System.err.println("SERIOUS! " + failedtoresolve
484 + " resolvable forward references failed to resolve.");
486 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
489 "Jalview Project Import: There are " + incompleteSeqs.size()
490 + " sequences which may have incomplete metadata.");
491 if (incompleteSeqs.size() < 10)
493 for (SequenceI s : incompleteSeqs.values())
495 System.err.println(s.toString());
501 "Too many to report. Skipping output of incomplete sequences.");
507 * This maintains a map of viewports, the key being the seqSetId. Important to
508 * set historyItem and redoList for multiple views
510 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
512 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
514 String uniqueSetSuffix = "";
517 * List of pdbfiles added to Jar
519 List<String> pdbfiles = null;
521 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
522 public void saveState(File statefile)
524 FileOutputStream fos = null;
527 fos = new FileOutputStream(statefile);
528 JarOutputStream jout = new JarOutputStream(fos);
531 } catch (Exception e)
533 // TODO: inform user of the problem - they need to know if their data was
535 if (errorMessage == null)
537 errorMessage = "Couldn't write Jalview Archive to output file '"
538 + statefile + "' - See console error log for details";
542 errorMessage += "(output file was '" + statefile + "')";
552 } catch (IOException e)
562 * Writes a jalview project archive to the given Jar output stream.
566 public void saveState(JarOutputStream jout)
568 AlignFrame[] frames = Desktop.getAlignFrames();
574 saveAllFrames(Arrays.asList(frames), jout);
578 * core method for storing state for a set of AlignFrames.
581 * - frames involving all data to be exported (including containing
584 * - project output stream
586 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
588 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
591 * ensure cached data is clear before starting
593 // todo tidy up seqRefIds, seqsToIds initialisation / reset
595 splitFrameCandidates.clear();
600 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
601 // //////////////////////////////////////////////////
603 List<String> shortNames = new ArrayList<>();
604 List<String> viewIds = new ArrayList<>();
607 for (int i = frames.size() - 1; i > -1; i--)
609 AlignFrame af = frames.get(i);
611 if (skipList != null && skipList
612 .containsKey(af.getViewport().getSequenceSetId()))
617 String shortName = makeFilename(af, shortNames);
619 int apSize = af.getAlignPanels().size();
621 for (int ap = 0; ap < apSize; ap++)
623 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
625 String fileName = apSize == 1 ? shortName : ap + shortName;
626 if (!fileName.endsWith(".xml"))
628 fileName = fileName + ".xml";
631 saveState(apanel, fileName, jout, viewIds);
633 String dssid = getDatasetIdRef(
634 af.getViewport().getAlignment().getDataset());
635 if (!dsses.containsKey(dssid))
637 dsses.put(dssid, af);
642 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
648 } catch (Exception foo)
653 } catch (Exception ex)
655 // TODO: inform user of the problem - they need to know if their data was
657 if (errorMessage == null)
659 errorMessage = "Couldn't write Jalview Archive - see error output for details";
661 ex.printStackTrace();
666 * Generates a distinct file name, based on the title of the AlignFrame, by
667 * appending _n for increasing n until an unused name is generated. The new
668 * name (without its extension) is added to the list.
672 * @return the generated name, with .xml extension
674 protected String makeFilename(AlignFrame af, List<String> namesUsed)
676 String shortName = af.getTitle();
678 if (shortName.indexOf(File.separatorChar) > -1)
680 shortName = shortName
681 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
686 while (namesUsed.contains(shortName))
688 if (shortName.endsWith("_" + (count - 1)))
690 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
693 shortName = shortName.concat("_" + count);
697 namesUsed.add(shortName);
699 if (!shortName.endsWith(".xml"))
701 shortName = shortName + ".xml";
706 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
707 public boolean saveAlignment(AlignFrame af, String jarFile,
712 FileOutputStream fos = new FileOutputStream(jarFile);
713 JarOutputStream jout = new JarOutputStream(fos);
714 List<AlignFrame> frames = new ArrayList<>();
716 // resolve splitframes
717 if (af.getViewport().getCodingComplement() != null)
719 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
725 saveAllFrames(frames, jout);
729 } catch (Exception foo)
735 } catch (Exception ex)
737 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
738 ex.printStackTrace();
743 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
744 String fileName, JarOutputStream jout)
747 for (String dssids : dsses.keySet())
749 AlignFrame _af = dsses.get(dssids);
750 String jfileName = fileName + " Dataset for " + _af.getTitle();
751 if (!jfileName.endsWith(".xml"))
753 jfileName = jfileName + ".xml";
755 saveState(_af.alignPanel, jfileName, true, jout, null);
760 * create a JalviewModel from an alignment view and marshall it to a
764 * panel to create jalview model for
766 * name of alignment panel written to output stream
773 public JalviewModel saveState(AlignmentPanel ap, String fileName,
774 JarOutputStream jout, List<String> viewIds)
776 return saveState(ap, fileName, false, jout, viewIds);
780 * create a JalviewModel from an alignment view and marshall it to a
784 * panel to create jalview model for
786 * name of alignment panel written to output stream
788 * when true, only write the dataset for the alignment, not the data
789 * associated with the view.
795 public JalviewModel saveState(AlignmentPanel ap, String fileName,
796 boolean storeDS, JarOutputStream jout, List<String> viewIds)
800 viewIds = new ArrayList<>();
805 List<UserColourScheme> userColours = new ArrayList<>();
807 AlignViewport av = ap.av;
808 ViewportRanges vpRanges = av.getRanges();
810 final ObjectFactory objectFactory = new ObjectFactory();
811 JalviewModel object = objectFactory.createJalviewModel();
812 object.setVamsasModel(new VAMSAS());
814 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
817 GregorianCalendar c = new GregorianCalendar();
818 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
819 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
820 object.setCreationDate(now);
821 } catch (DatatypeConfigurationException e)
823 System.err.println("error writing date: " + e.toString());
826 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
829 * rjal is full height alignment, jal is actual alignment with full metadata
830 * but excludes hidden sequences.
832 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
834 if (av.hasHiddenRows())
836 rjal = jal.getHiddenSequences().getFullAlignment();
839 SequenceSet vamsasSet = new SequenceSet();
841 // JalviewModelSequence jms = new JalviewModelSequence();
843 vamsasSet.setGapChar(jal.getGapCharacter() + "");
845 if (jal.getDataset() != null)
847 // dataset id is the dataset's hashcode
848 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
851 // switch jal and the dataset
852 jal = jal.getDataset();
856 if (jal.getProperties() != null)
858 Enumeration en = jal.getProperties().keys();
859 while (en.hasMoreElements())
861 String key = en.nextElement().toString();
862 SequenceSetProperties ssp = new SequenceSetProperties();
864 ssp.setValue(jal.getProperties().get(key).toString());
865 // vamsasSet.addSequenceSetProperties(ssp);
866 vamsasSet.getSequenceSetProperties().add(ssp);
871 Set<String> calcIdSet = new HashSet<>();
872 // record the set of vamsas sequence XML POJO we create.
873 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
875 for (final SequenceI jds : rjal.getSequences())
877 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
878 : jds.getDatasetSequence();
879 String id = seqHash(jds);
880 if (vamsasSetIds.get(id) == null)
882 if (seqRefIds.get(id) != null && !storeDS)
884 // This happens for two reasons: 1. multiple views are being
886 // 2. the hashCode has collided with another sequence's code. This
888 // HAPPEN! (PF00072.15.stk does this)
889 // JBPNote: Uncomment to debug writing out of files that do not read
890 // back in due to ArrayOutOfBoundExceptions.
891 // System.err.println("vamsasSeq backref: "+id+"");
892 // System.err.println(jds.getName()+"
893 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
894 // System.err.println("Hashcode: "+seqHash(jds));
895 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
896 // System.err.println(rsq.getName()+"
897 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
898 // System.err.println("Hashcode: "+seqHash(rsq));
902 vamsasSeq = createVamsasSequence(id, jds);
903 // vamsasSet.addSequence(vamsasSeq);
904 vamsasSet.getSequence().add(vamsasSeq);
905 vamsasSetIds.put(id, vamsasSeq);
906 seqRefIds.put(id, jds);
910 jseq.setStart(jds.getStart());
911 jseq.setEnd(jds.getEnd());
912 jseq.setColour(av.getSequenceColour(jds).getRGB());
914 jseq.setId(id); // jseq id should be a string not a number
917 // Store any sequences this sequence represents
918 if (av.hasHiddenRows())
920 // use rjal, contains the full height alignment
922 av.getAlignment().getHiddenSequences().isHidden(jds));
924 if (av.isHiddenRepSequence(jds))
926 jalview.datamodel.SequenceI[] reps = av
927 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
929 for (int h = 0; h < reps.length; h++)
933 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
934 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
939 // mark sequence as reference - if it is the reference for this view
942 jseq.setViewreference(jds == jal.getSeqrep());
946 // TODO: omit sequence features from each alignment view's XML dump if we
947 // are storing dataset
948 List<SequenceFeature> sfs = jds.getSequenceFeatures();
949 for (SequenceFeature sf : sfs)
951 // Features features = new Features();
952 Feature features = new Feature();
954 features.setBegin(sf.getBegin());
955 features.setEnd(sf.getEnd());
956 features.setDescription(sf.getDescription());
957 features.setType(sf.getType());
958 features.setFeatureGroup(sf.getFeatureGroup());
959 features.setScore(sf.getScore());
960 if (sf.links != null)
962 for (int l = 0; l < sf.links.size(); l++)
964 OtherData keyValue = new OtherData();
965 keyValue.setKey("LINK_" + l);
966 keyValue.setValue(sf.links.elementAt(l).toString());
967 // features.addOtherData(keyValue);
968 features.getOtherData().add(keyValue);
971 if (sf.otherDetails != null)
974 * save feature attributes, which may be simple strings or
975 * map valued (have sub-attributes)
977 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
979 String key = entry.getKey();
980 Object value = entry.getValue();
981 if (value instanceof Map<?, ?>)
983 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
986 OtherData otherData = new OtherData();
987 otherData.setKey(key);
988 otherData.setKey2(subAttribute.getKey());
989 otherData.setValue(subAttribute.getValue().toString());
990 // features.addOtherData(otherData);
991 features.getOtherData().add(otherData);
996 OtherData otherData = new OtherData();
997 otherData.setKey(key);
998 otherData.setValue(value.toString());
999 // features.addOtherData(otherData);
1000 features.getOtherData().add(otherData);
1005 // jseq.addFeatures(features);
1006 jseq.getFeatures().add(features);
1009 if (jdatasq.getAllPDBEntries() != null)
1011 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1012 while (en.hasMoreElements())
1014 Pdbids pdb = new Pdbids();
1015 jalview.datamodel.PDBEntry entry = en.nextElement();
1017 String pdbId = entry.getId();
1019 pdb.setType(entry.getType());
1022 * Store any structure views associated with this sequence. This
1023 * section copes with duplicate entries in the project, so a dataset
1024 * only view *should* be coped with sensibly.
1026 // This must have been loaded, is it still visible?
1027 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1028 String matchedFile = null;
1029 for (int f = frames.length - 1; f > -1; f--)
1031 if (frames[f] instanceof StructureViewerBase)
1033 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1034 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1035 matchedFile, viewFrame);
1037 * Only store each structure viewer's state once in the project
1038 * jar. First time through only (storeDS==false)
1040 String viewId = viewFrame.getViewId();
1041 if (!storeDS && !viewIds.contains(viewId))
1043 viewIds.add(viewId);
1046 String viewerState = viewFrame.getStateInfo();
1047 writeJarEntry(jout, getViewerJarEntryName(viewId),
1048 viewerState.getBytes());
1049 } catch (IOException e)
1052 "Error saving viewer state: " + e.getMessage());
1058 if (matchedFile != null || entry.getFile() != null)
1060 if (entry.getFile() != null)
1063 matchedFile = entry.getFile();
1065 pdb.setFile(matchedFile); // entry.getFile());
1066 if (pdbfiles == null)
1068 pdbfiles = new ArrayList<>();
1071 if (!pdbfiles.contains(pdbId))
1073 pdbfiles.add(pdbId);
1074 copyFileToJar(jout, matchedFile, pdbId);
1078 Enumeration<String> props = entry.getProperties();
1079 if (props.hasMoreElements())
1081 // PdbentryItem item = new PdbentryItem();
1082 while (props.hasMoreElements())
1084 Property prop = new Property();
1085 String key = props.nextElement();
1087 prop.setValue(entry.getProperty(key).toString());
1088 // item.addProperty(prop);
1089 pdb.getProperty().add(prop);
1091 // pdb.addPdbentryItem(item);
1094 // jseq.addPdbids(pdb);
1095 jseq.getPdbids().add(pdb);
1099 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1101 // jms.addJSeq(jseq);
1102 object.getJSeq().add(jseq);
1105 if (!storeDS && av.hasHiddenRows())
1107 jal = av.getAlignment();
1111 if (storeDS && jal.getCodonFrames() != null)
1113 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1114 for (AlignedCodonFrame acf : jac)
1116 AlcodonFrame alc = new AlcodonFrame();
1117 if (acf.getProtMappings() != null
1118 && acf.getProtMappings().length > 0)
1120 boolean hasMap = false;
1121 SequenceI[] dnas = acf.getdnaSeqs();
1122 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1123 for (int m = 0; m < pmaps.length; m++)
1125 AlcodMap alcmap = new AlcodMap();
1126 alcmap.setDnasq(seqHash(dnas[m]));
1128 createVamsasMapping(pmaps[m], dnas[m], null, false));
1129 // alc.addAlcodMap(alcmap);
1130 alc.getAlcodMap().add(alcmap);
1135 // vamsasSet.addAlcodonFrame(alc);
1136 vamsasSet.getAlcodonFrame().add(alc);
1139 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1141 // AlcodonFrame alc = new AlcodonFrame();
1142 // vamsasSet.addAlcodonFrame(alc);
1143 // for (int p = 0; p < acf.aaWidth; p++)
1145 // Alcodon cmap = new Alcodon();
1146 // if (acf.codons[p] != null)
1148 // // Null codons indicate a gapped column in the translated peptide
1150 // cmap.setPos1(acf.codons[p][0]);
1151 // cmap.setPos2(acf.codons[p][1]);
1152 // cmap.setPos3(acf.codons[p][2]);
1154 // alc.addAlcodon(cmap);
1156 // if (acf.getProtMappings() != null
1157 // && acf.getProtMappings().length > 0)
1159 // SequenceI[] dnas = acf.getdnaSeqs();
1160 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1161 // for (int m = 0; m < pmaps.length; m++)
1163 // AlcodMap alcmap = new AlcodMap();
1164 // alcmap.setDnasq(seqHash(dnas[m]));
1165 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1167 // alc.addAlcodMap(alcmap);
1174 // /////////////////////////////////
1175 if (!storeDS && av.getCurrentTree() != null)
1177 // FIND ANY ASSOCIATED TREES
1178 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1179 if (Desktop.desktop != null)
1181 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1183 for (int t = 0; t < frames.length; t++)
1185 if (frames[t] instanceof TreePanel)
1187 TreePanel tp = (TreePanel) frames[t];
1189 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1191 JalviewModel.Tree tree = new JalviewModel.Tree();
1192 tree.setTitle(tp.getTitle());
1193 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1194 tree.setNewick(tp.getTree().print());
1195 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1197 tree.setFitToWindow(tp.fitToWindow.getState());
1198 tree.setFontName(tp.getTreeFont().getName());
1199 tree.setFontSize(tp.getTreeFont().getSize());
1200 tree.setFontStyle(tp.getTreeFont().getStyle());
1201 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1203 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1204 tree.setShowDistances(tp.distanceMenu.getState());
1206 tree.setHeight(tp.getHeight());
1207 tree.setWidth(tp.getWidth());
1208 tree.setXpos(tp.getX());
1209 tree.setYpos(tp.getY());
1210 tree.setId(makeHashCode(tp, null));
1211 // jms.addTree(tree);
1212 object.getTree().add(tree);
1221 * store forward refs from an annotationRow to any groups
1223 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1226 for (SequenceI sq : jal.getSequences())
1228 // Store annotation on dataset sequences only
1229 AlignmentAnnotation[] aa = sq.getAnnotation();
1230 if (aa != null && aa.length > 0)
1232 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1239 if (jal.getAlignmentAnnotation() != null)
1241 // Store the annotation shown on the alignment.
1242 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1243 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1248 if (jal.getGroups() != null)
1250 JGroup[] groups = new JGroup[jal.getGroups().size()];
1252 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1254 JGroup jGroup = new JGroup();
1255 groups[++i] = jGroup;
1257 jGroup.setStart(sg.getStartRes());
1258 jGroup.setEnd(sg.getEndRes());
1259 jGroup.setName(sg.getName());
1260 if (groupRefs.containsKey(sg))
1262 // group has references so set its ID field
1263 jGroup.setId(groupRefs.get(sg));
1265 ColourSchemeI colourScheme = sg.getColourScheme();
1266 if (colourScheme != null)
1268 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1269 if (groupColourScheme.conservationApplied())
1271 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1273 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1276 setUserColourScheme(colourScheme, userColours,
1281 jGroup.setColour(colourScheme.getSchemeName());
1284 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1286 jGroup.setColour("AnnotationColourGradient");
1287 jGroup.setAnnotationColours(constructAnnotationColours(
1288 (jalview.schemes.AnnotationColourGradient) colourScheme,
1289 userColours, object));
1291 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1294 setUserColourScheme(colourScheme, userColours, object));
1298 jGroup.setColour(colourScheme.getSchemeName());
1301 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1304 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1305 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1306 jGroup.setDisplayText(sg.getDisplayText());
1307 jGroup.setColourText(sg.getColourText());
1308 jGroup.setTextCol1(sg.textColour.getRGB());
1309 jGroup.setTextCol2(sg.textColour2.getRGB());
1310 jGroup.setTextColThreshold(sg.thresholdTextColour);
1311 jGroup.setShowUnconserved(sg.getShowNonconserved());
1312 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1313 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1314 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1315 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1316 for (SequenceI seq : sg.getSequences())
1318 // jGroup.addSeq(seqHash(seq));
1319 jGroup.getSeq().add(seqHash(seq));
1323 //jms.setJGroup(groups);
1325 for (JGroup grp : groups)
1327 object.getJGroup().add(grp);
1332 // /////////SAVE VIEWPORT
1333 Viewport view = new Viewport();
1334 view.setTitle(ap.alignFrame.getTitle());
1335 view.setSequenceSetId(
1336 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1337 view.setId(av.getViewId());
1338 if (av.getCodingComplement() != null)
1340 view.setComplementId(av.getCodingComplement().getViewId());
1342 view.setViewName(av.getViewName());
1343 view.setGatheredViews(av.isGatherViewsHere());
1345 Rectangle size = ap.av.getExplodedGeometry();
1346 Rectangle position = size;
1349 size = ap.alignFrame.getBounds();
1350 if (av.getCodingComplement() != null)
1352 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1360 view.setXpos(position.x);
1361 view.setYpos(position.y);
1363 view.setWidth(size.width);
1364 view.setHeight(size.height);
1366 view.setStartRes(vpRanges.getStartRes());
1367 view.setStartSeq(vpRanges.getStartSeq());
1369 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1371 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1372 userColours, object));
1375 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1377 AnnotationColourScheme ac = constructAnnotationColours(
1378 (jalview.schemes.AnnotationColourGradient) av
1379 .getGlobalColourScheme(),
1380 userColours, object);
1382 view.setAnnotationColours(ac);
1383 view.setBgColour("AnnotationColourGradient");
1387 view.setBgColour(ColourSchemeProperty
1388 .getColourName(av.getGlobalColourScheme()));
1391 ResidueShaderI vcs = av.getResidueShading();
1392 ColourSchemeI cs = av.getGlobalColourScheme();
1396 if (vcs.conservationApplied())
1398 view.setConsThreshold(vcs.getConservationInc());
1399 if (cs instanceof jalview.schemes.UserColourScheme)
1401 view.setBgColour(setUserColourScheme(cs, userColours, object));
1404 view.setPidThreshold(vcs.getThreshold());
1407 view.setConservationSelected(av.getConservationSelected());
1408 view.setPidSelected(av.getAbovePIDThreshold());
1409 final Font font = av.getFont();
1410 view.setFontName(font.getName());
1411 view.setFontSize(font.getSize());
1412 view.setFontStyle(font.getStyle());
1413 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1414 view.setRenderGaps(av.isRenderGaps());
1415 view.setShowAnnotation(av.isShowAnnotation());
1416 view.setShowBoxes(av.getShowBoxes());
1417 view.setShowColourText(av.getColourText());
1418 view.setShowFullId(av.getShowJVSuffix());
1419 view.setRightAlignIds(av.isRightAlignIds());
1420 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1421 view.setShowText(av.getShowText());
1422 view.setShowUnconserved(av.getShowUnconserved());
1423 view.setWrapAlignment(av.getWrapAlignment());
1424 view.setTextCol1(av.getTextColour().getRGB());
1425 view.setTextCol2(av.getTextColour2().getRGB());
1426 view.setTextColThreshold(av.getThresholdTextColour());
1427 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1428 view.setShowSequenceLogo(av.isShowSequenceLogo());
1429 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1430 view.setShowGroupConsensus(av.isShowGroupConsensus());
1431 view.setShowGroupConservation(av.isShowGroupConservation());
1432 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1433 view.setShowDbRefTooltip(av.isShowDBRefs());
1434 view.setFollowHighlight(av.isFollowHighlight());
1435 view.setFollowSelection(av.followSelection);
1436 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1437 if (av.getFeaturesDisplayed() != null)
1439 FeatureSettings fs = new FeatureSettings();
1441 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1442 .getFeatureRenderer();
1443 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1445 Vector<String> settingsAdded = new Vector<>();
1446 if (renderOrder != null)
1448 for (String featureType : renderOrder)
1450 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1451 setting.setType(featureType);
1454 * save any filter for the feature type
1456 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1457 if (filter != null) {
1458 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1459 FeatureMatcherI firstFilter = filters.next();
1460 setting.setMatcherSet(Jalview2XML.marshalFilter(
1461 firstFilter, filters, filter.isAnded()));
1465 * save colour scheme for the feature type
1467 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1468 if (!fcol.isSimpleColour())
1470 setting.setColour(fcol.getMaxColour().getRGB());
1471 setting.setMincolour(fcol.getMinColour().getRGB());
1472 setting.setMin(fcol.getMin());
1473 setting.setMax(fcol.getMax());
1474 setting.setColourByLabel(fcol.isColourByLabel());
1475 if (fcol.isColourByAttribute())
1477 String[] attName = fcol.getAttributeName();
1478 setting.getAttributeName().add(attName[0]);
1479 if (attName.length > 1)
1481 setting.getAttributeName().add(attName[1]);
1484 setting.setAutoScale(fcol.isAutoScaled());
1485 setting.setThreshold(fcol.getThreshold());
1486 Color noColour = fcol.getNoColour();
1487 if (noColour == null)
1489 setting.setNoValueColour(NoValueColour.NONE);
1491 else if (noColour.equals(fcol.getMaxColour()))
1493 setting.setNoValueColour(NoValueColour.MAX);
1497 setting.setNoValueColour(NoValueColour.MIN);
1499 // -1 = No threshold, 0 = Below, 1 = Above
1500 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1501 : (fcol.isBelowThreshold() ? 0 : -1));
1505 setting.setColour(fcol.getColour().getRGB());
1509 av.getFeaturesDisplayed().isVisible(featureType));
1511 .getOrder(featureType);
1514 setting.setOrder(rorder);
1516 /// fs.addSetting(setting);
1517 fs.getSetting().add(setting);
1518 settingsAdded.addElement(featureType);
1522 // is groups actually supposed to be a map here ?
1523 Iterator<String> en = fr.getFeatureGroups().iterator();
1524 Vector<String> groupsAdded = new Vector<>();
1525 while (en.hasNext())
1527 String grp = en.next();
1528 if (groupsAdded.contains(grp))
1532 Group g = new Group();
1534 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1537 fs.getGroup().add(g);
1538 groupsAdded.addElement(grp);
1540 // jms.setFeatureSettings(fs);
1541 object.setFeatureSettings(fs);
1544 if (av.hasHiddenColumns())
1546 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1547 .getHiddenColumns();
1550 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1554 Iterator<int[]> hiddenRegions = hidden.iterator();
1555 while (hiddenRegions.hasNext())
1557 int[] region = hiddenRegions.next();
1558 HiddenColumns hc = new HiddenColumns();
1559 hc.setStart(region[0]);
1560 hc.setEnd(region[1]);
1561 // view.addHiddenColumns(hc);
1562 view.getHiddenColumns().add(hc);
1566 if (calcIdSet.size() > 0)
1568 for (String calcId : calcIdSet)
1570 if (calcId.trim().length() > 0)
1572 CalcIdParam cidp = createCalcIdParam(calcId, av);
1573 // Some calcIds have no parameters.
1576 // view.addCalcIdParam(cidp);
1577 view.getCalcIdParam().add(cidp);
1583 // jms.addViewport(view);
1584 object.getViewport().add(view);
1586 // object.setJalviewModelSequence(jms);
1587 // object.getVamsasModel().addSequenceSet(vamsasSet);
1588 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1590 if (jout != null && fileName != null)
1592 // We may not want to write the object to disk,
1593 // eg we can copy the alignViewport to a new view object
1594 // using save and then load
1597 System.out.println("Writing jar entry " + fileName);
1598 JarEntry entry = new JarEntry(fileName);
1599 jout.putNextEntry(entry);
1600 PrintWriter pout = new PrintWriter(
1601 new OutputStreamWriter(jout, UTF_8));
1602 JAXBContext jaxbContext = JAXBContext
1603 .newInstance(JalviewModel.class);
1604 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1606 // output pretty printed
1607 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1608 jaxbMarshaller.marshal(
1609 new ObjectFactory().createJalviewModel(object), pout);
1611 // jaxbMarshaller.marshal(object, pout);
1612 // marshaller.marshal(object);
1615 } catch (Exception ex)
1617 // TODO: raise error in GUI if marshalling failed.
1618 System.err.println("Error writing Jalview project");
1619 ex.printStackTrace();
1626 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1627 * for each viewer, with
1629 * <li>viewer geometry (position, size, split pane divider location)</li>
1630 * <li>index of the selected structure in the viewer (currently shows gapped
1632 * <li>the id of the annotation holding RNA secondary structure</li>
1633 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1635 * Varna viewer state is also written out (in native Varna XML) to separate
1636 * project jar entries. A separate entry is written for each RNA structure
1637 * displayed, with the naming convention
1639 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1647 * @param storeDataset
1649 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1650 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1651 boolean storeDataset)
1653 if (Desktop.desktop == null)
1657 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1658 for (int f = frames.length - 1; f > -1; f--)
1660 if (frames[f] instanceof AppVarna)
1662 AppVarna varna = (AppVarna) frames[f];
1664 * link the sequence to every viewer that is showing it and is linked to
1665 * its alignment panel
1667 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1669 String viewId = varna.getViewId();
1670 RnaViewer rna = new RnaViewer();
1671 rna.setViewId(viewId);
1672 rna.setTitle(varna.getTitle());
1673 rna.setXpos(varna.getX());
1674 rna.setYpos(varna.getY());
1675 rna.setWidth(varna.getWidth());
1676 rna.setHeight(varna.getHeight());
1677 rna.setDividerLocation(varna.getDividerLocation());
1678 rna.setSelectedRna(varna.getSelectedIndex());
1679 // jseq.addRnaViewer(rna);
1680 jseq.getRnaViewer().add(rna);
1683 * Store each Varna panel's state once in the project per sequence.
1684 * First time through only (storeDataset==false)
1686 // boolean storeSessions = false;
1687 // String sequenceViewId = viewId + seqsToIds.get(jds);
1688 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1690 // viewIds.add(sequenceViewId);
1691 // storeSessions = true;
1693 for (RnaModel model : varna.getModels())
1695 if (model.seq == jds)
1698 * VARNA saves each view (sequence or alignment secondary
1699 * structure, gapped or trimmed) as a separate XML file
1701 String jarEntryName = rnaSessions.get(model);
1702 if (jarEntryName == null)
1705 String varnaStateFile = varna.getStateInfo(model.rna);
1706 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1707 copyFileToJar(jout, varnaStateFile, jarEntryName);
1708 rnaSessions.put(model, jarEntryName);
1710 SecondaryStructure ss = new SecondaryStructure();
1711 String annotationId = varna.getAnnotation(jds).annotationId;
1712 ss.setAnnotationId(annotationId);
1713 ss.setViewerState(jarEntryName);
1714 ss.setGapped(model.gapped);
1715 ss.setTitle(model.title);
1716 // rna.addSecondaryStructure(ss);
1717 rna.getSecondaryStructure().add(ss);
1726 * Copy the contents of a file to a new entry added to the output jar
1730 * @param jarEntryName
1732 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1733 String jarEntryName)
1735 DataInputStream dis = null;
1738 File file = new File(infilePath);
1739 if (file.exists() && jout != null)
1741 dis = new DataInputStream(new FileInputStream(file));
1742 byte[] data = new byte[(int) file.length()];
1743 dis.readFully(data);
1744 writeJarEntry(jout, jarEntryName, data);
1746 } catch (Exception ex)
1748 ex.printStackTrace();
1756 } catch (IOException e)
1765 * Write the data to a new entry of given name in the output jar file
1768 * @param jarEntryName
1770 * @throws IOException
1772 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1773 byte[] data) throws IOException
1777 System.out.println("Writing jar entry " + jarEntryName);
1778 jout.putNextEntry(new JarEntry(jarEntryName));
1779 DataOutputStream dout = new DataOutputStream(jout);
1780 dout.write(data, 0, data.length);
1787 * Save the state of a structure viewer
1792 * the archive XML element under which to save the state
1795 * @param matchedFile
1799 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1800 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1801 String matchedFile, StructureViewerBase viewFrame)
1803 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1806 * Look for any bindings for this viewer to the PDB file of interest
1807 * (including part matches excluding chain id)
1809 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1811 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1812 final String pdbId = pdbentry.getId();
1813 if (!pdbId.equals(entry.getId())
1814 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1815 .startsWith(pdbId.toLowerCase())))
1818 * not interested in a binding to a different PDB entry here
1822 if (matchedFile == null)
1824 matchedFile = pdbentry.getFile();
1826 else if (!matchedFile.equals(pdbentry.getFile()))
1829 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1830 + pdbentry.getFile());
1834 // can get at it if the ID
1835 // match is ambiguous (e.g.
1838 for (int smap = 0; smap < viewFrame.getBinding()
1839 .getSequence()[peid].length; smap++)
1841 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1842 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1844 StructureState state = new StructureState();
1845 state.setVisible(true);
1846 state.setXpos(viewFrame.getX());
1847 state.setYpos(viewFrame.getY());
1848 state.setWidth(viewFrame.getWidth());
1849 state.setHeight(viewFrame.getHeight());
1850 final String viewId = viewFrame.getViewId();
1851 state.setViewId(viewId);
1852 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1853 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1854 state.setColourByJmol(viewFrame.isColouredByViewer());
1855 state.setType(viewFrame.getViewerType().toString());
1856 // pdb.addStructureState(state);
1857 pdb.getStructureState().add(state);
1865 * Populates the AnnotationColourScheme xml for save. This captures the
1866 * settings of the options in the 'Colour by Annotation' dialog.
1869 * @param userColours
1873 private AnnotationColourScheme constructAnnotationColours(
1874 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1877 AnnotationColourScheme ac = new AnnotationColourScheme();
1878 ac.setAboveThreshold(acg.getAboveThreshold());
1879 ac.setThreshold(acg.getAnnotationThreshold());
1880 // 2.10.2 save annotationId (unique) not annotation label
1881 ac.setAnnotation(acg.getAnnotation().annotationId);
1882 if (acg.getBaseColour() instanceof UserColourScheme)
1885 setUserColourScheme(acg.getBaseColour(), userColours, jm));
1890 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1893 ac.setMaxColour(acg.getMaxColour().getRGB());
1894 ac.setMinColour(acg.getMinColour().getRGB());
1895 ac.setPerSequence(acg.isSeqAssociated());
1896 ac.setPredefinedColours(acg.isPredefinedColours());
1900 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1901 IdentityHashMap<SequenceGroup, String> groupRefs,
1902 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1903 SequenceSet vamsasSet)
1906 for (int i = 0; i < aa.length; i++)
1908 Annotation an = new Annotation();
1910 AlignmentAnnotation annotation = aa[i];
1911 if (annotation.annotationId != null)
1913 annotationIds.put(annotation.annotationId, annotation);
1916 an.setId(annotation.annotationId);
1918 an.setVisible(annotation.visible);
1920 an.setDescription(annotation.description);
1922 if (annotation.sequenceRef != null)
1924 // 2.9 JAL-1781 xref on sequence id rather than name
1925 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1927 if (annotation.groupRef != null)
1929 String groupIdr = groupRefs.get(annotation.groupRef);
1930 if (groupIdr == null)
1932 // make a locally unique String
1933 groupRefs.put(annotation.groupRef,
1934 groupIdr = ("" + System.currentTimeMillis()
1935 + annotation.groupRef.getName()
1936 + groupRefs.size()));
1938 an.setGroupRef(groupIdr.toString());
1941 // store all visualization attributes for annotation
1942 an.setGraphHeight(annotation.graphHeight);
1943 an.setCentreColLabels(annotation.centreColLabels);
1944 an.setScaleColLabels(annotation.scaleColLabel);
1945 an.setShowAllColLabels(annotation.showAllColLabels);
1946 an.setBelowAlignment(annotation.belowAlignment);
1948 if (annotation.graph > 0)
1951 an.setGraphType(annotation.graph);
1952 an.setGraphGroup(annotation.graphGroup);
1953 if (annotation.getThreshold() != null)
1955 ThresholdLine line = new ThresholdLine();
1956 line.setLabel(annotation.getThreshold().label);
1957 line.setValue(annotation.getThreshold().value);
1958 line.setColour(annotation.getThreshold().colour.getRGB());
1959 an.setThresholdLine(line);
1967 an.setLabel(annotation.label);
1969 if (annotation == av.getAlignmentQualityAnnot()
1970 || annotation == av.getAlignmentConservationAnnotation()
1971 || annotation == av.getAlignmentConsensusAnnotation()
1972 || annotation.autoCalculated)
1974 // new way of indicating autocalculated annotation -
1975 an.setAutoCalculated(annotation.autoCalculated);
1977 if (annotation.hasScore())
1979 an.setScore(annotation.getScore());
1982 if (annotation.getCalcId() != null)
1984 calcIdSet.add(annotation.getCalcId());
1985 an.setCalcId(annotation.getCalcId());
1987 if (annotation.hasProperties())
1989 for (String pr : annotation.getProperties())
1991 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
1993 prop.setValue(annotation.getProperty(pr));
1994 // an.addProperty(prop);
1995 an.getProperty().add(prop);
1999 AnnotationElement ae;
2000 if (annotation.annotations != null)
2002 an.setScoreOnly(false);
2003 for (int a = 0; a < annotation.annotations.length; a++)
2005 if ((annotation == null) || (annotation.annotations[a] == null))
2010 ae = new AnnotationElement();
2011 if (annotation.annotations[a].description != null)
2013 ae.setDescription(annotation.annotations[a].description);
2015 if (annotation.annotations[a].displayCharacter != null)
2017 ae.setDisplayCharacter(
2018 annotation.annotations[a].displayCharacter);
2021 if (!Float.isNaN(annotation.annotations[a].value))
2023 ae.setValue(annotation.annotations[a].value);
2027 if (annotation.annotations[a].secondaryStructure > ' ')
2029 ae.setSecondaryStructure(
2030 annotation.annotations[a].secondaryStructure + "");
2033 if (annotation.annotations[a].colour != null
2034 && annotation.annotations[a].colour != java.awt.Color.black)
2036 ae.setColour(annotation.annotations[a].colour.getRGB());
2039 // an.addAnnotationElement(ae);
2040 an.getAnnotationElement().add(ae);
2041 if (annotation.autoCalculated)
2043 // only write one non-null entry into the annotation row -
2044 // sufficient to get the visualization attributes necessary to
2052 an.setScoreOnly(true);
2054 if (!storeDS || (storeDS && !annotation.autoCalculated))
2056 // skip autocalculated annotation - these are only provided for
2058 // vamsasSet.addAnnotation(an);
2059 vamsasSet.getAnnotation().add(an);
2065 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2067 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2068 if (settings != null)
2070 CalcIdParam vCalcIdParam = new CalcIdParam();
2071 vCalcIdParam.setCalcId(calcId);
2072 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2073 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2074 // generic URI allowing a third party to resolve another instance of the
2075 // service used for this calculation
2076 for (String url : settings.getServiceURLs())
2078 // vCalcIdParam.addServiceURL(urls);
2079 vCalcIdParam.getServiceURL().add(url);
2081 vCalcIdParam.setVersion("1.0");
2082 if (settings.getPreset() != null)
2084 WsParamSetI setting = settings.getPreset();
2085 vCalcIdParam.setName(setting.getName());
2086 vCalcIdParam.setDescription(setting.getDescription());
2090 vCalcIdParam.setName("");
2091 vCalcIdParam.setDescription("Last used parameters");
2093 // need to be able to recover 1) settings 2) user-defined presets or
2094 // recreate settings from preset 3) predefined settings provided by
2095 // service - or settings that can be transferred (or discarded)
2096 vCalcIdParam.setParameters(
2097 settings.getWsParamFile().replace("\n", "|\\n|"));
2098 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2099 // todo - decide if updateImmediately is needed for any projects.
2101 return vCalcIdParam;
2106 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2109 if (calcIdParam.getVersion().equals("1.0"))
2111 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2112 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2113 .getPreferredServiceFor(calcIds);
2114 if (service != null)
2116 WsParamSetI parmSet = null;
2119 parmSet = service.getParamStore().parseServiceParameterFile(
2120 calcIdParam.getName(), calcIdParam.getDescription(),
2122 calcIdParam.getParameters().replace("|\\n|", "\n"));
2123 } catch (IOException x)
2125 warn("Couldn't parse parameter data for "
2126 + calcIdParam.getCalcId(), x);
2129 List<ArgumentI> argList = null;
2130 if (calcIdParam.getName().length() > 0)
2132 parmSet = service.getParamStore()
2133 .getPreset(calcIdParam.getName());
2134 if (parmSet != null)
2136 // TODO : check we have a good match with settings in AACon -
2137 // otherwise we'll need to create a new preset
2142 argList = parmSet.getArguments();
2145 AAConSettings settings = new AAConSettings(
2146 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2147 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2148 calcIdParam.isNeedsUpdate());
2153 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2157 throw new Error(MessageManager.formatMessage(
2158 "error.unsupported_version_calcIdparam", new Object[]
2159 { calcIdParam.toString() }));
2163 * External mapping between jalview objects and objects yielding a valid and
2164 * unique object ID string. This is null for normal Jalview project IO, but
2165 * non-null when a jalview project is being read or written as part of a
2168 IdentityHashMap jv2vobj = null;
2171 * Construct a unique ID for jvobj using either existing bindings or if none
2172 * exist, the result of the hashcode call for the object.
2175 * jalview data object
2176 * @return unique ID for referring to jvobj
2178 private String makeHashCode(Object jvobj, String altCode)
2180 if (jv2vobj != null)
2182 Object id = jv2vobj.get(jvobj);
2185 return id.toString();
2187 // check string ID mappings
2188 if (jvids2vobj != null && jvobj instanceof String)
2190 id = jvids2vobj.get(jvobj);
2194 return id.toString();
2196 // give up and warn that something has gone wrong
2197 warn("Cannot find ID for object in external mapping : " + jvobj);
2203 * return local jalview object mapped to ID, if it exists
2207 * @return null or object bound to idcode
2209 private Object retrieveExistingObj(String idcode)
2211 if (idcode != null && vobj2jv != null)
2213 return vobj2jv.get(idcode);
2219 * binding from ID strings from external mapping table to jalview data model
2222 private Hashtable vobj2jv;
2224 private Sequence createVamsasSequence(String id, SequenceI jds)
2226 return createVamsasSequence(true, id, jds, null);
2229 private Sequence createVamsasSequence(boolean recurse, String id,
2230 SequenceI jds, SequenceI parentseq)
2232 Sequence vamsasSeq = new Sequence();
2233 vamsasSeq.setId(id);
2234 vamsasSeq.setName(jds.getName());
2235 vamsasSeq.setSequence(jds.getSequenceAsString());
2236 vamsasSeq.setDescription(jds.getDescription());
2237 jalview.datamodel.DBRefEntry[] dbrefs = null;
2238 if (jds.getDatasetSequence() != null)
2240 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2244 // seqId==dsseqid so we can tell which sequences really are
2245 // dataset sequences only
2246 vamsasSeq.setDsseqid(id);
2247 dbrefs = jds.getDBRefs();
2248 if (parentseq == null)
2255 for (int d = 0; d < dbrefs.length; d++)
2257 DBRef dbref = new DBRef();
2258 dbref.setSource(dbrefs[d].getSource());
2259 dbref.setVersion(dbrefs[d].getVersion());
2260 dbref.setAccessionId(dbrefs[d].getAccessionId());
2261 if (dbrefs[d].hasMap())
2263 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2265 dbref.setMapping(mp);
2267 // vamsasSeq.addDBRef(dbref);
2268 vamsasSeq.getDBRef().add(dbref);
2274 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2275 SequenceI parentseq, SequenceI jds, boolean recurse)
2278 if (jmp.getMap() != null)
2282 jalview.util.MapList mlst = jmp.getMap();
2283 List<int[]> r = mlst.getFromRanges();
2284 for (int[] range : r)
2286 MapListFrom mfrom = new MapListFrom();
2287 mfrom.setStart(range[0]);
2288 mfrom.setEnd(range[1]);
2289 // mp.addMapListFrom(mfrom);
2290 mp.getMapListFrom().add(mfrom);
2292 r = mlst.getToRanges();
2293 for (int[] range : r)
2295 MapListTo mto = new MapListTo();
2296 mto.setStart(range[0]);
2297 mto.setEnd(range[1]);
2298 // mp.addMapListTo(mto);
2299 mp.getMapListTo().add(mto);
2301 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2302 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2303 if (jmp.getTo() != null)
2305 // MappingChoice mpc = new MappingChoice();
2307 // check/create ID for the sequence referenced by getTo()
2310 SequenceI ps = null;
2311 if (parentseq != jmp.getTo()
2312 && parentseq.getDatasetSequence() != jmp.getTo())
2314 // chaining dbref rather than a handshaking one
2315 jmpid = seqHash(ps = jmp.getTo());
2319 jmpid = seqHash(ps = parentseq);
2321 // mpc.setDseqFor(jmpid);
2322 mp.setDseqFor(jmpid);
2323 if (!seqRefIds.containsKey(jmpid))
2325 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2326 seqRefIds.put(jmpid, ps);
2330 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2333 // mp.setMappingChoice(mpc);
2339 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2340 List<UserColourScheme> userColours, JalviewModel jm)
2343 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2344 boolean newucs = false;
2345 if (!userColours.contains(ucs))
2347 userColours.add(ucs);
2350 id = "ucs" + userColours.indexOf(ucs);
2353 // actually create the scheme's entry in the XML model
2354 java.awt.Color[] colours = ucs.getColours();
2355 UserColours uc = new UserColours();
2356 // UserColourScheme jbucs = new UserColourScheme();
2357 JalviewUserColours jbucs = new JalviewUserColours();
2359 for (int i = 0; i < colours.length; i++)
2361 Colour col = new Colour();
2362 col.setName(ResidueProperties.aa[i]);
2363 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2364 // jbucs.addColour(col);
2365 jbucs.getColour().add(col);
2367 if (ucs.getLowerCaseColours() != null)
2369 colours = ucs.getLowerCaseColours();
2370 for (int i = 0; i < colours.length; i++)
2372 Colour col = new Colour();
2373 col.setName(ResidueProperties.aa[i].toLowerCase());
2374 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2375 // jbucs.addColour(col);
2376 jbucs.getColour().add(col);
2381 uc.setUserColourScheme(jbucs);
2382 // jm.addUserColours(uc);
2383 jm.getUserColours().add(uc);
2389 jalview.schemes.UserColourScheme getUserColourScheme(
2390 JalviewModel jm, String id)
2392 List<UserColours> uc = jm.getUserColours();
2393 UserColours colours = null;
2395 for (int i = 0; i < uc.length; i++)
2397 if (uc[i].getId().equals(id))
2404 for (UserColours c : uc)
2406 if (c.getId().equals(id))
2413 java.awt.Color[] newColours = new java.awt.Color[24];
2415 for (int i = 0; i < 24; i++)
2417 newColours[i] = new java.awt.Color(Integer.parseInt(
2418 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2419 colours.getUserColourScheme().getColour().get(i).getRGB(),
2423 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2426 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2428 newColours = new java.awt.Color[23];
2429 for (int i = 0; i < 23; i++)
2431 newColours[i] = new java.awt.Color(Integer.parseInt(
2432 colours.getUserColourScheme().getColour().get(i + 24)
2436 ucs.setLowerCaseColours(newColours);
2443 * contains last error message (if any) encountered by XML loader.
2445 String errorMessage = null;
2448 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2449 * exceptions are raised during project XML parsing
2451 public boolean attemptversion1parse = false;
2454 * Load a jalview project archive from a jar file
2457 * - HTTP URL or filename
2459 public AlignFrame loadJalviewAlign(final String file)
2462 jalview.gui.AlignFrame af = null;
2466 // create list to store references for any new Jmol viewers created
2467 newStructureViewers = new Vector<>();
2468 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2469 // Workaround is to make sure caller implements the JarInputStreamProvider
2471 // so we can re-open the jar input stream for each entry.
2473 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2474 af = loadJalviewAlign(jprovider);
2477 af.setMenusForViewport();
2479 } catch (MalformedURLException e)
2481 errorMessage = "Invalid URL format for '" + file + "'";
2487 SwingUtilities.invokeAndWait(new Runnable()
2492 setLoadingFinishedForNewStructureViewers();
2495 } catch (Exception x)
2497 System.err.println("Error loading alignment: " + x.getMessage());
2503 private jarInputStreamProvider createjarInputStreamProvider(
2504 final String file) throws MalformedURLException
2507 errorMessage = null;
2508 uniqueSetSuffix = null;
2510 viewportsAdded.clear();
2511 frefedSequence = null;
2513 if (file.startsWith("http://"))
2515 url = new URL(file);
2517 final URL _url = url;
2518 return new jarInputStreamProvider()
2522 public JarInputStream getJarInputStream() throws IOException
2526 return new JarInputStream(_url.openStream());
2530 return new JarInputStream(new FileInputStream(file));
2535 public String getFilename()
2543 * Recover jalview session from a jalview project archive. Caller may
2544 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2545 * themselves. Any null fields will be initialised with default values,
2546 * non-null fields are left alone.
2551 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2553 errorMessage = null;
2554 if (uniqueSetSuffix == null)
2556 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2558 if (seqRefIds == null)
2562 AlignFrame af = null, _af = null;
2563 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2564 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2565 final String file = jprovider.getFilename();
2568 JarInputStream jin = null;
2569 JarEntry jarentry = null;
2574 jin = jprovider.getJarInputStream();
2575 for (int i = 0; i < entryCount; i++)
2577 jarentry = jin.getNextJarEntry();
2580 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2582 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2583 // JalviewModel object = new JalviewModel();
2585 JAXBContext jc = JAXBContext
2586 .newInstance("jalview.xml.binding.jalview");
2587 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2588 .createXMLStreamReader(jin);
2589 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2590 JAXBElement<JalviewModel> jbe = um
2591 .unmarshal(streamReader, JalviewModel.class);
2592 JalviewModel object = jbe.getValue();
2595 Unmarshaller unmar = new Unmarshaller(object);
2596 unmar.setValidation(false);
2597 object = (JalviewModel) unmar.unmarshal(in);
2599 if (true) // !skipViewport(object))
2601 _af = loadFromObject(object, file, true, jprovider);
2602 if (_af != null && object.getViewport().size() > 0)
2603 // getJalviewModelSequence().getViewportCount() > 0)
2607 // store a reference to the first view
2610 if (_af.getViewport().isGatherViewsHere())
2612 // if this is a gathered view, keep its reference since
2613 // after gathering views, only this frame will remain
2615 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2618 // Save dataset to register mappings once all resolved
2619 importedDatasets.put(
2620 af.getViewport().getAlignment().getDataset(),
2621 af.getViewport().getAlignment().getDataset());
2626 else if (jarentry != null)
2628 // Some other file here.
2631 } while (jarentry != null);
2632 resolveFrefedSequences();
2633 } catch (IOException ex)
2635 ex.printStackTrace();
2636 errorMessage = "Couldn't locate Jalview XML file : " + file;
2638 "Exception whilst loading jalview XML file : " + ex + "\n");
2639 } catch (Exception ex)
2641 System.err.println("Parsing as Jalview Version 2 file failed.");
2642 ex.printStackTrace(System.err);
2643 if (attemptversion1parse)
2645 // used to attempt to parse as V1 castor-generated xml
2647 if (Desktop.instance != null)
2649 Desktop.instance.stopLoading();
2653 System.out.println("Successfully loaded archive file");
2656 ex.printStackTrace();
2659 "Exception whilst loading jalview XML file : " + ex + "\n");
2660 } catch (OutOfMemoryError e)
2662 // Don't use the OOM Window here
2663 errorMessage = "Out of memory loading jalview XML file";
2664 System.err.println("Out of memory whilst loading jalview XML file");
2665 e.printStackTrace();
2669 * Regather multiple views (with the same sequence set id) to the frame (if
2670 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2671 * views instead of separate frames. Note this doesn't restore a state where
2672 * some expanded views in turn have tabbed views - the last "first tab" read
2673 * in will play the role of gatherer for all.
2675 for (AlignFrame fr : gatherToThisFrame.values())
2677 Desktop.instance.gatherViews(fr);
2680 restoreSplitFrames();
2681 for (AlignmentI ds : importedDatasets.keySet())
2683 if (ds.getCodonFrames() != null)
2685 StructureSelectionManager
2686 .getStructureSelectionManager(Desktop.instance)
2687 .registerMappings(ds.getCodonFrames());
2690 if (errorMessage != null)
2695 if (Desktop.instance != null)
2697 Desktop.instance.stopLoading();
2704 * Try to reconstruct and display SplitFrame windows, where each contains
2705 * complementary dna and protein alignments. Done by pairing up AlignFrame
2706 * objects (created earlier) which have complementary viewport ids associated.
2708 protected void restoreSplitFrames()
2710 List<SplitFrame> gatherTo = new ArrayList<>();
2711 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2712 Map<String, AlignFrame> dna = new HashMap<>();
2715 * Identify the DNA alignments
2717 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2720 AlignFrame af = candidate.getValue();
2721 if (af.getViewport().getAlignment().isNucleotide())
2723 dna.put(candidate.getKey().getId(), af);
2728 * Try to match up the protein complements
2730 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2733 AlignFrame af = candidate.getValue();
2734 if (!af.getViewport().getAlignment().isNucleotide())
2736 String complementId = candidate.getKey().getComplementId();
2737 // only non-null complements should be in the Map
2738 if (complementId != null && dna.containsKey(complementId))
2740 final AlignFrame dnaFrame = dna.get(complementId);
2741 SplitFrame sf = createSplitFrame(dnaFrame, af);
2742 addedToSplitFrames.add(dnaFrame);
2743 addedToSplitFrames.add(af);
2744 dnaFrame.setMenusForViewport();
2745 af.setMenusForViewport();
2746 if (af.getViewport().isGatherViewsHere())
2755 * Open any that we failed to pair up (which shouldn't happen!) as
2756 * standalone AlignFrame's.
2758 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2761 AlignFrame af = candidate.getValue();
2762 if (!addedToSplitFrames.contains(af))
2764 Viewport view = candidate.getKey();
2765 Desktop.addInternalFrame(af, view.getTitle(),
2766 safeInt(view.getWidth()), safeInt(view.getHeight()));
2767 af.setMenusForViewport();
2768 System.err.println("Failed to restore view " + view.getTitle()
2769 + " to split frame");
2774 * Gather back into tabbed views as flagged.
2776 for (SplitFrame sf : gatherTo)
2778 Desktop.instance.gatherViews(sf);
2781 splitFrameCandidates.clear();
2785 * Construct and display one SplitFrame holding DNA and protein alignments.
2788 * @param proteinFrame
2791 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2792 AlignFrame proteinFrame)
2794 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2795 String title = MessageManager.getString("label.linked_view_title");
2796 int width = (int) dnaFrame.getBounds().getWidth();
2797 int height = (int) (dnaFrame.getBounds().getHeight()
2798 + proteinFrame.getBounds().getHeight() + 50);
2801 * SplitFrame location is saved to both enclosed frames
2803 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2804 Desktop.addInternalFrame(splitFrame, title, width, height);
2807 * And compute cDNA consensus (couldn't do earlier with consensus as
2808 * mappings were not yet present)
2810 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
2816 * check errorMessage for a valid error message and raise an error box in the
2817 * GUI or write the current errorMessage to stderr and then clear the error
2820 protected void reportErrors()
2822 reportErrors(false);
2825 protected void reportErrors(final boolean saving)
2827 if (errorMessage != null)
2829 final String finalErrorMessage = errorMessage;
2832 javax.swing.SwingUtilities.invokeLater(new Runnable()
2837 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2839 "Error " + (saving ? "saving" : "loading")
2841 JvOptionPane.WARNING_MESSAGE);
2847 System.err.println("Problem loading Jalview file: " + errorMessage);
2850 errorMessage = null;
2853 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2856 * when set, local views will be updated from view stored in JalviewXML
2857 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2858 * sync if this is set to true.
2860 private final boolean updateLocalViews = false;
2863 * Returns the path to a temporary file holding the PDB file for the given PDB
2864 * id. The first time of asking, searches for a file of that name in the
2865 * Jalview project jar, and copies it to a new temporary file. Any repeat
2866 * requests just return the path to the file previously created.
2872 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2875 if (alreadyLoadedPDB.containsKey(pdbId))
2877 return alreadyLoadedPDB.get(pdbId).toString();
2880 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2882 if (tempFile != null)
2884 alreadyLoadedPDB.put(pdbId, tempFile);
2890 * Copies the jar entry of given name to a new temporary file and returns the
2891 * path to the file, or null if the entry is not found.
2894 * @param jarEntryName
2896 * a prefix for the temporary file name, must be at least three
2899 * null or original file - so new file can be given the same suffix
2903 protected String copyJarEntry(jarInputStreamProvider jprovider,
2904 String jarEntryName, String prefix, String origFile)
2906 BufferedReader in = null;
2907 PrintWriter out = null;
2908 String suffix = ".tmp";
2909 if (origFile == null)
2911 origFile = jarEntryName;
2913 int sfpos = origFile.lastIndexOf(".");
2914 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2916 suffix = "." + origFile.substring(sfpos + 1);
2920 JarInputStream jin = jprovider.getJarInputStream();
2922 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2923 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2924 * FileInputStream(jprovider)); }
2927 JarEntry entry = null;
2930 entry = jin.getNextJarEntry();
2931 } while (entry != null && !entry.getName().equals(jarEntryName));
2934 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2935 File outFile = File.createTempFile(prefix, suffix);
2936 outFile.deleteOnExit();
2937 out = new PrintWriter(new FileOutputStream(outFile));
2940 while ((data = in.readLine()) != null)
2945 String t = outFile.getAbsolutePath();
2950 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2952 } catch (Exception ex)
2954 ex.printStackTrace();
2962 } catch (IOException e)
2976 private class JvAnnotRow
2978 public JvAnnotRow(int i, AlignmentAnnotation jaa)
2985 * persisted version of annotation row from which to take vis properties
2987 public jalview.datamodel.AlignmentAnnotation template;
2990 * original position of the annotation row in the alignment
2996 * Load alignment frame from jalview XML DOM object
2998 * @param jalviewModel
3001 * filename source string
3002 * @param loadTreesAndStructures
3003 * when false only create Viewport
3005 * data source provider
3006 * @return alignment frame created from view stored in DOM
3008 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3009 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3011 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3012 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3014 // JalviewModelSequence jms = object.getJalviewModelSequence();
3016 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3018 Viewport view = (jalviewModel.getViewport().size() > 0)
3019 ? jalviewModel.getViewport().get(0)
3022 // ////////////////////////////////
3025 List<SequenceI> hiddenSeqs = null;
3027 List<SequenceI> tmpseqs = new ArrayList<>();
3029 boolean multipleView = false;
3030 SequenceI referenceseqForView = null;
3031 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3032 List<JSeq> jseqs = jalviewModel.getJSeq();
3033 int vi = 0; // counter in vamsasSeq array
3034 for (int i = 0; i < jseqs.size(); i++)
3036 JSeq jseq = jseqs.get(i);
3037 String seqId = jseq.getId();
3039 SequenceI tmpSeq = seqRefIds.get(seqId);
3042 if (!incompleteSeqs.containsKey(seqId))
3044 // may not need this check, but keep it for at least 2.9,1 release
3045 if (tmpSeq.getStart() != jseq.getStart()
3046 || tmpSeq.getEnd() != jseq.getEnd())
3049 "Warning JAL-2154 regression: updating start/end for sequence "
3050 + tmpSeq.toString() + " to " + jseq);
3055 incompleteSeqs.remove(seqId);
3057 if (vamsasSeqs.size() > vi
3058 && vamsasSeqs.get(vi).getId().equals(seqId))
3060 // most likely we are reading a dataset XML document so
3061 // update from vamsasSeq section of XML for this sequence
3062 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3063 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3064 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3069 // reading multiple views, so vamsasSeq set is a subset of JSeq
3070 multipleView = true;
3072 tmpSeq.setStart(jseq.getStart());
3073 tmpSeq.setEnd(jseq.getEnd());
3074 tmpseqs.add(tmpSeq);
3078 Sequence vamsasSeq = vamsasSeqs.get(vi);
3079 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3080 vamsasSeq.getSequence());
3081 tmpSeq.setDescription(vamsasSeq.getDescription());
3082 tmpSeq.setStart(jseq.getStart());
3083 tmpSeq.setEnd(jseq.getEnd());
3084 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3085 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3086 tmpseqs.add(tmpSeq);
3090 if (safeBoolean(jseq.isViewreference()))
3092 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3095 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3097 if (hiddenSeqs == null)
3099 hiddenSeqs = new ArrayList<>();
3102 hiddenSeqs.add(tmpSeq);
3107 // Create the alignment object from the sequence set
3108 // ///////////////////////////////
3109 SequenceI[] orderedSeqs = tmpseqs
3110 .toArray(new SequenceI[tmpseqs.size()]);
3112 AlignmentI al = null;
3113 // so we must create or recover the dataset alignment before going further
3114 // ///////////////////////////////
3115 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3117 // older jalview projects do not have a dataset - so creat alignment and
3119 al = new Alignment(orderedSeqs);
3120 al.setDataset(null);
3124 boolean isdsal = jalviewModel.getViewport().isEmpty();
3127 // we are importing a dataset record, so
3128 // recover reference to an alignment already materialsed as dataset
3129 al = getDatasetFor(vamsasSet.getDatasetId());
3133 // materialse the alignment
3134 al = new Alignment(orderedSeqs);
3138 addDatasetRef(vamsasSet.getDatasetId(), al);
3141 // finally, verify all data in vamsasSet is actually present in al
3142 // passing on flag indicating if it is actually a stored dataset
3143 recoverDatasetFor(vamsasSet, al, isdsal);
3146 if (referenceseqForView != null)
3148 al.setSeqrep(referenceseqForView);
3150 // / Add the alignment properties
3151 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3153 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3155 al.setProperty(ssp.getKey(), ssp.getValue());
3158 // ///////////////////////////////
3160 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3163 // load sequence features, database references and any associated PDB
3164 // structures for the alignment
3166 // prior to 2.10, this part would only be executed the first time a
3167 // sequence was encountered, but not afterwards.
3168 // now, for 2.10 projects, this is also done if the xml doc includes
3169 // dataset sequences not actually present in any particular view.
3171 for (int i = 0; i < vamsasSeqs.size(); i++)
3173 JSeq jseq = jseqs.get(i);
3174 if (jseq.getFeatures().size() > 0)
3176 List<Feature> features = jseq.getFeatures();
3177 for (int f = 0; f < features.size(); f++)
3179 Feature feat = features.get(f);
3180 SequenceFeature sf = new SequenceFeature(feat.getType(),
3181 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3182 safeFloat(feat.getScore()), feat.getFeatureGroup());
3183 sf.setStatus(feat.getStatus());
3186 * load any feature attributes - include map-valued attributes
3188 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3189 for (int od = 0; od < feat.getOtherData().size(); od++)
3191 OtherData keyValue = feat.getOtherData().get(od);
3192 String attributeName = keyValue.getKey();
3193 String attributeValue = keyValue.getValue();
3194 if (attributeName.startsWith("LINK"))
3196 sf.addLink(attributeValue);
3200 String subAttribute = keyValue.getKey2();
3201 if (subAttribute == null)
3203 // simple string-valued attribute
3204 sf.setValue(attributeName, attributeValue);
3208 // attribute 'key' has sub-attribute 'key2'
3209 if (!mapAttributes.containsKey(attributeName))
3211 mapAttributes.put(attributeName, new HashMap<>());
3213 mapAttributes.get(attributeName).put(subAttribute,
3218 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3221 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3224 // adds feature to datasequence's feature set (since Jalview 2.10)
3225 al.getSequenceAt(i).addSequenceFeature(sf);
3228 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3230 // adds dbrefs to datasequence's set (since Jalview 2.10)
3232 al.getSequenceAt(i).getDatasetSequence() == null
3233 ? al.getSequenceAt(i)
3234 : al.getSequenceAt(i).getDatasetSequence(),
3237 if (jseq.getPdbids().size() > 0)
3239 List<Pdbids> ids = jseq.getPdbids();
3240 for (int p = 0; p < ids.size(); p++)
3242 Pdbids pdbid = ids.get(p);
3243 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3244 entry.setId(pdbid.getId());
3245 if (pdbid.getType() != null)
3247 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3249 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3253 entry.setType(PDBEntry.Type.FILE);
3256 // jprovider is null when executing 'New View'
3257 if (pdbid.getFile() != null && jprovider != null)
3259 if (!pdbloaded.containsKey(pdbid.getFile()))
3261 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3266 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3270 if (pdbid.getPdbentryItem() != null)
3272 for (PdbentryItem item : pdbid.getPdbentryItem())
3274 for (Property pr : item.getProperty())
3276 entry.setProperty(pr.getName(), pr.getValue());
3281 for (Property prop : pdbid.getProperty())
3283 entry.setProperty(prop.getName(), prop.getValue());
3285 StructureSelectionManager
3286 .getStructureSelectionManager(Desktop.instance)
3287 .registerPDBEntry(entry);
3288 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3289 if (al.getSequenceAt(i).getDatasetSequence() != null)
3291 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3295 al.getSequenceAt(i).addPDBId(entry);
3300 } // end !multipleview
3302 // ///////////////////////////////
3303 // LOAD SEQUENCE MAPPINGS
3305 if (vamsasSet.getAlcodonFrame().size() > 0)
3307 // TODO Potentially this should only be done once for all views of an
3309 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3310 for (int i = 0; i < alc.size(); i++)
3312 AlignedCodonFrame cf = new AlignedCodonFrame();
3313 if (alc.get(i).getAlcodMap().size() > 0)
3315 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3316 for (int m = 0; m < maps.size(); m++)
3318 AlcodMap map = maps.get(m);
3319 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3321 jalview.datamodel.Mapping mapping = null;
3322 // attach to dna sequence reference.
3323 if (map.getMapping() != null)
3325 mapping = addMapping(map.getMapping());
3326 if (dnaseq != null && mapping.getTo() != null)
3328 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3334 newAlcodMapRef(map.getDnasq(), cf, mapping));
3338 al.addCodonFrame(cf);
3343 // ////////////////////////////////
3345 List<JvAnnotRow> autoAlan = new ArrayList<>();
3348 * store any annotations which forward reference a group's ID
3350 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3352 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3354 List<Annotation> an = vamsasSet.getAnnotation();
3356 for (int i = 0; i < an.size(); i++)
3358 Annotation annotation = an.get(i);
3361 * test if annotation is automatically calculated for this view only
3363 boolean autoForView = false;
3364 if (annotation.getLabel().equals("Quality")
3365 || annotation.getLabel().equals("Conservation")
3366 || annotation.getLabel().equals("Consensus"))
3368 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3370 // JAXB has no has() test; schema defaults value to false
3371 // if (!annotation.hasAutoCalculated())
3373 // annotation.setAutoCalculated(true);
3376 if (autoForView || annotation.isAutoCalculated())
3378 // remove ID - we don't recover annotation from other views for
3379 // view-specific annotation
3380 annotation.setId(null);
3383 // set visibility for other annotation in this view
3384 String annotationId = annotation.getId();
3385 if (annotationId != null && annotationIds.containsKey(annotationId))
3387 AlignmentAnnotation jda = annotationIds.get(annotationId);
3388 // in principle Visible should always be true for annotation displayed
3389 // in multiple views
3390 if (annotation.isVisible() != null)
3392 jda.visible = annotation.isVisible();
3395 al.addAnnotation(jda);
3399 // Construct new annotation from model.
3400 List<AnnotationElement> ae = annotation.getAnnotationElement();
3401 jalview.datamodel.Annotation[] anot = null;
3402 java.awt.Color firstColour = null;
3404 if (!annotation.isScoreOnly())
3406 anot = new jalview.datamodel.Annotation[al.getWidth()];
3407 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3409 AnnotationElement annElement = ae.get(aa);
3410 anpos = annElement.getPosition();
3412 if (anpos >= anot.length)
3417 float value = safeFloat(annElement.getValue());
3418 anot[anpos] = new jalview.datamodel.Annotation(
3419 annElement.getDisplayCharacter(),
3420 annElement.getDescription(),
3421 (annElement.getSecondaryStructure() == null
3422 || annElement.getSecondaryStructure()
3426 .getSecondaryStructure()
3429 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3430 if (firstColour == null)
3432 firstColour = anot[anpos].colour;
3436 jalview.datamodel.AlignmentAnnotation jaa = null;
3438 if (annotation.isGraph())
3440 float llim = 0, hlim = 0;
3441 // if (autoForView || an[i].isAutoCalculated()) {
3444 jaa = new jalview.datamodel.AlignmentAnnotation(
3445 annotation.getLabel(), annotation.getDescription(), anot,
3446 llim, hlim, safeInt(annotation.getGraphType()));
3448 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3449 jaa._linecolour = firstColour;
3450 if (annotation.getThresholdLine() != null)
3452 jaa.setThreshold(new jalview.datamodel.GraphLine(
3453 safeFloat(annotation.getThresholdLine().getValue()),
3454 annotation.getThresholdLine().getLabel(),
3455 new java.awt.Color(safeInt(
3456 annotation.getThresholdLine().getColour()))));
3458 if (autoForView || annotation.isAutoCalculated())
3460 // Hardwire the symbol display line to ensure that labels for
3461 // histograms are displayed
3467 jaa = new jalview.datamodel.AlignmentAnnotation(
3468 annotation.getLabel(), annotation.getDescription(), anot);
3469 jaa._linecolour = firstColour;
3471 // register new annotation
3472 if (annotation.getId() != null)
3474 annotationIds.put(annotation.getId(), jaa);
3475 jaa.annotationId = annotation.getId();
3477 // recover sequence association
3478 String sequenceRef = annotation.getSequenceRef();
3479 if (sequenceRef != null)
3481 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3482 SequenceI sequence = seqRefIds.get(sequenceRef);
3483 if (sequence == null)
3485 // in pre-2.9 projects sequence ref is to sequence name
3486 sequence = al.findName(sequenceRef);
3488 if (sequence != null)
3490 jaa.createSequenceMapping(sequence, 1, true);
3491 sequence.addAlignmentAnnotation(jaa);
3494 // and make a note of any group association
3495 if (annotation.getGroupRef() != null
3496 && annotation.getGroupRef().length() > 0)
3498 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3499 .get(annotation.getGroupRef());
3502 aal = new ArrayList<>();
3503 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3508 if (annotation.getScore() != null)
3510 jaa.setScore(annotation.getScore().doubleValue());
3512 if (annotation.isVisible() != null)
3514 jaa.visible = annotation.isVisible().booleanValue();
3517 if (annotation.isCentreColLabels() != null)
3519 jaa.centreColLabels = annotation.isCentreColLabels()
3523 if (annotation.isScaleColLabels() != null)
3525 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3527 if (annotation.isAutoCalculated())
3529 // newer files have an 'autoCalculated' flag and store calculation
3530 // state in viewport properties
3531 jaa.autoCalculated = true; // means annotation will be marked for
3532 // update at end of load.
3534 if (annotation.getGraphHeight() != null)
3536 jaa.graphHeight = annotation.getGraphHeight().intValue();
3538 jaa.belowAlignment = annotation.isBelowAlignment();
3539 jaa.setCalcId(annotation.getCalcId());
3540 if (annotation.getProperty().size() > 0)
3542 for (Annotation.Property prop : annotation
3545 jaa.setProperty(prop.getName(), prop.getValue());
3548 if (jaa.autoCalculated)
3550 autoAlan.add(new JvAnnotRow(i, jaa));
3553 // if (!autoForView)
3555 // add autocalculated group annotation and any user created annotation
3557 al.addAnnotation(jaa);
3561 // ///////////////////////
3563 // Create alignment markup and styles for this view
3564 if (jalviewModel.getJGroup().size() > 0)
3566 List<JGroup> groups = jalviewModel.getJGroup();
3567 boolean addAnnotSchemeGroup = false;
3568 for (int i = 0; i < groups.size(); i++)
3570 JGroup jGroup = groups.get(i);
3571 ColourSchemeI cs = null;
3572 if (jGroup.getColour() != null)
3574 if (jGroup.getColour().startsWith("ucs"))
3576 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3578 else if (jGroup.getColour().equals("AnnotationColourGradient")
3579 && jGroup.getAnnotationColours() != null)
3581 addAnnotSchemeGroup = true;
3585 cs = ColourSchemeProperty.getColourScheme(al,
3586 jGroup.getColour());
3589 int pidThreshold = safeInt(jGroup.getPidThreshold());
3591 Vector<SequenceI> seqs = new Vector<>();
3593 for (int s = 0; s < jGroup.getSeq().size(); s++)
3595 String seqId = jGroup.getSeq().get(s);
3596 SequenceI ts = seqRefIds.get(seqId);
3600 seqs.addElement(ts);
3604 if (seqs.size() < 1)
3609 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3610 safeBoolean(jGroup.isDisplayBoxes()),
3611 safeBoolean(jGroup.isDisplayText()),
3612 safeBoolean(jGroup.isColourText()),
3613 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3614 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3615 sg.getGroupColourScheme()
3616 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3617 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3619 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3620 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3621 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3622 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3623 // attributes with a default in the schema are never null
3624 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3625 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3626 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3627 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3628 if (jGroup.getConsThreshold() != null
3629 && jGroup.getConsThreshold().intValue() != 0)
3631 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3634 c.verdict(false, 25);
3635 sg.cs.setConservation(c);
3638 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3640 // re-instate unique group/annotation row reference
3641 List<AlignmentAnnotation> jaal = groupAnnotRefs
3642 .get(jGroup.getId());
3645 for (AlignmentAnnotation jaa : jaal)
3648 if (jaa.autoCalculated)
3650 // match up and try to set group autocalc alignment row for this
3652 if (jaa.label.startsWith("Consensus for "))
3654 sg.setConsensus(jaa);
3656 // match up and try to set group autocalc alignment row for this
3658 if (jaa.label.startsWith("Conservation for "))
3660 sg.setConservationRow(jaa);
3667 if (addAnnotSchemeGroup)
3669 // reconstruct the annotation colourscheme
3670 sg.setColourScheme(constructAnnotationColour(
3671 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3677 // only dataset in this model, so just return.
3680 // ///////////////////////////////
3683 // If we just load in the same jar file again, the sequenceSetId
3684 // will be the same, and we end up with multiple references
3685 // to the same sequenceSet. We must modify this id on load
3686 // so that each load of the file gives a unique id
3687 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3688 String viewId = (view.getId() == null ? null
3689 : view.getId() + uniqueSetSuffix);
3690 AlignFrame af = null;
3691 AlignViewport av = null;
3692 // now check to see if we really need to create a new viewport.
3693 if (multipleView && viewportsAdded.size() == 0)
3695 // We recovered an alignment for which a viewport already exists.
3696 // TODO: fix up any settings necessary for overlaying stored state onto
3697 // state recovered from another document. (may not be necessary).
3698 // we may need a binding from a viewport in memory to one recovered from
3700 // and then recover its containing af to allow the settings to be applied.
3701 // TODO: fix for vamsas demo
3703 "About to recover a viewport for existing alignment: Sequence set ID is "
3705 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3706 if (seqsetobj != null)
3708 if (seqsetobj instanceof String)
3710 uniqueSeqSetId = (String) seqsetobj;
3712 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3718 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3724 * indicate that annotation colours are applied across all groups (pre
3725 * Jalview 2.8.1 behaviour)
3727 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3728 jalviewModel.getVersion());
3730 AlignmentPanel ap = null;
3731 boolean isnewview = true;
3734 // Check to see if this alignment already has a view id == viewId
3735 jalview.gui.AlignmentPanel views[] = Desktop
3736 .getAlignmentPanels(uniqueSeqSetId);
3737 if (views != null && views.length > 0)
3739 for (int v = 0; v < views.length; v++)
3741 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3743 // recover the existing alignpanel, alignframe, viewport
3744 af = views[v].alignFrame;
3747 // TODO: could even skip resetting view settings if we don't want to
3748 // change the local settings from other jalview processes
3757 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
3758 uniqueSeqSetId, viewId, autoAlan);
3759 av = af.getViewport();
3764 * Load any trees, PDB structures and viewers
3766 * Not done if flag is false (when this method is used for New View)
3768 if (loadTreesAndStructures)
3770 loadTrees(jalviewModel, view, af, av, ap);
3771 loadPDBStructures(jprovider, jseqs, af, ap);
3772 loadRnaViewers(jprovider, jseqs, ap);
3774 // and finally return.
3779 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3780 * panel is restored from separate jar entries, two (gapped and trimmed) per
3781 * sequence and secondary structure.
3783 * Currently each viewer shows just one sequence and structure (gapped and
3784 * trimmed), however this method is designed to support multiple sequences or
3785 * structures in viewers if wanted in future.
3791 private void loadRnaViewers(jarInputStreamProvider jprovider,
3792 List<JSeq> jseqs, AlignmentPanel ap)
3795 * scan the sequences for references to viewers; create each one the first
3796 * time it is referenced, add Rna models to existing viewers
3798 for (JSeq jseq : jseqs)
3800 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
3802 RnaViewer viewer = jseq.getRnaViewer().get(i);
3803 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3806 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
3808 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
3809 SequenceI seq = seqRefIds.get(jseq.getId());
3810 AlignmentAnnotation ann = this.annotationIds
3811 .get(ss.getAnnotationId());
3814 * add the structure to the Varna display (with session state copied
3815 * from the jar to a temporary file)
3817 boolean gapped = safeBoolean(ss.isGapped());
3818 String rnaTitle = ss.getTitle();
3819 String sessionState = ss.getViewerState();
3820 String tempStateFile = copyJarEntry(jprovider, sessionState,
3822 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3823 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3825 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
3831 * Locate and return an already instantiated matching AppVarna, or create one
3835 * @param viewIdSuffix
3839 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3840 String viewIdSuffix, AlignmentPanel ap)
3843 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3844 * if load is repeated
3846 String postLoadId = viewer.getViewId() + viewIdSuffix;
3847 for (JInternalFrame frame : getAllFrames())
3849 if (frame instanceof AppVarna)
3851 AppVarna varna = (AppVarna) frame;
3852 if (postLoadId.equals(varna.getViewId()))
3854 // this viewer is already instantiated
3855 // could in future here add ap as another 'parent' of the
3856 // AppVarna window; currently just 1-to-many
3863 * viewer not found - make it
3865 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3866 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
3867 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
3868 safeInt(viewer.getDividerLocation()));
3869 AppVarna varna = new AppVarna(model, ap);
3875 * Load any saved trees
3883 protected void loadTrees(JalviewModel jm, Viewport view,
3884 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3886 // TODO result of automated refactoring - are all these parameters needed?
3889 for (int t = 0; t < jm.getTree().size(); t++)
3892 Tree tree = jm.getTree().get(t);
3894 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3897 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
3898 tree.getTitle(), safeInt(tree.getWidth()),
3899 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
3900 safeInt(tree.getYpos()));
3901 if (tree.getId() != null)
3903 // perhaps bind the tree id to something ?
3908 // update local tree attributes ?
3909 // TODO: should check if tp has been manipulated by user - if so its
3910 // settings shouldn't be modified
3911 tp.setTitle(tree.getTitle());
3912 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
3913 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
3914 safeInt(tree.getHeight())));
3915 tp.setViewport(av); // af.viewport;
3916 // TODO: verify 'associate with all views' works still
3917 tp.getTreeCanvas().setViewport(av); // af.viewport;
3918 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
3923 warn("There was a problem recovering stored Newick tree: \n"
3924 + tree.getNewick());
3928 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
3929 tp.fitToWindow_actionPerformed(null);
3931 if (tree.getFontName() != null)
3934 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
3935 safeInt(tree.getFontSize())));
3940 new Font(view.getFontName(), safeInt(view.getFontStyle()),
3941 safeInt(view.getFontSize())));
3944 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
3945 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
3946 tp.showDistances(safeBoolean(tree.isShowDistances()));
3948 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
3950 if (safeBoolean(tree.isCurrentTree()))
3952 af.getViewport().setCurrentTree(tp.getTree());
3956 } catch (Exception ex)
3958 ex.printStackTrace();
3963 * Load and link any saved structure viewers.
3970 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3971 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
3974 * Run through all PDB ids on the alignment, and collect mappings between
3975 * distinct view ids and all sequences referring to that view.
3977 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3979 for (int i = 0; i < jseqs.size(); i++)
3981 JSeq jseq = jseqs.get(i);
3982 if (jseq.getPdbids().size() > 0)
3984 List<Pdbids> ids = jseq.getPdbids();
3985 for (int p = 0; p < ids.size(); p++)
3987 Pdbids pdbid = ids.get(p);
3988 final int structureStateCount = pdbid.getStructureState().size();
3989 for (int s = 0; s < structureStateCount; s++)
3991 // check to see if we haven't already created this structure view
3992 final StructureState structureState = pdbid
3993 .getStructureState().get(s);
3994 String sviewid = (structureState.getViewId() == null) ? null
3995 : structureState.getViewId() + uniqueSetSuffix;
3996 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3997 // Originally : pdbid.getFile()
3998 // : TODO: verify external PDB file recovery still works in normal
3999 // jalview project load
4001 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4002 jpdb.setId(pdbid.getId());
4004 int x = safeInt(structureState.getXpos());
4005 int y = safeInt(structureState.getYpos());
4006 int width = safeInt(structureState.getWidth());
4007 int height = safeInt(structureState.getHeight());
4009 // Probably don't need to do this anymore...
4010 // Desktop.desktop.getComponentAt(x, y);
4011 // TODO: NOW: check that this recovers the PDB file correctly.
4012 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4014 jalview.datamodel.SequenceI seq = seqRefIds
4015 .get(jseq.getId() + "");
4016 if (sviewid == null)
4018 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4021 if (!structureViewers.containsKey(sviewid))
4023 structureViewers.put(sviewid,
4024 new StructureViewerModel(x, y, width, height, false,
4025 false, true, structureState.getViewId(),
4026 structureState.getType()));
4027 // Legacy pre-2.7 conversion JAL-823 :
4028 // do not assume any view has to be linked for colour by
4032 // assemble String[] { pdb files }, String[] { id for each
4033 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4034 // seqs_file 2}, boolean[] {
4035 // linkAlignPanel,superposeWithAlignpanel}} from hash
4036 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4037 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4038 || structureState.isAlignwithAlignPanel());
4041 * Default colour by linked panel to false if not specified (e.g.
4042 * for pre-2.7 projects)
4044 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4045 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4046 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4049 * Default colour by viewer to true if not specified (e.g. for
4052 boolean colourByViewer = jmoldat.isColourByViewer();
4053 colourByViewer &= structureState.isColourByJmol();
4054 jmoldat.setColourByViewer(colourByViewer);
4056 if (jmoldat.getStateData().length() < structureState
4057 .getValue()/*Content()*/.length())
4059 jmoldat.setStateData(structureState.getValue());// Content());
4061 if (pdbid.getFile() != null)
4063 File mapkey = new File(pdbid.getFile());
4064 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4065 if (seqstrmaps == null)
4067 jmoldat.getFileData().put(mapkey,
4068 seqstrmaps = jmoldat.new StructureData(pdbFile,
4071 if (!seqstrmaps.getSeqList().contains(seq))
4073 seqstrmaps.getSeqList().add(seq);
4079 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");
4086 // Instantiate the associated structure views
4087 for (Entry<String, StructureViewerModel> entry : structureViewers
4092 createOrLinkStructureViewer(entry, af, ap, jprovider);
4093 } catch (Exception e)
4096 "Error loading structure viewer: " + e.getMessage());
4097 // failed - try the next one
4109 protected void createOrLinkStructureViewer(
4110 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4111 AlignmentPanel ap, jarInputStreamProvider jprovider)
4113 final StructureViewerModel stateData = viewerData.getValue();
4116 * Search for any viewer windows already open from other alignment views
4117 * that exactly match the stored structure state
4119 StructureViewerBase comp = findMatchingViewer(viewerData);
4123 linkStructureViewer(ap, comp, stateData);
4128 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4129 * "viewer_"+stateData.viewId
4131 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4133 createChimeraViewer(viewerData, af, jprovider);
4138 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4140 createJmolViewer(viewerData, af, jprovider);
4145 * Create a new Chimera viewer.
4151 protected void createChimeraViewer(
4152 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4153 jarInputStreamProvider jprovider)
4155 StructureViewerModel data = viewerData.getValue();
4156 String chimeraSessionFile = data.getStateData();
4159 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4161 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4162 * 'uniquified' sviewid used to reconstruct the viewer here
4164 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4165 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4168 Set<Entry<File, StructureData>> fileData = data.getFileData()
4170 List<PDBEntry> pdbs = new ArrayList<>();
4171 List<SequenceI[]> allseqs = new ArrayList<>();
4172 for (Entry<File, StructureData> pdb : fileData)
4174 String filePath = pdb.getValue().getFilePath();
4175 String pdbId = pdb.getValue().getPdbId();
4176 // pdbs.add(new PDBEntry(filePath, pdbId));
4177 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4178 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4179 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4183 boolean colourByChimera = data.isColourByViewer();
4184 boolean colourBySequence = data.isColourWithAlignPanel();
4186 // TODO use StructureViewer as a factory here, see JAL-1761
4187 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4188 final SequenceI[][] seqsArray = allseqs
4189 .toArray(new SequenceI[allseqs.size()][]);
4190 String newViewId = viewerData.getKey();
4192 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4193 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4194 colourBySequence, newViewId);
4195 cvf.setSize(data.getWidth(), data.getHeight());
4196 cvf.setLocation(data.getX(), data.getY());
4200 * Create a new Jmol window. First parse the Jmol state to translate filenames
4201 * loaded into the view, and record the order in which files are shown in the
4202 * Jmol view, so we can add the sequence mappings in same order.
4208 protected void createJmolViewer(
4209 final Entry<String, StructureViewerModel> viewerData,
4210 AlignFrame af, jarInputStreamProvider jprovider)
4212 final StructureViewerModel svattrib = viewerData.getValue();
4213 String state = svattrib.getStateData();
4216 * Pre-2.9: state element value is the Jmol state string
4218 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4221 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4223 state = readJarEntry(jprovider,
4224 getViewerJarEntryName(svattrib.getViewId()));
4227 List<String> pdbfilenames = new ArrayList<>();
4228 List<SequenceI[]> seqmaps = new ArrayList<>();
4229 List<String> pdbids = new ArrayList<>();
4230 StringBuilder newFileLoc = new StringBuilder(64);
4231 int cp = 0, ncp, ecp;
4232 Map<File, StructureData> oldFiles = svattrib.getFileData();
4233 while ((ncp = state.indexOf("load ", cp)) > -1)
4237 // look for next filename in load statement
4238 newFileLoc.append(state.substring(cp,
4239 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4240 String oldfilenam = state.substring(ncp,
4241 ecp = state.indexOf("\"", ncp));
4242 // recover the new mapping data for this old filename
4243 // have to normalize filename - since Jmol and jalview do
4245 // translation differently.
4246 StructureData filedat = oldFiles.get(new File(oldfilenam));
4247 if (filedat == null)
4249 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4250 filedat = oldFiles.get(new File(reformatedOldFilename));
4252 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4253 pdbfilenames.add(filedat.getFilePath());
4254 pdbids.add(filedat.getPdbId());
4255 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4256 newFileLoc.append("\"");
4257 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4258 // look for next file statement.
4259 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4263 // just append rest of state
4264 newFileLoc.append(state.substring(cp));
4268 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4269 newFileLoc = new StringBuilder(state);
4270 newFileLoc.append("; load append ");
4271 for (File id : oldFiles.keySet())
4273 // add this and any other pdb files that should be present in
4275 StructureData filedat = oldFiles.get(id);
4276 newFileLoc.append(filedat.getFilePath());
4277 pdbfilenames.add(filedat.getFilePath());
4278 pdbids.add(filedat.getPdbId());
4279 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4280 newFileLoc.append(" \"");
4281 newFileLoc.append(filedat.getFilePath());
4282 newFileLoc.append("\"");
4285 newFileLoc.append(";");
4288 if (newFileLoc.length() == 0)
4292 int histbug = newFileLoc.indexOf("history = ");
4296 * change "history = [true|false];" to "history = [1|0];"
4299 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4300 String val = (diff == -1) ? null
4301 : newFileLoc.substring(histbug, diff);
4302 if (val != null && val.length() >= 4)
4304 if (val.contains("e")) // eh? what can it be?
4306 if (val.trim().equals("true"))
4314 newFileLoc.replace(histbug, diff, val);
4319 final String[] pdbf = pdbfilenames
4320 .toArray(new String[pdbfilenames.size()]);
4321 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4322 final SequenceI[][] sq = seqmaps
4323 .toArray(new SequenceI[seqmaps.size()][]);
4324 final String fileloc = newFileLoc.toString();
4325 final String sviewid = viewerData.getKey();
4326 final AlignFrame alf = af;
4327 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4328 svattrib.getWidth(), svattrib.getHeight());
4331 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4336 JalviewStructureDisplayI sview = null;
4339 sview = new StructureViewer(
4340 alf.alignPanel.getStructureSelectionManager())
4341 .createView(StructureViewer.ViewerType.JMOL,
4342 pdbf, id, sq, alf.alignPanel, svattrib,
4343 fileloc, rect, sviewid);
4344 addNewStructureViewer(sview);
4345 } catch (OutOfMemoryError ex)
4347 new OOMWarning("restoring structure view for PDB id " + id,
4348 (OutOfMemoryError) ex.getCause());
4349 if (sview != null && sview.isVisible())
4351 sview.closeViewer(false);
4352 sview.setVisible(false);
4358 } catch (InvocationTargetException ex)
4360 warn("Unexpected error when opening Jmol view.", ex);
4362 } catch (InterruptedException e)
4364 // e.printStackTrace();
4370 * Generates a name for the entry in the project jar file to hold state
4371 * information for a structure viewer
4376 protected String getViewerJarEntryName(String viewId)
4378 return VIEWER_PREFIX + viewId;
4382 * Returns any open frame that matches given structure viewer data. The match
4383 * is based on the unique viewId, or (for older project versions) the frame's
4389 protected StructureViewerBase findMatchingViewer(
4390 Entry<String, StructureViewerModel> viewerData)
4392 final String sviewid = viewerData.getKey();
4393 final StructureViewerModel svattrib = viewerData.getValue();
4394 StructureViewerBase comp = null;
4395 JInternalFrame[] frames = getAllFrames();
4396 for (JInternalFrame frame : frames)
4398 if (frame instanceof StructureViewerBase)
4401 * Post jalview 2.4 schema includes structure view id
4403 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4406 comp = (StructureViewerBase) frame;
4407 break; // break added in 2.9
4410 * Otherwise test for matching position and size of viewer frame
4412 else if (frame.getX() == svattrib.getX()
4413 && frame.getY() == svattrib.getY()
4414 && frame.getHeight() == svattrib.getHeight()
4415 && frame.getWidth() == svattrib.getWidth())
4417 comp = (StructureViewerBase) frame;
4418 // no break in faint hope of an exact match on viewId
4426 * Link an AlignmentPanel to an existing structure viewer.
4431 * @param useinViewerSuperpos
4432 * @param usetoColourbyseq
4433 * @param viewerColouring
4435 protected void linkStructureViewer(AlignmentPanel ap,
4436 StructureViewerBase viewer, StructureViewerModel stateData)
4438 // NOTE: if the jalview project is part of a shared session then
4439 // view synchronization should/could be done here.
4441 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4442 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4443 final boolean viewerColouring = stateData.isColourByViewer();
4444 Map<File, StructureData> oldFiles = stateData.getFileData();
4447 * Add mapping for sequences in this view to an already open viewer
4449 final AAStructureBindingModel binding = viewer.getBinding();
4450 for (File id : oldFiles.keySet())
4452 // add this and any other pdb files that should be present in the
4454 StructureData filedat = oldFiles.get(id);
4455 String pdbFile = filedat.getFilePath();
4456 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4457 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4459 binding.addSequenceForStructFile(pdbFile, seq);
4461 // and add the AlignmentPanel's reference to the view panel
4462 viewer.addAlignmentPanel(ap);
4463 if (useinViewerSuperpos)
4465 viewer.useAlignmentPanelForSuperposition(ap);
4469 viewer.excludeAlignmentPanelForSuperposition(ap);
4471 if (usetoColourbyseq)
4473 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4477 viewer.excludeAlignmentPanelForColourbyseq(ap);
4482 * Get all frames within the Desktop.
4486 protected JInternalFrame[] getAllFrames()
4488 JInternalFrame[] frames = null;
4489 // TODO is this necessary - is it safe - risk of hanging?
4494 frames = Desktop.desktop.getAllFrames();
4495 } catch (ArrayIndexOutOfBoundsException e)
4497 // occasional No such child exceptions are thrown here...
4501 } catch (InterruptedException f)
4505 } while (frames == null);
4510 * Answers true if 'version' is equal to or later than 'supported', where each
4511 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4512 * changes. Development and test values for 'version' are leniently treated
4516 * - minimum version we are comparing against
4518 * - version of data being processsed
4521 public static boolean isVersionStringLaterThan(String supported,
4524 if (supported == null || version == null
4525 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4526 || version.equalsIgnoreCase("Test")
4527 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4529 System.err.println("Assuming project file with "
4530 + (version == null ? "null" : version)
4531 + " is compatible with Jalview version " + supported);
4536 return StringUtils.compareVersions(version, supported, "b") >= 0;
4540 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4542 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4544 if (newStructureViewers != null)
4546 sview.getBinding().setFinishedLoadingFromArchive(false);
4547 newStructureViewers.add(sview);
4551 protected void setLoadingFinishedForNewStructureViewers()
4553 if (newStructureViewers != null)
4555 for (JalviewStructureDisplayI sview : newStructureViewers)
4557 sview.getBinding().setFinishedLoadingFromArchive(true);
4559 newStructureViewers.clear();
4560 newStructureViewers = null;
4564 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4565 List<SequenceI> hiddenSeqs, AlignmentI al,
4566 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4567 String viewId, List<JvAnnotRow> autoAlan)
4569 AlignFrame af = null;
4570 af = new AlignFrame(al, safeInt(view.getWidth()),
4571 safeInt(view.getHeight()), uniqueSeqSetId, viewId);
4573 af.setFileName(file, FileFormat.Jalview);
4575 final AlignViewport viewport = af.getViewport();
4576 for (int i = 0; i < JSEQ.size(); i++)
4578 int colour = safeInt(JSEQ.get(i).getColour());
4579 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4585 viewport.setColourByReferenceSeq(true);
4586 viewport.setDisplayReferenceSeq(true);
4589 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4591 if (view.getSequenceSetId() != null)
4593 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4595 viewport.setSequenceSetId(uniqueSeqSetId);
4598 // propagate shared settings to this new view
4599 viewport.setHistoryList(av.getHistoryList());
4600 viewport.setRedoList(av.getRedoList());
4604 viewportsAdded.put(uniqueSeqSetId, viewport);
4606 // TODO: check if this method can be called repeatedly without
4607 // side-effects if alignpanel already registered.
4608 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4610 // apply Hidden regions to view.
4611 if (hiddenSeqs != null)
4613 for (int s = 0; s < JSEQ.size(); s++)
4615 SequenceGroup hidden = new SequenceGroup();
4616 boolean isRepresentative = false;
4617 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4619 isRepresentative = true;
4620 SequenceI sequenceToHide = al
4621 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4622 hidden.addSequence(sequenceToHide, false);
4623 // remove from hiddenSeqs list so we don't try to hide it twice
4624 hiddenSeqs.remove(sequenceToHide);
4626 if (isRepresentative)
4628 SequenceI representativeSequence = al.getSequenceAt(s);
4629 hidden.addSequence(representativeSequence, false);
4630 viewport.hideRepSequences(representativeSequence, hidden);
4634 SequenceI[] hseqs = hiddenSeqs
4635 .toArray(new SequenceI[hiddenSeqs.size()]);
4636 viewport.hideSequence(hseqs);
4639 // recover view properties and display parameters
4641 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4642 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4643 final int pidThreshold = safeInt(view.getPidThreshold());
4644 viewport.setThreshold(pidThreshold);
4646 viewport.setColourText(safeBoolean(view.isShowColourText()));
4649 .setConservationSelected(
4650 safeBoolean(view.isConservationSelected()));
4651 viewport.setIncrement(safeInt(view.getConsThreshold()));
4652 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4653 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4654 viewport.setFont(new Font(view.getFontName(),
4655 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4657 ViewStyleI vs = viewport.getViewStyle();
4658 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4659 viewport.setViewStyle(vs);
4660 // TODO: allow custom charWidth/Heights to be restored by updating them
4661 // after setting font - which means set above to false
4662 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4663 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4664 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4666 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4668 viewport.setShowText(safeBoolean(view.isShowText()));
4670 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4671 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4672 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4673 viewport.setShowUnconserved(view.isShowUnconserved());
4674 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4676 if (view.getViewName() != null)
4678 viewport.setViewName(view.getViewName());
4679 af.setInitialTabVisible();
4681 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4682 safeInt(view.getWidth()), safeInt(view.getHeight()));
4683 // startSeq set in af.alignPanel.updateLayout below
4684 af.alignPanel.updateLayout();
4685 ColourSchemeI cs = null;
4686 // apply colourschemes
4687 if (view.getBgColour() != null)
4689 if (view.getBgColour().startsWith("ucs"))
4691 cs = getUserColourScheme(jm, view.getBgColour());
4693 else if (view.getBgColour().startsWith("Annotation"))
4695 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4696 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4703 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4707 viewport.setGlobalColourScheme(cs);
4708 viewport.getResidueShading().setThreshold(pidThreshold,
4709 view.isIgnoreGapsinConsensus());
4710 viewport.getResidueShading()
4711 .setConsensus(viewport.getSequenceConsensusHash());
4712 viewport.setColourAppliesToAllGroups(false);
4714 if (safeBoolean(view.isConservationSelected()) && cs != null)
4716 viewport.getResidueShading()
4717 .setConservationInc(safeInt(view.getConsThreshold()));
4720 af.changeColour(cs);
4722 viewport.setColourAppliesToAllGroups(true);
4725 .setShowSequenceFeatures(
4726 safeBoolean(view.isShowSequenceFeatures()));
4728 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4729 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4730 viewport.setFollowHighlight(view.isFollowHighlight());
4731 viewport.followSelection = view.isFollowSelection();
4732 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4733 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4734 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4735 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4736 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4737 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4738 viewport.setShowGroupConservation(view.isShowGroupConservation());
4740 // recover feature settings
4741 if (jm.getFeatureSettings() != null)
4743 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4744 .getFeatureRenderer();
4745 FeaturesDisplayed fdi;
4746 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4747 String[] renderOrder = new String[jm.getFeatureSettings()
4748 .getSetting().size()];
4749 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4750 Map<String, Float> featureOrder = new Hashtable<>();
4752 for (int fs = 0; fs < jm.getFeatureSettings()
4753 .getSetting().size(); fs++)
4755 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4756 String featureType = setting.getType();
4759 * restore feature filters (if any)
4761 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4763 if (filters != null)
4765 FeatureMatcherSetI filter = Jalview2XML
4766 .parseFilter(featureType, filters);
4767 if (!filter.isEmpty())
4769 fr.setFeatureFilter(featureType, filter);
4774 * restore feature colour scheme
4776 Color maxColour = new Color(setting.getColour());
4777 if (setting.getMincolour() != null)
4780 * minColour is always set unless a simple colour
4781 * (including for colour by label though it doesn't use it)
4783 Color minColour = new Color(setting.getMincolour().intValue());
4784 Color noValueColour = minColour;
4785 NoValueColour noColour = setting.getNoValueColour();
4786 if (noColour == NoValueColour.NONE)
4788 noValueColour = null;
4790 else if (noColour == NoValueColour.MAX)
4792 noValueColour = maxColour;
4794 float min = safeFloat(safeFloat(setting.getMin()));
4795 float max = setting.getMax() == null ? 1f
4796 : setting.getMax().floatValue();
4797 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4798 noValueColour, min, max);
4799 if (setting.getAttributeName().size() > 0)
4801 gc.setAttributeName(setting.getAttributeName().toArray(
4802 new String[setting.getAttributeName().size()]));
4804 if (setting.getThreshold() != null)
4806 gc.setThreshold(setting.getThreshold().floatValue());
4807 int threshstate = safeInt(setting.getThreshstate());
4808 // -1 = None, 0 = Below, 1 = Above threshold
4809 if (threshstate == 0)
4811 gc.setBelowThreshold(true);
4813 else if (threshstate == 1)
4815 gc.setAboveThreshold(true);
4818 gc.setAutoScaled(true); // default
4819 if (setting.isAutoScale() != null)
4821 gc.setAutoScaled(setting.isAutoScale());
4823 if (setting.isColourByLabel() != null)
4825 gc.setColourByLabel(setting.isColourByLabel());
4827 // and put in the feature colour table.
4828 featureColours.put(featureType, gc);
4832 featureColours.put(featureType,
4833 new FeatureColour(maxColour));
4835 renderOrder[fs] = featureType;
4836 if (setting.getOrder() != null)
4838 featureOrder.put(featureType, setting.getOrder().floatValue());
4842 featureOrder.put(featureType, new Float(
4843 fs / jm.getFeatureSettings().getSetting().size()));
4845 if (safeBoolean(setting.isDisplay()))
4847 fdi.setVisible(featureType);
4850 Map<String, Boolean> fgtable = new Hashtable<>();
4851 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4853 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4854 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
4856 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4857 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4858 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4859 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4860 fgtable, featureColours, 1.0f, featureOrder);
4861 fr.transferSettings(frs);
4864 if (view.getHiddenColumns().size() > 0)
4866 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4868 final HiddenColumns hc = view.getHiddenColumns().get(c);
4869 viewport.hideColumns(safeInt(hc.getStart()),
4870 safeInt(hc.getEnd()) /* +1 */);
4873 if (view.getCalcIdParam() != null)
4875 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4877 if (calcIdParam != null)
4879 if (recoverCalcIdParam(calcIdParam, viewport))
4884 warn("Couldn't recover parameters for "
4885 + calcIdParam.getCalcId());
4890 af.setMenusFromViewport(viewport);
4891 af.setTitle(view.getTitle());
4892 // TODO: we don't need to do this if the viewport is aready visible.
4894 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4895 * has a 'cdna/protein complement' view, in which case save it in order to
4896 * populate a SplitFrame once all views have been read in.
4898 String complementaryViewId = view.getComplementId();
4899 if (complementaryViewId == null)
4901 Desktop.addInternalFrame(af, view.getTitle(),
4902 safeInt(view.getWidth()), safeInt(view.getHeight()));
4903 // recompute any autoannotation
4904 af.alignPanel.updateAnnotation(false, true);
4905 reorderAutoannotation(af, al, autoAlan);
4906 af.alignPanel.alignmentChanged();
4910 splitFrameCandidates.put(view, af);
4916 * Reads saved data to restore Colour by Annotation settings
4918 * @param viewAnnColour
4922 * @param checkGroupAnnColour
4925 private ColourSchemeI constructAnnotationColour(
4926 AnnotationColourScheme viewAnnColour, AlignFrame af,
4927 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
4929 boolean propagateAnnColour = false;
4930 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
4932 if (checkGroupAnnColour && al.getGroups() != null
4933 && al.getGroups().size() > 0)
4935 // pre 2.8.1 behaviour
4936 // check to see if we should transfer annotation colours
4937 propagateAnnColour = true;
4938 for (SequenceGroup sg : al.getGroups())
4940 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4942 propagateAnnColour = false;
4948 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4950 String annotationId = viewAnnColour.getAnnotation();
4951 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4954 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4956 if (matchedAnnotation == null
4957 && annAlignment.getAlignmentAnnotation() != null)
4959 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4962 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4964 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4969 if (matchedAnnotation == null)
4971 System.err.println("Failed to match annotation colour scheme for "
4975 if (matchedAnnotation.getThreshold() == null)
4977 matchedAnnotation.setThreshold(
4978 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
4979 "Threshold", Color.black));
4982 AnnotationColourGradient cs = null;
4983 if (viewAnnColour.getColourScheme().equals("None"))
4985 cs = new AnnotationColourGradient(matchedAnnotation,
4986 new Color(safeInt(viewAnnColour.getMinColour())),
4987 new Color(safeInt(viewAnnColour.getMaxColour())),
4988 safeInt(viewAnnColour.getAboveThreshold()));
4990 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4992 cs = new AnnotationColourGradient(matchedAnnotation,
4993 getUserColourScheme(model, viewAnnColour.getColourScheme()),
4994 safeInt(viewAnnColour.getAboveThreshold()));
4998 cs = new AnnotationColourGradient(matchedAnnotation,
4999 ColourSchemeProperty.getColourScheme(al,
5000 viewAnnColour.getColourScheme()),
5001 safeInt(viewAnnColour.getAboveThreshold()));
5004 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5005 boolean useOriginalColours = safeBoolean(
5006 viewAnnColour.isPredefinedColours());
5007 cs.setSeqAssociated(perSequenceOnly);
5008 cs.setPredefinedColours(useOriginalColours);
5010 if (propagateAnnColour && al.getGroups() != null)
5012 // Also use these settings for all the groups
5013 for (int g = 0; g < al.getGroups().size(); g++)
5015 SequenceGroup sg = al.getGroups().get(g);
5016 if (sg.getGroupColourScheme() == null)
5021 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5022 matchedAnnotation, sg.getColourScheme(),
5023 safeInt(viewAnnColour.getAboveThreshold()));
5024 sg.setColourScheme(groupScheme);
5025 groupScheme.setSeqAssociated(perSequenceOnly);
5026 groupScheme.setPredefinedColours(useOriginalColours);
5032 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5033 List<JvAnnotRow> autoAlan)
5035 // copy over visualization settings for autocalculated annotation in the
5037 if (al.getAlignmentAnnotation() != null)
5040 * Kludge for magic autoannotation names (see JAL-811)
5042 String[] magicNames = new String[] { "Consensus", "Quality",
5044 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5045 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5046 for (String nm : magicNames)
5048 visan.put(nm, nullAnnot);
5050 for (JvAnnotRow auan : autoAlan)
5052 visan.put(auan.template.label
5053 + (auan.template.getCalcId() == null ? ""
5054 : "\t" + auan.template.getCalcId()),
5057 int hSize = al.getAlignmentAnnotation().length;
5058 List<JvAnnotRow> reorder = new ArrayList<>();
5059 // work through any autoCalculated annotation already on the view
5060 // removing it if it should be placed in a different location on the
5061 // annotation panel.
5062 List<String> remains = new ArrayList<>(visan.keySet());
5063 for (int h = 0; h < hSize; h++)
5065 jalview.datamodel.AlignmentAnnotation jalan = al
5066 .getAlignmentAnnotation()[h];
5067 if (jalan.autoCalculated)
5070 JvAnnotRow valan = visan.get(k = jalan.label);
5071 if (jalan.getCalcId() != null)
5073 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5078 // delete the auto calculated row from the alignment
5079 al.deleteAnnotation(jalan, false);
5083 if (valan != nullAnnot)
5085 if (jalan != valan.template)
5087 // newly created autoannotation row instance
5088 // so keep a reference to the visible annotation row
5089 // and copy over all relevant attributes
5090 if (valan.template.graphHeight >= 0)
5093 jalan.graphHeight = valan.template.graphHeight;
5095 jalan.visible = valan.template.visible;
5097 reorder.add(new JvAnnotRow(valan.order, jalan));
5102 // Add any (possibly stale) autocalculated rows that were not appended to
5103 // the view during construction
5104 for (String other : remains)
5106 JvAnnotRow othera = visan.get(other);
5107 if (othera != nullAnnot && othera.template.getCalcId() != null
5108 && othera.template.getCalcId().length() > 0)
5110 reorder.add(othera);
5113 // now put the automatic annotation in its correct place
5114 int s = 0, srt[] = new int[reorder.size()];
5115 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5116 for (JvAnnotRow jvar : reorder)
5119 srt[s++] = jvar.order;
5122 jalview.util.QuickSort.sort(srt, rws);
5123 // and re-insert the annotation at its correct position
5124 for (JvAnnotRow jvar : rws)
5126 al.addAnnotation(jvar.template, jvar.order);
5128 af.alignPanel.adjustAnnotationHeight();
5132 Hashtable skipList = null;
5135 * TODO remove this method
5138 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5139 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5140 * throw new Error("Implementation Error. No skipList defined for this
5141 * Jalview2XML instance."); } return (AlignFrame)
5142 * skipList.get(view.getSequenceSetId()); }
5146 * Check if the Jalview view contained in object should be skipped or not.
5149 * @return true if view's sequenceSetId is a key in skipList
5151 private boolean skipViewport(JalviewModel object)
5153 if (skipList == null)
5157 String id = object.getViewport().get(0).getSequenceSetId();
5158 if (skipList.containsKey(id))
5160 if (Cache.log != null && Cache.log.isDebugEnabled())
5162 Cache.log.debug("Skipping seuqence set id " + id);
5169 public void addToSkipList(AlignFrame af)
5171 if (skipList == null)
5173 skipList = new Hashtable();
5175 skipList.put(af.getViewport().getSequenceSetId(), af);
5178 public void clearSkipList()
5180 if (skipList != null)
5187 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5188 boolean ignoreUnrefed)
5190 jalview.datamodel.AlignmentI ds = getDatasetFor(
5191 vamsasSet.getDatasetId());
5192 Vector dseqs = null;
5195 // create a list of new dataset sequences
5196 dseqs = new Vector();
5198 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5200 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5201 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5203 // create a new dataset
5206 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5207 dseqs.copyInto(dsseqs);
5208 ds = new jalview.datamodel.Alignment(dsseqs);
5209 debug("Created new dataset " + vamsasSet.getDatasetId()
5210 + " for alignment " + System.identityHashCode(al));
5211 addDatasetRef(vamsasSet.getDatasetId(), ds);
5213 // set the dataset for the newly imported alignment.
5214 if (al.getDataset() == null && !ignoreUnrefed)
5223 * sequence definition to create/merge dataset sequence for
5227 * vector to add new dataset sequence to
5228 * @param ignoreUnrefed
5229 * - when true, don't create new sequences from vamsasSeq if it's id
5230 * doesn't already have an asssociated Jalview sequence.
5232 * - used to reorder the sequence in the alignment according to the
5233 * vamsasSeq array ordering, to preserve ordering of dataset
5235 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5236 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5238 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5240 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5241 boolean reorder = false;
5242 SequenceI dsq = null;
5243 if (sq != null && sq.getDatasetSequence() != null)
5245 dsq = sq.getDatasetSequence();
5251 if (sq == null && ignoreUnrefed)
5255 String sqid = vamsasSeq.getDsseqid();
5258 // need to create or add a new dataset sequence reference to this sequence
5261 dsq = seqRefIds.get(sqid);
5266 // make a new dataset sequence
5267 dsq = sq.createDatasetSequence();
5270 // make up a new dataset reference for this sequence
5271 sqid = seqHash(dsq);
5273 dsq.setVamsasId(uniqueSetSuffix + sqid);
5274 seqRefIds.put(sqid, dsq);
5279 dseqs.addElement(dsq);
5284 ds.addSequence(dsq);
5290 { // make this dataset sequence sq's dataset sequence
5291 sq.setDatasetSequence(dsq);
5292 // and update the current dataset alignment
5297 if (!dseqs.contains(dsq))
5304 if (ds.findIndex(dsq) < 0)
5306 ds.addSequence(dsq);
5313 // TODO: refactor this as a merge dataset sequence function
5314 // now check that sq (the dataset sequence) sequence really is the union of
5315 // all references to it
5316 // boolean pre = sq.getStart() < dsq.getStart();
5317 // boolean post = sq.getEnd() > dsq.getEnd();
5321 // StringBuffer sb = new StringBuffer();
5322 String newres = jalview.analysis.AlignSeq.extractGaps(
5323 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5324 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5325 && newres.length() > dsq.getLength())
5327 // Update with the longer sequence.
5331 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5332 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5333 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5334 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5336 dsq.setSequence(newres);
5338 // TODO: merges will never happen if we 'know' we have the real dataset
5339 // sequence - this should be detected when id==dssid
5341 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5342 // + (pre ? "prepended" : "") + " "
5343 // + (post ? "appended" : ""));
5348 // sequence refs are identical. We may need to update the existing dataset
5349 // alignment with this one, though.
5350 if (ds != null && dseqs == null)
5352 int opos = ds.findIndex(dsq);
5353 SequenceI tseq = null;
5354 if (opos != -1 && vseqpos != opos)
5356 // remove from old position
5357 ds.deleteSequence(dsq);
5359 if (vseqpos < ds.getHeight())
5361 if (vseqpos != opos)
5363 // save sequence at destination position
5364 tseq = ds.getSequenceAt(vseqpos);
5365 ds.replaceSequenceAt(vseqpos, dsq);
5366 ds.addSequence(tseq);
5371 ds.addSequence(dsq);
5378 * TODO use AlignmentI here and in related methods - needs
5379 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5381 Hashtable<String, AlignmentI> datasetIds = null;
5383 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5385 private AlignmentI getDatasetFor(String datasetId)
5387 if (datasetIds == null)
5389 datasetIds = new Hashtable<>();
5392 if (datasetIds.containsKey(datasetId))
5394 return datasetIds.get(datasetId);
5399 private void addDatasetRef(String datasetId, AlignmentI dataset)
5401 if (datasetIds == null)
5403 datasetIds = new Hashtable<>();
5405 datasetIds.put(datasetId, dataset);
5409 * make a new dataset ID for this jalview dataset alignment
5414 private String getDatasetIdRef(AlignmentI dataset)
5416 if (dataset.getDataset() != null)
5418 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5420 String datasetId = makeHashCode(dataset, null);
5421 if (datasetId == null)
5423 // make a new datasetId and record it
5424 if (dataset2Ids == null)
5426 dataset2Ids = new IdentityHashMap<>();
5430 datasetId = dataset2Ids.get(dataset);
5432 if (datasetId == null)
5434 datasetId = "ds" + dataset2Ids.size() + 1;
5435 dataset2Ids.put(dataset, datasetId);
5441 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5443 for (int d = 0; d < sequence.getDBRef().size(); d++)
5445 DBRef dr = sequence.getDBRef().get(d);
5446 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5447 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5448 if (dr.getMapping() != null)
5450 entry.setMap(addMapping(dr.getMapping()));
5452 datasetSequence.addDBRef(entry);
5456 private jalview.datamodel.Mapping addMapping(Mapping m)
5458 SequenceI dsto = null;
5459 // Mapping m = dr.getMapping();
5460 int fr[] = new int[m.getMapListFrom().size() * 2];
5461 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5462 for (int _i = 0; from.hasNext(); _i += 2)
5464 MapListFrom mf = from.next();
5465 fr[_i] = mf.getStart();
5466 fr[_i + 1] = mf.getEnd();
5468 int fto[] = new int[m.getMapListTo().size() * 2];
5469 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5470 for (int _i = 0; to.hasNext(); _i += 2)
5472 MapListTo mf = to.next();
5473 fto[_i] = mf.getStart();
5474 fto[_i + 1] = mf.getEnd();
5476 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5477 fto, m.getMapFromUnit().intValue(),
5478 m.getMapToUnit().intValue());
5479 // if (m.getMappingChoice() != null)
5481 // MappingChoice mc = m.getMappingChoice();
5482 if (m.getDseqFor() != null)
5484 String dsfor = m.getDseqFor();
5485 if (seqRefIds.containsKey(dsfor))
5490 jmap.setTo(seqRefIds.get(dsfor));
5494 frefedSequence.add(newMappingRef(dsfor, jmap));
5500 * local sequence definition
5502 Sequence ms = m.getSequence();
5503 SequenceI djs = null;
5504 String sqid = ms.getDsseqid();
5505 if (sqid != null && sqid.length() > 0)
5508 * recover dataset sequence
5510 djs = seqRefIds.get(sqid);
5515 "Warning - making up dataset sequence id for DbRef sequence map reference");
5516 sqid = ((Object) ms).toString(); // make up a new hascode for
5517 // undefined dataset sequence hash
5518 // (unlikely to happen)
5524 * make a new dataset sequence and add it to refIds hash
5526 djs = new jalview.datamodel.Sequence(ms.getName(),
5528 djs.setStart(jmap.getMap().getToLowest());
5529 djs.setEnd(jmap.getMap().getToHighest());
5530 djs.setVamsasId(uniqueSetSuffix + sqid);
5532 incompleteSeqs.put(sqid, djs);
5533 seqRefIds.put(sqid, djs);
5536 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5545 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5546 * view as XML (but not to file), and then reloading it
5551 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5554 JalviewModel jm = saveState(ap, null, null, null);
5556 uniqueSetSuffix = "";
5557 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5558 jm.getViewport().get(0).setId(null);
5559 // we don't overwrite the view we just copied
5561 if (this.frefedSequence == null)
5563 frefedSequence = new Vector<>();
5566 viewportsAdded.clear();
5568 AlignFrame af = loadFromObject(jm, null, false, null);
5569 af.getAlignPanels().clear();
5570 af.closeMenuItem_actionPerformed(true);
5573 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5574 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5575 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5576 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5577 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5580 return af.alignPanel;
5583 private Hashtable jvids2vobj;
5585 private void warn(String msg)
5590 private void warn(String msg, Exception e)
5592 if (Cache.log != null)
5596 Cache.log.warn(msg, e);
5600 Cache.log.warn(msg);
5605 System.err.println("Warning: " + msg);
5608 e.printStackTrace();
5613 private void debug(String string)
5615 debug(string, null);
5618 private void debug(String msg, Exception e)
5620 if (Cache.log != null)
5624 Cache.log.debug(msg, e);
5628 Cache.log.debug(msg);
5633 System.err.println("Warning: " + msg);
5636 e.printStackTrace();
5642 * set the object to ID mapping tables used to write/recover objects and XML
5643 * ID strings for the jalview project. If external tables are provided then
5644 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5645 * object goes out of scope. - also populates the datasetIds hashtable with
5646 * alignment objects containing dataset sequences
5649 * Map from ID strings to jalview datamodel
5651 * Map from jalview datamodel to ID strings
5655 public void setObjectMappingTables(Hashtable vobj2jv,
5656 IdentityHashMap jv2vobj)
5658 this.jv2vobj = jv2vobj;
5659 this.vobj2jv = vobj2jv;
5660 Iterator ds = jv2vobj.keySet().iterator();
5662 while (ds.hasNext())
5664 Object jvobj = ds.next();
5665 id = jv2vobj.get(jvobj).toString();
5666 if (jvobj instanceof jalview.datamodel.Alignment)
5668 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5670 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5673 else if (jvobj instanceof jalview.datamodel.Sequence)
5675 // register sequence object so the XML parser can recover it.
5676 if (seqRefIds == null)
5678 seqRefIds = new HashMap<>();
5680 if (seqsToIds == null)
5682 seqsToIds = new IdentityHashMap<>();
5684 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5685 seqsToIds.put((SequenceI) jvobj, id);
5687 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5690 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5691 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5692 if (jvann.annotationId == null)
5694 jvann.annotationId = anid;
5696 if (!jvann.annotationId.equals(anid))
5698 // TODO verify that this is the correct behaviour
5699 this.warn("Overriding Annotation ID for " + anid
5700 + " from different id : " + jvann.annotationId);
5701 jvann.annotationId = anid;
5704 else if (jvobj instanceof String)
5706 if (jvids2vobj == null)
5708 jvids2vobj = new Hashtable();
5709 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5714 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5720 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5721 * objects created from the project archive. If string is null (default for
5722 * construction) then suffix will be set automatically.
5726 public void setUniqueSetSuffix(String string)
5728 uniqueSetSuffix = string;
5733 * uses skipList2 as the skipList for skipping views on sequence sets
5734 * associated with keys in the skipList
5738 public void setSkipList(Hashtable skipList2)
5740 skipList = skipList2;
5744 * Reads the jar entry of given name and returns its contents, or null if the
5745 * entry is not found.
5748 * @param jarEntryName
5751 protected String readJarEntry(jarInputStreamProvider jprovider,
5752 String jarEntryName)
5754 String result = null;
5755 BufferedReader in = null;
5760 * Reopen the jar input stream and traverse its entries to find a matching
5763 JarInputStream jin = jprovider.getJarInputStream();
5764 JarEntry entry = null;
5767 entry = jin.getNextJarEntry();
5768 } while (entry != null && !entry.getName().equals(jarEntryName));
5772 StringBuilder out = new StringBuilder(256);
5773 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5776 while ((data = in.readLine()) != null)
5780 result = out.toString();
5784 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5786 } catch (Exception ex)
5788 ex.printStackTrace();
5796 } catch (IOException e)
5807 * Returns an incrementing counter (0, 1, 2...)
5811 private synchronized int nextCounter()
5817 * Populates an XML model of the feature colour scheme for one feature type
5819 * @param featureType
5823 public static Colour marshalColour(
5824 String featureType, FeatureColourI fcol)
5826 Colour col = new Colour();
5827 if (fcol.isSimpleColour())
5829 col.setRGB(Format.getHexString(fcol.getColour()));
5833 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5834 col.setMin(fcol.getMin());
5835 col.setMax(fcol.getMax());
5836 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5837 col.setAutoScale(fcol.isAutoScaled());
5838 col.setThreshold(fcol.getThreshold());
5839 col.setColourByLabel(fcol.isColourByLabel());
5840 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
5841 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
5842 : ThresholdType.NONE));
5843 if (fcol.isColourByAttribute())
5845 final String[] attName = fcol.getAttributeName();
5846 col.getAttributeName().add(attName[0]);
5847 if (attName.length > 1)
5849 col.getAttributeName().add(attName[1]);
5852 Color noColour = fcol.getNoColour();
5853 if (noColour == null)
5855 col.setNoValueColour(NoValueColour.NONE);
5857 else if (noColour == fcol.getMaxColour())
5859 col.setNoValueColour(NoValueColour.MAX);
5863 col.setNoValueColour(NoValueColour.MIN);
5866 col.setName(featureType);
5871 * Populates an XML model of the feature filter(s) for one feature type
5873 * @param firstMatcher
5874 * the first (or only) match condition)
5876 * remaining match conditions (if any)
5878 * if true, conditions are and-ed, else or-ed
5880 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
5881 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
5884 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
5886 if (filters.hasNext())
5891 CompoundMatcher compound = new CompoundMatcher();
5892 compound.setAnd(and);
5893 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
5894 firstMatcher, Collections.emptyIterator(), and);
5895 // compound.addMatcherSet(matcher1);
5896 compound.getMatcherSet().add(matcher1);
5897 FeatureMatcherI nextMatcher = filters.next();
5898 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
5899 nextMatcher, filters, and);
5900 // compound.addMatcherSet(matcher2);
5901 compound.getMatcherSet().add(matcher2);
5902 result.setCompoundMatcher(compound);
5907 * single condition matcher
5909 // MatchCondition matcherModel = new MatchCondition();
5910 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
5911 matcherModel.setCondition(
5912 firstMatcher.getMatcher().getCondition().getStableName());
5913 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5914 if (firstMatcher.isByAttribute())
5916 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
5917 // matcherModel.setAttributeName(firstMatcher.getAttribute());
5918 String[] attName = firstMatcher.getAttribute();
5919 matcherModel.getAttributeName().add(attName[0]); // attribute
5920 if (attName.length > 1)
5922 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
5925 else if (firstMatcher.isByLabel())
5927 matcherModel.setBy(FilterBy.BY_LABEL);
5929 else if (firstMatcher.isByScore())
5931 matcherModel.setBy(FilterBy.BY_SCORE);
5933 result.setMatchCondition(matcherModel);
5940 * Loads one XML model of a feature filter to a Jalview object
5942 * @param featureType
5943 * @param matcherSetModel
5946 public static FeatureMatcherSetI parseFilter(
5948 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
5950 FeatureMatcherSetI result = new FeatureMatcherSet();
5953 parseFilterConditions(result, matcherSetModel, true);
5954 } catch (IllegalStateException e)
5956 // mixing AND and OR conditions perhaps
5958 String.format("Error reading filter conditions for '%s': %s",
5959 featureType, e.getMessage()));
5960 // return as much as was parsed up to the error
5967 * Adds feature match conditions to matcherSet as unmarshalled from XML
5968 * (possibly recursively for compound conditions)
5971 * @param matcherSetModel
5973 * if true, multiple conditions are AND-ed, else they are OR-ed
5974 * @throws IllegalStateException
5975 * if AND and OR conditions are mixed
5977 protected static void parseFilterConditions(
5978 FeatureMatcherSetI matcherSet,
5979 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
5982 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
5983 .getMatchCondition();
5989 FilterBy filterBy = mc.getBy();
5990 Condition cond = Condition.fromString(mc.getCondition());
5991 String pattern = mc.getValue();
5992 FeatureMatcherI matchCondition = null;
5993 if (filterBy == FilterBy.BY_LABEL)
5995 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5997 else if (filterBy == FilterBy.BY_SCORE)
5999 matchCondition = FeatureMatcher.byScore(cond, pattern);
6002 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6004 final List<String> attributeName = mc.getAttributeName();
6005 String[] attNames = attributeName
6006 .toArray(new String[attributeName.size()]);
6007 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6012 * note this throws IllegalStateException if AND-ing to a
6013 * previously OR-ed compound condition, or vice versa
6017 matcherSet.and(matchCondition);
6021 matcherSet.or(matchCondition);
6027 * compound condition
6029 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6030 .getCompoundMatcher().getMatcherSet();
6031 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6032 if (matchers.size() == 2)
6034 parseFilterConditions(matcherSet, matchers.get(0), anded);
6035 parseFilterConditions(matcherSet, matchers.get(1), anded);
6039 System.err.println("Malformed compound filter condition");
6045 * Loads one XML model of a feature colour to a Jalview object
6047 * @param colourModel
6050 public static FeatureColourI parseColour(Colour colourModel)
6052 FeatureColourI colour = null;
6054 if (colourModel.getMax() != null)
6056 Color mincol = null;
6057 Color maxcol = null;
6058 Color noValueColour = null;
6062 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6063 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6064 } catch (Exception e)
6066 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6069 NoValueColour noCol = colourModel.getNoValueColour();
6070 if (noCol == NoValueColour.MIN)
6072 noValueColour = mincol;
6074 else if (noCol == NoValueColour.MAX)
6076 noValueColour = maxcol;
6079 colour = new FeatureColour(mincol, maxcol, noValueColour,
6080 safeFloat(colourModel.getMin()),
6081 safeFloat(colourModel.getMax()));
6082 final List<String> attributeName = colourModel.getAttributeName();
6083 String[] attributes = attributeName
6084 .toArray(new String[attributeName.size()]);
6085 if (attributes != null && attributes.length > 0)
6087 colour.setAttributeName(attributes);
6089 if (colourModel.isAutoScale() != null)
6091 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6093 if (colourModel.isColourByLabel() != null)
6095 colour.setColourByLabel(
6096 colourModel.isColourByLabel().booleanValue());
6098 if (colourModel.getThreshold() != null)
6100 colour.setThreshold(colourModel.getThreshold().floatValue());
6102 ThresholdType ttyp = colourModel.getThreshType();
6103 if (ttyp == ThresholdType.ABOVE)
6105 colour.setAboveThreshold(true);
6107 else if (ttyp == ThresholdType.BELOW)
6109 colour.setBelowThreshold(true);
6114 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6115 colour = new FeatureColour(color);