SimplePager row count is working incorrectly - gwt

I'm using SimplePager and I want to show 12 items (users) per page. My entire data set is 20 items.
The problem is that the first page (correctly) shows items 1-12, but the second page shows items 9-20. I want the second page to show items 13-20.
What's going wrong?
Here is my code:
CellTable<User> cellTable = new CellTable<User>();
SimplePager pager = new SimplePager(TextLocation.CENTER);
pager.setDisplay(cellTable);
pager.setPageSize(12);
ListDataProvider<User> dataProvider = new ListDataProvider<User>();<br>
dataProvider.setList(USERSList);
dataProvider.addDataDisplay(cellTable);
Thank you in advance!

Setting
setRangeLimited(false)
will always show a next page.
Instead, I have rangeLimited at true and I've overridden the following method for this :
#Override
public void setPageStart(int index) {
if (getDisplay() != null) {
Range range = getDisplay().getVisibleRange();
int pageSize = range.getLength();
// Removed the min to show fixed ranges
//if (isRangeLimited && display.isRowCountExact()) {
// index = Math.min(index, display.getRowCount() - pageSize);
//}
index = Math.max(0, index);
if (index != range.getStart()) {
getDisplay().setVisibleRange(index, pageSize);
}
}
}

Try setting:
setRangeLimited(false)
More details:
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/45e77082b796281d/d5101729e83a74ff?lnk=gst&q=pager+last+page#d5101729e83a74ff

#fbfcn and #MasterUZ's solution works, with a few slight modifications to make it comply with GWT 2.4's SimplePager:
public class MySimplePager extends SimplePager {
public MySimplePager() {
this.setRangeLimited(true);
}
public MySimplePager(TextLocation location, Resources resources, boolean showFastForwardButton, int fastForwardRows, boolean showLastPageButton) {
super(location, resources, showFastForwardButton, fastForwardRows, showLastPageButton);
this.setRangeLimited(true);
}
public void setPageStart(int index) {
if (this.getDisplay() != null) {
Range range = getDisplay().getVisibleRange();
int pageSize = range.getLength();
if (!isRangeLimited() && getDisplay().isRowCountExact()) {
index = Math.min(index, getDisplay().getRowCount() - pageSize);
}
index = Math.max(0, index);
if (index != range.getStart()) {
getDisplay().setVisibleRange(index, pageSize);
}
}
}
}

import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.view.client.Range;
public class MySimplePager extends SimplePager {
public MySimplePager() {
this.setRangeLimited(true);
}
public MySimplePager(TextLocation location, Resources resources, boolean showFastForwardButton, int fastForwardRows, boolean showLastPageButton) {
super(location, resources, showFastForwardButton, fastForwardRows, showLastPageButton);
this.setRangeLimited(true);
}
#Override
public void setPageStart(int index) {
if (getDisplay() != null) {
Range range = getDisplay().getVisibleRange();
int pageSize = range.getLength();
if (!isRangeLimited() && getDisplay().isRowCountExact()) {
index = Math.min(index, getDisplay().getRowCount() - pageSize);
}
index = Math.max(0, index);
if (index != range.getStart()) {
getDisplay().setVisibleRange(index, pageSize);
}
}
}
}

Related

GWT- In celltable column checkboxcell select all records i want select display record

Frineds,
I am using celltable and their is one column which I put in table header for select all record option and also I am using pager which showing max 15 record in one page. when I clicked on selectall option it will select all records which are present page no 2,3,4,.... in short all records get selected(if total records is 100 it's selected 100 records).so i want only select display page records not all...
ref code is -
final SelectionModel < GenericFirewallRule > selectionModel =
new MultiSelectionModel < GenericFirewallRule > ();
deleteRuleCellTable.setSelectionModel(selectionModel,DefaultSelectionEventManager. < GenericFirewallRule > createCheckboxManager());
// CheckboxCell cbForHeader = new CheckboxCell();
Column < GenericFirewallRule, Boolean > checkColumn = new Column < GenericFirewallRule, Boolean > (
new CheckboxCell()) {#Override
public Boolean getValue(GenericFirewallRule object) {
if(object == null || object.getRuleNumber() == null){
return null;
}else{
if (selectionModel.isSelected(object)) {
if (!ruleListForDelete.contains(object)) {
ruleListForDelete.add(object);
}
} else {
if (ruleListForDelete.contains(object)) {
ruleListForDelete.remove(object);
}
}
System.out.println("ruleListForDelete : " + ruleListForDelete);
return selectionModel.isSelected(object);
}
}
};
Please suggest me solutions....
You can do something like this:
selectAllHeader = new Header<Boolean>(new HeaderCheckbox()) {
#Override
public Boolean getValue() {
for (T item : getVisibleItems()) {
if (!getSelectionModel().isSelected(item)) {
return false;
}
}
return getVisibleItems().size() > 0;
}
};
selectAllHeader.setUpdater(new ValueUpdater<Boolean>() {
#Override
public void update(Boolean value) {
for (T object : getVisibleItems()) {
getSelectionModel().setSelected(object, value);
}
}
});
public class HeaderCheckbox extends CheckboxCell {
private final SafeHtml INPUT_CHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\" checked/>");
private final SafeHtml INPUT_UNCHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\"/>");
public HeaderCheckbox() {
}
#Override
public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
if (value != null && value) {
sb.append(INPUT_CHECKED);
} else {
sb.append(INPUT_UNCHECKED);
}
}
}

GWT sinkEvents in hosted mode

I extends a gwt celltable to create a custom celltable, i register the sinkevents ie onmouseover/onmouseout.
when you hover on the row of the table the row data is populated on the hover wiget(custom hover popup panel).
its works as it supose to do on development mode but once deployed on tomcat when you move the mouse over different rows on the celltable it
does not update the hover data on the popup panel unless you click away from the table(loose focus) and the hover again on the row.
public class MyCellTable<T> extends CellTable<T> {
private Tooltip popup = new Tooltip();
private List<String> tooltipHiddenColumn = new ArrayList<String>();
private boolean showTooltip;
public MyCellTable() {
super();
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
}
#Override
public void onBrowserEvent2(Event event) {
super.onBrowserEvent2(event);
if (isShowTooltip()) {
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEOUT: {
popup.hide(true);
break;
}
case Event.ONMOUSEOVER: {
popup.setAutoHideEnabled(true);
showToolTip(event);
break;
}
}
}
}
private void showToolTip(final Event event) {
EventTarget eventTarget = event.getEventTarget();
if (!Element.is(eventTarget)) {
return;
}
final Element target = event.getEventTarget().cast();
// Find the cell where the event occurred.
TableCellElement tableCell = findNearestParentCell(target);
if (tableCell == null) {
return;
}
Element trElem = tableCell.getParentElement();
if (trElem == null) {
return;
}
TableRowElement tr = TableRowElement.as(trElem);
Element sectionElem = tr.getParentElement();
if (sectionElem == null) {
return;
}
TableSectionElement section = TableSectionElement.as(sectionElem);
if (section == getTableHeadElement()) {
return;
}
NodeList<TableCellElement> cellElements = tr.getCells().cast();
NodeList<TableCellElement> headers = getTableHeadElement().getRows().getItem(0).getCells().cast();
popup.getGrid().clear(true);
popup.getGrid().resizeRows(cellElements.getLength());
for (int i = 0; i < cellElements.getLength(); i++) {
if (getTooltipHiddenColumn().indexOf(headers.getItem(i).getInnerHTML()) == -1) {
TableCellElement tst = TableCellElement.as(cellElements.getItem(i));
popup.getGrid().setHTML(i, 0, headers.getItem(i).getInnerHTML());
popup.getGrid().setHTML(i, 1, tst.getInnerHTML());
}
}
// Here the constant values are used to give some gap between mouse pointer and popup panel
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
int left = event.getClientX() + 5;
int top = event.getClientY() + 5;
if ((offsetHeight + top + 20) > Window.getClientHeight()) {
top = top - offsetHeight - 10;
}
popup.setPopupPosition(left, top);
}
});
popup.show();
}
public ArrayList<ReorderColumnsDetails> getColumnsHeaders(int index){
ArrayList<ReorderColumnsDetails> column = new ArrayList<ReorderColumnsDetails>();
NodeList<TableCellElement> headers = getTableHeadElement().getRows().getItem(0).getCells().cast();
for (int i = 0; i < index; i++) {
ReorderColumnsDetails clm = new ReorderColumnsDetails();
clm.setHearder(headers.getItem(i).getInnerHTML().toString());
clm.setItemIndex(i);
column.add(clm);
}
return column;
}
private TableCellElement findNearestParentCell(Element elem) {
while ((elem != null) && (elem != getElement())) {
String tagName = elem.getTagName();
if ("td".equalsIgnoreCase(tagName) || "th".equalsIgnoreCase(tagName)) {
return elem.cast();
}
elem = elem.getParentElement();
}
return null;
}
/**
* Specify Name of the column's which is not to shown in the Tooltip
*/
public List<String> getTooltipHiddenColumn() {
return tooltipHiddenColumn;
}
/**
* Set title to tooltip
*
* #param title
*/
public void setTooltipTitle(String title) {
popup.setHTML(title);
}
public boolean isShowTooltip() {
return showTooltip;
}
public void setShowTooltip(boolean showTooltip) {
this.showTooltip = showTooltip;
}
}

gwt cell table dynamic columns - sorting

