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.DBRefEntry;
33 import jalview.datamodel.GraphLine;
34 import jalview.datamodel.PDBEntry;
35 import jalview.datamodel.RnaViewerModel;
36 import jalview.datamodel.SequenceFeature;
37 import jalview.datamodel.SequenceGroup;
38 import jalview.datamodel.SequenceI;
39 import jalview.datamodel.StructureViewerModel;
40 import jalview.datamodel.StructureViewerModel.StructureData;
41 import jalview.datamodel.features.FeatureMatcher;
42 import jalview.datamodel.features.FeatureMatcherI;
43 import jalview.datamodel.features.FeatureMatcherSet;
44 import jalview.datamodel.features.FeatureMatcherSetI;
45 import jalview.ext.varna.RnaModel;
46 import jalview.gui.AlignFrame;
47 import jalview.gui.AlignViewport;
48 import jalview.gui.AlignmentPanel;
49 import jalview.gui.AppVarna;
50 import jalview.gui.ChimeraViewFrame;
51 import jalview.gui.Desktop;
52 import jalview.gui.FeatureRenderer;
53 import jalview.gui.Jalview2XML_V1;
54 import jalview.gui.JvOptionPane;
55 import jalview.gui.OOMWarning;
56 import jalview.gui.PaintRefresher;
57 import jalview.gui.SplitFrame;
58 import jalview.gui.StructureViewer;
59 import jalview.gui.StructureViewer.ViewerType;
60 import jalview.gui.StructureViewerBase;
61 import jalview.gui.TreePanel;
62 import jalview.io.DataSourceType;
63 import jalview.io.FileFormat;
64 import jalview.io.NewickFile;
65 import jalview.renderer.ResidueShaderI;
66 import jalview.schemes.AnnotationColourGradient;
67 import jalview.schemes.ColourSchemeI;
68 import jalview.schemes.ColourSchemeProperty;
69 import jalview.schemes.FeatureColour;
70 import jalview.schemes.ResidueProperties;
71 import jalview.schemes.UserColourScheme;
72 import jalview.structure.StructureSelectionManager;
73 import jalview.structures.models.AAStructureBindingModel;
74 import jalview.util.Format;
75 import jalview.util.MessageManager;
76 import jalview.util.Platform;
77 import jalview.util.StringUtils;
78 import jalview.util.jarInputStreamProvider;
79 import jalview.util.matcher.Condition;
80 import jalview.viewmodel.AlignmentViewport;
81 import jalview.viewmodel.ViewportRanges;
82 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
83 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
84 import jalview.ws.jws2.Jws2Discoverer;
85 import jalview.ws.jws2.dm.AAConSettings;
86 import jalview.ws.jws2.jabaws2.Jws2Instance;
87 import jalview.ws.params.ArgumentI;
88 import jalview.ws.params.AutoCalcSetting;
89 import jalview.ws.params.WsParamSetI;
90 import jalview.xml.binding.jalview.AlcodonFrame;
91 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
92 import jalview.xml.binding.jalview.Annotation;
93 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
94 import jalview.xml.binding.jalview.AnnotationColourScheme;
95 import jalview.xml.binding.jalview.AnnotationElement;
96 import jalview.xml.binding.jalview.Feature;
97 import jalview.xml.binding.jalview.Feature.OtherData;
98 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
99 import jalview.xml.binding.jalview.FilterBy;
100 import jalview.xml.binding.jalview.JalviewModel;
101 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
102 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
103 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
104 import jalview.xml.binding.jalview.JalviewModel.JGroup;
105 import jalview.xml.binding.jalview.JalviewModel.JSeq;
106 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
107 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
108 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
109 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
110 import jalview.xml.binding.jalview.JalviewModel.Tree;
111 import jalview.xml.binding.jalview.JalviewModel.UserColours;
112 import jalview.xml.binding.jalview.JalviewModel.Viewport;
113 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
114 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
115 import jalview.xml.binding.jalview.JalviewUserColours;
116 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
117 import jalview.xml.binding.jalview.MapListType.MapListFrom;
118 import jalview.xml.binding.jalview.MapListType.MapListTo;
119 import jalview.xml.binding.jalview.Mapping;
120 import jalview.xml.binding.jalview.NoValueColour;
121 import jalview.xml.binding.jalview.ObjectFactory;
122 import jalview.xml.binding.jalview.Pdbentry.Property;
123 import jalview.xml.binding.jalview.Sequence;
124 import jalview.xml.binding.jalview.Sequence.DBRef;
125 import jalview.xml.binding.jalview.SequenceSet;
126 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
127 import jalview.xml.binding.jalview.ThresholdType;
128 import jalview.xml.binding.jalview.VAMSAS;
130 import java.awt.Color;
131 import java.awt.Font;
132 import java.awt.Rectangle;
133 import java.io.BufferedReader;
134 import java.io.ByteArrayInputStream;
135 import java.io.DataInputStream;
136 import java.io.DataOutputStream;
138 import java.io.FileInputStream;
139 import java.io.FileOutputStream;
140 import java.io.IOException;
141 import java.io.InputStreamReader;
142 import java.io.OutputStreamWriter;
143 import java.io.PrintWriter;
144 import java.lang.reflect.InvocationTargetException;
145 import java.math.BigInteger;
146 import java.net.MalformedURLException;
148 import java.util.ArrayList;
149 import java.util.Arrays;
150 import java.util.Collections;
151 import java.util.Enumeration;
152 import java.util.GregorianCalendar;
153 import java.util.HashMap;
154 import java.util.HashSet;
155 import java.util.Hashtable;
156 import java.util.IdentityHashMap;
157 import java.util.Iterator;
158 import java.util.LinkedHashMap;
159 import java.util.List;
160 import java.util.Map;
161 import java.util.Map.Entry;
162 import java.util.Set;
163 import java.util.Vector;
164 import java.util.jar.JarEntry;
165 import java.util.jar.JarInputStream;
166 import java.util.jar.JarOutputStream;
168 import javax.swing.JInternalFrame;
169 import javax.swing.SwingUtilities;
170 import javax.xml.bind.JAXBContext;
171 import javax.xml.bind.JAXBElement;
172 import javax.xml.bind.Marshaller;
173 import javax.xml.datatype.DatatypeConfigurationException;
174 import javax.xml.datatype.DatatypeFactory;
175 import javax.xml.datatype.XMLGregorianCalendar;
176 import javax.xml.stream.XMLInputFactory;
177 import javax.xml.stream.XMLStreamReader;
180 * Write out the current jalview desktop state as a Jalview XML stream.
182 * Note: the vamsas objects referred to here are primitive versions of the
183 * VAMSAS project schema elements - they are not the same and most likely never
187 * @version $Revision: 1.134 $
189 public class Jalview2XML
192 // BH 2018 we add the .jvp binary extension to J2S so that
193 // it will declare that binary when we do the file save from the browser
195 private static void addJ2SBinaryType(String ext)
197 ext = "." + ext + "?";
202 * J2S._binaryTypes.push(ext);
209 addJ2SBinaryType(".jvp?");
212 private static final String VIEWER_PREFIX = "viewer_";
214 private static final String RNA_PREFIX = "rna_";
216 private static final String UTF_8 = "UTF-8";
218 // use this with nextCounter() to make unique names for entities
219 private int counter = 0;
222 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
223 * of sequence objects are created.
225 IdentityHashMap<SequenceI, String> seqsToIds = null;
228 * jalview XML Sequence ID to jalview sequence object reference (both dataset
229 * and alignment sequences. Populated as XML reps of sequence objects are
232 Map<String, SequenceI> seqRefIds = null;
234 Map<String, SequenceI> incompleteSeqs = null;
236 List<SeqFref> frefedSequence = null;
238 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
241 * Map of reconstructed AlignFrame objects that appear to have come from
242 * SplitFrame objects (have a dna/protein complement view).
244 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
247 * Map from displayed rna structure models to their saved session state jar
250 private Map<RnaModel, String> rnaSessions = new HashMap<>();
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 boolean value, or false
260 public static boolean safeBoolean(Boolean b)
262 return b == null ? false : b.booleanValue();
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 integer value, or zero
273 public static int safeInt(Integer i)
275 return i == null ? 0 : i.intValue();
279 * A helper method for safely using the value of an optional attribute that
280 * may be null if not present in the XML. Answers the float value, or zero if
286 public static float safeFloat(Float f)
288 return f == null ? 0f : f.floatValue();
292 * create/return unique hash string for sq
295 * @return new or existing unique string for sq
297 String seqHash(SequenceI sq)
299 if (seqsToIds == null)
303 if (seqsToIds.containsKey(sq))
305 return seqsToIds.get(sq);
309 // create sequential key
310 String key = "sq" + (seqsToIds.size() + 1);
311 key = makeHashCode(sq, key); // check we don't have an external reference
313 seqsToIds.put(sq, key);
320 if (seqsToIds == null)
322 seqsToIds = new IdentityHashMap<>();
324 if (seqRefIds == null)
326 seqRefIds = new HashMap<>();
328 if (incompleteSeqs == null)
330 incompleteSeqs = new HashMap<>();
332 if (frefedSequence == null)
334 frefedSequence = new ArrayList<>();
342 public Jalview2XML(boolean raiseGUI)
344 this.raiseGUI = raiseGUI;
348 * base class for resolving forward references to sequences by their ID
353 abstract class SeqFref
359 public SeqFref(String _sref, String type)
365 public String getSref()
370 public SequenceI getSrefSeq()
372 return seqRefIds.get(sref);
375 public boolean isResolvable()
377 return seqRefIds.get(sref) != null;
380 public SequenceI getSrefDatasetSeq()
382 SequenceI sq = seqRefIds.get(sref);
385 while (sq.getDatasetSequence() != null)
387 sq = sq.getDatasetSequence();
394 * @return true if the forward reference was fully resolved
396 abstract boolean resolve();
399 public String toString()
401 return type + " reference to " + sref;
406 * create forward reference for a mapping
412 public SeqFref newMappingRef(final String sref,
413 final jalview.datamodel.Mapping _jmap)
415 SeqFref fref = new SeqFref(sref, "Mapping")
417 public jalview.datamodel.Mapping jmap = _jmap;
422 SequenceI seq = getSrefDatasetSeq();
434 public SeqFref newAlcodMapRef(final String sref,
435 final AlignedCodonFrame _cf,
436 final jalview.datamodel.Mapping _jmap)
439 SeqFref fref = new SeqFref(sref, "Codon Frame")
441 AlignedCodonFrame cf = _cf;
443 public jalview.datamodel.Mapping mp = _jmap;
446 public boolean isResolvable()
448 return super.isResolvable() && mp.getTo() != null;
454 SequenceI seq = getSrefDatasetSeq();
459 cf.addMap(seq, mp.getTo(), mp.getMap());
466 public void resolveFrefedSequences()
468 Iterator<SeqFref> nextFref = frefedSequence.iterator();
469 int toresolve = frefedSequence.size();
470 int unresolved = 0, failedtoresolve = 0;
471 while (nextFref.hasNext())
473 SeqFref ref = nextFref.next();
474 if (ref.isResolvable())
486 } catch (Exception x)
489 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
502 System.err.println("Jalview Project Import: There were " + unresolved
503 + " forward references left unresolved on the stack.");
505 if (failedtoresolve > 0)
507 System.err.println("SERIOUS! " + failedtoresolve
508 + " resolvable forward references failed to resolve.");
510 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
513 "Jalview Project Import: There are " + incompleteSeqs.size()
514 + " sequences which may have incomplete metadata.");
515 if (incompleteSeqs.size() < 10)
517 for (SequenceI s : incompleteSeqs.values())
519 System.err.println(s.toString());
525 "Too many to report. Skipping output of incomplete sequences.");
531 * This maintains a map of viewports, the key being the seqSetId. Important to
532 * set historyItem and redoList for multiple views
534 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
536 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
538 String uniqueSetSuffix = "";
541 * List of pdbfiles added to Jar
543 List<String> pdbfiles = null;
545 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
546 public void saveState(File statefile)
548 FileOutputStream fos = null;
551 fos = new FileOutputStream(statefile);
552 JarOutputStream jout = new JarOutputStream(fos);
555 } catch (Exception e)
557 // TODO: inform user of the problem - they need to know if their data was
559 if (errorMessage == null)
561 errorMessage = "Couldn't write Jalview Archive to output file '"
562 + statefile + "' - See console error log for details";
566 errorMessage += "(output file was '" + statefile + "')";
576 } catch (IOException e)
586 * Writes a jalview project archive to the given Jar output stream.
590 public void saveState(JarOutputStream jout)
592 AlignFrame[] frames = Desktop.getAlignFrames();
598 saveAllFrames(Arrays.asList(frames), jout);
602 * core method for storing state for a set of AlignFrames.
605 * - frames involving all data to be exported (including containing
608 * - project output stream
610 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
612 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
615 * ensure cached data is clear before starting
617 // todo tidy up seqRefIds, seqsToIds initialisation / reset
619 splitFrameCandidates.clear();
624 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
625 // //////////////////////////////////////////////////
627 List<String> shortNames = new ArrayList<>();
628 List<String> viewIds = new ArrayList<>();
631 for (int i = frames.size() - 1; i > -1; i--)
633 AlignFrame af = frames.get(i);
635 if (skipList != null && skipList
636 .containsKey(af.getViewport().getSequenceSetId()))
641 String shortName = makeFilename(af, shortNames);
643 int apSize = af.getAlignPanels().size();
645 for (int ap = 0; ap < apSize; ap++)
647 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
649 String fileName = apSize == 1 ? shortName : ap + shortName;
650 if (!fileName.endsWith(".xml"))
652 fileName = fileName + ".xml";
655 saveState(apanel, fileName, jout, viewIds);
657 String dssid = getDatasetIdRef(
658 af.getViewport().getAlignment().getDataset());
659 if (!dsses.containsKey(dssid))
661 dsses.put(dssid, af);
666 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
672 } catch (Exception foo)
677 } catch (Exception ex)
679 // TODO: inform user of the problem - they need to know if their data was
681 if (errorMessage == null)
683 errorMessage = "Couldn't write Jalview Archive - see error output for details";
685 ex.printStackTrace();
690 * Generates a distinct file name, based on the title of the AlignFrame, by
691 * appending _n for increasing n until an unused name is generated. The new
692 * name (without its extension) is added to the list.
696 * @return the generated name, with .xml extension
698 protected String makeFilename(AlignFrame af, List<String> namesUsed)
700 String shortName = af.getTitle();
702 if (shortName.indexOf(File.separatorChar) > -1)
704 shortName = shortName
705 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
710 while (namesUsed.contains(shortName))
712 if (shortName.endsWith("_" + (count - 1)))
714 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
717 shortName = shortName.concat("_" + count);
721 namesUsed.add(shortName);
723 if (!shortName.endsWith(".xml"))
725 shortName = shortName + ".xml";
730 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
731 public boolean saveAlignment(AlignFrame af, String jarFile,
736 FileOutputStream fos = new FileOutputStream(jarFile);
737 JarOutputStream jout = new JarOutputStream(fos);
738 List<AlignFrame> frames = new ArrayList<>();
740 // resolve splitframes
741 if (af.getViewport().getCodingComplement() != null)
743 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
749 saveAllFrames(frames, jout);
753 } catch (Exception foo)
759 } catch (Exception ex)
761 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
762 ex.printStackTrace();
767 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
768 String fileName, JarOutputStream jout)
771 for (String dssids : dsses.keySet())
773 AlignFrame _af = dsses.get(dssids);
774 String jfileName = fileName + " Dataset for " + _af.getTitle();
775 if (!jfileName.endsWith(".xml"))
777 jfileName = jfileName + ".xml";
779 saveState(_af.alignPanel, jfileName, true, jout, null);
784 * create a JalviewModel from an alignment view and marshall it to a
788 * panel to create jalview model for
790 * name of alignment panel written to output stream
797 public JalviewModel saveState(AlignmentPanel ap, String fileName,
798 JarOutputStream jout, List<String> viewIds)
800 return saveState(ap, fileName, false, jout, viewIds);
804 * create a JalviewModel from an alignment view and marshall it to a
808 * panel to create jalview model for
810 * name of alignment panel written to output stream
812 * when true, only write the dataset for the alignment, not the data
813 * associated with the view.
819 public JalviewModel saveState(AlignmentPanel ap, String fileName,
820 boolean storeDS, JarOutputStream jout, List<String> viewIds)
824 viewIds = new ArrayList<>();
829 List<UserColourScheme> userColours = new ArrayList<>();
831 AlignViewport av = ap.av;
832 ViewportRanges vpRanges = av.getRanges();
834 final ObjectFactory objectFactory = new ObjectFactory();
835 JalviewModel object = objectFactory.createJalviewModel();
836 object.setVamsasModel(new VAMSAS());
838 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
841 GregorianCalendar c = new GregorianCalendar();
842 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
843 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
844 object.setCreationDate(now);
845 } catch (DatatypeConfigurationException e)
847 System.err.println("error writing date: " + e.toString());
850 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
853 * rjal is full height alignment, jal is actual alignment with full metadata
854 * but excludes hidden sequences.
856 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
858 if (av.hasHiddenRows())
860 rjal = jal.getHiddenSequences().getFullAlignment();
863 SequenceSet vamsasSet = new SequenceSet();
865 // JalviewModelSequence jms = new JalviewModelSequence();
867 vamsasSet.setGapChar(jal.getGapCharacter() + "");
869 if (jal.getDataset() != null)
871 // dataset id is the dataset's hashcode
872 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
875 // switch jal and the dataset
876 jal = jal.getDataset();
880 if (jal.getProperties() != null)
882 Enumeration en = jal.getProperties().keys();
883 while (en.hasMoreElements())
885 String key = en.nextElement().toString();
886 SequenceSetProperties ssp = new SequenceSetProperties();
888 ssp.setValue(jal.getProperties().get(key).toString());
889 // vamsasSet.addSequenceSetProperties(ssp);
890 vamsasSet.getSequenceSetProperties().add(ssp);
895 Set<String> calcIdSet = new HashSet<>();
896 // record the set of vamsas sequence XML POJO we create.
897 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
899 for (final SequenceI jds : rjal.getSequences())
901 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
902 : jds.getDatasetSequence();
903 String id = seqHash(jds);
904 if (vamsasSetIds.get(id) == null)
906 if (seqRefIds.get(id) != null && !storeDS)
908 // This happens for two reasons: 1. multiple views are being
910 // 2. the hashCode has collided with another sequence's code. This
912 // HAPPEN! (PF00072.15.stk does this)
913 // JBPNote: Uncomment to debug writing out of files that do not read
914 // back in due to ArrayOutOfBoundExceptions.
915 // System.err.println("vamsasSeq backref: "+id+"");
916 // System.err.println(jds.getName()+"
917 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
918 // System.err.println("Hashcode: "+seqHash(jds));
919 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
920 // System.err.println(rsq.getName()+"
921 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
922 // System.err.println("Hashcode: "+seqHash(rsq));
926 vamsasSeq = createVamsasSequence(id, jds);
927 // vamsasSet.addSequence(vamsasSeq);
928 vamsasSet.getSequence().add(vamsasSeq);
929 vamsasSetIds.put(id, vamsasSeq);
930 seqRefIds.put(id, jds);
934 jseq.setStart(jds.getStart());
935 jseq.setEnd(jds.getEnd());
936 jseq.setColour(av.getSequenceColour(jds).getRGB());
938 jseq.setId(id); // jseq id should be a string not a number
941 // Store any sequences this sequence represents
942 if (av.hasHiddenRows())
944 // use rjal, contains the full height alignment
946 av.getAlignment().getHiddenSequences().isHidden(jds));
948 if (av.isHiddenRepSequence(jds))
950 jalview.datamodel.SequenceI[] reps = av
951 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
953 for (int h = 0; h < reps.length; h++)
957 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
958 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
963 // mark sequence as reference - if it is the reference for this view
966 jseq.setViewreference(jds == jal.getSeqrep());
970 // TODO: omit sequence features from each alignment view's XML dump if we
971 // are storing dataset
972 List<SequenceFeature> sfs = jds.getSequenceFeatures();
973 for (SequenceFeature sf : sfs)
975 // Features features = new Features();
976 Feature features = new Feature();
978 features.setBegin(sf.getBegin());
979 features.setEnd(sf.getEnd());
980 features.setDescription(sf.getDescription());
981 features.setType(sf.getType());
982 features.setFeatureGroup(sf.getFeatureGroup());
983 features.setScore(sf.getScore());
984 if (sf.links != null)
986 for (int l = 0; l < sf.links.size(); l++)
988 OtherData keyValue = new OtherData();
989 keyValue.setKey("LINK_" + l);
990 keyValue.setValue(sf.links.elementAt(l).toString());
991 // features.addOtherData(keyValue);
992 features.getOtherData().add(keyValue);
995 if (sf.otherDetails != null)
998 * save feature attributes, which may be simple strings or
999 * map valued (have sub-attributes)
1001 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1003 String key = entry.getKey();
1004 Object value = entry.getValue();
1005 if (value instanceof Map<?, ?>)
1007 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1010 OtherData otherData = new OtherData();
1011 otherData.setKey(key);
1012 otherData.setKey2(subAttribute.getKey());
1013 otherData.setValue(subAttribute.getValue().toString());
1014 // features.addOtherData(otherData);
1015 features.getOtherData().add(otherData);
1020 OtherData otherData = new OtherData();
1021 otherData.setKey(key);
1022 otherData.setValue(value.toString());
1023 // features.addOtherData(otherData);
1024 features.getOtherData().add(otherData);
1029 // jseq.addFeatures(features);
1030 jseq.getFeatures().add(features);
1033 if (jdatasq.getAllPDBEntries() != null)
1035 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1036 while (en.hasMoreElements())
1038 Pdbids pdb = new Pdbids();
1039 jalview.datamodel.PDBEntry entry = en.nextElement();
1041 String pdbId = entry.getId();
1043 pdb.setType(entry.getType());
1046 * Store any structure views associated with this sequence. This
1047 * section copes with duplicate entries in the project, so a dataset
1048 * only view *should* be coped with sensibly.
1050 // This must have been loaded, is it still visible?
1051 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1052 String matchedFile = null;
1053 for (int f = frames.length - 1; f > -1; f--)
1055 if (frames[f] instanceof StructureViewerBase)
1057 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1058 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1059 matchedFile, viewFrame);
1061 * Only store each structure viewer's state once in the project
1062 * jar. First time through only (storeDS==false)
1064 String viewId = viewFrame.getViewId();
1065 if (!storeDS && !viewIds.contains(viewId))
1067 viewIds.add(viewId);
1070 String viewerState = viewFrame.getStateInfo();
1071 writeJarEntry(jout, getViewerJarEntryName(viewId),
1072 viewerState.getBytes());
1073 } catch (IOException e)
1076 "Error saving viewer state: " + e.getMessage());
1082 if (matchedFile != null || entry.getFile() != null)
1084 if (entry.getFile() != null)
1087 matchedFile = entry.getFile();
1089 pdb.setFile(matchedFile); // entry.getFile());
1090 if (pdbfiles == null)
1092 pdbfiles = new ArrayList<>();
1095 if (!pdbfiles.contains(pdbId))
1097 pdbfiles.add(pdbId);
1098 copyFileToJar(jout, matchedFile, pdbId);
1102 Enumeration<String> props = entry.getProperties();
1103 if (props.hasMoreElements())
1105 // PdbentryItem item = new PdbentryItem();
1106 while (props.hasMoreElements())
1108 Property prop = new Property();
1109 String key = props.nextElement();
1111 prop.setValue(entry.getProperty(key).toString());
1112 // item.addProperty(prop);
1113 pdb.getProperty().add(prop);
1115 // pdb.addPdbentryItem(item);
1118 // jseq.addPdbids(pdb);
1119 jseq.getPdbids().add(pdb);
1123 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1125 // jms.addJSeq(jseq);
1126 object.getJSeq().add(jseq);
1129 if (!storeDS && av.hasHiddenRows())
1131 jal = av.getAlignment();
1135 if (storeDS && jal.getCodonFrames() != null)
1137 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1138 for (AlignedCodonFrame acf : jac)
1140 AlcodonFrame alc = new AlcodonFrame();
1141 if (acf.getProtMappings() != null
1142 && acf.getProtMappings().length > 0)
1144 boolean hasMap = false;
1145 SequenceI[] dnas = acf.getdnaSeqs();
1146 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1147 for (int m = 0; m < pmaps.length; m++)
1149 AlcodMap alcmap = new AlcodMap();
1150 alcmap.setDnasq(seqHash(dnas[m]));
1152 createVamsasMapping(pmaps[m], dnas[m], null, false));
1153 // alc.addAlcodMap(alcmap);
1154 alc.getAlcodMap().add(alcmap);
1159 // vamsasSet.addAlcodonFrame(alc);
1160 vamsasSet.getAlcodonFrame().add(alc);
1163 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1165 // AlcodonFrame alc = new AlcodonFrame();
1166 // vamsasSet.addAlcodonFrame(alc);
1167 // for (int p = 0; p < acf.aaWidth; p++)
1169 // Alcodon cmap = new Alcodon();
1170 // if (acf.codons[p] != null)
1172 // // Null codons indicate a gapped column in the translated peptide
1174 // cmap.setPos1(acf.codons[p][0]);
1175 // cmap.setPos2(acf.codons[p][1]);
1176 // cmap.setPos3(acf.codons[p][2]);
1178 // alc.addAlcodon(cmap);
1180 // if (acf.getProtMappings() != null
1181 // && acf.getProtMappings().length > 0)
1183 // SequenceI[] dnas = acf.getdnaSeqs();
1184 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1185 // for (int m = 0; m < pmaps.length; m++)
1187 // AlcodMap alcmap = new AlcodMap();
1188 // alcmap.setDnasq(seqHash(dnas[m]));
1189 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1191 // alc.addAlcodMap(alcmap);
1198 // /////////////////////////////////
1199 if (!storeDS && av.getCurrentTree() != null)
1201 // FIND ANY ASSOCIATED TREES
1202 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1203 if (Desktop.desktop != null)
1205 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1207 for (int t = 0; t < frames.length; t++)
1209 if (frames[t] instanceof TreePanel)
1211 TreePanel tp = (TreePanel) frames[t];
1213 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1215 JalviewModel.Tree tree = new JalviewModel.Tree();
1216 tree.setTitle(tp.getTitle());
1217 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1218 tree.setNewick(tp.getTree().print());
1219 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1221 tree.setFitToWindow(tp.fitToWindow.getState());
1222 tree.setFontName(tp.getTreeFont().getName());
1223 tree.setFontSize(tp.getTreeFont().getSize());
1224 tree.setFontStyle(tp.getTreeFont().getStyle());
1225 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1227 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1228 tree.setShowDistances(tp.distanceMenu.getState());
1230 tree.setHeight(tp.getHeight());
1231 tree.setWidth(tp.getWidth());
1232 tree.setXpos(tp.getX());
1233 tree.setYpos(tp.getY());
1234 tree.setId(makeHashCode(tp, null));
1235 // jms.addTree(tree);
1236 object.getTree().add(tree);
1245 * store forward refs from an annotationRow to any groups
1247 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1250 for (SequenceI sq : jal.getSequences())
1252 // Store annotation on dataset sequences only
1253 AlignmentAnnotation[] aa = sq.getAnnotation();
1254 if (aa != null && aa.length > 0)
1256 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1263 if (jal.getAlignmentAnnotation() != null)
1265 // Store the annotation shown on the alignment.
1266 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1267 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1272 if (jal.getGroups() != null)
1274 JGroup[] groups = new JGroup[jal.getGroups().size()];
1276 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1278 JGroup jGroup = new JGroup();
1279 groups[++i] = jGroup;
1281 jGroup.setStart(sg.getStartRes());
1282 jGroup.setEnd(sg.getEndRes());
1283 jGroup.setName(sg.getName());
1284 if (groupRefs.containsKey(sg))
1286 // group has references so set its ID field
1287 jGroup.setId(groupRefs.get(sg));
1289 ColourSchemeI colourScheme = sg.getColourScheme();
1290 if (colourScheme != null)
1292 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1293 if (groupColourScheme.conservationApplied())
1295 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1297 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1300 setUserColourScheme(colourScheme, userColours,
1305 jGroup.setColour(colourScheme.getSchemeName());
1308 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1310 jGroup.setColour("AnnotationColourGradient");
1311 jGroup.setAnnotationColours(constructAnnotationColours(
1312 (jalview.schemes.AnnotationColourGradient) colourScheme,
1313 userColours, object));
1315 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1318 setUserColourScheme(colourScheme, userColours, object));
1322 jGroup.setColour(colourScheme.getSchemeName());
1325 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1328 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1329 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1330 jGroup.setDisplayText(sg.getDisplayText());
1331 jGroup.setColourText(sg.getColourText());
1332 jGroup.setTextCol1(sg.textColour.getRGB());
1333 jGroup.setTextCol2(sg.textColour2.getRGB());
1334 jGroup.setTextColThreshold(sg.thresholdTextColour);
1335 jGroup.setShowUnconserved(sg.getShowNonconserved());
1336 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1337 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1338 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1339 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1340 for (SequenceI seq : sg.getSequences())
1342 // jGroup.addSeq(seqHash(seq));
1343 jGroup.getSeq().add(seqHash(seq));
1347 //jms.setJGroup(groups);
1349 for (JGroup grp : groups)
1351 object.getJGroup().add(grp);
1356 // /////////SAVE VIEWPORT
1357 Viewport view = new Viewport();
1358 view.setTitle(ap.alignFrame.getTitle());
1359 view.setSequenceSetId(
1360 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1361 view.setId(av.getViewId());
1362 if (av.getCodingComplement() != null)
1364 view.setComplementId(av.getCodingComplement().getViewId());
1366 view.setViewName(av.getViewName());
1367 view.setGatheredViews(av.isGatherViewsHere());
1369 Rectangle size = ap.av.getExplodedGeometry();
1370 Rectangle position = size;
1373 size = ap.alignFrame.getBounds();
1374 if (av.getCodingComplement() != null)
1376 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1384 view.setXpos(position.x);
1385 view.setYpos(position.y);
1387 view.setWidth(size.width);
1388 view.setHeight(size.height);
1390 view.setStartRes(vpRanges.getStartRes());
1391 view.setStartSeq(vpRanges.getStartSeq());
1393 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1395 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1396 userColours, object));
1399 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1401 AnnotationColourScheme ac = constructAnnotationColours(
1402 (jalview.schemes.AnnotationColourGradient) av
1403 .getGlobalColourScheme(),
1404 userColours, object);
1406 view.setAnnotationColours(ac);
1407 view.setBgColour("AnnotationColourGradient");
1411 view.setBgColour(ColourSchemeProperty
1412 .getColourName(av.getGlobalColourScheme()));
1415 ResidueShaderI vcs = av.getResidueShading();
1416 ColourSchemeI cs = av.getGlobalColourScheme();
1420 if (vcs.conservationApplied())
1422 view.setConsThreshold(vcs.getConservationInc());
1423 if (cs instanceof jalview.schemes.UserColourScheme)
1425 view.setBgColour(setUserColourScheme(cs, userColours, object));
1428 view.setPidThreshold(vcs.getThreshold());
1431 view.setConservationSelected(av.getConservationSelected());
1432 view.setPidSelected(av.getAbovePIDThreshold());
1433 final Font font = av.getFont();
1434 view.setFontName(font.getName());
1435 view.setFontSize(font.getSize());
1436 view.setFontStyle(font.getStyle());
1437 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1438 view.setRenderGaps(av.isRenderGaps());
1439 view.setShowAnnotation(av.isShowAnnotation());
1440 view.setShowBoxes(av.getShowBoxes());
1441 view.setShowColourText(av.getColourText());
1442 view.setShowFullId(av.getShowJVSuffix());
1443 view.setRightAlignIds(av.isRightAlignIds());
1444 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1445 view.setShowText(av.getShowText());
1446 view.setShowUnconserved(av.getShowUnconserved());
1447 view.setWrapAlignment(av.getWrapAlignment());
1448 view.setTextCol1(av.getTextColour().getRGB());
1449 view.setTextCol2(av.getTextColour2().getRGB());
1450 view.setTextColThreshold(av.getThresholdTextColour());
1451 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1452 view.setShowSequenceLogo(av.isShowSequenceLogo());
1453 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1454 view.setShowGroupConsensus(av.isShowGroupConsensus());
1455 view.setShowGroupConservation(av.isShowGroupConservation());
1456 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1457 view.setShowDbRefTooltip(av.isShowDBRefs());
1458 view.setFollowHighlight(av.isFollowHighlight());
1459 view.setFollowSelection(av.followSelection);
1460 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1461 if (av.getFeaturesDisplayed() != null)
1463 FeatureSettings fs = new FeatureSettings();
1465 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1466 .getFeatureRenderer();
1467 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1469 Vector<String> settingsAdded = new Vector<>();
1470 if (renderOrder != null)
1472 for (String featureType : renderOrder)
1474 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1475 setting.setType(featureType);
1478 * save any filter for the feature type
1480 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1481 if (filter != null) {
1482 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1483 FeatureMatcherI firstFilter = filters.next();
1484 setting.setMatcherSet(Jalview2XML.marshalFilter(
1485 firstFilter, filters, filter.isAnded()));
1489 * save colour scheme for the feature type
1491 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1492 if (!fcol.isSimpleColour())
1494 setting.setColour(fcol.getMaxColour().getRGB());
1495 setting.setMincolour(fcol.getMinColour().getRGB());
1496 setting.setMin(fcol.getMin());
1497 setting.setMax(fcol.getMax());
1498 setting.setColourByLabel(fcol.isColourByLabel());
1499 if (fcol.isColourByAttribute())
1501 String[] attName = fcol.getAttributeName();
1502 setting.getAttributeName().add(attName[0]);
1503 if (attName.length > 1)
1505 setting.getAttributeName().add(attName[1]);
1508 setting.setAutoScale(fcol.isAutoScaled());
1509 setting.setThreshold(fcol.getThreshold());
1510 Color noColour = fcol.getNoColour();
1511 if (noColour == null)
1513 setting.setNoValueColour(NoValueColour.NONE);
1515 else if (noColour.equals(fcol.getMaxColour()))
1517 setting.setNoValueColour(NoValueColour.MAX);
1521 setting.setNoValueColour(NoValueColour.MIN);
1523 // -1 = No threshold, 0 = Below, 1 = Above
1524 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1525 : (fcol.isBelowThreshold() ? 0 : -1));
1529 setting.setColour(fcol.getColour().getRGB());
1533 av.getFeaturesDisplayed().isVisible(featureType));
1535 .getOrder(featureType);
1538 setting.setOrder(rorder);
1540 /// fs.addSetting(setting);
1541 fs.getSetting().add(setting);
1542 settingsAdded.addElement(featureType);
1546 // is groups actually supposed to be a map here ?
1547 Iterator<String> en = fr.getFeatureGroups().iterator();
1548 Vector<String> groupsAdded = new Vector<>();
1549 while (en.hasNext())
1551 String grp = en.next();
1552 if (groupsAdded.contains(grp))
1556 Group g = new Group();
1558 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1561 fs.getGroup().add(g);
1562 groupsAdded.addElement(grp);
1564 // jms.setFeatureSettings(fs);
1565 object.setFeatureSettings(fs);
1568 if (av.hasHiddenColumns())
1570 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1571 .getHiddenColumns();
1574 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1578 Iterator<int[]> hiddenRegions = hidden.iterator();
1579 while (hiddenRegions.hasNext())
1581 int[] region = hiddenRegions.next();
1582 HiddenColumns hc = new HiddenColumns();
1583 hc.setStart(region[0]);
1584 hc.setEnd(region[1]);
1585 // view.addHiddenColumns(hc);
1586 view.getHiddenColumns().add(hc);
1590 if (calcIdSet.size() > 0)
1592 for (String calcId : calcIdSet)
1594 if (calcId.trim().length() > 0)
1596 CalcIdParam cidp = createCalcIdParam(calcId, av);
1597 // Some calcIds have no parameters.
1600 // view.addCalcIdParam(cidp);
1601 view.getCalcIdParam().add(cidp);
1607 // jms.addViewport(view);
1608 object.getViewport().add(view);
1610 // object.setJalviewModelSequence(jms);
1611 // object.getVamsasModel().addSequenceSet(vamsasSet);
1612 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1614 if (jout != null && fileName != null)
1616 // We may not want to write the object to disk,
1617 // eg we can copy the alignViewport to a new view object
1618 // using save and then load
1621 fileName = fileName.replace('\\', '/');
1622 System.out.println("Writing jar entry " + fileName);
1623 JarEntry entry = new JarEntry(fileName);
1624 jout.putNextEntry(entry);
1625 PrintWriter pout = new PrintWriter(
1626 new OutputStreamWriter(jout, UTF_8));
1627 JAXBContext jaxbContext = JAXBContext
1628 .newInstance(JalviewModel.class);
1629 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1631 // output pretty printed
1632 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1633 jaxbMarshaller.marshal(
1634 new ObjectFactory().createJalviewModel(object), pout);
1636 // jaxbMarshaller.marshal(object, pout);
1637 // marshaller.marshal(object);
1640 } catch (Exception ex)
1642 // TODO: raise error in GUI if marshalling failed.
1643 System.err.println("Error writing Jalview project");
1644 ex.printStackTrace();
1651 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1652 * for each viewer, with
1654 * <li>viewer geometry (position, size, split pane divider location)</li>
1655 * <li>index of the selected structure in the viewer (currently shows gapped
1657 * <li>the id of the annotation holding RNA secondary structure</li>
1658 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1660 * Varna viewer state is also written out (in native Varna XML) to separate
1661 * project jar entries. A separate entry is written for each RNA structure
1662 * displayed, with the naming convention
1664 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1672 * @param storeDataset
1674 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1675 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1676 boolean storeDataset)
1678 if (Desktop.desktop == null)
1682 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1683 for (int f = frames.length - 1; f > -1; f--)
1685 if (frames[f] instanceof AppVarna)
1687 AppVarna varna = (AppVarna) frames[f];
1689 * link the sequence to every viewer that is showing it and is linked to
1690 * its alignment panel
1692 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1694 String viewId = varna.getViewId();
1695 RnaViewer rna = new RnaViewer();
1696 rna.setViewId(viewId);
1697 rna.setTitle(varna.getTitle());
1698 rna.setXpos(varna.getX());
1699 rna.setYpos(varna.getY());
1700 rna.setWidth(varna.getWidth());
1701 rna.setHeight(varna.getHeight());
1702 rna.setDividerLocation(varna.getDividerLocation());
1703 rna.setSelectedRna(varna.getSelectedIndex());
1704 // jseq.addRnaViewer(rna);
1705 jseq.getRnaViewer().add(rna);
1708 * Store each Varna panel's state once in the project per sequence.
1709 * First time through only (storeDataset==false)
1711 // boolean storeSessions = false;
1712 // String sequenceViewId = viewId + seqsToIds.get(jds);
1713 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1715 // viewIds.add(sequenceViewId);
1716 // storeSessions = true;
1718 for (RnaModel model : varna.getModels())
1720 if (model.seq == jds)
1723 * VARNA saves each view (sequence or alignment secondary
1724 * structure, gapped or trimmed) as a separate XML file
1726 String jarEntryName = rnaSessions.get(model);
1727 if (jarEntryName == null)
1730 String varnaStateFile = varna.getStateInfo(model.rna);
1731 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1732 copyFileToJar(jout, varnaStateFile, jarEntryName);
1733 rnaSessions.put(model, jarEntryName);
1735 SecondaryStructure ss = new SecondaryStructure();
1736 String annotationId = varna.getAnnotation(jds).annotationId;
1737 ss.setAnnotationId(annotationId);
1738 ss.setViewerState(jarEntryName);
1739 ss.setGapped(model.gapped);
1740 ss.setTitle(model.title);
1741 // rna.addSecondaryStructure(ss);
1742 rna.getSecondaryStructure().add(ss);
1751 * Copy the contents of a file to a new entry added to the output jar
1755 * @param jarEntryName
1757 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1758 String jarEntryName)
1760 DataInputStream dis = null;
1763 File file = new File(infilePath);
1764 if (file.exists() && jout != null)
1766 dis = new DataInputStream(new FileInputStream(file));
1767 byte[] data = new byte[(int) file.length()];
1768 dis.readFully(data);
1769 writeJarEntry(jout, jarEntryName, data);
1771 } catch (Exception ex)
1773 ex.printStackTrace();
1781 } catch (IOException e)
1790 * Write the data to a new entry of given name in the output jar file
1793 * @param jarEntryName
1795 * @throws IOException
1797 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1798 byte[] data) throws IOException
1802 jarEntryName = jarEntryName.replace('\\','/');
1803 System.out.println("Writing jar entry " + jarEntryName);
1804 jout.putNextEntry(new JarEntry(jarEntryName));
1805 DataOutputStream dout = new DataOutputStream(jout);
1806 dout.write(data, 0, data.length);
1813 * Save the state of a structure viewer
1818 * the archive XML element under which to save the state
1821 * @param matchedFile
1825 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1826 Pdbids pdb, PDBEntry entry, List<String> viewIds,
1827 String matchedFile, StructureViewerBase viewFrame)
1829 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1832 * Look for any bindings for this viewer to the PDB file of interest
1833 * (including part matches excluding chain id)
1835 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1837 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1838 final String pdbId = pdbentry.getId();
1839 if (!pdbId.equals(entry.getId())
1840 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1841 .startsWith(pdbId.toLowerCase())))
1844 * not interested in a binding to a different PDB entry here
1848 if (matchedFile == null)
1850 matchedFile = pdbentry.getFile();
1852 else if (!matchedFile.equals(pdbentry.getFile()))
1855 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1856 + pdbentry.getFile());
1860 // can get at it if the ID
1861 // match is ambiguous (e.g.
1864 for (int smap = 0; smap < viewFrame.getBinding()
1865 .getSequence()[peid].length; smap++)
1867 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1868 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1870 StructureState state = new StructureState();
1871 state.setVisible(true);
1872 state.setXpos(viewFrame.getX());
1873 state.setYpos(viewFrame.getY());
1874 state.setWidth(viewFrame.getWidth());
1875 state.setHeight(viewFrame.getHeight());
1876 final String viewId = viewFrame.getViewId();
1877 state.setViewId(viewId);
1878 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1879 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1880 state.setColourByJmol(viewFrame.isColouredByViewer());
1881 state.setType(viewFrame.getViewerType().toString());
1882 // pdb.addStructureState(state);
1883 pdb.getStructureState().add(state);
1891 * Populates the AnnotationColourScheme xml for save. This captures the
1892 * settings of the options in the 'Colour by Annotation' dialog.
1895 * @param userColours
1899 private AnnotationColourScheme constructAnnotationColours(
1900 AnnotationColourGradient acg, List<UserColourScheme> userColours,
1903 AnnotationColourScheme ac = new AnnotationColourScheme();
1904 ac.setAboveThreshold(acg.getAboveThreshold());
1905 ac.setThreshold(acg.getAnnotationThreshold());
1906 // 2.10.2 save annotationId (unique) not annotation label
1907 ac.setAnnotation(acg.getAnnotation().annotationId);
1908 if (acg.getBaseColour() instanceof UserColourScheme)
1911 setUserColourScheme(acg.getBaseColour(), userColours, jm));
1916 ColourSchemeProperty.getColourName(acg.getBaseColour()));
1919 ac.setMaxColour(acg.getMaxColour().getRGB());
1920 ac.setMinColour(acg.getMinColour().getRGB());
1921 ac.setPerSequence(acg.isSeqAssociated());
1922 ac.setPredefinedColours(acg.isPredefinedColours());
1926 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1927 IdentityHashMap<SequenceGroup, String> groupRefs,
1928 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1929 SequenceSet vamsasSet)
1932 for (int i = 0; i < aa.length; i++)
1934 Annotation an = new Annotation();
1936 AlignmentAnnotation annotation = aa[i];
1937 if (annotation.annotationId != null)
1939 annotationIds.put(annotation.annotationId, annotation);
1942 an.setId(annotation.annotationId);
1944 an.setVisible(annotation.visible);
1946 an.setDescription(annotation.description);
1948 if (annotation.sequenceRef != null)
1950 // 2.9 JAL-1781 xref on sequence id rather than name
1951 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1953 if (annotation.groupRef != null)
1955 String groupIdr = groupRefs.get(annotation.groupRef);
1956 if (groupIdr == null)
1958 // make a locally unique String
1959 groupRefs.put(annotation.groupRef,
1960 groupIdr = ("" + System.currentTimeMillis()
1961 + annotation.groupRef.getName()
1962 + groupRefs.size()));
1964 an.setGroupRef(groupIdr.toString());
1967 // store all visualization attributes for annotation
1968 an.setGraphHeight(annotation.graphHeight);
1969 an.setCentreColLabels(annotation.centreColLabels);
1970 an.setScaleColLabels(annotation.scaleColLabel);
1971 an.setShowAllColLabels(annotation.showAllColLabels);
1972 an.setBelowAlignment(annotation.belowAlignment);
1974 if (annotation.graph > 0)
1977 an.setGraphType(annotation.graph);
1978 an.setGraphGroup(annotation.graphGroup);
1979 if (annotation.getThreshold() != null)
1981 ThresholdLine line = new ThresholdLine();
1982 line.setLabel(annotation.getThreshold().label);
1983 line.setValue(annotation.getThreshold().value);
1984 line.setColour(annotation.getThreshold().colour.getRGB());
1985 an.setThresholdLine(line);
1993 an.setLabel(annotation.label);
1995 if (annotation == av.getAlignmentQualityAnnot()
1996 || annotation == av.getAlignmentConservationAnnotation()
1997 || annotation == av.getAlignmentConsensusAnnotation()
1998 || annotation.autoCalculated)
2000 // new way of indicating autocalculated annotation -
2001 an.setAutoCalculated(annotation.autoCalculated);
2003 if (annotation.hasScore())
2005 an.setScore(annotation.getScore());
2008 if (annotation.getCalcId() != null)
2010 calcIdSet.add(annotation.getCalcId());
2011 an.setCalcId(annotation.getCalcId());
2013 if (annotation.hasProperties())
2015 for (String pr : annotation.getProperties())
2017 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2019 prop.setValue(annotation.getProperty(pr));
2020 // an.addProperty(prop);
2021 an.getProperty().add(prop);
2025 AnnotationElement ae;
2026 if (annotation.annotations != null)
2028 an.setScoreOnly(false);
2029 for (int a = 0; a < annotation.annotations.length; a++)
2031 if ((annotation == null) || (annotation.annotations[a] == null))
2036 ae = new AnnotationElement();
2037 if (annotation.annotations[a].description != null)
2039 ae.setDescription(annotation.annotations[a].description);
2041 if (annotation.annotations[a].displayCharacter != null)
2043 ae.setDisplayCharacter(
2044 annotation.annotations[a].displayCharacter);
2047 if (!Float.isNaN(annotation.annotations[a].value))
2049 ae.setValue(annotation.annotations[a].value);
2053 if (annotation.annotations[a].secondaryStructure > ' ')
2055 ae.setSecondaryStructure(
2056 annotation.annotations[a].secondaryStructure + "");
2059 if (annotation.annotations[a].colour != null
2060 && annotation.annotations[a].colour != java.awt.Color.black)
2062 ae.setColour(annotation.annotations[a].colour.getRGB());
2065 // an.addAnnotationElement(ae);
2066 an.getAnnotationElement().add(ae);
2067 if (annotation.autoCalculated)
2069 // only write one non-null entry into the annotation row -
2070 // sufficient to get the visualization attributes necessary to
2078 an.setScoreOnly(true);
2080 if (!storeDS || (storeDS && !annotation.autoCalculated))
2082 // skip autocalculated annotation - these are only provided for
2084 // vamsasSet.addAnnotation(an);
2085 vamsasSet.getAnnotation().add(an);
2091 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2093 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2094 if (settings != null)
2096 CalcIdParam vCalcIdParam = new CalcIdParam();
2097 vCalcIdParam.setCalcId(calcId);
2098 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2099 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2100 // generic URI allowing a third party to resolve another instance of the
2101 // service used for this calculation
2102 for (String url : settings.getServiceURLs())
2104 // vCalcIdParam.addServiceURL(urls);
2105 vCalcIdParam.getServiceURL().add(url);
2107 vCalcIdParam.setVersion("1.0");
2108 if (settings.getPreset() != null)
2110 WsParamSetI setting = settings.getPreset();
2111 vCalcIdParam.setName(setting.getName());
2112 vCalcIdParam.setDescription(setting.getDescription());
2116 vCalcIdParam.setName("");
2117 vCalcIdParam.setDescription("Last used parameters");
2119 // need to be able to recover 1) settings 2) user-defined presets or
2120 // recreate settings from preset 3) predefined settings provided by
2121 // service - or settings that can be transferred (or discarded)
2122 vCalcIdParam.setParameters(
2123 settings.getWsParamFile().replace("\n", "|\\n|"));
2124 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2125 // todo - decide if updateImmediately is needed for any projects.
2127 return vCalcIdParam;
2132 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2135 if (calcIdParam.getVersion().equals("1.0"))
2137 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2138 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2139 .getPreferredServiceFor(calcIds);
2140 if (service != null)
2142 WsParamSetI parmSet = null;
2145 parmSet = service.getParamStore().parseServiceParameterFile(
2146 calcIdParam.getName(), calcIdParam.getDescription(),
2148 calcIdParam.getParameters().replace("|\\n|", "\n"));
2149 } catch (IOException x)
2151 warn("Couldn't parse parameter data for "
2152 + calcIdParam.getCalcId(), x);
2155 List<ArgumentI> argList = null;
2156 if (calcIdParam.getName().length() > 0)
2158 parmSet = service.getParamStore()
2159 .getPreset(calcIdParam.getName());
2160 if (parmSet != null)
2162 // TODO : check we have a good match with settings in AACon -
2163 // otherwise we'll need to create a new preset
2168 argList = parmSet.getArguments();
2171 AAConSettings settings = new AAConSettings(
2172 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2173 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2174 calcIdParam.isNeedsUpdate());
2179 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2183 throw new Error(MessageManager.formatMessage(
2184 "error.unsupported_version_calcIdparam", new Object[]
2185 { calcIdParam.toString() }));
2189 * External mapping between jalview objects and objects yielding a valid and
2190 * unique object ID string. This is null for normal Jalview project IO, but
2191 * non-null when a jalview project is being read or written as part of a
2194 IdentityHashMap jv2vobj = null;
2197 * Construct a unique ID for jvobj using either existing bindings or if none
2198 * exist, the result of the hashcode call for the object.
2201 * jalview data object
2202 * @return unique ID for referring to jvobj
2204 private String makeHashCode(Object jvobj, String altCode)
2206 if (jv2vobj != null)
2208 Object id = jv2vobj.get(jvobj);
2211 return id.toString();
2213 // check string ID mappings
2214 if (jvids2vobj != null && jvobj instanceof String)
2216 id = jvids2vobj.get(jvobj);
2220 return id.toString();
2222 // give up and warn that something has gone wrong
2223 warn("Cannot find ID for object in external mapping : " + jvobj);
2229 * return local jalview object mapped to ID, if it exists
2233 * @return null or object bound to idcode
2235 private Object retrieveExistingObj(String idcode)
2237 if (idcode != null && vobj2jv != null)
2239 return vobj2jv.get(idcode);
2245 * binding from ID strings from external mapping table to jalview data model
2248 private Hashtable vobj2jv;
2250 private Sequence createVamsasSequence(String id, SequenceI jds)
2252 return createVamsasSequence(true, id, jds, null);
2255 private Sequence createVamsasSequence(boolean recurse, String id,
2256 SequenceI jds, SequenceI parentseq)
2258 Sequence vamsasSeq = new Sequence();
2259 vamsasSeq.setId(id);
2260 vamsasSeq.setName(jds.getName());
2261 vamsasSeq.setSequence(jds.getSequenceAsString());
2262 vamsasSeq.setDescription(jds.getDescription());
2263 List<DBRefEntry> dbrefs = null;
2264 if (jds.getDatasetSequence() != null)
2266 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2270 // seqId==dsseqid so we can tell which sequences really are
2271 // dataset sequences only
2272 vamsasSeq.setDsseqid(id);
2273 dbrefs = jds.getDBRefs();
2274 if (parentseq == null)
2281 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2283 DBRef dbref = new DBRef();
2284 DBRefEntry ref = dbrefs.get(d);
2285 dbref.setSource(ref.getSource());
2286 dbref.setVersion(ref.getVersion());
2287 dbref.setAccessionId(ref.getAccessionId());
2290 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2292 dbref.setMapping(mp);
2294 // vamsasSeq.addDBRef(dbref);
2295 vamsasSeq.getDBRef().add(dbref);
2301 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2302 SequenceI parentseq, SequenceI jds, boolean recurse)
2305 if (jmp.getMap() != null)
2309 jalview.util.MapList mlst = jmp.getMap();
2310 List<int[]> r = mlst.getFromRanges();
2311 for (int[] range : r)
2313 MapListFrom mfrom = new MapListFrom();
2314 mfrom.setStart(range[0]);
2315 mfrom.setEnd(range[1]);
2316 // mp.addMapListFrom(mfrom);
2317 mp.getMapListFrom().add(mfrom);
2319 r = mlst.getToRanges();
2320 for (int[] range : r)
2322 MapListTo mto = new MapListTo();
2323 mto.setStart(range[0]);
2324 mto.setEnd(range[1]);
2325 // mp.addMapListTo(mto);
2326 mp.getMapListTo().add(mto);
2328 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2329 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2330 if (jmp.getTo() != null)
2332 // MappingChoice mpc = new MappingChoice();
2334 // check/create ID for the sequence referenced by getTo()
2337 SequenceI ps = null;
2338 if (parentseq != jmp.getTo()
2339 && parentseq.getDatasetSequence() != jmp.getTo())
2341 // chaining dbref rather than a handshaking one
2342 jmpid = seqHash(ps = jmp.getTo());
2346 jmpid = seqHash(ps = parentseq);
2348 // mpc.setDseqFor(jmpid);
2349 mp.setDseqFor(jmpid);
2350 if (!seqRefIds.containsKey(jmpid))
2352 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2353 seqRefIds.put(jmpid, ps);
2357 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2360 // mp.setMappingChoice(mpc);
2366 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2367 List<UserColourScheme> userColours, JalviewModel jm)
2370 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2371 boolean newucs = false;
2372 if (!userColours.contains(ucs))
2374 userColours.add(ucs);
2377 id = "ucs" + userColours.indexOf(ucs);
2380 // actually create the scheme's entry in the XML model
2381 java.awt.Color[] colours = ucs.getColours();
2382 UserColours uc = new UserColours();
2383 // UserColourScheme jbucs = new UserColourScheme();
2384 JalviewUserColours jbucs = new JalviewUserColours();
2386 for (int i = 0; i < colours.length; i++)
2388 Colour col = new Colour();
2389 col.setName(ResidueProperties.aa[i]);
2390 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2391 // jbucs.addColour(col);
2392 jbucs.getColour().add(col);
2394 if (ucs.getLowerCaseColours() != null)
2396 colours = ucs.getLowerCaseColours();
2397 for (int i = 0; i < colours.length; i++)
2399 Colour col = new Colour();
2400 col.setName(ResidueProperties.aa[i].toLowerCase());
2401 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2402 // jbucs.addColour(col);
2403 jbucs.getColour().add(col);
2408 uc.setUserColourScheme(jbucs);
2409 // jm.addUserColours(uc);
2410 jm.getUserColours().add(uc);
2416 jalview.schemes.UserColourScheme getUserColourScheme(
2417 JalviewModel jm, String id)
2419 List<UserColours> uc = jm.getUserColours();
2420 UserColours colours = null;
2422 for (int i = 0; i < uc.length; i++)
2424 if (uc[i].getId().equals(id))
2431 for (UserColours c : uc)
2433 if (c.getId().equals(id))
2440 java.awt.Color[] newColours = new java.awt.Color[24];
2442 for (int i = 0; i < 24; i++)
2444 newColours[i] = new java.awt.Color(Integer.parseInt(
2445 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2446 colours.getUserColourScheme().getColour().get(i).getRGB(),
2450 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2453 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2455 newColours = new java.awt.Color[23];
2456 for (int i = 0; i < 23; i++)
2458 newColours[i] = new java.awt.Color(Integer.parseInt(
2459 colours.getUserColourScheme().getColour().get(i + 24)
2463 ucs.setLowerCaseColours(newColours);
2470 * contains last error message (if any) encountered by XML loader.
2472 String errorMessage = null;
2475 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2476 * exceptions are raised during project XML parsing
2478 public boolean attemptversion1parse = false;
2481 * Load a jalview project archive from a jar file
2484 * - HTTP URL or filename
2486 public AlignFrame loadJalviewAlign(final Object file)
2489 jalview.gui.AlignFrame af = null;
2493 // create list to store references for any new Jmol viewers created
2494 newStructureViewers = new Vector<>();
2495 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2496 // Workaround is to make sure caller implements the JarInputStreamProvider
2498 // so we can re-open the jar input stream for each entry.
2500 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2501 af = loadJalviewAlign(jprovider);
2504 af.setMenusForViewport();
2506 } catch (MalformedURLException e)
2508 errorMessage = "Invalid URL format for '" + file + "'";
2514 SwingUtilities.invokeAndWait(new Runnable()
2519 setLoadingFinishedForNewStructureViewers();
2522 } catch (Exception x)
2524 System.err.println("Error loading alignment: " + x.getMessage());
2530 @SuppressWarnings("unused")
2531 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2533 // BH 2018 allow for bytes already attached to File object
2535 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2536 byte[] bytes = /** @j2sNative ofile._bytes || */
2539 errorMessage = null;
2540 uniqueSetSuffix = null;
2542 viewportsAdded.clear();
2543 frefedSequence = null;
2545 if (file.startsWith("http://")) {
2546 url = new URL(file);
2548 final URL _url = url;
2549 return new jarInputStreamProvider() {
2552 public JarInputStream getJarInputStream() throws IOException {
2553 if (bytes != null) {
2554 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2555 return new JarInputStream(new ByteArrayInputStream(bytes));
2558 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2559 return new JarInputStream(_url.openStream());
2561 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2562 return new JarInputStream(new FileInputStream(file));
2567 public String getFilename() {
2571 } catch (IOException e) {
2572 e.printStackTrace();
2578 * Recover jalview session from a jalview project archive. Caller may
2579 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2580 * themselves. Any null fields will be initialised with default values,
2581 * non-null fields are left alone.
2586 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2588 errorMessage = null;
2589 if (uniqueSetSuffix == null)
2591 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2593 if (seqRefIds == null)
2597 AlignFrame af = null, _af = null;
2598 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2599 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2600 final String file = jprovider.getFilename();
2603 JarInputStream jin = null;
2604 JarEntry jarentry = null;
2609 jin = jprovider.getJarInputStream();
2610 for (int i = 0; i < entryCount; i++)
2612 jarentry = jin.getNextJarEntry();
2615 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2617 JAXBContext jc = JAXBContext
2618 .newInstance("jalview.xml.binding.jalview");
2619 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2620 .createXMLStreamReader(jin);
2621 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2622 JAXBElement<JalviewModel> jbe = um
2623 .unmarshal(streamReader, JalviewModel.class);
2624 JalviewModel object = jbe.getValue();
2626 if (true) // !skipViewport(object))
2628 _af = loadFromObject(object, file, true, jprovider);
2629 if (_af != null && object.getViewport().size() > 0)
2630 // getJalviewModelSequence().getViewportCount() > 0)
2634 // store a reference to the first view
2637 if (_af.getViewport().isGatherViewsHere())
2639 // if this is a gathered view, keep its reference since
2640 // after gathering views, only this frame will remain
2642 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2645 // Save dataset to register mappings once all resolved
2646 importedDatasets.put(
2647 af.getViewport().getAlignment().getDataset(),
2648 af.getViewport().getAlignment().getDataset());
2653 else if (jarentry != null)
2655 // Some other file here.
2658 } while (jarentry != null);
2659 resolveFrefedSequences();
2660 } catch (IOException ex)
2662 ex.printStackTrace();
2663 errorMessage = "Couldn't locate Jalview XML file : " + file;
2665 "Exception whilst loading jalview XML file : " + ex + "\n");
2666 } catch (Exception ex)
2668 System.err.println("Parsing as Jalview Version 2 file failed.");
2669 ex.printStackTrace(System.err);
2670 if (attemptversion1parse)
2672 // Is Version 1 Jar file?
2675 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2676 } catch (Exception ex2)
2678 System.err.println("Exception whilst loading as jalviewXMLV1:");
2679 ex2.printStackTrace();
2683 if (Desktop.instance != null)
2685 Desktop.instance.stopLoading();
2689 System.out.println("Successfully loaded archive file");
2692 ex.printStackTrace();
2695 "Exception whilst loading jalview XML file : " + ex + "\n");
2696 } catch (OutOfMemoryError e)
2698 // Don't use the OOM Window here
2699 errorMessage = "Out of memory loading jalview XML file";
2700 System.err.println("Out of memory whilst loading jalview XML file");
2701 e.printStackTrace();
2705 * Regather multiple views (with the same sequence set id) to the frame (if
2706 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2707 * views instead of separate frames. Note this doesn't restore a state where
2708 * some expanded views in turn have tabbed views - the last "first tab" read
2709 * in will play the role of gatherer for all.
2711 for (AlignFrame fr : gatherToThisFrame.values())
2713 Desktop.instance.gatherViews(fr);
2716 restoreSplitFrames();
2717 for (AlignmentI ds : importedDatasets.keySet())
2719 if (ds.getCodonFrames() != null)
2721 StructureSelectionManager
2722 .getStructureSelectionManager(Desktop.instance)
2723 .registerMappings(ds.getCodonFrames());
2726 if (errorMessage != null)
2731 if (Desktop.instance != null)
2733 Desktop.instance.stopLoading();
2740 * Try to reconstruct and display SplitFrame windows, where each contains
2741 * complementary dna and protein alignments. Done by pairing up AlignFrame
2742 * objects (created earlier) which have complementary viewport ids associated.
2744 protected void restoreSplitFrames()
2746 List<SplitFrame> gatherTo = new ArrayList<>();
2747 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2748 Map<String, AlignFrame> dna = new HashMap<>();
2751 * Identify the DNA alignments
2753 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2756 AlignFrame af = candidate.getValue();
2757 if (af.getViewport().getAlignment().isNucleotide())
2759 dna.put(candidate.getKey().getId(), af);
2764 * Try to match up the protein complements
2766 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2769 AlignFrame af = candidate.getValue();
2770 if (!af.getViewport().getAlignment().isNucleotide())
2772 String complementId = candidate.getKey().getComplementId();
2773 // only non-null complements should be in the Map
2774 if (complementId != null && dna.containsKey(complementId))
2776 final AlignFrame dnaFrame = dna.get(complementId);
2777 SplitFrame sf = createSplitFrame(dnaFrame, af);
2778 addedToSplitFrames.add(dnaFrame);
2779 addedToSplitFrames.add(af);
2780 dnaFrame.setMenusForViewport();
2781 af.setMenusForViewport();
2782 if (af.getViewport().isGatherViewsHere())
2791 * Open any that we failed to pair up (which shouldn't happen!) as
2792 * standalone AlignFrame's.
2794 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2797 AlignFrame af = candidate.getValue();
2798 if (!addedToSplitFrames.contains(af))
2800 Viewport view = candidate.getKey();
2801 Desktop.addInternalFrame(af, view.getTitle(),
2802 safeInt(view.getWidth()), safeInt(view.getHeight()));
2803 af.setMenusForViewport();
2804 System.err.println("Failed to restore view " + view.getTitle()
2805 + " to split frame");
2810 * Gather back into tabbed views as flagged.
2812 for (SplitFrame sf : gatherTo)
2814 Desktop.instance.gatherViews(sf);
2817 splitFrameCandidates.clear();
2821 * Construct and display one SplitFrame holding DNA and protein alignments.
2824 * @param proteinFrame
2827 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2828 AlignFrame proteinFrame)
2830 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2831 String title = MessageManager.getString("label.linked_view_title");
2832 int width = (int) dnaFrame.getBounds().getWidth();
2833 int height = (int) (dnaFrame.getBounds().getHeight()
2834 + proteinFrame.getBounds().getHeight() + 50);
2837 * SplitFrame location is saved to both enclosed frames
2839 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2840 Desktop.addInternalFrame(splitFrame, title, width, height);
2843 * And compute cDNA consensus (couldn't do earlier with consensus as
2844 * mappings were not yet present)
2846 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
2852 * check errorMessage for a valid error message and raise an error box in the
2853 * GUI or write the current errorMessage to stderr and then clear the error
2856 protected void reportErrors()
2858 reportErrors(false);
2861 protected void reportErrors(final boolean saving)
2863 if (errorMessage != null)
2865 final String finalErrorMessage = errorMessage;
2868 javax.swing.SwingUtilities.invokeLater(new Runnable()
2873 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2875 "Error " + (saving ? "saving" : "loading")
2877 JvOptionPane.WARNING_MESSAGE);
2883 System.err.println("Problem loading Jalview file: " + errorMessage);
2886 errorMessage = null;
2889 Map<String, String> alreadyLoadedPDB = new HashMap<>();
2892 * when set, local views will be updated from view stored in JalviewXML
2893 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2894 * sync if this is set to true.
2896 private final boolean updateLocalViews = false;
2899 * Returns the path to a temporary file holding the PDB file for the given PDB
2900 * id. The first time of asking, searches for a file of that name in the
2901 * Jalview project jar, and copies it to a new temporary file. Any repeat
2902 * requests just return the path to the file previously created.
2908 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2911 if (alreadyLoadedPDB.containsKey(pdbId))
2913 return alreadyLoadedPDB.get(pdbId).toString();
2916 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2918 if (tempFile != null)
2920 alreadyLoadedPDB.put(pdbId, tempFile);
2926 * Copies the jar entry of given name to a new temporary file and returns the
2927 * path to the file, or null if the entry is not found.
2930 * @param jarEntryName
2932 * a prefix for the temporary file name, must be at least three
2935 * null or original file - so new file can be given the same suffix
2939 protected String copyJarEntry(jarInputStreamProvider jprovider,
2940 String jarEntryName, String prefix, String origFile)
2942 BufferedReader in = null;
2943 PrintWriter out = null;
2944 String suffix = ".tmp";
2945 if (origFile == null)
2947 origFile = jarEntryName;
2949 int sfpos = origFile.lastIndexOf(".");
2950 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2952 suffix = "." + origFile.substring(sfpos + 1);
2956 JarInputStream jin = jprovider.getJarInputStream();
2958 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2959 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2960 * FileInputStream(jprovider)); }
2963 JarEntry entry = null;
2966 entry = jin.getNextJarEntry();
2967 } while (entry != null && !entry.getName().equals(jarEntryName));
2970 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2971 File outFile = File.createTempFile(prefix, suffix);
2972 outFile.deleteOnExit();
2973 out = new PrintWriter(new FileOutputStream(outFile));
2976 while ((data = in.readLine()) != null)
2981 String t = outFile.getAbsolutePath();
2986 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2988 } catch (Exception ex)
2990 ex.printStackTrace();
2998 } catch (IOException e)
3012 private class JvAnnotRow
3014 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3021 * persisted version of annotation row from which to take vis properties
3023 public jalview.datamodel.AlignmentAnnotation template;
3026 * original position of the annotation row in the alignment
3032 * Load alignment frame from jalview XML DOM object
3034 * @param jalviewModel
3037 * filename source string
3038 * @param loadTreesAndStructures
3039 * when false only create Viewport
3041 * data source provider
3042 * @return alignment frame created from view stored in DOM
3044 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3045 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3047 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3048 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3050 // JalviewModelSequence jms = object.getJalviewModelSequence();
3052 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3054 Viewport view = (jalviewModel.getViewport().size() > 0)
3055 ? jalviewModel.getViewport().get(0)
3058 // ////////////////////////////////
3061 List<SequenceI> hiddenSeqs = null;
3063 List<SequenceI> tmpseqs = new ArrayList<>();
3065 boolean multipleView = false;
3066 SequenceI referenceseqForView = null;
3067 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3068 List<JSeq> jseqs = jalviewModel.getJSeq();
3069 int vi = 0; // counter in vamsasSeq array
3070 for (int i = 0; i < jseqs.size(); i++)
3072 JSeq jseq = jseqs.get(i);
3073 String seqId = jseq.getId();
3075 SequenceI tmpSeq = seqRefIds.get(seqId);
3078 if (!incompleteSeqs.containsKey(seqId))
3080 // may not need this check, but keep it for at least 2.9,1 release
3081 if (tmpSeq.getStart() != jseq.getStart()
3082 || tmpSeq.getEnd() != jseq.getEnd())
3085 "Warning JAL-2154 regression: updating start/end for sequence "
3086 + tmpSeq.toString() + " to " + jseq);
3091 incompleteSeqs.remove(seqId);
3093 if (vamsasSeqs.size() > vi
3094 && vamsasSeqs.get(vi).getId().equals(seqId))
3096 // most likely we are reading a dataset XML document so
3097 // update from vamsasSeq section of XML for this sequence
3098 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3099 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3100 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3105 // reading multiple views, so vamsasSeq set is a subset of JSeq
3106 multipleView = true;
3108 tmpSeq.setStart(jseq.getStart());
3109 tmpSeq.setEnd(jseq.getEnd());
3110 tmpseqs.add(tmpSeq);
3114 Sequence vamsasSeq = vamsasSeqs.get(vi);
3115 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3116 vamsasSeq.getSequence());
3117 tmpSeq.setDescription(vamsasSeq.getDescription());
3118 tmpSeq.setStart(jseq.getStart());
3119 tmpSeq.setEnd(jseq.getEnd());
3120 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3121 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3122 tmpseqs.add(tmpSeq);
3126 if (safeBoolean(jseq.isViewreference()))
3128 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3131 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3133 if (hiddenSeqs == null)
3135 hiddenSeqs = new ArrayList<>();
3138 hiddenSeqs.add(tmpSeq);
3143 // Create the alignment object from the sequence set
3144 // ///////////////////////////////
3145 SequenceI[] orderedSeqs = tmpseqs
3146 .toArray(new SequenceI[tmpseqs.size()]);
3148 AlignmentI al = null;
3149 // so we must create or recover the dataset alignment before going further
3150 // ///////////////////////////////
3151 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3153 // older jalview projects do not have a dataset - so creat alignment and
3155 al = new Alignment(orderedSeqs);
3156 al.setDataset(null);
3160 boolean isdsal = jalviewModel.getViewport().isEmpty();
3163 // we are importing a dataset record, so
3164 // recover reference to an alignment already materialsed as dataset
3165 al = getDatasetFor(vamsasSet.getDatasetId());
3169 // materialse the alignment
3170 al = new Alignment(orderedSeqs);
3174 addDatasetRef(vamsasSet.getDatasetId(), al);
3177 // finally, verify all data in vamsasSet is actually present in al
3178 // passing on flag indicating if it is actually a stored dataset
3179 recoverDatasetFor(vamsasSet, al, isdsal);
3182 if (referenceseqForView != null)
3184 al.setSeqrep(referenceseqForView);
3186 // / Add the alignment properties
3187 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3189 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3191 al.setProperty(ssp.getKey(), ssp.getValue());
3194 // ///////////////////////////////
3196 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3199 // load sequence features, database references and any associated PDB
3200 // structures for the alignment
3202 // prior to 2.10, this part would only be executed the first time a
3203 // sequence was encountered, but not afterwards.
3204 // now, for 2.10 projects, this is also done if the xml doc includes
3205 // dataset sequences not actually present in any particular view.
3207 for (int i = 0; i < vamsasSeqs.size(); i++)
3209 JSeq jseq = jseqs.get(i);
3210 if (jseq.getFeatures().size() > 0)
3212 List<Feature> features = jseq.getFeatures();
3213 for (int f = 0; f < features.size(); f++)
3215 Feature feat = features.get(f);
3216 SequenceFeature sf = new SequenceFeature(feat.getType(),
3217 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3218 safeFloat(feat.getScore()), feat.getFeatureGroup());
3219 sf.setStatus(feat.getStatus());
3222 * load any feature attributes - include map-valued attributes
3224 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3225 for (int od = 0; od < feat.getOtherData().size(); od++)
3227 OtherData keyValue = feat.getOtherData().get(od);
3228 String attributeName = keyValue.getKey();
3229 String attributeValue = keyValue.getValue();
3230 if (attributeName.startsWith("LINK"))
3232 sf.addLink(attributeValue);
3236 String subAttribute = keyValue.getKey2();
3237 if (subAttribute == null)
3239 // simple string-valued attribute
3240 sf.setValue(attributeName, attributeValue);
3244 // attribute 'key' has sub-attribute 'key2'
3245 if (!mapAttributes.containsKey(attributeName))
3247 mapAttributes.put(attributeName, new HashMap<>());
3249 mapAttributes.get(attributeName).put(subAttribute,
3254 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3257 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3260 // adds feature to datasequence's feature set (since Jalview 2.10)
3261 al.getSequenceAt(i).addSequenceFeature(sf);
3264 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3266 // adds dbrefs to datasequence's set (since Jalview 2.10)
3268 al.getSequenceAt(i).getDatasetSequence() == null
3269 ? al.getSequenceAt(i)
3270 : al.getSequenceAt(i).getDatasetSequence(),
3273 if (jseq.getPdbids().size() > 0)
3275 List<Pdbids> ids = jseq.getPdbids();
3276 for (int p = 0; p < ids.size(); p++)
3278 Pdbids pdbid = ids.get(p);
3279 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3280 entry.setId(pdbid.getId());
3281 if (pdbid.getType() != null)
3283 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3285 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3289 entry.setType(PDBEntry.Type.FILE);
3292 // jprovider is null when executing 'New View'
3293 if (pdbid.getFile() != null && jprovider != null)
3295 if (!pdbloaded.containsKey(pdbid.getFile()))
3297 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3302 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3306 if (pdbid.getPdbentryItem() != null)
3308 for (PdbentryItem item : pdbid.getPdbentryItem())
3310 for (Property pr : item.getProperty())
3312 entry.setProperty(pr.getName(), pr.getValue());
3317 for (Property prop : pdbid.getProperty())
3319 entry.setProperty(prop.getName(), prop.getValue());
3321 StructureSelectionManager
3322 .getStructureSelectionManager(Desktop.instance)
3323 .registerPDBEntry(entry);
3324 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3325 if (al.getSequenceAt(i).getDatasetSequence() != null)
3327 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3331 al.getSequenceAt(i).addPDBId(entry);
3336 } // end !multipleview
3338 // ///////////////////////////////
3339 // LOAD SEQUENCE MAPPINGS
3341 if (vamsasSet.getAlcodonFrame().size() > 0)
3343 // TODO Potentially this should only be done once for all views of an
3345 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3346 for (int i = 0; i < alc.size(); i++)
3348 AlignedCodonFrame cf = new AlignedCodonFrame();
3349 if (alc.get(i).getAlcodMap().size() > 0)
3351 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3352 for (int m = 0; m < maps.size(); m++)
3354 AlcodMap map = maps.get(m);
3355 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3357 jalview.datamodel.Mapping mapping = null;
3358 // attach to dna sequence reference.
3359 if (map.getMapping() != null)
3361 mapping = addMapping(map.getMapping());
3362 if (dnaseq != null && mapping.getTo() != null)
3364 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3370 newAlcodMapRef(map.getDnasq(), cf, mapping));
3374 al.addCodonFrame(cf);
3379 // ////////////////////////////////
3381 List<JvAnnotRow> autoAlan = new ArrayList<>();
3384 * store any annotations which forward reference a group's ID
3386 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3388 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3390 List<Annotation> an = vamsasSet.getAnnotation();
3392 for (int i = 0; i < an.size(); i++)
3394 Annotation annotation = an.get(i);
3397 * test if annotation is automatically calculated for this view only
3399 boolean autoForView = false;
3400 if (annotation.getLabel().equals("Quality")
3401 || annotation.getLabel().equals("Conservation")
3402 || annotation.getLabel().equals("Consensus"))
3404 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3406 // JAXB has no has() test; schema defaults value to false
3407 // if (!annotation.hasAutoCalculated())
3409 // annotation.setAutoCalculated(true);
3412 if (autoForView || annotation.isAutoCalculated())
3414 // remove ID - we don't recover annotation from other views for
3415 // view-specific annotation
3416 annotation.setId(null);
3419 // set visibility for other annotation in this view
3420 String annotationId = annotation.getId();
3421 if (annotationId != null && annotationIds.containsKey(annotationId))
3423 AlignmentAnnotation jda = annotationIds.get(annotationId);
3424 // in principle Visible should always be true for annotation displayed
3425 // in multiple views
3426 if (annotation.isVisible() != null)
3428 jda.visible = annotation.isVisible();
3431 al.addAnnotation(jda);
3435 // Construct new annotation from model.
3436 List<AnnotationElement> ae = annotation.getAnnotationElement();
3437 jalview.datamodel.Annotation[] anot = null;
3438 java.awt.Color firstColour = null;
3440 if (!annotation.isScoreOnly())
3442 anot = new jalview.datamodel.Annotation[al.getWidth()];
3443 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3445 AnnotationElement annElement = ae.get(aa);
3446 anpos = annElement.getPosition();
3448 if (anpos >= anot.length)
3453 float value = safeFloat(annElement.getValue());
3454 anot[anpos] = new jalview.datamodel.Annotation(
3455 annElement.getDisplayCharacter(),
3456 annElement.getDescription(),
3457 (annElement.getSecondaryStructure() == null
3458 || annElement.getSecondaryStructure()
3462 .getSecondaryStructure()
3465 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3466 if (firstColour == null)
3468 firstColour = anot[anpos].colour;
3472 jalview.datamodel.AlignmentAnnotation jaa = null;
3474 if (annotation.isGraph())
3476 float llim = 0, hlim = 0;
3477 // if (autoForView || an[i].isAutoCalculated()) {
3480 jaa = new jalview.datamodel.AlignmentAnnotation(
3481 annotation.getLabel(), annotation.getDescription(), anot,
3482 llim, hlim, safeInt(annotation.getGraphType()));
3484 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3485 jaa._linecolour = firstColour;
3486 if (annotation.getThresholdLine() != null)
3488 jaa.setThreshold(new jalview.datamodel.GraphLine(
3489 safeFloat(annotation.getThresholdLine().getValue()),
3490 annotation.getThresholdLine().getLabel(),
3491 new java.awt.Color(safeInt(
3492 annotation.getThresholdLine().getColour()))));
3494 if (autoForView || annotation.isAutoCalculated())
3496 // Hardwire the symbol display line to ensure that labels for
3497 // histograms are displayed
3503 jaa = new jalview.datamodel.AlignmentAnnotation(
3504 annotation.getLabel(), annotation.getDescription(), anot);
3505 jaa._linecolour = firstColour;
3507 // register new annotation
3508 if (annotation.getId() != null)
3510 annotationIds.put(annotation.getId(), jaa);
3511 jaa.annotationId = annotation.getId();
3513 // recover sequence association
3514 String sequenceRef = annotation.getSequenceRef();
3515 if (sequenceRef != null)
3517 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3518 SequenceI sequence = seqRefIds.get(sequenceRef);
3519 if (sequence == null)
3521 // in pre-2.9 projects sequence ref is to sequence name
3522 sequence = al.findName(sequenceRef);
3524 if (sequence != null)
3526 jaa.createSequenceMapping(sequence, 1, true);
3527 sequence.addAlignmentAnnotation(jaa);
3530 // and make a note of any group association
3531 if (annotation.getGroupRef() != null
3532 && annotation.getGroupRef().length() > 0)
3534 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3535 .get(annotation.getGroupRef());
3538 aal = new ArrayList<>();
3539 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3544 if (annotation.getScore() != null)
3546 jaa.setScore(annotation.getScore().doubleValue());
3548 if (annotation.isVisible() != null)
3550 jaa.visible = annotation.isVisible().booleanValue();
3553 if (annotation.isCentreColLabels() != null)
3555 jaa.centreColLabels = annotation.isCentreColLabels()
3559 if (annotation.isScaleColLabels() != null)
3561 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3563 if (annotation.isAutoCalculated())
3565 // newer files have an 'autoCalculated' flag and store calculation
3566 // state in viewport properties
3567 jaa.autoCalculated = true; // means annotation will be marked for
3568 // update at end of load.
3570 if (annotation.getGraphHeight() != null)
3572 jaa.graphHeight = annotation.getGraphHeight().intValue();
3574 jaa.belowAlignment = annotation.isBelowAlignment();
3575 jaa.setCalcId(annotation.getCalcId());
3576 if (annotation.getProperty().size() > 0)
3578 for (Annotation.Property prop : annotation
3581 jaa.setProperty(prop.getName(), prop.getValue());
3584 if (jaa.autoCalculated)
3586 autoAlan.add(new JvAnnotRow(i, jaa));
3589 // if (!autoForView)
3591 // add autocalculated group annotation and any user created annotation
3593 al.addAnnotation(jaa);
3597 // ///////////////////////
3599 // Create alignment markup and styles for this view
3600 if (jalviewModel.getJGroup().size() > 0)
3602 List<JGroup> groups = jalviewModel.getJGroup();
3603 boolean addAnnotSchemeGroup = false;
3604 for (int i = 0; i < groups.size(); i++)
3606 JGroup jGroup = groups.get(i);
3607 ColourSchemeI cs = null;
3608 if (jGroup.getColour() != null)
3610 if (jGroup.getColour().startsWith("ucs"))
3612 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3614 else if (jGroup.getColour().equals("AnnotationColourGradient")
3615 && jGroup.getAnnotationColours() != null)
3617 addAnnotSchemeGroup = true;
3621 cs = ColourSchemeProperty.getColourScheme(al,
3622 jGroup.getColour());
3625 int pidThreshold = safeInt(jGroup.getPidThreshold());
3627 Vector<SequenceI> seqs = new Vector<>();
3629 for (int s = 0; s < jGroup.getSeq().size(); s++)
3631 String seqId = jGroup.getSeq().get(s);
3632 SequenceI ts = seqRefIds.get(seqId);
3636 seqs.addElement(ts);
3640 if (seqs.size() < 1)
3645 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3646 safeBoolean(jGroup.isDisplayBoxes()),
3647 safeBoolean(jGroup.isDisplayText()),
3648 safeBoolean(jGroup.isColourText()),
3649 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3650 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3651 sg.getGroupColourScheme()
3652 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3653 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3655 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3656 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3657 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3658 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3659 // attributes with a default in the schema are never null
3660 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3661 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3662 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3663 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3664 if (jGroup.getConsThreshold() != null
3665 && jGroup.getConsThreshold().intValue() != 0)
3667 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3670 c.verdict(false, 25);
3671 sg.cs.setConservation(c);
3674 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3676 // re-instate unique group/annotation row reference
3677 List<AlignmentAnnotation> jaal = groupAnnotRefs
3678 .get(jGroup.getId());
3681 for (AlignmentAnnotation jaa : jaal)
3684 if (jaa.autoCalculated)
3686 // match up and try to set group autocalc alignment row for this
3688 if (jaa.label.startsWith("Consensus for "))
3690 sg.setConsensus(jaa);
3692 // match up and try to set group autocalc alignment row for this
3694 if (jaa.label.startsWith("Conservation for "))
3696 sg.setConservationRow(jaa);
3703 if (addAnnotSchemeGroup)
3705 // reconstruct the annotation colourscheme
3706 sg.setColourScheme(constructAnnotationColour(
3707 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3713 // only dataset in this model, so just return.
3716 // ///////////////////////////////
3719 // If we just load in the same jar file again, the sequenceSetId
3720 // will be the same, and we end up with multiple references
3721 // to the same sequenceSet. We must modify this id on load
3722 // so that each load of the file gives a unique id
3723 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3724 String viewId = (view.getId() == null ? null
3725 : view.getId() + uniqueSetSuffix);
3726 AlignFrame af = null;
3727 AlignViewport av = null;
3728 // now check to see if we really need to create a new viewport.
3729 if (multipleView && viewportsAdded.size() == 0)
3731 // We recovered an alignment for which a viewport already exists.
3732 // TODO: fix up any settings necessary for overlaying stored state onto
3733 // state recovered from another document. (may not be necessary).
3734 // we may need a binding from a viewport in memory to one recovered from
3736 // and then recover its containing af to allow the settings to be applied.
3737 // TODO: fix for vamsas demo
3739 "About to recover a viewport for existing alignment: Sequence set ID is "
3741 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3742 if (seqsetobj != null)
3744 if (seqsetobj instanceof String)
3746 uniqueSeqSetId = (String) seqsetobj;
3748 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3754 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3760 * indicate that annotation colours are applied across all groups (pre
3761 * Jalview 2.8.1 behaviour)
3763 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3764 jalviewModel.getVersion());
3766 AlignmentPanel ap = null;
3767 boolean isnewview = true;
3770 // Check to see if this alignment already has a view id == viewId
3771 jalview.gui.AlignmentPanel views[] = Desktop
3772 .getAlignmentPanels(uniqueSeqSetId);
3773 if (views != null && views.length > 0)
3775 for (int v = 0; v < views.length; v++)
3777 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3779 // recover the existing alignpanel, alignframe, viewport
3780 af = views[v].alignFrame;
3783 // TODO: could even skip resetting view settings if we don't want to
3784 // change the local settings from other jalview processes
3793 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
3794 uniqueSeqSetId, viewId, autoAlan);
3795 av = af.getViewport();
3800 * Load any trees, PDB structures and viewers
3802 * Not done if flag is false (when this method is used for New View)
3804 if (loadTreesAndStructures)
3806 loadTrees(jalviewModel, view, af, av, ap);
3807 loadPDBStructures(jprovider, jseqs, af, ap);
3808 loadRnaViewers(jprovider, jseqs, ap);
3810 // and finally return.
3815 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3816 * panel is restored from separate jar entries, two (gapped and trimmed) per
3817 * sequence and secondary structure.
3819 * Currently each viewer shows just one sequence and structure (gapped and
3820 * trimmed), however this method is designed to support multiple sequences or
3821 * structures in viewers if wanted in future.
3827 private void loadRnaViewers(jarInputStreamProvider jprovider,
3828 List<JSeq> jseqs, AlignmentPanel ap)
3831 * scan the sequences for references to viewers; create each one the first
3832 * time it is referenced, add Rna models to existing viewers
3834 for (JSeq jseq : jseqs)
3836 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
3838 RnaViewer viewer = jseq.getRnaViewer().get(i);
3839 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3842 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
3844 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
3845 SequenceI seq = seqRefIds.get(jseq.getId());
3846 AlignmentAnnotation ann = this.annotationIds
3847 .get(ss.getAnnotationId());
3850 * add the structure to the Varna display (with session state copied
3851 * from the jar to a temporary file)
3853 boolean gapped = safeBoolean(ss.isGapped());
3854 String rnaTitle = ss.getTitle();
3855 String sessionState = ss.getViewerState();
3856 String tempStateFile = copyJarEntry(jprovider, sessionState,
3858 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3859 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3861 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
3867 * Locate and return an already instantiated matching AppVarna, or create one
3871 * @param viewIdSuffix
3875 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3876 String viewIdSuffix, AlignmentPanel ap)
3879 * on each load a suffix is appended to the saved viewId, to avoid conflicts
3880 * if load is repeated
3882 String postLoadId = viewer.getViewId() + viewIdSuffix;
3883 for (JInternalFrame frame : getAllFrames())
3885 if (frame instanceof AppVarna)
3887 AppVarna varna = (AppVarna) frame;
3888 if (postLoadId.equals(varna.getViewId()))
3890 // this viewer is already instantiated
3891 // could in future here add ap as another 'parent' of the
3892 // AppVarna window; currently just 1-to-many
3899 * viewer not found - make it
3901 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3902 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
3903 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
3904 safeInt(viewer.getDividerLocation()));
3905 AppVarna varna = new AppVarna(model, ap);
3911 * Load any saved trees
3919 protected void loadTrees(JalviewModel jm, Viewport view,
3920 AlignFrame af, AlignViewport av, AlignmentPanel ap)
3922 // TODO result of automated refactoring - are all these parameters needed?
3925 for (int t = 0; t < jm.getTree().size(); t++)
3928 Tree tree = jm.getTree().get(t);
3930 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3933 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
3934 tree.getTitle(), safeInt(tree.getWidth()),
3935 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
3936 safeInt(tree.getYpos()));
3937 if (tree.getId() != null)
3939 // perhaps bind the tree id to something ?
3944 // update local tree attributes ?
3945 // TODO: should check if tp has been manipulated by user - if so its
3946 // settings shouldn't be modified
3947 tp.setTitle(tree.getTitle());
3948 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
3949 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
3950 safeInt(tree.getHeight())));
3951 tp.setViewport(av); // af.viewport;
3952 // TODO: verify 'associate with all views' works still
3953 tp.getTreeCanvas().setViewport(av); // af.viewport;
3954 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
3959 warn("There was a problem recovering stored Newick tree: \n"
3960 + tree.getNewick());
3964 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
3965 tp.fitToWindow_actionPerformed(null);
3967 if (tree.getFontName() != null)
3970 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
3971 safeInt(tree.getFontSize())));
3976 new Font(view.getFontName(), safeInt(view.getFontStyle()),
3977 safeInt(view.getFontSize())));
3980 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
3981 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
3982 tp.showDistances(safeBoolean(tree.isShowDistances()));
3984 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
3986 if (safeBoolean(tree.isCurrentTree()))
3988 af.getViewport().setCurrentTree(tp.getTree());
3992 } catch (Exception ex)
3994 ex.printStackTrace();
3999 * Load and link any saved structure viewers.
4006 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4007 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4010 * Run through all PDB ids on the alignment, and collect mappings between
4011 * distinct view ids and all sequences referring to that view.
4013 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4015 for (int i = 0; i < jseqs.size(); i++)
4017 JSeq jseq = jseqs.get(i);
4018 if (jseq.getPdbids().size() > 0)
4020 List<Pdbids> ids = jseq.getPdbids();
4021 for (int p = 0; p < ids.size(); p++)
4023 Pdbids pdbid = ids.get(p);
4024 final int structureStateCount = pdbid.getStructureState().size();
4025 for (int s = 0; s < structureStateCount; s++)
4027 // check to see if we haven't already created this structure view
4028 final StructureState structureState = pdbid
4029 .getStructureState().get(s);
4030 String sviewid = (structureState.getViewId() == null) ? null
4031 : structureState.getViewId() + uniqueSetSuffix;
4032 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4033 // Originally : pdbid.getFile()
4034 // : TODO: verify external PDB file recovery still works in normal
4035 // jalview project load
4037 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4038 jpdb.setId(pdbid.getId());
4040 int x = safeInt(structureState.getXpos());
4041 int y = safeInt(structureState.getYpos());
4042 int width = safeInt(structureState.getWidth());
4043 int height = safeInt(structureState.getHeight());
4045 // Probably don't need to do this anymore...
4046 // Desktop.desktop.getComponentAt(x, y);
4047 // TODO: NOW: check that this recovers the PDB file correctly.
4048 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4050 jalview.datamodel.SequenceI seq = seqRefIds
4051 .get(jseq.getId() + "");
4052 if (sviewid == null)
4054 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4057 if (!structureViewers.containsKey(sviewid))
4059 structureViewers.put(sviewid,
4060 new StructureViewerModel(x, y, width, height, false,
4061 false, true, structureState.getViewId(),
4062 structureState.getType()));
4063 // Legacy pre-2.7 conversion JAL-823 :
4064 // do not assume any view has to be linked for colour by
4068 // assemble String[] { pdb files }, String[] { id for each
4069 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4070 // seqs_file 2}, boolean[] {
4071 // linkAlignPanel,superposeWithAlignpanel}} from hash
4072 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4073 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4074 || structureState.isAlignwithAlignPanel());
4077 * Default colour by linked panel to false if not specified (e.g.
4078 * for pre-2.7 projects)
4080 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4081 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4082 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4085 * Default colour by viewer to true if not specified (e.g. for
4088 boolean colourByViewer = jmoldat.isColourByViewer();
4089 colourByViewer &= structureState.isColourByJmol();
4090 jmoldat.setColourByViewer(colourByViewer);
4092 if (jmoldat.getStateData().length() < structureState
4093 .getValue()/*Content()*/.length())
4095 jmoldat.setStateData(structureState.getValue());// Content());
4097 if (pdbid.getFile() != null)
4099 File mapkey = new File(pdbid.getFile());
4100 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4101 if (seqstrmaps == null)
4103 jmoldat.getFileData().put(mapkey,
4104 seqstrmaps = jmoldat.new StructureData(pdbFile,
4107 if (!seqstrmaps.getSeqList().contains(seq))
4109 seqstrmaps.getSeqList().add(seq);
4115 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");
4122 // Instantiate the associated structure views
4123 for (Entry<String, StructureViewerModel> entry : structureViewers
4128 createOrLinkStructureViewer(entry, af, ap, jprovider);
4129 } catch (Exception e)
4132 "Error loading structure viewer: " + e.getMessage());
4133 // failed - try the next one
4145 protected void createOrLinkStructureViewer(
4146 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4147 AlignmentPanel ap, jarInputStreamProvider jprovider)
4149 final StructureViewerModel stateData = viewerData.getValue();
4152 * Search for any viewer windows already open from other alignment views
4153 * that exactly match the stored structure state
4155 StructureViewerBase comp = findMatchingViewer(viewerData);
4159 linkStructureViewer(ap, comp, stateData);
4164 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4165 * "viewer_"+stateData.viewId
4167 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4169 createChimeraViewer(viewerData, af, jprovider);
4174 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4176 createJmolViewer(viewerData, af, jprovider);
4181 * Create a new Chimera viewer.
4187 protected void createChimeraViewer(
4188 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4189 jarInputStreamProvider jprovider)
4191 StructureViewerModel data = viewerData.getValue();
4192 String chimeraSessionFile = data.getStateData();
4195 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4197 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4198 * 'uniquified' sviewid used to reconstruct the viewer here
4200 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4201 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4204 Set<Entry<File, StructureData>> fileData = data.getFileData()
4206 List<PDBEntry> pdbs = new ArrayList<>();
4207 List<SequenceI[]> allseqs = new ArrayList<>();
4208 for (Entry<File, StructureData> pdb : fileData)
4210 String filePath = pdb.getValue().getFilePath();
4211 String pdbId = pdb.getValue().getPdbId();
4212 // pdbs.add(new PDBEntry(filePath, pdbId));
4213 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4214 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4215 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4219 boolean colourByChimera = data.isColourByViewer();
4220 boolean colourBySequence = data.isColourWithAlignPanel();
4222 // TODO use StructureViewer as a factory here, see JAL-1761
4223 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4224 final SequenceI[][] seqsArray = allseqs
4225 .toArray(new SequenceI[allseqs.size()][]);
4226 String newViewId = viewerData.getKey();
4228 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4229 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4230 colourBySequence, newViewId);
4231 cvf.setSize(data.getWidth(), data.getHeight());
4232 cvf.setLocation(data.getX(), data.getY());
4236 * Create a new Jmol window. First parse the Jmol state to translate filenames
4237 * loaded into the view, and record the order in which files are shown in the
4238 * Jmol view, so we can add the sequence mappings in same order.
4244 protected void createJmolViewer(
4245 final Entry<String, StructureViewerModel> viewerData,
4246 AlignFrame af, jarInputStreamProvider jprovider)
4248 final StructureViewerModel svattrib = viewerData.getValue();
4249 String state = svattrib.getStateData();
4252 * Pre-2.9: state element value is the Jmol state string
4254 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4257 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4259 state = readJarEntry(jprovider,
4260 getViewerJarEntryName(svattrib.getViewId()));
4263 List<String> pdbfilenames = new ArrayList<>();
4264 List<SequenceI[]> seqmaps = new ArrayList<>();
4265 List<String> pdbids = new ArrayList<>();
4266 StringBuilder newFileLoc = new StringBuilder(64);
4267 int cp = 0, ncp, ecp;
4268 Map<File, StructureData> oldFiles = svattrib.getFileData();
4269 while ((ncp = state.indexOf("load ", cp)) > -1)
4273 // look for next filename in load statement
4274 newFileLoc.append(state.substring(cp,
4275 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4276 String oldfilenam = state.substring(ncp,
4277 ecp = state.indexOf("\"", ncp));
4278 // recover the new mapping data for this old filename
4279 // have to normalize filename - since Jmol and jalview do
4281 // translation differently.
4282 StructureData filedat = oldFiles.get(new File(oldfilenam));
4283 if (filedat == null)
4285 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4286 filedat = oldFiles.get(new File(reformatedOldFilename));
4288 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4289 pdbfilenames.add(filedat.getFilePath());
4290 pdbids.add(filedat.getPdbId());
4291 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4292 newFileLoc.append("\"");
4293 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4294 // look for next file statement.
4295 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4299 // just append rest of state
4300 newFileLoc.append(state.substring(cp));
4304 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4305 newFileLoc = new StringBuilder(state);
4306 newFileLoc.append("; load append ");
4307 for (File id : oldFiles.keySet())
4309 // add this and any other pdb files that should be present in
4311 StructureData filedat = oldFiles.get(id);
4312 newFileLoc.append(filedat.getFilePath());
4313 pdbfilenames.add(filedat.getFilePath());
4314 pdbids.add(filedat.getPdbId());
4315 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4316 newFileLoc.append(" \"");
4317 newFileLoc.append(filedat.getFilePath());
4318 newFileLoc.append("\"");
4321 newFileLoc.append(";");
4324 if (newFileLoc.length() == 0)
4328 int histbug = newFileLoc.indexOf("history = ");
4332 * change "history = [true|false];" to "history = [1|0];"
4335 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4336 String val = (diff == -1) ? null
4337 : newFileLoc.substring(histbug, diff);
4338 if (val != null && val.length() >= 4)
4340 if (val.contains("e")) // eh? what can it be?
4342 if (val.trim().equals("true"))
4350 newFileLoc.replace(histbug, diff, val);
4355 final String[] pdbf = pdbfilenames
4356 .toArray(new String[pdbfilenames.size()]);
4357 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4358 final SequenceI[][] sq = seqmaps
4359 .toArray(new SequenceI[seqmaps.size()][]);
4360 final String fileloc = newFileLoc.toString();
4361 final String sviewid = viewerData.getKey();
4362 final AlignFrame alf = af;
4363 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4364 svattrib.getWidth(), svattrib.getHeight());
4367 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4372 JalviewStructureDisplayI sview = null;
4375 sview = new StructureViewer(
4376 alf.alignPanel.getStructureSelectionManager())
4377 .createView(StructureViewer.ViewerType.JMOL,
4378 pdbf, id, sq, alf.alignPanel, svattrib,
4379 fileloc, rect, sviewid);
4380 addNewStructureViewer(sview);
4381 } catch (OutOfMemoryError ex)
4383 new OOMWarning("restoring structure view for PDB id " + id,
4384 (OutOfMemoryError) ex.getCause());
4385 if (sview != null && sview.isVisible())
4387 sview.closeViewer(false);
4388 sview.setVisible(false);
4394 } catch (InvocationTargetException ex)
4396 warn("Unexpected error when opening Jmol view.", ex);
4398 } catch (InterruptedException e)
4400 // e.printStackTrace();
4406 * Generates a name for the entry in the project jar file to hold state
4407 * information for a structure viewer
4412 protected String getViewerJarEntryName(String viewId)
4414 return VIEWER_PREFIX + viewId;
4418 * Returns any open frame that matches given structure viewer data. The match
4419 * is based on the unique viewId, or (for older project versions) the frame's
4425 protected StructureViewerBase findMatchingViewer(
4426 Entry<String, StructureViewerModel> viewerData)
4428 final String sviewid = viewerData.getKey();
4429 final StructureViewerModel svattrib = viewerData.getValue();
4430 StructureViewerBase comp = null;
4431 JInternalFrame[] frames = getAllFrames();
4432 for (JInternalFrame frame : frames)
4434 if (frame instanceof StructureViewerBase)
4437 * Post jalview 2.4 schema includes structure view id
4439 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4442 comp = (StructureViewerBase) frame;
4443 break; // break added in 2.9
4446 * Otherwise test for matching position and size of viewer frame
4448 else if (frame.getX() == svattrib.getX()
4449 && frame.getY() == svattrib.getY()
4450 && frame.getHeight() == svattrib.getHeight()
4451 && frame.getWidth() == svattrib.getWidth())
4453 comp = (StructureViewerBase) frame;
4454 // no break in faint hope of an exact match on viewId
4462 * Link an AlignmentPanel to an existing structure viewer.
4467 * @param useinViewerSuperpos
4468 * @param usetoColourbyseq
4469 * @param viewerColouring
4471 protected void linkStructureViewer(AlignmentPanel ap,
4472 StructureViewerBase viewer, StructureViewerModel stateData)
4474 // NOTE: if the jalview project is part of a shared session then
4475 // view synchronization should/could be done here.
4477 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4478 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4479 final boolean viewerColouring = stateData.isColourByViewer();
4480 Map<File, StructureData> oldFiles = stateData.getFileData();
4483 * Add mapping for sequences in this view to an already open viewer
4485 final AAStructureBindingModel binding = viewer.getBinding();
4486 for (File id : oldFiles.keySet())
4488 // add this and any other pdb files that should be present in the
4490 StructureData filedat = oldFiles.get(id);
4491 String pdbFile = filedat.getFilePath();
4492 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4493 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4495 binding.addSequenceForStructFile(pdbFile, seq);
4497 // and add the AlignmentPanel's reference to the view panel
4498 viewer.addAlignmentPanel(ap);
4499 if (useinViewerSuperpos)
4501 viewer.useAlignmentPanelForSuperposition(ap);
4505 viewer.excludeAlignmentPanelForSuperposition(ap);
4507 if (usetoColourbyseq)
4509 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4513 viewer.excludeAlignmentPanelForColourbyseq(ap);
4518 * Get all frames within the Desktop.
4522 protected JInternalFrame[] getAllFrames()
4524 JInternalFrame[] frames = null;
4525 // TODO is this necessary - is it safe - risk of hanging?
4530 frames = Desktop.desktop.getAllFrames();
4531 } catch (ArrayIndexOutOfBoundsException e)
4533 // occasional No such child exceptions are thrown here...
4537 } catch (InterruptedException f)
4541 } while (frames == null);
4546 * Answers true if 'version' is equal to or later than 'supported', where each
4547 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4548 * changes. Development and test values for 'version' are leniently treated
4552 * - minimum version we are comparing against
4554 * - version of data being processsed
4557 public static boolean isVersionStringLaterThan(String supported,
4560 if (supported == null || version == null
4561 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4562 || version.equalsIgnoreCase("Test")
4563 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4565 System.err.println("Assuming project file with "
4566 + (version == null ? "null" : version)
4567 + " is compatible with Jalview version " + supported);
4572 return StringUtils.compareVersions(version, supported, "b") >= 0;
4576 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4578 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4580 if (newStructureViewers != null)
4582 sview.getBinding().setFinishedLoadingFromArchive(false);
4583 newStructureViewers.add(sview);
4587 protected void setLoadingFinishedForNewStructureViewers()
4589 if (newStructureViewers != null)
4591 for (JalviewStructureDisplayI sview : newStructureViewers)
4593 sview.getBinding().setFinishedLoadingFromArchive(true);
4595 newStructureViewers.clear();
4596 newStructureViewers = null;
4600 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4601 List<SequenceI> hiddenSeqs, AlignmentI al,
4602 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4603 String viewId, List<JvAnnotRow> autoAlan)
4605 AlignFrame af = null;
4606 af = new AlignFrame(al, safeInt(view.getWidth()),
4607 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4611 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4612 // System.out.println("Jalview2XML AF " + e);
4613 // super.processKeyEvent(e);
4620 af.setFileName(file, FileFormat.Jalview);
4622 final AlignViewport viewport = af.getViewport();
4623 for (int i = 0; i < JSEQ.size(); i++)
4625 int colour = safeInt(JSEQ.get(i).getColour());
4626 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4632 viewport.setColourByReferenceSeq(true);
4633 viewport.setDisplayReferenceSeq(true);
4636 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4638 if (view.getSequenceSetId() != null)
4640 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4642 viewport.setSequenceSetId(uniqueSeqSetId);
4645 // propagate shared settings to this new view
4646 viewport.setHistoryList(av.getHistoryList());
4647 viewport.setRedoList(av.getRedoList());
4651 viewportsAdded.put(uniqueSeqSetId, viewport);
4653 // TODO: check if this method can be called repeatedly without
4654 // side-effects if alignpanel already registered.
4655 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4657 // apply Hidden regions to view.
4658 if (hiddenSeqs != null)
4660 for (int s = 0; s < JSEQ.size(); s++)
4662 SequenceGroup hidden = new SequenceGroup();
4663 boolean isRepresentative = false;
4664 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4666 isRepresentative = true;
4667 SequenceI sequenceToHide = al
4668 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4669 hidden.addSequence(sequenceToHide, false);
4670 // remove from hiddenSeqs list so we don't try to hide it twice
4671 hiddenSeqs.remove(sequenceToHide);
4673 if (isRepresentative)
4675 SequenceI representativeSequence = al.getSequenceAt(s);
4676 hidden.addSequence(representativeSequence, false);
4677 viewport.hideRepSequences(representativeSequence, hidden);
4681 SequenceI[] hseqs = hiddenSeqs
4682 .toArray(new SequenceI[hiddenSeqs.size()]);
4683 viewport.hideSequence(hseqs);
4686 // recover view properties and display parameters
4688 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4689 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4690 final int pidThreshold = safeInt(view.getPidThreshold());
4691 viewport.setThreshold(pidThreshold);
4693 viewport.setColourText(safeBoolean(view.isShowColourText()));
4696 .setConservationSelected(
4697 safeBoolean(view.isConservationSelected()));
4698 viewport.setIncrement(safeInt(view.getConsThreshold()));
4699 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4700 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4701 viewport.setFont(new Font(view.getFontName(),
4702 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4704 ViewStyleI vs = viewport.getViewStyle();
4705 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4706 viewport.setViewStyle(vs);
4707 // TODO: allow custom charWidth/Heights to be restored by updating them
4708 // after setting font - which means set above to false
4709 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4710 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4711 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4713 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4715 viewport.setShowText(safeBoolean(view.isShowText()));
4717 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4718 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4719 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4720 viewport.setShowUnconserved(view.isShowUnconserved());
4721 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4723 if (view.getViewName() != null)
4725 viewport.setViewName(view.getViewName());
4726 af.setInitialTabVisible();
4728 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4729 safeInt(view.getWidth()), safeInt(view.getHeight()));
4730 // startSeq set in af.alignPanel.updateLayout below
4731 af.alignPanel.updateLayout();
4732 ColourSchemeI cs = null;
4733 // apply colourschemes
4734 if (view.getBgColour() != null)
4736 if (view.getBgColour().startsWith("ucs"))
4738 cs = getUserColourScheme(jm, view.getBgColour());
4740 else if (view.getBgColour().startsWith("Annotation"))
4742 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4743 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4750 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4754 viewport.setGlobalColourScheme(cs);
4755 viewport.getResidueShading().setThreshold(pidThreshold,
4756 view.isIgnoreGapsinConsensus());
4757 viewport.getResidueShading()
4758 .setConsensus(viewport.getSequenceConsensusHash());
4759 viewport.setColourAppliesToAllGroups(false);
4761 if (safeBoolean(view.isConservationSelected()) && cs != null)
4763 viewport.getResidueShading()
4764 .setConservationInc(safeInt(view.getConsThreshold()));
4767 af.changeColour(cs);
4769 viewport.setColourAppliesToAllGroups(true);
4772 .setShowSequenceFeatures(
4773 safeBoolean(view.isShowSequenceFeatures()));
4775 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4776 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4777 viewport.setFollowHighlight(view.isFollowHighlight());
4778 viewport.followSelection = view.isFollowSelection();
4779 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4780 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4781 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4782 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4783 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4784 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4785 viewport.setShowGroupConservation(view.isShowGroupConservation());
4787 // recover feature settings
4788 if (jm.getFeatureSettings() != null)
4790 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4791 .getFeatureRenderer();
4792 FeaturesDisplayed fdi;
4793 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4794 String[] renderOrder = new String[jm.getFeatureSettings()
4795 .getSetting().size()];
4796 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4797 Map<String, Float> featureOrder = new Hashtable<>();
4799 for (int fs = 0; fs < jm.getFeatureSettings()
4800 .getSetting().size(); fs++)
4802 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4803 String featureType = setting.getType();
4806 * restore feature filters (if any)
4808 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4810 if (filters != null)
4812 FeatureMatcherSetI filter = Jalview2XML
4813 .parseFilter(featureType, filters);
4814 if (!filter.isEmpty())
4816 fr.setFeatureFilter(featureType, filter);
4821 * restore feature colour scheme
4823 Color maxColour = new Color(setting.getColour());
4824 if (setting.getMincolour() != null)
4827 * minColour is always set unless a simple colour
4828 * (including for colour by label though it doesn't use it)
4830 Color minColour = new Color(setting.getMincolour().intValue());
4831 Color noValueColour = minColour;
4832 NoValueColour noColour = setting.getNoValueColour();
4833 if (noColour == NoValueColour.NONE)
4835 noValueColour = null;
4837 else if (noColour == NoValueColour.MAX)
4839 noValueColour = maxColour;
4841 float min = safeFloat(safeFloat(setting.getMin()));
4842 float max = setting.getMax() == null ? 1f
4843 : setting.getMax().floatValue();
4844 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4845 noValueColour, min, max);
4846 if (setting.getAttributeName().size() > 0)
4848 gc.setAttributeName(setting.getAttributeName().toArray(
4849 new String[setting.getAttributeName().size()]));
4851 if (setting.getThreshold() != null)
4853 gc.setThreshold(setting.getThreshold().floatValue());
4854 int threshstate = safeInt(setting.getThreshstate());
4855 // -1 = None, 0 = Below, 1 = Above threshold
4856 if (threshstate == 0)
4858 gc.setBelowThreshold(true);
4860 else if (threshstate == 1)
4862 gc.setAboveThreshold(true);
4865 gc.setAutoScaled(true); // default
4866 if (setting.isAutoScale() != null)
4868 gc.setAutoScaled(setting.isAutoScale());
4870 if (setting.isColourByLabel() != null)
4872 gc.setColourByLabel(setting.isColourByLabel());
4874 // and put in the feature colour table.
4875 featureColours.put(featureType, gc);
4879 featureColours.put(featureType,
4880 new FeatureColour(maxColour));
4882 renderOrder[fs] = featureType;
4883 if (setting.getOrder() != null)
4885 featureOrder.put(featureType, setting.getOrder().floatValue());
4889 featureOrder.put(featureType, new Float(
4890 fs / jm.getFeatureSettings().getSetting().size()));
4892 if (safeBoolean(setting.isDisplay()))
4894 fdi.setVisible(featureType);
4897 Map<String, Boolean> fgtable = new Hashtable<>();
4898 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4900 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4901 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
4903 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4904 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4905 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4906 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4907 fgtable, featureColours, 1.0f, featureOrder);
4908 fr.transferSettings(frs);
4911 if (view.getHiddenColumns().size() > 0)
4913 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4915 final HiddenColumns hc = view.getHiddenColumns().get(c);
4916 viewport.hideColumns(safeInt(hc.getStart()),
4917 safeInt(hc.getEnd()) /* +1 */);
4920 if (view.getCalcIdParam() != null)
4922 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4924 if (calcIdParam != null)
4926 if (recoverCalcIdParam(calcIdParam, viewport))
4931 warn("Couldn't recover parameters for "
4932 + calcIdParam.getCalcId());
4937 af.setMenusFromViewport(viewport);
4938 af.setTitle(view.getTitle());
4939 // TODO: we don't need to do this if the viewport is aready visible.
4941 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4942 * has a 'cdna/protein complement' view, in which case save it in order to
4943 * populate a SplitFrame once all views have been read in.
4945 String complementaryViewId = view.getComplementId();
4946 if (complementaryViewId == null)
4948 Desktop.addInternalFrame(af, view.getTitle(),
4949 safeInt(view.getWidth()), safeInt(view.getHeight()));
4950 // recompute any autoannotation
4951 af.alignPanel.updateAnnotation(false, true);
4952 reorderAutoannotation(af, al, autoAlan);
4953 af.alignPanel.alignmentChanged();
4957 splitFrameCandidates.put(view, af);
4963 * Reads saved data to restore Colour by Annotation settings
4965 * @param viewAnnColour
4969 * @param checkGroupAnnColour
4972 private ColourSchemeI constructAnnotationColour(
4973 AnnotationColourScheme viewAnnColour, AlignFrame af,
4974 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
4976 boolean propagateAnnColour = false;
4977 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
4979 if (checkGroupAnnColour && al.getGroups() != null
4980 && al.getGroups().size() > 0)
4982 // pre 2.8.1 behaviour
4983 // check to see if we should transfer annotation colours
4984 propagateAnnColour = true;
4985 for (SequenceGroup sg : al.getGroups())
4987 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4989 propagateAnnColour = false;
4995 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4997 String annotationId = viewAnnColour.getAnnotation();
4998 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5001 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5003 if (matchedAnnotation == null
5004 && annAlignment.getAlignmentAnnotation() != null)
5006 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5009 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5011 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5016 if (matchedAnnotation == null)
5018 System.err.println("Failed to match annotation colour scheme for "
5022 if (matchedAnnotation.getThreshold() == null)
5024 matchedAnnotation.setThreshold(
5025 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5026 "Threshold", Color.black));
5029 AnnotationColourGradient cs = null;
5030 if (viewAnnColour.getColourScheme().equals("None"))
5032 cs = new AnnotationColourGradient(matchedAnnotation,
5033 new Color(safeInt(viewAnnColour.getMinColour())),
5034 new Color(safeInt(viewAnnColour.getMaxColour())),
5035 safeInt(viewAnnColour.getAboveThreshold()));
5037 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5039 cs = new AnnotationColourGradient(matchedAnnotation,
5040 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5041 safeInt(viewAnnColour.getAboveThreshold()));
5045 cs = new AnnotationColourGradient(matchedAnnotation,
5046 ColourSchemeProperty.getColourScheme(al,
5047 viewAnnColour.getColourScheme()),
5048 safeInt(viewAnnColour.getAboveThreshold()));
5051 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5052 boolean useOriginalColours = safeBoolean(
5053 viewAnnColour.isPredefinedColours());
5054 cs.setSeqAssociated(perSequenceOnly);
5055 cs.setPredefinedColours(useOriginalColours);
5057 if (propagateAnnColour && al.getGroups() != null)
5059 // Also use these settings for all the groups
5060 for (int g = 0; g < al.getGroups().size(); g++)
5062 SequenceGroup sg = al.getGroups().get(g);
5063 if (sg.getGroupColourScheme() == null)
5068 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5069 matchedAnnotation, sg.getColourScheme(),
5070 safeInt(viewAnnColour.getAboveThreshold()));
5071 sg.setColourScheme(groupScheme);
5072 groupScheme.setSeqAssociated(perSequenceOnly);
5073 groupScheme.setPredefinedColours(useOriginalColours);
5079 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5080 List<JvAnnotRow> autoAlan)
5082 // copy over visualization settings for autocalculated annotation in the
5084 if (al.getAlignmentAnnotation() != null)
5087 * Kludge for magic autoannotation names (see JAL-811)
5089 String[] magicNames = new String[] { "Consensus", "Quality",
5091 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5092 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5093 for (String nm : magicNames)
5095 visan.put(nm, nullAnnot);
5097 for (JvAnnotRow auan : autoAlan)
5099 visan.put(auan.template.label
5100 + (auan.template.getCalcId() == null ? ""
5101 : "\t" + auan.template.getCalcId()),
5104 int hSize = al.getAlignmentAnnotation().length;
5105 List<JvAnnotRow> reorder = new ArrayList<>();
5106 // work through any autoCalculated annotation already on the view
5107 // removing it if it should be placed in a different location on the
5108 // annotation panel.
5109 List<String> remains = new ArrayList<>(visan.keySet());
5110 for (int h = 0; h < hSize; h++)
5112 jalview.datamodel.AlignmentAnnotation jalan = al
5113 .getAlignmentAnnotation()[h];
5114 if (jalan.autoCalculated)
5117 JvAnnotRow valan = visan.get(k = jalan.label);
5118 if (jalan.getCalcId() != null)
5120 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5125 // delete the auto calculated row from the alignment
5126 al.deleteAnnotation(jalan, false);
5130 if (valan != nullAnnot)
5132 if (jalan != valan.template)
5134 // newly created autoannotation row instance
5135 // so keep a reference to the visible annotation row
5136 // and copy over all relevant attributes
5137 if (valan.template.graphHeight >= 0)
5140 jalan.graphHeight = valan.template.graphHeight;
5142 jalan.visible = valan.template.visible;
5144 reorder.add(new JvAnnotRow(valan.order, jalan));
5149 // Add any (possibly stale) autocalculated rows that were not appended to
5150 // the view during construction
5151 for (String other : remains)
5153 JvAnnotRow othera = visan.get(other);
5154 if (othera != nullAnnot && othera.template.getCalcId() != null
5155 && othera.template.getCalcId().length() > 0)
5157 reorder.add(othera);
5160 // now put the automatic annotation in its correct place
5161 int s = 0, srt[] = new int[reorder.size()];
5162 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5163 for (JvAnnotRow jvar : reorder)
5166 srt[s++] = jvar.order;
5169 jalview.util.QuickSort.sort(srt, rws);
5170 // and re-insert the annotation at its correct position
5171 for (JvAnnotRow jvar : rws)
5173 al.addAnnotation(jvar.template, jvar.order);
5175 af.alignPanel.adjustAnnotationHeight();
5179 Hashtable skipList = null;
5182 * TODO remove this method
5185 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5186 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5187 * throw new Error("Implementation Error. No skipList defined for this
5188 * Jalview2XML instance."); } return (AlignFrame)
5189 * skipList.get(view.getSequenceSetId()); }
5193 * Check if the Jalview view contained in object should be skipped or not.
5196 * @return true if view's sequenceSetId is a key in skipList
5198 private boolean skipViewport(JalviewModel object)
5200 if (skipList == null)
5204 String id = object.getViewport().get(0).getSequenceSetId();
5205 if (skipList.containsKey(id))
5207 if (Cache.log != null && Cache.log.isDebugEnabled())
5209 Cache.log.debug("Skipping seuqence set id " + id);
5216 public void addToSkipList(AlignFrame af)
5218 if (skipList == null)
5220 skipList = new Hashtable();
5222 skipList.put(af.getViewport().getSequenceSetId(), af);
5225 public void clearSkipList()
5227 if (skipList != null)
5234 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5235 boolean ignoreUnrefed)
5237 jalview.datamodel.AlignmentI ds = getDatasetFor(
5238 vamsasSet.getDatasetId());
5239 Vector dseqs = null;
5242 // create a list of new dataset sequences
5243 dseqs = new Vector();
5245 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5247 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5248 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5250 // create a new dataset
5253 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5254 dseqs.copyInto(dsseqs);
5255 ds = new jalview.datamodel.Alignment(dsseqs);
5256 debug("Created new dataset " + vamsasSet.getDatasetId()
5257 + " for alignment " + System.identityHashCode(al));
5258 addDatasetRef(vamsasSet.getDatasetId(), ds);
5260 // set the dataset for the newly imported alignment.
5261 if (al.getDataset() == null && !ignoreUnrefed)
5270 * sequence definition to create/merge dataset sequence for
5274 * vector to add new dataset sequence to
5275 * @param ignoreUnrefed
5276 * - when true, don't create new sequences from vamsasSeq if it's id
5277 * doesn't already have an asssociated Jalview sequence.
5279 * - used to reorder the sequence in the alignment according to the
5280 * vamsasSeq array ordering, to preserve ordering of dataset
5282 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5283 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5285 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5287 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5288 boolean reorder = false;
5289 SequenceI dsq = null;
5290 if (sq != null && sq.getDatasetSequence() != null)
5292 dsq = sq.getDatasetSequence();
5298 if (sq == null && ignoreUnrefed)
5302 String sqid = vamsasSeq.getDsseqid();
5305 // need to create or add a new dataset sequence reference to this sequence
5308 dsq = seqRefIds.get(sqid);
5313 // make a new dataset sequence
5314 dsq = sq.createDatasetSequence();
5317 // make up a new dataset reference for this sequence
5318 sqid = seqHash(dsq);
5320 dsq.setVamsasId(uniqueSetSuffix + sqid);
5321 seqRefIds.put(sqid, dsq);
5326 dseqs.addElement(dsq);
5331 ds.addSequence(dsq);
5337 { // make this dataset sequence sq's dataset sequence
5338 sq.setDatasetSequence(dsq);
5339 // and update the current dataset alignment
5344 if (!dseqs.contains(dsq))
5351 if (ds.findIndex(dsq) < 0)
5353 ds.addSequence(dsq);
5360 // TODO: refactor this as a merge dataset sequence function
5361 // now check that sq (the dataset sequence) sequence really is the union of
5362 // all references to it
5363 // boolean pre = sq.getStart() < dsq.getStart();
5364 // boolean post = sq.getEnd() > dsq.getEnd();
5368 // StringBuffer sb = new StringBuffer();
5369 String newres = jalview.analysis.AlignSeq.extractGaps(
5370 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5371 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5372 && newres.length() > dsq.getLength())
5374 // Update with the longer sequence.
5378 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5379 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5380 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5381 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5383 dsq.setSequence(newres);
5385 // TODO: merges will never happen if we 'know' we have the real dataset
5386 // sequence - this should be detected when id==dssid
5388 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5389 // + (pre ? "prepended" : "") + " "
5390 // + (post ? "appended" : ""));
5395 // sequence refs are identical. We may need to update the existing dataset
5396 // alignment with this one, though.
5397 if (ds != null && dseqs == null)
5399 int opos = ds.findIndex(dsq);
5400 SequenceI tseq = null;
5401 if (opos != -1 && vseqpos != opos)
5403 // remove from old position
5404 ds.deleteSequence(dsq);
5406 if (vseqpos < ds.getHeight())
5408 if (vseqpos != opos)
5410 // save sequence at destination position
5411 tseq = ds.getSequenceAt(vseqpos);
5412 ds.replaceSequenceAt(vseqpos, dsq);
5413 ds.addSequence(tseq);
5418 ds.addSequence(dsq);
5425 * TODO use AlignmentI here and in related methods - needs
5426 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5428 Hashtable<String, AlignmentI> datasetIds = null;
5430 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5432 private AlignmentI getDatasetFor(String datasetId)
5434 if (datasetIds == null)
5436 datasetIds = new Hashtable<>();
5439 if (datasetIds.containsKey(datasetId))
5441 return datasetIds.get(datasetId);
5446 private void addDatasetRef(String datasetId, AlignmentI dataset)
5448 if (datasetIds == null)
5450 datasetIds = new Hashtable<>();
5452 datasetIds.put(datasetId, dataset);
5456 * make a new dataset ID for this jalview dataset alignment
5461 private String getDatasetIdRef(AlignmentI dataset)
5463 if (dataset.getDataset() != null)
5465 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5467 String datasetId = makeHashCode(dataset, null);
5468 if (datasetId == null)
5470 // make a new datasetId and record it
5471 if (dataset2Ids == null)
5473 dataset2Ids = new IdentityHashMap<>();
5477 datasetId = dataset2Ids.get(dataset);
5479 if (datasetId == null)
5481 datasetId = "ds" + dataset2Ids.size() + 1;
5482 dataset2Ids.put(dataset, datasetId);
5488 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5490 for (int d = 0; d < sequence.getDBRef().size(); d++)
5492 DBRef dr = sequence.getDBRef().get(d);
5493 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5494 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5495 if (dr.getMapping() != null)
5497 entry.setMap(addMapping(dr.getMapping()));
5499 datasetSequence.addDBRef(entry);
5503 private jalview.datamodel.Mapping addMapping(Mapping m)
5505 SequenceI dsto = null;
5506 // Mapping m = dr.getMapping();
5507 int fr[] = new int[m.getMapListFrom().size() * 2];
5508 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5509 for (int _i = 0; from.hasNext(); _i += 2)
5511 MapListFrom mf = from.next();
5512 fr[_i] = mf.getStart();
5513 fr[_i + 1] = mf.getEnd();
5515 int fto[] = new int[m.getMapListTo().size() * 2];
5516 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5517 for (int _i = 0; to.hasNext(); _i += 2)
5519 MapListTo mf = to.next();
5520 fto[_i] = mf.getStart();
5521 fto[_i + 1] = mf.getEnd();
5523 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5524 fto, m.getMapFromUnit().intValue(),
5525 m.getMapToUnit().intValue());
5526 // if (m.getMappingChoice() != null)
5528 // MappingChoice mc = m.getMappingChoice();
5529 if (m.getDseqFor() != null)
5531 String dsfor = m.getDseqFor();
5532 if (seqRefIds.containsKey(dsfor))
5537 jmap.setTo(seqRefIds.get(dsfor));
5541 frefedSequence.add(newMappingRef(dsfor, jmap));
5547 * local sequence definition
5549 Sequence ms = m.getSequence();
5550 SequenceI djs = null;
5551 String sqid = ms.getDsseqid();
5552 if (sqid != null && sqid.length() > 0)
5555 * recover dataset sequence
5557 djs = seqRefIds.get(sqid);
5562 "Warning - making up dataset sequence id for DbRef sequence map reference");
5563 sqid = ((Object) ms).toString(); // make up a new hascode for
5564 // undefined dataset sequence hash
5565 // (unlikely to happen)
5571 * make a new dataset sequence and add it to refIds hash
5573 djs = new jalview.datamodel.Sequence(ms.getName(),
5575 djs.setStart(jmap.getMap().getToLowest());
5576 djs.setEnd(jmap.getMap().getToHighest());
5577 djs.setVamsasId(uniqueSetSuffix + sqid);
5579 incompleteSeqs.put(sqid, djs);
5580 seqRefIds.put(sqid, djs);
5583 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5592 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5593 * view as XML (but not to file), and then reloading it
5598 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5601 JalviewModel jm = saveState(ap, null, null, null);
5603 uniqueSetSuffix = "";
5604 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5605 jm.getViewport().get(0).setId(null);
5606 // we don't overwrite the view we just copied
5608 if (this.frefedSequence == null)
5610 frefedSequence = new Vector<>();
5613 viewportsAdded.clear();
5615 AlignFrame af = loadFromObject(jm, null, false, null);
5616 af.getAlignPanels().clear();
5617 af.closeMenuItem_actionPerformed(true);
5620 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5621 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5622 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5623 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5624 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5627 return af.alignPanel;
5630 private Hashtable jvids2vobj;
5632 private void warn(String msg)
5637 private void warn(String msg, Exception e)
5639 if (Cache.log != null)
5643 Cache.log.warn(msg, e);
5647 Cache.log.warn(msg);
5652 System.err.println("Warning: " + msg);
5655 e.printStackTrace();
5660 private void debug(String string)
5662 debug(string, null);
5665 private void debug(String msg, Exception e)
5667 if (Cache.log != null)
5671 Cache.log.debug(msg, e);
5675 Cache.log.debug(msg);
5680 System.err.println("Warning: " + msg);
5683 e.printStackTrace();
5689 * set the object to ID mapping tables used to write/recover objects and XML
5690 * ID strings for the jalview project. If external tables are provided then
5691 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5692 * object goes out of scope. - also populates the datasetIds hashtable with
5693 * alignment objects containing dataset sequences
5696 * Map from ID strings to jalview datamodel
5698 * Map from jalview datamodel to ID strings
5702 public void setObjectMappingTables(Hashtable vobj2jv,
5703 IdentityHashMap jv2vobj)
5705 this.jv2vobj = jv2vobj;
5706 this.vobj2jv = vobj2jv;
5707 Iterator ds = jv2vobj.keySet().iterator();
5709 while (ds.hasNext())
5711 Object jvobj = ds.next();
5712 id = jv2vobj.get(jvobj).toString();
5713 if (jvobj instanceof jalview.datamodel.Alignment)
5715 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5717 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5720 else if (jvobj instanceof jalview.datamodel.Sequence)
5722 // register sequence object so the XML parser can recover it.
5723 if (seqRefIds == null)
5725 seqRefIds = new HashMap<>();
5727 if (seqsToIds == null)
5729 seqsToIds = new IdentityHashMap<>();
5731 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5732 seqsToIds.put((SequenceI) jvobj, id);
5734 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5737 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5738 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5739 if (jvann.annotationId == null)
5741 jvann.annotationId = anid;
5743 if (!jvann.annotationId.equals(anid))
5745 // TODO verify that this is the correct behaviour
5746 this.warn("Overriding Annotation ID for " + anid
5747 + " from different id : " + jvann.annotationId);
5748 jvann.annotationId = anid;
5751 else if (jvobj instanceof String)
5753 if (jvids2vobj == null)
5755 jvids2vobj = new Hashtable();
5756 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5761 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5767 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5768 * objects created from the project archive. If string is null (default for
5769 * construction) then suffix will be set automatically.
5773 public void setUniqueSetSuffix(String string)
5775 uniqueSetSuffix = string;
5780 * uses skipList2 as the skipList for skipping views on sequence sets
5781 * associated with keys in the skipList
5785 public void setSkipList(Hashtable skipList2)
5787 skipList = skipList2;
5791 * Reads the jar entry of given name and returns its contents, or null if the
5792 * entry is not found.
5795 * @param jarEntryName
5798 protected String readJarEntry(jarInputStreamProvider jprovider,
5799 String jarEntryName)
5801 String result = null;
5802 BufferedReader in = null;
5807 * Reopen the jar input stream and traverse its entries to find a matching
5810 JarInputStream jin = jprovider.getJarInputStream();
5811 JarEntry entry = null;
5814 entry = jin.getNextJarEntry();
5815 } while (entry != null && !entry.getName().equals(jarEntryName));
5819 StringBuilder out = new StringBuilder(256);
5820 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5823 while ((data = in.readLine()) != null)
5827 result = out.toString();
5831 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5833 } catch (Exception ex)
5835 ex.printStackTrace();
5843 } catch (IOException e)
5854 * Returns an incrementing counter (0, 1, 2...)
5858 private synchronized int nextCounter()
5864 * Populates an XML model of the feature colour scheme for one feature type
5866 * @param featureType
5870 public static Colour marshalColour(
5871 String featureType, FeatureColourI fcol)
5873 Colour col = new Colour();
5874 if (fcol.isSimpleColour())
5876 col.setRGB(Format.getHexString(fcol.getColour()));
5880 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5881 col.setMin(fcol.getMin());
5882 col.setMax(fcol.getMax());
5883 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5884 col.setAutoScale(fcol.isAutoScaled());
5885 col.setThreshold(fcol.getThreshold());
5886 col.setColourByLabel(fcol.isColourByLabel());
5887 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
5888 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
5889 : ThresholdType.NONE));
5890 if (fcol.isColourByAttribute())
5892 final String[] attName = fcol.getAttributeName();
5893 col.getAttributeName().add(attName[0]);
5894 if (attName.length > 1)
5896 col.getAttributeName().add(attName[1]);
5899 Color noColour = fcol.getNoColour();
5900 if (noColour == null)
5902 col.setNoValueColour(NoValueColour.NONE);
5904 else if (noColour == fcol.getMaxColour())
5906 col.setNoValueColour(NoValueColour.MAX);
5910 col.setNoValueColour(NoValueColour.MIN);
5913 col.setName(featureType);
5918 * Populates an XML model of the feature filter(s) for one feature type
5920 * @param firstMatcher
5921 * the first (or only) match condition)
5923 * remaining match conditions (if any)
5925 * if true, conditions are and-ed, else or-ed
5927 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
5928 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
5931 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
5933 if (filters.hasNext())
5938 CompoundMatcher compound = new CompoundMatcher();
5939 compound.setAnd(and);
5940 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
5941 firstMatcher, Collections.emptyIterator(), and);
5942 // compound.addMatcherSet(matcher1);
5943 compound.getMatcherSet().add(matcher1);
5944 FeatureMatcherI nextMatcher = filters.next();
5945 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
5946 nextMatcher, filters, and);
5947 // compound.addMatcherSet(matcher2);
5948 compound.getMatcherSet().add(matcher2);
5949 result.setCompoundMatcher(compound);
5954 * single condition matcher
5956 // MatchCondition matcherModel = new MatchCondition();
5957 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
5958 matcherModel.setCondition(
5959 firstMatcher.getMatcher().getCondition().getStableName());
5960 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5961 if (firstMatcher.isByAttribute())
5963 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
5964 // matcherModel.setAttributeName(firstMatcher.getAttribute());
5965 String[] attName = firstMatcher.getAttribute();
5966 matcherModel.getAttributeName().add(attName[0]); // attribute
5967 if (attName.length > 1)
5969 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
5972 else if (firstMatcher.isByLabel())
5974 matcherModel.setBy(FilterBy.BY_LABEL);
5976 else if (firstMatcher.isByScore())
5978 matcherModel.setBy(FilterBy.BY_SCORE);
5980 result.setMatchCondition(matcherModel);
5987 * Loads one XML model of a feature filter to a Jalview object
5989 * @param featureType
5990 * @param matcherSetModel
5993 public static FeatureMatcherSetI parseFilter(
5995 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
5997 FeatureMatcherSetI result = new FeatureMatcherSet();
6000 parseFilterConditions(result, matcherSetModel, true);
6001 } catch (IllegalStateException e)
6003 // mixing AND and OR conditions perhaps
6005 String.format("Error reading filter conditions for '%s': %s",
6006 featureType, e.getMessage()));
6007 // return as much as was parsed up to the error
6014 * Adds feature match conditions to matcherSet as unmarshalled from XML
6015 * (possibly recursively for compound conditions)
6018 * @param matcherSetModel
6020 * if true, multiple conditions are AND-ed, else they are OR-ed
6021 * @throws IllegalStateException
6022 * if AND and OR conditions are mixed
6024 protected static void parseFilterConditions(
6025 FeatureMatcherSetI matcherSet,
6026 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6029 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6030 .getMatchCondition();
6036 FilterBy filterBy = mc.getBy();
6037 Condition cond = Condition.fromString(mc.getCondition());
6038 String pattern = mc.getValue();
6039 FeatureMatcherI matchCondition = null;
6040 if (filterBy == FilterBy.BY_LABEL)
6042 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6044 else if (filterBy == FilterBy.BY_SCORE)
6046 matchCondition = FeatureMatcher.byScore(cond, pattern);
6049 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6051 final List<String> attributeName = mc.getAttributeName();
6052 String[] attNames = attributeName
6053 .toArray(new String[attributeName.size()]);
6054 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6059 * note this throws IllegalStateException if AND-ing to a
6060 * previously OR-ed compound condition, or vice versa
6064 matcherSet.and(matchCondition);
6068 matcherSet.or(matchCondition);
6074 * compound condition
6076 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6077 .getCompoundMatcher().getMatcherSet();
6078 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6079 if (matchers.size() == 2)
6081 parseFilterConditions(matcherSet, matchers.get(0), anded);
6082 parseFilterConditions(matcherSet, matchers.get(1), anded);
6086 System.err.println("Malformed compound filter condition");
6092 * Loads one XML model of a feature colour to a Jalview object
6094 * @param colourModel
6097 public static FeatureColourI parseColour(Colour colourModel)
6099 FeatureColourI colour = null;
6101 if (colourModel.getMax() != null)
6103 Color mincol = null;
6104 Color maxcol = null;
6105 Color noValueColour = null;
6109 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6110 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6111 } catch (Exception e)
6113 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6116 NoValueColour noCol = colourModel.getNoValueColour();
6117 if (noCol == NoValueColour.MIN)
6119 noValueColour = mincol;
6121 else if (noCol == NoValueColour.MAX)
6123 noValueColour = maxcol;
6126 colour = new FeatureColour(mincol, maxcol, noValueColour,
6127 safeFloat(colourModel.getMin()),
6128 safeFloat(colourModel.getMax()));
6129 final List<String> attributeName = colourModel.getAttributeName();
6130 String[] attributes = attributeName
6131 .toArray(new String[attributeName.size()]);
6132 if (attributes != null && attributes.length > 0)
6134 colour.setAttributeName(attributes);
6136 if (colourModel.isAutoScale() != null)
6138 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6140 if (colourModel.isColourByLabel() != null)
6142 colour.setColourByLabel(
6143 colourModel.isColourByLabel().booleanValue());
6145 if (colourModel.getThreshold() != null)
6147 colour.setThreshold(colourModel.getThreshold().floatValue());
6149 ThresholdType ttyp = colourModel.getThreshType();
6150 if (ttyp == ThresholdType.ABOVE)
6152 colour.setAboveThreshold(true);
6154 else if (ttyp == ThresholdType.BELOW)
6156 colour.setBelowThreshold(true);
6161 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6162 colour = new FeatureColour(color);