From 7f580e031f3eba299dc218804824b65dbe1979d0 Mon Sep 17 00:00:00 2001 From: jprocter Date: Tue, 25 Sep 2007 09:30:29 +0000 Subject: [PATCH] added store of undo/redo hash for each alignment so local state changes can be detected. Dataset and alignment sequences are now synchronised with document on updates and commits. --- src/jalview/gui/VamsasApplication.java | 7 +- src/jalview/io/VamsasAppDatastore.java | 306 ++++++++++++++++++++++++-------- 2 files changed, 235 insertions(+), 78 deletions(-) diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index 65212a6..50670a0 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -283,7 +283,7 @@ public class VamsasApplication Cache.log.debug("Jalview updating from sesion document .."); ensureJvVamsas(); VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj, - baseProvEntry()); + baseProvEntry(), alRedoState); vds.updateToJalview(); Cache.log.debug(".. finished updating from sesion document."); @@ -295,6 +295,7 @@ public class VamsasApplication { jv2vobj = new IdentityHashMap(); vobj2jv = new Hashtable(); + alRedoState = new Hashtable(); } } @@ -304,12 +305,12 @@ public class VamsasApplication IdentityHashMap jv2vobj = null; Hashtable vobj2jv = null; - + Hashtable alRedoState = null; public void updateVamsasDocument(IClientDocument doc) { ensureJvVamsas(); VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj, - baseProvEntry()); + baseProvEntry(), alRedoState); // wander through frames JInternalFrame[] frames = Desktop.desktop.getAllFrames(); diff --git a/src/jalview/io/VamsasAppDatastore.java b/src/jalview/io/VamsasAppDatastore.java index aaaf589..7e0513d 100644 --- a/src/jalview/io/VamsasAppDatastore.java +++ b/src/jalview/io/VamsasAppDatastore.java @@ -79,13 +79,16 @@ public class VamsasAppDatastore IdentityHashMap jv2vobj; + Hashtable alignRDHash; + public VamsasAppDatastore(IClientDocument cdoc, Hashtable vobj2jv, - IdentityHashMap jv2vobj, Entry provEntry) + IdentityHashMap jv2vobj, Entry provEntry, Hashtable alignRDHash) { this.cdoc = cdoc; this.vobj2jv = vobj2jv; this.jv2vobj = jv2vobj; this.provEntry = provEntry; + this.alignRDHash = alignRDHash; } /** @@ -235,7 +238,7 @@ public class VamsasAppDatastore root.addDataSet(dataset); bindjvvobj(jal.getDataset(), dataset); dataset.setProvenance(dummyProvenance()); - dataset.getProvenance().addEntry(provEntry); + // dataset.getProvenance().addEntry(provEntry); nw = true; } else @@ -251,6 +254,7 @@ public class VamsasAppDatastore // 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 @@ -265,25 +269,56 @@ public class VamsasAppDatastore sq.setVamsasId(sequence.getVorbaId().getId()); sequence.setSequence(sq.getSequenceAsString()); sequence.setDictionary(dict); - sequence.setName(jal.getDataset().getSequenceAt(i).getName()); - sequence.setStart(jal.getDataset().getSequenceAt(i).getStart()); - sequence.setEnd(jal.getDataset().getSequenceAt(i).getEnd()); - sequence.setDescription(jal.getDataset().getSequenceAt(i) - .getDescription()); + sequence.setName(sq.getName()); + sequence.setStart(sq.getStart()); + sequence.setEnd(sq.getEnd()); + sequence.setDescription(sq.getDescription()); dataset.addSequence(sequence); + dssmods.addElement(dssmods); } else { - // verify principal attributes. and update any new - // features/references. - System.out.println("update dataset sequence object."); + boolean dsmod = false; + // verify and update principal attributes. + if (sq.getDescription()!=null && (sequence.getDescription()==null || !sequence.getDescription().equals(sq.getDescription()))) + { + sequence.setDescription(sq.getDescription()); + dsmod = true; + } + if (sequence.getSequence()==null || !sequence.getSequence().equals(sq.getSequenceAsString())) + { + if (sequence.getStart()!=sq.getStart() || sequence.getEnd()!=sq.getEnd()) + { + // update modified sequence. + sequence.setSequence(sq.getSequenceAsString()); + sequence.setStart(sq.getStart()); + sequence.setEnd(sq.getEnd()); + dsmod = true; + } + } + if (!dict.equals(sequence.getDictionary())) + { + sequence.setDictionary(dict); + dsmod = true; + } + if (!sequence.getName().equals(sq.getName())) + { + sequence.setName(sq.getName()); + dsmod = true; + } + if (dsmod) + { + dssmods.addElement(sequence); + } } + // add or update any new features/references on dataset sequence if (sq.getSequenceFeatures() != null) { int sfSize = sq.getSequenceFeatures().length; for (int sf = 0; sf < sfSize; sf++) { + // TODO: update/modifiable synchronizer jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) sq .getSequenceFeatures()[sf]; @@ -323,11 +358,19 @@ public class VamsasAppDatastore } } + 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 (!av.getAlignment().isAligned()) return; // TODO: trees could be written - but for the moment we just skip - // //////////////////////////////////////////// // Save the Alignments @@ -354,33 +397,36 @@ public class VamsasAppDatastore alignment.addProperty(title); } alignment.setGapChar(String.valueOf(av.getGapCharacter())); - AlignmentSequence alseq = null; for (int i = 0; i < jal.getHeight(); i++) { - alseq = new AlignmentSequence(); - // TODO: VAMSAS: translate lowercase symbols to annotation ? - alseq.setSequence(jal.getSequenceAt(i).getSequenceAsString()); - alseq.setName(jal.getSequenceAt(i).getName()); - alseq.setStart(jal.getSequenceAt(i).getStart()); - alseq.setEnd(jal.getSequenceAt(i).getEnd()); - if (getjv2vObj(jal.getSequenceAt(i).getDatasetSequence()) == null) - { - Cache.log - .warn("Serious. Unbound dataset sequence in alignment: " - + jal.getSequenceAt(i).getDatasetSequence()); - } - alseq.setRefid(getjv2vObj(jal.getSequenceAt(i) - .getDatasetSequence())); - alignment.addAlignmentSequence(alseq); - bindjvvobj(jal.getSequenceAt(i), alseq); + syncToAlignmentSequence(jal.getSequenceAt(i), alignment); } + alignRDHash.put(av.getSequenceSetId(),av.getUndoRedoHash()); } else { + boolean alismod = av.isUndoRedoHashModified((long[]) alignRDHash.get(av.getSequenceSetId())); // todo: verify and update mutable alignment props. - if (alignment.getModifiable() == null) // TODO: USE VAMSAS LIBRARY - // OBJECT LOCK METHODS + // TODO: Use isLocked methods + if (alignment.getModifiable() == null || alignment.getModifiable().length()==0) { + boolean modified = false; + for (int i = 0; i < jal.getHeight(); i++) + { + modified |= syncToAlignmentSequence(jal.getSequenceAt(i), alignment); + } + 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 + } + } System.out.println("update alignment in document."); } else @@ -617,6 +663,147 @@ public class VamsasAppDatastore } } + /** + * 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. + */ + private boolean syncToAlignmentSequence(SequenceI jvalsq, + Alignment alignment) + { + boolean modal = false; + // todo: islocked method here + boolean up2doc=false; + AlignmentSequence alseq = (AlignmentSequence) getjv2vObj(jvalsq); + if (alseq==null) + { + alseq = new AlignmentSequence(); + up2doc = true; + } + // 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 + // 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) @@ -1116,6 +1303,7 @@ public class VamsasAppDatastore } iSize = alignment.getAlignmentSequenceCount(); boolean newal = (jal == null) ? true : false; + boolean refreshal = false; Vector newasAnnots = new Vector(); char gapChar = ' '; // default for new alignments read in from the // document @@ -1132,51 +1320,13 @@ public class VamsasAppDatastore for (i = 0; i < iSize; i++) { AlignmentSequence valseq = alignment.getAlignmentSequence(i); - jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq); - if (alseq != null) + jalview.datamodel.Sequence alseq = (jalview.datamodel.Sequence) getvObj2jv(valseq); + if (syncFromAlignmentSequence(valseq, valGapchar, gapChar, dsseqs) && alseq!=null) { - // TODO: upperCase/LowerCase situation here ? do we allow it ? - // if (!alseq.getSequence().equals(valseq.getSequence())) { - // throw new Error("Broken! - mismatch of dataset sequence and - // jalview internal dataset sequence."); - if (Cache.log.isDebugEnabled()) - { - Cache.log.debug("Updating apparently edited sequence " - + alseq.getName()); - } - // this might go *horribly* wrong - alseq.setSequence(new String(valseq.getSequence()).replace( - valGapchar, gapChar)); + + // updated to sequence from the document jremain--; - } - 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 - // 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); + refreshal = true; } if (valseq.getAlignmentSequenceAnnotationCount() > 0) { @@ -1344,6 +1494,10 @@ public class VamsasAppDatastore // TODO: fix this so we retrieve the alignFrame handing av // *directly* alignFrame = getAlignFrameFor(av); + if (refreshal) + { + av.alignmentChanged(alignFrame.alignPanel); + } } // LOAD TREES // ///////////////////////////////////// @@ -2116,9 +2270,11 @@ public class VamsasAppDatastore return prov; } - void addProvenance(Provenance p, String action) + Entry addProvenance(Provenance p, String action) { - p.addEntry(dummyPEntry(action)); + Entry dentry = dummyPEntry(action); + p.addEntry(dentry); + return dentry; } public Entry getProvEntry() -- 1.7.10.2