package jalview.gui;
import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.io.VamsasAppDatastore;
+import jalview.structure.SelectionListener;
+import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasListener;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
+import java.util.Enumeration;
import java.util.Hashtable;
import java.util.IdentityHashMap;
+import java.util.Iterator;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import uk.ac.vamsas.client.picking.IPickManager;
import uk.ac.vamsas.client.picking.Message;
import uk.ac.vamsas.client.picking.MouseOverMessage;
+import uk.ac.vamsas.client.picking.SelectionMessage;
import uk.ac.vamsas.objects.core.Entry;
+import uk.ac.vamsas.objects.core.Input;
+import uk.ac.vamsas.objects.core.Pos;
+import uk.ac.vamsas.objects.core.Seg;
/**
* @author jimp
*
*/
-public class VamsasApplication
+public class VamsasApplication implements SelectionSource
{
IClient vclient = null;
ensureJvVamsas();
VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
baseProvEntry(), alRedoState);
- vds.updateToJalview();
+ try
+ {
+ vds.updateToJalview();
+ } catch (Exception e)
+ {
+ Cache.log.error("Failed to update Jalview from vamsas document.", e);
+ }
+ try
+ {
+ if (firstUpdate)
+ {
+ vds.updateJalviewFromAppdata();
+ // Comment this out to repeatedly read in data from JalviewAppData
+ // firstUpdate=false;
+ }
+ } catch (Exception e)
+ {
+ Cache.log.error(
+ "Exception when updating Jalview settings from Appdata.", e);
+ }
Cache.log.debug(".. finished updating from sesion document.");
}
+ boolean firstUpdate = false;
+
private void ensureJvVamsas()
{
if (jv2vobj == null)
jv2vobj = new IdentityHashMap();
vobj2jv = new Hashtable();
alRedoState = new Hashtable();
+ firstUpdate = true;
}
}
Hashtable alRedoState = null;
+ boolean errorsDuringUpdate = false;
+
+ boolean errorsDuringAppUpdate = false;
+
+ /**
+ * update the document accessed through doc. A backup of the current object
+ * bindings is made.
+ *
+ * @param doc
+ */
public void updateVamsasDocument(IClientDocument doc)
{
ensureJvVamsas();
+ errorsDuringUpdate = false;
+ errorsDuringAppUpdate = false;
+ backup_objectMapping();
VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj,
baseProvEntry(), alRedoState);
// wander through frames
{
return;
}
+ Hashtable skipList = new Hashtable();
+ Hashtable viewset = new Hashtable();
try
{
if (frames[i] instanceof AlignFrame)
{
AlignFrame af = (AlignFrame) frames[i];
-
- // update alignment and root from frame.
- vds.storeVAMSAS(af.getViewport(), af.getTitle());
+ if (!viewset.containsKey(af.getViewport().getSequenceSetId()))
+ {
+ // update alignment and root from frame.
+ boolean stored = false;
+ try
+ {
+ stored = vds.storeVAMSAS(af.getViewport(), af.getTitle());
+ } catch (Exception e)
+ {
+ errorsDuringUpdate = true;
+ Cache.log.error("Exception synchronizing "
+ + af.getTitle()
+ + " "
+ + (af.getViewport().viewName == null ? "" : " view "
+ + af.getViewport().viewName)
+ + " to document.", e);
+ stored = false;
+ }
+ if (!stored)
+ { // record skip in skipList
+ skipList.put(af.getViewport().getSequenceSetId(), af);
+ }
+ else
+ {
+ // could try to eliminate sequenceSetId from skiplist ..
+ // (skipList.containsKey(af.getViewport().getSequenceSetId()))
+ // remember sequenceSetId so we can skip all the other views on
+ // same alignment
+ viewset.put(af.getViewport().getSequenceSetId(), af);
+ }
+ }
}
}
// REVERSE ORDER
- for (int i = frames.length - 1; i > -1; i--)
+ // for (int i = frames.length - 1; i > -1; i--)
+ // {
+ // if (frames[i] instanceof AlignFrame)
+ // {
+ // AlignFrame af = (AlignFrame) frames[i];
+ Iterator aframes = viewset.values().iterator();
+ while (aframes.hasNext())
{
- if (frames[i] instanceof AlignFrame)
- {
- AlignFrame af = (AlignFrame) frames[i];
+ AlignFrame af = (AlignFrame) aframes.next();
+ // add any AlignedCodonFrame mappings on this alignment to any other.
+ vds.storeSequenceMappings(af.getViewport(), af.getTitle());
+ }
+ } catch (Exception e)
+ {
+ Cache.log.error("Exception synchronizing Views to Document :", e);
+ errorsDuringUpdate = true;
+ }
- // add any AlignedCodonFrame mappings on this alignment to any other.
- vds.storeSequenceMappings(af.getViewport(), af.getTitle());
- }
+ try
+ {
+ if (viewset.size() > 0)
+ {
+ // Alignment views were synchronized, so store their state in the
+ // appData, too.
+ // The skipList ensures we don't write out any alignments not actually
+ // in the document.
+ vds.setSkipList(skipList);
+ vds.updateJalviewClientAppdata();
}
} catch (Exception e)
{
- Cache.log.error("Vamsas Document store exception", e);
+ Cache.log.error("Client Appdata Write exception", e);
+ errorsDuringAppUpdate = true;
}
+ vds.clearSkipList();
}
private Entry baseProvEntry()
{
System.err.println("Exception whilst updating :");
ee.printStackTrace(System.err);
+ // recover object map backup, since its probably corrupted with references
+ // to Vobjects that don't exist anymore.
+ this.recover_objectMappingBackup();
}
Cache.log.debug("Finished updating from document change.");
disableGui(false);
Desktop.instance.setVamsasUpdate(b);
}
+ Hashtable _backup_vobj2jv;
+
+ IdentityHashMap _backup_jv2vobj;
+
+ /**
+ * make a backup of the object mappings (vobj2jv and jv2vobj)
+ */
+ public void backup_objectMapping()
+ {
+ _backup_vobj2jv = new Hashtable(vobj2jv);
+ _backup_jv2vobj = new IdentityHashMap(jv2vobj);
+ }
+
+ /**
+ * recover original object mappings from the object mapping backup if document
+ * IO failed
+ *
+ * @throws Error
+ * if backup_objectMapping was not called.
+ */
+ public void recover_objectMappingBackup()
+ {
+ if (_backup_vobj2jv == null)
+ {
+ throw new Error(
+ "IMPLEMENTATION ERROR: Cannot recover vamsas object mappings - no backup was made.");
+ }
+ jv2vobj.clear();
+ Iterator el = _backup_jv2vobj.entrySet().iterator();
+ while (el.hasNext())
+ {
+ java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
+ jv2vobj.put(mp.getKey(), mp.getValue());
+ }
+ el = _backup_vobj2jv.entrySet().iterator();
+ while (el.hasNext())
+ {
+ java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
+ vobj2jv.put(mp.getKey(), mp.getValue());
+ }
+ }
+
private boolean joinedSession = false;
private VamsasListener picker = null;
+ private SelectionListener selecter;
+
private void startSession()
{
if (inSession())
final IPickManager pm = vclient.getPickManager();
final StructureSelectionManager ssm = StructureSelectionManager
.getStructureSelectionManager();
+ final SelectionSource me = this;
pm.registerMessageHandler(new IMessageHandler()
{
String last = null;
public void handleMessage(Message message)
{
- if (message instanceof MouseOverMessage && vobj2jv != null)
+ if (vobj2jv == null)
+ {
+ // we are not in a session yet.
+ return;
+ }
+ if (message instanceof MouseOverMessage)
{
MouseOverMessage mm = (MouseOverMessage) message;
String mstring = mm.getVorbaID() + " " + mm.getPosition();
.getPosition());
}
}
+ if (message instanceof uk.ac.vamsas.client.picking.SelectionMessage)
+ {
+ // we only care about AlignmentSequence selections
+ SelectionMessage sm = (SelectionMessage) message;
+ sm.validate();
+ System.err.println("Received\n"+sm.getRawMessage());
+ Object[] jvobjs = sm.getVorbaIDs()==null ? null : new Object[sm.getVorbaIDs().length];
+ if (jvobjs==null)
+ {
+ // TODO: rationalise : can only clear a selection over a referred to object
+ ssm.sendSelection(null,null,me);
+ return;
+ }
+ Class type = null;
+ boolean send = true;
+ for (int o = 0; o < jvobjs.length; o++)
+ {
+ jvobjs[o] = vobj2jv.get(sm.getVorbaIDs()[o]);
+ if (jvobjs[o] == null)
+ {
+ // can't cope with selections for unmapped objects
+ continue;
+ }
+ if (type == null)
+ {
+ type = jvobjs[o].getClass();
+ }
+ ;
+ if (type != jvobjs[o].getClass())
+ {
+ send=false;
+ // discard - can't cope with selections over mixed objects
+ continue;
+ }
+ }
+ SequenceGroup jselection = null;
+ ColumnSelection colsel = null;
+ if (type == jalview.datamodel.Alignment.class)
+ {
+ if (jvobjs.length == 1)
+ {
+ // TODO if (sm.isNone())// send a message to select the specified columns over the
+ // given
+ // alignment
+
+ send = true;
+ }
+ }
+ if (type == jalview.datamodel.Sequence.class)
+ {
+
+ SequenceI seq;
+ boolean aligned = ((jalview.datamodel.Sequence) jvobjs[0])
+ .getDatasetSequence() != null;
+ int maxWidth=0;
+ if (aligned)
+ {
+ jselection = new SequenceGroup();
+ jselection.addSequence(seq =
+ (jalview.datamodel.Sequence) jvobjs[0], false);
+ maxWidth = seq.getLength();
+ }
+ for (int c = 1; aligned && jvobjs.length > 1 && c < jvobjs.length; c++)
+ {
+ if (((jalview.datamodel.Sequence) jvobjs[c])
+ .getDatasetSequence() == null)
+ {
+ aligned = false;
+ continue;
+ }
+ else
+ {
+ jselection.addSequence(
+ seq = (jalview.datamodel.Sequence) jvobjs[c], false);
+ if (maxWidth<seq.getLength())
+ {
+ maxWidth = seq.getLength();
+ }
+
+ }
+ }
+ if (!aligned)
+ {
+ jselection = null;
+ // if cardinality is greater than one then verify all
+ // sequences are alignment sequences.
+ if (jvobjs.length == 1)
+ {
+ // find all instances of this dataset sequence in the
+ // displayed alignments containing the associated range and
+ // select them.
+ }
+ }
+ else
+ {
+ jselection.setStartRes(0);
+ jselection.setEndRes(maxWidth);
+ // locate the alignment containing the given sequences and
+ // select the associated ranges on them.
+ if (sm.getRanges() != null)
+ {
+ int[] prange = uk.ac.vamsas.objects.utils.Range.getBounds(sm.getRanges());
+ boolean rangeset=false;
+ colsel = new ColumnSelection();
+ prange = uk.ac.vamsas.objects.utils.Range.getIntervals(sm.getRanges());
+ for (int p=0;p<prange.length;p+=2)
+ {
+ int d = (prange[p]<=prange[p+1]) ? 1 : -1;
+ if (!rangeset)
+ {
+ if (jselection!=null)
+ {
+ // set the bounds of the selected area using the first interval.
+ jselection.setStartRes(prange[p]-1);
+ jselection.setEndRes(prange[p+1]-1);
+ rangeset=true;
+ }
+ } else {
+ // try to join up adjacent columns to make a larger selection
+ // lower and upper bounds
+ int l=(d<0) ? 1 : 0;
+ int u=(d>0) ? 1 : 0;
+
+ if (jselection.getStartRes()>0 && prange[p+l]==jselection.getStartRes())
+ {
+ jselection.setStartRes(prange[p+l]-1);
+ }
+ if (jselection.getEndRes()<=maxWidth && prange[p+u]==(jselection.getEndRes()+2))
+ {
+ jselection.setEndRes(prange[p+u]-1);
+ }
+ }
+ // mark all the columns in the range.
+ for (int sr=prange[p],er=prange[p+1],de=er+d; sr!=de; sr+=d)
+ {
+ colsel.addElement(sr-1);
+ }
+ }
+ }
+ send = true;
+ }
+ }
+ if (send)
+ {
+ ssm.sendSelection(jselection, colsel, me);
+ }
+ // discard message.
+ for (int c = 0; c < jvobjs.length; c++)
+ {
+ jvobjs[c] = null;
+ }
+ ;
+ jvobjs = null;
+ return;
+ }
}
});
picker = new VamsasListener()
}
}
};
+ selecter = new SelectionListener()
+ {
+
+ public void selection(SequenceGroup seqsel,
+ ColumnSelection colsel, SelectionSource source)
+ {
+ if (source != me)
+ {
+ AlignmentI visal=null;
+ if (source instanceof AlignViewport)
+ {
+ visal = ((AlignViewport) source).getAlignment();
+ }
+ SelectionMessage sm = null;
+ if ((seqsel == null || seqsel.getSize() == 0)
+ && (colsel == null || colsel.getSelected() == null || colsel
+ .getSelected().size() == 0))
+ {
+ if (source instanceof AlignViewport)
+ {
+ // the empty selection.
+ sm = new SelectionMessage("jalview", new String[] { ((AlignViewport)source).getSequenceSetId()}, null, true);
+ } else {
+ // the empty selection.
+ sm = new SelectionMessage("jalview", null, null, true);
+ }
+ }
+ else
+ {
+ String[] vobj = new String[seqsel.getSize()];
+ int o = 0;
+ Enumeration sels = seqsel.getSequences(null).elements();
+ while (sels.hasMoreElements())
+ {
+ SequenceI sel = (SequenceI) sels.nextElement();
+ VorbaId v = (VorbaId) jv2vobj.get(sel);
+ if (v != null)
+ {
+ vobj[o++] = v.toString();
+ }
+ }
+ if (o < vobj.length)
+ {
+ String t[] = vobj;
+ vobj = new String[o];
+ System.arraycopy(t, 0, vobj, 0, o);
+ t = null;
+ }
+ Input range = null;
+ if (seqsel!=null && colsel != null)
+ {
+ // deparse the colsel into positions on the vamsas alignment
+ // sequences
+ range = new Input();
+ if (colsel.getSelected()!=null && colsel.getSelected().size()>0 && visal!=null && seqsel.getSize()==visal.getHeight())
+ {
+ // gather selected columns outwith the sequence positions too
+ Enumeration cols = colsel.getSelected().elements();
+ while (cols.hasMoreElements())
+ {
+ int ival = ((Integer) cols.nextElement()).intValue();
+ Pos p = new Pos();
+ p.setI(ival+1);
+ range.addPos(p);
+ }
+ } else {
+ int[] intervals = colsel.getVisibleContigs(seqsel.getStartRes(), seqsel.getEndRes()+1);
+ for (int iv=0;iv<intervals.length; iv+=2)
+ {
+ Seg s = new Seg();
+ s.setStart(intervals[iv]+1); // vamsas indices begin at 1, not zero.
+ s.setEnd(intervals[iv+1]+1);
+ s.setInclusive(true);
+ range.addSeg(s);
+ }
+ }
+ }
+ sm = new SelectionMessage("jalview", vobj, range);
+ }
+ sm.validate(); // debug
+ Cache.log.debug("Pick Message\n"+sm.getRawMessage());
+ pm.sendMessage(sm);
+ }
+ }
+
+ };
ssm.addStructureViewerListener(picker); // better method here
+ ssm.addSelectionListener(selecter);
} catch (Exception e)
{
Cache.log.error("Failed to init Vamsas Picking", e);