X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=f9a2fa9a9c66fdd856b2a4a9a9a4c4407d61820a;hb=2d3bf89e4c4a93d78af9772a78e94d5be7d15402;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..a2cd147 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1,1691 +1,4745 @@ /* - * 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 2.8.2) + * Copyright (C) 2014 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.schemes.*; - -import java.io.*; - -import java.net.*; - -import java.util.*; - -import java.util.jar.*; - -import javax.swing.*; - -import org.exolab.castor.xml.*; - -import jalview.schemabinding.version2.*; - - - +import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Cache; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.datamodel.StructureViewerModel; +import jalview.datamodel.StructureViewerModel.StructureData; +import jalview.schemabinding.version2.AlcodMap; +import jalview.schemabinding.version2.Alcodon; +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.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.GraduatedColor; +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.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.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.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.StringTokenizer; +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.Unmarshaller; /** - * DOCUMENT ME! - * + * 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$ + * @version $Revision: 1.134 $ */ public class Jalview2XML { - - Hashtable seqRefIds; + /* + * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps + * of sequence objects are created. + */ + IdentityHashMap seqsToIds = null; /** - * This maintains a list of viewports, the key being the - * seqSetId. Important to set historyItem and redoList - * for multiple views + * jalview XML Sequence ID to jalview sequence object reference (both dataset + * and alignment sequences. Populated as XML reps of sequence objects are + * created.) */ - Hashtable viewportsAdded; + Map seqRefIds = null; - String uniqueSetSuffix = ""; + Vector frefedSequence = null; + boolean raiseGUI = true; // whether errors are raised in dialog boxes or not - // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE - public void SaveState(File statefile) + /** + * create/return unique hash string for sq + * + * @param sq + * @return new or existing unique string for sq + */ + String seqHash(SequenceI sq) + { + if (seqsToIds == null) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + 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; + } + } - if (frames == null) - { - return; - } + void clearSeqRefs() + { + if (_cleartables) + { + if (seqRefIds != null) + { + seqRefIds.clear(); + } + if (seqsToIds != null) + { + seqsToIds.clear(); + } + // seqRefIds = null; + // seqsToIds = null; + } + else + { + // do nothing + warn("clearSeqRefs called when _cleartables was not set. Doing nothing."); + // seqRefIds = new Hashtable(); + // seqsToIds = new IdentityHashMap(); + } + } - try - { - FileOutputStream fos = new FileOutputStream(statefile); - JarOutputStream jout = new JarOutputStream(fos); + void initSeqRefs() + { + if (seqsToIds == null) + { + seqsToIds = new IdentityHashMap(); + } + if (seqRefIds == null) + { + seqRefIds = new HashMap(); + } + } - //NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS - //////////////////////////////////////////////////// - PrintWriter out = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); + public Jalview2XML() + { + } - Vector shortNames = new Vector(); + public Jalview2XML(boolean raiseGUI) + { + this.raiseGUI = raiseGUI; + } - //REVERSE ORDER - for (int i = frames.length - 1; i > -1; i--) + public void resolveFrefedSequences() + { + if (frefedSequence.size() > 0) + { + int r = 0, rSize = frefedSequence.size(); + while (r < rSize) + { + Object[] ref = (Object[]) frefedSequence.elementAt(r); + if (ref != null) + { + String sref = (String) ref[0]; + if (seqRefIds.containsKey(sref)) + { + if (ref[1] instanceof jalview.datamodel.Mapping) + { + SequenceI seq = seqRefIds.get(sref); + while (seq.getDatasetSequence() != null) + { + seq = seq.getDatasetSequence(); + } + ((jalview.datamodel.Mapping) ref[1]).setTo(seq); + } + else { - if (frames[i] instanceof AlignFrame) + if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame) + { + SequenceI seq = seqRefIds.get(sref); + while (seq.getDatasetSequence() != null) + { + seq = seq.getDatasetSequence(); + } + if (ref[2] != null + && ref[2] instanceof jalview.datamodel.Mapping) { - 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); - } + jalview.datamodel.Mapping mp = (jalview.datamodel.Mapping) ref[2]; + ((jalview.datamodel.AlignedCodonFrame) ref[1]).addMap( + seq, mp.getTo(), mp.getMap()); } + else + { + System.err + .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for AlcodonFrames involving " + + ref[2].getClass() + " type objects."); + } + } + else + { + System.err + .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for " + + ref[1].getClass() + " type objects."); + } } - - out.close(); - jout.close(); + frefedSequence.remove(r); + rSize--; + } + else + { + System.err + .println("IMPLEMENTATION WARNING: Unresolved forward reference for hash string " + + ref[0] + + " with objecttype " + + ref[1].getClass()); + r++; + } } - catch (Exception ex) + else { - ex.printStackTrace(); + // empty reference + frefedSequence.remove(r); + rSize--; } + } } + } + + /** + * This maintains a list of viewports, the key being the seqSetId. Important + * to set historyItem and redoList for multiple views + */ + Hashtable viewportsAdded; + + Hashtable annotationIds = new Hashtable(); + + 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 dsses = new Hashtable(); - JalviewModel object = new JalviewModel(); - object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); + try + { - object.setCreationDate(new java.util.Date(System.currentTimeMillis())); - object.setVersion(jalview.bin.Cache.getProperty("VERSION")); + // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS + // ////////////////////////////////////////////////// - jalview.datamodel.AlignmentI jal = av.alignment; + Vector shortNames = new Vector(); - if(av.hasHiddenRows) + // REVERSE ORDER + for (int i = frames.length - 1; i > -1; i--) + { + if (frames[i] instanceof AlignFrame) { - jal = jal.getHiddenSequences().getFullAlignment(); - } - - SequenceSet vamsasSet = new SequenceSet(); - Sequence vamsasSeq; - JalviewModelSequence jms = new JalviewModelSequence(); + AlignFrame af = (AlignFrame) frames[i]; + // skip ? + if (skipList != null + && skipList.containsKey(af.getViewport() + .getSequenceSetId())) + { + continue; + } - vamsasSet.setGapChar(jal.getGapCharacter() + ""); + String shortName = af.getTitle(); - JSeq jseq; - Vector pdbfiles = null; + if (shortName.indexOf(File.separatorChar) > -1) + { + shortName = shortName.substring(shortName + .lastIndexOf(File.separatorChar) + 1); + } - //SAVE SEQUENCES - int id = 0; - jalview.datamodel.SequenceI jds; - for (int i = 0; i < jal.getHeight(); i++) - { - jds = jal.getSequenceAt(i); - id = jds.hashCode(); + int count = 1; - if(seqRefIds.get(id+"")!=null) + while (shortNames.contains(shortName)) + { + if (shortName.endsWith("_" + (count - 1))) { - + shortName = shortName + .substring(0, shortName.lastIndexOf("_")); } - else - { - vamsasSeq = new Sequence(); - vamsasSeq.setId(id + ""); - vamsasSeq.setName(jds.getName()); - vamsasSeq.setSequence(jds.getSequenceAsString()); - vamsasSeq.setDescription(jds.getDescription()); - if (jds.getDatasetSequence().getDBRef() != null) - { - jalview.datamodel.DBRefEntry[] dbrefs = - jds.getDatasetSequence().getDBRef(); - - 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); - } - } + shortName = shortName.concat("_" + count); + count++; + } - vamsasSet.addSequence(vamsasSeq); - seqRefIds.put(id+"", jal.getSequenceAt(i)); - } + shortNames.addElement(shortName); - jseq = new JSeq(); - jseq.setStart(jds.getStart()); - jseq.setEnd(jds.getEnd()); - jseq.setColour( av.getSequenceColour(jds).getRGB()); + if (!shortName.endsWith(".xml")) + { + shortName = shortName + ".xml"; + } - jseq.setId(id); + int ap, apSize = af.alignPanels.size(); - if (av.hasHiddenRows) + for (ap = 0; ap < apSize; ap++) + { + AlignmentPanel apanel = (AlignmentPanel) af.alignPanels + .elementAt(ap); + String fileName = apSize == 1 ? shortName : ap + shortName; + if (!fileName.endsWith(".xml")) { - jseq.setHidden(av.alignment.getHiddenSequences().isHidden(jds)); + fileName = fileName + ".xml"; + } - 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); + saveState(apanel, fileName, jout); - for(int h=0; h dsses = new Hashtable(); + for (ap = 0; ap < apSize; ap++) + { + AlignmentPanel apanel = (AlignmentPanel) af.alignPanels + .elementAt(ap); + String jfileName = apSize == 1 ? fileName : fileName + ap; + if (!jfileName.endsWith(".xml")) + { + jfileName = jfileName + ".xml"; + } + saveState(apanel, jfileName, jout); + String dssid = getDatasetIdRef(af.getViewport().getAlignment() + .getDataset()); + if (!dsses.containsKey(dssid)) + { + dsses.put(dssid, af); + } + } + writeDatasetFor(dsses, fileName, 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; + } + } - pdb.setId(entry.getId()); - pdb.setType(entry.getType()); + private void writeDatasetFor(Hashtable dsses, + String fileName, JarOutputStream jout) + { + 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); + } + } - if(entry.getFile()!=null) - { - pdb.setFile(entry.getFile()); - if(pdbfiles==null) - pdbfiles = new Vector(); + /** + * 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 out + * jar entry name + */ + public JalviewModel saveState(AlignmentPanel ap, String fileName, + JarOutputStream jout) + { + return saveState(ap, fileName, false, jout); + } - 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(); - } - } - } + /** + * 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 storeDS + * when true, only write the dataset for the alignment, not the data + * associated with the view. + * @param jout + * jar output stream + * @param out + * jar entry name + */ + public JalviewModel saveState(AlignmentPanel ap, String fileName, + boolean storeDS, JarOutputStream jout) + { + initSeqRefs(); + List viewIds = new ArrayList(); + List userColours = new ArrayList(); + AlignViewport av = ap.av; - 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); - } + JalviewModel object = new JalviewModel(); + object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); - jseq.addPdbids(pdb); - } - } + object.setCreationDate(new java.util.Date(System.currentTimeMillis())); + object.setVersion(jalview.bin.Cache.getDefault("VERSION", + "Development Build")); - jms.addJSeq(jseq); - } + jalview.datamodel.AlignmentI jal = av.getAlignment(); + + if (av.hasHiddenRows()) + { + jal = jal.getHiddenSequences().getFullAlignment(); + } + + SequenceSet vamsasSet = new SequenceSet(); + Sequence vamsasSeq; + JalviewModelSequence jms = new JalviewModelSequence(); + + vamsasSet.setGapChar(jal.getGapCharacter() + ""); - if(av.hasHiddenRows) - jal = av.alignment; + 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(); + } + } + 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 jseq; + Set calcIdSet = new HashSet(); + + // SAVE SEQUENCES + String id = ""; + jalview.datamodel.SequenceI jds, jdatasq; + for (int i = 0; i < jal.getHeight(); i++) + { + jds = jal.getSequenceAt(i); + jdatasq = jds.getDatasetSequence() == null ? jds : jds + .getDatasetSequence(); + id = seqHash(jds); + + 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) + jseq.setHidden(av.getAlignment().getHiddenSequences() + .isHidden(jds)); + + if (av.isHiddenRepSequence(jal.getSequenceAt(i))) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + jalview.datamodel.SequenceI[] reps = av + .getRepresentedSequences(jal.getSequenceAt(i)) + .getSequencesInOrder(jal); - for (int t = 0; t < frames.length; t++) + for (int h = 0; h < reps.length; h++) { - if (frames[t] instanceof TreePanel) + if (reps[h] != jal.getSequenceAt(i)) { - 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(jal.findIndex(reps[h])); } } } } + } - //SAVE ANNOTATIONS - if (jal.getAlignmentAnnotation() != null) + if (jdatasq.getSequenceFeatures() != null) + { + jalview.datamodel.SequenceFeature[] sf = jdatasq + .getSequenceFeatures(); + int index = 0; + while (index < sf.length) { - jalview.datamodel.AlignmentAnnotation[] aa = jal.getAlignmentAnnotation(); - - for (int i = 0; i < aa.length; i++) + 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; - } + 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; + Enumeration keys = sf[index].otherDetails.keys(); + while (keys.hasMoreElements()) + { + key = keys.nextElement().toString(); + OtherData keyValue = new OtherData(); + keyValue.setKey(key); + keyValue.setValue(sf[index].otherDetails.get(key).toString()); + features.addOtherData(keyValue); + } + } + jseq.addFeatures(features); + index++; + } + } - an.setDescription(aa[i].description); + if (jdatasq.getPDBId() != null) + { + Enumeration en = jdatasq.getPDBId().elements(); + while (en.hasMoreElements()) + { + Pdbids pdb = new Pdbids(); + jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en + .nextElement(); + + pdb.setId(entry.getId()); + 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); + } + } - if(aa[i].sequenceRef!=null) - { - an.setSequenceRef(aa[i].sequenceRef.getName()); - } + 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(); + } - if(aa[i].graph>0) + if (!pdbfiles.contains(entry.getId())) + { + pdbfiles.add(entry.getId()); + DataInputStream dis = null; + try + { + File file = new File(matchedFile); + if (file.exists() && jout != null) + { + byte[] data = new byte[(int) file.length()]; + jout.putNextEntry(new JarEntry(entry.getId())); + dis = new DataInputStream( + new FileInputStream(file)); + dis.readFully(data); + + DataOutputStream dout = new DataOutputStream(jout); + dout.write(data, 0, data.length); + dout.flush(); + jout.closeEntry(); + } + } catch (Exception ex) + { + ex.printStackTrace(); + } finally + { + if (dis != null) { - an.setGraph(true); - an.setGraphType(aa[i].graph); - an.setGraphGroup(aa[i].graphGroup); - if(aa[i].getThreshold()!=null) + try + { + dis.close(); + } catch (IOException e) { - 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); + // ignore } } - else - an.setGraph(false); + } - an.setLabel(aa[i].label); + } + } - AnnotationElement ae; + 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); + } - for (int a = 0; a < aa[i].annotations.length; a++) - { - 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); - } - - vamsasSet.addAnnotation(an); - } + jseq.addPdbids(pdb); } + } - //SAVE GROUPS - if (jal.getGroups() != null) - { - JGroup[] groups = new JGroup[jal.getGroups().size()]; - - for (int i = 0; i < groups.length; i++) - { - 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)); - } - - groups[i].setPidThreshold(sg.cs.getThreshold()); - } - - 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); - - 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 + if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0) + { + jalview.datamodel.AlignedCodonFrame[] jac = jal.getCodonFrames(); + for (int i = 0; i < jac.length; i++) + { + AlcodonFrame alc = new AlcodonFrame(); + vamsasSet.addAlcodonFrame(alc); + for (int p = 0; p < jac[i].aaWidth; p++) + { + Alcodon cmap = new Alcodon(); + if (jac[i].codons[p] != null) + { + // Null codons indicate a gapped column in the translated peptide + // alignment. + cmap.setPos1(jac[i].codons[p][0]); + cmap.setPos2(jac[i].codons[p][1]); + cmap.setPos3(jac[i].codons[p][2]); + } + alc.addAlcodon(cmap); } + if (jac[i].getProtMappings() != null + && jac[i].getProtMappings().length > 0) + { + SequenceI[] dnas = jac[i].getdnaSeqs(); + jalview.datamodel.Mapping[] pmaps = jac[i].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); - - - if (ap.av.explodedPosition != null) + for (int t = 0; t < frames.length; t++) { - view.setXpos(av.explodedPosition.x); - view.setYpos(av.explodedPosition.y); - view.setWidth(av.explodedPosition.width); - view.setHeight(av.explodedPosition.height); + 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); + } + } } - else + } + } + // 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 + jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation(); + if (aa != null && aa.length > 0) { - view.setXpos(ap.alignFrame.getBounds().x); - view.setYpos(ap.alignFrame.getBounds().y); - view.setWidth(ap.alignFrame.getBounds().width); - view.setHeight(ap.alignFrame.getBounds().height); + storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, + vamsasSet); } + } + } + else + { + if (jal.getAlignmentAnnotation() != null) + { + // Store the annotation shown on the alignment. + jalview.datamodel.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()) + { + groups[++i] = new JGroup(); - view.setStartRes(av.startRes); - view.setStartSeq(av.startSeq); - - if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme) + groups[i].setStart(sg.getStartRes()); + groups[i].setEnd(sg.getEndRes()); + groups[i].setName(sg.getName()); + if (groupRefs.containsKey(sg)) { - view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(), - userColours, jms)); + // group has references so set it's ID field + groups[i].setId(groupRefs.get(sg).toString()); } - else if(av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient) + if (sg.cs != null) { - jalview.schemes.AnnotationColourGradient acg - = (jalview.schemes.AnnotationColourGradient)av.getGlobalColourScheme(); + if (sg.cs.conservationApplied()) + { + groups[i].setConsThreshold(sg.cs.getConservationInc()); - 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)); + if (sg.cs instanceof jalview.schemes.UserColourScheme) + { + groups[i].setColour(setUserColourScheme(sg.cs, userColours, + jms)); + } else - ac.setColourScheme(ColourSchemeProperty.getColourName(acg.getBaseColour())); + { + groups[i] + .setColour(ColourSchemeProperty.getColourName(sg.cs)); + } + } + else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient) + { + groups[i].setColour("AnnotationColourGradient"); + groups[i].setAnnotationColours(constructAnnotationColours( + (jalview.schemes.AnnotationColourGradient) sg.cs, + userColours, jms)); + } + else if (sg.cs instanceof jalview.schemes.UserColourScheme) + { + groups[i] + .setColour(setUserColourScheme(sg.cs, userColours, jms)); + } + else + { + groups[i].setColour(ColourSchemeProperty.getColourName(sg.cs)); + } - ac.setMaxColour(acg.getMaxColour().getRGB()); - ac.setMinColour(acg.getMinColour().getRGB()); - view.setAnnotationColours(ac); - view.setBgColour("AnnotationColourGradient"); + groups[i].setPidThreshold(sg.cs.getThreshold()); } - else + + 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); + groups[i].setShowUnconserved(sg.getShowNonconserved()); + groups[i].setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); + groups[i].setShowConsensusHistogram(sg.isShowConsensusHistogram()); + groups[i].setShowSequenceLogo(sg.isShowSequenceLogo()); + groups[i].setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); + for (int s = 0; s < sg.getSize(); s++) { - view.setBgColour(ColourSchemeProperty.getColourName( - av.getGlobalColourScheme())); + jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg + .getSequenceAt(s); + groups[i].addSeq(seqHash(seq)); } + } + + 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()); + view.setViewName(av.viewName); + view.setGatheredViews(av.gatherViewsHere); + + if (ap.av.explodedPosition != null) + { + view.setXpos(av.explodedPosition.x); + view.setYpos(av.explodedPosition.y); + view.setWidth(av.explodedPosition.width); + view.setHeight(av.explodedPosition.height); + } + else + { + view.setXpos(ap.alignFrame.getBounds().x); + view.setYpos(ap.alignFrame.getBounds().y); + view.setWidth(ap.alignFrame.getBounds().width); + view.setHeight(ap.alignFrame.getBounds().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); - ColourSchemeI cs = av.getGlobalColourScheme(); + view.setAnnotationColours(ac); + view.setBgColour("AnnotationColourGradient"); + } + else + { + view.setBgColour(ColourSchemeProperty.getColourName(av + .getGlobalColourScheme())); + } - if(cs!=null) + ColourSchemeI cs = av.getGlobalColourScheme(); + + 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.setRenderGaps(av.renderGaps); + 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.textColour.getRGB()); + view.setTextCol2(av.textColour2.getRGB()); + view.setTextColThreshold(av.thresholdTextColour); + 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.followHighlight); + view.setFollowSelection(av.followSelection); + view.setIgnoreGapsinConsensus(av.getIgnoreGapsConsensus()); + 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(); + Object gstyle = null; + GraduatedColor gcol = null; + 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]); } + } - //Make sure we save none displayed feature settings - Enumeration en = - ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours.keys(); - while(en.hasMoreElements()) + // Make sure we save none displayed feature settings + Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getFeatureColours().keySet().iterator(); + while (en.hasNext()) + { + String key = en.next().toString(); + if (settingsAdded.contains(key)) { - 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() - ); + continue; + } - setting.setDisplay(false); + Setting setting = new Setting(); + setting.setType(key); + setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getColour(key).getRGB()); - fs.addSetting(setting); - settingsAdded.addElement(key); + setting.setDisplay(false); + float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getOrder(key); + if (rorder > -1) + { + setting.setOrder(rorder); + } + fs.addSetting(setting); + settingsAdded.addElement(key); + } + // is groups actually supposed to be a map here ? + en = ap.getSeqPanel().seqCanvas.getFeatureRenderer().getFeatureGroups() + .iterator(); + Vector groupsAdded = new Vector(); + while (en.hasNext()) + { + String grp = en.next().toString(); + if (groupsAdded.contains(grp)) + { + continue; } + 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); - jms.setFeatureSettings(fs); + } + 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."); } - - if(av.hasHiddenColumns) + 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); } + } + } + } + + jms.addViewport(view); + } + object.setJalviewModelSequence(jms); + object.getVamsasModel().addSequenceSet(vamsasSet); - JarEntry entry = new JarEntry(fileName); - jout.putNextEntry(entry); + if (jout != null && fileName != null) + { + // 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 + { + JarEntry entry = new JarEntry(fileName); + jout.putNextEntry(entry); + PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout, + "UTF-8")); + org.exolab.castor.xml.Marshaller marshaller = new org.exolab.castor.xml.Marshaller( + pout); + marshaller.marshal(object); + pout.flush(); + jout.closeEntry(); + } catch (Exception ex) + { + // TODO: raise error in GUI if marshalling failed. + ex.printStackTrace(); + } + } + return object; + } - object.marshal(out); + /** + * 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(); + 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()))) + { + 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) + String statestring = viewFrame.getStateInfo(); + + 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]) + { + 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()); + /* + * Only store each structure viewer's state once in each XML document. + */ + if (!viewIds.contains(viewId)) + { + viewIds.add(viewId); + state.setContent(statestring.replaceAll("\n", "")); } - catch (Exception ex) + else { - ex.printStackTrace(); + state.setContent("# duplicate state"); } + pdb.addStructureState(state); } - return object; + } } - - String SetUserColourScheme(jalview.schemes.ColourSchemeI cs, - Vector userColours, JalviewModelSequence jms) + 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 { - String id = null; - jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs; + ac.setColourScheme(ColourSchemeProperty.getColourName(acg + .getBaseColour())); + } - if (!userColours.contains(ucs)) - { - userColours.add(ucs); + ac.setMaxColour(acg.getMaxColour().getRGB()); + ac.setMinColour(acg.getMinColour().getRGB()); + ac.setPerSequence(acg.isSeqAssociated()); + ac.setPredefinedColours(acg.isPredefinedColours()); + return ac; + } - 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(); + private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, + IdentityHashMap groupRefs, AlignmentViewport av, + Set calcIdSet, boolean storeDS, SequenceSet vamsasSet) + { - 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); - } - } + for (int i = 0; i < aa.length; i++) + { + Annotation an = new Annotation(); - id = "ucs" + userColours.indexOf(ucs); - uc.setId(id); - uc.setUserColourScheme(jbucs); - jms.addUserColours(uc); - } + if (aa[i].annotationId != null) + { + annotationIds.put(aa[i].annotationId, aa[i]); + } - return id; - } + an.setId(aa[i].annotationId); - jalview.schemes.UserColourScheme GetUserColourScheme( - JalviewModelSequence jms, String id) - { - UserColours[] uc = jms.getUserColours(); - UserColours colours = null; + an.setVisible(aa[i].visible); - for (int i = 0; i < uc.length; i++) - { - if (uc[i].getId().equals(id)) - { - colours = uc[i]; + an.setDescription(aa[i].description); - break; - } + if (aa[i].sequenceRef != null) + { + // TODO later annotation sequenceRef should be the XML ID of the + // sequence rather than its display name + an.setSequenceRef(aa[i].sequenceRef.getName()); + } + if (aa[i].groupRef != null) + { + Object groupIdr = groupRefs.get(aa[i].groupRef); + if (groupIdr == null) + { + // make a locally unique String + groupRefs.put(aa[i].groupRef, + groupIdr = ("" + System.currentTimeMillis() + + aa[i].groupRef.getName() + groupRefs.size())); } + an.setGroupRef(groupIdr.toString()); + } - java.awt.Color[] newColours = new java.awt.Color[24]; + // store all visualization attributes for annotation + an.setGraphHeight(aa[i].graphHeight); + an.setCentreColLabels(aa[i].centreColLabels); + an.setScaleColLabels(aa[i].scaleColLabel); + an.setShowAllColLabels(aa[i].showAllColLabels); + an.setBelowAlignment(aa[i].belowAlignment); - for (int i = 0; i < 24; i++) + if (aa[i].graph > 0) + { + an.setGraph(true); + an.setGraphType(aa[i].graph); + an.setGraphGroup(aa[i].graphGroup); + if (aa[i].getThreshold() != null) { - newColours[i] = new java.awt.Color(Integer.parseInt( - colours.getUserColourScheme().getColour(i).getRGB(), 16)); + 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); + + if (aa[i] == av.getAlignmentQualityAnnot() + || aa[i] == av.getAlignmentConservationAnnotation() + || aa[i] == av.getAlignmentConsensusAnnotation() + || aa[i].autoCalculated) + { + // new way of indicating autocalculated annotation - + an.setAutoCalculated(aa[i].autoCalculated); + } + if (aa[i].hasScore()) + { + an.setScore(aa[i].getScore()); + } - jalview.schemes.UserColourScheme ucs = - new jalview.schemes.UserColourScheme(newColours); + if (aa[i].getCalcId() != null) + { + calcIdSet.add(aa[i].getCalcId()); + an.setCalcId(aa[i].getCalcId()); + } + if (aa[i].hasProperties()) + { + for (String pr : aa[i].getProperties()) + { + Property prop = new Property(); + prop.setName(pr); + prop.setValue(aa[i].getProperty(pr)); + an.addProperty(prop); + } + } - if (colours.getUserColourScheme().getColourCount() > 24) + AnnotationElement ae; + if (aa[i].annotations != null) + { + an.setScoreOnly(false); + for (int a = 0; a < aa[i].annotations.length; a++) { - newColours = new java.awt.Color[23]; - for (int i = 0; i < 23; i++) + if ((aa[i] == null) || (aa[i].annotations[a] == null)) { - newColours[i] = new java.awt.Color(Integer.parseInt( - colours.getUserColourScheme().getColour(i+24).getRGB(), 16)); + continue; } - ucs.setLowerCaseColours(newColours); - } - return ucs; - } + ae = new AnnotationElement(); + if (aa[i].annotations[a].description != null) + { + ae.setDescription(aa[i].annotations[a].description); + } + if (aa[i].annotations[a].displayCharacter != null) + { + ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter); + } + if (!Float.isNaN(aa[i].annotations[a].value)) + { + ae.setValue(aa[i].annotations[a].value); + } - /** - * DOCUMENT ME! - * - * @param file DOCUMENT ME! - */ - public AlignFrame LoadJalviewAlign(final String file) - { - uniqueSetSuffix = System.currentTimeMillis()%100000 +""; + ae.setPosition(a); + if (aa[i].annotations[a].secondaryStructure > ' ') + { + ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure + + ""); + } - jalview.gui.AlignFrame af = null; + if (aa[i].annotations[a].colour != null + && aa[i].annotations[a].colour != java.awt.Color.black) + { + ae.setColour(aa[i].annotations[a].colour.getRGB()); + } + + an.addAnnotationElement(ae); + if (aa[i].autoCalculated) + { + // only write one non-null entry into the annotation row - + // sufficient to get the visualization attributes necessary to + // display data + continue; + } + } + } + else + { + an.setScoreOnly(true); + } + if (!storeDS || (storeDS && !aa[i].autoCalculated)) + { + // skip autocalculated annotation - these are only provided for + // alignments + vamsasSet.addAnnotation(an); + } + } - seqRefIds = new Hashtable(); - viewportsAdded = new Hashtable(); + } - Vector gatherToThisFrame= new Vector(); + private CalcIdParam createCalcIdParam(String calcId, AlignViewport av) + { + AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId); + if (settings != null) + { + 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 + { + 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; + } + 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 { - //UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING - URL url = null; - - if (file.startsWith("http://")) - { - url = new URL(file); - } - - JarInputStream jin = null; - JarEntry jarentry = null; - int entryCount = 1; - - do - { - if (url != null) - { - jin = new JarInputStream(url.openStream()); - } - else - { - jin = new JarInputStream(new FileInputStream(file)); - } - - 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 ); - - 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) + parmSet = service.getParamStore().parseServiceParameterFile( + calcIdParam.getName(), calcIdParam.getDescription(), + calcIdParam.getServiceURL(), + calcIdParam.getParameters().replace("|\\n|", "\n")); + } catch (IOException x) { - 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); - } - }); + warn("Couldn't parse parameter data for " + + calcIdParam.getCalcId(), x); + return false; } - catch (Exception ex) + List argList = null; + if (calcIdParam.getName().length() > 0) { - //Is Version 1 Jar file? - af = new Jalview2XML_V1().LoadJalviewAlign(file); - - if(af!=null) + parmSet = service.getParamStore() + .getPreset(calcIdParam.getName()); + if (parmSet != null) { - System.out.println("Successfully loaded archive file"); - return af; + // TODO : check we have a good match with settings in AACon - + // otherwise we'll need to create a new preset } - - System.err.println("Exception whilst loading jalview XML file : " + - ex + "\n"); - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "Error loading " + file, - "Error loading Jalview file", - JOptionPane.WARNING_MESSAGE); - }}); } - - if (Desktop.instance != null) - Desktop.instance.stopLoading(); - - for (int i = 0; i < gatherToThisFrame.size(); i++) + else { - Desktop.instance.gatherViews( - (AlignFrame) gatherToThisFrame.elementAt(i)); + argList = parmSet.getArguments(); + parmSet = null; } + AAConSettings settings = new AAConSettings( + calcIdParam.isAutoUpdate(), service, parmSet, argList); + av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings, + calcIdParam.isNeedsUpdate()); + return true; + } + else + { + warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server."); + return false; + } + } + throw new Error(MessageManager.formatMessage("error.unsupported_version_calcIdparam", new String[]{calcIdParam.toString()})); + } - return af; + /** + * 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; + + /** + * 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) + { + 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; + } - String loadPDBFile(String file, String pdbId) + /** + * 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) { - System.out.println(file +" "+pdbId); - try + return vobj2jv.get(idcode); + } + return null; + } + + /** + * 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())); + if (jds.getDatasetSequence().getDBRef() != null) { - JarInputStream jin = null; + dbrefs = jds.getDatasetSequence().getDBRef(); + } + } + else + { + vamsasSeq.setDsseqid(id); // so we can tell which sequences really are + // dataset sequences only + dbrefs = jds.getDBRef(); + } + 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(); - if (file.startsWith("http://")) + jalview.util.MapList mlst = jmp.getMap(); + int r[] = mlst.getFromRanges(); + for (int s = 0; s < r.length; s += 2) + { + MapListFrom mfrom = new MapListFrom(); + mfrom.setStart(r[s]); + mfrom.setEnd(r[s + 1]); + mp.addMapListFrom(mfrom); + } + r = mlst.getToRanges(); + for (int s = 0; s < r.length; s += 2) + { + MapListTo mto = new MapListTo(); + mto.setStart(r[s]); + mto.setEnd(r[s + 1]); + mp.addMapListTo(mto); + } + mp.setMapFromUnit(mlst.getFromRatio()); + mp.setMapToUnit(mlst.getToRatio()); + if (jmp.getTo() != null) + { + MappingChoice mpc = new MappingChoice(); + if (recurse + && (parentseq != jmp.getTo() || parentseq + .getDatasetSequence() != jmp.getTo())) { - jin = new JarInputStream(new URL(file).openStream()); + mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()), + jmp.getTo(), jds)); } else { - jin = new JarInputStream(new FileInputStream(file)); + 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"); + } } + 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(); - JarEntry entry = null; - do + 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++) { - entry = jin.getNextJarEntry(); + 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); } - 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; + uc.setId(id); + uc.setUserColourScheme(jbucs); + jms.addUserColours(uc); + } - while ( (data = in.readLine()) != null) - { - out.println(data); - } - out.close(); - return outFile.getAbsolutePath(); + return id; + } - } - catch (Exception ex) + jalview.schemes.UserColourScheme getUserColourScheme( + JalviewModelSequence jms, String id) + { + UserColours[] uc = jms.getUserColours(); + UserColours colours = null; + + for (int i = 0; i < uc.length; i++) + { + if (uc[i].getId().equals(id)) { - ex.printStackTrace(); - } + colours = uc[i]; - return null; + break; + } } + java.awt.Color[] newColours = new java.awt.Color[24]; - AlignFrame LoadFromObject(JalviewModel object, - String file, - boolean loadTrees ) + for (int i = 0; i < 24; i++) { - SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0); - Sequence[] vamsasSeq = vamsasSet.getSequence(); - - JalviewModelSequence jms = object.getJalviewModelSequence(); + newColours[i] = new java.awt.Color(Integer.parseInt(colours + .getUserColourScheme().getColour(i).getRGB(), 16)); + } - Viewport view = jms.getViewport(0); + jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme( + newColours); - ////////////////////////////////// - //LOAD SEQUENCES + 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); + } - Vector hiddenSeqs = null; - jalview.datamodel.Sequence jseq; + return ucs; + } - ArrayList tmpseqs = new ArrayList(); + /** + * contains last error message (if any) encountered by XML loader. + */ + String errorMessage = null; - boolean multipleView = false; + /** + * flag to control whether the Jalview2XML_V1 parser should be deferred to if + * exceptions are raised during project XML parsing + */ + public boolean attemptversion1parse = true; - JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq(); - for (int i = 0; i < JSEQ.length; i++) - { - String seqId = JSEQ[i].getId() + ""; + /** + * Load a jalview project archive from a jar file + * + * @param file + * - HTTP URL or filename + */ + public AlignFrame loadJalviewAlign(final String file) + { - 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 ); - } + jalview.gui.AlignFrame af = 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); - if (JSEQ[i].getHidden()) + } catch (MalformedURLException e) + { + errorMessage = "Invalid URL format for '" + file + "'"; + reportErrors(); + } finally + { + try + { + SwingUtilities.invokeAndWait(new Runnable() + { + public void run() { - if (hiddenSeqs == null) - hiddenSeqs = new Vector(); - + setLoadingFinishedForNewStructureViewers(); + }; + }); + } catch (Exception x) + { - hiddenSeqs.addElement( - (jalview.datamodel.Sequence) seqRefIds.get(seqId)); - } + } + } + return af; + } + + private jarInputStreamProvider createjarInputStreamProvider( + final String file) throws MalformedURLException + { + URL url = null; + errorMessage = null; + uniqueSetSuffix = null; + seqRefIds = null; + viewportsAdded = null; + 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)); + } + } - ///SequenceFeatures are added to the DatasetSequence, - // so we must create the dataset before loading features - ///////////////////////////////// - - - jalview.datamodel.Sequence[] orderedSeqs = new jalview.datamodel.Sequence[ - tmpseqs.size()]; - - tmpseqs.toArray(orderedSeqs) ; - - - jalview.datamodel.Alignment al = - new jalview.datamodel.Alignment(orderedSeqs); + @Override + public String getFilename() + { + return file; + } + }; + } - al.setDataset(null); - ///////////////////////////////// + /** + * 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) + { + seqRefIds = new HashMap(); + } + if (viewportsAdded == null) + { + viewportsAdded = new Hashtable(); + } + if (frefedSequence == null) + { + frefedSequence = new Vector(); + } + jalview.gui.AlignFrame af = null, _af = null; + Hashtable gatherToThisFrame = new Hashtable(); + final String file = jprovider.getFilename(); + try + { + JarInputStream jin = null; + JarEntry jarentry = null; + int entryCount = 1; - Hashtable pdbloaded = new Hashtable(); - if(!multipleView) + do + { + jin = jprovider.getJarInputStream(); + for (int i = 0; i < entryCount; i++) { - for (int i = 0; i < vamsasSeq.length; i++) - { - 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()); - - } + jarentry = jin.getNextJarEntry(); + } - 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()); - } + if (jarentry != null && jarentry.getName().endsWith(".xml")) + { + InputStreamReader in = new InputStreamReader(jin, "UTF-8"); + JalviewModel object = new JalviewModel(); - al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); - } - } - if (vamsasSeq[i].getDBRefCount() > 0) + 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.gatherViewsHere) { - 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) + { + // Some other file here. + entryCount++; + } + } while (jarentry != null); + resolveFrefedSequences(); + } catch (java.io.FileNotFoundException ex) + { + ex.printStackTrace(); + errorMessage = "Couldn't locate Jalview XML file : " + file; + System.err.println("Exception whilst loading jalview XML file : " + + ex + "\n"); + } catch (java.net.UnknownHostException 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) { - Annotation[] an = vamsasSet.getAnnotation(); + 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(); - 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() ); - } + 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(); + } - jalview.datamodel.AlignmentAnnotation jaa = null; + if (Desktop.instance != null) + { + Desktop.instance.stopLoading(); + } - if (an[i].getGraph()) - { - jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), - an[i].getDescription(), anot, 0, 0, - an[i].getGraphType()); + Enumeration en = gatherToThisFrame.elements(); + while (en.hasMoreElements()) + { + Desktop.instance.gatherViews((AlignFrame) en.nextElement()); + } + if (errorMessage != null) + { + reportErrors(); + } + return af; + } - jaa.graphGroup = an[i].getGraphGroup(); + /** + * 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 (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())) - ); + Hashtable alreadyLoadedPDB; - } + /** + * 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; - } - else - { - jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), - an[i].getDescription(), anot); - } + String loadPDBFile(jarInputStreamProvider jprovider, String pdbId) + { + if (alreadyLoadedPDB == null) + { + alreadyLoadedPDB = new Hashtable(); + } - if(an[i].getSequenceRef()!=null) - { - jaa.createSequenceMapping( - al.findName(an[i].getSequenceRef()), 1, true - ); - al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa); - } + if (alreadyLoadedPDB.containsKey(pdbId)) + { + return alreadyLoadedPDB.get(pdbId).toString(); + } - al.addAnnotation(jaa); - } - } + 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(pdbId)); + if (entry != null) + { + 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; - ///////////////////////// - //LOAD GROUPS - if (jms.getJGroupCount() > 0) + while ((data = in.readLine()) != null) { - JGroup[] groups = jms.getJGroup(); - - for (int i = 0; i < groups.length; i++) + out.println(data); + } + try + { + out.flush(); + } catch (Exception foo) + { + } + ; + out.close(); + String t = outFile.getAbsolutePath(); + alreadyLoadedPDB.put(pdbId, t); + return t; + } + else + { + warn("Couldn't find PDB file entry in Jalview Jar for " + pdbId); + } + } catch (Exception ex) + { + ex.printStackTrace(); + } + + return null; + } + + private class JvAnnotRow + { + public JvAnnotRow(int i, AlignmentAnnotation jaa) + { + order = i; + template = jaa; + } + + /** + * persisted version of annotation row from which to take vis properties + */ + public jalview.datamodel.AlignmentAnnotation template; + + /** + * original position of the annotation row in the alignment + */ + public int order; + } + + /** + * 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(); + + JalviewModelSequence jms = object.getJalviewModelSequence(); + + Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0) + : null; + + // //////////////////////////////// + // LOAD SEQUENCES + + Vector hiddenSeqs = null; + jalview.datamodel.Sequence jseq; + + ArrayList tmpseqs = new ArrayList(); + + boolean multipleView = false; + + JSeq[] jseqs = object.getJalviewModelSequence().getJSeq(); + int vi = 0; // counter in vamsasSeq array + for (int i = 0; i < jseqs.length; i++) + { + String seqId = jseqs[i].getId(); + + if (seqRefIds.get(seqId) != null) + { + tmpseqs.add(seqRefIds.get(seqId)); + multipleView = true; + } + else + { + jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(), + vamsasSeq[vi].getSequence()); + jseq.setDescription(vamsasSeq[vi].getDescription()); + jseq.setStart(jseqs[i].getStart()); + jseq.setEnd(jseqs[i].getEnd()); + jseq.setVamsasId(uniqueSetSuffix + seqId); + seqRefIds.put(vamsasSeq[vi].getId(), jseq); + tmpseqs.add(jseq); + vi++; + } + + if (jseqs[i].getHidden()) + { + if (hiddenSeqs == null) + { + hiddenSeqs = new Vector(); + } + + hiddenSeqs.addElement(seqRefIds.get(seqId)); + } + + } + + // / + // Create the alignment object from the sequence set + // /////////////////////////////// + jalview.datamodel.Sequence[] orderedSeqs = new jalview.datamodel.Sequence[tmpseqs + .size()]; + + tmpseqs.toArray(orderedSeqs); + + jalview.datamodel.Alignment al = new jalview.datamodel.Alignment( + orderedSeqs); + + // / Add the alignment properties + for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++) + { + SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i); + al.setProperty(ssp.getKey(), ssp.getValue()); + } + + // / + // SequenceFeatures are added to the DatasetSequence, + // so we must create or recover the dataset before loading features + // /////////////////////////////// + if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "") + { + // older jalview projects do not have a dataset id. + al.setDataset(null); + } + else + { + // recover dataset - passing on flag indicating if this a 'viewless' + // sequence set (a.k.a. a stored dataset for the project) + recoverDatasetFor(vamsasSet, al, object.getJalviewModelSequence() + .getViewportCount() == 0); + } + // /////////////////////////////// + + Hashtable pdbloaded = new Hashtable(); + if (!multipleView) + { + // load sequence features, database references and any associated PDB + // structures for the alignment + for (int i = 0; i < vamsasSeq.length; i++) + { + if (jseqs[i].getFeaturesCount() > 0) + { + Features[] features = jseqs[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++) { - ColourSchemeI cs = null; + OtherData keyValue = features[f].getOtherData(od); + if (keyValue.getKey().startsWith("LINK")) + { + sf.addLink(keyValue.getValue()); + } + else + { + sf.setValue(keyValue.getKey(), keyValue.getValue()); + } - 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); - } + } + + al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf); + } + } + if (vamsasSeq[i].getDBRefCount() > 0) + { + addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]); + } + if (jseqs[i].getPdbidsCount() > 0) + { + Pdbids[] ids = jseqs[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())) + { + entry.setFile(loadPDBFile(jprovider, ids[p].getId())); + } + else + { + entry.setFile(pdbloaded.get(ids[p].getId()).toString()); + } + } + StructureSelectionManager.getStructureSelectionManager( + Desktop.instance) + .registerPDBEntry(entry); + al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); + } + } + } + } // end !multipleview - Vector seqs = new Vector(); + // /////////////////////////////// + // LOAD SEQUENCE MAPPINGS - for (int s = 0; s < groups[i].getSeqCount(); s++) - { - String seqId = groups[i].getSeq(s)+""; - seqs.addElement((jalview.datamodel.SequenceI) seqRefIds.get(seqId)); - } + if (vamsasSet.getAlcodonFrameCount() > 0) + { + // TODO Potentially this should only be done once for all views of an + // alignment + AlcodonFrame[] alc = vamsasSet.getAlcodonFrame(); + for (int i = 0; i < alc.length; i++) + { + jalview.datamodel.AlignedCodonFrame cf = new jalview.datamodel.AlignedCodonFrame( + alc[i].getAlcodonCount()); + if (alc[i].getAlcodonCount() > 0) + { + Alcodon[] alcods = alc[i].getAlcodon(); + for (int p = 0; p < cf.codons.length; p++) + { + if (alcods[p].hasPos1() && alcods[p].hasPos2() + && alcods[p].hasPos3()) + { + // translated codons require three valid positions + cf.codons[p] = new int[3]; + cf.codons[p][0] = (int) alcods[p].getPos1(); + cf.codons[p][1] = (int) alcods[p].getPos2(); + cf.codons[p][2] = (int) alcods[p].getPos3(); + } + else + { + cf.codons[p] = null; + } + } + } + if (alc[i].getAlcodMapCount() > 0) + { + AlcodMap[] maps = alc[i].getAlcodMap(); + for (int m = 0; m < maps.length; m++) + { + SequenceI dnaseq = seqRefIds + .get(maps[m].getDnasq()); + // Load Mapping + jalview.datamodel.Mapping mapping = null; + // attach to dna sequence reference. + if (maps[m].getMapping() != null) + { + mapping = addMapping(maps[m].getMapping()); + } + if (dnaseq != null) + { + cf.addMap(dnaseq, mapping.getTo(), mapping.getMap()); + } + else + { + // defer to later + frefedSequence.add(new Object[] + { maps[m].getDnasq(), cf, mapping }); + } + } + } + al.addCodonFrame(cf); + } - 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()); + } - sg.setOutlineColour(new java.awt.Color( - groups[i].getOutlineColour())); + // //////////////////////////////// + // LOAD ANNOTATIONS + ArrayList autoAlan = new ArrayList(); + /** + * store any annotations which forward reference a group's ID + */ + Hashtable> groupAnnotRefs = new Hashtable>(); - sg.textColour = new java.awt.Color(groups[i].getTextCol1()); - sg.textColour2 = new java.awt.Color(groups[i].getTextCol2()); - sg.thresholdTextColour = groups[i].getTextColThreshold(); + if (vamsasSet.getAnnotationCount() > 0) + { + Annotation[] an = vamsasSet.getAnnotation(); - 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); - } + for (int i = 0; i < an.length; i++) + { + /** + * test if annotation is automatically calculated for this view only + */ + boolean autoForView = false; + if (an[i].getLabel().equals("Quality") + || an[i].getLabel().equals("Conservation") + || an[i].getLabel().equals("Consensus")) + { + // Kludge for pre 2.5 projects which lacked the autocalculated flag + autoForView = true; + if (!an[i].hasAutoCalculated()) + { + an[i].setAutoCalculated(true); + } + } + if (autoForView + || (an[i].hasAutoCalculated() && an[i].isAutoCalculated())) + { + // remove ID - we don't recover annotation from other views for + // view-specific annotation + an[i].setId(null); + } + + // set visiblity for other annotation in this view + if (an[i].getId() != null + && annotationIds.containsKey(an[i].getId())) + { + jalview.datamodel.AlignmentAnnotation jda = (jalview.datamodel.AlignmentAnnotation) annotationIds + .get(an[i].getId()); + // in principle Visible should always be true for annotation displayed + // in multiple views + if (an[i].hasVisible()) + { + jda.visible = an[i].getVisible(); + } + + al.addAnnotation(jda); + + continue; + } + // Construct new annotation from model. + AnnotationElement[] ae = an[i].getAnnotationElement(); + jalview.datamodel.Annotation[] anot = null; + java.awt.Color firstColour = null; + int anpos; + if (!an[i].getScoreOnly()) + { + anot = new jalview.datamodel.Annotation[al.getWidth()]; + for (int aa = 0; aa < ae.length && aa < anot.length; aa++) + { + anpos = ae[aa].getPosition(); + + if (anpos >= anot.length) + { + continue; + } - al.addGroup(sg); + anot[anpos] = new jalview.datamodel.Annotation( + + ae[aa].getDisplayCharacter(), ae[aa].getDescription(), + (ae[aa].getSecondaryStructure() == null || ae[aa] + .getSecondaryStructure().length() == 0) ? ' ' + : ae[aa].getSecondaryStructure().charAt(0), + ae[aa].getValue() + + ); + // JBPNote: Consider verifying dataflow for IO of secondary + // structure annotation read from Stockholm files + // this was added to try to ensure that + // if (anot[ae[aa].getPosition()].secondaryStructure>' ') + // { + // anot[ae[aa].getPosition()].displayCharacter = ""; + // } + anot[anpos].colour = new java.awt.Color(ae[aa].getColour()); + if (firstColour == null) + { + firstColour = anot[anpos].colour; } + } + } + jalview.datamodel.AlignmentAnnotation jaa = null; + + if (an[i].getGraph()) + { + float llim = 0, hlim = 0; + // if (autoForView || an[i].isAutoCalculated()) { + // hlim=11f; + // } + jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), + an[i].getDescription(), anot, llim, hlim, + an[i].getGraphType()); + + jaa.graphGroup = an[i].getGraphGroup(); + jaa._linecolour = firstColour; + 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()))); + + } + if (autoForView || an[i].isAutoCalculated()) + { + // Hardwire the symbol display line to ensure that labels for + // histograms are displayed + jaa.hasText = true; + } + } + else + { + jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), + an[i].getDescription(), anot); + jaa._linecolour = firstColour; + } + // register new annotation + if (an[i].getId() != null) + { + annotationIds.put(an[i].getId(), jaa); + jaa.annotationId = an[i].getId(); + } + // recover sequence association + if (an[i].getSequenceRef() != null) + { + if (al.findName(an[i].getSequenceRef()) != null) + { + jaa.createSequenceMapping(al.findName(an[i].getSequenceRef()), + 1, true); + al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa); + } + } + // and make a note of any group association + if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0) + { + ArrayList aal = groupAnnotRefs + .get(an[i].getGroupRef()); + if (aal == null) + { + aal = new ArrayList(); + groupAnnotRefs.put(an[i].getGroupRef(), aal); + } + aal.add(jaa); + } + + if (an[i].hasScore()) + { + jaa.setScore(an[i].getScore()); + } + if (an[i].hasVisible()) + { + jaa.visible = an[i].getVisible(); + } + + if (an[i].hasCentreColLabels()) + { + jaa.centreColLabels = an[i].getCentreColLabels(); + } + + if (an[i].hasScaleColLabels()) + { + jaa.scaleColLabel = an[i].getScaleColLabels(); + } + if (an[i].hasAutoCalculated() && an[i].isAutoCalculated()) + { + // newer files have an 'autoCalculated' flag and store calculation + // state in viewport properties + jaa.autoCalculated = true; // means annotation will be marked for + // update at end of load. + } + if (an[i].hasGraphHeight()) + { + jaa.graphHeight = an[i].getGraphHeight(); + } + if (an[i].hasBelowAlignment()) + { + jaa.belowAlignment = an[i].isBelowAlignment(); + } + jaa.setCalcId(an[i].getCalcId()); + if (an[i].getPropertyCount() > 0) + { + for (jalview.schemabinding.version2.Property prop : an[i] + .getProperty()) + { + jaa.setProperty(prop.getName(), prop.getValue()); + } + } + if (jaa.autoCalculated) + { + autoAlan.add(new JvAnnotRow(i, jaa)); + } + else + // if (!autoForView) + { + // add autocalculated group annotation and any user created annotation + // for the view + al.addAnnotation(jaa); } + } + } + // /////////////////////// + // LOAD GROUPS + // Create alignment markup and styles for this view + if (jms.getJGroupCount() > 0) + { + JGroup[] groups = jms.getJGroup(); + boolean addAnnotSchemeGroup = false; + for (int i = 0; i < groups.length; i++) + { + ColourSchemeI cs = null; + + if (groups[i].getColour() != null) + { + if (groups[i].getColour().startsWith("ucs")) + { + cs = getUserColourScheme(jms, groups[i].getColour()); + } + else if (groups[i].getColour().equals("AnnotationColourGradient") + && groups[i].getAnnotationColours() != null) + { + addAnnotSchemeGroup = true; + cs = null; + } + else + { + cs = ColourSchemeProperty.getColour(al, groups[i].getColour()); + } + if (cs != null) + { + cs.setThreshold(groups[i].getPidThreshold(), true); + } + } - ///////////////////////////////// - // LOAD VIEWPORT + Vector seqs = new Vector(); - AlignFrame af = new AlignFrame(al, - view.getWidth(), - view.getHeight() ); + for (int s = 0; s < groups[i].getSeqCount(); s++) + { + String seqId = groups[i].getSeq(s) + ""; + jalview.datamodel.SequenceI ts = seqRefIds + .get(seqId); - af.setFileName(file, "Jalview"); + if (ts != null) + { + seqs.addElement(ts); + } + } - for (int i = 0; i < JSEQ.length; i++) + if (seqs.size() < 1) { - af.viewport.setSequenceColour( - af.viewport.alignment.getSequenceAt(i), - new java.awt.Color( - JSEQ[i].getColour())); + continue; } - //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; + 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()); + + sg.setOutlineColour(new java.awt.Color(groups[i].getOutlineColour())); - af.viewport.gatherViewsHere = view.getGatheredViews(); + sg.textColour = new java.awt.Color(groups[i].getTextCol1()); + sg.textColour2 = new java.awt.Color(groups[i].getTextCol2()); + sg.setShowNonconserved(groups[i].hasShowUnconserved() ? groups[i] + .isShowUnconserved() : false); + sg.thresholdTextColour = groups[i].getTextColThreshold(); + if (groups[i].hasShowConsensusHistogram()) + { + sg.setShowConsensusHistogram(groups[i].isShowConsensusHistogram()); + } + ; + if (groups[i].hasShowSequenceLogo()) + { + sg.setshowSequenceLogo(groups[i].isShowSequenceLogo()); + } + if (groups[i].hasNormaliseSequenceLogo()) + { + sg.setNormaliseSequenceLogo(groups[i].isNormaliseSequenceLogo()); + } + if (groups[i].hasIgnoreGapsinConsensus()) + { + sg.setIgnoreGapsConsensus(groups[i].getIgnoreGapsinConsensus()); + } + 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); + } - if (view.getSequenceSetId() != null) + if (groups[i].getId() != null && groupAnnotRefs.size() > 0) + { + // re-instate unique group/annotation row reference + ArrayList jaal = groupAnnotRefs + .get(groups[i].getId()); + if (jaal != null) + { + for (jalview.datamodel.AlignmentAnnotation jaa : jaal) + { + jaa.groupRef = sg; + if (jaa.autoCalculated) + { + // match up and try to set group autocalc alignment row for this + // annotation + if (jaa.label.startsWith("Consensus for ")) + { + sg.setConsensus(jaa); + } + // match up and try to set group autocalc alignment row for this + // annotation + if (jaa.label.startsWith("Conservation for ")) + { + sg.setConservationRow(jaa); + } + } + } + } + } + al.addGroup(sg); + if (addAnnotSchemeGroup) + { + // reconstruct the annotation colourscheme + sg.cs = constructAnnotationColour( + groups[i].getAnnotationColours(), null, al, jms, false); + } + } + } + if (view == null) + { + // only dataset in this model, so just return. + return null; + } + // /////////////////////////////// + // LOAD VIEWPORT + + // 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; + String viewId = (view.getId() == null ? null : view.getId() + + uniqueSetSuffix); + AlignFrame af = null; + AlignViewport av = null; + // now check to see if we really need to create a new viewport. + if (multipleView && viewportsAdded.size() == 0) + { + // We recovered an alignment for which a viewport already exists. + // TODO: fix up any settings necessary for overlaying stored state onto + // state recovered from another document. (may not be necessary). + // we may need a binding from a viewport in memory to one recovered from + // XML. + // and then recover its containing af to allow the settings to be applied. + // TODO: fix for vamsas demo + System.err + .println("About to recover a viewport for existing alignment: Sequence set ID is " + + uniqueSeqSetId); + Object seqsetobj = retrieveExistingObj(uniqueSeqSetId); + if (seqsetobj != null) + { + if (seqsetobj instanceof String) + { + uniqueSeqSetId = (String) seqsetobj; + System.err + .println("Recovered extant sequence set ID mapping for ID : New Sequence set ID is " + + uniqueSeqSetId); + } + else { - jalview.gui.AlignViewport av = - (jalview.gui.AlignViewport) - viewportsAdded.get(uniqueSeqSetId); + System.err + .println("Warning : Collision between sequence set ID string and existing jalview object mapping."); + } + + } + } + /** + * indicate that annotation colours are applied across all groups (pre + * Jalview 2.8.1 behaviour) + */ + boolean doGroupAnnColour = isVersionStringLaterThan("2.8.1", + object.getVersion()); - af.viewport.sequenceSetID = uniqueSeqSetId; - if(av!=null) + AlignmentPanel ap = null; + boolean isnewview = true; + if (viewId != null) + { + // Check to see if this alignment already has a view id == viewId + jalview.gui.AlignmentPanel views[] = Desktop + .getAlignmentPanels(uniqueSeqSetId); + if (views != null && views.length > 0) + { + for (int v = 0; v < views.length; v++) + { + if (views[v].av.getViewId().equalsIgnoreCase(viewId)) + { + // recover the existing alignpanel, alignframe, viewport + af = views[v].alignFrame; + av = views[v].av; + ap = views[v]; + // TODO: could even skip resetting view settings if we don't want to + // change the local settings from other jalview processes + isnewview = false; + } + } + } + } + + if (isnewview) + { + af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view, + uniqueSeqSetId, viewId, autoAlan); + av = af.viewport; + ap = af.alignPanel; + } + // LOAD TREES + // ///////////////////////////////////// + if (loadTreesAndStructures && jms.getTreeCount() > 0) + { + try + { + for (int t = 0; t < jms.getTreeCount(); t++) + { + + Tree tree = jms.getTree(t); + + TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId()); + if (tp == null) + { + tp = af.ShowNewickTree( + new jalview.io.NewickFile(tree.getNewick()), + tree.getTitle(), tree.getWidth(), tree.getHeight(), + tree.getXpos(), tree.getYpos()); + if (tree.getId() != null) + { + // perhaps bind the tree id to something ? + } + } + else + { + // update local tree attributes ? + // TODO: should check if tp has been manipulated by user - if so its + // settings shouldn't be modified + tp.setTitle(tree.getTitle()); + tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(), tree + .getWidth(), tree.getHeight())); + tp.av = av; // af.viewport; // TODO: verify 'associate with all + // views' + // works still + tp.treeCanvas.av = av; // af.viewport; + tp.treeCanvas.ap = ap; // af.alignPanel; + + } + if (tp == null) + { + warn("There was a problem recovering stored Newick tree: \n" + + tree.getNewick()); + continue; + } + + tp.fitToWindow.setState(tree.getFitToWindow()); + tp.fitToWindow_actionPerformed(null); + + if (tree.getFontName() != null) + { + tp.setTreeFont(new java.awt.Font(tree.getFontName(), tree + .getFontStyle(), tree.getFontSize())); + } + else + { + tp.setTreeFont(new java.awt.Font(view.getFontName(), view + .getFontStyle(), tree.getFontSize())); + } + + tp.showPlaceholders(tree.getMarkUnlinked()); + tp.showBootstrap(tree.getShowBootstrap()); + tp.showDistances(tree.getShowDistances()); + + tp.treeCanvas.threshold = tree.getThreshold(); + + if (tree.getCurrentTree()) + { + af.viewport.setCurrentTree(tp.getTree()); + } + } + + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + + // //LOAD STRUCTURES + if (loadTreesAndStructures) + { + loadStructures(jprovider, jseqs, af, ap); + } + // and finally return. + return af; + } + + /** + * Load and link any saved structure viewers. + * + * @param jprovider + * @param jseqs + * @param af + * @param ap + */ + protected void loadStructures(jarInputStreamProvider jprovider, + JSeq[] jseqs, AlignFrame af, AlignmentPanel ap) + { + /* + * Run through all PDB ids on the alignment, and collect mappings between + * distinct view ids and all sequences referring to that view. + */ + Map structureViewers = new LinkedHashMap(); + + for (int i = 0; i < jseqs.length; i++) + { + if (jseqs[i].getPdbidsCount() > 0) + { + Pdbids[] ids = jseqs[i].getPdbids(); + for (int p = 0; p < ids.length; p++) + { + final int structureStateCount = ids[p].getStructureStateCount(); + for (int s = 0; s < structureStateCount; s++) + { + // check to see if we haven't already created this structure view + final StructureState structureState = ids[p].getStructureState(s); + String sviewid = (structureState.getViewId() == null) ? null + : structureState.getViewId() + + uniqueSetSuffix; + jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry(); + // Originally : ids[p].getFile() + // : TODO: verify external PDB file recovery still works in normal + // jalview project load + jpdb.setFile(loadPDBFile(jprovider, ids[p].getId())); + jpdb.setId(ids[p].getId()); + + int x = structureState.getXpos(); + int y = structureState.getYpos(); + int width = structureState.getWidth(); + int height = structureState.getHeight(); + + // Probably don't need to do this anymore... + // Desktop.desktop.getComponentAt(x, y); + // TODO: NOW: check that this recovers the PDB file correctly. + String pdbFile = loadPDBFile(jprovider, ids[p].getId()); + jalview.datamodel.SequenceI seq = seqRefIds + .get(jseqs[i].getId() + ""); + if (sviewid == null) + { + sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + + "," + height; + } + if (!structureViewers.containsKey(sviewid)) + { + structureViewers.put(sviewid, new StructureViewerModel(x, y, width, height, + false, false, true)); + // Legacy pre-2.7 conversion JAL-823 : + // do not assume any view has to be linked for colour by + // sequence + } + + // assemble String[] { pdb files }, String[] { id for each + // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, { + // seqs_file 2}, boolean[] { + // linkAlignPanel,superposeWithAlignpanel}} from hash + StructureViewerModel jmoldat = structureViewers.get(sviewid); + jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel() + | (structureState.hasAlignwithAlignPanel() ? structureState + .getAlignwithAlignPanel() : false)); + + /* + * Default colour by linked panel to false if not specified (e.g. + * for pre-2.7 projects) + */ + boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel(); + colourWithAlignPanel |= (structureState + .hasColourwithAlignPanel() ? structureState + .getColourwithAlignPanel() : false); + jmoldat.setColourWithAlignPanel(colourWithAlignPanel); + + /* + * Default colour by viewer to true if not specified (e.g. for + * pre-2.7 projects) + */ + boolean colourByViewer = jmoldat.isColourByViewer(); + colourByViewer &= structureState + .hasColourByJmol() ? structureState + .getColourByJmol() : true; + jmoldat.setColourByViewer(colourByViewer); + + if (jmoldat.getStateData().length() < structureState + .getContent().length()) + { + { + jmoldat.setStateData(structureState.getContent()); + } + } + if (ids[p].getFile() != null) + { + File mapkey = new File(ids[p].getFile()); + StructureData seqstrmaps = jmoldat.getFileData().get(mapkey); + if (seqstrmaps == null) + { + jmoldat.getFileData().put( + mapkey, + seqstrmaps = jmoldat.new StructureData(pdbFile, + ids[p].getId())); + } + if (!seqstrmaps.getSeqList().contains(seq)) + { + seqstrmaps.getSeqList().add(seq); + // TODO and chains? + } + } + else + { + errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747"); + warn(errorMessage); + } + } + } + } + } + // Instantiate the associated structure views + for (Entry entry : structureViewers.entrySet()) + { + createOrLinkStructureViewer(entry, af, ap); + } + } + + /** + * + * @param viewerData + * @param af + * @param ap + */ + protected void createOrLinkStructureViewer( + Entry viewerData, AlignFrame af, + AlignmentPanel ap) + { + final StructureViewerModel svattrib = viewerData.getValue(); + + /* + * Search for any viewer windows already open from other alignment views + * that exactly match the stored structure state + */ + StructureViewerBase comp = findMatchingViewer(viewerData); + + if (comp != null) + { + linkStructureViewer(ap, comp, svattrib); + return; + } + + /* + * Pending an XML element for ViewerType, just check if stateData contains + * "chimera" (part of the chimera session filename). + */ + if (svattrib.getStateData().indexOf("chimera") > -1) + { + createChimeraViewer(viewerData, af); + } + else + { + createJmolViewer(viewerData, af); + } + } + + /** + * Create a new Chimera viewer. + * + * @param viewerData + * @param af + */ + protected void createChimeraViewer(Entry viewerData, + AlignFrame af) + { + final StructureViewerModel data = viewerData.getValue(); + String chimeraSession = data.getStateData(); + + if (new File(chimeraSession).exists()) + { + Set> fileData = data.getFileData() + .entrySet(); + List pdbs = new ArrayList(); + List allseqs = new ArrayList(); + for (Entry pdb : fileData) + { + String filePath = pdb.getValue().getFilePath(); + String pdbId = pdb.getValue().getPdbId(); + pdbs.add(new PDBEntry(filePath, pdbId)); + final List seqList = pdb.getValue().getSeqList(); + SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]); + allseqs.add(seqs); + } + + boolean colourByChimera = data.isColourByViewer(); + boolean colourBySequence = data.isColourWithAlignPanel(); + + // TODO can/should this be done via StructureViewer (like Jmol)? + final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs + .size()]); + final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs.size()][]); + new ChimeraViewFrame(chimeraSession, af.alignPanel, pdbArray, + seqsArray, + colourByChimera, colourBySequence); + } + else + { + Cache.log.error("Chimera session file " + chimeraSession + + " not found"); + } + } + + /** + * Create a new Jmol window. First parse the Jmol state to translate filenames + * loaded into the view, and record the order in which files are shown in the + * Jmol view, so we can add the sequence mappings in same order. + * + * @param viewerData + * @param af + */ + protected void createJmolViewer( + final Entry viewerData, AlignFrame af) + { + final StructureViewerModel svattrib = viewerData.getValue(); + String state = svattrib.getStateData(); + List pdbfilenames = new ArrayList(); + List seqmaps = new ArrayList(); + List pdbids = new ArrayList(); + StringBuilder newFileLoc = new StringBuilder(64); + int cp = 0, ncp, ecp; + Map oldFiles = svattrib.getFileData(); + while ((ncp = state.indexOf("load ", cp)) > -1) + { + do + { + // look for next filename in load statement + newFileLoc.append(state.substring(cp, + ncp = (state.indexOf("\"", ncp + 1) + 1))); + String oldfilenam = state.substring(ncp, + ecp = state.indexOf("\"", ncp)); + // recover the new mapping data for this old filename + // have to normalize filename - since Jmol and jalview do + // filename + // translation differently. + StructureData filedat = oldFiles.get(new File(oldfilenam)); + newFileLoc.append(Platform.escapeString(filedat.getFilePath())); + pdbfilenames.add(filedat.getFilePath()); + pdbids.add(filedat.getPdbId()); + seqmaps.add(filedat.getSeqList() + .toArray(new SequenceI[0])); + newFileLoc.append("\""); + cp = ecp + 1; // advance beyond last \" and set cursor so we can + // look for next file statement. + } while ((ncp = state.indexOf("/*file*/", cp)) > -1); + } + if (cp > 0) + { + // just append rest of state + newFileLoc.append(state.substring(cp)); + } + else + { + System.err.print("Ignoring incomplete Jmol state for PDB ids: "); + newFileLoc = new StringBuilder(state); + newFileLoc.append("; load append "); + for (File id : oldFiles.keySet()) + { + // add this and any other pdb files that should be present in + // the viewer + StructureData filedat = oldFiles.get(id); + newFileLoc.append(filedat.getFilePath()); + pdbfilenames.add(filedat.getFilePath()); + pdbids.add(filedat.getPdbId()); + seqmaps.add(filedat.getSeqList() + .toArray(new SequenceI[0])); + newFileLoc.append(" \""); + newFileLoc.append(filedat.getFilePath()); + newFileLoc.append("\""); + + } + newFileLoc.append(";"); + } + + if (newFileLoc.length() > 0) + { + int histbug = newFileLoc.indexOf("history = "); + histbug += 10; + int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug); + String val = (diff == -1) ? null : newFileLoc + .substring(histbug, diff); + if (val != null && val.length() >= 4) + { + if (val.contains("e")) + { + if (val.trim().equals("true")) + { + val = "1"; + } + else + { + val = "0"; + } + newFileLoc.replace(histbug, diff, val); + } + } + + final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames + .size()]); + final String[] id = pdbids.toArray(new String[pdbids.size()]); + final SequenceI[][] sq = seqmaps + .toArray(new SequenceI[seqmaps.size()][]); + final String fileloc = newFileLoc.toString(); + final String sviewid = viewerData.getKey(); + final AlignFrame alf = af; + final Rectangle rect = new Rectangle(svattrib.getX(), + svattrib.getY(), svattrib.getWidth(), svattrib.getHeight()); + try + { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() + { + @Override + public void run() + { + JalviewStructureDisplayI sview = null; + try + { + // JAL-1333 note - we probably can't migrate Jmol views to UCSF + // Chimera! + sview = new StructureViewer(alf.alignPanel + .getStructureSelectionManager()).createView( + StructureViewer.ViewerType.JMOL, pdbf, id, sq, + alf.alignPanel, svattrib, fileloc, rect, sviewid); + addNewStructureViewer(sview); + } catch (OutOfMemoryError ex) + { + new OOMWarning("restoring structure view for PDB id " + id, + (OutOfMemoryError) ex.getCause()); + if (sview != null && sview.isVisible()) + { + sview.closeViewer(); + sview.setVisible(false); + sview.dispose(); + } + } + } + }); + } catch (InvocationTargetException ex) + { + warn("Unexpected error when opening Jmol view.", ex); + + } catch (InterruptedException e) + { + // e.printStackTrace(); + } + } + } + + /** + * Returns any open frame that matches given structure viewer data. The match + * is based on the unique viewId, or (for older project versions) the frame's + * geometry. + * + * @param viewerData + * @return + */ + protected StructureViewerBase findMatchingViewer( + Entry viewerData) + { + final String sviewid = viewerData.getKey(); + final StructureViewerModel svattrib = viewerData.getValue(); + StructureViewerBase comp = null; + JInternalFrame[] frames = getAllFrames(); + for (JInternalFrame frame : frames) + { + if (frame instanceof StructureViewerBase) + { + /* + * Post jalview 2.4 schema includes structure view id + */ + if (sviewid != null + && ((StructureViewerBase) frame).getViewId().equals( + sviewid)) + { + comp = (AppJmol) frame; + // todo: break? + } + /* + * Otherwise test for matching position and size of viewer frame + */ + else if (frame.getX() == svattrib.getX() + && frame.getY() == svattrib.getY() + && frame.getHeight() == svattrib.getHeight() + && frame.getWidth() == svattrib.getWidth()) + { + comp = (AppJmol) frame; + // todo: break? + } + } + } + return comp; + } + + /** + * Link an AlignmentPanel to an existing structure viewer. + * + * @param ap + * @param viewer + * @param oldFiles + * @param useinViewerSuperpos + * @param usetoColourbyseq + * @param viewerColouring + */ + protected void linkStructureViewer(AlignmentPanel ap, + StructureViewerBase viewer, StructureViewerModel svattrib) + { + // NOTE: if the jalview project is part of a shared session then + // view synchronization should/could be done here. + + final boolean useinViewerSuperpos = svattrib.isAlignWithPanel(); + final boolean usetoColourbyseq = svattrib.isColourWithAlignPanel(); + final boolean viewerColouring = svattrib.isColourByViewer(); + Map oldFiles = svattrib.getFileData(); + + /* + * Add mapping for sequences in this view to an already open viewer + */ + final AAStructureBindingModel binding = viewer.getBinding(); + for (File id : oldFiles.keySet()) + { + // add this and any other pdb files that should be present in the + // viewer + StructureData filedat = oldFiles.get(id); + String pdbFile = filedat.getFilePath(); + SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]); + binding.getSsm().setMapping(seq, null, pdbFile, + jalview.io.AppletFormatAdapter.FILE); + binding.addSequenceForStructFile(pdbFile, seq); + } + // and add the AlignmentPanel's reference to the view panel + viewer.addAlignmentPanel(ap); + if (useinViewerSuperpos) + { + viewer.useAlignmentPanelForSuperposition(ap); + } + else + { + viewer.excludeAlignmentPanelForSuperposition(ap); + } + if (usetoColourbyseq) + { + viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring); + } + else + { + viewer.excludeAlignmentPanelForColourbyseq(ap); + } + } + + /** + * Get all frames within the Desktop. + * + * @return + */ + protected JInternalFrame[] getAllFrames() + { + JInternalFrame[] frames = null; + // TODO is this necessary - is it safe - risk of hanging? + do + { + try + { + frames = Desktop.desktop.getAllFrames(); + } catch (ArrayIndexOutOfBoundsException e) + { + // occasional No such child exceptions are thrown here... + try + { + Thread.sleep(10); + } catch (InterruptedException f) + { + } + } + } while (frames == null); + return frames; + } + + /** + * + * @param supported + * - minimum version we are comparing against + * @param version + * - version of data being processsed. + * @return true if version is development/null or evaluates to the same or + * later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*) + */ + private boolean isVersionStringLaterThan(String supported, String version) + { + if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD") + || version.equalsIgnoreCase("Test") + || version.equalsIgnoreCase("AUTOMATED BUILD")) + { + System.err.println("Assuming project file with " + + (version == null ? "null" : version) + + " is compatible with Jalview version " + supported); + return true; + } + else + { + StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer( + version, "."); + while (currentV.hasMoreTokens() && fileV.hasMoreTokens()) + { + // convert b to decimal to catch bugfix releases within a series + String curT = currentV.nextToken().toLowerCase().replace('b', '.'); + String fileT = fileV.nextToken().toLowerCase().replace('b', '.'); + try + { + if (Float.valueOf(curT) > Float.valueOf(fileT)) + { + // current version is newer than the version that wrote the file + return false; + } + } catch (NumberFormatException nfe) + { + System.err + .println("** WARNING: Version comparison failed for tokens (" + + curT + + ") and (" + + fileT + + ")\n** Current: '" + + supported + "' and Version: '" + version + "'"); + } + } + if (currentV.hasMoreElements()) + { + // fileV has no minor version but identical series to current + return false; + } + } + return true; + } + + Vector newStructureViewers = null; + + protected void addNewStructureViewer(JalviewStructureDisplayI sview) + { + if (newStructureViewers != null) + { + sview.getBinding().setFinishedLoadingFromArchive(false); + newStructureViewers.add(sview); + } + } + + protected void setLoadingFinishedForNewStructureViewers() + { + if (newStructureViewers != null) + { + for (JalviewStructureDisplayI sview : newStructureViewers) + { + sview.getBinding().setFinishedLoadingFromArchive(true); + } + newStructureViewers.clear(); + newStructureViewers = null; + } + } + + AlignFrame loadViewport(String file, JSeq[] JSEQ, Vector hiddenSeqs, + Alignment al, JalviewModelSequence jms, Viewport view, + String uniqueSeqSetId, String viewId, + ArrayList autoAlan) + { + AlignFrame af = null; + af = new AlignFrame(al, view.getWidth(), view.getHeight(), + uniqueSeqSetId, viewId); + + af.setFileName(file, "Jalview"); + + for (int i = 0; i < JSEQ.length; i++) + { + af.viewport.setSequenceColour(af.viewport.getAlignment() + .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour())); + } + + af.viewport.gatherViewsHere = view.getGatheredViews(); + + if (view.getSequenceSetId() != null) + { + jalview.gui.AlignViewport av = (jalview.gui.AlignViewport) viewportsAdded + .get(uniqueSeqSetId); + + af.viewport.setSequenceSetId(uniqueSeqSetId); + if (av != null) + { + // propagate shared settings to this new view + af.viewport.historyList = av.historyList; + af.viewport.redoList = av.redoList; + } + else + { + viewportsAdded.put(uniqueSeqSetId, af.viewport); + } + // TODO: check if this method can be called repeatedly without + // side-effects if alignpanel already registered. + PaintRefresher.Register(af.alignPanel, uniqueSeqSetId); + } + // apply Hidden regions to view. + if (hiddenSeqs != null) + { + for (int s = 0; s < JSEQ.length; s++) + { + jalview.datamodel.SequenceGroup hidden = new jalview.datamodel.SequenceGroup(); + + for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++) + { + hidden.addSequence( + al.getSequenceAt(JSEQ[s].getHiddenSequences(r)), false); + } + af.viewport.hideRepSequences(al.getSequenceAt(s), hidden); + } + + jalview.datamodel.SequenceI[] hseqs = new jalview.datamodel.SequenceI[hiddenSeqs + .size()]; + + for (int s = 0; s < hiddenSeqs.size(); s++) + { + hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s); + } + + af.viewport.hideSequence(hseqs); + + } + // recover view properties and display parameters + if (view.getViewName() != null) + { + af.viewport.viewName = view.getViewName(); + af.setInitialTabVisible(); + } + af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(), + view.getHeight()); + + af.viewport.setShowAnnotation(view.getShowAnnotation()); + af.viewport.setAbovePIDThreshold(view.getPidSelected()); + + af.viewport.setColourText(view.getShowColourText()); + + af.viewport.setConservationSelected(view.getConservationSelected()); + af.viewport.setShowJVSuffix(view.getShowFullId()); + af.viewport.setRightAlignIds(view.getRightAlignIds()); + af.viewport.setFont(new java.awt.Font(view.getFontName(), view + .getFontStyle(), view.getFontSize())); + af.alignPanel.fontChanged(); + af.viewport.setRenderGaps(view.getRenderGaps()); + af.viewport.setWrapAlignment(view.getWrapAlignment()); + af.alignPanel.setWrapAlignment(view.getWrapAlignment()); + af.viewport.setShowAnnotation(view.getShowAnnotation()); + af.alignPanel.setAnnotationVisible(view.getShowAnnotation()); + + af.viewport.setShowBoxes(view.getShowBoxes()); + + af.viewport.setShowText(view.getShowText()); + + af.viewport.textColour = new java.awt.Color(view.getTextCol1()); + af.viewport.textColour2 = new java.awt.Color(view.getTextCol2()); + af.viewport.thresholdTextColour = view.getTextColThreshold(); + af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view + .isShowUnconserved() : false); + af.viewport.setStartRes(view.getStartRes()); + af.viewport.setStartSeq(view.getStartSeq()); + + ColourSchemeI cs = null; + // apply colourschemes + if (view.getBgColour() != null) + { + if (view.getBgColour().startsWith("ucs")) + { + cs = getUserColourScheme(jms, view.getBgColour()); + } + else if (view.getBgColour().startsWith("Annotation")) + { + AnnotationColours viewAnnColour = view.getAnnotationColours(); + cs = constructAnnotationColour(viewAnnColour, af, al, jms, true); + + // annpos + + } + else + { + cs = ColourSchemeProperty.getColour(al, view.getBgColour()); + } + + if (cs != null) + { + cs.setThreshold(view.getPidThreshold(), true); + cs.setConsensus(af.viewport.getSequenceConsensusHash()); + } + } + + af.viewport.setGlobalColourScheme(cs); + af.viewport.setColourAppliesToAllGroups(false); + + if (view.getConservationSelected() && cs != null) + { + cs.setConservationInc(view.getConsThreshold()); + } + + af.changeColour(cs); + + af.viewport.setColourAppliesToAllGroups(true); + + af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures()); + + if (view.hasCentreColumnLabels()) + { + af.viewport.setCentreColumnLabels(view.getCentreColumnLabels()); + } + if (view.hasIgnoreGapsinConsensus()) + { + af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(), + null); + } + if (view.hasFollowHighlight()) + { + af.viewport.followHighlight = view.getFollowHighlight(); + } + if (view.hasFollowSelection()) + { + af.viewport.followSelection = view.getFollowSelection(); + } + if (view.hasShowConsensusHistogram()) + { + af.viewport.setShowConsensusHistogram(view + .getShowConsensusHistogram()); + } + else + { + af.viewport.setShowConsensusHistogram(true); + } + if (view.hasShowSequenceLogo()) + { + af.viewport.setShowSequenceLogo(view.getShowSequenceLogo()); + } + else + { + af.viewport.setShowSequenceLogo(false); + } + if (view.hasNormaliseSequenceLogo()) + { + af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo()); + } + if (view.hasShowDbRefTooltip()) + { + af.viewport.setShowDbRefs(view.getShowDbRefTooltip()); + } + if (view.hasShowNPfeatureTooltip()) + { + af.viewport.setShowNpFeats(view.hasShowNPfeatureTooltip()); + } + if (view.hasShowGroupConsensus()) + { + af.viewport.setShowGroupConsensus(view.getShowGroupConsensus()); + } + else + { + af.viewport.setShowGroupConsensus(false); + } + if (view.hasShowGroupConservation()) + { + af.viewport.setShowGroupConservation(view.getShowGroupConservation()); + } + else + { + af.viewport.setShowGroupConservation(false); + } + + // recover featre settings + if (jms.getFeatureSettings() != null) + { + FeaturesDisplayed fdi; + af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed()); + String[] renderOrder = new String[jms.getFeatureSettings() + .getSettingCount()]; + Hashtable featureGroups = new Hashtable(); + Hashtable featureColours = new Hashtable(); + Hashtable featureOrder = new Hashtable(); + + for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++) + { + Setting setting = jms.getFeatureSettings().getSetting(fs); + if (setting.hasMincolour()) + { + GraduatedColor gc = setting.hasMin() ? new GraduatedColor( + new java.awt.Color(setting.getMincolour()), + new java.awt.Color(setting.getColour()), + setting.getMin(), setting.getMax()) : new GraduatedColor( + new java.awt.Color(setting.getMincolour()), + new java.awt.Color(setting.getColour()), 0, 1); + if (setting.hasThreshold()) + { + gc.setThresh(setting.getThreshold()); + gc.setThreshType(setting.getThreshstate()); + } + gc.setAutoScaled(true); // default + if (setting.hasAutoScale()) + { + gc.setAutoScaled(setting.getAutoScale()); + } + if (setting.hasColourByLabel()) + { + gc.setColourByLabel(setting.getColourByLabel()); + } + // and put in the feature colour table. + featureColours.put(setting.getType(), gc); + } + else + { + featureColours.put(setting.getType(), + new java.awt.Color(setting.getColour())); + } + renderOrder[fs] = setting.getType(); + if (setting.hasOrder()) + { + featureOrder.put(setting.getType(), setting.getOrder()); + } + else + { + featureOrder.put(setting.getType(), new Float(fs + / jms.getFeatureSettings().getSettingCount())); + } + if (setting.getDisplay()) + { + fdi.setVisible(setting.getType()); + } + } + Hashtable fgtable = new Hashtable(); + for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++) + { + Group grp = jms.getFeatureSettings().getGroup(gs); + fgtable.put(grp.getName(), new Boolean(grp.getDisplay())); + } + // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder, + // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ? + // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder); + FeatureRendererSettings frs = new FeatureRendererSettings( + renderOrder, fgtable, featureColours, 1.0f, featureOrder); + af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() + .transferSettings(frs); + + } + + if (view.getHiddenColumnsCount() > 0) + { + for (int c = 0; c < view.getHiddenColumnsCount(); c++) + { + af.viewport.hideColumns(view.getHiddenColumns(c).getStart(), view + .getHiddenColumns(c).getEnd() // +1 + ); + } + } + if (view.getCalcIdParam() != null) + { + for (CalcIdParam calcIdParam : view.getCalcIdParam()) + { + if (calcIdParam != null) + { + if (recoverCalcIdParam(calcIdParam, af.viewport)) + { + } + else + { + warn("Couldn't recover parameters for " + + calcIdParam.getCalcId()); + } + } + } + } + af.setMenusFromViewport(af.viewport); + // TODO: we don't need to do this if the viewport is aready visible. + Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(), + view.getHeight()); + af.alignPanel.updateAnnotation(false, true); // recompute any autoannotation + reorderAutoannotation(af, al, autoAlan); + af.alignPanel.alignmentChanged(); + return af; + } + + private ColourSchemeI constructAnnotationColour( + AnnotationColours viewAnnColour, AlignFrame af, Alignment al, + JalviewModelSequence jms, boolean checkGroupAnnColour) + { + boolean propagateAnnColour = false; + ColourSchemeI cs = null; + AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al; + if (checkGroupAnnColour && al.getGroups() != null + && al.getGroups().size() > 0) + { + // pre 2.8.1 behaviour + // check to see if we should transfer annotation colours + propagateAnnColour = true; + for (jalview.datamodel.SequenceGroup sg : al.getGroups()) + { + if (sg.cs instanceof AnnotationColourGradient) + { + propagateAnnColour = false; + } + } + } + // int find annotation + if (annAlignment.getAlignmentAnnotation() != null) + { + for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++) + { + if (annAlignment.getAlignmentAnnotation()[i].label + .equals(viewAnnColour.getAnnotation())) + { + if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null) + { + annAlignment.getAlignmentAnnotation()[i] + .setThreshold(new jalview.datamodel.GraphLine( + viewAnnColour.getThreshold(), "Threshold", + java.awt.Color.black) + + ); + } + + if (viewAnnColour.getColourScheme().equals("None")) + { + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + new java.awt.Color(viewAnnColour.getMinColour()), + new java.awt.Color(viewAnnColour.getMaxColour()), + viewAnnColour.getAboveThreshold()); + } + else if (viewAnnColour.getColourScheme().startsWith("ucs")) { - - af.viewport.historyList = av.historyList; - af.viewport.redoList = av.redoList; + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + getUserColourScheme(jms, + viewAnnColour.getColourScheme()), + viewAnnColour.getAboveThreshold()); } else { - viewportsAdded.put(uniqueSeqSetId, af.viewport); + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + ColourSchemeProperty.getColour(al, + viewAnnColour.getColourScheme()), + viewAnnColour.getAboveThreshold()); } - - PaintRefresher.Register(af.alignPanel, uniqueSeqSetId); - } - if(hiddenSeqs!=null) - { - for(int s=0; s