From 811fb76382f3601b35dc08b8c0ceabed049c3326 Mon Sep 17 00:00:00 2001 From: jprocter Date: Wed, 12 Jan 2011 17:05:05 +0000 Subject: [PATCH] javascript callback for selection, mousover, and functions for selection and highlighting JAL-469 JAL-433 JAL-744 --- src/jalview/appletgui/APopupMenu.java | 24 ++ src/jalview/appletgui/AlignFrame.java | 110 +++++-- src/jalview/appletgui/AlignViewport.java | 97 +++++- src/jalview/appletgui/AnnotationLabels.java | 52 +++- src/jalview/appletgui/IdPanel.java | 2 + src/jalview/appletgui/PaintRefresher.java | 19 ++ src/jalview/appletgui/RotatableCanvas.java | 4 +- src/jalview/appletgui/ScalePanel.java | 2 + src/jalview/appletgui/SeqPanel.java | 94 +++++- src/jalview/appletgui/TreeCanvas.java | 2 + src/jalview/bin/JalviewLite.java | 444 ++++++++++++++++++++++++++- 11 files changed, 809 insertions(+), 41 deletions(-) diff --git a/src/jalview/appletgui/APopupMenu.java b/src/jalview/appletgui/APopupMenu.java index 5288fe4..a56f76d 100755 --- a/src/jalview/appletgui/APopupMenu.java +++ b/src/jalview/appletgui/APopupMenu.java @@ -112,6 +112,11 @@ public class APopupMenu extends java.awt.PopupMenu implements MenuItem revealAll = new MenuItem(); + MenuItem revealSeq = new MenuItem(); + /** + * index of sequence to be revealed + */ + int revealSeq_index=-1; Menu menu1 = new Menu(); public APopupMenu(AlignmentPanel apanel, final Sequence seq, Vector links) @@ -298,6 +303,17 @@ public class APopupMenu extends java.awt.PopupMenu implements if (!ap.av.hasHiddenRows) { remove(revealAll); + remove(revealSeq); + } else { + final int index = ap.av.alignment.findIndex(seq); + + if (ap.av.adjustForHiddenSeqs(index) + - ap.av.adjustForHiddenSeqs(index - 1) > 1) + { + revealSeq_index=index; + } else { + remove(revealSeq); + } } } @@ -446,6 +462,10 @@ public class APopupMenu extends java.awt.PopupMenu implements { hideSequences(true); } + else if (source == revealSeq) + { + ap.av.showSequence(revealSeq_index); + } else if (source == revealAll) { ap.av.showAllHiddenSeqs(); @@ -712,10 +732,12 @@ public class APopupMenu extends java.awt.PopupMenu implements hideSeqs.setLabel("Hide Sequences"); repGroup.setLabel("Represent Group with"); revealAll.setLabel("Reveal All"); + revealSeq.setLabel("Reveal Sequences"); menu1.setLabel("Group"); add(groupMenu); this.add(seqMenu); this.add(hideSeqs); + this.add(revealSeq); this.add(revealAll); groupMenu.add(editGroupName); groupMenu.add(editMenu); @@ -796,6 +818,7 @@ public class APopupMenu extends java.awt.PopupMenu implements hideSeqs.addActionListener(this); repGroup.addActionListener(this); revealAll.addActionListener(this); + revealSeq.addActionListener(this); } void refresh() @@ -1034,6 +1057,7 @@ public class APopupMenu extends java.awt.PopupMenu implements } ap.av.hideSequence(hseqs); + ap.av.sendSelection(); } } diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index ffe445b..2fde9ad 100755 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -21,12 +21,9 @@ import java.io.*; import java.net.*; import java.util.*; -import java.applet.Applet; import java.awt.*; import java.awt.event.*; -import org.jmol.api.JmolViewer; - import jalview.analysis.*; import jalview.api.SequenceStructureBinding; import jalview.bin.JalviewLite; @@ -796,7 +793,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else if (source == alProperties) { - StringBuffer contents = new jalview.io.AlignmentProperties(viewport.alignment).formatAsString(); + StringBuffer contents = new jalview.io.AlignmentProperties( + viewport.alignment).formatAsString(); CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this); cap.setText(contents.toString()); Frame frame = new Frame(); @@ -1640,6 +1638,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { this.setVisible(false); } + viewport.sendSelection(); } protected void makeGrpsFromSelection_actionPerformed() @@ -1694,6 +1693,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, viewport.setSelectionGroup(sg); alignPanel.paintAlignment(true); PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + viewport.sendSelection(); } public void deselectAllSequenceMenuItem_actionPerformed() @@ -1710,6 +1710,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, alignPanel.seqPanel.seqCanvas.highlightSearchResults(null); alignPanel.paintAlignment(true); PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + viewport.sendSelection(); } public void invertSequenceMenuItem_actionPerformed() @@ -1721,6 +1722,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + viewport.sendSelection(); } public void invertColSel_actionPerformed() @@ -1728,6 +1730,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, viewport.invertColumnSelection(); alignPanel.paintAlignment(true); PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + viewport.sendSelection(); } void trimAlignment(boolean trimLeft) @@ -3164,36 +3167,73 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, * create a new binding between structures in an existing jmol viewer instance * and an alignpanel with sequences that have existing PDBFile entries. Note, * this does not open a new Jmol window, or modify the display of the - * structures in the original jmol window. Note + * structures in the original jmol window. Note This method doesn't work + * without an additional javascript library to exchange messages between the + * distinct applets. See http://issues.jalview.org/browse/JAL-621 * * @param viewer * JmolViewer instance * @param sequenceIds - * - sequence Ids to search for associations This method doesn't - * work. See http://issues.jalview.org/browse/JAL-621 - * - * public SequenceStructureBinding addStructureViewInstance(Object - * jmolviewer, String[] sequenceIds) { org.jmol.api.JmolViewer - * viewer=null; try { viewer = (org.jmol.api.JmolViewer) jmolviewer; - * } catch (ClassCastException ex) { - * System.err.println("Unsupported viewer object :" - * +jmolviewer.getClass()); } if (viewer==null) { - * System.err.println("Can't use this object as a structure viewer:" - * +jmolviewer.getClass()); return null; } SequenceI[] seqs=null; if - * (sequenceIds==null || sequenceIds.length==0) { seqs = - * viewport.getAlignment().getSequencesArray(); } else { Vector - * sqi=new Vector(); AlignmentI al = viewport.getAlignment(); for - * (int sid=0;sid0) { seqs = new SequenceI[sqi.size()]; for (int - * sid=0,sSize=sqi.size();sid 0) + { + seqs = new SequenceI[sqi.size()]; + for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++) + { + seqs[sid] = (SequenceI) sqi.elementAt(sid); + } + } + else + { + return null; + } + } + ExtJmol jmv = null; + // TODO: search for a jmv that involves viewer + if (jmv == null) + { // create a new viewer/jalview binding. + jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][] {seqs}); + } + return jmv; + + } + public boolean addPdbFile(String sequenceId, String pdbEntryString, String pdbFile) { @@ -3344,4 +3384,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, // TODO Auto-generated method stub System.err.println("Aligned Structure View: Not yet implemented."); } + + /** + * modify the current selection, providing the user has not made a selection already. + * @param sel - sequences from this alignment + * @param csel - columns to be selected on the alignment + */ + public void select(SequenceGroup sel, ColumnSelection csel) + { + alignPanel.seqPanel.selection(sel, csel, null); + } } diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index 62c313f..ed61bc5 100755 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -25,8 +25,9 @@ import jalview.analysis.*; import jalview.bin.*; import jalview.datamodel.*; import jalview.schemes.*; +import jalview.structure.SelectionSource; -public class AlignViewport +public class AlignViewport implements SelectionSource { int startRes; @@ -1122,7 +1123,31 @@ public class AlignViewport firePropertyChange("alignment", null, alignment.getSequences()); } } + public void showSequence(int index) + { + Vector tmp = alignment.getHiddenSequences().showSequence(index, + hiddenRepSequences); + if (tmp.size() > 0) + { + if (selectionGroup == null) + { + selectionGroup = new SequenceGroup(); + selectionGroup.setEndRes(alignment.getWidth() - 1); + } + + for (int t = 0; t < tmp.size(); t++) + { + selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false); + } + firePropertyChange("alignment", null, alignment.getSequences()); + sendSelection(); + } + if (alignment.getHiddenSequences().getSize() < 1) + { + hasHiddenRows = false; + } + } public void showColumn(int col) { colSel.revealHiddenColumns(col); @@ -1156,6 +1181,7 @@ public class AlignViewport firePropertyChange("alignment", null, alignment.getSequences()); hasHiddenRows = false; hiddenRepSequences = null; + sendSelection(); } } @@ -1378,6 +1404,20 @@ public class AlignViewport return sequenceSetID; } + /** + * unique viewId for synchronizing state (e.g. with stored Jalview Project) + * + */ + private String viewId = null; + + public String getViewId() + { + if (viewId == null) + { + viewId = this.getSequenceSetId() + "." + this.hashCode() + ""; + } + return viewId; + } public void alignmentChanged(AlignmentPanel ap) { @@ -1483,6 +1523,53 @@ public class AlignViewport return followHighlight; } + public boolean followSelection = true; + + /** + * @return true if view selection should always follow the selections + * broadcast by other selection sources + */ + public boolean getFollowSelection() + { + return followSelection; + } + + private long sgrouphash = -1, colselhash = -1; + + /** + * checks current SelectionGroup against record of last hash value, and + * updates record. + * + * @return true if SelectionGroup changed since last call + */ + boolean isSelectionGroupChanged() + { + int hc = (selectionGroup == null) ? -1 : selectionGroup.hashCode(); + if (hc != sgrouphash) + { + sgrouphash = hc; + return true; + } + return false; + } + + /** + * checks current colsel against record of last hash value, and updates + * record. + * + * @return true if colsel changed since last call + */ + boolean isColSelChanged() + { + int hc = (colSel == null) ? -1 : colSel.hashCode(); + if (hc != colselhash) + { + colselhash = hc; + return true; + } + return false; + } + /** * show non-conserved residues only */ @@ -1612,5 +1699,13 @@ public class AlignViewport } } } + public void sendSelection() + { + jalview.structure.StructureSelectionManager + .getStructureSelectionManager().sendSelection( + new SequenceGroup(getSelectionGroup()), + new ColumnSelection(getColumnSelection()), this); + } + } diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index ebc4ebb..2184851 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -249,9 +249,13 @@ public class AnnotationLabels extends Panel implements ActionListener, public void mousePressed(MouseEvent evt) { selectedRow = getSelectedRow(evt.getY() - scrollOffset); - AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation(); + // DETECT RIGHT MOUSE BUTTON IN AWT + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) + { + + PopupMenu popup = new PopupMenu("Annotations"); MenuItem item = new MenuItem(ADDNEW); @@ -309,7 +313,53 @@ public class AnnotationLabels extends Panel implements ActionListener, } popup.show(this, evt.getX(), evt.getY()); + } else { + // selection action. + if (selectedRow > -1 && selectedRow < aa.length) + { + if (aa[selectedRow].groupRef != null) + { + if (evt.getClickCount() >= 2) + { + // todo: make the ap scroll to the selection - not necessary, first click highlights/scrolls, second selects + ap.seqPanel.ap.idPanel.highlightSearchResults(null); + ap.av.setSelectionGroup(// new SequenceGroup( + aa[selectedRow].groupRef); // ); + ap.av.sendSelection(); + ap.paintAlignment(false); + PaintRefresher.Refresh(ap, ap.av.getSequenceSetId()); + } + else + { + ap.seqPanel.ap.idPanel + .highlightSearchResults(aa[selectedRow].groupRef + .getSequences(null)); + } + return; + } + else if (aa[selectedRow].sequenceRef != null) + { + Vector sr = new Vector(); + sr.addElement(aa[selectedRow].sequenceRef); + if (evt.getClickCount() == 1) + { + ap.seqPanel.ap.idPanel.highlightSearchResults(sr); + } + else if (evt.getClickCount() >= 2) + { + ap.seqPanel.ap.idPanel.highlightSearchResults(null); + SequenceGroup sg = new SequenceGroup(); + sg.addSequence(aa[selectedRow].sequenceRef, false); + ap.av.setSelectionGroup(sg); + ap.paintAlignment(false); + PaintRefresher.Refresh(ap, ap.av.getSequenceSetId()); + ap.av.sendSelection(); + } + + } + } + } } /** diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index a7a20ed..43da907 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -386,6 +386,8 @@ public class IdPanel extends Panel implements MouseListener, mouseDragging = false; PaintRefresher.Refresh(this, av.getSequenceSetId()); + // always send selection message when mouse is released + av.sendSelection(); } public void highlightSearchResults(java.util.Vector found) diff --git a/src/jalview/appletgui/PaintRefresher.java b/src/jalview/appletgui/PaintRefresher.java index ab3325b..f08bd66 100755 --- a/src/jalview/appletgui/PaintRefresher.java +++ b/src/jalview/appletgui/PaintRefresher.java @@ -225,4 +225,23 @@ public class PaintRefresher } } } + + public static AlignmentPanel[] getAssociatedPanels(String id) + { + Vector comps = (Vector) components.get(id); + Vector tmp = new Vector(); + int i, iSize = comps.size(); + for (i = 0; i < iSize; i++) + { + if (comps.elementAt(i) instanceof AlignmentPanel) + { + tmp.addElement(((AlignmentPanel) comps.elementAt(i))); + } + } + AlignmentPanel[] result = new AlignmentPanel[tmp.size()]; + tmp.toArray(result); + + return result; + } + } diff --git a/src/jalview/appletgui/RotatableCanvas.java b/src/jalview/appletgui/RotatableCanvas.java index 4872aad..34db801 100755 --- a/src/jalview/appletgui/RotatableCanvas.java +++ b/src/jalview/appletgui/RotatableCanvas.java @@ -514,11 +514,11 @@ public class RotatableCanvas extends Panel implements MouseListener, if (found != null) { + // TODO: applet PCA is not associatable with multi-panels - only parent view if (av.getSelectionGroup() != null) { av.getSelectionGroup().addOrRemove(found, true); av.getSelectionGroup().setEndRes(av.alignment.getWidth() - 1); - PaintRefresher.Refresh(this, av.getSequenceSetId()); } else { @@ -527,6 +527,8 @@ public class RotatableCanvas extends Panel implements MouseListener, av.getSelectionGroup().setEndRes(av.alignment.getWidth() - 1); } + PaintRefresher.Refresh(this, av.getSequenceSetId()); + av.sendSelection(); } repaint(); } diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index 0971882..28139fb 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -173,6 +173,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, } ap.paintAlignment(true); + av.sendSelection(); } public void mouseReleased(MouseEvent evt) @@ -211,6 +212,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, stretchingGroup = false; ap.paintAlignment(false); + av.sendSelection(); } public void mouseDragged(MouseEvent evt) diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index 24f4786..98dcc07 100755 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -25,6 +25,7 @@ import java.awt.event.*; import jalview.commands.*; import jalview.datamodel.*; import jalview.schemes.*; +import jalview.structure.SelectionSource; import jalview.structure.SequenceListener; import jalview.structure.StructureSelectionManager; @@ -302,8 +303,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, sg.addSequence(sequence, false); av.setSelectionGroup(sg); } - ap.paintAlignment(false); + av.sendSelection(); } void insertGapAtCursor(boolean group) @@ -1448,6 +1449,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, stretchGroup = null; PaintRefresher.Refresh(ap, av.getSequenceSetId()); ap.paintAlignment(true); + av.sendSelection(); } public void doMouseDraggedDefineMode(MouseEvent evt) @@ -1681,5 +1683,95 @@ public class SeqPanel extends Panel implements MouseMotionListener, } } } + /** + * modify current selection according to a received message. + */ + public void selection(SequenceGroup seqsel, ColumnSelection colsel, + SelectionSource source) + { + // TODO: fix this hack - source of messages is align viewport, but SeqPanel + // handles selection messages... + // TODO: extend config options to allow user to control if selections may be + // shared between viewports. + if (av!=null && (av == source + || !av.followSelection + || (source instanceof AlignViewport && ((AlignViewport) source) + .getSequenceSetId().equals(av.getSequenceSetId())))) + { + return; + } + // do we want to thread this ? (contention with seqsel and colsel locks, I + // suspect) + // rules are: colsel is copied if there is a real intersection between + // sequence selection + boolean repaint = false, copycolsel = true; + if (av.selectionGroup == null || !av.isSelectionGroupChanged()) + { + SequenceGroup sgroup = null; + if (seqsel != null) + { + if (av.alignment == null) + { + System.out.println("Selection message: alignviewport av SeqSetId=" + + av.getSequenceSetId() + " ViewId=" + av.getViewId() + + " 's alignment is NULL! returning immediatly."); + return; + } + sgroup = seqsel.intersect(av.alignment, + (av.hasHiddenRows) ? av.hiddenRepSequences : null); + if ((sgroup == null || sgroup.getSize() == 0) + && (colsel == null || colsel.size() == 0)) + { + // don't copy columns if the region didn't intersect. + copycolsel = false; + } + } + if (sgroup != null && sgroup.getSize() > 0) + { + av.setSelectionGroup(sgroup); + } + else + { + av.setSelectionGroup(null); + } + repaint = av.isSelectionGroupChanged(); + } + if (copycolsel && (av.colSel == null || !av.isColSelChanged())) + { + // the current selection is unset or from a previous message + // so import the new colsel. + if (colsel == null || colsel.size() == 0) + { + if (av.colSel != null) + { + av.colSel.clear(); + } + } + else + { + // TODO: shift colSel according to the intersecting sequences + if (av.colSel == null) + { + av.colSel = new ColumnSelection(colsel); + } + else + { + av.colSel.setElementsFrom(colsel); + } + } + repaint |= av.isColSelChanged(); + } + if (copycolsel && av.hasHiddenColumns + && (av.colSel == null || av.colSel.getHiddenColumns() == null)) + { + System.err.println("Bad things"); + } + if (repaint) + { + // probably finessing with multiple redraws here + PaintRefresher.Refresh(this, av.getSequenceSetId()); + // ap.paintAlignment(false); + } + } } diff --git a/src/jalview/appletgui/TreeCanvas.java b/src/jalview/appletgui/TreeCanvas.java index d40ab73..4a38767 100755 --- a/src/jalview/appletgui/TreeCanvas.java +++ b/src/jalview/appletgui/TreeCanvas.java @@ -508,6 +508,7 @@ public class TreeCanvas extends Panel implements MouseListener, PaintRefresher.Refresh(this, av.getSequenceSetId()); repaint(); + av.sendSelection(); } } @@ -550,6 +551,7 @@ public class TreeCanvas extends Panel implements MouseListener, treeSelectionChanged((Sequence) ob); PaintRefresher.Refresh(this, av.getSequenceSetId()); repaint(); + av.sendSelection(); return; } else if (!(ob instanceof SequenceNode)) diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index 6a29ecd..5c5e3df 100755 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -17,20 +17,24 @@ */ package jalview.bin; -import jalview.api.SequenceStructureBinding; import jalview.appletgui.AlignFrame; -import jalview.appletgui.AppletJmol; import jalview.appletgui.EmbmenuFrame; import jalview.appletgui.FeatureSettings; import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.AnnotationFile; import jalview.io.AppletFormatAdapter; import jalview.io.FileParse; import jalview.io.IdentifyFile; import jalview.io.JnetAnnotationMaker; +import jalview.javascript.JsCallBack; +import jalview.structure.SelectionListener; +import jalview.structure.StructureSelectionManager; import java.applet.Applet; import java.awt.Button; @@ -44,8 +48,6 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.InputStreamReader; -import java.lang.reflect.Method; -import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; @@ -125,6 +127,259 @@ public class JalviewLite extends Applet } /** + * + * @param sequenceId id of sequence to highlight + * @param position integer position [ tobe implemented or range ] on sequence + * @param alignedPosition true/false/empty string - indicate if position is an alignment column or unaligned sequence position + */ + public void highlight(String sequenceId, String position, String alignedPosition) + { + highlight(currentAlignFrame, sequenceId, position, alignedPosition); + } + /** + * + * @param sequenceId id of sequence to highlight + * @param position integer position [ tobe implemented or range ] on sequence + * @param alignedPosition false, blank or something else - indicate if position is an alignment column or unaligned sequence position + */ + public void highlight(AlignFrame alf, String sequenceId, String position, String alignedPosition) + { + SequenceI sq = alf.getAlignViewport().getAlignment().findName(sequenceId); + if (sq!=null) + { + int pos, apos=-1; + try { + apos = new Integer(position).intValue(); + apos--; + } catch (NumberFormatException ex) + { + return; + } + // use vamsas listener to broadcast to all listeners in scope + if (alignedPosition!=null && (alignedPosition.trim().length()==0 || alignedPosition.toLowerCase().indexOf("false")>-1)) + { + StructureSelectionManager.getStructureSelectionManager().mouseOverVamsasSequence(sq,sq.findIndex(apos)); + } else { + StructureSelectionManager.getStructureSelectionManager().mouseOverVamsasSequence(sq,apos); + } + + } + } + /** + * select regions of the currrent alignment frame + * + * @param sequenceIds String separated list of sequence ids or empty string + * @param columns + * String separated list { column range or column, ..} or empty string + */ + public void select(String sequenceIds, String columns) + { + select(currentAlignFrame, sequenceIds, columns, "¬"); + } + + /** + * select regions of the currrent alignment frame + * + * @param toselect + * String separated list { column range, seq1...seqn sequence ids } + * @param sep + * separator between toselect fields + */ + public void select(String sequenceIds, String columns, String sep) + { + select(currentAlignFrame, sequenceIds, columns, sep); + } + + /** + * select regions of the given alignment frame + * + * @param alf + * @param toselect + * String separated list { column range, seq1...seqn sequence ids } + * @param sep + * separator between toselect fields + */ + public void select(AlignFrame alf, String sequenceIds, String columns) + { + select(alf, sequenceIds, columns, separator); + } + + /** + * select regions of the given alignment frame + * + * @param alf + * @param toselect + * String separated list { column range, seq1...seqn sequence ids } + * @param sep + * separator between toselect fields + */ + public void select(AlignFrame alf, String sequenceIds, String columns, + String sep) + { + if (sep == null || sep.length() == 0) + { + sep = separator; + } + // deparse fields + String[] ids = separatorListToArray(sequenceIds, sep); + String[] cols = separatorListToArray(columns, sep); + SequenceGroup sel = new SequenceGroup(); + ColumnSelection csel = new ColumnSelection(); + AlignmentI al = alf.viewport.getAlignment(); + int start = 0, end = al.getWidth(), alw = al.getWidth(); + if (ids != null && ids.length > 0) + { + for (int i = 0; i < ids.length; i++) + { + if (ids[i].trim().length() == 0) + { + continue; + } + SequenceI sq = al.findName(ids[i]); + if (sq != null) + { + sel.addSequence(sq, false); + } + } + } + if (cols != null && cols.length > 0) + { + boolean seset = false; + for (int i = 0; i < cols.length; i++) + { + String cl = cols[i].trim(); + if (cl.length() == 0) + { + continue; + } + int p; + if ((p = cl.indexOf("-")) > -1) + { + int from = -1, to = -1; + try + { + from = new Integer(cl.substring(0, p)).intValue(); + from--; + } catch (NumberFormatException ex) + { + System.err + .println("ERROR: Couldn't parse first integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + try + { + to = new Integer(cl.substring(p + 1)).intValue(); + to--; + } catch (NumberFormatException ex) + { + System.err + .println("ERROR: Couldn't parse second integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + if (from >= 0 && to >= 0) + { + // valid range + if (from < to) + { + int t = to; + to = from; + to = t; + } + if (!seset) + { + start = from; + end = to; + seset = true; + } + else + { + // comment to prevent range extension + if (start > from) + { + start = from; + } + if (end < to) + { + end = to; + } + } + for (int r = from; r <= to; r++) + { + if (r >= 0 && r < alw) + { + csel.addElement(r); + } + } + if (debug) + { + System.err.println("Range '" + cl + "' deparsed as [" + from + + "," + to + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Range '" + cl + + "' deparsed as [" + from + "," + to + "]"); + } + } + else + { + int r = -1; + try + { + r = new Integer(cl).intValue(); + r--; + } catch (NumberFormatException ex) + { + System.err + .println("ERROR: Couldn't parse integer from point selection element of column selection string '" + + cl + "'"); + return; + } + if (r >= 0 && r <= alw) + { + if (!seset) + { + start = r; + end = r; + seset = true; + } + else + { + // comment to prevent range extension + if (start > r) + { + start = r; + } + if (end < r) + { + end = r; + } + } + csel.addElement(r); + if (debug) + { + System.err.println("Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + } + } + sel.setStartRes(start); + sel.setEndRes(end); + alf.select(sel, csel); + + } + + /** * get sequences selected in current alignFrame and return their alignment in * format 'format' either with or without suffix * @@ -297,6 +552,155 @@ public class JalviewLite extends Applet return null; } + public void setMouseoverListener(String listener) + { + setMouseoverListener(currentAlignFrame, listener); + } + + private Vector mouseoverListeners = new Vector(); + + public void setMouseoverListener(AlignFrame af, String listener) + { + if (listener != null) + { + listener = listener.trim(); + if (listener.length() == 0) + { + System.err + .println("jalview Javascript error: Ignoring empty function for mouseover listener."); + return; + } + } + jalview.javascript.MouseOverListener mol = new jalview.javascript.MouseOverListener( + this, af, listener); + mouseoverListeners.add(mol); + StructureSelectionManager.getStructureSelectionManager() + .addStructureViewerListener(mol); + if (debug) + { + System.err.println("Added a mouseover listener for " + + ((af == null) ? "All frames" : "Just views for " + + af.getAlignViewport().getSequenceSetId())); + System.err.println("There are now " + mouseoverListeners.size() + + " listeners in total."); + } + } + + public void setSelectionListener(String listener) + { + setSelectionListener(currentAlignFrame, listener); + } + + public void setSelectionListener(AlignFrame af, String listener) + { + if (listener != null) + { + listener = listener.trim(); + if (listener.length() == 0) + { + System.err + .println("jalview Javascript error: Ignoring empty function for selection listener."); + return; + } + } + jalview.javascript.JsSelectionSender mol = new jalview.javascript.JsSelectionSender( + this, af, listener); + mouseoverListeners.add(mol); + StructureSelectionManager.getStructureSelectionManager() + .addSelectionListener(mol); + if (debug) + { + System.err.println("Added a selection listener for " + + ((af == null) ? "All frames" : "Just views for " + + af.getAlignViewport().getSequenceSetId())); + System.err.println("There are now " + mouseoverListeners.size() + + " listeners in total."); + } + } + + /** + * remove any callback using the given listener function and associated with + * the given alignFrame (or null for all callbacks) + * + * @param af + * (may be null) + * @param listener + * (may be null) + */ + public void removeJavascriptListener(AlignFrame af, String listener) + { + if (listener != null) + { + listener = listener.trim(); + if (listener.length() == 0) + { + listener = null; + } + } + boolean rprt = false; + for (Object lstn : mouseoverListeners) + { + JsCallBack lstner = (JsCallBack) lstn; + if ((af == null || lstner.getAlignFrame() == af) + && (listener == null || lstner.getListenerFunction().equals( + listener))) + { + mouseoverListeners.remove(lstner); + if (lstner instanceof SelectionListener) + { + StructureSelectionManager.getStructureSelectionManager() + .removeSelectionListener((SelectionListener) lstner); + } + else + { + StructureSelectionManager.getStructureSelectionManager() + .removeStructureViewerListener(lstner, null); + } + rprt = debug; + if (debug) + { + System.err.println("Removed listener '" + listener + "'"); + } + } + } + if (rprt) + { + System.err.println("There are now " + mouseoverListeners.size() + + " listeners in total."); + } + } + + public void stop() + { + if (mouseoverListeners!=null) + { + while (mouseoverListeners.size()>0) + { + Object mol = mouseoverListeners.remove(0); +// mouseoverListeners.elementAt(0); + if (mol instanceof SelectionListener) + { + StructureSelectionManager.getStructureSelectionManager().removeSelectionListener((SelectionListener)mol); + } else { + StructureSelectionManager.getStructureSelectionManager().removeStructureViewerListener(mol, null); + } + } + } + } + /** + * send a mouseover message to all the alignment windows associated with the + * given residue in the pdbfile + * + * @param pdbResNum + * @param chain + * @param pdbfile + */ + public void mouseOverStructure(int pdbResNum, String chain, String pdbfile) + { + StructureSelectionManager.getStructureSelectionManager() + .mouseOverStructure(pdbResNum, chain, pdbfile); + } + // ////////////////////////////////////////////// // ////////////////////////////////////////////// @@ -391,7 +795,8 @@ public class JalviewLite extends Applet */ public void init() { - + // remove any handlers that might be hanging around from an earlier instance + /** * turn on extra applet debugging */ @@ -1147,8 +1552,21 @@ public class JalviewLite extends Applet */ public String[] separatorListToArray(String list) { + return separatorListToArray(list, separator); + } + + /** + * parse the string into a list + * + * @param list + * @param separator + * @return elements separated by separator + */ + public String[] separatorListToArray(String list, String separator) + { + // note separator local variable intentionally masks object field int seplen = separator.length(); - if (list == null || list.equals("")) + if (list == null || list.equals("") || list.equals(separator)) return null; java.util.Vector jv = new Vector(); int cp = 0, pos; @@ -1196,6 +1614,18 @@ public class JalviewLite extends Applet */ public String arrayToSeparatorList(String[] list) { + return arrayToSeparatorList(list, separator); + } + + /** + * concatenate the list with separator + * + * @param list + * @param separator + * @return concatenated string + */ + public String arrayToSeparatorList(String[] list, String separator) + { StringBuffer v = new StringBuffer(); if (list != null && list.length > 0) { @@ -1224,7 +1654,7 @@ public class JalviewLite extends Applet System.err.println("Returning empty '" + separator + "' separated List\n"); } - return ""; + return "" + separator; } /** -- 1.7.10.2