GWT Sorting after filtering a table - gwt

I have a simple table (CellTable) and a TextBox for filter.
Values for CellTable I take from backend. After list of items is loaded I can put some filter string to get suitable result. To filter list from dataprovider I use a predicate. After filtering I set result to CellTable.
Like here:
void onFilterNameKeyUp(KeyUpEvent e) {
List<CustomerDTO> filtered = this.dataProvider.getList();
Predicate<CustomerDTO> filter = new Predicate<CustomerDTO>() {
#Override
public boolean apply(CustomerDTO input) {
if (input.getName() == null) {
return false;
} else {
return input.getName().toLowerCase()
.contains(filterName.getValue().toLowerCase());
}
}
};
filtered = Lists.newArrayList(Iterables.filter(this.dataProvider.getList(), filter));
this.customerList.setRowCount(filtered.size(), true);
this.customerList.setRowData(0, filtered);
}
this.dataProvider = new ListDataProvider<CustomerDTO>();
dataProvider.addDataDisplay(this.customerList);
final ListHandler<CustomerDTO> sortHandler = new ListHandler<CustomerDTO>(
this.dataProvider.getList());
this.customerList.addColumnSortHandler(sortHandler);
this.customerList.getColumnSortList().push(this.rbKeyNameColumn);
Everything work fine but I have also a sort handler for first column of this table and when I want to sort a list then I'm sorting original list of items.
How to solve this problem? It means that I want to sort and display filtered list instead of original list from dataprovider.
Please help.

I have a table changing content after receiving some data from the server. This is my approach:
public void onSuccess(List<List<String>> result) {
List<Product> list = dataProvider.getList();
list.clear();
r_tableproducts.setRowCount(result.size());
for (List<String> l : result) {
list.add(new Product(l));
}
r_tableproducts.getColumnSortList().clear();
r_tableproducts.getColumnSortList().push(r_tableproducts.getColumn(1));
ColumnSortEvent.fire(r_tableproducts,r_tableproducts.getColumnSortList());
}
This sorts my list using 2nd column after reciving new data (overriding all old data).
Maybe try this approach? Filter your data in a new list and modify the list your dataProvider provides you, adding all elements.
Something like:
List<CustomerDTO> result = Lists.newArrayList(Iterables.filter(this.dataProvider.getList(), filter));
this.customerList.setRowCount(result.size(), true);
this.dataProvider.getList().clear();
this.dataProvider.getList().addAll(result);

You need to separate the dataProvider that holds the full list and provide a separate "filtered" data provider that will be driving the display of the cellTable. The cellTable in below example is bound to a filteredDataProvider for sorting, display purposes.
The code below is to give a general idea and therefore may not be syntactically accurate.
void onFilterNameKeyUp(KeyUpEvent e) {
List<CustomerDTO> filtered = this.dataProvider.getList();
Predicate<CustomerDTO> filter = new Predicate<CustomerDTO>() {
#Override
public boolean apply(CustomerDTO input) {
if (input.getName() == null) {
return false;
} else {
return input.getName().toLowerCase()
.contains(filterName.getValue().toLowerCase());
}
}
};
filtered = Lists.newArrayList(Iterables.filter(this.dataProvider.getList(), filter));
this.customerList.setRowCount(filtered.size(), true);
this.filteredDataProvider.getList().clear();
this.filteredDataProvider.getList().addAll(filtered);
}
this.dataProvider = new ListDataProvider<CustomerDTO>();
// Code here to populate the dataProvider
this.filteredDataProvider = new ListDataProvider<CustomerDTO>();
// Creating separate DataProvider to hold the filtered set
this.filteredDataProvider.getList().addAll(this.dataProvider.getList());
filteredDataProvider.addDataDisplay(this.customerList);
// dataProvider.addDataDisplay(this.customerList);
// Sort Handler uses filteredDataProvider instead of the dataProvider with full list
final ListHandler<CustomerDTO> sortHandler = new ListHandler<CustomerDTO>(
this.filteredDataProvider.getList());
this.customerList.addColumnSortHandler(sortHandler);
this.customerList.getColumnSortList().push(this.rbKeyNameColumn);

