/*
* Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
* Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
*
* 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.
*
* 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 Jalview. If not, see .
*/
package jalview.io;
import jalview.bin.Cache;
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.GraphLine;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.AlignViewport;
import jalview.gui.Desktop;
import jalview.gui.TreePanel;
import jalview.io.vamsas.Datasetsequence;
import jalview.io.vamsas.DatastoreItem;
import jalview.io.vamsas.DatastoreRegistry;
import jalview.io.vamsas.Rangetype;
import jalview.util.UrlLink;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Vector;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import uk.ac.vamsas.client.*;
import uk.ac.vamsas.objects.core.*;
import uk.ac.vamsas.objects.utils.Properties;
/*
*
* static {
* org.exolab.castor.util.LocalConfiguration.getInstance().getProperties().setProperty(
* "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); }
*
*/
/*
* TODO: check/verify consistency for vamsas sync with group associated alignment annotation
*/
public class VamsasAppDatastore
{
/**
* Type used for general jalview generated annotation added to vamsas document
*/
public static final String JALVIEW_ANNOTATION_ROW = "JalviewAnnotation";
/**
* AlignmentAnnotation property to indicate that values should not be
* interpolated
*/
public static final String DISCRETE_ANNOTATION = "discrete";
/**
* continuous property - optional to specify that annotation should be
* represented as a continous graph line
*/
private static final String CONTINUOUS_ANNOTATION = "continuous";
private static final String THRESHOLD = "threshold";
/**
* template for provenance entries written to vamsas session document
*/
Entry provEntry = null;
/**
* Instance of the session document being synchronized with
*/
IClientDocument cdoc;
/**
* map Vorba (vamsas object xml ref) IDs to live jalview object references
*/
Hashtable vobj2jv;
/**
* map live jalview object references to Vorba IDs
*/
IdentityHashMap jv2vobj;
/**
* map jalview sequence set ID (which is vorba ID for alignment) to last
* recorded hash value for the alignment viewport (the undo/redo hash value)
*/
Hashtable alignRDHash;
public VamsasAppDatastore(IClientDocument cdoc, Hashtable vobj2jv,
IdentityHashMap jv2vobj, Entry provEntry, Hashtable alignRDHash)
{
this.cdoc = cdoc;
this.vobj2jv = vobj2jv;
this.jv2vobj = jv2vobj;
this.provEntry = provEntry;
this.alignRDHash = alignRDHash;
buildSkipList();
}
/**
* the skipList used to skip over views from Jalview Appdata's that we've
* already syncrhonized
*/
Hashtable skipList;
private void buildSkipList()
{
skipList = new Hashtable();
AlignFrame[] al = Desktop.getAlignframes();
for (int f = 0; al != null && f < al.length; f++)
{
skipList.put(al[f].getViewport().getSequenceSetId(), al[f]);
}
}
/**
* @return the Vobject bound to Jalview datamodel object
*/
protected Vobject getjv2vObj(Object jvobj)
{
if (jv2vobj.containsKey(jvobj))
{
return cdoc.getObject((VorbaId) jv2vobj.get(jvobj));
}
// check if we're working with a string - then workaround
// the use of IdentityHashTable because different strings
// have different object IDs.
if (jvobj instanceof String)
{
Object seqsetidobj = null;
seqsetidobj = getVamsasObjectBinding().get(jvobj);
if (seqsetidobj != null)
{
if (seqsetidobj instanceof String)
{
// what is expected. object returned by av.getSequenceSetId() -
// reverse lookup to get the 'registered' instance of this string
Vobject obj = getjv2vObj(seqsetidobj);
if (obj != null && !(obj instanceof Alignment))
{
Cache.log
.warn("IMPLEMENTATION ERROR?: Unexpected mapping for unmapped jalview string object content:"
+ seqsetidobj + " to object " + obj);
}
return obj;
}
else
{
Cache.log.warn("Unexpected mapping for Jalview String Object ID "
+ seqsetidobj + " to another jalview dataset object "
+ seqsetidobj);
}
}
}
if (Cache.log.isDebugEnabled())
{
Cache.log.debug("Returning null VorbaID binding for jalview object "
+ jvobj);
}
return null;
}
/**
*
* @param vobj
* @return Jalview datamodel object bound to the vamsas document object
*/
protected Object getvObj2jv(uk.ac.vamsas.client.Vobject vobj)
{
VorbaId id = vobj.getVorbaId();
if (id == null)
{
id = cdoc.registerObject(vobj);
Cache.log
.debug("Registering new object and returning null for getvObj2jv");
return null;
}
if (vobj2jv.containsKey(vobj.getVorbaId()))
{
return vobj2jv.get(vobj.getVorbaId());
}
return null;
}
protected void bindjvvobj(Object jvobj, uk.ac.vamsas.client.Vobject vobj)
{
VorbaId id = vobj.getVorbaId();
if (id == null)
{
id = cdoc.registerObject(vobj);
if (id == null || vobj.getVorbaId() == null
|| cdoc.getObject(id) != vobj)
{
Cache.log.error("Failed to get id for "
+ (vobj.isRegisterable() ? "registerable"
: "unregisterable") + " object " + vobj);
}
}
if (vobj2jv.containsKey(vobj.getVorbaId())
&& !((VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
{
Cache.log.debug(
"Warning? Overwriting existing vamsas id binding for "
+ vobj.getVorbaId(), new Exception(
"Overwriting vamsas id binding."));
}
else if (jv2vobj.containsKey(jvobj)
&& !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
{
Cache.log.debug(
"Warning? Overwriting existing jalview object binding for "
+ jvobj, new Exception(
"Overwriting jalview object binding."));
}
/*
* Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id "
* +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+"
* already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to
* bindjvvobj")); }
*/
// we just update the hash's regardless!
Cache.log.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
vobj2jv.put(vobj.getVorbaId(), jvobj);
// JBPNote - better implementing a hybrid invertible hash.
jv2vobj.put(jvobj, vobj.getVorbaId());
}
/**
* put the alignment viewed by AlignViewport into cdoc.
*
* @param av
* alignViewport to be stored
* @param aFtitle
* title for alignment
* @return true if alignment associated with viewport was stored/synchronized
* to document
*/
public boolean storeVAMSAS(AlignViewport av, String aFtitle)
{
try
{
jalview.datamodel.AlignmentI jal = av.getAlignment();
jalview.datamodel.AlignmentI jds = jal.getDataset();
boolean nw = false;
VAMSAS root = null; // will be resolved based on Dataset Parent.
// /////////////////////////////////////////
// SAVE THE DATASET
DataSet dataset = null;
if (jds == null)
{
Cache.log.warn("Creating new dataset for an alignment.");
jal.setDataset(null);
jds = jal.getDataset();
}
// try and get alignment and association for sequence set id
Alignment alignment = (Alignment) getjv2vObj(av.getSequenceSetId());
if (alignment != null)
{
dataset = (DataSet) alignment.getV_parent();
}
else
{
// is the dataset already registered
dataset = (DataSet) getjv2vObj(jds);
}
if (dataset == null)
{
// it might be that one of the dataset sequences does actually have a
// binding, so search for it indirectly. If it does, then the local
// jalview dataset
// must be merged with the existing vamsas dataset.
jalview.datamodel.SequenceI[] jdatset = jds.getSequencesArray();
for (int i = 0; i < jdatset.length; i++)
{
Vobject vbound = getjv2vObj(jdatset[i]);
if (vbound != null)
{
if (vbound instanceof uk.ac.vamsas.objects.core.Sequence)
{
if (dataset == null)
{
dataset = (DataSet) vbound.getV_parent();
}
else
{
if (vbound.getV_parent() != null
&& dataset != vbound.getV_parent())
{
throw new Error(
"IMPLEMENTATION ERROR: Cannot map an alignment of sequences from different datasets into a single alignment in the vamsas document.");
// This occurs because the dataset for the alignment we are
// trying to
}
}
}
}
}
}
if (dataset == null)
{
Cache.log.warn("Creating new vamsas dataset for alignment view "
+ av.getSequenceSetId());
// we create a new dataset on the default vamsas root.
root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.
dataset = new DataSet();
root.addDataSet(dataset);
bindjvvobj(jds, dataset);
dataset.setProvenance(dummyProvenance());
// dataset.getProvenance().addEntry(provEntry);
nw = true;
}
else
{
root = (VAMSAS) dataset.getV_parent();
}
// update dataset
Sequence sequence;
// set new dataset and alignment sequences based on alignment Nucleotide
// flag.
// this *will* break when alignment contains both nucleotide and amino
// acid sequences.
String dict = jal.isNucleotide() ? uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA
: uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;
Vector dssmods = new Vector();
for (int i = 0; i < jal.getHeight(); i++)
{
SequenceI sq = jal.getSequenceAt(i).getDatasetSequence(); // only insert
// referenced
// sequences
// to dataset.
Datasetsequence dssync = new jalview.io.vamsas.Datasetsequence(
this, sq, dict, dataset);
sequence = (Sequence) dssync.getVobj();
if (dssync.getModified())
{
dssmods.addElement(sequence);
}
;
}
if (dssmods.size() > 0)
{
if (!nw)
{
Entry pentry = this.addProvenance(dataset.getProvenance(),
"updated sequences");
// pentry.addInput(vInput); could write in which sequences were
// modified.
dssmods.removeAllElements();
}
}
// dataset.setProvenance(getVamsasProvenance(jal.getDataset().getProvenance()));
// ////////////////////////////////////////////
if (alignmentWillBeSkipped(av))
{
// TODO: trees could be written - but for the moment we just
addToSkipList(av);
// add to the JalviewXML skipList and ..
return false;
}
if (alignment == null)
{
alignment = new Alignment();
bindjvvobj(av.getSequenceSetId(), alignment);
if (alignment.getProvenance() == null)
{
alignment.setProvenance(new Provenance());
}
addProvenance(alignment.getProvenance(), "added"); // TODO: insert some
// sensible source
// here
dataset.addAlignment(alignment);
{
Property title = new Property();
title.setName("title");
title.setType("string");
title.setContent(aFtitle);
alignment.addProperty(title);
}
alignment.setGapChar(String.valueOf(av.getGapCharacter()));
for (int i = 0; i < jal.getHeight(); i++)
{
syncToAlignmentSequence(jal.getSequenceAt(i), alignment, null);
}
alignRDHash.put(av.getSequenceSetId(), av.getUndoRedoHash());
}
else
{
// always prepare to clone the alignment
boolean alismod = av.isUndoRedoHashModified((long[]) alignRDHash
.get(av.getSequenceSetId()));
// todo: verify and update mutable alignment props.
// TODO: Use isLocked methods
if (alignment.getModifiable() == null
|| alignment.getModifiable().length() == 0)
// && !alignment.isDependedOn())
{
boolean modified = false;
// check existing sequences in local and in document.
Vector docseqs = new Vector(
alignment.getAlignmentSequenceAsReference());
for (int i = 0; i < jal.getHeight(); i++)
{
modified |= syncToAlignmentSequence(jal.getSequenceAt(i),
alignment, docseqs);
}
if (docseqs.size() > 0)
{
// removeValignmentSequences(alignment, docseqs);
docseqs.removeAllElements();
System.out
.println("Sequence deletion from alignment is not implemented.");
}
if (modified)
{
if (alismod)
{
// info in the undo
addProvenance(alignment.getProvenance(), "Edited"); // TODO:
// insert
// something
// sensible
// here again
}
else
{
// info in the undo
addProvenance(alignment.getProvenance(), "Attributes Edited"); // TODO:
// insert
// something
// sensible
// here
// again
}
}
if (alismod)
{
System.out.println("update alignment in document.");
}
else
{
System.out.println("alignment in document left unchanged.");
}
}
else
{
// unbind alignment from view.
// create new binding and new alignment.
// mark trail on new alignment as being derived from old ?
System.out
.println("update edited alignment to new alignment in document.");
}
}
// ////////////////////////////////////////////
// SAVE Alignment Sequence Features
for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize; i++)
{
AlignmentSequence valseq;
SequenceI alseq = (SequenceI) getvObj2jv(valseq = alignment
.getAlignmentSequence(i));
if (alseq != null && alseq.getSequenceFeatures() != null)
{
/*
* We do not put local Alignment Sequence Features into the vamsas
* document yet.
*
*
* jalview.datamodel.SequenceFeature[] features = alseq
* .getSequenceFeatures(); for (int f = 0; f < features.length; f++) {
* if (features[f] != null) { AlignmentSequenceAnnotation valseqf = (
* AlignmentSequenceAnnotation) getjv2vObj(features[i]); if (valseqf
* == null) {
*
* valseqf = (AlignmentSequenceAnnotation) getDSAnnotationFromJalview(
* new AlignmentSequenceAnnotation(), features[i]);
* valseqf.setGraph(false);
* valseqf.addProperty(newProperty("jalview:feature"
* ,"boolean","true")); if (valseqf.getProvenance() == null) {
* valseqf.setProvenance(new Provenance()); }
* addProvenance(valseqf.getProvenance(), "created"); // JBPNote - //
* need to // update bindjvvobj(features[i], valseqf);
* valseq.addAlignmentSequenceAnnotation(valseqf); } } }
*/
}
}
// ////////////////////////////////////////////
// SAVE ANNOTATIONS
if (jal.getAlignmentAnnotation() != null)
{
jalview.datamodel.AlignmentAnnotation[] aa = jal
.getAlignmentAnnotation();
java.util.HashMap AlSeqMaps = new HashMap(); // stores int maps from
// alignment columns to
// sequence positions.
for (int i = 0; i < aa.length; i++)
{
if (aa[i] == null || isJalviewOnly(aa[i]))
{
continue;
}
if (aa[i].groupRef != null)
{
// TODO: store any group associated annotation references
Cache.log
.warn("Group associated sequence annotation is not stored in VAMSAS document.");
continue;
}
if (aa[i].sequenceRef != null)
{
// Deal with sequence associated annotation
Vobject sref = getjv2vObj(aa[i].sequenceRef);
if (sref instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
{
saveAlignmentSequenceAnnotation(AlSeqMaps,
(AlignmentSequence) sref, aa[i]);
}
else
{
// first find the alignment sequence to associate this with.
SequenceI jvalsq = null;
Enumeration jval = av.getAlignment().getSequences()
.elements();
while (jval.hasMoreElements())
{
jvalsq = (SequenceI) jval.nextElement();
// saveDatasetSequenceAnnotation(AlSeqMaps,(uk.ac.vamsas.objects.core.Sequence)
// sref, aa[i]);
if (jvalsq.getDatasetSequence() == aa[i].sequenceRef)
{
Vobject alsref = getjv2vObj(jvalsq);
saveAlignmentSequenceAnnotation(AlSeqMaps,
(AlignmentSequence) alsref, aa[i]);
break;
}
;
}
}
}
else
{
// add Alignment Annotation
uk.ac.vamsas.objects.core.AlignmentAnnotation an = (uk.ac.vamsas.objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);
if (an == null)
{
an = new uk.ac.vamsas.objects.core.AlignmentAnnotation();
an.setType(JALVIEW_ANNOTATION_ROW);
an.setDescription(aa[i].description);
alignment.addAlignmentAnnotation(an);
Seg vSeg = new Seg(); // TODO: refactor to have a default
// rangeAnnotationType initer/updater that
// takes a set of int ranges.
vSeg.setStart(1);
vSeg.setInclusive(true);
vSeg.setEnd(jal.getWidth());
an.addSeg(vSeg);
if (aa[i].graph > 0)
{
an.setGraph(true); // aa[i].graph);
}
an.setLabel(aa[i].label);
an.setProvenance(dummyProvenance());
if (aa[i].graph != AlignmentAnnotation.NO_GRAPH)
{
an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote
// -
// originally we
// were going to
// store
// graphGroup in
// the Jalview
// specific
// bits.
an.setGraph(true);
}
else
{
an.setGraph(false);
}
AnnotationElement ae;
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.addGlyph(new Glyph());
ae.getGlyph(0).setContent(
aa[i].annotations[a].displayCharacter); // assume
// jax-b
// takes
// care
// of
// utf8
// translation
if (an.isGraph())
{
ae.addValue(aa[i].annotations[a].value);
}
ae.setPosition(a + 1);
if (aa[i].annotations[a].secondaryStructure != ' ')
{
Glyph ss = new Glyph();
ss.setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
ss.setContent(String
.valueOf(aa[i].annotations[a].secondaryStructure));
ae.addGlyph(ss);
}
an.addAnnotationElement(ae);
}
if (aa[i].editable)
{
// an.addProperty(newProperty("jalview:editable", null,
// "true"));
// an.setModifiable(""); // TODO: This is not the way the
// modifiable flag is supposed to be used.
}
setAnnotationType(an, aa[i]);
if (aa[i].graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
{
an.setGraph(true);
an.setGroup(Integer.toString(aa[i].graphGroup));
if (aa[i].threshold != null && aa[i].threshold.displayed)
{
an.addProperty(Properties.newProperty(THRESHOLD,
Properties.FLOATTYPE, "" + aa[i].threshold.value));
if (aa[i].threshold.label != null)
{
an.addProperty(Properties.newProperty(THRESHOLD
+ "Name", Properties.STRINGTYPE, ""
+ aa[i].threshold.label));
}
}
}
}
else
{
if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT
// LOCK METHODS)
{
// verify annotation - update (perhaps)
Cache.log
.info("update alignment sequence annotation. not yet implemented.");
}
else
{
// verify annotation - update (perhaps)
Cache.log
.info("updated alignment sequence annotation added.");
}
}
}
}
}
// /////////////////////////////////////////////////////
// //////////////////////////////////////////////
// /SAVE THE TREES
// /////////////////////////////////
// FIND ANY ASSOCIATED TREES
if (Desktop.desktop != null)
{
javax.swing.JInternalFrame[] frames = Desktop.instance
.getAllFrames();
for (int t = 0; t < frames.length; t++)
{
if (frames[t] instanceof TreePanel)
{
TreePanel tp = (TreePanel) frames[t];
if (tp.getViewPort().getSequenceSetId()
.equals(av.getSequenceSetId()))
{
DatastoreItem vtree = new jalview.io.vamsas.Tree(this, tp,
jal, alignment);
}
}
}
}
// Store Jalview specific stuff in the Jalview appData
// not implemented in the SimpleDoc interface.
}
catch (Exception ex)
{
ex.printStackTrace();
return false;
}
return true;
}
/**
* very quick test to see if the viewport would be stored in the vamsas
* document. Reasons for not storing include the unaligned flag being false
* (for all sequences, including the hidden ones!)
*
* @param av
* @return true if alignment associated with this view will be stored in
* document.
*/
public boolean alignmentWillBeSkipped(AlignViewport av)
{
return (!av.getAlignment().isAligned());
}
private void addToSkipList(AlignViewport av)
{
if (skipList == null)
{
skipList = new Hashtable();
}
skipList.put(av.getSequenceSetId(), av);
}
/**
* remove docseqs from the given alignment marking provenance appropriately
* and removing any references to the sequences.
*
* @param alignment
* @param docseqs
*/
private void removeValignmentSequences(Alignment alignment, Vector docseqs)
{
// delete these from document. This really needs to be a generic document
// API function derived by CASTOR.
Enumeration en = docseqs.elements();
while (en.hasMoreElements())
{
alignment.removeAlignmentSequence((AlignmentSequence) en
.nextElement());
}
Entry pe = addProvenance(alignment.getProvenance(), "Removed "
+ docseqs.size() + " sequences");
en = alignment.enumerateAlignmentAnnotation();
Vector toremove = new Vector();
while (en.hasMoreElements())
{
uk.ac.vamsas.objects.core.AlignmentAnnotation alan = (uk.ac.vamsas.objects.core.AlignmentAnnotation) en
.nextElement();
if (alan.getSeqrefsCount() > 0)
{
int p = 0;
Vector storem = new Vector();
Enumeration sr = alan.enumerateSeqrefs();
while (sr.hasMoreElements())
{
Object alsr = sr.nextElement();
if (docseqs.contains(alsr))
{
storem.addElement(alsr);
}
}
// remove references to the deleted sequences
sr = storem.elements();
while (sr.hasMoreElements())
{
alan.removeSeqrefs(sr.nextElement());
}
if (alan.getSeqrefsCount() == 0)
{
// should then delete alan from dataset
toremove.addElement(alan);
}
}
}
// remove any annotation that used to be associated to a specific bunch of
// sequences
en = toremove.elements();
while (en.hasMoreElements())
{
alignment
.removeAlignmentAnnotation((uk.ac.vamsas.objects.core.AlignmentAnnotation) en
.nextElement());
}
// TODO: search through alignment annotations to remove any references to
// this alignment sequence
}
/**
* sync a jalview alignment seuqence into a vamsas alignment assumes all lock
* transformation/bindings have been sorted out before hand. creates/syncs the
* vamsas alignment sequence for jvalsq and adds it to the alignment if
* necessary. unbounddocseq is a duplicate of the vamsas alignment sequences
* and these are removed after being processed w.r.t a bound jvalsq
*
*/
private boolean syncToAlignmentSequence(SequenceI jvalsq,
Alignment alignment, Vector unbounddocseq)
{
boolean modal = false;
// todo: islocked method here
boolean up2doc = false;
AlignmentSequence alseq = (AlignmentSequence) getjv2vObj(jvalsq);
if (alseq == null)
{
alseq = new AlignmentSequence();
up2doc = true;
}
else
{
if (unbounddocseq != null)
{
unbounddocseq.removeElement(alseq);
}
}
// boolean locked = (alignment.getModifiable()==null ||
// alignment.getModifiable().length()>0);
// TODO: VAMSAS: translate lowercase symbols to annotation ?
if (up2doc || !alseq.getSequence().equals(jvalsq.getSequenceAsString()))
{
alseq.setSequence(jvalsq.getSequenceAsString());
alseq.setStart(jvalsq.getStart());
alseq.setEnd(jvalsq.getEnd());
modal = true;
}
if (up2doc || !alseq.getName().equals(jvalsq.getName()))
{
modal = true;
alseq.setName(jvalsq.getName());
}
if (jvalsq.getDescription() != null
&& (alseq.getDescription() == null || !jvalsq.getDescription()
.equals(alseq.getDescription())))
{
modal = true;
alseq.setDescription(jvalsq.getDescription());
}
if (getjv2vObj(jvalsq.getDatasetSequence()) == null)
{
Cache.log
.warn("Serious Implementation error - Unbound dataset sequence in alignment: "
+ jvalsq.getDatasetSequence());
}
alseq.setRefid(getjv2vObj(jvalsq.getDatasetSequence()));
if (up2doc)
{
alignment.addAlignmentSequence(alseq);
bindjvvobj(jvalsq, alseq);
}
return up2doc || modal;
}
/**
* locally sync a jalview alignment seuqence from a vamsas alignment assumes
* all lock transformation/bindings have been sorted out before hand.
* creates/syncs the jvalsq from the alignment sequence
*/
private boolean syncFromAlignmentSequence(AlignmentSequence valseq,
char valGapchar, char gapChar, Vector dsseqs)
{
boolean modal = false;
// todo: islocked method here
boolean upFromdoc = false;
jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);
if (alseq == null)
{
upFromdoc = true;
}
if (alseq != null)
{
// boolean locked = (alignment.getModifiable()==null ||
// alignment.getModifiable().length()>0);
// TODO: VAMSAS: translate lowercase symbols to annotation ?
if (upFromdoc
|| !valseq.getSequence().equals(alseq.getSequenceAsString()))
{
// this might go *horribly* wrong
alseq.setSequence(new String(valseq.getSequence()).replace(
valGapchar, gapChar));
alseq.setStart((int) valseq.getStart());
alseq.setEnd((int) valseq.getEnd());
modal = true;
}
if (!valseq.getName().equals(alseq.getName()))
{
modal = true;
alseq.setName(valseq.getName());
}
if (alseq.getDescription() == null
|| (valseq.getDescription() != null && !alseq
.getDescription().equals(valseq.getDescription())))
{
alseq.setDescription(valseq.getDescription());
modal = true;
}
if (modal && Cache.log.isDebugEnabled())
{
Cache.log.debug("Updating apparently edited sequence "
+ alseq.getName());
}
}
else
{
alseq = new jalview.datamodel.Sequence(valseq.getName(), valseq
.getSequence().replace(valGapchar, gapChar),
(int) valseq.getStart(), (int) valseq.getEnd());
Vobject datsetseq = (Vobject) valseq.getRefid();
if (datsetseq != null)
{
alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
if (valseq.getDescription() != null)
{
alseq.setDescription(valseq.getDescription());
}
else
{
// inherit description line from dataset.
if (alseq.getDatasetSequence().getDescription() != null)
{
alseq.setDescription(alseq.getDatasetSequence()
.getDescription());
}
}
// if
// AlignemntSequence
// reference
// isn't
// a
// simple
// SequenceI
}
else
{
Cache.log
.error("Invalid dataset sequence id (null) for alignment sequence "
+ valseq.getVorbaId());
}
bindjvvobj(alseq, valseq);
alseq.setVamsasId(valseq.getVorbaId().getId());
dsseqs.add(alseq);
}
Vobject datsetseq = (Vobject) valseq.getRefid();
if (datsetseq != null)
{
if (datsetseq != alseq.getDatasetSequence())
{
modal = true;
}
alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
}
return upFromdoc || modal;
}
private void initRangeAnnotationType(RangeAnnotation an,
AlignmentAnnotation alan, int[] gapMap)
{
Seg vSeg = new Seg();
vSeg.setStart(1);
vSeg.setInclusive(true);
vSeg.setEnd(gapMap.length);
an.addSeg(vSeg);
// LATER: much of this is verbatim from the alignmentAnnotation
// method below. suggests refactoring to make rangeAnnotation the
// base class
an.setDescription(alan.description);
an.setLabel(alan.label);
an.setGroup(Integer.toString(alan.graphGroup));
// // JBPNote -
// originally we
// were going to
// store
// graphGroup in
// the Jalview
// specific
// bits.
AnnotationElement ae;
for (int a = 0; a < alan.annotations.length; a++)
{
if (alan.annotations[a] == null)
{
continue;
}
ae = new AnnotationElement();
ae.setDescription(alan.annotations[a].description);
ae.addGlyph(new Glyph());
ae.getGlyph(0).setContent(alan.annotations[a].displayCharacter); // assume
// jax-b
// takes
// care
// of
// utf8
// translation
if (alan.graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
{
ae.addValue(alan.annotations[a].value);
}
ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
// symbols
if (alan.annotations[a].secondaryStructure != ' ')
{
// we only write an annotation where it really exists.
Glyph ss = new Glyph();
ss.setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
ss.setContent(String
.valueOf(alan.annotations[a].secondaryStructure));
ae.addGlyph(ss);
}
an.addAnnotationElement(ae);
}
}
private void saveDatasetSequenceAnnotation(HashMap AlSeqMaps,
uk.ac.vamsas.objects.core.Sequence sref, AlignmentAnnotation alan)
{
// {
// uk.ac.vamsas.
// objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
// objects.core.AlignmentSequence) sref;
uk.ac.vamsas.objects.core.DataSetAnnotations an = (uk.ac.vamsas.objects.core.DataSetAnnotations) getjv2vObj(alan);
int[] gapMap = getGapMap(AlSeqMaps, alan);
if (an == null)
{
an = new uk.ac.vamsas.objects.core.DataSetAnnotations();
initRangeAnnotationType(an, alan, gapMap);
an.setProvenance(dummyProvenance()); // get provenance as user
// created, or jnet, or
// something else.
setAnnotationType(an, alan);
an.setGroup(Integer.toString(alan.graphGroup)); // // JBPNote -
// originally we
// were going to
// store
// graphGroup in
// the Jalview
// specific
// bits.
if (alan.getThreshold() != null && alan.getThreshold().displayed)
{
an.addProperty(Properties.newProperty(THRESHOLD,
Properties.FLOATTYPE, "" + alan.getThreshold().value));
if (alan.getThreshold().label != null)
an.addProperty(Properties.newProperty(THRESHOLD + "Name",
Properties.STRINGTYPE, "" + alan.getThreshold().label));
}
((DataSet) sref.getV_parent()).addDataSetAnnotations(an);
bindjvvobj(alan, an);
}
else
{
// update reference sequence Annotation
if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
// METHODS)
{
// verify existing alignment sequence annotation is up to date
System.out.println("update dataset sequence annotation.");
}
else
{
// verify existing alignment sequence annotation is up to date
System.out
.println("make new alignment dataset sequence annotation if modification has happened.");
}
}
}
private int[] getGapMap(HashMap AlSeqMaps, AlignmentAnnotation alan)
{
int[] gapMap;
if (AlSeqMaps.containsKey(alan.sequenceRef))
{
gapMap = (int[]) AlSeqMaps.get(alan.sequenceRef);
}
else
{
gapMap = new int[alan.sequenceRef.getLength()];
// map from alignment position to sequence position.
int[] sgapMap = alan.sequenceRef.gapMap();
for (int a = 0; a < sgapMap.length; a++)
{
gapMap[sgapMap[a]] = a;
}
}
return gapMap;
}
private void saveAlignmentSequenceAnnotation(HashMap AlSeqMaps,
AlignmentSequence alsref, AlignmentAnnotation alan)
{
// {
// uk.ac.vamsas.
// objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
// objects.core.AlignmentSequence) sref;
uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(alan);
int[] gapMap = getGapMap(AlSeqMaps, alan);
if (an == null)
{
an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
initRangeAnnotationType(an, alan, gapMap);
/**
* I mean here that we don't actually have a semantic 'type' for the
* annotation (this might be - score, intrinsic property, measurement,
* something extracted from another program, etc)
*/
an.setType(JALVIEW_ANNOTATION_ROW); // TODO: better fix
// this rough guess ;)
alsref.addAlignmentSequenceAnnotation(an);
bindjvvobj(alan, an);
// These properties are directly supported by the
// AlignmentSequenceAnnotation type.
setAnnotationType(an, alan);
an.setProvenance(dummyProvenance()); // get provenance as user
// created, or jnet, or
// something else.
}
else
{
// update reference sequence Annotation
if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
// METHODS)
{
// verify existing alignment sequence annotation is up to date
System.out.println("update alignment sequence annotation.");
}
else
{
// verify existing alignment sequence annotation is up to date
System.out
.println("make new alignment sequence annotation if modification has happened.");
}
}
}
/**
* set vamsas annotation object type from jalview annotation
*
* @param an
* @param alan
*/
private void setAnnotationType(RangeAnnotation an,
AlignmentAnnotation alan)
{
if (an instanceof AlignmentSequenceAnnotation)
{
if (alan.graph != AlignmentAnnotation.NO_GRAPH)
{
((AlignmentSequenceAnnotation) an).setGraph(true);
}
else
{
((AlignmentSequenceAnnotation) an).setGraph(false);
}
}
if (an instanceof uk.ac.vamsas.objects.core.AlignmentAnnotation)
{
if (alan.graph != AlignmentAnnotation.NO_GRAPH)
{
((uk.ac.vamsas.objects.core.AlignmentAnnotation) an).setGraph(true);
}
else
{
((uk.ac.vamsas.objects.core.AlignmentAnnotation) an)
.setGraph(false);
}
}
switch (alan.graph)
{
case AlignmentAnnotation.BAR_GRAPH:
an.addProperty(Properties.newProperty(DISCRETE_ANNOTATION,
Properties.BOOLEANTYPE, "true"));
break;
case AlignmentAnnotation.LINE_GRAPH:
an.addProperty(Properties.newProperty(CONTINUOUS_ANNOTATION,
Properties.BOOLEANTYPE, "true"));
break;
default:
// don't add any kind of discrete or continous property info.
}
}
/**
* get start 1)
{
// we need to close the original document view.
// work out how to do this by seeing if the views are gathered.
// pretty clunky but the only way to do this without adding more flags
// to the align frames.
boolean gathered = false;
String newviewid = null;
AlignedCodonFrame[] mappings = av.getAlignment().getCodonFrames();
for (int i = 0; i < views.length; i++)
{
if (views[i] != av)
{
AlignFrame viewframe = Desktop.getAlignFrameFor(views[i]);
if (viewframe == af)
{
gathered = true;
}
newviewid = views[i].getSequenceSetId();
}
else
{
// lose the reference to the vamsas document created view
views[i] = null;
}
}
// close the view generated by the vamsas document synchronization
if (gathered)
{
af.closeView(av);
}
else
{
af.closeMenuItem_actionPerformed(false);
}
replaceJvObjMapping(seqsetidobj, newviewid);
seqsetidobj = newviewid;
// not sure if we need to do this:
if (false) // mappings != null)
{
// ensure sequence mappings from vamsas document view still
// active
if (mappings != null && mappings.length > 0)
{
jalview.structure.StructureSelectionManager
.getStructureSelectionManager().addMappings(mappings);
}
}
}
// ensure vamsas object binds to the stored views retrieved from
// Jalview appdata
// jalview.structure.StructureSelectionManager
// .getStructureSelectionManager()
// .addStructureViewerListener(viewframe.alignPanel);
}
newviews = null;
newAlignmentViews.clear();
}
/**
* replaces oldjvobject with newjvobject in the Jalview Object <> VorbaID
* binding tables
*
* @param oldjvobject
* @param newjvobject
* (may be null)
*/
private void replaceJvObjMapping(Object oldjvobject, Object newjvobject)
{
Object vobject = jv2vobj.remove(oldjvobject);
if (vobject == null)
{
throw new Error(
"IMPLEMENTATION ERROR: old jalview object is not bound ! ("
+ oldjvobject + ")");
}
if (newjvobject != null)
{
jv2vobj.put(newjvobject, vobject);
vobj2jv.put(vobject, newjvobject);
}
}
/**
* Update the jalview client and user appdata from the local jalview settings
*/
public void updateJalviewClientAppdata()
{
final IClientAppdata cappdata = cdoc.getClientAppdata();
if (cappdata != null)
{
try
{
jalview.gui.Jalview2XML jxml = new jalview.gui.Jalview2XML();
jxml.setObjectMappingTables(mapKeysToString(vobj2jv),
mapValuesToString(jv2vobj));
jxml.setSkipList(skipList);
if (dojvsync)
{
jxml.SaveState(new JarOutputStream(cappdata
.getClientOutputStream()));
}
} catch (Exception e)
{
// TODO raise GUI warning if user requests it.
jalview.bin.Cache.log
.error("Couldn't update jalview client application data. Giving up - local settings probably lost.",
e);
}
}
else
{
jalview.bin.Cache.log
.error("Couldn't access client application data for vamsas session. This is probably a vamsas client bug.");
}
}
/**
* translate the Vobject keys to strings for use in Jalview2XML
*
* @param jv2vobj2
* @return
*/
private IdentityHashMap mapValuesToString(IdentityHashMap jv2vobj2)
{
IdentityHashMap mapped = new IdentityHashMap();
Iterator keys = jv2vobj2.keySet().iterator();
while (keys.hasNext())
{
Object key = keys.next();
mapped.put(key, jv2vobj2.get(key).toString());
}
return mapped;
}
/**
* translate the Vobject values to strings for use in Jalview2XML
*
* @param vobj2jv2
* @return hashtable with string values
*/
private Hashtable mapKeysToString(Hashtable vobj2jv2)
{
Hashtable mapped = new Hashtable();
Iterator keys = vobj2jv2.keySet().iterator();
while (keys.hasNext())
{
Object key = keys.next();
mapped.put(key.toString(), vobj2jv2.get(key));
}
return mapped;
}
/**
* synchronize Jalview from the vamsas document
*
* @return number of new views from document
*/
public int updateToJalview()
{
VAMSAS _roots[] = cdoc.getVamsasRoots();
for (int _root = 0; _root < _roots.length; _root++)
{
VAMSAS root = _roots[_root];
boolean newds = false;
for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
{
// ///////////////////////////////////
// ///LOAD DATASET
DataSet dataset = root.getDataSet(_ds);
int i, iSize = dataset.getSequenceCount();
Vector dsseqs;
jalview.datamodel.Alignment jdataset = (jalview.datamodel.Alignment) getvObj2jv(dataset);
int jremain = 0;
if (jdataset == null)
{
Cache.log.debug("Initialising new jalview dataset fields");
newds = true;
dsseqs = new Vector();
}
else
{
Cache.log.debug("Update jalview dataset from vamsas.");
jremain = jdataset.getHeight();
dsseqs = jdataset.getSequences();
}
// TODO: test sequence merging - we preserve existing non vamsas
// sequences but add in any new vamsas ones, and don't yet update any
// sequence attributes
for (i = 0; i < iSize; i++)
{
Sequence vdseq = dataset.getSequence(i);
jalview.io.vamsas.Datasetsequence dssync = new Datasetsequence(
this, vdseq);
jalview.datamodel.SequenceI dsseq = (SequenceI) dssync.getJvobj();
if (dssync.isAddfromdoc())
{
dsseqs.add(dsseq);
}
if (vdseq.getDbRefCount() > 0)
{
DbRef[] dbref = vdseq.getDbRef();
for (int db = 0; db < dbref.length; db++)
{
new jalview.io.vamsas.Dbref(this, dbref[db], vdseq, dsseq);
}
dsseq.updatePDBIds();
}
}
if (newds)
{
SequenceI[] seqs = new SequenceI[dsseqs.size()];
for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
{
seqs[i] = (SequenceI) dsseqs.elementAt(i);
dsseqs.setElementAt(null, i);
}
jdataset = new jalview.datamodel.Alignment(seqs);
Cache.log.debug("New vamsas dataset imported into jalview.");
bindjvvobj(jdataset, dataset);
}
// ////////
// add any new dataset sequence feature annotations
if (dataset.getDataSetAnnotations() != null)
{
for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++)
{
DataSetAnnotations dseta = dataset.getDataSetAnnotations(dsa);
// TODO: deal with group annotation on datset sequences.
if (dseta.getSeqRefCount() == 1)
{
SequenceI dsSeq = (SequenceI) getvObj2jv((Vobject) dseta
.getSeqRef(0)); // TODO: deal with group dataset
// annotations
if (dsSeq == null)
{
jalview.bin.Cache.log
.warn("Couldn't resolve jalview sequenceI for dataset object reference "
+ ((Vobject) dataset.getDataSetAnnotations(
dsa).getSeqRef(0)).getVorbaId()
.getId());
}
else
{
if (dseta.getAnnotationElementCount() == 0)
{
new jalview.io.vamsas.Sequencefeature(this, dseta, dsSeq);
}
else
{
// TODO: deal with alignmentAnnotation style annotation
// appearing on dataset sequences.
// JBPNote: we could just add them to all alignments but
// that may complicate cross references in the jalview
// datamodel
Cache.log
.warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
}
}
}
else
{
Cache.log
.warn("Ignoring multiply referenced dataset sequence annotation for binding to datsaet sequence features.");
}
}
}
if (dataset.getAlignmentCount() > 0)
{
// LOAD ALIGNMENTS from DATASET
for (int al = 0, nal = dataset.getAlignmentCount(); al < nal; al++)
{
uk.ac.vamsas.objects.core.Alignment alignment = dataset
.getAlignment(al);
// TODO check this handles multiple views properly
AlignViewport av = findViewport(alignment);
jalview.datamodel.AlignmentI jal = null;
if (av != null)
{
// TODO check that correct alignment object is retrieved when
// hidden seqs exist.
jal = (av.hasHiddenRows()) ? av.getAlignment()
.getHiddenSequences().getFullAlignment() : av
.getAlignment();
}
iSize = alignment.getAlignmentSequenceCount();
boolean refreshal = false;
Vector newasAnnots = new Vector();
char gapChar = ' '; // default for new alignments read in from the
// document
if (jal != null)
{
dsseqs = jal.getSequences(); // for merge/update
gapChar = jal.getGapCharacter();
}
else
{
dsseqs = new Vector();
}
char valGapchar = alignment.getGapChar().charAt(0);
for (i = 0; i < iSize; i++)
{
AlignmentSequence valseq = alignment.getAlignmentSequence(i);
jalview.datamodel.Sequence alseq = (jalview.datamodel.Sequence) getvObj2jv(valseq);
if (syncFromAlignmentSequence(valseq, valGapchar, gapChar,
dsseqs) && alseq != null)
{
// updated to sequence from the document
jremain--;
refreshal = true;
}
if (valseq.getAlignmentSequenceAnnotationCount() > 0)
{
AlignmentSequenceAnnotation[] vasannot = valseq
.getAlignmentSequenceAnnotation();
for (int a = 0; a < vasannot.length; a++)
{
jalview.datamodel.AlignmentAnnotation asa = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO:
// 1:many
// jalview
// alignment
// sequence
// annotations
if (asa == null)
{
int se[] = getBounds(vasannot[a]);
asa = getjAlignmentAnnotation(jal, vasannot[a]);
asa.setSequenceRef(alseq);
asa.createSequenceMapping(alseq, se[0], false); // TODO:
// verify
// that
// positions
// in
// alseqAnnotation
// correspond
// to
// ungapped
// residue
// positions.
alseq.addAlignmentAnnotation(asa);
bindjvvobj(asa, vasannot[a]);
refreshal = true;
newasAnnots.add(asa);
}
else
{
// update existing annotation - can do this in place
if (vasannot[a].getModifiable() == null) // TODO: USE
// VAMSAS LIBRARY
// OBJECT LOCK
// METHODS)
{
Cache.log
.info("UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
// TODO: should at least replace with new one - otherwise
// things will break
// basically do this:
// int se[] = getBounds(vasannot[a]);
// asa.update(getjAlignmentAnnotation(jal, vasannot[a]));
// // update from another annotation object in place.
// asa.createSequenceMapping(alseq, se[0], false);
}
}
}
}
}
if (jal == null)
{
SequenceI[] seqs = new SequenceI[dsseqs.size()];
for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
{
seqs[i] = (SequenceI) dsseqs.elementAt(i);
dsseqs.setElementAt(null, i);
}
jal = new jalview.datamodel.Alignment(seqs);
Cache.log.debug("New vamsas alignment imported into jalview "
+ alignment.getVorbaId().getId());
jal.setDataset(jdataset);
}
if (newasAnnots != null && newasAnnots.size() > 0)
{
// Add the new sequence annotations in to the alignment.
for (int an = 0, anSize = newasAnnots.size(); an < anSize; an++)
{
jal.addAnnotation((AlignmentAnnotation) newasAnnots
.elementAt(an));
// TODO: check if anything has to be done - like calling
// adjustForAlignment or something.
newasAnnots.setElementAt(null, an);
}
newasAnnots = null;
}
// //////////////////////////////////////////
// //LOAD ANNOTATIONS FOR THE ALIGNMENT
// ////////////////////////////////////
if (alignment.getAlignmentAnnotationCount() > 0)
{
uk.ac.vamsas.objects.core.AlignmentAnnotation[] an = alignment
.getAlignmentAnnotation();
for (int j = 0; j < an.length; j++)
{
jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(an[j]);
if (jan != null)
{
// update or stay the same.
// TODO: should at least replace with a new one - otherwise
// things will break
// basically do this:
// jan.update(getjAlignmentAnnotation(jal, an[a])); // update
// from another annotation object in place.
Cache.log
.debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
if (an[j].getModifiable() == null) // TODO: USE VAMSAS
// LIBRARY OBJECT LOCK
// METHODS)
{
// TODO: user defined annotation is totally mutable... - so
// load it up or throw away if locally edited.
Cache.log
.info("NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
}
// TODO: compare annotation element rows
// TODO: compare props.
}
else
{
jan = getjAlignmentAnnotation(jal, an[j]);
// TODO: ensure we add the alignment annotation before the
// automatic annotation rows
jal.addAnnotation(jan);
bindjvvobj(jan, an[j]);
refreshal = true;
}
}
}
AlignFrame alignFrame;
if (av == null)
{
Cache.log.debug("New alignframe for alignment "
+ alignment.getVorbaId());
// ///////////////////////////////
// construct alignment view
alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT, alignment.getVorbaId()
.toString());
av = alignFrame.getViewport();
newAlignmentViews.addElement(av);
String title = alignment
.getProvenance()
.getEntry(
alignment.getProvenance().getEntryCount() - 1)
.getAction();
if (alignment.getPropertyCount() > 0)
{
for (int p = 0, pe = alignment.getPropertyCount(); p < pe; p++)
{
if (alignment.getProperty(p).getName().equals("title"))
{
title = alignment.getProperty(p).getContent();
}
}
}
// TODO: automatically create meaningful title for a vamsas
// alignment using its provenance.
if (Cache.log.isDebugEnabled())
{
title = title + "(" + alignment.getVorbaId() + ")";
}
jalview.gui.Desktop.addInternalFrame(alignFrame, title,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
bindjvvobj(av.getSequenceSetId(), alignment);
}
else
{
// find the alignFrame for jal.
// TODO: fix this so we retrieve the alignFrame handing av
// *directly* (JBPNote - don't understand this now)
// TODO: make sure all associated views are refreshed
alignFrame = Desktop.getAlignFrameFor(av);
if (refreshal)
{
av.alignmentChanged(alignFrame.alignPanel);
alignFrame.alignPanel.adjustAnnotationHeight();
}
}
// LOAD TREES
// /////////////////////////////////////
if (alignment.getTreeCount() > 0)
{
for (int t = 0; t < alignment.getTreeCount(); t++)
{
jalview.io.vamsas.Tree vstree = new jalview.io.vamsas.Tree(
this, alignFrame, alignment.getTree(t));
TreePanel tp = null;
if (vstree.isValidTree())
{
tp = alignFrame.ShowNewickTree(vstree.getNewickTree(),
vstree.getTitle(), vstree.getInputData(), 600,
500, t * 20 + 50, t * 20 + 50);
}
if (tp != null)
{
bindjvvobj(tp, alignment.getTree(t));
try
{
vstree.UpdateSequenceTreeMap(tp);
} catch (RuntimeException e)
{
Cache.log.warn("update of labels failed.", e);
}
}
else
{
Cache.log.warn("Cannot create tree for tree " + t
+ " in document ("
+ alignment.getTree(t).getVorbaId());
}
}
}
}
}
}
// we do sequenceMappings last because they span all datasets in a vamsas
// root
for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
{
DataSet dataset = root.getDataSet(_ds);
if (dataset.getSequenceMappingCount() > 0)
{
for (int sm = 0, smCount = dataset.getSequenceMappingCount(); sm < smCount; sm++)
{
Rangetype seqmap = new jalview.io.vamsas.Sequencemapping(this,
dataset.getSequenceMapping(sm));
}
}
}
}
return newAlignmentViews.size();
}
public AlignViewport findViewport(Alignment alignment)
{
AlignViewport av = null;
AlignViewport[] avs = Desktop
.getViewports((String) getvObj2jv(alignment));
if (avs != null)
{
av = avs[0];
}
return av;
}
// bitfields - should be a template in j1.5
private static int HASSECSTR = 0;
private static int HASVALS = 1;
private static int HASHPHOB = 2;
private static int HASDC = 3;
private static int HASDESCSTR = 4;
private static int HASTWOSTATE = 5; // not used yet.
/**
* parses the AnnotationElements - if they exist - into
* jalview.datamodel.Annotation[] rows Two annotation rows are made if there
* are distinct annotation for both at 'pos' and 'after pos' at any particular
* site.
*
* @param annotation
* @return { boolean[static int constants ], int[ae.length] - map to annotated
* object frame, jalview.datamodel.Annotation[],
* jalview.datamodel.Annotation[] (after)}
*/
private Object[] parseRangeAnnotation(
uk.ac.vamsas.objects.core.RangeAnnotation annotation)
{
// set these attributes by looking in the annotation to decide what kind of
// alignment annotation rows will be made
// TODO: potentially we might make several annotation rows from one vamsas
// alignment annotation. the jv2Vobj binding mechanism
// may not quite cope with this (without binding an array of annotations to
// a vamsas alignment annotation)
// summary flags saying what we found over the set of annotation rows.
boolean[] AeContent = new boolean[]
{ false, false, false, false, false };
int[] rangeMap = getMapping(annotation);
jalview.datamodel.Annotation[][] anot = new jalview.datamodel.Annotation[][]
{ new jalview.datamodel.Annotation[rangeMap.length],
new jalview.datamodel.Annotation[rangeMap.length] };
boolean mergeable = true; // false if 'after positions cant be placed on
// same annotation row as positions.
if (annotation.getAnnotationElementCount() > 0)
{
AnnotationElement ae[] = annotation.getAnnotationElement();
for (int aa = 0; aa < ae.length; aa++)
{
int pos = (int) ae[aa].getPosition() - 1; // pos counts from 1 to
// (|seg.start-seg.end|+1)
if (pos >= 0 && pos < rangeMap.length)
{
int row = ae[aa].getAfter() ? 1 : 0;
if (anot[row][pos] != null)
{
// only time this should happen is if the After flag is set.
Cache.log.debug("Ignoring duplicate annotation site at " + pos);
continue;
}
if (anot[1 - row][pos] != null)
{
mergeable = false;
}
String desc = "";
if (ae[aa].getDescription() != null)
{
desc = ae[aa].getDescription();
if (desc.length() > 0)
{
// have imported valid description string
AeContent[HASDESCSTR] = true;
}
}
String dc = null; // ae[aa].getDisplayCharacter()==null ? "dc" :
// ae[aa].getDisplayCharacter();
String ss = null; // ae[aa].getSecondaryStructure()==null ? "ss" :
// ae[aa].getSecondaryStructure();
java.awt.Color colour = null;
if (ae[aa].getGlyphCount() > 0)
{
Glyph[] glyphs = ae[aa].getGlyph();
for (int g = 0; g < glyphs.length; g++)
{
if (glyphs[g]
.getDict()
.equals(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE))
{
ss = glyphs[g].getContent();
AeContent[HASSECSTR] = true;
}
else if (glyphs[g]
.getDict()
.equals(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO))
{
Cache.log.debug("ignoring hydrophobicity glyph marker.");
AeContent[HASHPHOB] = true;
char c = (dc = glyphs[g].getContent()).charAt(0);
// dc may get overwritten - but we still set the colour.
colour = new java.awt.Color(c == '+' ? 255 : 0,
c == '.' ? 255 : 0, c == '-' ? 255 : 0);
}
else if (glyphs[g].getDict().equals(
uk.ac.vamsas.objects.utils.GlyphDictionary.DEFAULT))
{
dc = glyphs[g].getContent();
AeContent[HASDC] = true;
}
else
{
Cache.log
.debug("IMPLEMENTATION TODO: Ignoring unknown glyph type "
+ glyphs[g].getDict());
}
}
}
float val = 0;
if (ae[aa].getValueCount() > 0)
{
AeContent[HASVALS] = true;
if (ae[aa].getValueCount() > 1)
{
Cache.log.warn("ignoring additional "
+ (ae[aa].getValueCount() - 1)
+ " values in annotation element.");
}
val = ae[aa].getValue(0);
}
if (colour == null)
{
anot[row][pos] = new jalview.datamodel.Annotation(
(dc != null) ? dc : "", desc,
(ss != null) ? ss.charAt(0) : ' ', val);
}
else
{
anot[row][pos] = new jalview.datamodel.Annotation(
(dc != null) ? dc : "", desc,
(ss != null) ? ss.charAt(0) : ' ', val, colour);
}
}
else
{
Cache.log.warn("Ignoring out of bound annotation element " + aa
+ " in " + annotation.getVorbaId().getId());
}
}
// decide on how many annotation rows are needed.
if (mergeable)
{
for (int i = 0; i < anot[0].length; i++)
{
if (anot[1][i] != null)
{
anot[0][i] = anot[1][i];
anot[0][i].description = anot[0][i].description + " (after)";
AeContent[HASDESCSTR] = true; // we have valid description string
// data
anot[1][i] = null;
}
}
anot[1] = null;
}
else
{
for (int i = 0; i < anot[0].length; i++)
{
anot[1][i].description = anot[1][i].description + " (after)";
}
}
return new Object[]
{ AeContent, rangeMap, anot[0], anot[1] };
}
else
{
// no annotations to parse. Just return an empty annotationElement[]
// array.
return new Object[]
{ AeContent, rangeMap, anot[0], anot[1] };
}
// return null;
}
/**
* @param jal
* the jalview alignment to which the annotation will be attached
* (ideally - freshly updated from corresponding vamsas alignment)
* @param annotation
* @return unbound jalview alignment annotation object.
*/
private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(
jalview.datamodel.AlignmentI jal,
uk.ac.vamsas.objects.core.RangeAnnotation annotation)
{
if (annotation == null)
{
return null;
}
// boolean
// hasSequenceRef=annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation.class);
// boolean hasProvenance=hasSequenceRef ||
// (annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class));
/*
* int se[] = getBounds(annotation); if (se==null) se=new int[]
* {0,jal.getWidth()-1};
*/
Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);
String a_label = annotation.getLabel();
String a_descr = annotation.getDescription();
GraphLine gl = null;
int type = 0;
boolean interp = true; // cleared if annotation is DISCRETE
// set type and other attributes from properties
if (annotation.getPropertyCount() > 0)
{
// look for special jalview properties
uk.ac.vamsas.objects.core.Property[] props = annotation.getProperty();
for (int p = 0; p < props.length; p++)
{
if (props[p].getName().equalsIgnoreCase(DISCRETE_ANNOTATION))
{
type = AlignmentAnnotation.BAR_GRAPH;
interp = false;
}
else if (props[p].getName().equalsIgnoreCase(CONTINUOUS_ANNOTATION))
{
type = AlignmentAnnotation.LINE_GRAPH;
}
else if (props[p].getName().equalsIgnoreCase(THRESHOLD))
{
Float val = null;
try
{
val = new Float(props[p].getContent());
} catch (Exception e)
{
Cache.log.warn("Failed to parse threshold property");
}
if (val != null)
if (gl == null)
{
gl = new GraphLine(val.floatValue(), "", java.awt.Color.black);
}
else
{
gl.value = val.floatValue();
}
}
else if (props[p].getName().equalsIgnoreCase(THRESHOLD + "Name"))
{
if (gl == null)
gl = new GraphLine(0, "", java.awt.Color.black);
gl.label = props[p].getContent();
}
}
}
jalview.datamodel.AlignmentAnnotation jan = null;
if (a_label == null || a_label.length() == 0)
{
a_label = annotation.getType();
if (a_label.length() == 0)
{
a_label = "Unamed annotation";
}
}
if (a_descr == null || a_descr.length() == 0)
{
a_descr = "Annotation of type '" + annotation.getType() + "'";
}
if (parsedRangeAnnotation == null)
{
Cache.log
.debug("Inserting empty annotation row elements for a whole-alignment annotation.");
}
else
{
if (parsedRangeAnnotation[3] != null)
{
Cache.log.warn("Ignoring 'After' annotation row in "
+ annotation.getVorbaId());
}
jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];
boolean[] has = (boolean[]) parsedRangeAnnotation[0];
// VAMSAS: getGraph is only on derived annotation for alignments - in this
// way its 'odd' - there is already an existing TODO about removing this
// flag as being redundant
/*
* if((annotation.getClass().equals(uk.ac.vamsas.objects.core.
* AlignmentAnnotation.class) &&
* ((uk.ac.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph())
* || (hasSequenceRef=true &&
* ((uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation
* )annotation).getGraph())) {
*/
if (has[HASVALS])
{
if (type == 0)
{
type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH; // default
// type of
// value
// annotation
if (has[HASHPHOB])
{
// no hints - so we ensure HPHOB display is like this.
type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
}
}
// make bounds and automatic description strings for jalview user's
// benefit (these shouldn't be written back to vamsas document)
boolean first = true;
float min = 0, max = 1;
int lastval = 0;
for (int i = 0; i < arow.length; i++)
{
if (arow[i] != null)
{
if (i - lastval > 1 && interp)
{
// do some interpolation *between* points
if (arow[lastval] != null)
{
float interval = arow[i].value - arow[lastval].value;
interval /= i - lastval;
float base = arow[lastval].value;
for (int ip = lastval + 1, np = 0; ip < i; np++, ip++)
{
arow[ip] = new jalview.datamodel.Annotation("", "", ' ',
interval * np + base);
// NB - Interpolated points don't get a tooltip and
// description.
}
}
}
lastval = i;
// check range - shouldn't we have a min and max property in the
// annotation object ?
if (first)
{
min = max = arow[i].value;
first = false;
}
else
{
if (arow[i].value < min)
{
min = arow[i].value;
}
else if (arow[i].value > max)
{
max = arow[i].value;
}
}
// make tooltip and display char value
if (!has[HASDESCSTR])
{
arow[i].description = arow[i].value + "";
}
if (!has[HASDC])
{
if (!interp)
{
if (arow[i].description != null
&& arow[i].description.length() < 3)
{
// copy over the description as the display char.
arow[i].displayCharacter = new String(arow[i].description);
}
}
else
{
// mark the position as a point used for the interpolation.
arow[i].displayCharacter = arow[i].value + "";
}
}
}
}
jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
arow, min, max, type);
}
else
{
if (annotation.getAnnotationElementCount() == 0)
{
// empty annotation array
// TODO: alignment 'features' compare rangeType spec to alignment
// width - if it is not complete, then mark regions on the annotation
// row.
}
jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
arow);
jan.setThreshold(null);
jan.annotationId = annotation.getVorbaId().toString(); // keep all the
// ids together.
}
if (annotation.getLinkCount() > 0)
{
Cache.log.warn("Ignoring " + annotation.getLinkCount()
+ "links added to AlignmentAnnotation.");
}
if (annotation.getModifiable() == null
|| annotation.getModifiable().length() == 0) // TODO: USE VAMSAS
// LIBRARY OBJECT
// LOCK METHODS)
{
jan.editable = true;
}
try
{
if (annotation.getGroup() != null
&& annotation.getGroup().length() > 0)
{
jan.graphGroup = Integer.parseInt(annotation.getGroup()); // TODO:
// group
// similarly
// named
// annotation
// together
// ?
}
} catch (Exception e)
{
Cache.log
.info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
}
return jan;
}
return null;
}
/**
* get real bounds of a RangeType's specification. start and end are an
* inclusive range within which all segments and positions lie. TODO: refactor
* to vamsas utils
*
* @param dseta
* @return int[] { start, end}
*/
private int[] getBounds(RangeType dseta)
{
if (dseta != null)
{
int[] se = null;
if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
{
throw new Error(
"Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
}
if (dseta.getSegCount() > 0)
{
se = getSegRange(dseta.getSeg(0), true);
for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)
{
int nse[] = getSegRange(dseta.getSeg(s), true);
if (se[0] > nse[0])
{
se[0] = nse[0];
}
if (se[1] < nse[1])
{
se[1] = nse[1];
}
}
}
if (dseta.getPosCount() > 0)
{
// could do a polarity for pos range too. and pass back indication of
// discontinuities.
int pos = dseta.getPos(0).getI();
se = new int[]
{ pos, pos };
for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
{
pos = dseta.getPos(p).getI();
if (se[0] > pos)
{
se[0] = pos;
}
if (se[1] < pos)
{
se[1] = pos;
}
}
}
return se;
}
return null;
}
/**
* map from a rangeType's internal frame to the referenced object's coordinate
* frame.
*
* @param dseta
* @return int [] { ref(pos)...} for all pos in rangeType's frame.
*/
private int[] getMapping(RangeType dseta)
{
Vector posList = new Vector();
if (dseta != null)
{
int[] se = null;
if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
{
throw new Error(
"Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
}
if (dseta.getSegCount() > 0)
{
for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)
{
se = getSegRange(dseta.getSeg(s), false);
int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
{
posList.add(new Integer(p));
}
}
}
else if (dseta.getPosCount() > 0)
{
int pos = dseta.getPos(0).getI();
for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
{
pos = dseta.getPos(p).getI();
posList.add(new Integer(pos));
}
}
}
if (posList != null && posList.size() > 0)
{
int[] range = new int[posList.size()];
for (int i = 0; i < range.length; i++)
{
range[i] = ((Integer) posList.elementAt(i)).intValue();
}
posList.clear();
return range;
}
return null;
}
/**
*
* @param maprange
* where the from range is the local mapped range, and the to range
* is the 'mapped' range in the MapRangeType
* @param default unit for local
* @param default unit for mapped
* @return MapList
*/
private jalview.util.MapList parsemapType(MapType maprange, int localu,
int mappedu)
{
jalview.util.MapList ml = null;
int[] localRange = getMapping(maprange.getLocal());
int[] mappedRange = getMapping(maprange.getMapped());
long lu = maprange.getLocal().hasUnit() ? maprange.getLocal().getUnit()
: localu;
long mu = maprange.getMapped().hasUnit() ? maprange.getMapped()
.getUnit() : mappedu;
ml = new jalview.util.MapList(localRange, mappedRange, (int) lu,
(int) mu);
return ml;
}
/**
* initialise a range type object from a set of start/end inclusive intervals
*
* @param mrt
* @param range
*/
private void initRangeType(RangeType mrt, int[] range)
{
for (int i = 0; i < range.length; i += 2)
{
Seg vSeg = new Seg();
vSeg.setStart(range[i]);
vSeg.setEnd(range[i + 1]);
mrt.addSeg(vSeg);
}
}
/**
* initialise a MapType object from a MapList object.
*
* @param maprange
* @param ml
* @param setUnits
*/
private void initMapType(MapType maprange, jalview.util.MapList ml,
boolean setUnits)
{
maprange.setLocal(new Local());
maprange.setMapped(new Mapped());
initRangeType(maprange.getLocal(), ml.getFromRanges());
initRangeType(maprange.getMapped(), ml.getToRanges());
if (setUnits)
{
maprange.getLocal().setUnit(ml.getFromRatio());
maprange.getLocal().setUnit(ml.getToRatio());
}
}
/*
* not needed now. Provenance getVamsasProvenance(jalview.datamodel.Provenance
* jprov) { jalview.datamodel.ProvenanceEntry[] entries = null; // TODO: fix
* App and Action here. Provenance prov = new Provenance();
* org.exolab.castor.types.Date date = new org.exolab.castor.types.Date( new
* java.util.Date()); Entry provEntry;
*
* if (jprov != null) { entries = jprov.getEntries(); for (int i = 0; i <
* entries.length; i++) { provEntry = new Entry(); try { date = new
* org.exolab.castor.types.Date(entries[i].getDate()); } catch (Exception ex)
* { ex.printStackTrace();
*
* date = new org.exolab.castor.types.Date(entries[i].getDate()); }
* provEntry.setDate(date); provEntry.setUser(entries[i].getUser());
* provEntry.setAction(entries[i].getAction()); prov.addEntry(provEntry); } }
* else { provEntry = new Entry(); provEntry.setDate(date);
* provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
* provEntry.setApp("JVAPP"); // TODO: ext string provEntry.setAction(action);
* prov.addEntry(provEntry); }
*
* return prov; }
*/
jalview.datamodel.Provenance getJalviewProvenance(Provenance prov)
{
// TODO: fix App and Action entries and check use of provenance in jalview.
jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();
for (int i = 0; i < prov.getEntryCount(); i++)
{
jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i)
.getAction(), prov.getEntry(i).getDate(), prov.getEntry(i)
.getId());
}
return jprov;
}
/**
*
* @return default initial provenance list for a Jalview created vamsas
* object.
*/
Provenance dummyProvenance()
{
return dummyProvenance(null);
}
Entry dummyPEntry(String action)
{
Entry entry = new Entry();
entry.setApp(this.provEntry.getApp());
if (action != null)
{
entry.setAction(action);
}
else
{
entry.setAction("created.");
}
entry.setDate(new java.util.Date());
entry.setUser(this.provEntry.getUser());
return entry;
}
Provenance dummyProvenance(String action)
{
Provenance prov = new Provenance();
prov.addEntry(dummyPEntry(action));
return prov;
}
Entry addProvenance(Provenance p, String action)
{
Entry dentry = dummyPEntry(action);
p.addEntry(dentry);
return dentry;
}
public Entry getProvEntry()
{
return provEntry;
}
public IClientDocument getClientDocument()
{
return cdoc;
}
public IdentityHashMap getJvObjectBinding()
{
return jv2vobj;
}
public Hashtable getVamsasObjectBinding()
{
return vobj2jv;
}
public void storeSequenceMappings(AlignViewport viewport, String title)
throws Exception
{
AlignViewport av = viewport;
try
{
jalview.datamodel.AlignmentI jal = av.getAlignment();
// /////////////////////////////////////////
// SAVE THE DATASET
DataSet dataset = null;
if (jal.getDataset() == null)
{
Cache.log.warn("Creating new dataset for an alignment.");
jal.setDataset(null);
}
dataset = (DataSet) ((Alignment) getjv2vObj(viewport
.getSequenceSetId())).getV_parent(); // jal.getDataset());
if (dataset == null)
{
dataset = (DataSet) getjv2vObj(jal.getDataset());
Cache.log
.error("Can't find the correct dataset for the alignment in this view. Creating new one.");
}
// Store any sequence mappings.
if (av.getAlignment().getCodonFrames() != null
&& av.getAlignment().getCodonFrames().length > 0)
{
jalview.datamodel.AlignedCodonFrame[] cframes = av.getAlignment()
.getCodonFrames();
for (int cf = 0; cf < cframes.length; cf++)
{
if (cframes[cf].getdnaSeqs() != null
&& cframes[cf].getdnaSeqs().length > 0)
{
jalview.datamodel.SequenceI[] dmps = cframes[cf].getdnaSeqs();
jalview.datamodel.Mapping[] mps = cframes[cf].getProtMappings();
for (int smp = 0; smp < mps.length; smp++)
{
uk.ac.vamsas.objects.core.SequenceType mfrom = (SequenceType) getjv2vObj(dmps[smp]);
if (mfrom != null)
{
new jalview.io.vamsas.Sequencemapping(this, mps[smp],
mfrom, dataset);
}
else
{
Cache.log
.warn("NO Vamsas Binding for local sequence! NOT CREATING MAPPING FOR "
+ dmps[smp].getDisplayId(true)
+ " to "
+ mps[smp].getTo().getName());
}
}
}
}
}
} catch (Exception e)
{
throw new Exception("Couldn't store sequence mappings for " + title,
e);
}
}
public void clearSkipList()
{
if (skipList != null)
{
skipList.clear();
}
}
/**
* @return the skipList
*/
public Hashtable getSkipList()
{
return skipList;
}
/**
* @param skipList
* the skipList to set
*/
public void setSkipList(Hashtable skipList)
{
this.skipList = skipList;
}
/**
* registry for datastoreItems
*/
DatastoreRegistry dsReg = new DatastoreRegistry();
public DatastoreRegistry getDatastoreRegisty()
{
if (dsReg == null)
{
dsReg = new DatastoreRegistry();
}
return dsReg;
}
}