You can represent your "rows" as List<String> instances, you have to change your parameterization from String to List in your Grid, Column and data provider; and of course you have to call updateRowData with a List<List<String>>, not a List<String>.
You also need one Column instance per column, taking the value out of the List by index:
class IndexedColumn extends Column<List<String>, String> {
private final int index;
public IndexedColumn(int index) {
super(new EditTextCell());
this.index = index;
}
#Override
public String getValue(List<String> object) {
return object.get(this.index);
}
}
How do i add sorting to this example. I tried a ListHandler but not sure how to compare List<String>. Any help is appreciated.
You need to add a ListHandler to each column you want to sort separately. Kind of like this:
You'll have to add a getter method to IndexedColumn for the index:
class IndexedColumn extends Column<List<String>, String> {
private final int index;
public IndexedColumn(int index) {
super(new EditTextCell());
this.index = index;
}
#Override
public String getValue(List<String> object) {
return object.get(this.index);
}
public int getIndex(){
return index;
}
}
Then you'll need to add a ListHandler to the CellTable:
ListHandler<List<String>> columnSortHandler = new ListHandler<List<String>>(list);
columnSortHandler.setComparator(columnName, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
if (o1 == o2) {
return 0;
}
// Compare the column.
if (o1 != null) {
int index = columnName.getIndex();
return (o2 != null) ? o1.get(index).compareTo(o2.get(index)) : 1;
}
return -1;
}
});
table.addColumnSortHandler(columnSortHandler);
In the example above list is the List<List<String>> object. The columnName is the Column object. You'll have to do this for every column you want to sort.
Don't forget to also call .setSortable(true) on each of the columns that you will sort.
A good basic example of column sorting can be found here. The code above is based on this example but I used your index in IndexedColumn in order to get the proper String for the column to do the comparison.
Here is the data grid code
indexedColumn.setSortable(true);
sortHandler.setComparator((Column<T, ?>) indexedColumn, (Comparator<T>) indexedColumn.getComparator(true));
Here is the actual class
public class IndexedColumn extends Column<List<String>, String>
{
private Comparator<List<String>> forwardComparator;
private Comparator<List<String>> reverseComparator;
private final int index;
public IndexedColumn(int index)
{
super(new TextCell());
this.index = index;
}
#Override
public String getValue(List<String> object)
{
return object.get(index);
}
public Comparator<List<String>> getComparator(final boolean reverse)
{
if (!reverse && forwardComparator != null)
{
return forwardComparator;
}
if (reverse && reverseComparator != null)
{
return reverseComparator;
}
Comparator<List<String>> comparator = new Comparator<List<String>>()
{
public int compare(List<String> o1, List<String> o2)
{
if (o1 == null && o2 == null)
{
return 0;
}
else if (o1 == null)
{
return reverse ? 1 : -1;
}
else if (o2 == null)
{
return reverse ? -1 : 1;
}
// Compare the column value.
String c1 = getValue(o1);
String c2 = getValue(o2);
if (c1 == null && c2 == null)
{
return 0;
}
else if (c1 == null)
{
return reverse ? 1 : -1;
}
else if (c2 == null)
{
return reverse ? -1 : 1;
}
int comparison = ((String) c1).compareTo(c2);
return reverse ? -comparison : comparison;
}
};
if (reverse)
{
reverseComparator = comparator;
}
else
{
forwardComparator = comparator;
}
return comparator;
}
}

Making a drag and drop FlexTable in GWT 2.5

