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.Jalview2XML_V1;
53 import jalview.gui.JvOptionPane;
54 import jalview.gui.OOMWarning;
55 import jalview.gui.PaintRefresher;
56 import jalview.gui.SplitFrame;
57 import jalview.gui.StructureViewer;
58 import jalview.gui.StructureViewer.ViewerType;
59 import jalview.gui.StructureViewerBase;
60 import jalview.gui.TreePanel;
61 import jalview.io.DataSourceType;
62 import jalview.io.FileFormat;
63 import jalview.io.NewickFile;
64 import jalview.renderer.ResidueShaderI;
65 import jalview.schemes.AnnotationColourGradient;
66 import jalview.schemes.ColourSchemeI;
67 import jalview.schemes.ColourSchemeProperty;
68 import jalview.schemes.FeatureColour;
69 import jalview.schemes.ResidueProperties;
70 import jalview.schemes.UserColourScheme;
71 import jalview.structure.StructureSelectionManager;
72 import jalview.structures.models.AAStructureBindingModel;
73 import jalview.util.Format;
74 import jalview.util.MessageManager;
75 import jalview.util.Platform;
76 import jalview.util.StringUtils;
77 import jalview.util.jarInputStreamProvider;
78 import jalview.util.matcher.Condition;
79 import jalview.viewmodel.AlignmentViewport;
80 import jalview.viewmodel.ViewportRanges;
81 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
82 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
83 import jalview.ws.jws2.Jws2Discoverer;
84 import jalview.ws.jws2.dm.AAConSettings;
85 import jalview.ws.jws2.jabaws2.Jws2Instance;
86 import jalview.ws.params.ArgumentI;
87 import jalview.ws.params.AutoCalcSetting;
88 import jalview.ws.params.WsParamSetI;
89 import jalview.xml.binding.jalview.AlcodonFrame;
90 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
91 import jalview.xml.binding.jalview.Annotation;
92 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
93 import jalview.xml.binding.jalview.AnnotationColourScheme;
94 import jalview.xml.binding.jalview.AnnotationElement;
95 import jalview.xml.binding.jalview.Feature;
96 import jalview.xml.binding.jalview.Feature.OtherData;
97 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
98 import jalview.xml.binding.jalview.FilterBy;
99 import jalview.xml.binding.jalview.JalviewModel;
100 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
101 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
102 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
103 import jalview.xml.binding.jalview.JalviewModel.JGroup;
104 import jalview.xml.binding.jalview.JalviewModel.JSeq;
105 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
106 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
107 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
108 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
109 import jalview.xml.binding.jalview.JalviewModel.Tree;
110 import jalview.xml.binding.jalview.JalviewModel.UserColours;
111 import jalview.xml.binding.jalview.JalviewModel.Viewport;
112 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
113 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
114 import jalview.xml.binding.jalview.JalviewUserColours;
115 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
116 import jalview.xml.binding.jalview.MapListType.MapListFrom;
117 import jalview.xml.binding.jalview.MapListType.MapListTo;
118 import jalview.xml.binding.jalview.Mapping;
119 import jalview.xml.binding.jalview.NoValueColour;
120 import jalview.xml.binding.jalview.ObjectFactory;
121 import jalview.xml.binding.jalview.Pdbentry.Property;
122 import jalview.xml.binding.jalview.Sequence;
123 import jalview.xml.binding.jalview.Sequence.DBRef;
124 import jalview.xml.binding.jalview.SequenceSet;
125 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
126 import jalview.xml.binding.jalview.ThresholdType;
127 import jalview.xml.binding.jalview.VAMSAS;
129 import java.awt.Color;
130 import java.awt.Font;
131 import java.awt.Rectangle;
132 import java.io.BufferedReader;
133 import java.io.ByteArrayInputStream;
134 import java.io.DataInputStream;
135 import java.io.DataOutputStream;
137 import java.io.FileInputStream;
138 import java.io.FileOutputStream;
139 import java.io.IOException;
140 import java.io.InputStreamReader;
141 import java.io.OutputStreamWriter;
142 import java.io.PrintWriter;
143 import java.lang.reflect.InvocationTargetException;
144 import java.math.BigInteger;
145 import java.net.MalformedURLException;
147 import java.util.ArrayList;
148 import java.util.Arrays;
149 import java.util.Collections;
150 import java.util.Enumeration;
151 import java.util.GregorianCalendar;
152 import java.util.HashMap;
153 import java.util.HashSet;
154 import java.util.Hashtable;
155 import java.util.IdentityHashMap;
156 import java.util.Iterator;
157 import java.util.LinkedHashMap;
158 import java.util.List;
159 import java.util.Map;
160 import java.util.Map.Entry;
161 import java.util.Set;
162 import java.util.Vector;
163 import java.util.jar.JarEntry;
164 import java.util.jar.JarInputStream;
165 import java.util.jar.JarOutputStream;
167 import javax.swing.JInternalFrame;
168 import javax.swing.SwingUtilities;
169 import javax.xml.bind.JAXBContext;
170 import javax.xml.bind.JAXBElement;
171 import javax.xml.bind.Marshaller;
172 import javax.xml.datatype.DatatypeConfigurationException;
173 import javax.xml.datatype.DatatypeFactory;
174 import javax.xml.datatype.XMLGregorianCalendar;
175 import javax.xml.stream.XMLInputFactory;
176 import javax.xml.stream.XMLStreamReader;
179 * Write out the current jalview desktop state as a Jalview XML stream.
181 * Note: the vamsas objects referred to here are primitive versions of the
182 * VAMSAS project schema elements - they are not the same and most likely never
186 * @version $Revision: 1.134 $
188 public class Jalview2XML
191 // BH 2018 we add the .jvp binary extension to J2S so that
192 // it will declare that binary when we do the file save from the browser
196 Platform.addJ2SBinaryType(".jvp?");
199 private static final String VIEWER_PREFIX = "viewer_";
201 private static final String RNA_PREFIX = "rna_";
203 private static final String UTF_8 = "UTF-8";
205 // use this with nextCounter() to make unique names for entities
206 private int counter = 0;
209 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
210 * of sequence objects are created.
212 IdentityHashMap<SequenceI, String> seqsToIds = null;
215 * jalview XML Sequence ID to jalview sequence object reference (both dataset
216 * and alignment sequences. Populated as XML reps of sequence objects are
219 Map<String, SequenceI> seqRefIds = null;
221 Map<String, SequenceI> incompleteSeqs = null;
223 List<SeqFref> frefedSequence = null;
225 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
228 * Map of reconstructed AlignFrame objects that appear to have come from
229 * SplitFrame objects (have a dna/protein complement view).
231 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
234 * Map from displayed rna structure models to their saved session state jar
237 private Map<RnaModel, String> rnaSessions = new HashMap<>();
240 * A helper method for safely using the value of an optional attribute that
241 * may be null if not present in the XML. Answers the boolean value, or false
247 public static boolean safeBoolean(Boolean b)
249 return b == null ? false : b.booleanValue();
253 * A helper method for safely using the value of an optional attribute that
254 * may be null if not present in the XML. Answers the integer value, or zero
260 public static int safeInt(Integer i)
262 return i == null ? 0 : i.intValue();
266 * A helper method for safely using the value of an optional attribute that
267 * may be null if not present in the XML. Answers the float value, or zero if
273 public static float safeFloat(Float f)
275 return f == null ? 0f : f.floatValue();
279 * create/return unique hash string for sq
282 * @return new or existing unique string for sq
284 String seqHash(SequenceI sq)
286 if (seqsToIds == null)
290 if (seqsToIds.containsKey(sq))
292 return seqsToIds.get(sq);
296 // create sequential key
297 String key = "sq" + (seqsToIds.size() + 1);
298 key = makeHashCode(sq, key); // check we don't have an external reference
300 seqsToIds.put(sq, key);
307 if (seqsToIds == null)
309 seqsToIds = new IdentityHashMap<>();
311 if (seqRefIds == null)
313 seqRefIds = new HashMap<>();
315 if (incompleteSeqs == null)
317 incompleteSeqs = new HashMap<>();
319 if (frefedSequence == null)
321 frefedSequence = new ArrayList<>();
329 public Jalview2XML(boolean raiseGUI)
331 this.raiseGUI = raiseGUI;
335 * base class for resolving forward references to sequences by their ID
340 abstract class SeqFref
346 public SeqFref(String _sref, String type)
352 public String getSref()
357 public SequenceI getSrefSeq()
359 return seqRefIds.get(sref);
362 public boolean isResolvable()
364 return seqRefIds.get(sref) != null;
367 public SequenceI getSrefDatasetSeq()
369 SequenceI sq = seqRefIds.get(sref);
372 while (sq.getDatasetSequence() != null)
374 sq = sq.getDatasetSequence();
381 * @return true if the forward reference was fully resolved
383 abstract boolean resolve();
386 public String toString()
388 return type + " reference to " + sref;
393 * create forward reference for a mapping
399 public SeqFref newMappingRef(final String sref,
400 final jalview.datamodel.Mapping _jmap)
402 SeqFref fref = new SeqFref(sref, "Mapping")
404 public jalview.datamodel.Mapping jmap = _jmap;
409 SequenceI seq = getSrefDatasetSeq();
421 public SeqFref newAlcodMapRef(final String sref,
422 final AlignedCodonFrame _cf,
423 final jalview.datamodel.Mapping _jmap)
426 SeqFref fref = new SeqFref(sref, "Codon Frame")
428 AlignedCodonFrame cf = _cf;
430 public jalview.datamodel.Mapping mp = _jmap;
433 public boolean isResolvable()
435 return super.isResolvable() && mp.getTo() != null;
441 SequenceI seq = getSrefDatasetSeq();
446 cf.addMap(seq, mp.getTo(), mp.getMap());
453 public void resolveFrefedSequences()
455 Iterator<SeqFref> nextFref = frefedSequence.iterator();
456 int toresolve = frefedSequence.size();
457 int unresolved = 0, failedtoresolve = 0;
458 while (nextFref.hasNext())
460 SeqFref ref = nextFref.next();
461 if (ref.isResolvable())
473 } catch (Exception x)
476 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
489 System.err.println("Jalview Project Import: There were " + unresolved
490 + " forward references left unresolved on the stack.");
492 if (failedtoresolve > 0)
494 System.err.println("SERIOUS! " + failedtoresolve
495 + " resolvable forward references failed to resolve.");
497 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
500 "Jalview Project Import: There are " + incompleteSeqs.size()
501 + " sequences which may have incomplete metadata.");
502 if (incompleteSeqs.size() < 10)
504 for (SequenceI s : incompleteSeqs.values())
506 System.err.println(s.toString());
512 "Too many to report. Skipping output of incomplete sequences.");
518 * This maintains a map of viewports, the key being the seqSetId. Important to
519 * set historyItem and redoList for multiple views
521 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
523 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
525 String uniqueSetSuffix = "";
528 * List of pdbfiles added to Jar
530 List<String> pdbfiles = null;
532 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
533 public void saveState(File statefile)
535 FileOutputStream fos = null;
538 fos = new FileOutputStream(statefile);
539 JarOutputStream jout = new JarOutputStream(fos);
542 } catch (Exception e)
544 // TODO: inform user of the problem - they need to know if their data was
546 if (errorMessage == null)
548 errorMessage = "Couldn't write Jalview Archive to output file '"
549 + statefile + "' - See console error log for details";
553 errorMessage += "(output file was '" + statefile + "')";
563 } catch (IOException e)
573 * Writes a jalview project archive to the given Jar output stream.
577 public void saveState(JarOutputStream jout)
579 AlignFrame[] frames = Desktop.getAlignFrames();
585 saveAllFrames(Arrays.asList(frames), jout);
589 * core method for storing state for a set of AlignFrames.
592 * - frames involving all data to be exported (including containing
595 * - project output stream
597 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
599 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
602 * ensure cached data is clear before starting
604 // todo tidy up seqRefIds, seqsToIds initialisation / reset
606 splitFrameCandidates.clear();
611 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
612 // //////////////////////////////////////////////////
614 List<String> shortNames = new ArrayList<>();
615 List<String> viewIds = new ArrayList<>();
618 for (int i = frames.size() - 1; i > -1; i--)
620 AlignFrame af = frames.get(i);
622 if (skipList != null && skipList
623 .containsKey(af.getViewport().getSequenceSetId()))
628 String shortName = makeFilename(af, shortNames);
630 int apSize = af.getAlignPanels().size();
632 for (int ap = 0; ap < apSize; ap++)
634 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
636 String fileName = apSize == 1 ? shortName : ap + shortName;
637 if (!fileName.endsWith(".xml"))
639 fileName = fileName + ".xml";
642 saveState(apanel, fileName, jout, viewIds);
644 String dssid = getDatasetIdRef(
645 af.getViewport().getAlignment().getDataset());
646 if (!dsses.containsKey(dssid))
648 dsses.put(dssid, af);
653 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
659 } catch (Exception foo)
664 } catch (Exception ex)
666 // TODO: inform user of the problem - they need to know if their data was
668 if (errorMessage == null)
670 errorMessage = "Couldn't write Jalview Archive - see error output for details";
672 ex.printStackTrace();
677 * Generates a distinct file name, based on the title of the AlignFrame, by
678 * appending _n for increasing n until an unused name is generated. The new
679 * name (without its extension) is added to the list.
683 * @return the generated name, with .xml extension
685 protected String makeFilename(AlignFrame af, List<String> namesUsed)
687 String shortName = af.getTitle();
689 if (shortName.indexOf(File.separatorChar) > -1)
691 shortName = shortName
692 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
697 while (namesUsed.contains(shortName))
699 if (shortName.endsWith("_" + (count - 1)))
701 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
704 shortName = shortName.concat("_" + count);
708 namesUsed.add(shortName);
710 if (!shortName.endsWith(".xml"))
712 shortName = shortName + ".xml";
717 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
718 public boolean saveAlignment(AlignFrame af, String jarFile,
723 FileOutputStream fos = new FileOutputStream(jarFile);
724 JarOutputStream jout = new JarOutputStream(fos);
725 List<AlignFrame> frames = new ArrayList<>();
727 // resolve splitframes
728 if (af.getViewport().getCodingComplement() != null)
730 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
736 saveAllFrames(frames, jout);
740 } catch (Exception foo)
746 } catch (Exception ex)
748 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
749 ex.printStackTrace();
754 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
755 String fileName, JarOutputStream jout)
758 for (String dssids : dsses.keySet())
760 AlignFrame _af = dsses.get(dssids);
761 String jfileName = fileName + " Dataset for " + _af.getTitle();
762 if (!jfileName.endsWith(".xml"))
764 jfileName = jfileName + ".xml";
766 saveState(_af.alignPanel, jfileName, true, jout, null);
771 * create a JalviewModel from an alignment view and marshall it to a
775 * panel to create jalview model for
777 * name of alignment panel written to output stream
784 public JalviewModel saveState(AlignmentPanel ap, String fileName,
785 JarOutputStream jout, List<String> viewIds)
787 return saveState(ap, fileName, false, jout, viewIds);
791 * create a JalviewModel from an alignment view and marshall it to a
795 * panel to create jalview model for
797 * name of alignment panel written to output stream
799 * when true, only write the dataset for the alignment, not the data
800 * associated with the view.
806 public JalviewModel saveState(AlignmentPanel ap, String fileName,
807 boolean storeDS, JarOutputStream jout, List<String> viewIds)
811 viewIds = new ArrayList<>();
816 List<UserColourScheme> userColours = new ArrayList<>();
818 AlignViewport av = ap.av;
819 ViewportRanges vpRanges = av.getRanges();
821 final ObjectFactory objectFactory = new ObjectFactory();
822 JalviewModel object = objectFactory.createJalviewModel();
823 object.setVamsasModel(new VAMSAS());
825 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
828 GregorianCalendar c = new GregorianCalendar();
829 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
830 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
831 object.setCreationDate(now);
832 } catch (DatatypeConfigurationException e)
834 System.err.println("error writing date: " + e.toString());
837 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
840 * rjal is full height alignment, jal is actual alignment with full metadata
841 * but excludes hidden sequences.
843 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
845 if (av.hasHiddenRows())
847 rjal = jal.getHiddenSequences().getFullAlignment();
850 SequenceSet vamsasSet = new SequenceSet();
852 // JalviewModelSequence jms = new JalviewModelSequence();
854 vamsasSet.setGapChar(jal.getGapCharacter() + "");
856 if (jal.getDataset() != null)
858 // dataset id is the dataset's hashcode
859 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
862 // switch jal and the dataset
863 jal = jal.getDataset();
867 if (jal.getProperties() != null)
869 Enumeration en = jal.getProperties().keys();
870 while (en.hasMoreElements())
872 String key = en.nextElement().toString();
873 SequenceSetProperties ssp = new SequenceSetProperties();
875 ssp.setValue(jal.getProperties().get(key).toString());
876 // vamsasSet.addSequenceSetProperties(ssp);
877 vamsasSet.getSequenceSetProperties().add(ssp);
882 Set<String> calcIdSet = new HashSet<>();
883 // record the set of vamsas sequence XML POJO we create.
884 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
886 for (final SequenceI jds : rjal.getSequences())
888 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
889 : jds.getDatasetSequence();
890 String id = seqHash(jds);
891 if (vamsasSetIds.get(id) == null)
893 if (seqRefIds.get(id) != null && !storeDS)
895 // This happens for two reasons: 1. multiple views are being
897 // 2. the hashCode has collided with another sequence's code. This
899 // HAPPEN! (PF00072.15.stk does this)
900 // JBPNote: Uncomment to debug writing out of files that do not read
901 // back in due to ArrayOutOfBoundExceptions.
902 // System.err.println("vamsasSeq backref: "+id+"");
903 // System.err.println(jds.getName()+"
904 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
905 // System.err.println("Hashcode: "+seqHash(jds));
906 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
907 // System.err.println(rsq.getName()+"
908 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
909 // System.err.println("Hashcode: "+seqHash(rsq));
913 vamsasSeq = createVamsasSequence(id, jds);
914 // vamsasSet.addSequence(vamsasSeq);
915 vamsasSet.getSequence().add(vamsasSeq);
916 vamsasSetIds.put(id, vamsasSeq);
917 seqRefIds.put(id, jds);
921 jseq.setStart(jds.getStart());
922 jseq.setEnd(jds.getEnd());
923 jseq.setColour(av.getSequenceColour(jds).getRGB());
925 jseq.setId(id); // jseq id should be a string not a number
928 // Store any sequences this sequence represents
929 if (av.hasHiddenRows())
931 // use rjal, contains the full height alignment
933 av.getAlignment().getHiddenSequences().isHidden(jds));
935 if (av.isHiddenRepSequence(jds))
937 jalview.datamodel.SequenceI[] reps = av
938 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
940 for (int h = 0; h < reps.length; h++)
944 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
945 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
950 // mark sequence as reference - if it is the reference for this view
953 jseq.setViewreference(jds == jal.getSeqrep());
957 // TODO: omit sequence features from each alignment view's XML dump if we
958 // are storing dataset
959 List<SequenceFeature> sfs = jds.getSequenceFeatures();
960 for (SequenceFeature sf : sfs)
962 // Features features = new Features();
963 Feature features = new Feature();
965 features.setBegin(sf.getBegin());
966 features.setEnd(sf.getEnd());
967 features.setDescription(sf.getDescription());
968 features.setType(sf.getType());
969 features.setFeatureGroup(sf.getFeatureGroup());
970 features.setScore(sf.getScore());
971 if (sf.links != null)
973 for (int l = 0; l < sf.links.size(); l++)
975 OtherData keyValue = new OtherData();
976 keyValue.setKey("LINK_" + l);
977 keyValue.setValue(sf.links.elementAt(l).toString());
978 // features.addOtherData(keyValue);
979 features.getOtherData().add(keyValue);
982 if (sf.otherDetails != null)
985 * save feature attributes, which may be simple strings or
986 * map valued (have sub-attributes)
988 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
990 String key = entry.getKey();
991 Object value = entry.getValue();
992 if (value instanceof Map<?, ?>)
994 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
997 OtherData otherData = new OtherData();
998 otherData.setKey(key);
999 otherData.setKey2(subAttribute.getKey());
1000 otherData.setValue(subAttribute.getValue().toString());
1001 // features.addOtherData(otherData);
1002 features.getOtherData().add(otherData);
1007 OtherData otherData = new OtherData();
1008 otherData.setKey(key);
1009 otherData.setValue(value.toString());
1010 // features.addOtherData(otherData);
1011 features.getOtherData().add(otherData);
1016 // jseq.addFeatures(features);
1017 jseq.getFeatures().add(features);
1020 if (jdatasq.getAllPDBEntries() != null)
1022 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1023 while (en.hasMoreElements())
1025 Pdbids pdb = new Pdbids();
1026 jalview.datamodel.PDBEntry entry = en.nextElement();
1028 String pdbId = entry.getId();
1030 pdb.setType(entry.getType());
1033 * Store any structure views associated with this sequence. This
1034 * section copes with duplicate entries in the project, so a dataset
1035 * only view *should* be coped with sensibly.
1037 // This must have been loaded, is it still visible?
1038 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1039 String matchedFile = null;
1040 for (int f = frames.length - 1; f > -1; f--)
1042 if (frames[f] instanceof StructureViewerBase)
1044 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1045 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1046 matchedFile, viewFrame);
1048 * Only store each structure viewer's state once in the project
1049 * jar. First time through only (storeDS==false)
1051 String viewId = viewFrame.getViewId();
1052 if (!storeDS && !viewIds.contains(viewId))
1054 viewIds.add(viewId);
1057 String viewerState = viewFrame.getStateInfo();
1058 writeJarEntry(jout, getViewerJarEntryName(viewId),
1059 viewerState.getBytes());
1060 } catch (IOException e)
1063 "Error saving viewer state: " + e.getMessage());
1069 if (matchedFile != null || entry.getFile() != null)
1071 if (entry.getFile() != null)
1074 matchedFile = entry.getFile();
1076 pdb.setFile(matchedFile); // entry.getFile());
1077 if (pdbfiles == null)
1079 pdbfiles = new ArrayList<>();
1082 if (!pdbfiles.contains(pdbId))
1084 pdbfiles.add(pdbId);
1085 copyFileToJar(jout, matchedFile, pdbId);
1089 Enumeration<String> props = entry.getProperties();
1090 if (props.hasMoreElements())
1092 // PdbentryItem item = new PdbentryItem();
1093 while (props.hasMoreElements())
1095 Property prop = new Property();
1096 String key = props.nextElement();
1098 prop.setValue(entry.getProperty(key).toString());
1099 // item.addProperty(prop);
1100 pdb.getProperty().add(prop);
1102 // pdb.addPdbentryItem(item);
1105 // jseq.addPdbids(pdb);
1106 jseq.getPdbids().add(pdb);
1110 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1112 // jms.addJSeq(jseq);
1113 object.getJSeq().add(jseq);
1116 if (!storeDS && av.hasHiddenRows())
1118 jal = av.getAlignment();
1122 if (storeDS && jal.getCodonFrames() != null)
1124 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1125 for (AlignedCodonFrame acf : jac)
1127 AlcodonFrame alc = new AlcodonFrame();
1128 if (acf.getProtMappings() != null
1129 && acf.getProtMappings().length > 0)
1131 boolean hasMap = false;
1132 SequenceI[] dnas = acf.getdnaSeqs();
1133 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1134 for (int m = 0; m < pmaps.length; m++)
1136 AlcodMap alcmap = new AlcodMap();
1137 alcmap.setDnasq(seqHash(dnas[m]));
1139 createVamsasMapping(pmaps[m], dnas[m], null, false));
1140 // alc.addAlcodMap(alcmap);
1141 alc.getAlcodMap().add(alcmap);
1146 // vamsasSet.addAlcodonFrame(alc);
1147 vamsasSet.getAlcodonFrame().add(alc);
1150 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1152 // AlcodonFrame alc = new AlcodonFrame();
1153 // vamsasSet.addAlcodonFrame(alc);
1154 // for (int p = 0; p < acf.aaWidth; p++)
1156 // Alcodon cmap = new Alcodon();
1157 // if (acf.codons[p] != null)
1159 // // Null codons indicate a gapped column in the translated peptide
1161 // cmap.setPos1(acf.codons[p][0]);
1162 // cmap.setPos2(acf.codons[p][1]);
1163 // cmap.setPos3(acf.codons[p][2]);
1165 // alc.addAlcodon(cmap);
1167 // if (acf.getProtMappings() != null
1168 // && acf.getProtMappings().length > 0)
1170 // SequenceI[] dnas = acf.getdnaSeqs();
1171 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1172 // for (int m = 0; m < pmaps.length; m++)
1174 // AlcodMap alcmap = new AlcodMap();
1175 // alcmap.setDnasq(seqHash(dnas[m]));
1176 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1178 // alc.addAlcodMap(alcmap);
1185 // /////////////////////////////////
1186 if (!storeDS && av.getCurrentTree() != null)
1188 // FIND ANY ASSOCIATED TREES
1189 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1190 if (Desktop.desktop != null)
1192 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1194 for (int t = 0; t < frames.length; t++)
1196 if (frames[t] instanceof TreePanel)
1198 TreePanel tp = (TreePanel) frames[t];
1200 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1202 JalviewModel.Tree tree = new JalviewModel.Tree();
1203 tree.setTitle(tp.getTitle());
1204 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1205 tree.setNewick(tp.getTree().print());
1206 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1208 tree.setFitToWindow(tp.fitToWindow.getState());
1209 tree.setFontName(tp.getTreeFont().getName());
1210 tree.setFontSize(tp.getTreeFont().getSize());
1211 tree.setFontStyle(tp.getTreeFont().getStyle());
1212 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1214 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1215 tree.setShowDistances(tp.distanceMenu.getState());
1217 tree.setHeight(tp.getHeight());
1218 tree.setWidth(tp.getWidth());
1219 tree.setXpos(tp.getX());
1220 tree.setYpos(tp.getY());
1221 tree.setId(makeHashCode(tp, null));
1222 // jms.addTree(tree);
1223 object.getTree().add(tree);
1232 * store forward refs from an annotationRow to any groups
1234 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1237 for (SequenceI sq : jal.getSequences())
1239 // Store annotation on dataset sequences only
1240 AlignmentAnnotation[] aa = sq.getAnnotation();
1241 if (aa != null && aa.length > 0)
1243 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1250 if (jal.getAlignmentAnnotation() != null)
1252 // Store the annotation shown on the alignment.
1253 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1254 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1259 if (jal.getGroups() != null)
1261 JGroup[] groups = new JGroup[jal.getGroups().size()];
1263 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1265 JGroup jGroup = new JGroup();
1266 groups[++i] = jGroup;
1268 jGroup.setStart(sg.getStartRes());
1269 jGroup.setEnd(sg.getEndRes());
1270 jGroup.setName(sg.getName());
1271 if (groupRefs.containsKey(sg))
1273 // group has references so set its ID field
1274 jGroup.setId(groupRefs.get(sg));
1276 ColourSchemeI colourScheme = sg.getColourScheme();
1277 if (colourScheme != null)
1279 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1280 if (groupColourScheme.conservationApplied())
1282 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1284 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1287 setUserColourScheme(colourScheme, userColours,
1292 jGroup.setColour(colourScheme.getSchemeName());
1295 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1297 jGroup.setColour("AnnotationColourGradient");
1298 jGroup.setAnnotationColours(constructAnnotationColours(
1299 (jalview.schemes.AnnotationColourGradient) colourScheme,
1300 userColours, object));
1302 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1305 setUserColourScheme(colourScheme, userColours, object));
1309 jGroup.setColour(colourScheme.getSchemeName());
1312 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1315 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1316 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1317 jGroup.setDisplayText(sg.getDisplayText());
1318 jGroup.setColourText(sg.getColourText());
1319 jGroup.setTextCol1(sg.textColour.getRGB());
1320 jGroup.setTextCol2(sg.textColour2.getRGB());
1321 jGroup.setTextColThreshold(sg.thresholdTextColour);
1322 jGroup.setShowUnconserved(sg.getShowNonconserved());
1323 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1324 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1325 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1326 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1327 for (SequenceI seq : sg.getSequences())
1329 // jGroup.addSeq(seqHash(seq));
1330 jGroup.getSeq().add(seqHash(seq));
1334 //jms.setJGroup(groups);
1336 for (JGroup grp : groups)
1338 object.getJGroup().add(grp);
1343 // /////////SAVE VIEWPORT
1344 Viewport view = new Viewport();
1345 view.setTitle(ap.alignFrame.getTitle());
1346 view.setSequenceSetId(
1347 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1348 view.setId(av.getViewId());
1349 if (av.getCodingComplement() != null)
1351 view.setComplementId(av.getCodingComplement().getViewId());
1353 view.setViewName(av.getViewName());
1354 view.setGatheredViews(av.isGatherViewsHere());
1356 Rectangle size = ap.av.getExplodedGeometry();
1357 Rectangle position = size;
1360 size = ap.alignFrame.getBounds();
1361 if (av.getCodingComplement() != null)
1363 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1371 view.setXpos(position.x);
1372 view.setYpos(position.y);
1374 view.setWidth(size.width);
1375 view.setHeight(size.height);
1377 view.setStartRes(vpRanges.getStartRes());
1378 view.setStartSeq(vpRanges.getStartSeq());
1380 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1382 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1383 userColours, object));
1386 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1388 AnnotationColourScheme ac = constructAnnotationColours(
1389 (jalview.schemes.AnnotationColourGradient) av
1390 .getGlobalColourScheme(),
1391 userColours, object);
1393 view.setAnnotationColours(ac);
1394 view.setBgColour("AnnotationColourGradient");
1398 view.setBgColour(ColourSchemeProperty
1399 .getColourName(av.getGlobalColourScheme()));
1402 ResidueShaderI vcs = av.getResidueShading();
1403 ColourSchemeI cs = av.getGlobalColourScheme();
1407 if (vcs.conservationApplied())
1409 view.setConsThreshold(vcs.getConservationInc());
1410 if (cs instanceof jalview.schemes.UserColourScheme)
1412 view.setBgColour(setUserColourScheme(cs, userColours, object));
1415 view.setPidThreshold(vcs.getThreshold());
1418 view.setConservationSelected(av.getConservationSelected());
1419 view.setPidSelected(av.getAbovePIDThreshold());
1420 final Font font = av.getFont();
1421 view.setFontName(font.getName());
1422 view.setFontSize(font.getSize());
1423 view.setFontStyle(font.getStyle());
1424 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1425 view.setRenderGaps(av.isRenderGaps());
1426 view.setShowAnnotation(av.isShowAnnotation());
1427 view.setShowBoxes(av.getShowBoxes());
1428 view.setShowColourText(av.getColourText());
1429 view.setShowFullId(av.getShowJVSuffix());
1430 view.setRightAlignIds(av.isRightAlignIds());
1431 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1432 view.setShowText(av.getShowText());
1433 view.setShowUnconserved(av.getShowUnconserved());
1434 view.setWrapAlignment(av.getWrapAlignment());
1435 view.setTextCol1(av.getTextColour().getRGB());
1436 view.setTextCol2(av.getTextColour2().getRGB());
1437 view.setTextColThreshold(av.getThresholdTextColour());
1438 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1439 view.setShowSequenceLogo(av.isShowSequenceLogo());
1440 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1441 view.setShowGroupConsensus(av.isShowGroupConsensus());
1442 view.setShowGroupConservation(av.isShowGroupConservation());
1443 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1444 view.setShowDbRefTooltip(av.isShowDBRefs());
1445 view.setFollowHighlight(av.isFollowHighlight());
1446 view.setFollowSelection(av.followSelection);
1447 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1448 if (av.getFeaturesDisplayed() != null)
1450 FeatureSettings fs = new FeatureSettings();
1452 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1453 .getFeatureRenderer();
1454 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1456 Vector<String> settingsAdded = new Vector<>();
1457 if (renderOrder != null)
1459 for (String featureType : renderOrder)
1461 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1462 setting.setType(featureType);
1465 * save any filter for the feature type
1467 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1468 if (filter != null) {
1469 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1470 FeatureMatcherI firstFilter = filters.next();
1471 setting.setMatcherSet(Jalview2XML.marshalFilter(
1472 firstFilter, filters, filter.isAnded()));
1476 * save colour scheme for the feature type
1478 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1479 if (!fcol.isSimpleColour())
1481 setting.setColour(fcol.getMaxColour().getRGB());
1482 setting.setMincolour(fcol.getMinColour().getRGB());
1483 setting.setMin(fcol.getMin());
1484 setting.setMax(fcol.getMax());
1485 setting.setColourByLabel(fcol.isColourByLabel());
1486 if (fcol.isColourByAttribute())
1488 String[] attName = fcol.getAttributeName();
1489 setting.getAttributeName().add(attName[0]);
1490 if (attName.length > 1)
1492 setting.getAttributeName().add(attName[1]);
1495 setting.setAutoScale(fcol.isAutoScaled());
1496 setting.setThreshold(fcol.getThreshold());
1497 Color noColour = fcol.getNoColour();
1498 if (noColour == null)
1500 setting.setNoValueColour(NoValueColour.NONE);
1502 else if (noColour.equals(fcol.getMaxColour()))
1504 setting.setNoValueColour(NoValueColour.MAX);
1508 setting.setNoValueColour(NoValueColour.MIN);
1510 // -1 = No threshold, 0 = Below, 1 = Above
1511 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1512 : (fcol.isBelowThreshold() ? 0 : -1));
1516 setting.setColour(fcol.getColour().getRGB());
1520 av.getFeaturesDisplayed().isVisible(featureType));
1522 .getOrder(featureType);
1525 setting.setOrder(rorder);
1527 /// fs.addSetting(setting);
1528 fs.getSetting().add(setting);
1529 settingsAdded.addElement(featureType);
1533 // is groups actually supposed to be a map here ?
1534 Iterator<String> en = fr.getFeatureGroups().iterator();
1535 Vector<String> groupsAdded = new Vector<>();
1536 while (en.hasNext())
1538 String grp = en.next();
1539 if (groupsAdded.contains(grp))
1543 Group g = new Group();
1545 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1548 fs.getGroup().add(g);
1549 groupsAdded.addElement(grp);
1551 // jms.setFeatureSettings(fs);
1552 object.setFeatureSettings(fs);
1555 if (av.hasHiddenColumns())
1557 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1558 .getHiddenColumns();
1561 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1565 Iterator<int[]> hiddenRegions = hidden.iterator();
1566 while (hiddenRegions.hasNext())
1568 int[] region = hiddenRegions.next();
1569 HiddenColumns hc = new HiddenColumns();
1570 hc.setStart(region[0]);
1571 hc.setEnd(region[1]);
1572 // view.addHiddenColumns(hc);
1573 view.getHiddenColumns().add(hc);
1577 if (calcIdSet.size() > 0)
1579 for (String calcId : calcIdSet)
1581 if (calcId.trim().length() > 0)
1583 CalcIdParam cidp = createCalcIdParam(calcId, av);
1584 // Some calcIds have no parameters.
1587 // view.addCalcIdParam(cidp);
1588 view.getCalcIdParam().add(cidp);
1594 // jms.addViewport(view);
1595 object.getViewport().add(view);
1597 // object.setJalviewModelSequence(jms);
1598 // object.getVamsasModel().addSequenceSet(vamsasSet);
1599 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1601 if (jout != null && fileName != null)
1603 // We may not want to write the object to disk,
1604 // eg we can copy the alignViewport to a new view object
1605 // using save and then load
1608 fileName = fileName.replace('\\', '/');
1609 System.out.println("Writing jar entry " + fileName);
1610 JarEntry entry = new JarEntry(fileName);
1611 jout.putNextEntry(entry);
1612 PrintWriter pout = new PrintWriter(
1613 new OutputStreamWriter(jout, UTF_8));
1614 JAXBContext jaxbContext = JAXBContext
1615 .newInstance(JalviewModel.class);
1616 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1618 // output pretty printed
1619 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1620 jaxbMarshaller.marshal(
1621 new ObjectFactory().createJalviewModel(object), pout);
1623 // jaxbMarshaller.marshal(object, pout);
1624 // marshaller.marshal(object);
1627 } catch (Exception ex)
1629 // TODO: raise error in GUI if marshalling failed.
1630 System.err.println("Error writing Jalview project");
1631 ex.printStackTrace();
1638 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1639 * for each viewer, with
1641 * <li>viewer geometry (position, size, split pane divider location)</li>
1642 * <li>index of the selected structure in the viewer (currently shows gapped
1644 * <li>the id of the annotation holding RNA secondary structure</li>
1645 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1647 * Varna viewer state is also written out (in native Varna XML) to separate
1648 * project jar entries. A separate entry is written for each RNA structure
1649 * displayed, with the naming convention
1651 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1659 * @param storeDataset
1661 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1662 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1663 boolean storeDataset)
1665 if (Desktop.desktop == null)
1669 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1670 for (int f = frames.length - 1; f > -1; f--)
1672 if (frames[f] instanceof AppVarna)
1674 AppVarna varna = (AppVarna) frames[f];
1676 * link the sequence to every viewer that is showing it and is linked to
1677 * its alignment panel
1679 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1681 String viewId = varna.getViewId();
1682 RnaViewer rna = new RnaViewer();
1683 rna.setViewId(viewId);
1684 rna.setTitle(varna.getTitle());
1685 rna.setXpos(varna.getX());
1686 rna.setYpos(varna.getY());
1687 rna.setWidth(varna.getWidth());
1688 rna.setHeight(varna.getHeight());
1689 rna.setDividerLocation(varna.getDividerLocation());
1690 rna.setSelectedRna(varna.getSelectedIndex());
1691 // jseq.addRnaViewer(rna);
1692 jseq.getRnaViewer().add(rna);
1695 * Store each Varna panel's state once in the project per sequence.
1696 * First time through only (storeDataset==false)
1698 // boolean storeSessions = false;
1699 // String sequenceViewId = viewId + seqsToIds.get(jds);
1700 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1702 // viewIds.add(sequenceViewId);
1703 // storeSessions = true;
1705 for (RnaModel model : varna.getModels())
1707 if (model.seq == jds)
1710 * VARNA saves each view (sequence or alignment secondary
1711 * structure, gapped or trimmed) as a separate XML file
1713 String jarEntryName = rnaSessions.get(model);
1714 if (jarEntryName == null)
1717 String varnaStateFile = varna.getStateInfo(model.rna);
1718 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1719 copyFileToJar(jout, varnaStateFile, jarEntryName);
1720 rnaSessions.put(model, jarEntryName);
1722 SecondaryStructure ss = new SecondaryStructure();
1723 String annotationId = varna.getAnnotation(jds).annotationId;
1724 ss.setAnnotationId(annotationId);
1725 ss.setViewerState(jarEntryName);
1726 ss.setGapped(model.gapped);
1727 ss.setTitle(model.title);
1728 // rna.addSecondaryStructure(ss);
1729 rna.getSecondaryStructure().add(ss);
1738 * Copy the contents of a file to a new entry added to the output jar
1742 * @param jarEntryName
1744 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1745 String jarEntryName)
1747 DataInputStream dis = null;
1750 File file = new File(infilePath);
1751 if (file.exists() && jout != null)
1753 dis = new DataInputStream(new FileInputStream(file));
1754 byte[] data = new byte[(int) file.length()];
1755 dis.readFully(data);
1756 writeJarEntry(jout, jarEntryName, data);
1758 } catch (Exception ex)
1760 ex.printStackTrace();
1768 } catch (IOException e)
1777 * Write the data to a new entry of given name in the output jar file
1780 * @param jarEntryName
1782 * @throws IOException
1784 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1785 byte[] data) throws IOException
1789 jarEntryName = jarEntryName.replace('\\','/');
1790 System.out.println("Writing jar entry " + jarEntryName);
1791 jout.putNextEntry(new JarEntry(jarEntryName));
1792 DataOutputStream dout = new DataOutputStream(jout);
1793 dout.write(data, 0, data.length);
1800 * Save the state of a structure viewer
1805 * the archive XML element under which to save the state
1808 * @param matchedFile
1812 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1813 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1814 String matchedFile, StructureViewerBase viewFrame)
1816 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1819 * Look for any bindings for this viewer to the PDB file of interest
1820 * (including part matches excluding chain id)
1822 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1824 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1825 final String pdbId = pdbentry.getId();
1826 if (!pdbId.equals(entry.getId())
1827 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1828 .startsWith(pdbId.toLowerCase())))
1831 * not interested in a binding to a different PDB entry here
1835 if (matchedFile == null)
1837 matchedFile = pdbentry.getFile();
1839 else if (!matchedFile.equals(pdbentry.getFile()))
1842 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1843 + pdbentry.getFile());
1847 // can get at it if the ID
1848 // match is ambiguous (e.g.
1851 for (int smap = 0; smap < viewFrame.getBinding()
1852 .getSequence()[peid].length; smap++)
1854 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1855 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1857 StructureState state = new StructureState();
1858 state.setVisible(true);
1859 state.setXpos(viewFrame.getX());
1860 state.setYpos(viewFrame.getY());
1861 state.setWidth(viewFrame.getWidth());
1862 state.setHeight(viewFrame.getHeight());
1863 final String viewId = viewFrame.getViewId();
1864 state.setViewId(viewId);
1865 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1866 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1867 state.setColourByJmol(viewFrame.isColouredByViewer());
1868 state.setType(viewFrame.getViewerType().toString());
1869 // pdb.addStructureState(state);
1870 pdb.getStructureState().add(state);
1878 * Populates the AnnotationColourScheme xml for save. This captures the
1879 * settings of the options in the 'Colour by Annotation' dialog.
1882 * @param userColours
1886 private AnnotationColourScheme constructAnnotationColours(
1887 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1890 AnnotationColourScheme ac = new AnnotationColourScheme();
1891 ac.setAboveThreshold(acg.getAboveThreshold());
1892 ac.setThreshold(acg.getAnnotationThreshold());
1893 // 2.10.2 save annotationId (unique) not annotation label
1894 ac.setAnnotation(acg.getAnnotation().annotationId);
1895 if (acg.getBaseColour() instanceof UserColourScheme)
1898 setUserColourScheme(acg.getBaseColour(), userColours, jm));
1903 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1906 ac.setMaxColour(acg.getMaxColour().getRGB());
1907 ac.setMinColour(acg.getMinColour().getRGB());
1908 ac.setPerSequence(acg.isSeqAssociated());
1909 ac.setPredefinedColours(acg.isPredefinedColours());
1913 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1914 IdentityHashMap<SequenceGroup, String> groupRefs,
1915 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1916 SequenceSet vamsasSet)
1919 for (int i = 0; i < aa.length; i++)
1921 Annotation an = new Annotation();
1923 AlignmentAnnotation annotation = aa[i];
1924 if (annotation.annotationId != null)
1926 annotationIds.put(annotation.annotationId, annotation);
1929 an.setId(annotation.annotationId);
1931 an.setVisible(annotation.visible);
1933 an.setDescription(annotation.description);
1935 if (annotation.sequenceRef != null)
1937 // 2.9 JAL-1781 xref on sequence id rather than name
1938 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1940 if (annotation.groupRef != null)
1942 String groupIdr = groupRefs.get(annotation.groupRef);
1943 if (groupIdr == null)
1945 // make a locally unique String
1946 groupRefs.put(annotation.groupRef,
1947 groupIdr = ("" + System.currentTimeMillis()
1948 + annotation.groupRef.getName()
1949 + groupRefs.size()));
1951 an.setGroupRef(groupIdr.toString());
1954 // store all visualization attributes for annotation
1955 an.setGraphHeight(annotation.graphHeight);
1956 an.setCentreColLabels(annotation.centreColLabels);
1957 an.setScaleColLabels(annotation.scaleColLabel);
1958 an.setShowAllColLabels(annotation.showAllColLabels);
1959 an.setBelowAlignment(annotation.belowAlignment);
1961 if (annotation.graph > 0)
1964 an.setGraphType(annotation.graph);
1965 an.setGraphGroup(annotation.graphGroup);
1966 if (annotation.getThreshold() != null)
1968 ThresholdLine line = new ThresholdLine();
1969 line.setLabel(annotation.getThreshold().label);
1970 line.setValue(annotation.getThreshold().value);
1971 line.setColour(annotation.getThreshold().colour.getRGB());
1972 an.setThresholdLine(line);
1980 an.setLabel(annotation.label);
1982 if (annotation == av.getAlignmentQualityAnnot()
1983 || annotation == av.getAlignmentConservationAnnotation()
1984 || annotation == av.getAlignmentConsensusAnnotation()
1985 || annotation.autoCalculated)
1987 // new way of indicating autocalculated annotation -
1988 an.setAutoCalculated(annotation.autoCalculated);
1990 if (annotation.hasScore())
1992 an.setScore(annotation.getScore());
1995 if (annotation.getCalcId() != null)
1997 calcIdSet.add(annotation.getCalcId());
1998 an.setCalcId(annotation.getCalcId());
2000 if (annotation.hasProperties())
2002 for (String pr : annotation.getProperties())
2004 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2006 prop.setValue(annotation.getProperty(pr));
2007 // an.addProperty(prop);
2008 an.getProperty().add(prop);
2012 AnnotationElement ae;
2013 if (annotation.annotations != null)
2015 an.setScoreOnly(false);
2016 for (int a = 0; a < annotation.annotations.length; a++)
2018 if ((annotation == null) || (annotation.annotations[a] == null))
2023 ae = new AnnotationElement();
2024 if (annotation.annotations[a].description != null)
2026 ae.setDescription(annotation.annotations[a].description);
2028 if (annotation.annotations[a].displayCharacter != null)
2030 ae.setDisplayCharacter(
2031 annotation.annotations[a].displayCharacter);
2034 if (!Float.isNaN(annotation.annotations[a].value))
2036 ae.setValue(annotation.annotations[a].value);
2040 if (annotation.annotations[a].secondaryStructure > ' ')
2042 ae.setSecondaryStructure(
2043 annotation.annotations[a].secondaryStructure + "");
2046 if (annotation.annotations[a].colour != null
2047 && annotation.annotations[a].colour != java.awt.Color.black)
2049 ae.setColour(annotation.annotations[a].colour.getRGB());
2052 // an.addAnnotationElement(ae);
2053 an.getAnnotationElement().add(ae);
2054 if (annotation.autoCalculated)
2056 // only write one non-null entry into the annotation row -
2057 // sufficient to get the visualization attributes necessary to
2065 an.setScoreOnly(true);
2067 if (!storeDS || (storeDS && !annotation.autoCalculated))
2069 // skip autocalculated annotation - these are only provided for
2071 // vamsasSet.addAnnotation(an);
2072 vamsasSet.getAnnotation().add(an);
2078 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2080 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2081 if (settings != null)
2083 CalcIdParam vCalcIdParam = new CalcIdParam();
2084 vCalcIdParam.setCalcId(calcId);
2085 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2086 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2087 // generic URI allowing a third party to resolve another instance of the
2088 // service used for this calculation
2089 for (String url : settings.getServiceURLs())
2091 // vCalcIdParam.addServiceURL(urls);
2092 vCalcIdParam.getServiceURL().add(url);
2094 vCalcIdParam.setVersion("1.0");
2095 if (settings.getPreset() != null)
2097 WsParamSetI setting = settings.getPreset();
2098 vCalcIdParam.setName(setting.getName());
2099 vCalcIdParam.setDescription(setting.getDescription());
2103 vCalcIdParam.setName("");
2104 vCalcIdParam.setDescription("Last used parameters");
2106 // need to be able to recover 1) settings 2) user-defined presets or
2107 // recreate settings from preset 3) predefined settings provided by
2108 // service - or settings that can be transferred (or discarded)
2109 vCalcIdParam.setParameters(
2110 settings.getWsParamFile().replace("\n", "|\\n|"));
2111 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2112 // todo - decide if updateImmediately is needed for any projects.
2114 return vCalcIdParam;
2119 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2122 if (calcIdParam.getVersion().equals("1.0"))
2124 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2125 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2126 .getPreferredServiceFor(calcIds);
2127 if (service != null)
2129 WsParamSetI parmSet = null;
2132 parmSet = service.getParamStore().parseServiceParameterFile(
2133 calcIdParam.getName(), calcIdParam.getDescription(),
2135 calcIdParam.getParameters().replace("|\\n|", "\n"));
2136 } catch (IOException x)
2138 warn("Couldn't parse parameter data for "
2139 + calcIdParam.getCalcId(), x);
2142 List<ArgumentI> argList = null;
2143 if (calcIdParam.getName().length() > 0)
2145 parmSet = service.getParamStore()
2146 .getPreset(calcIdParam.getName());
2147 if (parmSet != null)
2149 // TODO : check we have a good match with settings in AACon -
2150 // otherwise we'll need to create a new preset
2155 argList = parmSet.getArguments();
2158 AAConSettings settings = new AAConSettings(
2159 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2160 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2161 calcIdParam.isNeedsUpdate());
2166 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2170 throw new Error(MessageManager.formatMessage(
2171 "error.unsupported_version_calcIdparam", new Object[]
2172 { calcIdParam.toString() }));
2176 * External mapping between jalview objects and objects yielding a valid and
2177 * unique object ID string. This is null for normal Jalview project IO, but
2178 * non-null when a jalview project is being read or written as part of a
2181 IdentityHashMap jv2vobj = null;
2184 * Construct a unique ID for jvobj using either existing bindings or if none
2185 * exist, the result of the hashcode call for the object.
2188 * jalview data object
2189 * @return unique ID for referring to jvobj
2191 private String makeHashCode(Object jvobj, String altCode)
2193 if (jv2vobj != null)
2195 Object id = jv2vobj.get(jvobj);
2198 return id.toString();
2200 // check string ID mappings
2201 if (jvids2vobj != null && jvobj instanceof String)
2203 id = jvids2vobj.get(jvobj);
2207 return id.toString();
2209 // give up and warn that something has gone wrong
2210 warn("Cannot find ID for object in external mapping : " + jvobj);
2216 * return local jalview object mapped to ID, if it exists
2220 * @return null or object bound to idcode
2222 private Object retrieveExistingObj(String idcode)
2224 if (idcode != null && vobj2jv != null)
2226 return vobj2jv.get(idcode);
2232 * binding from ID strings from external mapping table to jalview data model
2235 private Hashtable vobj2jv;
2237 private Sequence createVamsasSequence(String id, SequenceI jds)
2239 return createVamsasSequence(true, id, jds, null);
2242 private Sequence createVamsasSequence(boolean recurse, String id,
2243 SequenceI jds, SequenceI parentseq)
2245 Sequence vamsasSeq = new Sequence();
2246 vamsasSeq.setId(id);
2247 vamsasSeq.setName(jds.getName());
2248 vamsasSeq.setSequence(jds.getSequenceAsString());
2249 vamsasSeq.setDescription(jds.getDescription());
2250 jalview.datamodel.DBRefEntry[] dbrefs = null;
2251 if (jds.getDatasetSequence() != null)
2253 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2257 // seqId==dsseqid so we can tell which sequences really are
2258 // dataset sequences only
2259 vamsasSeq.setDsseqid(id);
2260 dbrefs = jds.getDBRefs();
2261 if (parentseq == null)
2268 for (int d = 0; d < dbrefs.length; d++)
2270 DBRef dbref = new DBRef();
2271 dbref.setSource(dbrefs[d].getSource());
2272 dbref.setVersion(dbrefs[d].getVersion());
2273 dbref.setAccessionId(dbrefs[d].getAccessionId());
2274 if (dbrefs[d].hasMap())
2276 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2278 dbref.setMapping(mp);
2280 // vamsasSeq.addDBRef(dbref);
2281 vamsasSeq.getDBRef().add(dbref);
2287 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2288 SequenceI parentseq, SequenceI jds, boolean recurse)
2291 if (jmp.getMap() != null)
2295 jalview.util.MapList mlst = jmp.getMap();
2296 List<int[]> r = mlst.getFromRanges();
2297 for (int[] range : r)
2299 MapListFrom mfrom = new MapListFrom();
2300 mfrom.setStart(range[0]);
2301 mfrom.setEnd(range[1]);
2302 // mp.addMapListFrom(mfrom);
2303 mp.getMapListFrom().add(mfrom);
2305 r = mlst.getToRanges();
2306 for (int[] range : r)
2308 MapListTo mto = new MapListTo();
2309 mto.setStart(range[0]);
2310 mto.setEnd(range[1]);
2311 // mp.addMapListTo(mto);
2312 mp.getMapListTo().add(mto);
2314 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2315 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2316 if (jmp.getTo() != null)
2318 // MappingChoice mpc = new MappingChoice();
2320 // check/create ID for the sequence referenced by getTo()
2323 SequenceI ps = null;
2324 if (parentseq != jmp.getTo()
2325 && parentseq.getDatasetSequence() != jmp.getTo())
2327 // chaining dbref rather than a handshaking one
2328 jmpid = seqHash(ps = jmp.getTo());
2332 jmpid = seqHash(ps = parentseq);
2334 // mpc.setDseqFor(jmpid);
2335 mp.setDseqFor(jmpid);
2336 if (!seqRefIds.containsKey(jmpid))
2338 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2339 seqRefIds.put(jmpid, ps);
2343 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2346 // mp.setMappingChoice(mpc);
2352 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2353 List<UserColourScheme> userColours, JalviewModel jm)
2356 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2357 boolean newucs = false;
2358 if (!userColours.contains(ucs))
2360 userColours.add(ucs);
2363 id = "ucs" + userColours.indexOf(ucs);
2366 // actually create the scheme's entry in the XML model
2367 java.awt.Color[] colours = ucs.getColours();
2368 UserColours uc = new UserColours();
2369 // UserColourScheme jbucs = new UserColourScheme();
2370 JalviewUserColours jbucs = new JalviewUserColours();
2372 for (int i = 0; i < colours.length; i++)
2374 Colour col = new Colour();
2375 col.setName(ResidueProperties.aa[i]);
2376 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2377 // jbucs.addColour(col);
2378 jbucs.getColour().add(col);
2380 if (ucs.getLowerCaseColours() != null)
2382 colours = ucs.getLowerCaseColours();
2383 for (int i = 0; i < colours.length; i++)
2385 Colour col = new Colour();
2386 col.setName(ResidueProperties.aa[i].toLowerCase());
2387 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2388 // jbucs.addColour(col);
2389 jbucs.getColour().add(col);
2394 uc.setUserColourScheme(jbucs);
2395 // jm.addUserColours(uc);
2396 jm.getUserColours().add(uc);
2402 jalview.schemes.UserColourScheme getUserColourScheme(
2403 JalviewModel jm, String id)
2405 List<UserColours> uc = jm.getUserColours();
2406 UserColours colours = null;
2408 for (int i = 0; i < uc.length; i++)
2410 if (uc[i].getId().equals(id))
2417 for (UserColours c : uc)
2419 if (c.getId().equals(id))
2426 java.awt.Color[] newColours = new java.awt.Color[24];
2428 for (int i = 0; i < 24; i++)
2430 newColours[i] = new java.awt.Color(Integer.parseInt(
2431 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2432 colours.getUserColourScheme().getColour().get(i).getRGB(),
2436 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2439 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2441 newColours = new java.awt.Color[23];
2442 for (int i = 0; i < 23; i++)
2444 newColours[i] = new java.awt.Color(Integer.parseInt(
2445 colours.getUserColourScheme().getColour().get(i + 24)
2449 ucs.setLowerCaseColours(newColours);
2456 * contains last error message (if any) encountered by XML loader.
2458 String errorMessage = null;
2461 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2462 * exceptions are raised during project XML parsing
2464 public boolean attemptversion1parse = false;
2467 * Load a jalview project archive from a jar file
2470 * - HTTP URL or filename
2472 public AlignFrame loadJalviewAlign(final Object file)
2475 jalview.gui.AlignFrame af = null;
2479 // create list to store references for any new Jmol viewers created
2480 newStructureViewers = new Vector<>();
2481 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2482 // Workaround is to make sure caller implements the JarInputStreamProvider
2484 // so we can re-open the jar input stream for each entry.
2486 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2487 af = loadJalviewAlign(jprovider);
2490 af.setMenusForViewport();
2492 } catch (MalformedURLException e)
2494 errorMessage = "Invalid URL format for '" + file + "'";
2500 SwingUtilities.invokeAndWait(new Runnable()
2505 setLoadingFinishedForNewStructureViewers();
2508 } catch (Exception x)
2510 System.err.println("Error loading alignment: " + x.getMessage());
2516 @SuppressWarnings("unused")
2517 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2519 // BH 2018 allow for bytes already attached to File object
2521 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2522 byte[] bytes = Platform.getFileBytes((File) ofile);
2524 errorMessage = null;
2525 uniqueSetSuffix = null;
2527 viewportsAdded.clear();
2528 frefedSequence = null;
2530 if (file.startsWith("http://")) {
2531 url = new URL(file);
2533 final URL _url = url;
2534 return new jarInputStreamProvider() {
2537 public JarInputStream getJarInputStream() throws IOException {
2538 if (bytes != null) {
2539 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2540 return new JarInputStream(new ByteArrayInputStream(bytes));
2543 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2544 return new JarInputStream(_url.openStream());
2546 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2547 return new JarInputStream(new FileInputStream(file));
2552 public String getFilename() {
2556 } catch (IOException e) {
2557 e.printStackTrace();
2563 * Recover jalview session from a jalview project archive. Caller may
2564 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2565 * themselves. Any null fields will be initialised with default values,
2566 * non-null fields are left alone.
2571 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2573 errorMessage = null;
2574 if (uniqueSetSuffix == null)
2576 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2578 if (seqRefIds == null)
2582 AlignFrame af = null, _af = null;
2583 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2584 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2585 final String file = jprovider.getFilename();
2588 JarInputStream jin = null;
2589 JarEntry jarentry = null;
2594 jin = jprovider.getJarInputStream();
2595 for (int i = 0; i < entryCount; i++)
2597 jarentry = jin.getNextJarEntry();
2600 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2602 JAXBContext jc = JAXBContext
2603 .newInstance("jalview.xml.binding.jalview");
2604 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2605 .createXMLStreamReader(jin);
2606 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2607 JAXBElement<JalviewModel> jbe = um
2608 .unmarshal(streamReader, JalviewModel.class);
2609 JalviewModel object = jbe.getValue();
2611 if (true) // !skipViewport(object))
2613 _af = loadFromObject(object, file, true, jprovider);
2614 if (_af != null && object.getViewport().size() > 0)
2615 // getJalviewModelSequence().getViewportCount() > 0)
2619 // store a reference to the first view
2622 if (_af.getViewport().isGatherViewsHere())
2624 // if this is a gathered view, keep its reference since
2625 // after gathering views, only this frame will remain
2627 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2630 // Save dataset to register mappings once all resolved
2631 importedDatasets.put(
2632 af.getViewport().getAlignment().getDataset(),
2633 af.getViewport().getAlignment().getDataset());
2638 else if (jarentry != null)
2640 // Some other file here.
2643 } while (jarentry != null);
2644 resolveFrefedSequences();
2645 } catch (IOException ex)
2647 ex.printStackTrace();
2648 errorMessage = "Couldn't locate Jalview XML file : " + file;
2650 "Exception whilst loading jalview XML file : " + ex + "\n");
2651 } catch (Exception ex)
2653 System.err.println("Parsing as Jalview Version 2 file failed.");
2654 ex.printStackTrace(System.err);
2655 if (attemptversion1parse)
2657 // Is Version 1 Jar file?
2660 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2661 } catch (Exception ex2)
2663 System.err.println("Exception whilst loading as jalviewXMLV1:");
2664 ex2.printStackTrace();
2668 if (Desktop.instance != null)
2670 Desktop.instance.stopLoading();
2674 System.out.println("Successfully loaded archive file");
2677 ex.printStackTrace();
2680 "Exception whilst loading jalview XML file : " + ex + "\n");
2681 } catch (OutOfMemoryError e)
2683 // Don't use the OOM Window here
2684 errorMessage = "Out of memory loading jalview XML file";
2685 System.err.println("Out of memory whilst loading jalview XML file");
2686 e.printStackTrace();
2690 * Regather multiple views (with the same sequence set id) to the frame (if
2691 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2692 * views instead of separate frames. Note this doesn't restore a state where
2693 * some expanded views in turn have tabbed views - the last "first tab" read
2694 * in will play the role of gatherer for all.
2696 for (AlignFrame fr : gatherToThisFrame.values())
2698 Desktop.instance.gatherViews(fr);
2701 restoreSplitFrames();
2702 for (AlignmentI ds : importedDatasets.keySet())
2704 if (ds.getCodonFrames() != null)
2706 StructureSelectionManager
2707 .getStructureSelectionManager(Desktop.instance)
2708 .registerMappings(ds.getCodonFrames());
2711 if (errorMessage != null)
2716 if (Desktop.instance != null)
2718 Desktop.instance.stopLoading();
2725 * Try to reconstruct and display SplitFrame windows, where each contains
2726 * complementary dna and protein alignments. Done by pairing up AlignFrame
2727 * objects (created earlier) which have complementary viewport ids associated.
2729 protected void restoreSplitFrames()
2731 List<SplitFrame> gatherTo = new ArrayList<>();
2732 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2733 Map<String, AlignFrame> dna = new HashMap<>();
2736 * Identify the DNA alignments
2738 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2741 AlignFrame af = candidate.getValue();
2742 if (af.getViewport().getAlignment().isNucleotide())
2744 dna.put(candidate.getKey().getId(), af);
2749 * Try to match up the protein complements
2751 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2754 AlignFrame af = candidate.getValue();
2755 if (!af.getViewport().getAlignment().isNucleotide())
2757 String complementId = candidate.getKey().getComplementId();
2758 // only non-null complements should be in the Map
2759 if (complementId != null && dna.containsKey(complementId))
2761 final AlignFrame dnaFrame = dna.get(complementId);
2762 SplitFrame sf = createSplitFrame(dnaFrame, af);
2763 addedToSplitFrames.add(dnaFrame);
2764 addedToSplitFrames.add(af);
2765 dnaFrame.setMenusForViewport();
2766 af.setMenusForViewport();
2767 if (af.getViewport().isGatherViewsHere())
2776 * Open any that we failed to pair up (which shouldn't happen!) as
2777 * standalone AlignFrame's.
2779 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2782 AlignFrame af = candidate.getValue();
2783 if (!addedToSplitFrames.contains(af))
2785 Viewport view = candidate.getKey();
2786 Desktop.addInternalFrame(af, view.getTitle(),
2787 safeInt(view.getWidth()), safeInt(view.getHeight()));
2788 af.setMenusForViewport();
2789 System.err.println("Failed to restore view " + view.getTitle()
2790 + " to split frame");
2795 * Gather back into tabbed views as flagged.
2797 for (SplitFrame sf : gatherTo)
2799 Desktop.instance.gatherViews(sf);
2802 splitFrameCandidates.clear();
2806 * Construct and display one SplitFrame holding DNA and protein alignments.
2809 * @param proteinFrame
2812 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2813 AlignFrame proteinFrame)
2815 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2816 String title = MessageManager.getString("label.linked_view_title");
2817 int width = (int) dnaFrame.getBounds().getWidth();
2818 int height = (int) (dnaFrame.getBounds().getHeight()
2819 + proteinFrame.getBounds().getHeight() + 50);
2822 * SplitFrame location is saved to both enclosed frames
2824 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2825 Desktop.addInternalFrame(splitFrame, title, width, height);
2828 * And compute cDNA consensus (couldn't do earlier with consensus as
2829 * mappings were not yet present)
2831 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
2837 * check errorMessage for a valid error message and raise an error box in the
2838 * GUI or write the current errorMessage to stderr and then clear the error
2841 protected void reportErrors()
2843 reportErrors(false);
2846 protected void reportErrors(final boolean saving)
2848 if (errorMessage != null)
2850 final String finalErrorMessage = errorMessage;
2853 javax.swing.SwingUtilities.invokeLater(new Runnable()
2858 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2860 "Error " + (saving ? "saving" : "loading")
2862 JvOptionPane.WARNING_MESSAGE);
2868 System.err.println("Problem loading Jalview file: " + errorMessage);
2871 errorMessage = null;
2874 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2877 * when set, local views will be updated from view stored in JalviewXML
2878 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2879 * sync if this is set to true.
2881 private final boolean updateLocalViews = false;
2884 * Returns the path to a temporary file holding the PDB file for the given PDB
2885 * id. The first time of asking, searches for a file of that name in the
2886 * Jalview project jar, and copies it to a new temporary file. Any repeat
2887 * requests just return the path to the file previously created.
2893 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2896 if (alreadyLoadedPDB.containsKey(pdbId))
2898 return alreadyLoadedPDB.get(pdbId).toString();
2901 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2903 if (tempFile != null)
2905 alreadyLoadedPDB.put(pdbId, tempFile);
2911 * Copies the jar entry of given name to a new temporary file and returns the
2912 * path to the file, or null if the entry is not found.
2915 * @param jarEntryName
2917 * a prefix for the temporary file name, must be at least three
2920 * null or original file - so new file can be given the same suffix
2924 protected String copyJarEntry(jarInputStreamProvider jprovider,
2925 String jarEntryName, String prefix, String origFile)
2927 BufferedReader in = null;
2928 PrintWriter out = null;
2929 String suffix = ".tmp";
2930 if (origFile == null)
2932 origFile = jarEntryName;
2934 int sfpos = origFile.lastIndexOf(".");
2935 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2937 suffix = "." + origFile.substring(sfpos + 1);
2941 JarInputStream jin = jprovider.getJarInputStream();
2943 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2944 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2945 * FileInputStream(jprovider)); }
2948 JarEntry entry = null;
2951 entry = jin.getNextJarEntry();
2952 } while (entry != null && !entry.getName().equals(jarEntryName));
2955 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2956 File outFile = File.createTempFile(prefix, suffix);
2957 outFile.deleteOnExit();
2958 out = new PrintWriter(new FileOutputStream(outFile));
2961 while ((data = in.readLine()) != null)
2966 String t = outFile.getAbsolutePath();
2971 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2973 } catch (Exception ex)
2975 ex.printStackTrace();
2983 } catch (IOException e)
2997 private class JvAnnotRow
2999 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3006 * persisted version of annotation row from which to take vis properties
3008 public jalview.datamodel.AlignmentAnnotation template;
3011 * original position of the annotation row in the alignment
3017 * Load alignment frame from jalview XML DOM object
3019 * @param jalviewModel
3022 * filename source string
3023 * @param loadTreesAndStructures
3024 * when false only create Viewport
3026 * data source provider
3027 * @return alignment frame created from view stored in DOM
3029 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3030 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3032 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3033 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3035 // JalviewModelSequence jms = object.getJalviewModelSequence();
3037 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3039 Viewport view = (jalviewModel.getViewport().size() > 0)
3040 ? jalviewModel.getViewport().get(0)
3043 // ////////////////////////////////
3046 List<SequenceI> hiddenSeqs = null;
3048 List<SequenceI> tmpseqs = new ArrayList<>();
3050 boolean multipleView = false;
3051 SequenceI referenceseqForView = null;
3052 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3053 List<JSeq> jseqs = jalviewModel.getJSeq();
3054 int vi = 0; // counter in vamsasSeq array
3055 for (int i = 0; i < jseqs.size(); i++)
3057 JSeq jseq = jseqs.get(i);
3058 String seqId = jseq.getId();
3060 SequenceI tmpSeq = seqRefIds.get(seqId);
3063 if (!incompleteSeqs.containsKey(seqId))
3065 // may not need this check, but keep it for at least 2.9,1 release
3066 if (tmpSeq.getStart() != jseq.getStart()
3067 || tmpSeq.getEnd() != jseq.getEnd())
3070 "Warning JAL-2154 regression: updating start/end for sequence "
3071 + tmpSeq.toString() + " to " + jseq);
3076 incompleteSeqs.remove(seqId);
3078 if (vamsasSeqs.size() > vi
3079 && vamsasSeqs.get(vi).getId().equals(seqId))
3081 // most likely we are reading a dataset XML document so
3082 // update from vamsasSeq section of XML for this sequence
3083 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3084 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3085 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3090 // reading multiple views, so vamsasSeq set is a subset of JSeq
3091 multipleView = true;
3093 tmpSeq.setStart(jseq.getStart());
3094 tmpSeq.setEnd(jseq.getEnd());
3095 tmpseqs.add(tmpSeq);
3099 Sequence vamsasSeq = vamsasSeqs.get(vi);
3100 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3101 vamsasSeq.getSequence());
3102 tmpSeq.setDescription(vamsasSeq.getDescription());
3103 tmpSeq.setStart(jseq.getStart());
3104 tmpSeq.setEnd(jseq.getEnd());
3105 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3106 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3107 tmpseqs.add(tmpSeq);
3111 if (safeBoolean(jseq.isViewreference()))
3113 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3116 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3118 if (hiddenSeqs == null)
3120 hiddenSeqs = new ArrayList<>();
3123 hiddenSeqs.add(tmpSeq);
3128 // Create the alignment object from the sequence set
3129 // ///////////////////////////////
3130 SequenceI[] orderedSeqs = tmpseqs
3131 .toArray(new SequenceI[tmpseqs.size()]);
3133 AlignmentI al = null;
3134 // so we must create or recover the dataset alignment before going further
3135 // ///////////////////////////////
3136 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3138 // older jalview projects do not have a dataset - so creat alignment and
3140 al = new Alignment(orderedSeqs);
3141 al.setDataset(null);
3145 boolean isdsal = jalviewModel.getViewport().isEmpty();
3148 // we are importing a dataset record, so
3149 // recover reference to an alignment already materialsed as dataset
3150 al = getDatasetFor(vamsasSet.getDatasetId());
3154 // materialse the alignment
3155 al = new Alignment(orderedSeqs);
3159 addDatasetRef(vamsasSet.getDatasetId(), al);
3162 // finally, verify all data in vamsasSet is actually present in al
3163 // passing on flag indicating if it is actually a stored dataset
3164 recoverDatasetFor(vamsasSet, al, isdsal);
3167 if (referenceseqForView != null)
3169 al.setSeqrep(referenceseqForView);
3171 // / Add the alignment properties
3172 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3174 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3176 al.setProperty(ssp.getKey(), ssp.getValue());
3179 // ///////////////////////////////
3181 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3184 // load sequence features, database references and any associated PDB
3185 // structures for the alignment
3187 // prior to 2.10, this part would only be executed the first time a
3188 // sequence was encountered, but not afterwards.
3189 // now, for 2.10 projects, this is also done if the xml doc includes
3190 // dataset sequences not actually present in any particular view.
3192 for (int i = 0; i < vamsasSeqs.size(); i++)
3194 JSeq jseq = jseqs.get(i);
3195 if (jseq.getFeatures().size() > 0)
3197 List<Feature> features = jseq.getFeatures();
3198 for (int f = 0; f < features.size(); f++)
3200 Feature feat = features.get(f);
3201 SequenceFeature sf = new SequenceFeature(feat.getType(),
3202 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3203 safeFloat(feat.getScore()), feat.getFeatureGroup());
3204 sf.setStatus(feat.getStatus());
3207 * load any feature attributes - include map-valued attributes
3209 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3210 for (int od = 0; od < feat.getOtherData().size(); od++)
3212 OtherData keyValue = feat.getOtherData().get(od);
3213 String attributeName = keyValue.getKey();
3214 String attributeValue = keyValue.getValue();
3215 if (attributeName.startsWith("LINK"))
3217 sf.addLink(attributeValue);
3221 String subAttribute = keyValue.getKey2();
3222 if (subAttribute == null)
3224 // simple string-valued attribute
3225 sf.setValue(attributeName, attributeValue);
3229 // attribute 'key' has sub-attribute 'key2'
3230 if (!mapAttributes.containsKey(attributeName))
3232 mapAttributes.put(attributeName, new HashMap<>());
3234 mapAttributes.get(attributeName).put(subAttribute,
3239 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3242 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3245 // adds feature to datasequence's feature set (since Jalview 2.10)
3246 al.getSequenceAt(i).addSequenceFeature(sf);
3249 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3251 // adds dbrefs to datasequence's set (since Jalview 2.10)
3253 al.getSequenceAt(i).getDatasetSequence() == null
3254 ? al.getSequenceAt(i)
3255 : al.getSequenceAt(i).getDatasetSequence(),
3258 if (jseq.getPdbids().size() > 0)
3260 List<Pdbids> ids = jseq.getPdbids();
3261 for (int p = 0; p < ids.size(); p++)
3263 Pdbids pdbid = ids.get(p);
3264 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3265 entry.setId(pdbid.getId());
3266 if (pdbid.getType() != null)
3268 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3270 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3274 entry.setType(PDBEntry.Type.FILE);
3277 // jprovider is null when executing 'New View'
3278 if (pdbid.getFile() != null && jprovider != null)
3280 if (!pdbloaded.containsKey(pdbid.getFile()))
3282 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3287 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3291 if (pdbid.getPdbentryItem() != null)
3293 for (PdbentryItem item : pdbid.getPdbentryItem())
3295 for (Property pr : item.getProperty())
3297 entry.setProperty(pr.getName(), pr.getValue());
3302 for (Property prop : pdbid.getProperty())
3304 entry.setProperty(prop.getName(), prop.getValue());
3306 StructureSelectionManager
3307 .getStructureSelectionManager(Desktop.instance)
3308 .registerPDBEntry(entry);
3309 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3310 if (al.getSequenceAt(i).getDatasetSequence() != null)
3312 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3316 al.getSequenceAt(i).addPDBId(entry);
3321 } // end !multipleview
3323 // ///////////////////////////////
3324 // LOAD SEQUENCE MAPPINGS
3326 if (vamsasSet.getAlcodonFrame().size() > 0)
3328 // TODO Potentially this should only be done once for all views of an
3330 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3331 for (int i = 0; i < alc.size(); i++)
3333 AlignedCodonFrame cf = new AlignedCodonFrame();
3334 if (alc.get(i).getAlcodMap().size() > 0)
3336 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3337 for (int m = 0; m < maps.size(); m++)
3339 AlcodMap map = maps.get(m);
3340 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3342 jalview.datamodel.Mapping mapping = null;
3343 // attach to dna sequence reference.
3344 if (map.getMapping() != null)
3346 mapping = addMapping(map.getMapping());
3347 if (dnaseq != null && mapping.getTo() != null)
3349 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3355 newAlcodMapRef(map.getDnasq(), cf, mapping));
3359 al.addCodonFrame(cf);
3364 // ////////////////////////////////
3366 List<JvAnnotRow> autoAlan = new ArrayList<>();
3369 * store any annotations which forward reference a group's ID
3371 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3373 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3375 List<Annotation> an = vamsasSet.getAnnotation();
3377 for (int i = 0; i < an.size(); i++)
3379 Annotation annotation = an.get(i);
3382 * test if annotation is automatically calculated for this view only
3384 boolean autoForView = false;
3385 if (annotation.getLabel().equals("Quality")
3386 || annotation.getLabel().equals("Conservation")
3387 || annotation.getLabel().equals("Consensus"))
3389 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3391 // JAXB has no has() test; schema defaults value to false
3392 // if (!annotation.hasAutoCalculated())
3394 // annotation.setAutoCalculated(true);
3397 if (autoForView || annotation.isAutoCalculated())
3399 // remove ID - we don't recover annotation from other views for
3400 // view-specific annotation
3401 annotation.setId(null);
3404 // set visibility for other annotation in this view
3405 String annotationId = annotation.getId();
3406 if (annotationId != null && annotationIds.containsKey(annotationId))
3408 AlignmentAnnotation jda = annotationIds.get(annotationId);
3409 // in principle Visible should always be true for annotation displayed
3410 // in multiple views
3411 if (annotation.isVisible() != null)
3413 jda.visible = annotation.isVisible();
3416 al.addAnnotation(jda);
3420 // Construct new annotation from model.
3421 List<AnnotationElement> ae = annotation.getAnnotationElement();
3422 jalview.datamodel.Annotation[] anot = null;
3423 java.awt.Color firstColour = null;
3425 if (!annotation.isScoreOnly())
3427 anot = new jalview.datamodel.Annotation[al.getWidth()];
3428 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3430 AnnotationElement annElement = ae.get(aa);
3431 anpos = annElement.getPosition();
3433 if (anpos >= anot.length)
3438 float value = safeFloat(annElement.getValue());
3439 anot[anpos] = new jalview.datamodel.Annotation(
3440 annElement.getDisplayCharacter(),
3441 annElement.getDescription(),
3442 (annElement.getSecondaryStructure() == null
3443 || annElement.getSecondaryStructure()
3447 .getSecondaryStructure()
3450 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3451 if (firstColour == null)
3453 firstColour = anot[anpos].colour;
3457 jalview.datamodel.AlignmentAnnotation jaa = null;
3459 if (annotation.isGraph())
3461 float llim = 0, hlim = 0;
3462 // if (autoForView || an[i].isAutoCalculated()) {
3465 jaa = new jalview.datamodel.AlignmentAnnotation(
3466 annotation.getLabel(), annotation.getDescription(), anot,
3467 llim, hlim, safeInt(annotation.getGraphType()));
3469 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3470 jaa._linecolour = firstColour;
3471 if (annotation.getThresholdLine() != null)
3473 jaa.setThreshold(new jalview.datamodel.GraphLine(
3474 safeFloat(annotation.getThresholdLine().getValue()),
3475 annotation.getThresholdLine().getLabel(),
3476 new java.awt.Color(safeInt(
3477 annotation.getThresholdLine().getColour()))));
3479 if (autoForView || annotation.isAutoCalculated())
3481 // Hardwire the symbol display line to ensure that labels for
3482 // histograms are displayed
3488 jaa = new jalview.datamodel.AlignmentAnnotation(
3489 annotation.getLabel(), annotation.getDescription(), anot);
3490 jaa._linecolour = firstColour;
3492 // register new annotation
3493 if (annotation.getId() != null)
3495 annotationIds.put(annotation.getId(), jaa);
3496 jaa.annotationId = annotation.getId();
3498 // recover sequence association
3499 String sequenceRef = annotation.getSequenceRef();
3500 if (sequenceRef != null)
3502 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3503 SequenceI sequence = seqRefIds.get(sequenceRef);
3504 if (sequence == null)
3506 // in pre-2.9 projects sequence ref is to sequence name
3507 sequence = al.findName(sequenceRef);
3509 if (sequence != null)
3511 jaa.createSequenceMapping(sequence, 1, true);
3512 sequence.addAlignmentAnnotation(jaa);
3515 // and make a note of any group association
3516 if (annotation.getGroupRef() != null
3517 && annotation.getGroupRef().length() > 0)
3519 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3520 .get(annotation.getGroupRef());
3523 aal = new ArrayList<>();
3524 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3529 if (annotation.getScore() != null)
3531 jaa.setScore(annotation.getScore().doubleValue());
3533 if (annotation.isVisible() != null)
3535 jaa.visible = annotation.isVisible().booleanValue();
3538 if (annotation.isCentreColLabels() != null)
3540 jaa.centreColLabels = annotation.isCentreColLabels()
3544 if (annotation.isScaleColLabels() != null)
3546 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3548 if (annotation.isAutoCalculated())
3550 // newer files have an 'autoCalculated' flag and store calculation
3551 // state in viewport properties
3552 jaa.autoCalculated = true; // means annotation will be marked for
3553 // update at end of load.
3555 if (annotation.getGraphHeight() != null)
3557 jaa.graphHeight = annotation.getGraphHeight().intValue();
3559 jaa.belowAlignment = annotation.isBelowAlignment();
3560 jaa.setCalcId(annotation.getCalcId());
3561 if (annotation.getProperty().size() > 0)
3563 for (Annotation.Property prop : annotation
3566 jaa.setProperty(prop.getName(), prop.getValue());
3569 if (jaa.autoCalculated)
3571 autoAlan.add(new JvAnnotRow(i, jaa));
3574 // if (!autoForView)
3576 // add autocalculated group annotation and any user created annotation
3578 al.addAnnotation(jaa);
3582 // ///////////////////////
3584 // Create alignment markup and styles for this view
3585 if (jalviewModel.getJGroup().size() > 0)
3587 List<JGroup> groups = jalviewModel.getJGroup();
3588 boolean addAnnotSchemeGroup = false;
3589 for (int i = 0; i < groups.size(); i++)
3591 JGroup jGroup = groups.get(i);
3592 ColourSchemeI cs = null;
3593 if (jGroup.getColour() != null)
3595 if (jGroup.getColour().startsWith("ucs"))
3597 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3599 else if (jGroup.getColour().equals("AnnotationColourGradient")
3600 && jGroup.getAnnotationColours() != null)
3602 addAnnotSchemeGroup = true;
3606 cs = ColourSchemeProperty.getColourScheme(al,
3607 jGroup.getColour());
3610 int pidThreshold = safeInt(jGroup.getPidThreshold());
3612 Vector<SequenceI> seqs = new Vector<>();
3614 for (int s = 0; s < jGroup.getSeq().size(); s++)
3616 String seqId = jGroup.getSeq().get(s);
3617 SequenceI ts = seqRefIds.get(seqId);
3621 seqs.addElement(ts);
3625 if (seqs.size() < 1)
3630 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3631 safeBoolean(jGroup.isDisplayBoxes()),
3632 safeBoolean(jGroup.isDisplayText()),
3633 safeBoolean(jGroup.isColourText()),
3634 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3635 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3636 sg.getGroupColourScheme()
3637 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3638 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3640 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3641 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3642 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3643 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3644 // attributes with a default in the schema are never null
3645 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3646 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3647 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3648 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3649 if (jGroup.getConsThreshold() != null
3650 && jGroup.getConsThreshold().intValue() != 0)
3652 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3655 c.verdict(false, 25);
3656 sg.cs.setConservation(c);
3659 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3661 // re-instate unique group/annotation row reference
3662 List<AlignmentAnnotation> jaal = groupAnnotRefs
3663 .get(jGroup.getId());
3666 for (AlignmentAnnotation jaa : jaal)
3669 if (jaa.autoCalculated)
3671 // match up and try to set group autocalc alignment row for this
3673 if (jaa.label.startsWith("Consensus for "))
3675 sg.setConsensus(jaa);
3677 // match up and try to set group autocalc alignment row for this
3679 if (jaa.label.startsWith("Conservation for "))
3681 sg.setConservationRow(jaa);
3688 if (addAnnotSchemeGroup)
3690 // reconstruct the annotation colourscheme
3691 sg.setColourScheme(constructAnnotationColour(
3692 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3698 // only dataset in this model, so just return.
3701 // ///////////////////////////////
3704 // If we just load in the same jar file again, the sequenceSetId
3705 // will be the same, and we end up with multiple references
3706 // to the same sequenceSet. We must modify this id on load
3707 // so that each load of the file gives a unique id
3708 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3709 String viewId = (view.getId() == null ? null
3710 : view.getId() + uniqueSetSuffix);
3711 AlignFrame af = null;
3712 AlignViewport av = null;
3713 // now check to see if we really need to create a new viewport.
3714 if (multipleView && viewportsAdded.size() == 0)
3716 // We recovered an alignment for which a viewport already exists.
3717 // TODO: fix up any settings necessary for overlaying stored state onto
3718 // state recovered from another document. (may not be necessary).
3719 // we may need a binding from a viewport in memory to one recovered from
3721 // and then recover its containing af to allow the settings to be applied.
3722 // TODO: fix for vamsas demo
3724 "About to recover a viewport for existing alignment: Sequence set ID is "
3726 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3727 if (seqsetobj != null)
3729 if (seqsetobj instanceof String)
3731 uniqueSeqSetId = (String) seqsetobj;
3733 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3739 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3745 * indicate that annotation colours are applied across all groups (pre
3746 * Jalview 2.8.1 behaviour)
3748 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3749 jalviewModel.getVersion());
3751 AlignmentPanel ap = null;
3752 boolean isnewview = true;
3755 // Check to see if this alignment already has a view id == viewId
3756 jalview.gui.AlignmentPanel views[] = Desktop
3757 .getAlignmentPanels(uniqueSeqSetId);
3758 if (views != null && views.length > 0)
3760 for (int v = 0; v < views.length; v++)
3762 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3764 // recover the existing alignpanel, alignframe, viewport
3765 af = views[v].alignFrame;
3768 // TODO: could even skip resetting view settings if we don't want to
3769 // change the local settings from other jalview processes
3778 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
3779 uniqueSeqSetId, viewId, autoAlan);
3780 av = af.getViewport();
3785 * Load any trees, PDB structures and viewers
3787 * Not done if flag is false (when this method is used for New View)
3789 if (loadTreesAndStructures)
3791 loadTrees(jalviewModel, view, af, av, ap);
3792 loadPDBStructures(jprovider, jseqs, af, ap);
3793 loadRnaViewers(jprovider, jseqs, ap);
3795 // and finally return.
3800 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3801 * panel is restored from separate jar entries, two (gapped and trimmed) per
3802 * sequence and secondary structure.
3804 * Currently each viewer shows just one sequence and structure (gapped and
3805 * trimmed), however this method is designed to support multiple sequences or
3806 * structures in viewers if wanted in future.
3812 private void loadRnaViewers(jarInputStreamProvider jprovider,
3813 List<JSeq> jseqs, AlignmentPanel ap)
3816 * scan the sequences for references to viewers; create each one the first
3817 * time it is referenced, add Rna models to existing viewers
3819 for (JSeq jseq : jseqs)
3821 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
3823 RnaViewer viewer = jseq.getRnaViewer().get(i);
3824 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3827 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
3829 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
3830 SequenceI seq = seqRefIds.get(jseq.getId());
3831 AlignmentAnnotation ann = this.annotationIds
3832 .get(ss.getAnnotationId());
3835 * add the structure to the Varna display (with session state copied
3836 * from the jar to a temporary file)
3838 boolean gapped = safeBoolean(ss.isGapped());
3839 String rnaTitle = ss.getTitle();
3840 String sessionState = ss.getViewerState();
3841 String tempStateFile = copyJarEntry(jprovider, sessionState,
3843 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3844 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3846 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
3852 * Locate and return an already instantiated matching AppVarna, or create one
3856 * @param viewIdSuffix
3860 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3861 String viewIdSuffix, AlignmentPanel ap)
3864 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3865 * if load is repeated
3867 String postLoadId = viewer.getViewId() + viewIdSuffix;
3868 for (JInternalFrame frame : getAllFrames())
3870 if (frame instanceof AppVarna)
3872 AppVarna varna = (AppVarna) frame;
3873 if (postLoadId.equals(varna.getViewId()))
3875 // this viewer is already instantiated
3876 // could in future here add ap as another 'parent' of the
3877 // AppVarna window; currently just 1-to-many
3884 * viewer not found - make it
3886 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3887 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
3888 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
3889 safeInt(viewer.getDividerLocation()));
3890 AppVarna varna = new AppVarna(model, ap);
3896 * Load any saved trees
3904 protected void loadTrees(JalviewModel jm, Viewport view,
3905 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3907 // TODO result of automated refactoring - are all these parameters needed?
3910 for (int t = 0; t < jm.getTree().size(); t++)
3913 Tree tree = jm.getTree().get(t);
3915 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3918 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
3919 tree.getTitle(), safeInt(tree.getWidth()),
3920 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
3921 safeInt(tree.getYpos()));
3922 if (tree.getId() != null)
3924 // perhaps bind the tree id to something ?
3929 // update local tree attributes ?
3930 // TODO: should check if tp has been manipulated by user - if so its
3931 // settings shouldn't be modified
3932 tp.setTitle(tree.getTitle());
3933 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
3934 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
3935 safeInt(tree.getHeight())));
3936 tp.setViewport(av); // af.viewport;
3937 // TODO: verify 'associate with all views' works still
3938 tp.getTreeCanvas().setViewport(av); // af.viewport;
3939 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
3944 warn("There was a problem recovering stored Newick tree: \n"
3945 + tree.getNewick());
3949 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
3950 tp.fitToWindow_actionPerformed(null);
3952 if (tree.getFontName() != null)
3955 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
3956 safeInt(tree.getFontSize())));
3961 new Font(view.getFontName(), safeInt(view.getFontStyle()),
3962 safeInt(view.getFontSize())));
3965 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
3966 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
3967 tp.showDistances(safeBoolean(tree.isShowDistances()));
3969 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
3971 if (safeBoolean(tree.isCurrentTree()))
3973 af.getViewport().setCurrentTree(tp.getTree());
3977 } catch (Exception ex)
3979 ex.printStackTrace();
3984 * Load and link any saved structure viewers.
3991 protected void loadPDBStructures(jarInputStreamProvider jprovider,
3992 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
3995 * Run through all PDB ids on the alignment, and collect mappings between
3996 * distinct view ids and all sequences referring to that view.
3998 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4000 for (int i = 0; i < jseqs.size(); i++)
4002 JSeq jseq = jseqs.get(i);
4003 if (jseq.getPdbids().size() > 0)
4005 List<Pdbids> ids = jseq.getPdbids();
4006 for (int p = 0; p < ids.size(); p++)
4008 Pdbids pdbid = ids.get(p);
4009 final int structureStateCount = pdbid.getStructureState().size();
4010 for (int s = 0; s < structureStateCount; s++)
4012 // check to see if we haven't already created this structure view
4013 final StructureState structureState = pdbid
4014 .getStructureState().get(s);
4015 String sviewid = (structureState.getViewId() == null) ? null
4016 : structureState.getViewId() + uniqueSetSuffix;
4017 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4018 // Originally : pdbid.getFile()
4019 // : TODO: verify external PDB file recovery still works in normal
4020 // jalview project load
4022 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4023 jpdb.setId(pdbid.getId());
4025 int x = safeInt(structureState.getXpos());
4026 int y = safeInt(structureState.getYpos());
4027 int width = safeInt(structureState.getWidth());
4028 int height = safeInt(structureState.getHeight());
4030 // Probably don't need to do this anymore...
4031 // Desktop.desktop.getComponentAt(x, y);
4032 // TODO: NOW: check that this recovers the PDB file correctly.
4033 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4035 jalview.datamodel.SequenceI seq = seqRefIds
4036 .get(jseq.getId() + "");
4037 if (sviewid == null)
4039 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4042 if (!structureViewers.containsKey(sviewid))
4044 structureViewers.put(sviewid,
4045 new StructureViewerModel(x, y, width, height, false,
4046 false, true, structureState.getViewId(),
4047 structureState.getType()));
4048 // Legacy pre-2.7 conversion JAL-823 :
4049 // do not assume any view has to be linked for colour by
4053 // assemble String[] { pdb files }, String[] { id for each
4054 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4055 // seqs_file 2}, boolean[] {
4056 // linkAlignPanel,superposeWithAlignpanel}} from hash
4057 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4058 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4059 || structureState.isAlignwithAlignPanel());
4062 * Default colour by linked panel to false if not specified (e.g.
4063 * for pre-2.7 projects)
4065 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4066 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4067 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4070 * Default colour by viewer to true if not specified (e.g. for
4073 boolean colourByViewer = jmoldat.isColourByViewer();
4074 colourByViewer &= structureState.isColourByJmol();
4075 jmoldat.setColourByViewer(colourByViewer);
4077 if (jmoldat.getStateData().length() < structureState
4078 .getValue()/*Content()*/.length())
4080 jmoldat.setStateData(structureState.getValue());// Content());
4082 if (pdbid.getFile() != null)
4084 File mapkey = new File(pdbid.getFile());
4085 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4086 if (seqstrmaps == null)
4088 jmoldat.getFileData().put(mapkey,
4089 seqstrmaps = jmoldat.new StructureData(pdbFile,
4092 if (!seqstrmaps.getSeqList().contains(seq))
4094 seqstrmaps.getSeqList().add(seq);
4100 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");
4107 // Instantiate the associated structure views
4108 for (Entry<String, StructureViewerModel> entry : structureViewers
4113 createOrLinkStructureViewer(entry, af, ap, jprovider);
4114 } catch (Exception e)
4117 "Error loading structure viewer: " + e.getMessage());
4118 // failed - try the next one
4130 protected void createOrLinkStructureViewer(
4131 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4132 AlignmentPanel ap, jarInputStreamProvider jprovider)
4134 final StructureViewerModel stateData = viewerData.getValue();
4137 * Search for any viewer windows already open from other alignment views
4138 * that exactly match the stored structure state
4140 StructureViewerBase comp = findMatchingViewer(viewerData);
4144 linkStructureViewer(ap, comp, stateData);
4149 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4150 * "viewer_"+stateData.viewId
4152 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4154 createChimeraViewer(viewerData, af, jprovider);
4159 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4161 createJmolViewer(viewerData, af, jprovider);
4166 * Create a new Chimera viewer.
4172 protected void createChimeraViewer(
4173 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4174 jarInputStreamProvider jprovider)
4176 StructureViewerModel data = viewerData.getValue();
4177 String chimeraSessionFile = data.getStateData();
4180 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4182 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4183 * 'uniquified' sviewid used to reconstruct the viewer here
4185 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4186 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4189 Set<Entry<File, StructureData>> fileData = data.getFileData()
4191 List<PDBEntry> pdbs = new ArrayList<>();
4192 List<SequenceI[]> allseqs = new ArrayList<>();
4193 for (Entry<File, StructureData> pdb : fileData)
4195 String filePath = pdb.getValue().getFilePath();
4196 String pdbId = pdb.getValue().getPdbId();
4197 // pdbs.add(new PDBEntry(filePath, pdbId));
4198 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4199 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4200 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4204 boolean colourByChimera = data.isColourByViewer();
4205 boolean colourBySequence = data.isColourWithAlignPanel();
4207 // TODO use StructureViewer as a factory here, see JAL-1761
4208 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4209 final SequenceI[][] seqsArray = allseqs
4210 .toArray(new SequenceI[allseqs.size()][]);
4211 String newViewId = viewerData.getKey();
4213 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4214 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4215 colourBySequence, newViewId);
4216 cvf.setSize(data.getWidth(), data.getHeight());
4217 cvf.setLocation(data.getX(), data.getY());
4221 * Create a new Jmol window. First parse the Jmol state to translate filenames
4222 * loaded into the view, and record the order in which files are shown in the
4223 * Jmol view, so we can add the sequence mappings in same order.
4229 protected void createJmolViewer(
4230 final Entry<String, StructureViewerModel> viewerData,
4231 AlignFrame af, jarInputStreamProvider jprovider)
4233 final StructureViewerModel svattrib = viewerData.getValue();
4234 String state = svattrib.getStateData();
4237 * Pre-2.9: state element value is the Jmol state string
4239 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4242 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4244 state = readJarEntry(jprovider,
4245 getViewerJarEntryName(svattrib.getViewId()));
4248 List<String> pdbfilenames = new ArrayList<>();
4249 List<SequenceI[]> seqmaps = new ArrayList<>();
4250 List<String> pdbids = new ArrayList<>();
4251 StringBuilder newFileLoc = new StringBuilder(64);
4252 int cp = 0, ncp, ecp;
4253 Map<File, StructureData> oldFiles = svattrib.getFileData();
4254 while ((ncp = state.indexOf("load ", cp)) > -1)
4258 // look for next filename in load statement
4259 newFileLoc.append(state.substring(cp,
4260 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4261 String oldfilenam = state.substring(ncp,
4262 ecp = state.indexOf("\"", ncp));
4263 // recover the new mapping data for this old filename
4264 // have to normalize filename - since Jmol and jalview do
4266 // translation differently.
4267 StructureData filedat = oldFiles.get(new File(oldfilenam));
4268 if (filedat == null)
4270 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4271 filedat = oldFiles.get(new File(reformatedOldFilename));
4273 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4274 pdbfilenames.add(filedat.getFilePath());
4275 pdbids.add(filedat.getPdbId());
4276 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4277 newFileLoc.append("\"");
4278 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4279 // look for next file statement.
4280 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4284 // just append rest of state
4285 newFileLoc.append(state.substring(cp));
4289 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4290 newFileLoc = new StringBuilder(state);
4291 newFileLoc.append("; load append ");
4292 for (File id : oldFiles.keySet())
4294 // add this and any other pdb files that should be present in
4296 StructureData filedat = oldFiles.get(id);
4297 newFileLoc.append(filedat.getFilePath());
4298 pdbfilenames.add(filedat.getFilePath());
4299 pdbids.add(filedat.getPdbId());
4300 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4301 newFileLoc.append(" \"");
4302 newFileLoc.append(filedat.getFilePath());
4303 newFileLoc.append("\"");
4306 newFileLoc.append(";");
4309 if (newFileLoc.length() == 0)
4313 int histbug = newFileLoc.indexOf("history = ");
4317 * change "history = [true|false];" to "history = [1|0];"
4320 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4321 String val = (diff == -1) ? null
4322 : newFileLoc.substring(histbug, diff);
4323 if (val != null && val.length() >= 4)
4325 if (val.contains("e")) // eh? what can it be?
4327 if (val.trim().equals("true"))
4335 newFileLoc.replace(histbug, diff, val);
4340 final String[] pdbf = pdbfilenames
4341 .toArray(new String[pdbfilenames.size()]);
4342 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4343 final SequenceI[][] sq = seqmaps
4344 .toArray(new SequenceI[seqmaps.size()][]);
4345 final String fileloc = newFileLoc.toString();
4346 final String sviewid = viewerData.getKey();
4347 final AlignFrame alf = af;
4348 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4349 svattrib.getWidth(), svattrib.getHeight());
4352 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4357 JalviewStructureDisplayI sview = null;
4360 sview = new StructureViewer(
4361 alf.alignPanel.getStructureSelectionManager())
4362 .createView(StructureViewer.ViewerType.JMOL,
4363 pdbf, id, sq, alf.alignPanel, svattrib,
4364 fileloc, rect, sviewid);
4365 addNewStructureViewer(sview);
4366 } catch (OutOfMemoryError ex)
4368 new OOMWarning("restoring structure view for PDB id " + id,
4369 (OutOfMemoryError) ex.getCause());
4370 if (sview != null && sview.isVisible())
4372 sview.closeViewer(false);
4373 sview.setVisible(false);
4379 } catch (InvocationTargetException ex)
4381 warn("Unexpected error when opening Jmol view.", ex);
4383 } catch (InterruptedException e)
4385 // e.printStackTrace();
4391 * Generates a name for the entry in the project jar file to hold state
4392 * information for a structure viewer
4397 protected String getViewerJarEntryName(String viewId)
4399 return VIEWER_PREFIX + viewId;
4403 * Returns any open frame that matches given structure viewer data. The match
4404 * is based on the unique viewId, or (for older project versions) the frame's
4410 protected StructureViewerBase findMatchingViewer(
4411 Entry<String, StructureViewerModel> viewerData)
4413 final String sviewid = viewerData.getKey();
4414 final StructureViewerModel svattrib = viewerData.getValue();
4415 StructureViewerBase comp = null;
4416 JInternalFrame[] frames = getAllFrames();
4417 for (JInternalFrame frame : frames)
4419 if (frame instanceof StructureViewerBase)
4422 * Post jalview 2.4 schema includes structure view id
4424 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4427 comp = (StructureViewerBase) frame;
4428 break; // break added in 2.9
4431 * Otherwise test for matching position and size of viewer frame
4433 else if (frame.getX() == svattrib.getX()
4434 && frame.getY() == svattrib.getY()
4435 && frame.getHeight() == svattrib.getHeight()
4436 && frame.getWidth() == svattrib.getWidth())
4438 comp = (StructureViewerBase) frame;
4439 // no break in faint hope of an exact match on viewId
4447 * Link an AlignmentPanel to an existing structure viewer.
4452 * @param useinViewerSuperpos
4453 * @param usetoColourbyseq
4454 * @param viewerColouring
4456 protected void linkStructureViewer(AlignmentPanel ap,
4457 StructureViewerBase viewer, StructureViewerModel stateData)
4459 // NOTE: if the jalview project is part of a shared session then
4460 // view synchronization should/could be done here.
4462 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4463 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4464 final boolean viewerColouring = stateData.isColourByViewer();
4465 Map<File, StructureData> oldFiles = stateData.getFileData();
4468 * Add mapping for sequences in this view to an already open viewer
4470 final AAStructureBindingModel binding = viewer.getBinding();
4471 for (File id : oldFiles.keySet())
4473 // add this and any other pdb files that should be present in the
4475 StructureData filedat = oldFiles.get(id);
4476 String pdbFile = filedat.getFilePath();
4477 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4478 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4480 binding.addSequenceForStructFile(pdbFile, seq);
4482 // and add the AlignmentPanel's reference to the view panel
4483 viewer.addAlignmentPanel(ap);
4484 if (useinViewerSuperpos)
4486 viewer.useAlignmentPanelForSuperposition(ap);
4490 viewer.excludeAlignmentPanelForSuperposition(ap);
4492 if (usetoColourbyseq)
4494 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4498 viewer.excludeAlignmentPanelForColourbyseq(ap);
4503 * Get all frames within the Desktop.
4507 protected JInternalFrame[] getAllFrames()
4509 JInternalFrame[] frames = null;
4510 // TODO is this necessary - is it safe - risk of hanging?
4515 frames = Desktop.desktop.getAllFrames();
4516 } catch (ArrayIndexOutOfBoundsException e)
4518 // occasional No such child exceptions are thrown here...
4522 } catch (InterruptedException f)
4526 } while (frames == null);
4531 * Answers true if 'version' is equal to or later than 'supported', where each
4532 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4533 * changes. Development and test values for 'version' are leniently treated
4537 * - minimum version we are comparing against
4539 * - version of data being processsed
4542 public static boolean isVersionStringLaterThan(String supported,
4545 if (supported == null || version == null
4546 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4547 || version.equalsIgnoreCase("Test")
4548 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4550 System.err.println("Assuming project file with "
4551 + (version == null ? "null" : version)
4552 + " is compatible with Jalview version " + supported);
4557 return StringUtils.compareVersions(version, supported, "b") >= 0;
4561 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4563 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4565 if (newStructureViewers != null)
4567 sview.getBinding().setFinishedLoadingFromArchive(false);
4568 newStructureViewers.add(sview);
4572 protected void setLoadingFinishedForNewStructureViewers()
4574 if (newStructureViewers != null)
4576 for (JalviewStructureDisplayI sview : newStructureViewers)
4578 sview.getBinding().setFinishedLoadingFromArchive(true);
4580 newStructureViewers.clear();
4581 newStructureViewers = null;
4585 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4586 List<SequenceI> hiddenSeqs, AlignmentI al,
4587 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4588 String viewId, List<JvAnnotRow> autoAlan)
4590 AlignFrame af = null;
4591 af = new AlignFrame(al, safeInt(view.getWidth()),
4592 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4596 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4597 // System.out.println("Jalview2XML AF " + e);
4598 // super.processKeyEvent(e);
4605 af.setFileName(file, FileFormat.Jalview);
4607 final AlignViewport viewport = af.getViewport();
4608 for (int i = 0; i < JSEQ.size(); i++)
4610 int colour = safeInt(JSEQ.get(i).getColour());
4611 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4617 viewport.setColourByReferenceSeq(true);
4618 viewport.setDisplayReferenceSeq(true);
4621 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4623 if (view.getSequenceSetId() != null)
4625 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4627 viewport.setSequenceSetId(uniqueSeqSetId);
4630 // propagate shared settings to this new view
4631 viewport.setHistoryList(av.getHistoryList());
4632 viewport.setRedoList(av.getRedoList());
4636 viewportsAdded.put(uniqueSeqSetId, viewport);
4638 // TODO: check if this method can be called repeatedly without
4639 // side-effects if alignpanel already registered.
4640 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4642 // apply Hidden regions to view.
4643 if (hiddenSeqs != null)
4645 for (int s = 0; s < JSEQ.size(); s++)
4647 SequenceGroup hidden = new SequenceGroup();
4648 boolean isRepresentative = false;
4649 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4651 isRepresentative = true;
4652 SequenceI sequenceToHide = al
4653 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4654 hidden.addSequence(sequenceToHide, false);
4655 // remove from hiddenSeqs list so we don't try to hide it twice
4656 hiddenSeqs.remove(sequenceToHide);
4658 if (isRepresentative)
4660 SequenceI representativeSequence = al.getSequenceAt(s);
4661 hidden.addSequence(representativeSequence, false);
4662 viewport.hideRepSequences(representativeSequence, hidden);
4666 SequenceI[] hseqs = hiddenSeqs
4667 .toArray(new SequenceI[hiddenSeqs.size()]);
4668 viewport.hideSequence(hseqs);
4671 // recover view properties and display parameters
4673 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4674 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4675 final int pidThreshold = safeInt(view.getPidThreshold());
4676 viewport.setThreshold(pidThreshold);
4678 viewport.setColourText(safeBoolean(view.isShowColourText()));
4681 .setConservationSelected(
4682 safeBoolean(view.isConservationSelected()));
4683 viewport.setIncrement(safeInt(view.getConsThreshold()));
4684 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4685 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4686 viewport.setFont(new Font(view.getFontName(),
4687 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4689 ViewStyleI vs = viewport.getViewStyle();
4690 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4691 viewport.setViewStyle(vs);
4692 // TODO: allow custom charWidth/Heights to be restored by updating them
4693 // after setting font - which means set above to false
4694 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4695 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4696 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4698 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4700 viewport.setShowText(safeBoolean(view.isShowText()));
4702 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4703 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4704 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4705 viewport.setShowUnconserved(view.isShowUnconserved());
4706 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4708 if (view.getViewName() != null)
4710 viewport.setViewName(view.getViewName());
4711 af.setInitialTabVisible();
4713 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4714 safeInt(view.getWidth()), safeInt(view.getHeight()));
4715 // startSeq set in af.alignPanel.updateLayout below
4716 af.alignPanel.updateLayout();
4717 ColourSchemeI cs = null;
4718 // apply colourschemes
4719 if (view.getBgColour() != null)
4721 if (view.getBgColour().startsWith("ucs"))
4723 cs = getUserColourScheme(jm, view.getBgColour());
4725 else if (view.getBgColour().startsWith("Annotation"))
4727 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4728 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4735 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4739 viewport.setGlobalColourScheme(cs);
4740 viewport.getResidueShading().setThreshold(pidThreshold,
4741 view.isIgnoreGapsinConsensus());
4742 viewport.getResidueShading()
4743 .setConsensus(viewport.getSequenceConsensusHash());
4744 viewport.setColourAppliesToAllGroups(false);
4746 if (safeBoolean(view.isConservationSelected()) && cs != null)
4748 viewport.getResidueShading()
4749 .setConservationInc(safeInt(view.getConsThreshold()));
4752 af.changeColour(cs);
4754 viewport.setColourAppliesToAllGroups(true);
4757 .setShowSequenceFeatures(
4758 safeBoolean(view.isShowSequenceFeatures()));
4760 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4761 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4762 viewport.setFollowHighlight(view.isFollowHighlight());
4763 viewport.followSelection = view.isFollowSelection();
4764 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4765 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4766 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4767 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4768 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4769 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4770 viewport.setShowGroupConservation(view.isShowGroupConservation());
4772 // recover feature settings
4773 if (jm.getFeatureSettings() != null)
4775 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4776 .getFeatureRenderer();
4777 FeaturesDisplayed fdi;
4778 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4779 String[] renderOrder = new String[jm.getFeatureSettings()
4780 .getSetting().size()];
4781 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4782 Map<String, Float> featureOrder = new Hashtable<>();
4784 for (int fs = 0; fs < jm.getFeatureSettings()
4785 .getSetting().size(); fs++)
4787 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4788 String featureType = setting.getType();
4791 * restore feature filters (if any)
4793 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4795 if (filters != null)
4797 FeatureMatcherSetI filter = Jalview2XML
4798 .parseFilter(featureType, filters);
4799 if (!filter.isEmpty())
4801 fr.setFeatureFilter(featureType, filter);
4806 * restore feature colour scheme
4808 Color maxColour = new Color(setting.getColour());
4809 if (setting.getMincolour() != null)
4812 * minColour is always set unless a simple colour
4813 * (including for colour by label though it doesn't use it)
4815 Color minColour = new Color(setting.getMincolour().intValue());
4816 Color noValueColour = minColour;
4817 NoValueColour noColour = setting.getNoValueColour();
4818 if (noColour == NoValueColour.NONE)
4820 noValueColour = null;
4822 else if (noColour == NoValueColour.MAX)
4824 noValueColour = maxColour;
4826 float min = safeFloat(safeFloat(setting.getMin()));
4827 float max = setting.getMax() == null ? 1f
4828 : setting.getMax().floatValue();
4829 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4830 noValueColour, min, max);
4831 if (setting.getAttributeName().size() > 0)
4833 gc.setAttributeName(setting.getAttributeName().toArray(
4834 new String[setting.getAttributeName().size()]));
4836 if (setting.getThreshold() != null)
4838 gc.setThreshold(setting.getThreshold().floatValue());
4839 int threshstate = safeInt(setting.getThreshstate());
4840 // -1 = None, 0 = Below, 1 = Above threshold
4841 if (threshstate == 0)
4843 gc.setBelowThreshold(true);
4845 else if (threshstate == 1)
4847 gc.setAboveThreshold(true);
4850 gc.setAutoScaled(true); // default
4851 if (setting.isAutoScale() != null)
4853 gc.setAutoScaled(setting.isAutoScale());
4855 if (setting.isColourByLabel() != null)
4857 gc.setColourByLabel(setting.isColourByLabel());
4859 // and put in the feature colour table.
4860 featureColours.put(featureType, gc);
4864 featureColours.put(featureType,
4865 new FeatureColour(maxColour));
4867 renderOrder[fs] = featureType;
4868 if (setting.getOrder() != null)
4870 featureOrder.put(featureType, setting.getOrder().floatValue());
4874 featureOrder.put(featureType, new Float(
4875 fs / jm.getFeatureSettings().getSetting().size()));
4877 if (safeBoolean(setting.isDisplay()))
4879 fdi.setVisible(featureType);
4882 Map<String, Boolean> fgtable = new Hashtable<>();
4883 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4885 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4886 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
4888 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4889 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4890 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4891 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4892 fgtable, featureColours, 1.0f, featureOrder);
4893 fr.transferSettings(frs);
4896 if (view.getHiddenColumns().size() > 0)
4898 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4900 final HiddenColumns hc = view.getHiddenColumns().get(c);
4901 viewport.hideColumns(safeInt(hc.getStart()),
4902 safeInt(hc.getEnd()) /* +1 */);
4905 if (view.getCalcIdParam() != null)
4907 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4909 if (calcIdParam != null)
4911 if (recoverCalcIdParam(calcIdParam, viewport))
4916 warn("Couldn't recover parameters for "
4917 + calcIdParam.getCalcId());
4922 af.setMenusFromViewport(viewport);
4923 af.setTitle(view.getTitle());
4924 // TODO: we don't need to do this if the viewport is aready visible.
4926 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4927 * has a 'cdna/protein complement' view, in which case save it in order to
4928 * populate a SplitFrame once all views have been read in.
4930 String complementaryViewId = view.getComplementId();
4931 if (complementaryViewId == null)
4933 Desktop.addInternalFrame(af, view.getTitle(),
4934 safeInt(view.getWidth()), safeInt(view.getHeight()));
4935 // recompute any autoannotation
4936 af.alignPanel.updateAnnotation(false, true);
4937 reorderAutoannotation(af, al, autoAlan);
4938 af.alignPanel.alignmentChanged();
4942 splitFrameCandidates.put(view, af);
4948 * Reads saved data to restore Colour by Annotation settings
4950 * @param viewAnnColour
4954 * @param checkGroupAnnColour
4957 private ColourSchemeI constructAnnotationColour(
4958 AnnotationColourScheme viewAnnColour, AlignFrame af,
4959 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
4961 boolean propagateAnnColour = false;
4962 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
4964 if (checkGroupAnnColour && al.getGroups() != null
4965 && al.getGroups().size() > 0)
4967 // pre 2.8.1 behaviour
4968 // check to see if we should transfer annotation colours
4969 propagateAnnColour = true;
4970 for (SequenceGroup sg : al.getGroups())
4972 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4974 propagateAnnColour = false;
4980 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4982 String annotationId = viewAnnColour.getAnnotation();
4983 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4986 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4988 if (matchedAnnotation == null
4989 && annAlignment.getAlignmentAnnotation() != null)
4991 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4994 .equals(annAlignment.getAlignmentAnnotation()[i].label))
4996 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5001 if (matchedAnnotation == null)
5003 System.err.println("Failed to match annotation colour scheme for "
5007 if (matchedAnnotation.getThreshold() == null)
5009 matchedAnnotation.setThreshold(
5010 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5011 "Threshold", Color.black));
5014 AnnotationColourGradient cs = null;
5015 if (viewAnnColour.getColourScheme().equals("None"))
5017 cs = new AnnotationColourGradient(matchedAnnotation,
5018 new Color(safeInt(viewAnnColour.getMinColour())),
5019 new Color(safeInt(viewAnnColour.getMaxColour())),
5020 safeInt(viewAnnColour.getAboveThreshold()));
5022 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5024 cs = new AnnotationColourGradient(matchedAnnotation,
5025 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5026 safeInt(viewAnnColour.getAboveThreshold()));
5030 cs = new AnnotationColourGradient(matchedAnnotation,
5031 ColourSchemeProperty.getColourScheme(al,
5032 viewAnnColour.getColourScheme()),
5033 safeInt(viewAnnColour.getAboveThreshold()));
5036 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5037 boolean useOriginalColours = safeBoolean(
5038 viewAnnColour.isPredefinedColours());
5039 cs.setSeqAssociated(perSequenceOnly);
5040 cs.setPredefinedColours(useOriginalColours);
5042 if (propagateAnnColour && al.getGroups() != null)
5044 // Also use these settings for all the groups
5045 for (int g = 0; g < al.getGroups().size(); g++)
5047 SequenceGroup sg = al.getGroups().get(g);
5048 if (sg.getGroupColourScheme() == null)
5053 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5054 matchedAnnotation, sg.getColourScheme(),
5055 safeInt(viewAnnColour.getAboveThreshold()));
5056 sg.setColourScheme(groupScheme);
5057 groupScheme.setSeqAssociated(perSequenceOnly);
5058 groupScheme.setPredefinedColours(useOriginalColours);
5064 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5065 List<JvAnnotRow> autoAlan)
5067 // copy over visualization settings for autocalculated annotation in the
5069 if (al.getAlignmentAnnotation() != null)
5072 * Kludge for magic autoannotation names (see JAL-811)
5074 String[] magicNames = new String[] { "Consensus", "Quality",
5076 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5077 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5078 for (String nm : magicNames)
5080 visan.put(nm, nullAnnot);
5082 for (JvAnnotRow auan : autoAlan)
5084 visan.put(auan.template.label
5085 + (auan.template.getCalcId() == null ? ""
5086 : "\t" + auan.template.getCalcId()),
5089 int hSize = al.getAlignmentAnnotation().length;
5090 List<JvAnnotRow> reorder = new ArrayList<>();
5091 // work through any autoCalculated annotation already on the view
5092 // removing it if it should be placed in a different location on the
5093 // annotation panel.
5094 List<String> remains = new ArrayList<>(visan.keySet());
5095 for (int h = 0; h < hSize; h++)
5097 jalview.datamodel.AlignmentAnnotation jalan = al
5098 .getAlignmentAnnotation()[h];
5099 if (jalan.autoCalculated)
5102 JvAnnotRow valan = visan.get(k = jalan.label);
5103 if (jalan.getCalcId() != null)
5105 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5110 // delete the auto calculated row from the alignment
5111 al.deleteAnnotation(jalan, false);
5115 if (valan != nullAnnot)
5117 if (jalan != valan.template)
5119 // newly created autoannotation row instance
5120 // so keep a reference to the visible annotation row
5121 // and copy over all relevant attributes
5122 if (valan.template.graphHeight >= 0)
5125 jalan.graphHeight = valan.template.graphHeight;
5127 jalan.visible = valan.template.visible;
5129 reorder.add(new JvAnnotRow(valan.order, jalan));
5134 // Add any (possibly stale) autocalculated rows that were not appended to
5135 // the view during construction
5136 for (String other : remains)
5138 JvAnnotRow othera = visan.get(other);
5139 if (othera != nullAnnot && othera.template.getCalcId() != null
5140 && othera.template.getCalcId().length() > 0)
5142 reorder.add(othera);
5145 // now put the automatic annotation in its correct place
5146 int s = 0, srt[] = new int[reorder.size()];
5147 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5148 for (JvAnnotRow jvar : reorder)
5151 srt[s++] = jvar.order;
5154 jalview.util.QuickSort.sort(srt, rws);
5155 // and re-insert the annotation at its correct position
5156 for (JvAnnotRow jvar : rws)
5158 al.addAnnotation(jvar.template, jvar.order);
5160 af.alignPanel.adjustAnnotationHeight();
5164 Hashtable skipList = null;
5167 * TODO remove this method
5170 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5171 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5172 * throw new Error("Implementation Error. No skipList defined for this
5173 * Jalview2XML instance."); } return (AlignFrame)
5174 * skipList.get(view.getSequenceSetId()); }
5178 * Check if the Jalview view contained in object should be skipped or not.
5181 * @return true if view's sequenceSetId is a key in skipList
5183 private boolean skipViewport(JalviewModel object)
5185 if (skipList == null)
5189 String id = object.getViewport().get(0).getSequenceSetId();
5190 if (skipList.containsKey(id))
5192 if (Cache.log != null && Cache.log.isDebugEnabled())
5194 Cache.log.debug("Skipping seuqence set id " + id);
5201 public void addToSkipList(AlignFrame af)
5203 if (skipList == null)
5205 skipList = new Hashtable();
5207 skipList.put(af.getViewport().getSequenceSetId(), af);
5210 public void clearSkipList()
5212 if (skipList != null)
5219 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5220 boolean ignoreUnrefed)
5222 jalview.datamodel.AlignmentI ds = getDatasetFor(
5223 vamsasSet.getDatasetId());
5224 Vector dseqs = null;
5227 // create a list of new dataset sequences
5228 dseqs = new Vector();
5230 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5232 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5233 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5235 // create a new dataset
5238 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5239 dseqs.copyInto(dsseqs);
5240 ds = new jalview.datamodel.Alignment(dsseqs);
5241 debug("Created new dataset " + vamsasSet.getDatasetId()
5242 + " for alignment " + System.identityHashCode(al));
5243 addDatasetRef(vamsasSet.getDatasetId(), ds);
5245 // set the dataset for the newly imported alignment.
5246 if (al.getDataset() == null && !ignoreUnrefed)
5255 * sequence definition to create/merge dataset sequence for
5259 * vector to add new dataset sequence to
5260 * @param ignoreUnrefed
5261 * - when true, don't create new sequences from vamsasSeq if it's id
5262 * doesn't already have an asssociated Jalview sequence.
5264 * - used to reorder the sequence in the alignment according to the
5265 * vamsasSeq array ordering, to preserve ordering of dataset
5267 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5268 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5270 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5272 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5273 boolean reorder = false;
5274 SequenceI dsq = null;
5275 if (sq != null && sq.getDatasetSequence() != null)
5277 dsq = sq.getDatasetSequence();
5283 if (sq == null && ignoreUnrefed)
5287 String sqid = vamsasSeq.getDsseqid();
5290 // need to create or add a new dataset sequence reference to this sequence
5293 dsq = seqRefIds.get(sqid);
5298 // make a new dataset sequence
5299 dsq = sq.createDatasetSequence();
5302 // make up a new dataset reference for this sequence
5303 sqid = seqHash(dsq);
5305 dsq.setVamsasId(uniqueSetSuffix + sqid);
5306 seqRefIds.put(sqid, dsq);
5311 dseqs.addElement(dsq);
5316 ds.addSequence(dsq);
5322 { // make this dataset sequence sq's dataset sequence
5323 sq.setDatasetSequence(dsq);
5324 // and update the current dataset alignment
5329 if (!dseqs.contains(dsq))
5336 if (ds.findIndex(dsq) < 0)
5338 ds.addSequence(dsq);
5345 // TODO: refactor this as a merge dataset sequence function
5346 // now check that sq (the dataset sequence) sequence really is the union of
5347 // all references to it
5348 // boolean pre = sq.getStart() < dsq.getStart();
5349 // boolean post = sq.getEnd() > dsq.getEnd();
5353 // StringBuffer sb = new StringBuffer();
5354 String newres = jalview.analysis.AlignSeq.extractGaps(
5355 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5356 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5357 && newres.length() > dsq.getLength())
5359 // Update with the longer sequence.
5363 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5364 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5365 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5366 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5368 dsq.setSequence(newres);
5370 // TODO: merges will never happen if we 'know' we have the real dataset
5371 // sequence - this should be detected when id==dssid
5373 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5374 // + (pre ? "prepended" : "") + " "
5375 // + (post ? "appended" : ""));
5380 // sequence refs are identical. We may need to update the existing dataset
5381 // alignment with this one, though.
5382 if (ds != null && dseqs == null)
5384 int opos = ds.findIndex(dsq);
5385 SequenceI tseq = null;
5386 if (opos != -1 && vseqpos != opos)
5388 // remove from old position
5389 ds.deleteSequence(dsq);
5391 if (vseqpos < ds.getHeight())
5393 if (vseqpos != opos)
5395 // save sequence at destination position
5396 tseq = ds.getSequenceAt(vseqpos);
5397 ds.replaceSequenceAt(vseqpos, dsq);
5398 ds.addSequence(tseq);
5403 ds.addSequence(dsq);
5410 * TODO use AlignmentI here and in related methods - needs
5411 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5413 Hashtable<String, AlignmentI> datasetIds = null;
5415 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5417 private AlignmentI getDatasetFor(String datasetId)
5419 if (datasetIds == null)
5421 datasetIds = new Hashtable<>();
5424 if (datasetIds.containsKey(datasetId))
5426 return datasetIds.get(datasetId);
5431 private void addDatasetRef(String datasetId, AlignmentI dataset)
5433 if (datasetIds == null)
5435 datasetIds = new Hashtable<>();
5437 datasetIds.put(datasetId, dataset);
5441 * make a new dataset ID for this jalview dataset alignment
5446 private String getDatasetIdRef(AlignmentI dataset)
5448 if (dataset.getDataset() != null)
5450 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5452 String datasetId = makeHashCode(dataset, null);
5453 if (datasetId == null)
5455 // make a new datasetId and record it
5456 if (dataset2Ids == null)
5458 dataset2Ids = new IdentityHashMap<>();
5462 datasetId = dataset2Ids.get(dataset);
5464 if (datasetId == null)
5466 datasetId = "ds" + dataset2Ids.size() + 1;
5467 dataset2Ids.put(dataset, datasetId);
5473 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5475 for (int d = 0; d < sequence.getDBRef().size(); d++)
5477 DBRef dr = sequence.getDBRef().get(d);
5478 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5479 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5480 if (dr.getMapping() != null)
5482 entry.setMap(addMapping(dr.getMapping()));
5484 datasetSequence.addDBRef(entry);
5488 private jalview.datamodel.Mapping addMapping(Mapping m)
5490 SequenceI dsto = null;
5491 // Mapping m = dr.getMapping();
5492 int fr[] = new int[m.getMapListFrom().size() * 2];
5493 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5494 for (int _i = 0; from.hasNext(); _i += 2)
5496 MapListFrom mf = from.next();
5497 fr[_i] = mf.getStart();
5498 fr[_i + 1] = mf.getEnd();
5500 int fto[] = new int[m.getMapListTo().size() * 2];
5501 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5502 for (int _i = 0; to.hasNext(); _i += 2)
5504 MapListTo mf = to.next();
5505 fto[_i] = mf.getStart();
5506 fto[_i + 1] = mf.getEnd();
5508 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5509 fto, m.getMapFromUnit().intValue(),
5510 m.getMapToUnit().intValue());
5511 // if (m.getMappingChoice() != null)
5513 // MappingChoice mc = m.getMappingChoice();
5514 if (m.getDseqFor() != null)
5516 String dsfor = m.getDseqFor();
5517 if (seqRefIds.containsKey(dsfor))
5522 jmap.setTo(seqRefIds.get(dsfor));
5526 frefedSequence.add(newMappingRef(dsfor, jmap));
5532 * local sequence definition
5534 Sequence ms = m.getSequence();
5535 SequenceI djs = null;
5536 String sqid = ms.getDsseqid();
5537 if (sqid != null && sqid.length() > 0)
5540 * recover dataset sequence
5542 djs = seqRefIds.get(sqid);
5547 "Warning - making up dataset sequence id for DbRef sequence map reference");
5548 sqid = ((Object) ms).toString(); // make up a new hascode for
5549 // undefined dataset sequence hash
5550 // (unlikely to happen)
5556 * make a new dataset sequence and add it to refIds hash
5558 djs = new jalview.datamodel.Sequence(ms.getName(),
5560 djs.setStart(jmap.getMap().getToLowest());
5561 djs.setEnd(jmap.getMap().getToHighest());
5562 djs.setVamsasId(uniqueSetSuffix + sqid);
5564 incompleteSeqs.put(sqid, djs);
5565 seqRefIds.put(sqid, djs);
5568 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5577 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5578 * view as XML (but not to file), and then reloading it
5583 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5586 JalviewModel jm = saveState(ap, null, null, null);
5588 uniqueSetSuffix = "";
5589 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5590 jm.getViewport().get(0).setId(null);
5591 // we don't overwrite the view we just copied
5593 if (this.frefedSequence == null)
5595 frefedSequence = new Vector<>();
5598 viewportsAdded.clear();
5600 AlignFrame af = loadFromObject(jm, null, false, null);
5601 af.getAlignPanels().clear();
5602 af.closeMenuItem_actionPerformed(true);
5605 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5606 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5607 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5608 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5609 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5612 return af.alignPanel;
5615 private Hashtable jvids2vobj;
5617 private void warn(String msg)
5622 private void warn(String msg, Exception e)
5624 if (Cache.log != null)
5628 Cache.log.warn(msg, e);
5632 Cache.log.warn(msg);
5637 System.err.println("Warning: " + msg);
5640 e.printStackTrace();
5645 private void debug(String string)
5647 debug(string, null);
5650 private void debug(String msg, Exception e)
5652 if (Cache.log != null)
5656 Cache.log.debug(msg, e);
5660 Cache.log.debug(msg);
5665 System.err.println("Warning: " + msg);
5668 e.printStackTrace();
5674 * set the object to ID mapping tables used to write/recover objects and XML
5675 * ID strings for the jalview project. If external tables are provided then
5676 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5677 * object goes out of scope. - also populates the datasetIds hashtable with
5678 * alignment objects containing dataset sequences
5681 * Map from ID strings to jalview datamodel
5683 * Map from jalview datamodel to ID strings
5687 public void setObjectMappingTables(Hashtable vobj2jv,
5688 IdentityHashMap jv2vobj)
5690 this.jv2vobj = jv2vobj;
5691 this.vobj2jv = vobj2jv;
5692 Iterator ds = jv2vobj.keySet().iterator();
5694 while (ds.hasNext())
5696 Object jvobj = ds.next();
5697 id = jv2vobj.get(jvobj).toString();
5698 if (jvobj instanceof jalview.datamodel.Alignment)
5700 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5702 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5705 else if (jvobj instanceof jalview.datamodel.Sequence)
5707 // register sequence object so the XML parser can recover it.
5708 if (seqRefIds == null)
5710 seqRefIds = new HashMap<>();
5712 if (seqsToIds == null)
5714 seqsToIds = new IdentityHashMap<>();
5716 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5717 seqsToIds.put((SequenceI) jvobj, id);
5719 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5722 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5723 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5724 if (jvann.annotationId == null)
5726 jvann.annotationId = anid;
5728 if (!jvann.annotationId.equals(anid))
5730 // TODO verify that this is the correct behaviour
5731 this.warn("Overriding Annotation ID for " + anid
5732 + " from different id : " + jvann.annotationId);
5733 jvann.annotationId = anid;
5736 else if (jvobj instanceof String)
5738 if (jvids2vobj == null)
5740 jvids2vobj = new Hashtable();
5741 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5746 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5752 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5753 * objects created from the project archive. If string is null (default for
5754 * construction) then suffix will be set automatically.
5758 public void setUniqueSetSuffix(String string)
5760 uniqueSetSuffix = string;
5765 * uses skipList2 as the skipList for skipping views on sequence sets
5766 * associated with keys in the skipList
5770 public void setSkipList(Hashtable skipList2)
5772 skipList = skipList2;
5776 * Reads the jar entry of given name and returns its contents, or null if the
5777 * entry is not found.
5780 * @param jarEntryName
5783 protected String readJarEntry(jarInputStreamProvider jprovider,
5784 String jarEntryName)
5786 String result = null;
5787 BufferedReader in = null;
5792 * Reopen the jar input stream and traverse its entries to find a matching
5795 JarInputStream jin = jprovider.getJarInputStream();
5796 JarEntry entry = null;
5799 entry = jin.getNextJarEntry();
5800 } while (entry != null && !entry.getName().equals(jarEntryName));
5804 StringBuilder out = new StringBuilder(256);
5805 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5808 while ((data = in.readLine()) != null)
5812 result = out.toString();
5816 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5818 } catch (Exception ex)
5820 ex.printStackTrace();
5828 } catch (IOException e)
5839 * Returns an incrementing counter (0, 1, 2...)
5843 private synchronized int nextCounter()
5849 * Populates an XML model of the feature colour scheme for one feature type
5851 * @param featureType
5855 public static Colour marshalColour(
5856 String featureType, FeatureColourI fcol)
5858 Colour col = new Colour();
5859 if (fcol.isSimpleColour())
5861 col.setRGB(Format.getHexString(fcol.getColour()));
5865 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5866 col.setMin(fcol.getMin());
5867 col.setMax(fcol.getMax());
5868 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5869 col.setAutoScale(fcol.isAutoScaled());
5870 col.setThreshold(fcol.getThreshold());
5871 col.setColourByLabel(fcol.isColourByLabel());
5872 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
5873 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
5874 : ThresholdType.NONE));
5875 if (fcol.isColourByAttribute())
5877 final String[] attName = fcol.getAttributeName();
5878 col.getAttributeName().add(attName[0]);
5879 if (attName.length > 1)
5881 col.getAttributeName().add(attName[1]);
5884 Color noColour = fcol.getNoColour();
5885 if (noColour == null)
5887 col.setNoValueColour(NoValueColour.NONE);
5889 else if (noColour == fcol.getMaxColour())
5891 col.setNoValueColour(NoValueColour.MAX);
5895 col.setNoValueColour(NoValueColour.MIN);
5898 col.setName(featureType);
5903 * Populates an XML model of the feature filter(s) for one feature type
5905 * @param firstMatcher
5906 * the first (or only) match condition)
5908 * remaining match conditions (if any)
5910 * if true, conditions are and-ed, else or-ed
5912 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
5913 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
5916 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
5918 if (filters.hasNext())
5923 CompoundMatcher compound = new CompoundMatcher();
5924 compound.setAnd(and);
5925 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
5926 firstMatcher, Collections.emptyIterator(), and);
5927 // compound.addMatcherSet(matcher1);
5928 compound.getMatcherSet().add(matcher1);
5929 FeatureMatcherI nextMatcher = filters.next();
5930 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
5931 nextMatcher, filters, and);
5932 // compound.addMatcherSet(matcher2);
5933 compound.getMatcherSet().add(matcher2);
5934 result.setCompoundMatcher(compound);
5939 * single condition matcher
5941 // MatchCondition matcherModel = new MatchCondition();
5942 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
5943 matcherModel.setCondition(
5944 firstMatcher.getMatcher().getCondition().getStableName());
5945 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5946 if (firstMatcher.isByAttribute())
5948 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
5949 // matcherModel.setAttributeName(firstMatcher.getAttribute());
5950 String[] attName = firstMatcher.getAttribute();
5951 matcherModel.getAttributeName().add(attName[0]); // attribute
5952 if (attName.length > 1)
5954 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
5957 else if (firstMatcher.isByLabel())
5959 matcherModel.setBy(FilterBy.BY_LABEL);
5961 else if (firstMatcher.isByScore())
5963 matcherModel.setBy(FilterBy.BY_SCORE);
5965 result.setMatchCondition(matcherModel);
5972 * Loads one XML model of a feature filter to a Jalview object
5974 * @param featureType
5975 * @param matcherSetModel
5978 public static FeatureMatcherSetI parseFilter(
5980 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
5982 FeatureMatcherSetI result = new FeatureMatcherSet();
5985 parseFilterConditions(result, matcherSetModel, true);
5986 } catch (IllegalStateException e)
5988 // mixing AND and OR conditions perhaps
5990 String.format("Error reading filter conditions for '%s': %s",
5991 featureType, e.getMessage()));
5992 // return as much as was parsed up to the error
5999 * Adds feature match conditions to matcherSet as unmarshalled from XML
6000 * (possibly recursively for compound conditions)
6003 * @param matcherSetModel
6005 * if true, multiple conditions are AND-ed, else they are OR-ed
6006 * @throws IllegalStateException
6007 * if AND and OR conditions are mixed
6009 protected static void parseFilterConditions(
6010 FeatureMatcherSetI matcherSet,
6011 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6014 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6015 .getMatchCondition();
6021 FilterBy filterBy = mc.getBy();
6022 Condition cond = Condition.fromString(mc.getCondition());
6023 String pattern = mc.getValue();
6024 FeatureMatcherI matchCondition = null;
6025 if (filterBy == FilterBy.BY_LABEL)
6027 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6029 else if (filterBy == FilterBy.BY_SCORE)
6031 matchCondition = FeatureMatcher.byScore(cond, pattern);
6034 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6036 final List<String> attributeName = mc.getAttributeName();
6037 String[] attNames = attributeName
6038 .toArray(new String[attributeName.size()]);
6039 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6044 * note this throws IllegalStateException if AND-ing to a
6045 * previously OR-ed compound condition, or vice versa
6049 matcherSet.and(matchCondition);
6053 matcherSet.or(matchCondition);
6059 * compound condition
6061 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6062 .getCompoundMatcher().getMatcherSet();
6063 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6064 if (matchers.size() == 2)
6066 parseFilterConditions(matcherSet, matchers.get(0), anded);
6067 parseFilterConditions(matcherSet, matchers.get(1), anded);
6071 System.err.println("Malformed compound filter condition");
6077 * Loads one XML model of a feature colour to a Jalview object
6079 * @param colourModel
6082 public static FeatureColourI parseColour(Colour colourModel)
6084 FeatureColourI colour = null;
6086 if (colourModel.getMax() != null)
6088 Color mincol = null;
6089 Color maxcol = null;
6090 Color noValueColour = null;
6094 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6095 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6096 } catch (Exception e)
6098 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6101 NoValueColour noCol = colourModel.getNoValueColour();
6102 if (noCol == NoValueColour.MIN)
6104 noValueColour = mincol;
6106 else if (noCol == NoValueColour.MAX)
6108 noValueColour = maxcol;
6111 colour = new FeatureColour(mincol, maxcol, noValueColour,
6112 safeFloat(colourModel.getMin()),
6113 safeFloat(colourModel.getMax()));
6114 final List<String> attributeName = colourModel.getAttributeName();
6115 String[] attributes = attributeName
6116 .toArray(new String[attributeName.size()]);
6117 if (attributes != null && attributes.length > 0)
6119 colour.setAttributeName(attributes);
6121 if (colourModel.isAutoScale() != null)
6123 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6125 if (colourModel.isColourByLabel() != null)
6127 colour.setColourByLabel(
6128 colourModel.isColourByLabel().booleanValue());
6130 if (colourModel.getThreshold() != null)
6132 colour.setThreshold(colourModel.getThreshold().floatValue());
6134 ThresholdType ttyp = colourModel.getThreshType();
6135 if (ttyp == ThresholdType.ABOVE)
6137 colour.setAboveThreshold(true);
6139 else if (ttyp == ThresholdType.BELOW)
6141 colour.setBelowThreshold(true);
6146 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6147 colour = new FeatureColour(color);