X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=8bbf735f5c9d3b367451c8bf24b6d8628b92b597;hb=b718dc55184e25f610ba7cf8cfb26b84c179fbfd;hp=6652aea7fefe82ee1baf0c3617745eec1e648c24;hpb=0452450533728e478ef8c893ea2cb3483c740fb3;p=jalview.git diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java old mode 100755 new mode 100644 index 6652aea..094fa7a --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1,1691 +1,5482 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer - * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; +import jalview.api.FeatureColourI; +import jalview.api.ViewStyleI; +import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Cache; +import jalview.datamodel.AlignedCodonFrame; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.RnaViewerModel; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.datamodel.StructureViewerModel; +import jalview.datamodel.StructureViewerModel.StructureData; +import jalview.ext.varna.RnaModel; +import jalview.gui.StructureViewer.ViewerType; +import jalview.schemabinding.version2.AlcodMap; +import jalview.schemabinding.version2.AlcodonFrame; +import jalview.schemabinding.version2.Annotation; +import jalview.schemabinding.version2.AnnotationColours; +import jalview.schemabinding.version2.AnnotationElement; +import jalview.schemabinding.version2.CalcIdParam; +import jalview.schemabinding.version2.DBRef; +import jalview.schemabinding.version2.Features; +import jalview.schemabinding.version2.Group; +import jalview.schemabinding.version2.HiddenColumns; +import jalview.schemabinding.version2.JGroup; +import jalview.schemabinding.version2.JSeq; +import jalview.schemabinding.version2.JalviewModel; +import jalview.schemabinding.version2.JalviewModelSequence; +import jalview.schemabinding.version2.MapListFrom; +import jalview.schemabinding.version2.MapListTo; +import jalview.schemabinding.version2.Mapping; +import jalview.schemabinding.version2.MappingChoice; +import jalview.schemabinding.version2.OtherData; +import jalview.schemabinding.version2.PdbentryItem; +import jalview.schemabinding.version2.Pdbids; +import jalview.schemabinding.version2.Property; +import jalview.schemabinding.version2.RnaViewer; +import jalview.schemabinding.version2.SecondaryStructure; +import jalview.schemabinding.version2.Sequence; +import jalview.schemabinding.version2.SequenceSet; +import jalview.schemabinding.version2.SequenceSetProperties; +import jalview.schemabinding.version2.Setting; +import jalview.schemabinding.version2.StructureState; +import jalview.schemabinding.version2.ThresholdLine; +import jalview.schemabinding.version2.Tree; +import jalview.schemabinding.version2.UserColours; +import jalview.schemabinding.version2.Viewport; +import jalview.schemes.AnnotationColourGradient; +import jalview.schemes.ColourSchemeI; +import jalview.schemes.ColourSchemeProperty; +import jalview.schemes.FeatureColour; +import jalview.schemes.ResidueColourScheme; +import jalview.schemes.ResidueProperties; +import jalview.schemes.UserColourScheme; +import jalview.structure.StructureSelectionManager; +import jalview.structures.models.AAStructureBindingModel; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.util.StringUtils; +import jalview.util.jarInputStreamProvider; +import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.seqfeatures.FeatureRendererSettings; +import jalview.viewmodel.seqfeatures.FeaturesDisplayed; +import jalview.ws.jws2.Jws2Discoverer; +import jalview.ws.jws2.dm.AAConSettings; +import jalview.ws.jws2.jabaws2.Jws2Instance; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.AutoCalcSetting; +import jalview.ws.params.WsParamSetI; + +import java.awt.Color; +import java.awt.Rectangle; +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Vector; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; + +import javax.swing.JInternalFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import org.exolab.castor.xml.Marshaller; +import org.exolab.castor.xml.Unmarshaller; -import jalview.schemes.*; +/** + * Write out the current jalview desktop state as a Jalview XML stream. + * + * Note: the vamsas objects referred to here are primitive versions of the + * VAMSAS project schema elements - they are not the same and most likely never + * will be :) + * + * @author $author$ + * @version $Revision: 1.134 $ + */ +public class Jalview2XML +{ + private static final String VIEWER_PREFIX = "viewer_"; -import java.io.*; + private static final String RNA_PREFIX = "rna_"; -import java.net.*; + private static final String UTF_8 = "UTF-8"; -import java.util.*; + // use this with nextCounter() to make unique names for entities + private int counter = 0; -import java.util.jar.*; + /* + * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps + * of sequence objects are created. + */ + IdentityHashMap seqsToIds = null; -import javax.swing.*; + /** + * jalview XML Sequence ID to jalview sequence object reference (both dataset + * and alignment sequences. Populated as XML reps of sequence objects are + * created.) + */ + Map seqRefIds = null; -import org.exolab.castor.xml.*; + Map incompleteSeqs = null; -import jalview.schemabinding.version2.*; + List frefedSequence = null; + boolean raiseGUI = true; // whether errors are raised in dialog boxes or not + /* + * Map of reconstructed AlignFrame objects that appear to have come from + * SplitFrame objects (have a dna/protein complement view). + */ + private Map splitFrameCandidates = new HashMap(); + /* + * Map from displayed rna structure models to their saved session state jar + * entry names + */ + private Map rnaSessions = new HashMap(); -/** - * DOCUMENT ME! - * - * @author $author$ - * @version $Revision$ - */ -public class Jalview2XML -{ + /** + * create/return unique hash string for sq + * + * @param sq + * @return new or existing unique string for sq + */ + String seqHash(SequenceI sq) + { + if (seqsToIds == null) + { + initSeqRefs(); + } + if (seqsToIds.containsKey(sq)) + { + return seqsToIds.get(sq); + } + else + { + // create sequential key + String key = "sq" + (seqsToIds.size() + 1); + key = makeHashCode(sq, key); // check we don't have an external reference + // for it already. + seqsToIds.put(sq, key); + return key; + } + } + + void clearSeqRefs() + { + if (_cleartables) + { + if (seqRefIds != null) + { + seqRefIds.clear(); + } + if (seqsToIds != null) + { + seqsToIds.clear(); + } + if (incompleteSeqs != null) + { + incompleteSeqs.clear(); + } + // seqRefIds = null; + // seqsToIds = null; + } + else + { + // do nothing + warn("clearSeqRefs called when _cleartables was not set. Doing nothing."); + // seqRefIds = new Hashtable(); + // seqsToIds = new IdentityHashMap(); + } + } + + void initSeqRefs() + { + if (seqsToIds == null) + { + seqsToIds = new IdentityHashMap(); + } + if (seqRefIds == null) + { + seqRefIds = new HashMap(); + } + if (incompleteSeqs == null) + { + incompleteSeqs = new HashMap(); + } + if (frefedSequence == null) + { + frefedSequence = new ArrayList(); + } + } - Hashtable seqRefIds; + public Jalview2XML() + { + } + + public Jalview2XML(boolean raiseGUI) + { + this.raiseGUI = raiseGUI; + } /** - * This maintains a list of viewports, the key being the - * seqSetId. Important to set historyItem and redoList - * for multiple views + * base class for resolving forward references to sequences by their ID + * + * @author jprocter + * */ - Hashtable viewportsAdded; + abstract class SeqFref + { + String sref; - String uniqueSetSuffix = ""; + String type; + + public SeqFref(String _sref, String type) + { + sref = _sref; + this.type = type; + } + public String getSref() + { + return sref; + } - // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE - public void SaveState(File statefile) + public SequenceI getSrefSeq() { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + return seqRefIds.get(sref); + } + + public boolean isResolvable() + { + return seqRefIds.get(sref) != null; + } - if (frames == null) + public SequenceI getSrefDatasetSeq() + { + SequenceI sq = seqRefIds.get(sref); + if (sq != null) + { + while (sq.getDatasetSequence() != null) { - return; + sq = sq.getDatasetSequence(); } + } + return sq; + } + /** + * @return true if the forward reference was fully resolved + */ + abstract boolean resolve(); - try + @Override + public String toString() + { + return type + " reference to " + sref; + } + } + + /** + * create forward reference for a mapping + * + * @param sref + * @param _jmap + * @return + */ + public SeqFref newMappingRef(final String sref, + final jalview.datamodel.Mapping _jmap) + { + SeqFref fref = new SeqFref(sref, "Mapping") + { + public jalview.datamodel.Mapping jmap = _jmap; + + @Override + boolean resolve() + { + SequenceI seq = getSrefDatasetSeq(); + if (seq == null) { - FileOutputStream fos = new FileOutputStream(statefile); - JarOutputStream jout = new JarOutputStream(fos); + return false; + } + jmap.setTo(seq); + return true; + } + }; + return fref; + } - //NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS - //////////////////////////////////////////////////// - PrintWriter out = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); + public SeqFref newAlcodMapRef(final String sref, + final AlignedCodonFrame _cf, final jalview.datamodel.Mapping _jmap) + { - Vector shortNames = new Vector(); + SeqFref fref = new SeqFref(sref, "Codon Frame") + { + AlignedCodonFrame cf = _cf; - //REVERSE ORDER - for (int i = frames.length - 1; i > -1; i--) - { - if (frames[i] instanceof AlignFrame) - { - AlignFrame af = (AlignFrame) frames[i]; - - String shortName = af.getTitle(); - - if (shortName.indexOf(File.separatorChar) > -1) - { - shortName = shortName.substring(shortName.lastIndexOf( - File.separatorChar) + 1); - } - - int count = 1; - - while (shortNames.contains(shortName)) - { - if (shortName.endsWith("_" + (count - 1))) - { - shortName = shortName.substring(0, - shortName.lastIndexOf("_")); - } - - shortName = shortName.concat("_" + count); - count++; - } - - shortNames.addElement(shortName); - - if (!shortName.endsWith(".xml")) - { - shortName = shortName + ".xml"; - } - - int ap, apSize= af.alignPanels.size(); - for (ap = 0; ap < apSize; ap++) - { - AlignmentPanel apanel = (AlignmentPanel) af.alignPanels. - elementAt(ap); - - SaveState(apanel, - apSize == 1 ? shortName : ap+shortName, - jout, out); - } - } - } + public jalview.datamodel.Mapping mp = _jmap; - out.close(); - jout.close(); + @Override + boolean resolve() + { + SequenceI seq = getSrefDatasetSeq(); + if (seq == null) + { + return false; } - catch (Exception ex) + cf.addMap(seq, mp.getTo(), mp.getMap()); + return true; + } + }; + return fref; + } + + public void resolveFrefedSequences() + { + Iterator nextFref=frefedSequence.iterator(); + int toresolve=frefedSequence.size(); + int unresolved=0,failedtoresolve=0; + while (nextFref.hasNext()) { + SeqFref ref = nextFref.next(); + if (ref.isResolvable()) + { + try { + if (ref.resolve()) + { + nextFref.remove(); + } else { + failedtoresolve++; + } + } catch (Exception x) { + System.err.println("IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "+ref.getSref()); + x.printStackTrace(); + failedtoresolve++; + } + } else { + unresolved++; + } + } + if (unresolved>0) + { + System.err.println("Jalview Project Import: There were " + unresolved + + " forward references left unresolved on the stack."); + } + if (failedtoresolve>0) + { + System.err.println("SERIOUS! " + failedtoresolve + + " resolvable forward references failed to resolve."); + } + if (incompleteSeqs != null && incompleteSeqs.size() > 0) + { + System.err.println("Jalview Project Import: There are " + + incompleteSeqs.size() + + " sequences which may have incomplete metadata."); + if (incompleteSeqs.size() < 10) + { + for (SequenceI s : incompleteSeqs.values()) { - ex.printStackTrace(); + System.err.println(s.toString()); } + } + else + { + System.err + .println("Too many to report. Skipping output of incomplete sequences."); + } } + } + + /** + * This maintains a map of viewports, the key being the seqSetId. Important to + * set historyItem and redoList for multiple views + */ + Map viewportsAdded = new HashMap(); + + Map annotationIds = new HashMap(); + + String uniqueSetSuffix = ""; - // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW - public boolean SaveAlignment(AlignFrame af, String jarFile, - String fileName) + /** + * List of pdbfiles added to Jar + */ + List pdbfiles = null; + + // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE + public void saveState(File statefile) + { + FileOutputStream fos = null; + try + { + fos = new FileOutputStream(statefile); + JarOutputStream jout = new JarOutputStream(fos); + saveState(jout); + + } catch (Exception e) + { + // TODO: inform user of the problem - they need to know if their data was + // not saved ! + if (errorMessage == null) + { + errorMessage = "Couldn't write Jalview Archive to output file '" + + statefile + "' - See console error log for details"; + } + else + { + errorMessage += "(output file was '" + statefile + "')"; + } + e.printStackTrace(); + } finally { + if (fos != null) + { try { - int ap, apSize= af.alignPanels.size(); - FileOutputStream fos = new FileOutputStream(jarFile); - JarOutputStream jout = new JarOutputStream(fos); - PrintWriter out = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); - for( ap=0; ap frames, JarOutputStream jout) + { + Hashtable dsses = new Hashtable(); + + /* + * ensure cached data is clear before starting */ - public JalviewModel SaveState(AlignmentPanel ap, - String fileName, - JarOutputStream jout, - PrintWriter out) + // todo tidy up seqRefIds, seqsToIds initialisation / reset + rnaSessions.clear(); + splitFrameCandidates.clear(); + + try { - if (seqRefIds == null) - seqRefIds = new Hashtable(); - Vector userColours = new Vector(); + // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS + // ////////////////////////////////////////////////// - AlignViewport av = ap.av; + List shortNames = new ArrayList(); + List viewIds = new ArrayList(); - JalviewModel object = new JalviewModel(); - object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); + // REVERSE ORDER + for (int i = frames.size() - 1; i > -1; i--) + { + AlignFrame af = frames.get(i); + // skip ? + if (skipList != null + && skipList + .containsKey(af.getViewport().getSequenceSetId())) + { + continue; + } - object.setCreationDate(new java.util.Date(System.currentTimeMillis())); - object.setVersion(jalview.bin.Cache.getProperty("VERSION")); + String shortName = makeFilename(af, shortNames); - jalview.datamodel.AlignmentI jal = av.alignment; + int ap, apSize = af.alignPanels.size(); - if(av.hasHiddenRows) + for (ap = 0; ap < apSize; ap++) { - jal = jal.getHiddenSequences().getFullAlignment(); + AlignmentPanel apanel = af.alignPanels.get(ap); + String fileName = apSize == 1 ? shortName : ap + shortName; + if (!fileName.endsWith(".xml")) + { + fileName = fileName + ".xml"; + } + + saveState(apanel, fileName, jout, viewIds); + + String dssid = getDatasetIdRef(af.getViewport().getAlignment() + .getDataset()); + if (!dsses.containsKey(dssid)) + { + dsses.put(dssid, af); + } } + } - SequenceSet vamsasSet = new SequenceSet(); - Sequence vamsasSeq; - JalviewModelSequence jms = new JalviewModelSequence(); + writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix, + jout); - vamsasSet.setGapChar(jal.getGapCharacter() + ""); + try + { + jout.flush(); + } catch (Exception foo) + { + } + ; + jout.close(); + } catch (Exception ex) + { + // TODO: inform user of the problem - they need to know if their data was + // not saved ! + if (errorMessage == null) + { + errorMessage = "Couldn't write Jalview Archive - see error output for details"; + } + ex.printStackTrace(); + } + } - JSeq jseq; - Vector pdbfiles = null; + /** + * Generates a distinct file name, based on the title of the AlignFrame, by + * appending _n for increasing n until an unused name is generated. The new + * name (without its extension) is added to the list. + * + * @param af + * @param namesUsed + * @return the generated name, with .xml extension + */ + protected String makeFilename(AlignFrame af, List namesUsed) + { + String shortName = af.getTitle(); - //SAVE SEQUENCES - int id = 0; - jalview.datamodel.SequenceI jds; - for (int i = 0; i < jal.getHeight(); i++) - { - jds = jal.getSequenceAt(i); - id = jds.hashCode(); + if (shortName.indexOf(File.separatorChar) > -1) + { + shortName = shortName.substring(shortName + .lastIndexOf(File.separatorChar) + 1); + } - if(seqRefIds.get(id+"")!=null) - { + int count = 1; - } - else - { - vamsasSeq = new Sequence(); - vamsasSeq.setId(id + ""); - vamsasSeq.setName(jds.getName()); - vamsasSeq.setSequence(jds.getSequenceAsString()); - vamsasSeq.setDescription(jds.getDescription()); + while (namesUsed.contains(shortName)) + { + if (shortName.endsWith("_" + (count - 1))) + { + shortName = shortName.substring(0, shortName.lastIndexOf("_")); + } - if (jds.getDatasetSequence().getDBRef() != null) - { - jalview.datamodel.DBRefEntry[] dbrefs = - jds.getDatasetSequence().getDBRef(); + shortName = shortName.concat("_" + count); + count++; + } - for (int d = 0; d < dbrefs.length; d++) - { - DBRef dbref = new DBRef(); - dbref.setSource(dbrefs[d].getSource()); - dbref.setVersion(dbrefs[d].getVersion()); - dbref.setAccessionId(dbrefs[d].getAccessionId()); - vamsasSeq.addDBRef(dbref); - } - } + namesUsed.add(shortName); - vamsasSet.addSequence(vamsasSeq); - seqRefIds.put(id+"", jal.getSequenceAt(i)); - } + if (!shortName.endsWith(".xml")) + { + shortName = shortName + ".xml"; + } + return shortName; + } + + // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW + public boolean saveAlignment(AlignFrame af, String jarFile, + String fileName) + { + try + { + FileOutputStream fos = new FileOutputStream(jarFile); + JarOutputStream jout = new JarOutputStream(fos); + List frames = new ArrayList(); - jseq = new JSeq(); - jseq.setStart(jds.getStart()); - jseq.setEnd(jds.getEnd()); - jseq.setColour( av.getSequenceColour(jds).getRGB()); + // resolve splitframes + if (af.getViewport().getCodingComplement() != null) + { + frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames(); + } + else + { + frames.add(af); + } + saveAllFrames(frames, jout); + try + { + jout.flush(); + } catch (Exception foo) + { + } + ; + jout.close(); + return true; + } catch (Exception ex) + { + errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details"; + ex.printStackTrace(); + return false; + } + } - jseq.setId(id); + private void writeDatasetFor(Hashtable dsses, + String fileName, JarOutputStream jout) + { - if (av.hasHiddenRows) - { - jseq.setHidden(av.alignment.getHiddenSequences().isHidden(jds)); + for (String dssids : dsses.keySet()) + { + AlignFrame _af = dsses.get(dssids); + String jfileName = fileName + " Dataset for " + _af.getTitle(); + if (!jfileName.endsWith(".xml")) + { + jfileName = jfileName + ".xml"; + } + saveState(_af.alignPanel, jfileName, true, jout, null); + } + } - if(av.hiddenRepSequences!=null - && av.hiddenRepSequences.containsKey(jal.getSequenceAt(i))) - { - jalview.datamodel.SequenceI[] reps = - ( (jalview.datamodel.SequenceGroup) - av.hiddenRepSequences.get( - jal.getSequenceAt(i))).getSequencesInOrder(jal); + /** + * create a JalviewModel from an alignment view and marshall it to a + * JarOutputStream + * + * @param ap + * panel to create jalview model for + * @param fileName + * name of alignment panel written to output stream + * @param jout + * jar output stream + * @param viewIds + * @param out + * jar entry name + */ + public JalviewModel saveState(AlignmentPanel ap, String fileName, + JarOutputStream jout, List viewIds) + { + return saveState(ap, fileName, false, jout, viewIds); + } - for(int h=0; h viewIds) + { + if (viewIds == null) + { + viewIds = new ArrayList(); + } + initSeqRefs(); - if(jds.getDatasetSequence().getSequenceFeatures()!=null) - { - jalview.datamodel.SequenceFeature[] sf - = jds.getDatasetSequence().getSequenceFeatures(); - int index = 0; - while(index < sf.length) - { - Features features = new Features(); - - features.setBegin(sf[index].getBegin()); - features.setEnd(sf[index].getEnd()); - features.setDescription(sf[index].getDescription()); - features.setType(sf[index].getType()); - features.setFeatureGroup(sf[index].getFeatureGroup()); - features.setScore(sf[index].getScore()); - if(sf[index].links!=null) - { - for(int l=0; l userColours = new ArrayList(); - jseq.addFeatures(features); - index ++; - } - } + AlignViewport av = ap.av; - if(jds.getDatasetSequence().getPDBId()!=null) - { - Enumeration en = jds.getDatasetSequence().getPDBId().elements(); - while(en.hasMoreElements()) - { - Pdbids pdb = new Pdbids(); - jalview.datamodel.PDBEntry entry - = (jalview.datamodel.PDBEntry)en.nextElement(); + JalviewModel object = new JalviewModel(); + object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); - pdb.setId(entry.getId()); - pdb.setType(entry.getType()); + object.setCreationDate(new java.util.Date(System.currentTimeMillis())); + object.setVersion(jalview.bin.Cache.getDefault("VERSION", + "Development Build")); + /** + * rjal is full height alignment, jal is actual alignment with full metadata + * but excludes hidden sequences. + */ + jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal; - if(entry.getFile()!=null) - { - pdb.setFile(entry.getFile()); - if(pdbfiles==null) - pdbfiles = new Vector(); + if (av.hasHiddenRows()) + { + rjal = jal.getHiddenSequences().getFullAlignment(); + } - if(!pdbfiles.contains(entry.getId())) - { - pdbfiles.addElement(entry.getId()); - try - { - File file = new File(entry.getFile()); - if(file.exists() && jout!=null) - { - byte[] data = new byte[ (int) file.length()]; - jout.putNextEntry(new JarEntry(entry.getId())); - DataInputStream dis = new DataInputStream(new - FileInputStream(file)); - dis.readFully(data); - - DataOutputStream dout = new DataOutputStream(jout); - dout.write(data, 0, data.length); - jout.closeEntry(); - } - } - catch (Exception ex) - { - ex.printStackTrace(); - } - } - } + SequenceSet vamsasSet = new SequenceSet(); + Sequence vamsasSeq; + JalviewModelSequence jms = new JalviewModelSequence(); + vamsasSet.setGapChar(jal.getGapCharacter() + ""); - if(entry.getProperty()!=null) - { - PdbentryItem item = new PdbentryItem(); - Hashtable properties = entry.getProperty(); - Enumeration en2 = properties.keys(); - while(en2.hasMoreElements()) - { - Property prop = new Property(); - String key = en2.nextElement().toString(); - prop.setName(key); - prop.setValue( properties.get(key).toString() ); - item.addProperty(prop); - } - pdb.addPdbentryItem(item); - } + if (jal.getDataset() != null) + { + // dataset id is the dataset's hashcode + vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset())); + if (storeDS) + { + // switch jal and the dataset + jal = jal.getDataset(); + rjal = jal; + } + } + if (jal.getProperties() != null) + { + Enumeration en = jal.getProperties().keys(); + while (en.hasMoreElements()) + { + String key = en.nextElement().toString(); + SequenceSetProperties ssp = new SequenceSetProperties(); + ssp.setKey(key); + ssp.setValue(jal.getProperties().get(key).toString()); + vamsasSet.addSequenceSetProperties(ssp); + } + } - jseq.addPdbids(pdb); - } - } + JSeq jseq; + Set calcIdSet = new HashSet(); - jms.addJSeq(jseq); - } + // SAVE SEQUENCES + for (final SequenceI jds : rjal.getSequences()) + { + final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds + : jds.getDatasetSequence(); + String id = seqHash(jds); - if(av.hasHiddenRows) - jal = av.alignment; + if (seqRefIds.get(id) != null) + { + // This happens for two reasons: 1. multiple views are being serialised. + // 2. the hashCode has collided with another sequence's code. This DOES + // HAPPEN! (PF00072.15.stk does this) + // JBPNote: Uncomment to debug writing out of files that do not read + // back in due to ArrayOutOfBoundExceptions. + // System.err.println("vamsasSeq backref: "+id+""); + // System.err.println(jds.getName()+" + // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString()); + // System.err.println("Hashcode: "+seqHash(jds)); + // SequenceI rsq = (SequenceI) seqRefIds.get(id + ""); + // System.err.println(rsq.getName()+" + // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString()); + // System.err.println("Hashcode: "+seqHash(rsq)); + } + else + { + vamsasSeq = createVamsasSequence(id, jds); + vamsasSet.addSequence(vamsasSeq); + seqRefIds.put(id, jds); + } + jseq = new JSeq(); + jseq.setStart(jds.getStart()); + jseq.setEnd(jds.getEnd()); + jseq.setColour(av.getSequenceColour(jds).getRGB()); - //SAVE TREES - /////////////////////////////////// - if (av.currentTree != null) + jseq.setId(id); // jseq id should be a string not a number + if (!storeDS) + { + // Store any sequences this sequence represents + if (av.hasHiddenRows()) { - // FIND ANY ASSOCIATED TREES - // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT - if (Desktop.desktop != null) + // use rjal, contains the full height alignment + jseq.setHidden(av.getAlignment().getHiddenSequences() + .isHidden(jds)); + + if (av.isHiddenRepSequence(jds)) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + jalview.datamodel.SequenceI[] reps = av + .getRepresentedSequences(jds) + .getSequencesInOrder(rjal); - for (int t = 0; t < frames.length; t++) + for (int h = 0; h < reps.length; h++) { - if (frames[t] instanceof TreePanel) + if (reps[h] != jds) { - TreePanel tp = (TreePanel) frames[t]; - - if (tp.treeCanvas.av.alignment == jal) - { - Tree tree = new Tree(); - tree.setTitle(tp.getTitle()); - tree.setCurrentTree( (av.currentTree == tp.getTree())); - tree.setNewick(tp.getTree().toString()); - tree.setThreshold(tp.treeCanvas.threshold); - - tree.setFitToWindow(tp.fitToWindow.getState()); - tree.setFontName(tp.getTreeFont().getName()); - tree.setFontSize(tp.getTreeFont().getSize()); - tree.setFontStyle(tp.getTreeFont().getStyle()); - tree.setMarkUnlinked(tp.placeholdersMenu.getState()); - - tree.setShowBootstrap(tp.bootstrapMenu.getState()); - tree.setShowDistances(tp.distanceMenu.getState()); - - tree.setHeight(tp.getHeight()); - tree.setWidth(tp.getWidth()); - tree.setXpos(tp.getX()); - tree.setYpos(tp.getY()); - - jms.addTree(tree); - } + jseq.addHiddenSequences(rjal.findIndex(reps[h])); } } } } - - //SAVE ANNOTATIONS - if (jal.getAlignmentAnnotation() != null) + // mark sequence as reference - if it is the reference for this view + if (jal.hasSeqrep()) { - jalview.datamodel.AlignmentAnnotation[] aa = jal.getAlignmentAnnotation(); + jseq.setViewreference(jds == jal.getSeqrep()); + } + } - for (int i = 0; i < aa.length; i++) + // TODO: omit sequence features from each alignment view's XML dump if we + // are storing dataset + if (jds.getSequenceFeatures() != null) + { + jalview.datamodel.SequenceFeature[] sf = jds.getSequenceFeatures(); + int index = 0; + while (index < sf.length) + { + Features features = new Features(); + + features.setBegin(sf[index].getBegin()); + features.setEnd(sf[index].getEnd()); + features.setDescription(sf[index].getDescription()); + features.setType(sf[index].getType()); + features.setFeatureGroup(sf[index].getFeatureGroup()); + features.setScore(sf[index].getScore()); + if (sf[index].links != null) + { + for (int l = 0; l < sf[index].links.size(); l++) { - Annotation an = new Annotation(); - - if (aa[i].label.equals("Quality") || - aa[i].label.equals("Conservation") || - aa[i].label.equals("Consensus")) - { - an.setLabel(aa[i].label); - an.setGraph(true); - vamsasSet.addAnnotation(an); - continue; - } - - - an.setDescription(aa[i].description); + OtherData keyValue = new OtherData(); + keyValue.setKey("LINK_" + l); + keyValue.setValue(sf[index].links.elementAt(l).toString()); + features.addOtherData(keyValue); + } + } + if (sf[index].otherDetails != null) + { + String key; + Iterator keys = sf[index].otherDetails.keySet() + .iterator(); + while (keys.hasNext()) + { + key = keys.next(); + OtherData keyValue = new OtherData(); + keyValue.setKey(key); + keyValue.setValue(sf[index].otherDetails.get(key).toString()); + features.addOtherData(keyValue); + } + } - if(aa[i].sequenceRef!=null) - { - an.setSequenceRef(aa[i].sequenceRef.getName()); - } + jseq.addFeatures(features); + index++; + } + } - if(aa[i].graph>0) + if (jdatasq.getAllPDBEntries() != null) + { + Enumeration en = jdatasq.getAllPDBEntries().elements(); + while (en.hasMoreElements()) + { + Pdbids pdb = new Pdbids(); + jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en + .nextElement(); + + String pdbId = entry.getId(); + pdb.setId(pdbId); + pdb.setType(entry.getType()); + + /* + * Store any structure views associated with this sequence. This + * section copes with duplicate entries in the project, so a dataset + * only view *should* be coped with sensibly. + */ + // This must have been loaded, is it still visible? + JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + String matchedFile = null; + for (int f = frames.length - 1; f > -1; f--) + { + if (frames[f] instanceof StructureViewerBase) + { + StructureViewerBase viewFrame = (StructureViewerBase) frames[f]; + matchedFile = saveStructureState(ap, jds, pdb, entry, + viewIds, matchedFile, viewFrame); + /* + * Only store each structure viewer's state once in the project + * jar. First time through only (storeDS==false) + */ + String viewId = viewFrame.getViewId(); + if (!storeDS && !viewIds.contains(viewId)) + { + viewIds.add(viewId); + try { - an.setGraph(true); - an.setGraphType(aa[i].graph); - an.setGraphGroup(aa[i].graphGroup); - if(aa[i].getThreshold()!=null) - { - ThresholdLine line = new ThresholdLine(); - line.setLabel(aa[i].getThreshold().label); - line.setValue(aa[i].getThreshold().value); - line.setColour(aa[i].getThreshold().colour.getRGB()); - an.setThresholdLine(line); - } - } - else - an.setGraph(false); - - an.setLabel(aa[i].label); - - AnnotationElement ae; - - for (int a = 0; a < aa[i].annotations.length; a++) + String viewerState = viewFrame.getStateInfo(); + writeJarEntry(jout, getViewerJarEntryName(viewId), + viewerState.getBytes()); + } catch (IOException e) { - if ((aa[i] == null) || (aa[i].annotations[a] == null)) - { - continue; - } - - ae = new AnnotationElement(); - ae.setDescription(aa[i].annotations[a].description); - ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter); - ae.setValue(aa[i].annotations[a].value); - ae.setPosition(a); - ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure + - ""); - - if(aa[i].annotations[a].colour!=java.awt.Color.black) - ae.setColour(aa[i].annotations[a].colour.getRGB()); - - an.addAnnotationElement(ae); + System.err.println("Error saving viewer state: " + + e.getMessage()); } + } + } + } - vamsasSet.addAnnotation(an); + if (matchedFile != null || entry.getFile() != null) + { + if (entry.getFile() != null) + { + // use entry's file + matchedFile = entry.getFile(); + } + pdb.setFile(matchedFile); // entry.getFile()); + if (pdbfiles == null) + { + pdbfiles = new ArrayList(); } - } - //SAVE GROUPS - if (jal.getGroups() != null) - { - JGroup[] groups = new JGroup[jal.getGroups().size()]; + if (!pdbfiles.contains(pdbId)) + { + pdbfiles.add(pdbId); + copyFileToJar(jout, matchedFile, pdbId); + } + } - for (int i = 0; i < groups.length; i++) + if (entry.getProperty() != null && !entry.getProperty().isEmpty()) + { + PdbentryItem item = new PdbentryItem(); + Hashtable properties = entry.getProperty(); + Enumeration en2 = properties.keys(); + while (en2.hasMoreElements()) { - groups[i] = new JGroup(); - - jalview.datamodel.SequenceGroup sg = (jalview.datamodel.SequenceGroup) jal.getGroups() - .elementAt(i); - groups[i].setStart(sg.getStartRes()); - groups[i].setEnd(sg.getEndRes()); - groups[i].setName(sg.getName()); - if(sg.cs!=null) - { - if (sg.cs.conservationApplied()) - { - groups[i].setConsThreshold(sg.cs.getConservationInc()); - - if (sg.cs instanceof jalview.schemes.UserColourScheme) - { - groups[i].setColour(SetUserColourScheme(sg.cs, - userColours, - jms)); - } - else - { - groups[i].setColour(ColourSchemeProperty.getColourName(sg. - cs)); - } - } - else if(sg.cs instanceof jalview.schemes.AnnotationColourGradient) - { - groups[i].setColour( - ColourSchemeProperty.getColourName( - ( (jalview.schemes.AnnotationColourGradient) sg.cs).getBaseColour())); - } - else if (sg.cs instanceof jalview.schemes.UserColourScheme) - { - groups[i].setColour(SetUserColourScheme(sg.cs, userColours, - jms)); - } - else - { - groups[i].setColour(ColourSchemeProperty.getColourName( - sg.cs)); - } + Property prop = new Property(); + String key = en2.nextElement().toString(); + prop.setName(key); + prop.setValue(properties.get(key).toString()); + item.addProperty(prop); + } + pdb.addPdbentryItem(item); + } - groups[i].setPidThreshold(sg.cs.getThreshold()); - } + jseq.addPdbids(pdb); + } + } - groups[i].setOutlineColour(sg.getOutlineColour().getRGB()); - groups[i].setDisplayBoxes(sg.getDisplayBoxes()); - groups[i].setDisplayText(sg.getDisplayText()); - groups[i].setColourText(sg.getColourText()); - groups[i].setTextCol1(sg.textColour.getRGB()); - groups[i].setTextCol2(sg.textColour2.getRGB()); - groups[i].setTextColThreshold(sg.thresholdTextColour); + saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS); - for (int s = 0; s < sg.getSize(); s++) - { - jalview.datamodel.Sequence seq = - (jalview.datamodel.Sequence) sg.getSequenceAt(s); - groups[i].addSeq(seq.hashCode()); - } - } + jms.addJSeq(jseq); + } - jms.setJGroup(groups); + if (!storeDS && av.hasHiddenRows()) + { + jal = av.getAlignment(); + } + // SAVE MAPPINGS + // FOR DATASET + if (storeDS && jal.getCodonFrames() != null) + { + List jac = jal.getCodonFrames(); + for (AlignedCodonFrame acf : jac) + { + AlcodonFrame alc = new AlcodonFrame(); + if (acf.getProtMappings() != null + && acf.getProtMappings().length > 0) + { + boolean hasMap = false; + SequenceI[] dnas = acf.getdnaSeqs(); + jalview.datamodel.Mapping[] pmaps = acf.getProtMappings(); + for (int m = 0; m < pmaps.length; m++) + { + AlcodMap alcmap = new AlcodMap(); + alcmap.setDnasq(seqHash(dnas[m])); + alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null, + false)); + alc.addAlcodMap(alcmap); + hasMap = true; + } + if (hasMap) + { + vamsasSet.addAlcodonFrame(alc); + } } + // TODO: delete this ? dead code from 2.8.3->2.9 ? + // { + // AlcodonFrame alc = new AlcodonFrame(); + // vamsasSet.addAlcodonFrame(alc); + // for (int p = 0; p < acf.aaWidth; p++) + // { + // Alcodon cmap = new Alcodon(); + // if (acf.codons[p] != null) + // { + // // Null codons indicate a gapped column in the translated peptide + // // alignment. + // cmap.setPos1(acf.codons[p][0]); + // cmap.setPos2(acf.codons[p][1]); + // cmap.setPos3(acf.codons[p][2]); + // } + // alc.addAlcodon(cmap); + // } + // if (acf.getProtMappings() != null + // && acf.getProtMappings().length > 0) + // { + // SequenceI[] dnas = acf.getdnaSeqs(); + // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings(); + // for (int m = 0; m < pmaps.length; m++) + // { + // AlcodMap alcmap = new AlcodMap(); + // alcmap.setDnasq(seqHash(dnas[m])); + // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null, + // false)); + // alc.addAlcodMap(alcmap); + // } + // } + } + } + // SAVE TREES + // ///////////////////////////////// + if (!storeDS && av.currentTree != null) + { + // FIND ANY ASSOCIATED TREES + // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT + if (Desktop.desktop != null) + { + JInternalFrame[] frames = Desktop.desktop.getAllFrames(); - ///////////SAVE VIEWPORT - Viewport view = new Viewport(); - view.setTitle(ap.alignFrame.getTitle()); - view.setSequenceSetId(av.getSequenceSetId()); - view.setViewName(av.viewName); - view.setGatheredViews(av.gatherViewsHere); + for (int t = 0; t < frames.length; t++) + { + if (frames[t] instanceof TreePanel) + { + TreePanel tp = (TreePanel) frames[t]; + if (tp.treeCanvas.av.getAlignment() == jal) + { + Tree tree = new Tree(); + tree.setTitle(tp.getTitle()); + tree.setCurrentTree((av.currentTree == tp.getTree())); + tree.setNewick(tp.getTree().toString()); + tree.setThreshold(tp.treeCanvas.threshold); + + tree.setFitToWindow(tp.fitToWindow.getState()); + tree.setFontName(tp.getTreeFont().getName()); + tree.setFontSize(tp.getTreeFont().getSize()); + tree.setFontStyle(tp.getTreeFont().getStyle()); + tree.setMarkUnlinked(tp.placeholdersMenu.getState()); + + tree.setShowBootstrap(tp.bootstrapMenu.getState()); + tree.setShowDistances(tp.distanceMenu.getState()); + + tree.setHeight(tp.getHeight()); + tree.setWidth(tp.getWidth()); + tree.setXpos(tp.getX()); + tree.setYpos(tp.getY()); + tree.setId(makeHashCode(tp, null)); + jms.addTree(tree); + } + } + } + } + } - if (ap.av.explodedPosition != null) + // SAVE ANNOTATIONS + /** + * store forward refs from an annotationRow to any groups + */ + IdentityHashMap groupRefs = new IdentityHashMap(); + if (storeDS) + { + for (SequenceI sq : jal.getSequences()) + { + // Store annotation on dataset sequences only + AlignmentAnnotation[] aa = sq.getAnnotation(); + if (aa != null && aa.length > 0) { - view.setXpos(av.explodedPosition.x); - view.setYpos(av.explodedPosition.y); - view.setWidth(av.explodedPosition.width); - view.setHeight(av.explodedPosition.height); + storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, + vamsasSet); } - else + } + } + else + { + if (jal.getAlignmentAnnotation() != null) + { + // Store the annotation shown on the alignment. + AlignmentAnnotation[] aa = jal.getAlignmentAnnotation(); + storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, + vamsasSet); + } + } + // SAVE GROUPS + if (jal.getGroups() != null) + { + JGroup[] groups = new JGroup[jal.getGroups().size()]; + int i = -1; + for (jalview.datamodel.SequenceGroup sg : jal.getGroups()) + { + JGroup jGroup = new JGroup(); + groups[++i] = jGroup; + + jGroup.setStart(sg.getStartRes()); + jGroup.setEnd(sg.getEndRes()); + jGroup.setName(sg.getName()); + if (groupRefs.containsKey(sg)) { - view.setXpos(ap.alignFrame.getBounds().x); - view.setYpos(ap.alignFrame.getBounds().y); - view.setWidth(ap.alignFrame.getBounds().width); - view.setHeight(ap.alignFrame.getBounds().height); + // group has references so set its ID field + jGroup.setId(groupRefs.get(sg)); } - - view.setStartRes(av.startRes); - view.setStartSeq(av.startSeq); - - if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme) + if (sg.cs != null) { - view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(), + if (sg.cs.conservationApplied()) + { + jGroup.setConsThreshold(sg.cs.getConservationInc()); + + if (sg.cs instanceof jalview.schemes.UserColourScheme) + { + jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms)); + } + else + { + jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs)); + } + } + else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient) + { + jGroup.setColour("AnnotationColourGradient"); + jGroup.setAnnotationColours(constructAnnotationColours( + (jalview.schemes.AnnotationColourGradient) sg.cs, userColours, jms)); + } + else if (sg.cs instanceof jalview.schemes.UserColourScheme) + { + jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms)); + } + else + { + jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs)); + } + + jGroup.setPidThreshold(sg.cs.getThreshold()); } - else if(av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient) + + jGroup.setOutlineColour(sg.getOutlineColour().getRGB()); + jGroup.setDisplayBoxes(sg.getDisplayBoxes()); + jGroup.setDisplayText(sg.getDisplayText()); + jGroup.setColourText(sg.getColourText()); + jGroup.setTextCol1(sg.textColour.getRGB()); + jGroup.setTextCol2(sg.textColour2.getRGB()); + jGroup.setTextColThreshold(sg.thresholdTextColour); + jGroup.setShowUnconserved(sg.getShowNonconserved()); + jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); + jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram()); + jGroup.setShowSequenceLogo(sg.isShowSequenceLogo()); + jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); + for (SequenceI seq : sg.getSequences()) { - jalview.schemes.AnnotationColourGradient acg - = (jalview.schemes.AnnotationColourGradient)av.getGlobalColourScheme(); + jGroup.addSeq(seqHash(seq)); + } + } - AnnotationColours ac = new AnnotationColours(); - ac.setAboveThreshold(acg.getAboveThreshold()); - ac.setThreshold(acg.getAnnotationThreshold()); - ac.setAnnotation(acg.getAnnotation()); - if(acg.getBaseColour() instanceof jalview.schemes.UserColourScheme) - ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(), - userColours, jms)); - else - ac.setColourScheme(ColourSchemeProperty.getColourName(acg.getBaseColour())); + jms.setJGroup(groups); + } + if (!storeDS) + { + // /////////SAVE VIEWPORT + Viewport view = new Viewport(); + view.setTitle(ap.alignFrame.getTitle()); + view.setSequenceSetId(makeHashCode(av.getSequenceSetId(), + av.getSequenceSetId())); + view.setId(av.getViewId()); + if (av.getCodingComplement() != null) + { + view.setComplementId(av.getCodingComplement().getViewId()); + } + view.setViewName(av.viewName); + view.setGatheredViews(av.isGatherViewsHere()); - ac.setMaxColour(acg.getMaxColour().getRGB()); - ac.setMinColour(acg.getMinColour().getRGB()); - view.setAnnotationColours(ac); - view.setBgColour("AnnotationColourGradient"); + Rectangle size = ap.av.getExplodedGeometry(); + Rectangle position = size; + if (size == null) + { + size = ap.alignFrame.getBounds(); + if (av.getCodingComplement() != null) + { + position = ((SplitFrame) ap.alignFrame.getSplitViewContainer()) + .getBounds(); } else { - view.setBgColour(ColourSchemeProperty.getColourName( - av.getGlobalColourScheme())); + position = size; } + } + view.setXpos(position.x); + view.setYpos(position.y); + + view.setWidth(size.width); + view.setHeight(size.height); + + view.setStartRes(av.startRes); + view.setStartSeq(av.startSeq); + + if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme) + { + view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(), + userColours, jms)); + } + else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient) + { + AnnotationColours ac = constructAnnotationColours( + (jalview.schemes.AnnotationColourGradient) av + .getGlobalColourScheme(), + userColours, jms); + + view.setAnnotationColours(ac); + view.setBgColour("AnnotationColourGradient"); + } + else + { + view.setBgColour(ColourSchemeProperty.getColourName(av + .getGlobalColourScheme())); + } - ColourSchemeI cs = av.getGlobalColourScheme(); + ColourSchemeI cs = av.getGlobalColourScheme(); - if(cs!=null) + if (cs != null) + { + if (cs.conservationApplied()) { - if (cs.conservationApplied()) + view.setConsThreshold(cs.getConservationInc()); + if (cs instanceof jalview.schemes.UserColourScheme) { - view.setConsThreshold(cs.getConservationInc()); - if (cs instanceof jalview.schemes.UserColourScheme) - view.setBgColour(SetUserColourScheme(cs, userColours, jms)); + view.setBgColour(setUserColourScheme(cs, userColours, jms)); } + } - if (cs instanceof ResidueColourScheme) - { - view.setPidThreshold(cs.getThreshold()); - } + if (cs instanceof ResidueColourScheme) + { + view.setPidThreshold(cs.getThreshold()); } + } - view.setConservationSelected(av.getConservationSelected()); - view.setPidSelected(av.getAbovePIDThreshold()); - view.setFontName(av.font.getName()); - view.setFontSize(av.font.getSize()); - view.setFontStyle(av.font.getStyle()); - view.setRenderGaps(av.renderGaps); - view.setShowAnnotation(av.getShowAnnotation()); - view.setShowBoxes(av.getShowBoxes()); - view.setShowColourText(av.getColourText()); - view.setShowFullId(av.getShowJVSuffix()); - view.setRightAlignIds(av.rightAlignIds); - view.setShowSequenceFeatures(av.showSequenceFeatures); - view.setShowText(av.getShowText()); - view.setWrapAlignment(av.getWrapAlignment()); - view.setTextCol1(av.textColour.getRGB()); - view.setTextCol2(av.textColour2.getRGB()); - view.setTextColThreshold(av.thresholdTextColour); + view.setConservationSelected(av.getConservationSelected()); + view.setPidSelected(av.getAbovePIDThreshold()); + view.setFontName(av.font.getName()); + view.setFontSize(av.font.getSize()); + view.setFontStyle(av.font.getStyle()); + view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna()); + view.setRenderGaps(av.isRenderGaps()); + view.setShowAnnotation(av.isShowAnnotation()); + view.setShowBoxes(av.getShowBoxes()); + view.setShowColourText(av.getColourText()); + view.setShowFullId(av.getShowJVSuffix()); + view.setRightAlignIds(av.isRightAlignIds()); + view.setShowSequenceFeatures(av.isShowSequenceFeatures()); + view.setShowText(av.getShowText()); + view.setShowUnconserved(av.getShowUnconserved()); + view.setWrapAlignment(av.getWrapAlignment()); + view.setTextCol1(av.getTextColour().getRGB()); + view.setTextCol2(av.getTextColour2().getRGB()); + view.setTextColThreshold(av.getThresholdTextColour()); + view.setShowConsensusHistogram(av.isShowConsensusHistogram()); + view.setShowSequenceLogo(av.isShowSequenceLogo()); + view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo()); + view.setShowGroupConsensus(av.isShowGroupConsensus()); + view.setShowGroupConservation(av.isShowGroupConservation()); + view.setShowNPfeatureTooltip(av.isShowNPFeats()); + view.setShowDbRefTooltip(av.isShowDBRefs()); + view.setFollowHighlight(av.isFollowHighlight()); + view.setFollowSelection(av.followSelection); + view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus()); + if (av.getFeaturesDisplayed() != null) + { + jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings(); + String[] renderOrder = ap.getSeqPanel().seqCanvas + .getFeatureRenderer().getRenderOrder() + .toArray(new String[0]); - if(av.featuresDisplayed!=null) + Vector settingsAdded = new Vector(); + if (renderOrder != null) { - jalview.schemabinding.version2.FeatureSettings fs - = new jalview.schemabinding.version2.FeatureSettings(); - - String [] renderOrder = - ap.seqPanel.seqCanvas.getFeatureRenderer().renderOrder; - - Vector settingsAdded = new Vector(); - for(int ro=0; ro -1) + { + setting.setOrder(rorder); + } fs.addSetting(setting); - settingsAdded.addElement(renderOrder[ro]); + settingsAdded.addElement(featureType); } + } - //Make sure we save none displayed feature settings - Enumeration en = - ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours.keys(); - while(en.hasMoreElements()) + // is groups actually supposed to be a map here ? + Iterator en = ap.getSeqPanel().seqCanvas + .getFeatureRenderer() + .getFeatureGroups().iterator(); + Vector groupsAdded = new Vector(); + while (en.hasNext()) + { + String grp = en.next(); + if (groupsAdded.contains(grp)) { - String key = en.nextElement().toString(); - if(settingsAdded.contains(key)) - continue; - - Setting setting = new Setting(); - setting.setType(key); - setting.setColour( - ap.seqPanel.seqCanvas.getFeatureRenderer().getColour(key).getRGB() - ); - - setting.setDisplay(false); - - fs.addSetting(setting); - settingsAdded.addElement(key); + continue; } - - jms.setFeatureSettings(fs); - + Group g = new Group(); + g.setName(grp); + g.setDisplay(((Boolean) ap.getSeqPanel().seqCanvas + .getFeatureRenderer().checkGroupVisibility(grp, false)) + .booleanValue()); + fs.addGroup(g); + groupsAdded.addElement(grp); } + jms.setFeatureSettings(fs); + } - if(av.hasHiddenColumns) + if (av.hasHiddenColumns()) + { + if (av.getColumnSelection() == null + || av.getColumnSelection().getHiddenColumns() == null) + { + warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this."); + } + else { - for(int c=0; c 0) + { + for (String calcId : calcIdSet) { - //We may not want to right the object to disk, - //eg we can copy the alignViewport to a new view object - //using save and then load - try + if (calcId.trim().length() > 0) { - if (!fileName.endsWith(".xml")) + CalcIdParam cidp = createCalcIdParam(calcId, av); + // Some calcIds have no parameters. + if (cidp != null) { - fileName = fileName + ".xml"; + view.addCalcIdParam(cidp); } - - JarEntry entry = new JarEntry(fileName); - jout.putNextEntry(entry); - - object.marshal(out); - } - catch (Exception ex) - { - ex.printStackTrace(); } } - return object; + } + + jms.addViewport(view); } + object.setJalviewModelSequence(jms); + object.getVamsasModel().addSequenceSet(vamsasSet); - String SetUserColourScheme(jalview.schemes.ColourSchemeI cs, - Vector userColours, JalviewModelSequence jms) + if (jout != null && fileName != null) { - String id = null; - jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs; - - if (!userColours.contains(ucs)) - { - userColours.add(ucs); - - java.awt.Color[] colours = ucs.getColours(); - jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours(); - jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme(); - - for (int i = 0; i < colours.length; i++) - { - jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour(); - col.setName(ResidueProperties.aa[i]); - col.setRGB(jalview.util.Format.getHexString(colours[i])); - jbucs.addColour(col); - } - if(ucs.getLowerCaseColours()!=null) - { - colours = ucs.getLowerCaseColours(); - for (int i = 0; i < colours.length; i++) - { - jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour(); - col.setName(ResidueProperties.aa[i].toLowerCase()); - col.setRGB(jalview.util.Format.getHexString(colours[i])); - jbucs.addColour(col); - } - } - - id = "ucs" + userColours.indexOf(ucs); - uc.setId(id); - uc.setUserColourScheme(jbucs); - jms.addUserColours(uc); - } - - return id; + // We may not want to write the object to disk, + // eg we can copy the alignViewport to a new view object + // using save and then load + try + { + System.out.println("Writing jar entry " + fileName); + JarEntry entry = new JarEntry(fileName); + jout.putNextEntry(entry); + PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout, + UTF_8)); + Marshaller marshaller = new Marshaller(pout); + marshaller.marshal(object); + pout.flush(); + jout.closeEntry(); + } catch (Exception ex) + { + // TODO: raise error in GUI if marshalling failed. + ex.printStackTrace(); + } } + return object; + } - jalview.schemes.UserColourScheme GetUserColourScheme( - JalviewModelSequence jms, String id) + /** + * Save any Varna viewers linked to this sequence. Writes an rnaViewer element + * for each viewer, with + *
    + *
  • viewer geometry (position, size, split pane divider location)
  • + *
  • index of the selected structure in the viewer (currently shows gapped + * or ungapped)
  • + *
  • the id of the annotation holding RNA secondary structure
  • + *
  • (currently only one SS is shown per viewer, may be more in future)
  • + *
+ * Varna viewer state is also written out (in native Varna XML) to separate + * project jar entries. A separate entry is written for each RNA structure + * displayed, with the naming convention + *
    + *
  • rna_viewId_sequenceId_annotationId_[gapped|trimmed]
  • + *
+ * + * @param jout + * @param jseq + * @param jds + * @param viewIds + * @param ap + * @param storeDataset + */ + protected void saveRnaViewers(JarOutputStream jout, JSeq jseq, + final SequenceI jds, List viewIds, AlignmentPanel ap, + boolean storeDataset) + { + if (Desktop.desktop == null) { - UserColours[] uc = jms.getUserColours(); - UserColours colours = null; - - for (int i = 0; i < uc.length; i++) + return; + } + JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + for (int f = frames.length - 1; f > -1; f--) + { + if (frames[f] instanceof AppVarna) + { + AppVarna varna = (AppVarna) frames[f]; + /* + * link the sequence to every viewer that is showing it and is linked to + * its alignment panel + */ + if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel()) { - if (uc[i].getId().equals(id)) + String viewId = varna.getViewId(); + RnaViewer rna = new RnaViewer(); + rna.setViewId(viewId); + rna.setTitle(varna.getTitle()); + rna.setXpos(varna.getX()); + rna.setYpos(varna.getY()); + rna.setWidth(varna.getWidth()); + rna.setHeight(varna.getHeight()); + rna.setDividerLocation(varna.getDividerLocation()); + rna.setSelectedRna(varna.getSelectedIndex()); + jseq.addRnaViewer(rna); + + /* + * Store each Varna panel's state once in the project per sequence. + * First time through only (storeDataset==false) + */ + // boolean storeSessions = false; + // String sequenceViewId = viewId + seqsToIds.get(jds); + // if (!storeDataset && !viewIds.contains(sequenceViewId)) + // { + // viewIds.add(sequenceViewId); + // storeSessions = true; + // } + for (RnaModel model : varna.getModels()) + { + if (model.seq == jds) { - colours = uc[i]; + /* + * VARNA saves each view (sequence or alignment secondary + * structure, gapped or trimmed) as a separate XML file + */ + String jarEntryName = rnaSessions.get(model); + if (jarEntryName == null) + { - break; + String varnaStateFile = varna.getStateInfo(model.rna); + jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter(); + copyFileToJar(jout, varnaStateFile, jarEntryName); + rnaSessions.put(model, jarEntryName); + } + SecondaryStructure ss = new SecondaryStructure(); + String annotationId = varna.getAnnotation(jds).annotationId; + ss.setAnnotationId(annotationId); + ss.setViewerState(jarEntryName); + ss.setGapped(model.gapped); + ss.setTitle(model.title); + rna.addSecondaryStructure(ss); } + } } + } + } + } - java.awt.Color[] newColours = new java.awt.Color[24]; - - for (int i = 0; i < 24; i++) + /** + * Copy the contents of a file to a new entry added to the output jar + * + * @param jout + * @param infilePath + * @param jarEntryName + */ + protected void copyFileToJar(JarOutputStream jout, String infilePath, + String jarEntryName) + { + DataInputStream dis = null; + try + { + File file = new File(infilePath); + if (file.exists() && jout != null) + { + dis = new DataInputStream(new FileInputStream(file)); + byte[] data = new byte[(int) file.length()]; + dis.readFully(data); + writeJarEntry(jout, jarEntryName, data); + } + } catch (Exception ex) + { + ex.printStackTrace(); + } finally + { + if (dis != null) + { + try { - newColours[i] = new java.awt.Color(Integer.parseInt( - colours.getUserColourScheme().getColour(i).getRGB(), 16)); + dis.close(); + } catch (IOException e) + { + // ignore } + } + } + } + + /** + * Write the data to a new entry of given name in the output jar file + * + * @param jout + * @param jarEntryName + * @param data + * @throws IOException + */ + protected void writeJarEntry(JarOutputStream jout, String jarEntryName, + byte[] data) throws IOException + { + if (jout != null) + { + System.out.println("Writing jar entry " + jarEntryName); + jout.putNextEntry(new JarEntry(jarEntryName)); + DataOutputStream dout = new DataOutputStream(jout); + dout.write(data, 0, data.length); + dout.flush(); + jout.closeEntry(); + } + } - jalview.schemes.UserColourScheme ucs = - new jalview.schemes.UserColourScheme(newColours); + /** + * Save the state of a structure viewer + * + * @param ap + * @param jds + * @param pdb + * the archive XML element under which to save the state + * @param entry + * @param viewIds + * @param matchedFile + * @param viewFrame + * @return + */ + protected String saveStructureState(AlignmentPanel ap, SequenceI jds, + Pdbids pdb, PDBEntry entry, List viewIds, + String matchedFile, StructureViewerBase viewFrame) + { + final AAStructureBindingModel bindingModel = viewFrame.getBinding(); + + /* + * Look for any bindings for this viewer to the PDB file of interest + * (including part matches excluding chain id) + */ + for (int peid = 0; peid < bindingModel.getPdbCount(); peid++) + { + final PDBEntry pdbentry = bindingModel.getPdbEntry(peid); + final String pdbId = pdbentry.getId(); + if (!pdbId.equals(entry.getId()) + && !(entry.getId().length() > 4 && entry.getId() + .toLowerCase().startsWith(pdbId.toLowerCase()))) + { + /* + * not interested in a binding to a different PDB entry here + */ + continue; + } + if (matchedFile == null) + { + matchedFile = pdbentry.getFile(); + } + else if (!matchedFile.equals(pdbentry.getFile())) + { + Cache.log + .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): " + + pdbentry.getFile()); + } + // record the + // file so we + // can get at it if the ID + // match is ambiguous (e.g. + // 1QIP==1qipA) - if (colours.getUserColourScheme().getColourCount() > 24) + for (int smap = 0; smap < viewFrame.getBinding().getSequence()[peid].length; smap++) + { + // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1) + if (jds == viewFrame.getBinding().getSequence()[peid][smap]) { - newColours = new java.awt.Color[23]; - for (int i = 0; i < 23; i++) - { - newColours[i] = new java.awt.Color(Integer.parseInt( - colours.getUserColourScheme().getColour(i+24).getRGB(), 16)); - } - ucs.setLowerCaseColours(newColours); + StructureState state = new StructureState(); + state.setVisible(true); + state.setXpos(viewFrame.getX()); + state.setYpos(viewFrame.getY()); + state.setWidth(viewFrame.getWidth()); + state.setHeight(viewFrame.getHeight()); + final String viewId = viewFrame.getViewId(); + state.setViewId(viewId); + state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap)); + state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap)); + state.setColourByJmol(viewFrame.isColouredByViewer()); + state.setType(viewFrame.getViewerType().toString()); + pdb.addStructureState(state); } - - return ucs; + } + } + return matchedFile; + } + + private AnnotationColours constructAnnotationColours( + AnnotationColourGradient acg, List userColours, + JalviewModelSequence jms) + { + AnnotationColours ac = new AnnotationColours(); + ac.setAboveThreshold(acg.getAboveThreshold()); + ac.setThreshold(acg.getAnnotationThreshold()); + ac.setAnnotation(acg.getAnnotation()); + if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme) + { + ac.setColourScheme(setUserColourScheme(acg.getBaseColour(), + userColours, jms)); + } + else + { + ac.setColourScheme(ColourSchemeProperty.getColourName(acg + .getBaseColour())); } + ac.setMaxColour(acg.getMaxColour().getRGB()); + ac.setMinColour(acg.getMinColour().getRGB()); + ac.setPerSequence(acg.isSeqAssociated()); + ac.setPredefinedColours(acg.isPredefinedColours()); + return ac; + } - /** - * DOCUMENT ME! - * - * @param file DOCUMENT ME! - */ - public AlignFrame LoadJalviewAlign(final String file) + private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, + IdentityHashMap groupRefs, + AlignmentViewport av, Set calcIdSet, boolean storeDS, + SequenceSet vamsasSet) + { + + for (int i = 0; i < aa.length; i++) { - uniqueSetSuffix = System.currentTimeMillis()%100000 +""; + Annotation an = new Annotation(); + + AlignmentAnnotation annotation = aa[i]; + if (annotation.annotationId != null) + { + annotationIds.put(annotation.annotationId, annotation); + } - jalview.gui.AlignFrame af = null; + an.setId(annotation.annotationId); - seqRefIds = new Hashtable(); - viewportsAdded = new Hashtable(); + an.setVisible(annotation.visible); - Vector gatherToThisFrame= new Vector(); + an.setDescription(annotation.description); - try + if (annotation.sequenceRef != null) + { + // 2.9 JAL-1781 xref on sequence id rather than name + an.setSequenceRef(seqsToIds.get(annotation.sequenceRef)); + } + if (annotation.groupRef != null) + { + String groupIdr = groupRefs.get(annotation.groupRef); + if (groupIdr == null) { - //UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING - URL url = null; + // make a locally unique String + groupRefs.put( + annotation.groupRef, + groupIdr = ("" + System.currentTimeMillis() + + annotation.groupRef.getName() + groupRefs + .size())); + } + an.setGroupRef(groupIdr.toString()); + } - if (file.startsWith("http://")) - { - url = new URL(file); - } + // store all visualization attributes for annotation + an.setGraphHeight(annotation.graphHeight); + an.setCentreColLabels(annotation.centreColLabels); + an.setScaleColLabels(annotation.scaleColLabel); + an.setShowAllColLabels(annotation.showAllColLabels); + an.setBelowAlignment(annotation.belowAlignment); - JarInputStream jin = null; - JarEntry jarentry = null; - int entryCount = 1; + if (annotation.graph > 0) + { + an.setGraph(true); + an.setGraphType(annotation.graph); + an.setGraphGroup(annotation.graphGroup); + if (annotation.getThreshold() != null) + { + ThresholdLine line = new ThresholdLine(); + line.setLabel(annotation.getThreshold().label); + line.setValue(annotation.getThreshold().value); + line.setColour(annotation.getThreshold().colour.getRGB()); + an.setThresholdLine(line); + } + } + else + { + an.setGraph(false); + } - do - { - if (url != null) - { - jin = new JarInputStream(url.openStream()); - } - else - { - jin = new JarInputStream(new FileInputStream(file)); - } + an.setLabel(annotation.label); - for (int i = 0; i < entryCount; i++) - { - jarentry = jin.getNextJarEntry(); - } + if (annotation == av.getAlignmentQualityAnnot() + || annotation == av.getAlignmentConservationAnnotation() + || annotation == av.getAlignmentConsensusAnnotation() + || annotation.autoCalculated) + { + // new way of indicating autocalculated annotation - + an.setAutoCalculated(annotation.autoCalculated); + } + if (annotation.hasScore()) + { + an.setScore(annotation.getScore()); + } - if (jarentry != null && jarentry.getName().endsWith(".xml")) - { - InputStreamReader in = new InputStreamReader(jin, "UTF-8"); - JalviewModel object = new JalviewModel(); - - Unmarshaller unmar = new Unmarshaller(object); - unmar.setValidation(false); - object = (JalviewModel) unmar.unmarshal( in ); - - af = LoadFromObject(object, file, true); - if(af.viewport.gatherViewsHere) - { - gatherToThisFrame.add(af); - } - entryCount++; - } - else if (jarentry != null) - { - //Some other file here. - entryCount++; - } - } - while (jarentry != null); - } - catch(java.net.UnknownHostException ex) + if (annotation.getCalcId() != null) + { + calcIdSet.add(annotation.getCalcId()); + an.setCalcId(annotation.getCalcId()); + } + if (annotation.hasProperties()) + { + for (String pr : annotation.getProperties()) { - ex.printStackTrace(); - System.err.println("Couldn't locate Jalview XML file : " + - ex + "\n"); - - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "Couldn't locate " + file, - "URL not found", - JOptionPane.WARNING_MESSAGE); - } - }); + Property prop = new Property(); + prop.setName(pr); + prop.setValue(annotation.getProperty(pr)); + an.addProperty(prop); } - catch (Exception ex) + } + + AnnotationElement ae; + if (annotation.annotations != null) + { + an.setScoreOnly(false); + for (int a = 0; a < annotation.annotations.length; a++) { - //Is Version 1 Jar file? - af = new Jalview2XML_V1().LoadJalviewAlign(file); + if ((annotation == null) || (annotation.annotations[a] == null)) + { + continue; + } - if(af!=null) + ae = new AnnotationElement(); + if (annotation.annotations[a].description != null) + { + ae.setDescription(annotation.annotations[a].description); + } + if (annotation.annotations[a].displayCharacter != null) { - System.out.println("Successfully loaded archive file"); - return af; + ae.setDisplayCharacter(annotation.annotations[a].displayCharacter); } - System.err.println("Exception whilst loading jalview XML file : " + - ex + "\n"); - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + if (!Float.isNaN(annotation.annotations[a].value)) + { + ae.setValue(annotation.annotations[a].value); + } - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "Error loading " + file, - "Error loading Jalview file", - JOptionPane.WARNING_MESSAGE); - }}); - } + ae.setPosition(a); + if (annotation.annotations[a].secondaryStructure > ' ') + { + ae.setSecondaryStructure(annotation.annotations[a].secondaryStructure + + ""); + } - if (Desktop.instance != null) - Desktop.instance.stopLoading(); + if (annotation.annotations[a].colour != null + && annotation.annotations[a].colour != java.awt.Color.black) + { + ae.setColour(annotation.annotations[a].colour.getRGB()); + } - for (int i = 0; i < gatherToThisFrame.size(); i++) - { - Desktop.instance.gatherViews( - (AlignFrame) gatherToThisFrame.elementAt(i)); + an.addAnnotationElement(ae); + if (annotation.autoCalculated) + { + // only write one non-null entry into the annotation row - + // sufficient to get the visualization attributes necessary to + // display data + continue; + } } - - return af; + } + else + { + an.setScoreOnly(true); + } + if (!storeDS || (storeDS && !annotation.autoCalculated)) + { + // skip autocalculated annotation - these are only provided for + // alignments + vamsasSet.addAnnotation(an); + } } - String loadPDBFile(String file, String pdbId) + } + + private CalcIdParam createCalcIdParam(String calcId, AlignViewport av) + { + AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId); + if (settings != null) { - System.out.println(file +" "+pdbId); - try + CalcIdParam vCalcIdParam = new CalcIdParam(); + vCalcIdParam.setCalcId(calcId); + vCalcIdParam.addServiceURL(settings.getServiceURI()); + // generic URI allowing a third party to resolve another instance of the + // service used for this calculation + for (String urls : settings.getServiceURLs()) + { + vCalcIdParam.addServiceURL(urls); + } + vCalcIdParam.setVersion("1.0"); + if (settings.getPreset() != null) + { + WsParamSetI setting = settings.getPreset(); + vCalcIdParam.setName(setting.getName()); + vCalcIdParam.setDescription(setting.getDescription()); + } + else { - JarInputStream jin = null; + vCalcIdParam.setName(""); + vCalcIdParam.setDescription("Last used parameters"); + } + // need to be able to recover 1) settings 2) user-defined presets or + // recreate settings from preset 3) predefined settings provided by + // service - or settings that can be transferred (or discarded) + vCalcIdParam.setParameters(settings.getWsParamFile().replace("\n", + "|\\n|")); + vCalcIdParam.setAutoUpdate(settings.isAutoUpdate()); + // todo - decide if updateImmediately is needed for any projects. + + return vCalcIdParam; + } + return null; + } - if (file.startsWith("http://")) + private boolean recoverCalcIdParam(CalcIdParam calcIdParam, + AlignViewport av) + { + if (calcIdParam.getVersion().equals("1.0")) + { + Jws2Instance service = Jws2Discoverer.getDiscoverer() + .getPreferredServiceFor(calcIdParam.getServiceURL()); + if (service != null) + { + WsParamSetI parmSet = null; + try { - jin = new JarInputStream(new URL(file).openStream()); - } - else + parmSet = service.getParamStore().parseServiceParameterFile( + calcIdParam.getName(), calcIdParam.getDescription(), + calcIdParam.getServiceURL(), + calcIdParam.getParameters().replace("|\\n|", "\n")); + } catch (IOException x) { - jin = new JarInputStream(new FileInputStream(file)); + warn("Couldn't parse parameter data for " + + calcIdParam.getCalcId(), x); + return false; } - - JarEntry entry = null; - do + List argList = null; + if (calcIdParam.getName().length() > 0) { - entry = jin.getNextJarEntry(); + parmSet = service.getParamStore() + .getPreset(calcIdParam.getName()); + if (parmSet != null) + { + // TODO : check we have a good match with settings in AACon - + // otherwise we'll need to create a new preset + } } - while (!entry.getName().equals(pdbId)); - - BufferedReader in = new BufferedReader(new InputStreamReader(jin)); - File outFile = File.createTempFile("jalview_pdb", ".txt"); - outFile.deleteOnExit(); - PrintWriter out = new PrintWriter(new FileOutputStream(outFile)); - String data; - - while ( (data = in.readLine()) != null) + else { - out.println(data); + argList = parmSet.getArguments(); + parmSet = null; } - out.close(); - return outFile.getAbsolutePath(); - + AAConSettings settings = new AAConSettings( + calcIdParam.isAutoUpdate(), service, parmSet, argList); + av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings, + calcIdParam.isNeedsUpdate()); + return true; } - catch (Exception ex) + else { - ex.printStackTrace(); + warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server."); + return false; } - - return null; } + throw new Error(MessageManager.formatMessage( + "error.unsupported_version_calcIdparam", + new Object[] { calcIdParam.toString() })); + } + /** + * External mapping between jalview objects and objects yielding a valid and + * unique object ID string. This is null for normal Jalview project IO, but + * non-null when a jalview project is being read or written as part of a + * vamsas session. + */ + IdentityHashMap jv2vobj = null; - AlignFrame LoadFromObject(JalviewModel object, - String file, - boolean loadTrees ) + /** + * Construct a unique ID for jvobj using either existing bindings or if none + * exist, the result of the hashcode call for the object. + * + * @param jvobj + * jalview data object + * @return unique ID for referring to jvobj + */ + private String makeHashCode(Object jvobj, String altCode) + { + if (jv2vobj != null) { - SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0); - Sequence[] vamsasSeq = vamsasSet.getSequence(); + Object id = jv2vobj.get(jvobj); + if (id != null) + { + return id.toString(); + } + // check string ID mappings + if (jvids2vobj != null && jvobj instanceof String) + { + id = jvids2vobj.get(jvobj); + } + if (id != null) + { + return id.toString(); + } + // give up and warn that something has gone wrong + warn("Cannot find ID for object in external mapping : " + jvobj); + } + return altCode; + } - JalviewModelSequence jms = object.getJalviewModelSequence(); + /** + * return local jalview object mapped to ID, if it exists + * + * @param idcode + * (may be null) + * @return null or object bound to idcode + */ + private Object retrieveExistingObj(String idcode) + { + if (idcode != null && vobj2jv != null) + { + return vobj2jv.get(idcode); + } + return null; + } - Viewport view = jms.getViewport(0); + /** + * binding from ID strings from external mapping table to jalview data model + * objects. + */ + private Hashtable vobj2jv; + + private Sequence createVamsasSequence(String id, SequenceI jds) + { + return createVamsasSequence(true, id, jds, null); + } + + private Sequence createVamsasSequence(boolean recurse, String id, + SequenceI jds, SequenceI parentseq) + { + Sequence vamsasSeq = new Sequence(); + vamsasSeq.setId(id); + vamsasSeq.setName(jds.getName()); + vamsasSeq.setSequence(jds.getSequenceAsString()); + vamsasSeq.setDescription(jds.getDescription()); + jalview.datamodel.DBRefEntry[] dbrefs = null; + if (jds.getDatasetSequence() != null) + { + vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence())); + } + else + { + // seqId==dsseqid so we can tell which sequences really are + // dataset sequences only + vamsasSeq.setDsseqid(id); + dbrefs = jds.getDBRefs(); + if (parentseq == null) + { + parentseq = jds; + } + } + if (dbrefs != null) + { + for (int d = 0; d < dbrefs.length; d++) + { + DBRef dbref = new DBRef(); + dbref.setSource(dbrefs[d].getSource()); + dbref.setVersion(dbrefs[d].getVersion()); + dbref.setAccessionId(dbrefs[d].getAccessionId()); + if (dbrefs[d].hasMap()) + { + Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq, + jds, recurse); + dbref.setMapping(mp); + } + vamsasSeq.addDBRef(dbref); + } + } + return vamsasSeq; + } + + private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp, + SequenceI parentseq, SequenceI jds, boolean recurse) + { + Mapping mp = null; + if (jmp.getMap() != null) + { + mp = new Mapping(); - ////////////////////////////////// - //LOAD SEQUENCES + jalview.util.MapList mlst = jmp.getMap(); + List r = mlst.getFromRanges(); + for (int[] range : r) + { + MapListFrom mfrom = new MapListFrom(); + mfrom.setStart(range[0]); + mfrom.setEnd(range[1]); + mp.addMapListFrom(mfrom); + } + r = mlst.getToRanges(); + for (int[] range : r) + { + MapListTo mto = new MapListTo(); + mto.setStart(range[0]); + mto.setEnd(range[1]); + mp.addMapListTo(mto); + } + mp.setMapFromUnit(mlst.getFromRatio()); + mp.setMapToUnit(mlst.getToRatio()); + if (jmp.getTo() != null) + { + MappingChoice mpc = new MappingChoice(); - Vector hiddenSeqs = null; - jalview.datamodel.Sequence jseq; + // check/create ID for the sequence referenced by getTo() - ArrayList tmpseqs = new ArrayList(); + String jmpid = ""; + SequenceI ps = null; + if (parentseq != jmp.getTo() + && parentseq.getDatasetSequence() != jmp.getTo()) + { + // chaining dbref rather than a handshaking one + jmpid = seqHash(ps = jmp.getTo()); + } + else + { + jmpid = seqHash(ps = parentseq); + } + mpc.setDseqFor(jmpid); + if (!seqRefIds.containsKey(mpc.getDseqFor())) + { + jalview.bin.Cache.log.debug("creatign new DseqFor ID"); + seqRefIds.put(mpc.getDseqFor(), ps); + } + else + { + jalview.bin.Cache.log.debug("reusing DseqFor ID"); + } - boolean multipleView = false; + mp.setMappingChoice(mpc); + } + } + return mp; + } + + String setUserColourScheme(jalview.schemes.ColourSchemeI cs, + List userColours, JalviewModelSequence jms) + { + String id = null; + jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs; + boolean newucs = false; + if (!userColours.contains(ucs)) + { + userColours.add(ucs); + newucs = true; + } + id = "ucs" + userColours.indexOf(ucs); + if (newucs) + { + // actually create the scheme's entry in the XML model + java.awt.Color[] colours = ucs.getColours(); + jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours(); + jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme(); - JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq(); - for (int i = 0; i < JSEQ.length; i++) + for (int i = 0; i < colours.length; i++) + { + jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour(); + col.setName(ResidueProperties.aa[i]); + col.setRGB(jalview.util.Format.getHexString(colours[i])); + jbucs.addColour(col); + } + if (ucs.getLowerCaseColours() != null) + { + colours = ucs.getLowerCaseColours(); + for (int i = 0; i < colours.length; i++) { - String seqId = JSEQ[i].getId() + ""; + jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour(); + col.setName(ResidueProperties.aa[i].toLowerCase()); + col.setRGB(jalview.util.Format.getHexString(colours[i])); + jbucs.addColour(col); + } + } - if (seqRefIds.get(seqId) != null) - { - tmpseqs.add( (jalview.datamodel.Sequence) seqRefIds.get(seqId)); - multipleView = true; - } - else - { - jseq = new jalview.datamodel.Sequence(vamsasSeq[i].getName(), - vamsasSeq[i].getSequence()); - jseq.setDescription(vamsasSeq[i].getDescription()); - jseq.setStart(JSEQ[i].getStart()); - jseq.setEnd(JSEQ[i].getEnd()); - seqRefIds.put(vamsasSeq[i].getId(), jseq); - tmpseqs.add( jseq ); - } + uc.setId(id); + uc.setUserColourScheme(jbucs); + jms.addUserColours(uc); + } + return id; + } + jalview.schemes.UserColourScheme getUserColourScheme( + JalviewModelSequence jms, String id) + { + UserColours[] uc = jms.getUserColours(); + UserColours colours = null; - if (JSEQ[i].getHidden()) - { - if (hiddenSeqs == null) - hiddenSeqs = new Vector(); + for (int i = 0; i < uc.length; i++) + { + if (uc[i].getId().equals(id)) + { + colours = uc[i]; + break; + } + } - hiddenSeqs.addElement( - (jalview.datamodel.Sequence) seqRefIds.get(seqId)); - } + java.awt.Color[] newColours = new java.awt.Color[24]; - } + for (int i = 0; i < 24; i++) + { + newColours[i] = new java.awt.Color(Integer.parseInt(colours + .getUserColourScheme().getColour(i).getRGB(), 16)); + } + + jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme( + newColours); - ///SequenceFeatures are added to the DatasetSequence, - // so we must create the dataset before loading features - ///////////////////////////////// + if (colours.getUserColourScheme().getColourCount() > 24) + { + newColours = new java.awt.Color[23]; + for (int i = 0; i < 23; i++) + { + newColours[i] = new java.awt.Color(Integer.parseInt(colours + .getUserColourScheme().getColour(i + 24).getRGB(), 16)); + } + ucs.setLowerCaseColours(newColours); + } + return ucs; + } - jalview.datamodel.Sequence[] orderedSeqs = new jalview.datamodel.Sequence[ - tmpseqs.size()]; + /** + * contains last error message (if any) encountered by XML loader. + */ + String errorMessage = null; - tmpseqs.toArray(orderedSeqs) ; + /** + * flag to control whether the Jalview2XML_V1 parser should be deferred to if + * exceptions are raised during project XML parsing + */ + public boolean attemptversion1parse = true; + /** + * Load a jalview project archive from a jar file + * + * @param file + * - HTTP URL or filename + */ + public AlignFrame loadJalviewAlign(final String file) + { - jalview.datamodel.Alignment al = - new jalview.datamodel.Alignment(orderedSeqs); + jalview.gui.AlignFrame af = null; - al.setDataset(null); - ///////////////////////////////// + try + { + // create list to store references for any new Jmol viewers created + newStructureViewers = new Vector(); + // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING + // Workaround is to make sure caller implements the JarInputStreamProvider + // interface + // so we can re-open the jar input stream for each entry. + jarInputStreamProvider jprovider = createjarInputStreamProvider(file); + af = loadJalviewAlign(jprovider); - Hashtable pdbloaded = new Hashtable(); - if(!multipleView) + } catch (MalformedURLException e) + { + errorMessage = "Invalid URL format for '" + file + "'"; + reportErrors(); + } finally + { + try + { + SwingUtilities.invokeAndWait(new Runnable() { - for (int i = 0; i < vamsasSeq.length; i++) + @Override + public void run() { - if (JSEQ[i].getFeaturesCount() > 0) - { - Features[] features = JSEQ[i].getFeatures(); - for (int f = 0; f < features.length; f++) - { - jalview.datamodel.SequenceFeature sf - = new jalview.datamodel.SequenceFeature(features[f].getType(), - features[f].getDescription(), features[f].getStatus(), - features[f].getBegin(), features[f].getEnd(), - features[f].getFeatureGroup()); - - sf.setScore(features[f].getScore()); - for (int od = 0; od < features[f].getOtherDataCount(); od++) - { - OtherData keyValue = features[f].getOtherData(od); - if (keyValue.getKey().startsWith("LINK")) - sf.addLink(keyValue.getValue()); - else - sf.setValue(keyValue.getKey(), keyValue.getValue()); + setLoadingFinishedForNewStructureViewers(); + }; + }); + } catch (Exception x) + { + System.err.println("Error loading alignment: " + x.getMessage()); + } + } + return af; + } + + private jarInputStreamProvider createjarInputStreamProvider( + final String file) throws MalformedURLException + { + URL url = null; + errorMessage = null; + uniqueSetSuffix = null; + seqRefIds = null; + viewportsAdded.clear(); + frefedSequence = null; + + if (file.startsWith("http://")) + { + url = new URL(file); + } + final URL _url = url; + return new jarInputStreamProvider() + { - } + @Override + public JarInputStream getJarInputStream() throws IOException + { + if (_url != null) + { + return new JarInputStream(_url.openStream()); + } + else + { + return new JarInputStream(new FileInputStream(file)); + } + } - al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf); - } - } - if (JSEQ[i].getPdbidsCount() > 0) - { - Pdbids[] ids = JSEQ[i].getPdbids(); - for (int p = 0; p < ids.length; p++) - { - jalview.datamodel.PDBEntry entry = new jalview.datamodel. - PDBEntry(); - entry.setId(ids[p].getId()); - entry.setType(ids[p].getType()); - if (ids[p].getFile() != null) - { - if (!pdbloaded.containsKey(ids[p].getFile())) - { - String tmppdb = loadPDBFile(file, ids[p].getId()); - entry.setFile(tmppdb); - pdbloaded.put(ids[p].getId(), tmppdb); - } - else - entry.setFile(pdbloaded.get(ids[p].getId()).toString()); - } + @Override + public String getFilename() + { + return file; + } + }; + } - al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); - } - } - if (vamsasSeq[i].getDBRefCount() > 0) + /** + * Recover jalview session from a jalview project archive. Caller may + * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence + * themselves. Any null fields will be initialised with default values, + * non-null fields are left alone. + * + * @param jprovider + * @return + */ + public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider) + { + errorMessage = null; + if (uniqueSetSuffix == null) + { + uniqueSetSuffix = System.currentTimeMillis() % 100000 + ""; + } + if (seqRefIds == null) + { + initSeqRefs(); + } + AlignFrame af = null, _af = null; + Map gatherToThisFrame = new HashMap(); + final String file = jprovider.getFilename(); + try + { + JarInputStream jin = null; + JarEntry jarentry = null; + int entryCount = 1; + + do + { + jin = jprovider.getJarInputStream(); + for (int i = 0; i < entryCount; i++) + { + jarentry = jin.getNextJarEntry(); + } + + if (jarentry != null && jarentry.getName().endsWith(".xml")) + { + InputStreamReader in = new InputStreamReader(jin, UTF_8); + JalviewModel object = new JalviewModel(); + + Unmarshaller unmar = new Unmarshaller(object); + unmar.setValidation(false); + object = (JalviewModel) unmar.unmarshal(in); + if (true) // !skipViewport(object)) + { + _af = loadFromObject(object, file, true, jprovider); + if (object.getJalviewModelSequence().getViewportCount() > 0) { - for (int d = 0; d < vamsasSeq[i].getDBRefCount(); d++) + af = _af; + if (af.viewport.isGatherViewsHere()) { - jalview.datamodel.DBRefEntry entry = - new jalview.datamodel.DBRefEntry( - vamsasSeq[i].getDBRef(d).getSource(), - vamsasSeq[i].getDBRef(d).getVersion(), - vamsasSeq[i].getDBRef(d).getAccessionId() - ); - al.getSequenceAt(i).getDatasetSequence().addDBRef(entry); + gatherToThisFrame.put(af.viewport.getSequenceSetId(), af); } - } } + entryCount++; } - - - ///////////////////////////////// - ////////////////////////////////// - //LOAD ANNOTATIONS - boolean hideQuality = true, - hideConservation = true, - hideConsensus = true; - - if (vamsasSet.getAnnotationCount()>0) + else if (jarentry != null) { - Annotation[] an = vamsasSet.getAnnotation(); - - for (int i = 0; i < an.length; i++) - { - if (an[i].getLabel().equals("Quality")) - { - hideQuality = false; - continue; - } - else if(an[i].getLabel().equals("Conservation")) - { - hideConservation = false; - continue; - } - else if(an[i].getLabel().equals("Consensus")) - { - hideConsensus = false; - continue; - } - - AnnotationElement[] ae = an[i].getAnnotationElement(); - jalview.datamodel.Annotation[] anot = new jalview.datamodel.Annotation[al.getWidth()]; - - for (int aa = 0; aa < ae.length; aa++) - { - anot[ae[aa].getPosition()] = new jalview.datamodel.Annotation(ae[aa].getDisplayCharacter(), - ae[aa].getDescription(), - ae[aa].getSecondaryStructure().length()==0?' ':ae[aa].getSecondaryStructure().charAt(0), - ae[aa].getValue()); - anot[ae[aa].getPosition()].colour = new java.awt.Color( ae[aa].getColour() ); - } + // Some other file here. + entryCount++; + } + } while (jarentry != null); + resolveFrefedSequences(); + } catch (IOException ex) + { + ex.printStackTrace(); + errorMessage = "Couldn't locate Jalview XML file : " + file; + System.err.println("Exception whilst loading jalview XML file : " + + ex + "\n"); + } catch (Exception ex) + { + System.err.println("Parsing as Jalview Version 2 file failed."); + ex.printStackTrace(System.err); + if (attemptversion1parse) + { + // Is Version 1 Jar file? + try + { + af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider); + } catch (Exception ex2) + { + System.err.println("Exception whilst loading as jalviewXMLV1:"); + ex2.printStackTrace(); + af = null; + } + } + if (Desktop.instance != null) + { + Desktop.instance.stopLoading(); + } + if (af != null) + { + System.out.println("Successfully loaded archive file"); + return af; + } + ex.printStackTrace(); - jalview.datamodel.AlignmentAnnotation jaa = null; + System.err.println("Exception whilst loading jalview XML file : " + + ex + "\n"); + } catch (OutOfMemoryError e) + { + // Don't use the OOM Window here + errorMessage = "Out of memory loading jalview XML file"; + System.err.println("Out of memory whilst loading jalview XML file"); + e.printStackTrace(); + } - if (an[i].getGraph()) - { - jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), - an[i].getDescription(), anot, 0, 0, - an[i].getGraphType()); + if (Desktop.instance != null) + { + Desktop.instance.stopLoading(); + } - jaa.graphGroup = an[i].getGraphGroup(); + /* + * Regather multiple views (with the same sequence set id) to the frame (if + * any) that is flagged as the one to gather to, i.e. convert them to tabbed + * views instead of separate frames. Note this doesn't restore a state where + * some expanded views in turn have tabbed views - the last "first tab" read + * in will play the role of gatherer for all. + */ + for (AlignFrame fr : gatherToThisFrame.values()) + { + Desktop.instance.gatherViews(fr); + } - if (an[i].getThresholdLine() != null) - { - jaa.setThreshold(new jalview.datamodel.GraphLine( - an[i].getThresholdLine().getValue(), - an[i].getThresholdLine().getLabel(), - new java.awt.Color(an[i].getThresholdLine().getColour())) - ); + restoreSplitFrames(); - } + if (errorMessage != null) + { + reportErrors(); + } + return af; + } - } - else - { - jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), - an[i].getDescription(), anot); - } - - if(an[i].getSequenceRef()!=null) - { - jaa.createSequenceMapping( - al.findName(an[i].getSequenceRef()), 1, true - ); - al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa); - } - - al.addAnnotation(jaa); - } - } + /** + * Try to reconstruct and display SplitFrame windows, where each contains + * complementary dna and protein alignments. Done by pairing up AlignFrame + * objects (created earlier) which have complementary viewport ids associated. + */ + protected void restoreSplitFrames() + { + List gatherTo = new ArrayList(); + List addedToSplitFrames = new ArrayList(); + Map dna = new HashMap(); + + /* + * Identify the DNA alignments + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (af.getViewport().getAlignment().isNucleotide()) + { + dna.put(candidate.getKey().getId(), af); + } + } - ///////////////////////// - //LOAD GROUPS - if (jms.getJGroupCount() > 0) + /* + * Try to match up the protein complements + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (!af.getViewport().getAlignment().isNucleotide()) + { + String complementId = candidate.getKey().getComplementId(); + // only non-null complements should be in the Map + if (complementId != null && dna.containsKey(complementId)) { - JGroup[] groups = jms.getJGroup(); + final AlignFrame dnaFrame = dna.get(complementId); + SplitFrame sf = createSplitFrame(dnaFrame, af); + addedToSplitFrames.add(dnaFrame); + addedToSplitFrames.add(af); + if (af.viewport.isGatherViewsHere()) + { + gatherTo.add(sf); + } + } + } + } - for (int i = 0; i < groups.length; i++) - { - ColourSchemeI cs = null; + /* + * Open any that we failed to pair up (which shouldn't happen!) as + * standalone AlignFrame's. + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (!addedToSplitFrames.contains(af)) + { + Viewport view = candidate.getKey(); + Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(), + view.getHeight()); + System.err.println("Failed to restore view " + view.getTitle() + + " to split frame"); + } + } - if (groups[i].getColour() != null) - { - if (groups[i].getColour().startsWith("ucs")) - { - cs = GetUserColourScheme(jms, groups[i].getColour()); - } - else - { - cs = ColourSchemeProperty.getColour(al, - groups[i].getColour()); - } - - if(cs!=null) - cs.setThreshold(groups[i].getPidThreshold(), true); - } + /* + * Gather back into tabbed views as flagged. + */ + for (SplitFrame sf : gatherTo) + { + Desktop.instance.gatherViews(sf); + } - Vector seqs = new Vector(); + splitFrameCandidates.clear(); + } - for (int s = 0; s < groups[i].getSeqCount(); s++) - { - String seqId = groups[i].getSeq(s)+""; - seqs.addElement((jalview.datamodel.SequenceI) seqRefIds.get(seqId)); - } + /** + * Construct and display one SplitFrame holding DNA and protein alignments. + * + * @param dnaFrame + * @param proteinFrame + * @return + */ + protected SplitFrame createSplitFrame(AlignFrame dnaFrame, + AlignFrame proteinFrame) + { + SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame); + String title = MessageManager.getString("label.linked_view_title"); + int width = (int) dnaFrame.getBounds().getWidth(); + int height = (int) (dnaFrame.getBounds().getHeight() + + proteinFrame.getBounds().getHeight() + 50); + + /* + * SplitFrame location is saved to both enclosed frames + */ + splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY()); + Desktop.addInternalFrame(splitFrame, title, width, height); - jalview.datamodel.SequenceGroup sg = new jalview.datamodel.SequenceGroup(seqs, - groups[i].getName(), cs, groups[i].getDisplayBoxes(), - groups[i].getDisplayText(), groups[i].getColourText(), - groups[i].getStart(), groups[i].getEnd()); + /* + * And compute cDNA consensus (couldn't do earlier with consensus as + * mappings were not yet present) + */ + proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel); - sg.setOutlineColour(new java.awt.Color( - groups[i].getOutlineColour())); + return splitFrame; + } - sg.textColour = new java.awt.Color(groups[i].getTextCol1()); - sg.textColour2 = new java.awt.Color(groups[i].getTextCol2()); - sg.thresholdTextColour = groups[i].getTextColThreshold(); + /** + * check errorMessage for a valid error message and raise an error box in the + * GUI or write the current errorMessage to stderr and then clear the error + * state. + */ + protected void reportErrors() + { + reportErrors(false); + } + + protected void reportErrors(final boolean saving) + { + if (errorMessage != null) + { + final String finalErrorMessage = errorMessage; + if (raiseGUI) + { + javax.swing.SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + JOptionPane.showInternalMessageDialog(Desktop.desktop, + finalErrorMessage, "Error " + + (saving ? "saving" : "loading") + + " Jalview file", JOptionPane.WARNING_MESSAGE); + } + }); + } + else + { + System.err.println("Problem loading Jalview file: " + errorMessage); + } + } + errorMessage = null; + } - if (groups[i].getConsThreshold() != 0) - { - jalview.analysis.Conservation c = new jalview.analysis.Conservation("All", - ResidueProperties.propHash, 3, sg.getSequences(null), 0, - sg.getWidth() - 1); - c.calculate(); - c.verdict(false, 25); - sg.cs.setConservation(c); - } + Map alreadyLoadedPDB = new HashMap(); - al.addGroup(sg); - } - } + /** + * when set, local views will be updated from view stored in JalviewXML + * Currently (28th Sep 2008) things will go horribly wrong in vamsas document + * sync if this is set to true. + */ + private final boolean updateLocalViews = false; + /** + * Returns the path to a temporary file holding the PDB file for the given PDB + * id. The first time of asking, searches for a file of that name in the + * Jalview project jar, and copies it to a new temporary file. Any repeat + * requests just return the path to the file previously created. + * + * @param jprovider + * @param pdbId + * @return + */ + String loadPDBFile(jarInputStreamProvider jprovider, String pdbId) + { + if (alreadyLoadedPDB.containsKey(pdbId)) + { + return alreadyLoadedPDB.get(pdbId).toString(); + } - ///////////////////////////////// - // LOAD VIEWPORT + String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb"); + if (tempFile != null) + { + alreadyLoadedPDB.put(pdbId, tempFile); + } + return tempFile; + } - AlignFrame af = new AlignFrame(al, - view.getWidth(), - view.getHeight() ); + /** + * Copies the jar entry of given name to a new temporary file and returns the + * path to the file, or null if the entry is not found. + * + * @param jprovider + * @param jarEntryName + * @param prefix + * a prefix for the temporary file name, must be at least three + * characters long + * @return + */ + protected String copyJarEntry(jarInputStreamProvider jprovider, + String jarEntryName, String prefix) + { + BufferedReader in = null; + PrintWriter out = null; - af.setFileName(file, "Jalview"); + try + { + JarInputStream jin = jprovider.getJarInputStream(); + /* + * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new + * URL(jprovider).openStream()); } else { jin = new JarInputStream(new + * FileInputStream(jprovider)); } + */ + + JarEntry entry = null; + do + { + entry = jin.getNextJarEntry(); + } while (entry != null && !entry.getName().equals(jarEntryName)); + if (entry != null) + { + in = new BufferedReader(new InputStreamReader(jin, UTF_8)); + File outFile = File.createTempFile(prefix, ".tmp"); + outFile.deleteOnExit(); + out = new PrintWriter(new FileOutputStream(outFile)); + String data; - for (int i = 0; i < JSEQ.length; i++) + while ((data = in.readLine()) != null) + { + out.println(data); + } + out.flush(); + String t = outFile.getAbsolutePath(); + return t; + } + else + { + warn("Couldn't find entry in Jalview Jar for " + jarEntryName); + } + } catch (Exception ex) + { + ex.printStackTrace(); + } finally + { + if (in != null) + { + try + { + in.close(); + } catch (IOException e) { - af.viewport.setSequenceColour( - af.viewport.alignment.getSequenceAt(i), - new java.awt.Color( - JSEQ[i].getColour())); + // ignore } + } + if (out != null) + { + out.close(); + } + } - //If we just load in the same jar file again, the sequenceSetId - //will be the same, and we end up with multiple references - //to the same sequenceSet. We must modify this id on load - //so that each load of the file gives a unique id - String uniqueSeqSetId = view.getSequenceSetId()+uniqueSetSuffix; + return null; + } - af.viewport.gatherViewsHere = view.getGatheredViews(); + private class JvAnnotRow + { + public JvAnnotRow(int i, AlignmentAnnotation jaa) + { + order = i; + template = jaa; + } - if (view.getSequenceSetId() != null) - { - jalview.gui.AlignViewport av = - (jalview.gui.AlignViewport) - viewportsAdded.get(uniqueSeqSetId); + /** + * persisted version of annotation row from which to take vis properties + */ + public jalview.datamodel.AlignmentAnnotation template; - af.viewport.sequenceSetID = uniqueSeqSetId; - if(av!=null) - { + /** + * original position of the annotation row in the alignment + */ + public int order; + } - af.viewport.historyList = av.historyList; - af.viewport.redoList = av.redoList; - } - else - { - viewportsAdded.put(uniqueSeqSetId, af.viewport); - } + /** + * Load alignment frame from jalview XML DOM object + * + * @param object + * DOM + * @param file + * filename source string + * @param loadTreesAndStructures + * when false only create Viewport + * @param jprovider + * data source provider + * @return alignment frame created from view stored in DOM + */ + AlignFrame loadFromObject(JalviewModel object, String file, + boolean loadTreesAndStructures, jarInputStreamProvider jprovider) + { + SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0); + Sequence[] vamsasSeq = vamsasSet.getSequence(); - PaintRefresher.Register(af.alignPanel, uniqueSeqSetId); - } - if(hiddenSeqs!=null) - { - for(int s=0; s