Vojtech Szocs has uploaded a new change for review. Change subject: webadmin: WiP column sorting ......................................................................
webadmin: WiP column sorting Work in progress, open for review. This patch introduces server-side table column sorting feature exposed through UI. It provides API/infra to make table columns sortable, assuming that corresponding SearchableListModel supports server-side sorting. Column sorting feature is showcased for "Name" column in "Data Centers" main tab. Changes in DataCenterListModel: @Override public boolean supportsServerSideSorting() { return true; } @Override protected void syncSearch() { SearchParameters tempVar = new SearchParameters( // getSearchString(), <- current code applySortOptions(getSearchString()), // <- change SearchType.StoragePool, isCaseSensitiveSearch() ); ... } In code above, we update search string with current sort options before running SearchQuery against the backend. Changes in MainTabDataCenterView: TextColumnWithTooltip<StoragePool> nameColumn = ... nameColumn.makeSortable("name"); // <- sort by field In code above, "Name" column is made sortable, clicking its header will update sort options on given list model (DataCenterListModel) and trigger model refresh, which in turn executes syncSearch method. Due to lack of consistent server-side sorting support across all queries, for now we can only support column sorting for list models (main and sub tabs) which use SearchQuery. (After moving to REST API, server-side sorting should be supported for all entities.) Change-Id: I141ea068fe90409852d34bea6fedb45d0d8a07ae Signed-off-by: Vojtech Szocs <vsz...@redhat.com> --- M frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/AbstractActionTable.java A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/SortableColumn.java M frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TextColumnWithTooltip.java M frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/SearchableListModel.java M frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/datacenters/DataCenterListModel.java M frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabDataCenterView.java 6 files changed, 127 insertions(+), 9 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/10/25910/1 diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/AbstractActionTable.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/AbstractActionTable.java index 73f8155..71ee0fe 100644 --- a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/AbstractActionTable.java +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/AbstractActionTable.java @@ -10,8 +10,10 @@ import org.ovirt.engine.ui.common.uicommon.model.SearchableTableModelProvider; import org.ovirt.engine.ui.common.widget.action.AbstractActionPanel; import org.ovirt.engine.ui.common.widget.label.NoItemsLabel; +import org.ovirt.engine.ui.common.widget.table.column.SortableColumn; import org.ovirt.engine.ui.uicommonweb.UICommand; import org.ovirt.engine.ui.uicommonweb.models.Model; +import org.ovirt.engine.ui.uicommonweb.models.SearchableListModel; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; @@ -34,7 +36,8 @@ import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.CellTable.Resources; import com.google.gwt.user.cellview.client.Column; -import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler; +import com.google.gwt.user.cellview.client.ColumnSortEvent; +import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo; import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy; import com.google.gwt.user.cellview.client.LoadingStateChangeEvent.LoadingState; import com.google.gwt.user.cellview.client.RowStyles; @@ -295,9 +298,8 @@ // Set up table data provider getDataProvider().addDataDisplay(table); - // Add default sort handler that delegates to the data provider - AsyncHandler columnSortHandler = new AsyncHandler(table); - table.addColumnSortHandler(columnSortHandler); + // Set up sort handler + initSortHandler(); // Set up table selection model table.setSelectionModel(selectionModel); @@ -369,6 +371,41 @@ enforceScrollPosition(); } + void initSortHandler() { + // Allow sorting by one column at a time + tableHeader.getColumnSortList().setLimit(1); + table.getColumnSortList().setLimit(1); + + // Attach column sort handler + ActionCellTable<T> tableWithHeader = isTableHeaderVisible() ? tableHeader : table; + tableWithHeader.addColumnSortHandler(new ColumnSortEvent.Handler() { + @Override + public void onColumnSort(ColumnSortEvent event) { + Object model = getDataProvider().getModel(); + Column<?, ?> column = event.getColumn(); + + if (model instanceof SearchableListModel) { + SearchableListModel<?> searchableModel = (SearchableListModel<?>) model; + String sortBy = null; + + // Explicit null check to make it clear that null column should reset sort + if (column != null && column instanceof SortableColumn) { + SortableColumn<?, ?> sortableColumn = (SortableColumn<?, ?>) column; + sortBy = sortableColumn.getSortBy(); + } + + // Apply sort options to model + searchableModel.setSortOptions(sortBy, event.isSortAscending()); + + // Synchronize column sort info + ColumnSortInfo columnSortInfo = event.getColumnSortList().get(0); + tableHeader.getColumnSortList().push(columnSortInfo); + table.getColumnSortList().push(columnSortInfo); + } + } + }); + } + void enforceScrollPosition() { tableContainer.getElement().setScrollLeft(tableContainerHorizontalScrollPosition); updateTableHeaderPosition(); diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/SortableColumn.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/SortableColumn.java new file mode 100644 index 0000000..386c0c9 --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/SortableColumn.java @@ -0,0 +1,29 @@ +package org.ovirt.engine.ui.common.widget.table.column; + +import com.google.gwt.cell.client.Cell; +import com.google.gwt.user.cellview.client.Column; + +public abstract class SortableColumn<T, C> extends Column<T, C> { + + private String sortBy; + + public SortableColumn(Cell<C> cell) { + super(cell); + } + + /** + * Returns the name of the field to sort by, effective only when sorting is requested by the user on this column. + */ + public String getSortBy() { + return sortBy; + } + + /** + * Makes this column sortable, passing the name of the field to sort by. + */ + public void makeSortable(String sortBy) { + setSortable(true); + this.sortBy = sortBy; + } + +} diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TextColumnWithTooltip.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TextColumnWithTooltip.java index 719f9d4..714d16e 100644 --- a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TextColumnWithTooltip.java +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TextColumnWithTooltip.java @@ -1,6 +1,5 @@ package org.ovirt.engine.ui.common.widget.table.column; -import com.google.gwt.user.cellview.client.Column; /** * Column for displaying text using {@link TextCellWithTooltip}. @@ -8,7 +7,7 @@ * @param <T> * Table row data type. */ -public abstract class TextColumnWithTooltip<T> extends Column<T, String> implements ColumnWithElementId { +public abstract class TextColumnWithTooltip<T> extends SortableColumn<T, String> implements ColumnWithElementId { public TextColumnWithTooltip() { this(TextCellWithTooltip.UNLIMITED_LENGTH); diff --git a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/SearchableListModel.java b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/SearchableListModel.java index fe27f60..188fda7 100644 --- a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/SearchableListModel.java +++ b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/SearchableListModel.java @@ -711,9 +711,57 @@ /** * Override this method to take care on sync fetching. + * <p> + * If server-side sorting is supported when fetching items: + * <ul> + * <li>override {@link #supportsServerSideSorting} to return {@code true} + * <li>make sure {@link #syncSearch} implementation takes current sort options into account + * </ul> */ - protected void syncSearch() - { + protected void syncSearch() { + } + + // Name of the field to sort by, null for undefined sort order + protected String sortBy; + + // Sort direction, effective only when sortBy != null + protected boolean sortAscending = true; + + /** + * Updates current sort options, performing {@link #refresh} if necessary. + */ + public void setSortOptions(String sortBy, boolean sortAscending) { + boolean shouldRefresh = (this.sortBy == null && sortBy != null) + || (this.sortBy != null && sortBy == null) + || (!this.sortBy.equals(sortBy)); + shouldRefresh = shouldRefresh || this.sortAscending != sortAscending; + + this.sortBy = sortBy; + this.sortAscending = sortAscending; + + if (shouldRefresh) { + refresh(); + } + } + + /** + * Returns the given {@code searchQuery} with current sort options applied. + */ + protected String applySortOptions(String searchQuery) { + String result = searchQuery; + + if (sortBy != null) { + result += " SORTBY " + sortBy + " " + (sortAscending ? "ASC" : "DESC"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + return result; + } + + /** + * Returns {@code true} if this model's {@link #syncSearch} implementation supports server-side sorting. + */ + public boolean supportsServerSideSorting() { + return false; } private Comparator<T> comparator; diff --git a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/datacenters/DataCenterListModel.java b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/datacenters/DataCenterListModel.java index 815d1da..6bbc917 100644 --- a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/datacenters/DataCenterListModel.java +++ b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/datacenters/DataCenterListModel.java @@ -262,10 +262,14 @@ @Override protected void syncSearch() { - SearchParameters tempVar = new SearchParameters(getSearchString(), SearchType.StoragePool, isCaseSensitiveSearch()); + SearchParameters tempVar = new SearchParameters(applySortOptions(getSearchString()), SearchType.StoragePool, isCaseSensitiveSearch()); tempVar.setMaxCount(getSearchPageSize()); super.syncSearch(VdcQueryType.Search, tempVar); + } + @Override + public boolean supportsServerSideSorting() { + return true; } public void newEntity() diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabDataCenterView.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabDataCenterView.java index 13bb2a3..4c95667 100644 --- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabDataCenterView.java +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabDataCenterView.java @@ -54,6 +54,7 @@ return object.getName(); } }; + nameColumn.makeSortable("name"); //$NON-NLS-1$ getTable().addColumn(nameColumn, constants.nameDc(), "150px"); //$NON-NLS-1$ CommentColumn<StoragePool> commentColumn = new CommentColumn<StoragePool>(); -- To view, visit http://gerrit.ovirt.org/25910 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I141ea068fe90409852d34bea6fedb45d0d8a07ae Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Vojtech Szocs <vsz...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches