1
votes

I am trying to get a proper method for days to select multiple cells in a flextable's column.

So far i only managed to do it with clicks which works well, but a drag selection would be much better. I have been reading docs and searching, but all the stuff i found was based on deprecated code. I use GWT 2.0 .

I know i need some event handler which would run when drag selection mouse gesture occurs, and that handler needs to know the cell's index where the selection start and of course the cell's index where the selection ends.

Any advice || code would be much appreciated.

1
Have you looked at gwt-dnd (code.google.com/p/gwt-dnd)?Igor Klimer
Yes, i found gwt-dnd too. I looked at demos and wiki, and they support all kind of drag and drop stuff, but there is no support for drag selection.Stoto
I am still looking for a solution.Stoto

1 Answers

1
votes

This needs to be improved but it should give you the basic idea. First you need to create a CustomTable that listens to MouseEvents. You can do this by extending composite to wrap a focuspanel and a flextable as such :

public class CustomTable extends Composite implements MouseDownHandler, MouseMoveHandler, MouseUpHandler{

List<CellWidget> widgets = new ArrayList<CellWidget>();
FlexTable table = new FlexTable();
FocusPanel focusPanel = new FocusPanel();
boolean selecting= false;
Point selectStart,selectEnd;    

public CustomTable(){
    focusPanel.setWidget(table);
    focusPanel.addMouseDownHandler(this);
    focusPanel.addMouseMoveHandler(this);
    focusPanel.addMouseUpHandler(this);

    initWidget(focusPanel);
}

public void setWidget(int row, int column, CellWidget widget){
    widgets.add(widget);
    table.setWidget(row, column, widget);
}

@Override
public void onMouseUp(MouseUpEvent event) {
    event.preventDefault();
    if (selecting){
        selecting=false;
        DOM.releaseCapture(this.getElement());
        selectEnd = new Point(event.getClientX(),event.getClientY());

        for (CellWidget widget : widgets){
            if (widget.isIn(selectStart,selectEnd))
                widget.say();               
        }
        selectStart = selectEnd = null;         
    }       
}

@Override
public void onMouseMove(MouseMoveEvent event) {
    event.preventDefault();
    if (selecting){
        //do some fancy layout
    }       
}

@Override
public void onMouseDown(MouseDownEvent event) {
    event.preventDefault();
    selecting = true;
    DOM.setCapture(this.getElement());  
    selectStart = new Point(event.getClientX(),event.getClientY());
}   
}

Next you define a CellWidget which basically encapsulates what you would like to add to your cells. When added to DOM, CellWidget calculates and stores its position later to determine if it is in the selected area :

public class CellWidget extends Composite{

Widget content;
Point topLeft,topRight,bottomLeft,bottomRight;

public CellWidget(Widget w){
    this.content = w;
    initWidget(w);
}

@Override
protected void onLoad() {
    topLeft = new Point(getAbsoluteLeft(),getAbsoluteTop());
    topRight = new Point(getAbsoluteLeft()+getOffsetWidth(),getAbsoluteTop());
    bottomLeft = new Point(getAbsoluteLeft(),getAbsoluteTop()+getOffsetHeight());
    bottomRight = new Point(getAbsoluteLeft()+getOffsetWidth(),getAbsoluteTop()+getOffsetHeight());
}

public void say(){
    Window.alert(content + " is selected!");
}

public boolean isIn(Point start, Point end){
    if (topLeft.isBetween(start, end) || topRight.isBetween(start, end)
            || bottomLeft.isBetween(start, end) || bottomRight.isBetween(start, end))
        return true;
    else
        return false;           
}
}

A simple point implementation to make things easier :

public class Point {

int x,y;

public Point(int x,int y){
    this.x=x;
    this.y=y;
}   
public int getX() {
    return x;
}
public int getY() {
    return y;
}
@Override
public String toString() {
    return x+","+y;
}
public boolean isBetween(Point p1,Point p2){
    if (p1.getX() < x && p2.getX() > x && p1.getY() < y && p2.getY() > y)
        return true;
    return false;
}
}

Finally at your EntryPoint module you wrap things up by :

public void onModuleLoad() {
    RootPanel rootPanel = RootPanel.get();
    CustomTable table = new CustomTable();
    table.setWidget(0, 0, new CellWidget(new Label("hello 0,0")));
    table.setWidget(0, 1, new CellWidget(new Label("hello 0,1")));
    table.setWidget(1, 0, new CellWidget(new Label("hello 1,0")));
    table.setWidget(1, 1, new CellWidget(new Label("hello 1,1")));
    rootPanel.add(table);
}

I know that the actual logic to determine if the widgets fall within the selected area is incomplete and needs to be improved but i think this solution is clear enough to give the basic idea. Cheers