diff options
author | Patrik Lindström <patrik@vaadin.com> | 2014-06-17 18:30:04 +0300 |
---|---|---|
committer | Patrik Lindström <patrik@vaadin.com> | 2014-06-26 16:15:05 +0300 |
commit | 6294a26ab8ae5df83d25318c4a8b14db34f5b8a4 (patch) | |
tree | 6513a1c58d8b0e9b1699981269c630335ddd858b /client | |
parent | f4a538019bc6c5abeeb453d9f116088d03d7c32f (diff) | |
download | vaadin-framework-6294a26ab8ae5df83d25318c4a8b14db34f5b8a4.tar.gz vaadin-framework-6294a26ab8ae5df83d25318c4a8b14db34f5b8a4.zip |
Implement Grid client-side Sorting API (#13334)
Change-Id: I9ab18c93bdc1aaf66aa2701c3939311671a60f04
Diffstat (limited to 'client')
7 files changed, 626 insertions, 108 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index dfcda40b04..1739e28608 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -49,16 +49,21 @@ import com.vaadin.client.ui.grid.selection.SelectionModel; import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.client.ui.grid.selection.SelectionModelNone; import com.vaadin.client.ui.grid.selection.SelectionModelSingle; +import com.vaadin.client.ui.grid.sort.Sort; +import com.vaadin.client.ui.grid.sort.SortEvent; +import com.vaadin.client.ui.grid.sort.SortEventHandler; +import com.vaadin.client.ui.grid.sort.SortOrder; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; +import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.shared.util.SharedUtil; /** * A data grid view that supports columns and lazy loading of data rows from a * data source. - * + * * <h3>Columns</h3> * <p> * The {@link GridColumn} class defines the renderer used to render a cell in @@ -72,15 +77,15 @@ import com.vaadin.shared.util.SharedUtil; * specific column index using {@link Grid#getColumn(int)}. * </p> * <p> - * + * * TODO Explain about headers/footers once the multiple header/footer api has * been implemented - * + * * <h3>Data sources</h3> * <p> * TODO Explain about what a data source is and how it should be implemented. * </p> - * + * * @param <T> * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. @@ -213,6 +218,12 @@ public class Grid<T> extends Composite implements */ private GridColumn<?, T> lastFrozenColumn; + /** + * Current sort order. The (private) sort() method reads this list to + * determine the order in which to present rows. + */ + private List<SortOrder> sortOrder = new ArrayList<SortOrder>(); + private Renderer<Boolean> selectColumnRenderer = null; private SelectionColumn selectionColumn; @@ -269,10 +280,10 @@ public class Grid<T> extends Composite implements /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. - * + * * @param <C> * the column type - * + * * @param <T> * the row type */ @@ -320,7 +331,7 @@ public class Grid<T> extends Composite implements /** * Constructs a new column with a custom renderer. - * + * * @param renderer * The renderer to use for rendering the cells */ @@ -334,7 +345,7 @@ public class Grid<T> extends Composite implements /** * Constructs a new column with custom renderers for rows, header and * footer cells. - * + * * @param bodyRenderer * The renderer to use for rendering body cells * @param headerRenderer @@ -355,7 +366,7 @@ public class Grid<T> extends Composite implements /** * Internally used by the grid to set itself - * + * * @param grid */ private void setGrid(Grid<T> grid) { @@ -371,7 +382,7 @@ public class Grid<T> extends Composite implements /** * Gets text in the header of the column. By default the header caption * is empty. - * + * * @return the text displayed in the column caption */ public String getHeaderCaption() { @@ -380,7 +391,7 @@ public class Grid<T> extends Composite implements /** * Returns the renderer used for rendering the header cells - * + * * @return a renderer that renders header cells */ public Renderer<String> getHeaderRenderer() { @@ -389,7 +400,7 @@ public class Grid<T> extends Composite implements /** * Sets the renderer that renders header cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering header cells. */ @@ -405,7 +416,7 @@ public class Grid<T> extends Composite implements /** * Returns the renderer used for rendering the footer cells - * + * * @return a renderer that renders footer cells */ public Renderer<String> getFooterRenderer() { @@ -414,7 +425,7 @@ public class Grid<T> extends Composite implements /** * Sets the renderer that renders footer cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering footer cells. */ @@ -430,7 +441,7 @@ public class Grid<T> extends Composite implements /** * Sets the text in the header of the column. - * + * * @param caption * the text displayed in the column header */ @@ -449,7 +460,7 @@ public class Grid<T> extends Composite implements /** * Gets text in the footer of the column. By default the footer caption * is empty. - * + * * @return The text displayed in the footer of the column */ public String getFooterCaption() { @@ -458,7 +469,7 @@ public class Grid<T> extends Composite implements /** * Sets text in the footer of the column. - * + * * @param caption * the text displayed in the footer of the column */ @@ -476,7 +487,7 @@ public class Grid<T> extends Composite implements /** * Is the column visible. By default all columns are visible. - * + * * @return <code>true</code> if the column is visible */ @Override @@ -486,7 +497,7 @@ public class Grid<T> extends Composite implements /** * Sets a column as visible in the grid. - * + * * @param visible * <code>true</code> if the column should be displayed in the * grid @@ -515,19 +526,26 @@ public class Grid<T> extends Composite implements } /** - * Returns the data that should be rendered into the cell. - * + * Returns the data that should be rendered into the cell. By default + * returning Strings and Widgets are supported. If the return type is a + * String then it will be treated as preformatted text. + * <p> + * To support other types you will need to pass a custom renderer to the + * column via the column constructor. + * * @param row * The row object that provides the cell content. - * + * * @return The cell content */ public abstract C getValue(T row); /** - * Returns the renderer used to render the cells of this column. - * - * @return the renderer to render the cell content with + * The renderer to render the cell width. By default renders the data as + * a String or adds the widget into the cell if the column type is of + * widget type. + * + * @return The renderer to render the cell content with */ public Renderer<? super C> getRenderer() { return bodyRenderer; @@ -535,7 +553,7 @@ public class Grid<T> extends Composite implements /** * Finds the index of this column instance - * + * */ private int findIndexOfColumn() { return grid.findVisibleColumnIndex((GridColumn<?, T>) this); @@ -544,7 +562,7 @@ public class Grid<T> extends Composite implements /** * Sets the pixel width of the column. Use a negative value for the grid * to autosize column based on content and available space - * + * * @param pixels * the width in pixels or negative for auto sizing */ @@ -561,7 +579,7 @@ public class Grid<T> extends Composite implements /** * Returns the pixel width of the column - * + * * @return pixel width of the column */ public int getWidth() { @@ -594,7 +612,7 @@ public class Grid<T> extends Composite implements /** * Constructs an updater for updating a header / footer - * + * * @param rows * The row container * @param inverted @@ -607,17 +625,17 @@ public class Grid<T> extends Composite implements /** * Gets the header/footer caption value - * + * * @param column * The column to get the value for. - * + * * @return The value that should be rendered for the column caption */ public abstract String getColumnValue(GridColumn<?, T> column); /** * Gets the group caption value - * + * * @param group * The group for with the caption value should be returned * @return The value that should be rendered for the column caption @@ -626,34 +644,34 @@ public class Grid<T> extends Composite implements /** * Is the row visible in the header/footer - * + * * @param row * the row to check - * + * * @return <code>true</code> if the row should be visible */ public abstract boolean isRowVisible(ColumnGroupRow<T> row); /** * Should the first row be visible - * + * * @return <code>true</code> if the first row should be visible */ public abstract boolean firstRowIsVisible(); /** * The renderer that renders the cell - * + * * @param column * The column for which the cell should be rendered - * + * * @return renderer used for rendering */ public abstract Renderer<String> getRenderer(GridColumn<?, T> column); /** * The renderer that renders the cell for column groups - * + * * @param group * The group that should be rendered * @return renderer used for rendering @@ -780,7 +798,7 @@ public class Grid<T> extends Composite implements /** * Creates the header updater that updates the escalator header rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { @@ -950,7 +968,7 @@ public class Grid<T> extends Composite implements /** * Creates the footer updater that updates the escalator footer rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { @@ -990,7 +1008,7 @@ public class Grid<T> extends Composite implements /** * Refreshes header or footer rows on demand - * + * * @param rows * The row container * @param firstRowIsVisible @@ -1042,7 +1060,7 @@ public class Grid<T> extends Composite implements /** * Adds a column as the last column in the grid. - * + * * @param column * the column to add */ @@ -1052,7 +1070,7 @@ public class Grid<T> extends Composite implements /** * Inserts a column into a specific position in the grid. - * + * * @param index * the index where the column should be inserted into * @param column @@ -1161,7 +1179,7 @@ public class Grid<T> extends Composite implements /** * Removes a column from the grid. - * + * * @param column * the column to remove */ @@ -1196,7 +1214,7 @@ public class Grid<T> extends Composite implements /** * Returns the amount of columns in the grid. - * + * * @return The number of columns in the grid */ public int getColumnCount() { @@ -1205,7 +1223,7 @@ public class Grid<T> extends Composite implements /** * Returns a list of columns in the grid. - * + * * @return A unmodifiable list of the columns in the grid */ public List<GridColumn<?, T>> getColumns() { @@ -1215,7 +1233,7 @@ public class Grid<T> extends Composite implements /** * Returns a column by its index in the grid. - * + * * @param index * the index of the column * @return The column in the given index @@ -1232,30 +1250,30 @@ public class Grid<T> extends Composite implements /** * Set the column headers visible. - * + * * <p> * A column header is a single cell header on top of each column reserved * for a specific header for that column. The column header can be set by * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be * merged with other column headers. * </p> - * + * * <p> * All column headers occupy the first header row of the grid. If you do not * wish to show the column headers in the grid you should hide the row by * setting visibility of the header row to <code>false</code>. * </p> - * + * * <p> * If you want to merge the column headers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * header. See {@link #addColumnGroupRow()} for details. * </p> - * + * * <p> * The header row is by default visible. * </p> - * + * * @param visible * <code>true</code> if header rows should be visible */ @@ -1269,7 +1287,7 @@ public class Grid<T> extends Composite implements /** * Are the column headers visible - * + * * @return <code>true</code> if they are visible */ public boolean isColumnHeadersVisible() { @@ -1278,30 +1296,30 @@ public class Grid<T> extends Composite implements /** * Set the column footers visible. - * + * * <p> * A column footer is a single cell footer below of each column reserved for * a specific footer for that column. The column footer can be set by * {@link GridColumn#setFooterCaption(String)} and column footers cannot be * merged with other column footers. * </p> - * + * * <p> * All column footers occupy the first footer row of the grid. If you do not * wish to show the column footers in the grid you should hide the row by * setting visibility of the footer row to <code>false</code>. * </p> - * + * * <p> * If you want to merge the column footers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * footer. See {@link #addColumnGroupRow()} for details. * </p> - * + * * <p> * The footer row is by default hidden. * </p> - * + * * @param visible * <code>true</code> if the footer row should be visible */ @@ -1315,9 +1333,9 @@ public class Grid<T> extends Composite implements /** * Are the column footers visible - * + * * @return <code>true</code> if they are visible - * + * */ public boolean isColumnFootersVisible() { return columnFootersVisible; @@ -1325,15 +1343,15 @@ public class Grid<T> extends Composite implements /** * Adds a new column group row to the grid. - * + * * <p> * Column group rows are rendered in the header and footer of the grid. * Column group rows are made up of column groups which groups together * columns for adding a common auxiliary header or footer for the columns. * </p> - * + * * Example usage: - * + * * <pre> * // Add a new column group row to the grid * ColumnGroupRow row = grid.addColumnGroupRow(); @@ -1347,7 +1365,7 @@ public class Grid<T> extends Composite implements * // Set a common footer for "Column1" and "Column2" * column12.setFooter("Column 1&2"); * </pre> - * + * * @return a column group row instance you can use to add column groups */ public ColumnGroupRow<T> addColumnGroupRow() { @@ -1360,10 +1378,10 @@ public class Grid<T> extends Composite implements /** * Adds a new column group row to the grid at a specific index. - * + * * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example * usage - * + * * @param rowIndex * the index where the column group row should be added * @return a column group row instance you can use to add column groups @@ -1378,7 +1396,7 @@ public class Grid<T> extends Composite implements /** * Removes a column group row - * + * * @param row * The row to remove */ @@ -1390,9 +1408,9 @@ public class Grid<T> extends Composite implements /** * Get the column group rows - * + * * @return a unmodifiable list of column group rows - * + * */ public List<ColumnGroupRow<T>> getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList<ColumnGroupRow<T>>( @@ -1401,7 +1419,7 @@ public class Grid<T> extends Composite implements /** * Returns the column group for a row and column - * + * * @param row * The row of the column * @param column @@ -1425,7 +1443,7 @@ public class Grid<T> extends Composite implements * <p> * <em>Note:</em> This method will change the widget's size in the browser * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}. - * + * * @see #setHeightMode(HeightMode) */ @Override @@ -1440,7 +1458,7 @@ public class Grid<T> extends Composite implements /** * Sets the data source used by this grid. - * + * * @param dataSource * the data source to use, not null * @throws IllegalArgumentException @@ -1493,7 +1511,7 @@ public class Grid<T> extends Composite implements * <p> * All columns up to and including the given column will be frozen in place * when the grid is scrolled sideways. - * + * * @param lastFrozenColumn * the rightmost column to freeze, or <code>null</code> to not * have any columns frozen @@ -1526,7 +1544,7 @@ public class Grid<T> extends Composite implements * <em>Note:</em> Most usually, this method returns the very value set with * {@link #setLastFrozenColumn(GridColumn)}. This value, however, can be * reset to <code>null</code> if the column is removed from this grid. - * + * * @return the rightmost frozen column in the grid, or <code>null</code> if * no columns are frozen. */ @@ -1546,7 +1564,7 @@ public class Grid<T> extends Composite implements /** * Scrolls to a certain row, using {@link ScrollDestination#ANY}. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @throws IllegalArgumentException @@ -1560,7 +1578,7 @@ public class Grid<T> extends Composite implements /** * Scrolls to a certain row, using user-specified scroll destination. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1579,7 +1597,7 @@ public class Grid<T> extends Composite implements /** * Scrolls to a certain row using only user-specified parameters. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1636,7 +1654,7 @@ public class Grid<T> extends Composite implements * <p> * If Grid is currently not in {@link HeightMode#ROW}, the given value is * remembered, and applied once the mode is applied. - * + * * @param rows * The height in terms of number of rows displayed in Grid's * body. If Grid doesn't contain enough rows, white space is @@ -1648,7 +1666,7 @@ public class Grid<T> extends Composite implements * infinite} * @throws IllegalArgumentException * if {@code rows} is {@link Double#isNaN(double) NaN} - * + * * @see #setHeightMode(HeightMode) */ public void setHeightByRows(double rows) throws IllegalArgumentException { @@ -1660,7 +1678,7 @@ public class Grid<T> extends Composite implements * {@link #getHeightMode()} is {@link HeightMode#ROW}. * <p> * By default, it is {@value Escalator#DEFAULT_HEIGHT_BY_ROWS}. - * + * * @return the amount of rows that should be shown in Grid's body, while in * {@link HeightMode#ROW}. * @see #setHeightByRows(double) @@ -1680,7 +1698,7 @@ public class Grid<T> extends Composite implements * <em>Note:</em> If headers/footers are inserted or removed, the widget * will resize itself to still display the required amount of rows in its * body. It also takes the horizontal scrollbar into account. - * + * * @param heightMode * the mode in to which Grid should be set */ @@ -1702,7 +1720,7 @@ public class Grid<T> extends Composite implements * Returns the current {@link HeightMode} the Grid is in. * <p> * Defaults to {@link HeightMode#CSS}. - * + * * @return the current HeightMode */ public HeightMode getHeightMode() { @@ -1865,7 +1883,7 @@ public class Grid<T> extends Composite implements /** * Accesses the package private method Widget#setParent() - * + * * @param widget * The widget to access * @param parent @@ -1878,7 +1896,7 @@ public class Grid<T> extends Composite implements /** * Sets the current selection model. - * + * * @param selectionModel * a selection model implementation. * @throws IllegalArgumentException @@ -1896,7 +1914,7 @@ public class Grid<T> extends Composite implements /** * Gets a reference to the current selection model. - * + * * @return the currently used SelectionModel instance. */ public SelectionModel<T> getSelectionModel() { @@ -1907,7 +1925,7 @@ public class Grid<T> extends Composite implements * Sets current selection mode. * <p> * This is a shorthand method for {@link Grid#setSelectionModel}. - * + * * @param mode * a selection mode value * @see {@link SelectionMode}. @@ -1919,7 +1937,7 @@ public class Grid<T> extends Composite implements /** * Test if a row is selected. - * + * * @param row * a row object * @return true, if the current selection model considers the provided row @@ -1935,7 +1953,7 @@ public class Grid<T> extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return <code>true</code> iff the current selection changed @@ -1960,7 +1978,7 @@ public class Grid<T> extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return <code>true</code> iff the current selection changed @@ -1985,7 +2003,7 @@ public class Grid<T> extends Composite implements * Only selection models implementing {@link SelectionModel.Single} are * valid for this method; for anything else, use the * {@link Grid#getSelectedRows()} method. - * + * * @return a selected row reference, or null, if no row is selected * @throws IllegalStateException * if the current selection model is not an instance of @@ -2002,7 +2020,7 @@ public class Grid<T> extends Composite implements /** * Gets currently selected rows from the current selection model. - * + * * @return a non-null collection containing all currently selected rows. */ public Collection<T> getSelectedRows() { @@ -2015,4 +2033,91 @@ public class Grid<T> extends Composite implements return addHandler(handler, SelectionChangeEvent.getType()); } + /** + * Sets the current sort order using the fluid Sort API. Read the + * documentation for {@link Sort} for more information. + * + * @param s + * a sort instance + */ + public void sort(Sort s) { + setSortOrder(s.build()); + } + + /** + * Sorts the Grid data in ascending order along one column. + * + * @param column + * a grid column reference + */ + public <C> void sort(GridColumn<C, T> column) { + sort(column, SortDirection.ASCENDING); + } + + /** + * Sorts the Grid data along one column. + * + * @param column + * a grid column reference + * @param direction + * a sort direction value + */ + public <C> void sort(GridColumn<C, T> column, SortDirection direction) { + sort(Sort.by(column, direction)); + } + + /** + * Sets the sort order to use. Setting this causes the Grid to re-sort + * itself. + * + * @param order + * a sort order list. If set to null, the sort order is cleared. + */ + public void setSortOrder(List<SortOrder> order) { + sortOrder.clear(); + if (order != null) { + sortOrder.addAll(order); + } + sort(); + } + + /** + * Get a copy of the current sort order array. + * + * @return a copy of the current sort order array + */ + public List<SortOrder> getSortOrder() { + return Collections.unmodifiableList(sortOrder); + } + + /** + * Register a GWT event handler for a sorting event. This handler gets + * called whenever this Grid needs its data source to provide data sorted in + * a specific order. + * + * @param handler + * a sort event handler + * @return the registration for the event + */ + public HandlerRegistration addSortHandler(SortEventHandler<T> handler) { + return addHandler(handler, SortEvent.getType()); + } + + /** + * Apply sorting to data source. + */ + private void sort() { + fireEvent(new SortEvent<T>(this, + Collections.unmodifiableList(sortOrder))); + } + + /** + * Missing getDataSource method. TODO: remove this and other duplicates + * after The Merge + * + * @return a DataSource reference + */ + public DataSource<T> getDataSource() { + return dataSource; + } } diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index 94c32bfb33..97b358a299 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -18,6 +18,8 @@ package com.vaadin.client.ui.grid.datasources; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -30,23 +32,23 @@ import com.vaadin.shared.util.SharedUtil; * A simple list based on an in-memory data source for simply adding a list of * row pojos to the grid. Based on a wrapped list instance which supports adding * and removing of items. - * + * * <p> * Usage: - * + * * <pre> * ListDataSource<Integer> ds = new ListDataSource<Integer>(1, 2, 3, 4); - * + * * // Add item to the data source * ds.asList().add(5); - * + * * // Remove item from the data source * ds.asList().remove(3); - * + * * // Add multiple items * ds.asList().addAll(Arrays.asList(5, 6, 7)); * </pre> - * + * * @since 7.4 * @author Vaadin Ltd */ @@ -342,8 +344,8 @@ public class ListDataSource<T> implements DataSource<T> { * data source after the data source has been constructed. To add or remove * items to the data source after it has been constructed use * {@link ListDataSource#asList()}. - * - * + * + * * @param datasource * The list to use for providing the data to the grid */ @@ -359,7 +361,7 @@ public class ListDataSource<T> implements DataSource<T> { * Constructs a data source with a set of rows. You can dynamically add and * remove rows from the data source via the list you get from * {@link ListDataSource#asList()} - * + * * @param rows * The rows to initially add to the data source */ @@ -401,7 +403,7 @@ public class ListDataSource<T> implements DataSource<T> { * <p> * Note: The list is not the same list as passed into the data source via * the constructor. - * + * * @return Returns a list implementation that wraps the real list that backs * the data source and provides events for the data source * listeners. @@ -416,4 +418,18 @@ public class ListDataSource<T> implements DataSource<T> { + row; return new RowHandleImpl(row); } + + /** + * Sort entire container according to a {@link Comparator}. + * + * @param comparator + * a comparator object, which compares two data source entries + * (beans/pojos) + */ + public void sort(Comparator<T> comparator) { + Collections.sort(ds, comparator); + if (changeHandler != null) { + changeHandler.dataUpdated(0, ds.size()); + } + } } diff --git a/client/src/com/vaadin/client/ui/grid/sort/Sort.java b/client/src/com/vaadin/client/ui/grid/sort/Sort.java new file mode 100644 index 0000000000..fdf3c64d60 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/Sort.java @@ -0,0 +1,155 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.shared.ui.grid.SortDirection; + +/** + * Fluid Sort descriptor object. + * + * @since 7.4 + * @author Vaadin Ltd + * @param T + * grid data type + */ +public class Sort { + + private final Sort previous; + private final SortOrder order; + private final int count; + + /** + * Basic constructor, used by the {@link #by(GridColumn)} and + * {@link #by(GridColumn, SortDirection)} methods. + * + * @param column + * a grid column + * @param direction + * a sort direction + */ + private Sort(GridColumn<?, ?> column, SortDirection direction) { + previous = null; + count = 1; + order = new SortOrder(column, direction); + } + + /** + * Extension constructor. Performs object equality checks on all previous + * Sort objects in the chain to make sure that the column being passed in + * isn't already used earlier (which would indicate a bug). If the column + * has been used before, this constructor throws an + * {@link IllegalStateException}. + * + * @param previous + * the sort instance that the new sort instance is to extend + * @param column + * a (previously unused) grid column reference + * @param direction + * a sort direction + */ + private Sort(Sort previous, GridColumn<?, ?> column, SortDirection direction) { + this.previous = previous; + count = previous.count + 1; + order = new SortOrder(column, direction); + + Sort s = previous; + while (s != null) { + if (s.order.getColumn() == column) { + throw new IllegalStateException( + "Can not sort along the same column twice"); + } + s = s.previous; + } + } + + /** + * Start building a Sort order by sorting a provided column in ascending + * order. + * + * @param column + * a grid column object reference + * @return a sort instance, typed to the grid data type + */ + public static Sort by(GridColumn<?, ?> column) { + return by(column, SortDirection.ASCENDING); + } + + /** + * Start building a Sort order by sorting a provided column. + * + * @param column + * a grid column object reference + * @param direction + * indicator of sort direction - either ascending or descending + * @return a sort instance, typed to the grid data type + */ + public static Sort by(GridColumn<?, ?> column, SortDirection direction) { + return new Sort(column, direction); + } + + /** + * Continue building a Sort order. The provided column is sorted in + * ascending order if the previously added columns have been evaluated as + * equals. + * + * @param column + * a grid column object reference + * @return a sort instance, typed to the grid data type + */ + public Sort then(GridColumn<?, ?> column) { + return then(column, SortDirection.ASCENDING); + } + + /** + * Continue building a Sort order. The provided column is sorted in + * specified order if the previously added columns have been evaluated as + * equals. + * + * @param column + * a grid column object reference + * @param direction + * indicator of sort direction - either ascending or descending + * @return a sort instance, typed to the grid data type + */ + public Sort then(GridColumn<?, ?> column, SortDirection direction) { + return new Sort(this, column, direction); + } + + /** + * Build a sort order list. This method is called internally by Grid when + * calling {@link com.vaadin.client.ui.grid.Grid#sort(Sort)}, but can also + * be called manually to create a SortOrder list, which can also be provided + * directly to Grid. + * + * @return a sort order list. + */ + public List<SortOrder> build() { + + List<SortOrder> order = new ArrayList<SortOrder>(count); + + Sort s = this; + for (int i = count - 1; i >= 0; --i) { + order.add(0, s.order); + s = s.previous; + } + + return order; + } +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java new file mode 100644 index 0000000000..d39cdfc4f2 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import java.util.List; + +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.grid.Grid; + +/** + * A sort event, fired by the Grid when it needs its data source to provide data + * sorted in a specific manner. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class SortEvent<T> extends GwtEvent<SortEventHandler<?>> { + + private static final Type<SortEventHandler<?>> TYPE = new Type<SortEventHandler<?>>(); + + private final Grid<T> grid; + private final List<SortOrder> order; + + /** + * Creates a new Sort Event. All provided parameters are final, and passed + * on as-is. + * + * @param grid + * a grid reference + * @param datasource + * a reference to the grid's data source + * @param order + * an array dictating the desired sort order of the data source + */ + public SortEvent(Grid<T> grid, List<SortOrder> order) { + this.grid = grid; + this.order = order; + } + + @Override + public Type<SortEventHandler<?>> getAssociatedType() { + return TYPE; + } + + /** + * Static access to the GWT event type identifier associated with this Event + * class + * + * @return a type object, uniquely describing this event type. + */ + public static Type<SortEventHandler<?>> getType() { + return TYPE; + } + + /** + * Get access to the Grid that fired this event + * + * @return the grid instance + */ + @Override + public Grid<T> getSource() { + return grid; + } + + /** + * Get access to the Grid that fired this event + * + * @return the grid instance + */ + public Grid<T> getGrid() { + return grid; + } + + /** + * Access the data source of the Grid that fired this event + * + * @return a data source instance + */ + public DataSource<T> getDataSource() { + return grid.getDataSource(); + } + + /** + * Get the sort ordering that is to be applied to the Grid + * + * @return a list of sort order objects + */ + public List<SortOrder> getOrder() { + return order; + } + + @SuppressWarnings("unchecked") + @Override + protected void dispatch(SortEventHandler<?> handler) { + ((SortEventHandler<T>) handler).sort(this); + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java new file mode 100644 index 0000000000..8895b43631 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Handler for a Grid sort event, called when the Grid needs its data source to + * provide data sorted in a specific manner. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public interface SortEventHandler<T> extends EventHandler { + + /** + * Handle sorting of the Grid. This method is called when a re-sorting of + * the Grid's data is requested. + * + * @param event + * the sort event + */ + public void sort(SortEvent<T> event); + +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java new file mode 100644 index 0000000000..bd76124d0c --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.shared.ui.grid.SortDirection; + +/** + * Sort order descriptor. Contains column and direction references. + * + * @since 7.4 + * @author Vaadin Ltd + * @param T + * grid data type + */ +public class SortOrder { + + private final GridColumn<?, ?> column; + private final SortDirection direction; + + /** + * Create a sort order descriptor. + * + * @param column + * a grid column descriptor object + * @param direction + * a sorting direction value (ascending or descending) + */ + public SortOrder(GridColumn<?, ?> column, SortDirection direction) { + if (column == null) { + throw new IllegalArgumentException( + "Grid column reference can not be null!"); + } + if (direction == null) { + throw new IllegalArgumentException( + "Direction value can not be null!"); + } + this.column = column; + this.direction = direction; + } + + /** + * Returns the {@link GridColumn} reference given in the constructor. + * + * @return a grid column reference + */ + public GridColumn<?, ?> getColumn() { + return column; + } + + /** + * Returns the {@link SortDirection} value given in the constructor. + * + * @return a sort direction value + */ + public SortDirection getDirection() { + return direction; + } + +} diff --git a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java index 5c5e88bf69..823eb224ea 100644 --- a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java +++ b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2013 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -16,8 +16,10 @@ package com.vaadin.client.ui.grid; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.Arrays; +import java.util.Comparator; import org.easymock.EasyMock; import org.junit.Test; @@ -26,7 +28,7 @@ import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.ui.grid.datasources.ListDataSource; /** - * + * * @since 7.2 * @author Vaadin Ltd */ @@ -175,4 +177,21 @@ public class ListDataSourceTest { ds.asList().iterator().remove(); } + @Test + public void sortColumn() { + ListDataSource<Integer> ds = new ListDataSource<Integer>(3, 4, 2, 3, 1); + + // TODO Should be simplified to sort(). No point in providing these + // trivial comparators. + ds.sort(new Comparator<Integer>() { + @Override + public int compare(Integer o1, Integer o2) { + return o1.compareTo(o2); + } + }); + + assertTrue(Arrays.equals(ds.asList().toArray(), new Integer[] { 1, 2, + 3, 3, 4 })); + } + } |