Related

GWT DataGrid header click event for sorting

I want to know if user clicked on header for Ascending or Descending sorting.
How can I find that?
Regards
Try this:
1) create SortHandler and attach to your grid
ColumnSortEvent.AsyncHandler sortHandler= new ColumnSortEvent.AsyncHandler(grid);
grid.addColumnSortHandler(sortHandler);
ColumnSortList columnSortList = grid.getColumnSortList();
2) create your Column (TextColumn etc) such as:
TextColumn<Dog> yourTextColumn = new TextColumn<Dog>() {
#Override
public String getValue(String object) {
return object;
}
}
3) create your Header
Header yourHeader = new Header() {
#Override
public Object getValue() {
return value; // here return header value
}
}
3) add column to grid and push a ColumnSortInfo onto the list
grid.addColumn(yourTextColumn, yourHeader);
columnSortList.push(new ColumnSortList.ColumnSortInfo(yourColumn, true));
You can always look here for more useful examples.
in order to get the direction of the ordering, all you have to do is to get the ColumnSortList and call method #get(0) with zero index. as documentation of ColumnSortList says the "The 0th item is the {#link ColumnSortInfo} of the most recently sorted * column.". so the returned object (which is ColumnSortList.ColumnSortInfo) contains information about last clicked Column and it has a method called #isAscending() which is a flag to identify the direction.
the sample code:
ColumnSortList sortList = dataGrid.getColumnSortList();
ColumnSortList.ColumnSortInfo info = sortList.get(0);
also want to note that this code block should be in AsyncDataProvider#onRangeChanged.
there is also an alternative to this, consider the following:
columnSortHandler = new ColumnSortEvent.AsyncHandler(table) {
#Override
public void onColumnSort(ColumnSortEvent event) {
List<T> newData = new ArrayList(table.getVisibleItems());
if (event.isSortAscending()) {
Collections.sort(newData, (Comparator)event.getColumn());
} else {
Collections.sort(newData, (Comparator)event.getColumn());
Collections.reverse(newData);
}
table.setRowData(newData);
}
};
table.addColumnSortHandler(columnSortHandler);

dynamically select a checkbox for siblings treenode in Smart GWT

I have a selectable Tree with checkbox appearance. I need to select all sibling TreeNode on selection of a specific TreeNode.
I could get all the sibling tree nodes, but I don't know what is the attribute name of TreeNode to make that checkbox selected.
Can anybody help me giving some way to select those nodes.
compareGrid.addSelectionChangedHandler(new SelectionChangedHandler() {
#Override
public void onSelectionChanged(SelectionEvent event) {
TreeNode node = (TreeNode) event.getSelectedRecord();
TreeNode parent = tree.getParent(node);//tree is Tree object
treeGrid.selectRecord(parent);
TreeNode[] nodes = tree.getAllNodes(parent);
for(int i=0; i< nodes.length; i++){
if(!nodes[i].getAttributeAsBoolean("isSelected"))
treeGrid.selectRecord(nodes[i]);
}
}
}
});
You can use any of the following:
treeGrid.selectAllRecords();
treeGrid.selectRecord(record);
treeGrid.selectRecords(records);
The first method will select all the TreeNodes of the tree.
The 2nd one will select only one specified TreeNodes of the tree.
And the 3rd one will select multiple specified TreeNodes of the tree.
There are multiple overloaded methods for the last 2 methods, which allows you to specify Nodes in terms of, TreeNode(s) itself, or index of the TreeNode(s).
Here's a solution quite close (without checkboxes) to what you need.
employeeTreeGrid.addNodeClickHandler(new NodeClickHandler() {
public void onNodeClick(NodeClickEvent event) {
if (event.getNode() != null) {
TreeNode node = event.getNode();
TreeNode parent = employeeTree.getParent(node);
if (employeeTreeGrid.isSelected(node)) {
List<TreeNode> nodesToSelect = new ArrayList<TreeNode>();
// omit parent (root) if on first level
if (!"1".equals(node.getAttribute("ReportsTo"))) {
nodesToSelect.add(parent);
}
TreeNode[] siblings = employeeTree.getChildren(parent);
nodesToSelect.addAll(Arrays.asList(siblings));
RecordList recordList = employeeTreeGrid.getOriginalRecordList();
for (TreeNode treeNode : nodesToSelect) {
Record record = recordList.find("EmployeeId", treeNode.getAttribute("EmployeeId"));
if (record != null) {
employeeTreeGrid.selectRecord(record);
}
}
}
}
}
});
Have to use the RecordList and first find required records in order to use ListGrid.selectRecord() methods.
Using SelectionAppearance.CHECKBOX and SelectionChangedHandler can be tricky as programmatic selections are going to trigger further selection events.
This is based on Checkbox tree sample with below changes.
// employeeTreeGrid.setSelectionAppearance(SelectionAppearance.CHECKBOX);
// employeeTreeGrid.setShowSelectedStyle(false);
employeeTreeGrid.setShowPartialSelection(false);
// employeeTreeGrid.setCascadeSelection(true);
employeeTreeGrid.setSelectionType(SelectionStyle.SIMPLE);
To get the value of selected checkbox from tree grid in smart gwt I have following solution ListGridRecord[] arrRec = event.getSelection(); sample code is below.
employeeTreeGrid.setSelectionAppearance(SelectionAppearance.CHECKBOX);
employeeTreeGrid.setSelectionType(SelectionStyle.SIMPLE);
employeeTreeGrid.addSelectionChangedHandler(new SelectionChangedHandler() {
#Override
public void onSelectionChanged(SelectionEvent event)
//selectedCounties Set to add selected checkbox or deslected checkbox names/title
if (selectedCounties == null || selectedCounties.size() == 0)
selectedCounties = new TreeSet<String>();
selectedCounties.clear();
ListGridRecord[] arrRec = event.getSelection();
for (ListGridRecord listGridRecord : arrRec) {
selectedCounties.add(listGridRecord.getAttribute("Name"));
}
// You can do iteration over it if needed
selectedCounties.remove("All Counties");
Iterator<String> it = selectedCounties.iterator();
while (it.hasNext()) {
if (it.next().contains("Zone")) {
it.remove();
}
}
}
});

Adding links to a row in a column on click (CellTable)

I have a CellTable where I want to add several links to a row when I click an add button. Right now Im facing the problem that when I click the add button the link will be added to all rows in that column. Somehow it feels like I only can add things to columns.
// shows project column
final MultipleLinkTextCell projectCell = new MultipleLinkTextCell();
final Column<Booking, String> projectColumn = new Column<Booking, String>(
projectCell) {
#Override
public String getValue(Booking project) {
return "";
}
};
getView().getTimeTable().addColumn(projectColumn, "Tasks");
An Example with Buttons
#Override
protected void render(com.google.gwt.cell.client.Cell.Context context,
SafeHtml data, SafeHtmlBuilder sb) {
String string = "";
for (int i = 0; i < value; i++) {
string += "<button type=\"button\" style=\" height:20px; width:22px\">";
}
sb.appendHtmlConstant(string);
if (data != null) {
sb.append(data);
}
}
Im thinking about to use the Anchor widget because I can handle the placemanager from gwtp with it. But still I dont know how to add widgets to a specific row.
//Update:
I did it like this now, it works, but its better to use the revealmanager. The hardcoded link is kinda bad because I always need to change the reference to the link when I change the webserver. I get a string with several values splitted by a commar.
#Override
protected void render(com.google.gwt.cell.client.Cell.Context context,
SafeHtml data, SafeHtmlBuilder sb) {
String stringData = data.asString();
String[] splitResult = stringData.split(",");
for (int i = 0; i < splitResult.length; i++) {
if (!splitResult[i].equals("")) {
sb.appendHtmlConstant("<div><a href=\"http://127.0.0.1:8888/gwtpTimeTracking.html?gwt.codesvr=127.0.0.1:9997#project;projectid="+splitResult[i].substring(0, 7)+"\">"
+ splitResult[i].substring(0, 7) + "</a></div>");
}
}
You can't use any Widgets in CellWidgets.
However you can create your custom cell that mimics it or create an ActionCell and add a VaueUpdater that fires a PlaceRequest Event.
For adding the link to a specific row you have to add a field (i..e List<String> links) to your DTO that is rendered in your CellTable. When you click on the "Add" button you have to modify the field of the specific DTO in your list.
MyDTO obj = // get the specific DTO from the DataProvider
obj.setLinks(LIST OF LINKS);
In the render method of your custom cell you check the field (i..e links) and either render out the links or not.
Where does the value data in your render method come from ?

Sortable ListView in Apache WIcket

I have successfully displayed data in tabular form using ListView. However, I wanted it to be sortable. How do I go about doing this?
Hmm.. Perhaps DefaultDataTable could have been better suited for your use case of displaying tabular data in a sortable fashion. Let me know if you need more explanation or a code example.
You can just sort the List that you pass to ListView.
Something like:
final SortState sort = SortState.ByName;
add(new ListView(id, new AbstractReadOnlyModel<ArrayList<Person>>() {
public ArrayList<Person> getObject() {
ArrayList<Person> list = makeList();
Comparator<Person> comparator = getComparator(sort);
Collections.sort(comparator, list);
return list;
}
});
add(new Link(sortByAgeLinkId) {
public void onClick() { sort = SortState.ByAge;}
});
... more links for different criteria.

Creating custom ActionCell in CellTable Column

I want one of my table columns to have a deleteButton.
ActionCell<Entrata> deleteCell = new ActionCell<Entrata>("x",new Delegate<Entrata>() {
#Override
public void execute(Entrata object) {
// rpc stuff....
}
});
Ok but this line generates an error:
Column<Entrata,Entrata> deleteColumn = new Column<Entrata, Entrata>(deleteCell);
"Cannot instantiate the type Column"
What do you think?
Here you go with working code:
Assumptions:
TYPE - Is the class of the data you show in rows of Cell Table it the same because I assume you want reference to the instance of data when you going to delete it
public class DeleteColumn extends Column<TYPE, TYPE>
{
public DeleteColumn()
{
super(new ActionCell<TYPE>("Delete", new ActionCell.Delegate<TYPE>() {
#Override
public void execute(TYPE record)
{
/**
*Here you go. You got a reference to an object in a row that delete was clicked. Put your "delete" code here
*/
}
}));
}
#Override
public TYPE getValue(TYPE object)
{
return object;
}
};
From the doku:
A representation of a column in a table. The column may maintain view data for each cell on demand. New view data, if needed, is created by the cell's onBrowserEvent method, stored in the Column, and passed to future calls to Cell's
So you have to declar it something like this:
Column<String, String> colum = new Column<String, String>(null) {
#Override
public String getValue(String object) {
// TODO Auto-generated method stub
return null;
}
};
Still I don't exactly know how you implement the delete button, so it would be nice if you can give us the rest of your code.
This works
//table = initialized CellTable with content already loaded
ActionCell editCell = new ActionCell<EmployeeObject>("remove", new ActionCell.Delegate<EmployeeObject>() {
public void execute(EmployeeObject object){
List<EmployeeObject> list = new ArrayList<EmployeeObject>(table.getVisibleItems());
for(int i = 0; i < list.size(); i ++){
if(object.getFirstname().equals(list.get(i).getFirstname())){
list.remove(i);
break;
}
}
table.setRowData(list);
}
});
Column<EmployeeObject, ActionCell> editColumn = (new IdentityColumn(editCell));