I'm trying to make a simple Drag and Drop FlexTable using native GWT drag events to allow the user to move rows around.
//This works fine
galleryList.getElement().setDraggable(Element.DRAGGABLE_TRUE);
galleryList.addDragStartHandler(new DragStartHandler() {
#Override
public void onDragStart(DragStartEvent event) {
event.setData("text", "Hello World");
groupList.getElement().getStyle().setBackgroundColor("#aff");
}
});
However, I'd like to:
1. Give a visual indicator where the item will be dropped.
2. Work out where i should drop the row, when the drop event fires.
galleryList.addDragOverHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
//TODO: How do i get the current location one would drop an item into a flextable here
}
});
galleryList.addDragEndHandler(new DragEndHandler() {
#Override
public void onDragEnd(DragEndEvent event) {
//TODO: How do i know where i am in the flextable
}
});
I see these FlexTable methods are useful in getting a cell/row:
public Cell getCellForEvent(ClickEvent event)
protected Element getEventTargetCell(Event event)
But the problem is the Drag events do not inherit of Event
Thanks in advance
Caveat: I cant gaurentee this will work out the box. This is the code I ended up making (And works for me) - it's a Drag n Drop Widget which inherits from FlexTable. I detect any drag events on the table, and then try compute where the mouse is over that FlexTable.
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Widget;
public class DragFlexTable extends FlexTable implements DraggableWidget {
public String dragStyle = "drag-table-row";
public String dragReplaceStyle;
protected DragVerticalHandler dragFlexTableHandler;
private int currentRow;
private int[] yLocations;
private int rowBeingDragged;
DragFlexTable() {
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
getElement().setDraggable(Element.DRAGGABLE_TRUE);
final DragUtil dragUtil = new DragUtil();
addDragStartHandler(new DragStartHandler() {
#Override
public void onDragStart(DragStartEvent event) {
dragUtil.startVerticalDrag(event, DragFlexTable.this);
}
});
addDragEndHandler(new DragEndHandler() {
#Override
public void onDragEnd(DragEndEvent event) {
dragUtil.endVerticalDrag(event, DragFlexTable.this);
}
});
addDragOverHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
dragUtil.handleVerticalDragOver(event, DragFlexTable.this, 3);
}
});
}
#Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
Element td = getEventTargetCell(event);
if (td == null) return;
Element tr = DOM.getParent(td);
currentRow = TableRowElement.as(td.getParentElement()).getSectionRowIndex();
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEOVER: {
//tr.addClassName(ROW_STYLE_NAME + "-mouseover");
tr.addClassName(dragStyle);
break;
}
case Event.ONMOUSEOUT: {
tr.removeClassName(dragStyle);
break;
}
}
}
public void setDragStyle(String dragStyle) {
this.dragStyle = dragStyle;
}
#Override
public void resetDragState() {
yLocations = null;
}
#Override
public void setRowBeingDragged(int currentRow) {
this.rowBeingDragged = currentRow;
}
#Override
public int getDragRow(DragDropEventBase event) {
if (yLocations == null) {
yLocations = new int[getRowCount()];
for (int i = 0; i < getRowCount(); i++) {
Widget widget = getWidget(i, 0);
if (widget.isVisible()) {
com.google.gwt.dom.client.Element imgTd = widget.getElement().getParentElement();
int absoluteBottom = imgTd.getAbsoluteBottom();
yLocations[i] = absoluteBottom;
} else {
yLocations[i] = -1;
}
}
}
int lastY = 0;
for (int i = 0; i < yLocations.length; i++) {
int absoluteBottom = yLocations[i];
//invisible
if (absoluteBottom != -1) {
int absoluteTop = lastY;
int clientY = event.getNativeEvent().getClientY();
if (absoluteBottom > clientY && absoluteTop < clientY) {
//com.google.gwt.dom.client.Element tr = imgTd.getParentElement();
return i;
}
lastY = absoluteBottom;
}
}
return currentRow;
}
#Override
public com.google.gwt.dom.client.Element getTrElement(int row) {
return getWidget(row, 0).getElement().getParentElement().getParentElement();
}
#Override
public DragVerticalHandler getDragFlexTableHandler() {
return dragFlexTableHandler;
}
public void setDragReplaceStyle(String dragReplaceStyle) {
this.dragReplaceStyle = dragReplaceStyle;
}
#Override
public int getRowBeingDragged() {
return rowBeingDragged;
}
#Override
public String getDragReplaceStyle() {
return dragReplaceStyle;
}
public void setDragFlexTableHandler(DragVerticalHandler dragFlexTableHandler) {
this.dragFlexTableHandler = dragFlexTableHandler;
}
}
This is util class which it uses
import com.google.gwt.event.dom.client.DragEndEvent;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragStartEvent;
import com.google.gwt.user.client.ui.Image;
public class DragUtil {
private int alternateIgnoreEvent = 0;
private int lastDragRow = -1;
public void startVerticalDrag(DragStartEvent event, DraggableWidget widget) {
widget.resetDragState();
//Required
event.setData("text", "dragging");
int currentRow = widget.getDragRow(event);
widget.setRowBeingDragged(currentRow);
if (widget.getDragFlexTableHandler()!=null) {
Image thumbnailImg = widget.getDragFlexTableHandler().getImage(currentRow);
if (thumbnailImg!=null) {
event.getDataTransfer().setDragImage(thumbnailImg.getElement(), -10, -10);
}
}
}
public void handleVerticalDragOver(DragOverEvent event, DraggableWidget widgets, int sensitivity) {
if (alternateIgnoreEvent++ % sensitivity != 0) {
//many events fire, for every pixel move, which slow the browser, so ill ignore some
return;
}
int dragRow = widgets.getDragRow(event);
if (dragRow != lastDragRow) {
com.google.gwt.dom.client.Element dragOverTr = widgets.getTrElement(dragRow);
if (lastDragRow != -1) {
com.google.gwt.dom.client.Element lastTr = widgets.getTrElement(lastDragRow);
lastTr.removeClassName(widgets.getDragReplaceStyle());
}
lastDragRow = dragRow;
dragOverTr.addClassName(widgets.getDragReplaceStyle());
}
}
public void endVerticalDrag(DragEndEvent event, DraggableWidget widgets) {
int newRowPosition = widgets.getDragRow(event);
//cleanup last position
if (newRowPosition != lastDragRow) {
com.google.gwt.dom.client.Element lastTr = widgets.getTrElement(lastDragRow);
lastTr.removeClassName(widgets.getDragReplaceStyle());
}
if (newRowPosition != widgets.getRowBeingDragged()) {
com.google.gwt.dom.client.Element dragOverTr = widgets.getTrElement(newRowPosition);
dragOverTr.removeClassName(widgets.getDragReplaceStyle());
widgets.getDragFlexTableHandler().moveRow(widgets.getRowBeingDragged(), newRowPosition);
}
}
}
In the uibinder I then use it like this:
<adminDnd:DragFlexTable ui:field='itemFlexTable' styleName='{style.table}' cellSpacing='0'
cellPadding='0'
dragStyle='{style.drag-table-row-mouseover}'
dragReplaceStyle='{style.drag-replace-table-row}'
/>
Even i had this problem and after a little prototyping this is what I ended up with
.I created a class which extended the flex table.Here is the code
public class DragFlexTable extends FlexTable implements
MouseDownHandler,MouseUpHandler,MouseMoveHandler,
MouseOutHandler
{
private int row,column,draggedrow,draggedcolumn;
private Element td;
private Widget w;
private boolean emptycellclicked;
DragFlexTable()
{
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEDOWN | Event.ONMOUSEMOVE);
this.addMouseDownHandler(this);
this.addMouseMoveHandler(this);
this.addMouseUpHandler(this);
this.addMouseOutHandler(this);
}
#Override
public void onBrowserEvent(Event event)
{
super.onBrowserEvent(event);
td = getEventTargetCell(event);
if (td == null)
{
return;
}
Element tr = DOM.getParent((com.google.gwt.user.client.Element) td);
Element body = DOM.getParent((com.google.gwt.user.client.Element) tr);
row = DOM.getChildIndex((com.google.gwt.user.client.Element) body, (com.google.gwt.user.client.Element) tr);//(body, tr);
column = DOM.getChildIndex((com.google.gwt.user.client.Element) tr, (com.google.gwt.user.client.Element) td);
}
boolean mousedown;
#Override
public void onMouseDown(MouseDownEvent event)
{
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT)
{
//to ensure empty cell is not clciked
if (!td.hasChildNodes())
{
emptycellclicked = true;
}
event.preventDefault();
start(event);
mousedown = true;
}
}
#Override
public void onMouseMove(MouseMoveEvent event)
{
if (mousedown)
{
drag(event);
}
}
#Override
public void onMouseUp(MouseUpEvent event)
{
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT)
{
if (!emptycellclicked)
{
end(event);
}
emptycellclicked = false;
mousedown = false;
}
}
#Override
public void onMouseOut(MouseOutEvent event)
{
this.getCellFormatter().getElement(row, column).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(row, column).getStyle().clearBorderColor();
this.getCellFormatter().getElement(row, column).getStyle().clearBorderWidth();
w.getElement().getStyle().setOpacity(1);
mousedown = false;
}
private void start(MouseDownEvent event)
{
w = this.getWidget(row, column);
w.getElement().getStyle().setOpacity(0.5);
}
private void drag(MouseMoveEvent event)
{
if (draggedrow != row || draggedcolumn != column)
{
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderColor();
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderWidth();
this.draggedrow = row;
this.draggedcolumn = column;
this.getCellFormatter().getElement(row, column).getStyle().setBorderStyle(BorderStyle.DASHED);
this.getCellFormatter().getElement(row, column).getStyle().setBorderColor("black");
this.getCellFormatter().getElement(row, column).getStyle().setBorderWidth(2, Unit.PX);
}
}
private void end(MouseUpEvent event)
{
insertDraggedWidget(row, column);
}
private void insertDraggedWidget(int r,int c)
{
this.getCellFormatter().getElement(r, c).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(r, c).getStyle().clearBorderColor();
this.getCellFormatter().getElement(r, c).getStyle().clearBorderWidth();
w.getElement().getStyle().setOpacity(1);
if (this.getWidget(r, c) != null)
{
//pushing down the widgets already in the column
// int widgetheight = (this.getWidget(r, c).getOffsetHeight() / 2) + this.getWidget(r, c).getAbsoluteTop();
// int rw;
//placing the widget above the dropped widget
for (int i = this.getRowCount() - 1; i >= r; i--)
{
if (this.isCellPresent(i, c))
{
this.setWidget(i + 1, c, this.getWidget(i, c));
}
}
}
this.setWidget(r, c, w);
//removes unneccesary blank rows
cleanupRows();
//pushing up the column in the stack
// for (int i = oldrow;i<this.getRowCount()-1 ;i++)
// {
//
// this.setWidget(i ,oldcolumn, this.getWidget(i+1, oldcolumn));
//
// }
}
private void cleanupRows()
{
ArrayList<Integer> rowsfilled = new ArrayList<Integer>();
for (int i = 0; i <= this.getRowCount() - 1; i++)
{
for (int j = 0; j <= this.getCellCount(i) - 1; j++)
{
if (this.getWidget(i, j) != null)
{
rowsfilled.add(i);
break;
}
}
}
//replace the empty rows
for (int i = 0; i < rowsfilled.size(); i++)
{
int currentFilledRow = rowsfilled.get(i);
if (i != currentFilledRow)
{
for (int j = 0; j < this.getCellCount(currentFilledRow); j++)
{
this.setWidget(i, j, this.getWidget(currentFilledRow, j));
}
}
}
for (int i = rowsfilled.size(); i < this.getRowCount(); i++)
{
this.removeRow(i);
}
}
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler)
{
return addDomHandler(handler, MouseUpEvent.getType());
}
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler)
{
return addDomHandler(handler, MouseDownEvent.getType());
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler)
{
return addDomHandler(handler, MouseMoveEvent.getType());
}
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler)
{
return addDomHandler(handler, MouseOutEvent.getType());
}
}
and the on module load for the above custom widget is
public void onModuleLoad()
{
Label a = new Label("asad");
Label b = new Label("ad");
Label c = new Label("qwad");
Label w = new Label("zxd");
a.setPixelSize(200, 200);
a.getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
a.getElement().getStyle().setBorderWidth(1, Unit.PX);
b.setPixelSize(200, 200);
c.setPixelSize(200, 200);
w.setPixelSize(200, 200);
a.getElement().getStyle().setBackgroundColor("red");
b.getElement().getStyle().setBackgroundColor("yellowgreen");
c.getElement().getStyle().setBackgroundColor("lightblue");
w.getElement().getStyle().setBackgroundColor("grey");
DragFlexTable d = new DragFlexTable();
d.setWidget(0, 0, a);
d.setWidget(0, 1, b);
d.setWidget(1, 0, c);
d.setWidget(1, 1, w);
d.setCellPadding(20);
RootPanel.get().add(d);
}

CheckboxCell, MultiSelectionModel unwantonly reset DataGrid's data

Using GWT 2.4...
I am building upon a complex Composite dual view/edit mode implementation that is backed GWT's DataGrid and MultiSelectionModel. My goal is for a user to be able to click a checkbox in each row that they'd like to post updates for.
Here's a screenshot from a semi-functional interface:
Note the selected (highlighted) rows.
Now the problem is that when I type something in any of the cells (e.g., the first row's $ cell under the $/Mw 1 composite cell header), then click that row's checkbox (or any other row's checkbox for that matter) to select or de-select, the value gets reset to the original value when the screen's data was first requested. Not desired behavior by any stretch!
Let's take a look at my custom implementation for the grid. (Excuse the length).
public abstract class ToggleableGrid<T extends Identifiable<?>> extends Composite {
private static final int CHKBOX_COLUMN_WIDTH = App.INSTANCE.checkboxColumnWidth();
private static final DisplayMode DEFAULT_MODE = DisplayMode.VIEW;
private ProvidesKey<T> keyProvider;
private DataGrid<T> grid;
private MultiSelectionModel<T> selectionModel;
private ListDataProvider<T> dataProvider;
private int tabIndex = 0;
public ToggleableGrid() {
final DataGridConfiguration config = new DefaultDataGridConfiguration();
initGrid(config);
}
public ToggleableGrid(DataGridConfiguration config) {
initGrid(config);
}
private void initGrid(DataGridConfiguration config) {
keyProvider = new ProvidesKey<T>() {
#Override
public Object getKey(T item) {
return item == null ? null : item.getId();
}
};
grid = new DataGrid<T>(config.getPageSize(), config.getResources(), keyProvider);
// Set the message to display when the table is empty.
grid.setEmptyTableWidget(new Label(UiMessages.INSTANCE.no_results()));
initWidget(grid);
setVisible(true);
}
public void setInput(List<T> content) {
setInput(content, DEFAULT_MODE);
}
public void setInput(List<T> content, DisplayMode mode) {
resetTableColumns();
if (isInEditMode(mode)) {
// Add a selection model so we can select cells
selectionModel = new MultiSelectionModel<T>(keyProvider);
grid.setSelectionModel(selectionModel, DefaultSelectionEventManager.<T> createCheckboxManager(0));
addRowSelector();
}
dataProvider = new ListDataProvider<T>(content);
final ListHandler<T> sortHandler = new ListHandler<T>(dataProvider.getList());
grid.addColumnSortHandler(sortHandler);
initializeStructure(constructMetadata(), sortHandler, mode);
dataProvider.addDataDisplay(grid);
}
// see https://stackoverflow.com/questions/3772480/remove-all-columns-from-a-celltable
// concrete classes are forced to maintain a handle on all columns added
private void resetTableColumns() {
for (final Column<T, ?> column: allColumns()) {
grid.removeColumn(column);
}
allColumns().clear();
}
protected boolean isInEditMode(DisplayMode currentDisplayMode) {
boolean result = false;
if (currentDisplayMode.equals(DisplayMode.EDIT)) {
result = true;
}
return result;
}
protected abstract Set<Column<T, ?>> allColumns();
protected abstract TableMetadata constructMetadata();
protected abstract void initializeStructure(TableMetadata metadata, ListHandler<T> sortHandler, DisplayMode mode);
protected void setColumnHorizontalAlignment(Column<T, ?> column, HorizontalAlignmentConstant alignment) {
column.setHorizontalAlignment(alignment);
}
// TODO figure out how to add a checkbox to column header that provides select/de-select all capability
// see https://stackoverflow.com/questions/6174689/gwt-celltable-programmatically-select-checkboxcell
protected void addRowSelector() {
final Column<T, Boolean> rowSelectColumn = new Column<T, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(T value) {
Boolean result;
// check for null value and return null;
if(value == null || value.getId() == null) {
result = null;
} else { // get value from the selection model
result = selectionModel.isSelected(value);
}
return result;
}
};
addColumn(rowSelectColumn, UiMessages.INSTANCE.select());
setColumnWidth(rowSelectColumn, CHKBOX_COLUMN_WIDTH, Unit.PX);
setColumnHorizontalAlignment(rowSelectColumn, HasHorizontalAlignment.ALIGN_CENTER);
}
protected void setColumnWidth(Column<T, ?> column, int width, Unit unit) {
grid.setColumnWidth(column, width, unit);
}
protected void addColumn(Column<T, ?> column, String columnHeaderName) {
addColumn(column, columnHeaderName, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addColumn(Column<T, ?> column, String columnHeaderName, HorizontalAlignmentConstant alignment) {
final SafeHtmlBuilder sb = new SafeHtmlBuilder();
final String divStart = "<div align=\""+ alignment.getTextAlignString() + "\" class=\"" +UiResources.INSTANCE.style().word_wrap() + "\">";
sb.appendHtmlConstant(divStart).appendEscaped(columnHeaderName).appendHtmlConstant("</div>");
final SafeHtml header = sb.toSafeHtml();
grid.addColumn(column, header);
allColumns().add(column);
}
protected CompositeCell<T> generateCompositeCell(final List<HasCell<T, ?>> hasCells) {
final CompositeCell<T> compositeCell = new CompositeCell<T>(hasCells) {
#Override
public void render(Context context, T value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<table><tbody><tr>");
super.render(context, value, sb);
sb.appendHtmlConstant("</tr></tbody></table>");
}
#Override
protected Element getContainerElement(Element parent) {
// Return the first TR element in the table.
return parent.getFirstChildElement().getFirstChildElement().getFirstChildElement();
}
#Override
protected <X> void render(Context context, T value,
SafeHtmlBuilder sb, HasCell<T, X> hasCell) {
final Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
cell.render(context, hasCell.getValue(value), sb);
sb.appendHtmlConstant("</td>");
}
};
return compositeCell;
}
// FIXME not working quite the way we'd expect, index incremented within column for each row, not each row by column
protected int nextTabIndex() {
tabIndex++;
return tabIndex;
}
protected AbstractCellTable<T> getGrid() {
return grid;
}
/**
* Gets the selected (row(s) of) data from grid (used in edit mode)
* #return the selected data (as per selection model)
*/
public List<T> getSelectedData() {
final List<T> data = new ArrayList<T>();
data.addAll(selectionModel.getSelectedSet());
return data;
}
/**
* Gets all (row(s) of) data in grid (used in edit mode)
* #return all data as list
*/
public List<T> getAllData() {
return dataProvider.getList();
}
/**
* Clears the currently selected (row(s) of) data (used in edit mode)
*/
public void clearSelectedData() {
selectionModel.clear();
grid.redraw();
}
}
So, the interesting methods to stare at above (I think) are setInput, generateCompositeCell and addRowSelector.
We initialize the grid with List data and set a display mode in setInput. It's here as well that the selection model is initialized. It uses GWT's DefaultSelectionEventManager createCheckboxManager().
I've been trying to grok the event model, but it eludes me. I've visited the following sources online, but have come up short on avenues to solving this problem.
-- https://groups.google.com/forum/?fromgroups#!topic/google-web-toolkit/k5sfURxDaVg
AbstractInputCell's getConsumedEventsImpl adds focus, blur and keydown, so this (I believe) is not a track I need to explore
-- GWT CellTable programmatically select CheckBoxCell
The various ways you can instantiate a CheckBoxCell got me curious, and I've tried many constructor argument permutations, but the one I settled on (true, false) is (I believe) the right one
Agreeing here and now (before being reprimanded) that there's perhaps some unnecessary complexity in my implementation, but I am looking for guidance nonetheless. Thanks!
Update
If it helps here's an impl of the aforementioned ToggleableGrid. If anything it gives you more detail on what goes into each CompositeCell. For details on AbstractValidatableColumn and ValidatableInputCell, see: In search of a GWT validation example... where art thou?.
public class EnergyOfferGrid extends ToggleableGrid<EnergyOfferDTO> {
public EnergyOfferGrid() {
super();
}
public EnergyOfferGrid(DataGridConfiguration config) {
super(config);
}
private static final int MAX_NUMBER_OF_MW_PRICE_POINTS = App.INSTANCE.maxNoOfMwPricePoints();
private Set<Column<EnergyOfferDTO, ?>> columns = new HashSet<Column<EnergyOfferDTO, ?>>();
#Override
protected Set<Column<EnergyOfferDTO, ?>> allColumns() {
return columns;
}
#Override
protected TableMetadata constructMetadata() {
final TableMetadata metadata = new TableMetadata();
// TODO Consider a predefined set of ReferenceData to be held in a common package
// Use Slope
metadata.addColumnMetadata(UiMessages.INSTANCE.use_slope(), new String[] {UiMessages.INSTANCE.yes(), UiMessages.INSTANCE.no()}, new String[] {"true", "false"});
return metadata;
}
#Override
protected void initializeStructure(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
addHourColumn(sortHandler);
addUseSlopeColumn(metadata, sortHandler, currentDisplayMode);
for (int i = 0; i < MAX_NUMBER_OF_MW_PRICE_POINTS; i++) { // zero-based indexing
addPriceMwColumn(i, currentDisplayMode);
}
}
protected void addHourColumn(ListHandler<EnergyOfferDTO> sortHandler) {
final Column<EnergyOfferDTO, String> hourColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
String result = "";
if (energyOffer.getId() != null) {
final String isoDateTime = energyOffer.getId().getOperatingHour();
if (isoDateTime != null && !isoDateTime.isEmpty()) {
final Date dateTime = CSTimeUtil.isoToDate(isoDateTime);
if (dateTime != null) {
result = CSTimeUtil.dateToHour(dateTime);
}
}
}
return result;
}
};
hourColumn.setSortable(true);
sortHandler.setComparator(hourColumn, new Comparator<EnergyOfferDTO>() {
#Override
public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
final String date1 = eo1.getId() != null ? eo1.getId().getOperatingHour() : "";
final String date2 = eo2.getId() != null ? eo2.getId().getOperatingHour() : "";
return date1.compareTo(date2);
}
});
// We know that the data is sorted by hour by default.
getGrid(). getColumnSortList().push(hourColumn);
addColumn(hourColumn, UiMessages.INSTANCE.hour());
setColumnWidth(hourColumn, 45, Unit.PX);
setColumnHorizontalAlignment(hourColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addUseSlopeColumn(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
final ReferenceData refData = metadata.allColumnMetadata().get(UiMessages.INSTANCE.use_slope());
Column<EnergyOfferDTO, String> useSlopeColumn;
Cell<String> cell;
if (isInEditMode(currentDisplayMode)) {
cell = new ReferenceDataBackedSelectionCell(refData);
} else {
cell = new TextCell();
}
useSlopeColumn = new Column<EnergyOfferDTO, String>(cell) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return refData.getDisplayValueForSubmitValue(Boolean.toString(energyOffer.isSlopeUsed()));
}
};
useSlopeColumn.setSortable(true);
sortHandler.setComparator(useSlopeColumn, new Comparator<EnergyOfferDTO>() {
#Override
public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
final String slopeUsed1 = String.valueOf(eo1.isSlopeUsed());
final String slopeUsed2 = String.valueOf(eo1.isSlopeUsed());
return slopeUsed1.compareTo(slopeUsed2);
}
});
addColumn(useSlopeColumn, UiMessages.INSTANCE.use_slope());
setColumnWidth(useSlopeColumn, 75, Unit.PX);
setColumnHorizontalAlignment(useSlopeColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addPriceMwColumn(final int colIndex, DisplayMode currentDisplayMode) {
// Construct a composite cell for energy offers that includes a pair of text inputs
final List<HasCell<EnergyOfferDTO, ?>> columns = new ArrayList<
HasCell<EnergyOfferDTO, ?>>();
// this DTO is passed along so that price and mw values for new entries are kept together
final OfferPriceMwPair newOfferPriceMwPair = new OfferPriceMwPair();
// Price
final Column<EnergyOfferDTO, String> priceColumn = generatePriceColumn(colIndex, newOfferPriceMwPair, currentDisplayMode);
columns.add(priceColumn);
// MW
final Column<EnergyOfferDTO, String> mwColumn = generateMwColumn(colIndex, newOfferPriceMwPair, currentDisplayMode);
columns.add(mwColumn);
// Composite
final CompositeCell<EnergyOfferDTO> priceMwColumnInnards = generateCompositeCell(columns);
final IdentityColumn<EnergyOfferDTO> priceMwColumn = new IdentityColumn<EnergyOfferDTO>(priceMwColumnInnards);
final StringBuilder colHeader = new StringBuilder();
colHeader.append(UiMessages.INSTANCE.price_mw_header()).append(" ").append(String.valueOf(colIndex + 1));
addColumn(priceMwColumn, colHeader.toString());
setColumnWidth(priceMwColumn, 7, Unit.EM);
setColumnHorizontalAlignment(priceMwColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected Column<EnergyOfferDTO, String> generatePriceColumn(final int colIndex, final OfferPriceMwPair newOfferPriceMwPair, DisplayMode currentDisplayMode) {
Column<EnergyOfferDTO, String> priceColumn;
if (isInEditMode(currentDisplayMode)) {
priceColumn = new BigDecimalValidatableColumn<EnergyOfferDTO, OfferPriceMwPair>(nextTabIndex(), getGrid()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return obtainPriceValue(colIndex, energyOffer, false);
}
#Override
public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
if (value != null && !value.isEmpty()) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair == null) { // we have a new price value
newOfferPriceMwPair.setPrice(price);
offerPriceCurve.add(newOfferPriceMwPair);
} else {
offerPriceMwPair.setPrice(price);
}
}
}
#Override
protected String getPropertyName() {
return "price";
}
#Override
protected Class<OfferPriceMwPair> getPropertyOwner() {
return OfferPriceMwPair.class;
}
};
} else {
priceColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
final String result = obtainPriceValue(colIndex, energyOffer, true);
return result;
}
};
}
return priceColumn;
}
private String obtainPriceValue(final int colIndex, EnergyOfferDTO energyOffer, boolean withCurrency) {
String result = "";
if (energyOffer != null) {
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final int numberOfPairs = offerPriceCurve.size();
if (colIndex < numberOfPairs) {
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair != null) {
final BigDecimal price = offerPriceMwPair.getPrice();
if (price != null) {
final double value = price.doubleValue();
if (withCurrency) {
result = NumberFormat.getCurrencyFormat().format(value);
} else {
result = NumberFormat.getDecimalFormat().format(value);
}
}
}
}
}
return result;
}
protected Column<EnergyOfferDTO, String> generateMwColumn(final int colIndex, final OfferPriceMwPair newOfferPriceMwPair, DisplayMode currentDisplayMode) {
Column<EnergyOfferDTO, String> mwColumn;
if (isInEditMode(currentDisplayMode)) {
mwColumn = new BigDecimalValidatableColumn<EnergyOfferDTO, PriceMwPair>(nextTabIndex(), getGrid()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return obtainMwValue(colIndex, energyOffer);
}
#Override
public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
if (value != null && !value.isEmpty()) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal mw = BigDecimal.valueOf(valueAsDouble);
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair == null) { // we have a new price value
newOfferPriceMwPair.setMw(mw);
offerPriceCurve.add(newOfferPriceMwPair);
} else {
offerPriceMwPair.setMw(mw);
}
}
}
#Override
protected String getPropertyName() {
return "mw";
}
#Override
protected Class<PriceMwPair> getPropertyOwner() {
return PriceMwPair.class;
}
};
} else {
mwColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
final String result = obtainMwValue(colIndex, energyOffer);
return result;
}
};
}
return mwColumn;
}
private String obtainMwValue(final int colIndex, EnergyOfferDTO energyOffer) {
String result = "";
if (energyOffer != null) {
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final int numberOfPairs = offerPriceCurve.size();
if (colIndex < numberOfPairs) {
final PriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair != null) {
final BigDecimal mw = offerPriceMwPair.getMw();
if (mw != null) {
result = NumberFormat.getDecimalFormat().format(mw);
}
}
}
}
return result;
}
}
All that custom work w.r.t. WrapperCell and CompositeValidatableColumn was unnecessary.
It turns out that there's a way you should not construct CompositeCells. See http://code.google.com/p/google-web-toolkit/issues/detail?id=5714. My CompositeCells were not receiving events. So, I changed the way I construct them in ToggleableGrid.
protected CompositeCell<T> generateCompositeCell(final List<HasCell<T, String>> hasCells) {
final CompositeCell<T> compositeCell = new CompositeCell<T>(hasCells) {
// to not run afoul of http://code.google.com/p/google-web-toolkit/issues/detail?id=5714
#Override
public void render(Context context, T value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<div style=\"display: inline\">");
super.render(context, value, sb);
sb.appendHtmlConstant("</div>");
}
#Override
protected Element getContainerElement(Element parent) {
// Return the first element in the DIV.
return parent.getFirstChildElement();
}
};
return compositeCell;
}
After that change and incorporating my other validation-oriented classes: ValidatableFieldUpdater, AbstractValidatableColumn (and derivatives), ValidatableInputField and ConversionResult, life couldn't be more grand!