diff options
author | John Ahlroos <john@vaadin.com> | 2014-08-07 16:04:17 +0300 |
---|---|---|
committer | John Ahlroos <john@vaadin.com> | 2014-08-19 10:37:58 +0300 |
commit | 5dfdd40d00dc0f7a2eea19f8c77485f1afcf77ad (patch) | |
tree | 30b92381f2bce518697d2ead721d12cb97ceb6c5 | |
parent | c1a873bc9e47b98c58b298aa6935ab0853e6963f (diff) | |
download | vaadin-framework-5dfdd40d00dc0f7a2eea19f8c77485f1afcf77ad.tar.gz vaadin-framework-5dfdd40d00dc0f7a2eea19f8c77485f1afcf77ad.zip |
Removed SortableColumnHeaderRenderer #13334
Change-Id: I3f15765228428049febfe3a8d5966c3631d010a9
4 files changed, 260 insertions, 321 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index aae7f046b6..a407038917 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -30,6 +30,7 @@ import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; @@ -464,6 +465,83 @@ public class Grid<T> extends Composite implements } /** + * Class for sorting at a later time + */ + private class LazySorter extends Timer { + + private Cell cell; + + private boolean multisort; + + @Override + public void run() { + SortOrder sortingOrder = getSortOrder(getColumnFromVisibleIndex(cell + .getColumn())); + if (sortingOrder == null) { + /* + * No previous sorting, sort Ascending + */ + sort(cell, SortDirection.ASCENDING, multisort); + + } else { + // Toggle sorting + SortDirection direction = sortingOrder.getDirection(); + if (direction == SortDirection.ASCENDING) { + sort(cell, SortDirection.DESCENDING, multisort); + } else { + sort(cell, SortDirection.ASCENDING, multisort); + } + } + } + + /** + * Set the cell reference to the primary cell that sorting should be + * done for. + * + * @param cell + * + */ + public void setCellReference(Cell cell) { + this.cell = cell; + } + + /** + * Is multiple column sorting is enabled/disabled + * + * @param multisort + * true if multiple column sorting is enabled + */ + public void setMultisort(boolean multisort) { + this.multisort = multisort; + } + + /** + * Sorts the column in a direction + */ + private void sort(Cell cell, SortDirection direction, boolean multisort) { + TableCellElement th = TableCellElement.as(cell.getElement()); + + // Apply primary sorting on clicked column + GridColumn<?, ?> columnInstance = getColumnFromVisibleIndex(cell + .getColumn()); + Sort sorting = Sort.by(columnInstance, direction); + + // Re-apply old sorting to the sort order + if (multisort) { + for (SortOrder order : getSortOrder()) { + if (order.getColumn() != columnInstance) { + sorting = sorting.then(order.getColumn(), + order.getDirection()); + } + } + } + + // Perform sorting + Grid.this.sort(sorting); + } + } + + /** * Escalator used internally by grid to render the rows */ private Escalator escalator = GWT.create(Escalator.class); @@ -511,6 +589,8 @@ public class Grid<T> extends Composite implements private final ActiveCellHandler activeCellHandler; + private final LazySorter lazySorter = new LazySorter(); + /** * Enumeration for easy setting of selection mode. */ @@ -552,13 +632,6 @@ public class Grid<T> extends Composite implements protected abstract <T> SelectionModel<T> createModel(); } - class SortableColumnHeaderRenderer extends - AbstractGridColumn.SortableColumnHeaderRenderer { - SortableColumnHeaderRenderer(Renderer<String> cellRenderer) { - super(Grid.this, cellRenderer); - } - } - /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. @@ -572,274 +645,7 @@ public class Grid<T> extends Composite implements static abstract class AbstractGridColumn<C, T> implements HasVisibility { /** - * Renderer for columns which are sortable - * - * FIXME Currently assumes multisorting - */ - static class SortableColumnHeaderRenderer extends - ComplexRenderer<String> { - - private Grid<?> grid; - - /** - * Delay before a long tap action is triggered. Number in - * milliseconds. - */ - private static final int LONG_TAP_DELAY = 500; - - /** - * The threshold in pixels a finger can move while long tapping. - */ - private static final int LONG_TAP_THRESHOLD = 3; - - /** - * Class for sorting at a later time - */ - private class LazySorter extends Timer { - - private Cell cell; - - private boolean multisort; - - @Override - public void run() { - SortOrder sortingOrder = getSortingOrder(grid - .getColumnFromVisibleIndex(cell.getColumn())); - if (sortingOrder == null) { - /* - * No previous sorting, sort Ascending - */ - sort(cell, SortDirection.ASCENDING, multisort); - - } else { - // Toggle sorting - SortDirection direction = sortingOrder.getDirection(); - if (direction == SortDirection.ASCENDING) { - sort(cell, SortDirection.DESCENDING, multisort); - } else { - sort(cell, SortDirection.ASCENDING, multisort); - } - } - } - - public void setCurrentCell(Cell cell) { - this.cell = cell; - } - - public void setMultisort(boolean multisort) { - this.multisort = multisort; - } - } - - private final LazySorter lazySorter = new LazySorter(); - - private Renderer<String> cellRenderer; - - private Point touchStartPoint; - - /** - * Creates column renderer with sort indicators - * - * @param cellRenderer - * The actual cell renderer - */ - public SortableColumnHeaderRenderer(Grid<?> grid, - Renderer<String> cellRenderer) { - this.grid = grid; - this.cellRenderer = cellRenderer; - } - - @Override - public void render(FlyweightCell cell, String data) { - - // Render cell - this.cellRenderer.render(cell, data); - - /* - * FIXME This grid null check is needed since Grid.addColumns() - * is invoking Escalator.insertColumn() before the grid instance - * for the column is set resulting in the first render() being - * done without a grid instance. Remove the if statement when - * this is fixed. - */ - if (grid != null) { - GridColumn<?, ?> column = grid - .getColumnFromVisibleIndex(cell.getColumn()); - SortOrder sortingOrder = getSortingOrder(column); - Element cellElement = cell.getElement(); - if (column.isSortable()) { - if (sortingOrder != null) { - if (SortDirection.ASCENDING == sortingOrder - .getDirection()) { - cellElement.replaceClassName("sort-desc", - "sort-asc"); - } else { - cellElement.replaceClassName("sort-asc", - "sort-desc"); - } - - int sortIndex = grid.getSortOrder().indexOf( - sortingOrder); - if (sortIndex > -1 - && grid.getSortOrder().size() > 1) { - // Show sort order indicator if column is sorted - // and other sorted columns also exists. - cellElement.setAttribute("sort-order", - String.valueOf(sortIndex + 1)); - - } else { - cellElement.removeAttribute("sort-order"); - } - } else { - cleanup(cell); - } - } else { - cleanup(cell); - } - } - } - - private void cleanup(FlyweightCell cell) { - Element cellElement = cell.getElement(); - cellElement.removeAttribute("sort-order"); - cellElement.removeClassName("sort-desc"); - cellElement.removeClassName("sort-asc"); - } - - @Override - public Collection<String> getConsumedEvents() { - return Arrays.asList(BrowserEvents.TOUCHSTART, - BrowserEvents.TOUCHMOVE, BrowserEvents.TOUCHEND, - BrowserEvents.TOUCHCANCEL, BrowserEvents.CLICK); - } - - @Override - public boolean onBrowserEvent(final Cell cell, NativeEvent event) { - - // Handle sorting events if column is sortable - if (grid.getColumn(cell.getColumn()).isSortable()) { - - if (BrowserEvents.TOUCHSTART.equals(event.getType())) { - if (event.getTouches().length() > 1) { - return false; - } - - event.preventDefault(); - - Touch touch = event.getChangedTouches().get(0); - touchStartPoint = new Point(touch.getClientX(), - touch.getClientY()); - - lazySorter.setCurrentCell(cell); - lazySorter.setMultisort(true); - lazySorter.schedule(LONG_TAP_DELAY); - - } else if (BrowserEvents.TOUCHMOVE.equals(event.getType())) { - if (event.getTouches().length() > 1) { - return false; - } - - event.preventDefault(); - - Touch touch = event.getChangedTouches().get(0); - double diffX = Math.abs(touch.getClientX() - - touchStartPoint.getX()); - double diffY = Math.abs(touch.getClientY() - - touchStartPoint.getY()); - - // Cancel long tap if finger strays too far from - // starting point - if (diffX > LONG_TAP_THRESHOLD - || diffY > LONG_TAP_THRESHOLD) { - lazySorter.cancel(); - } - - } else if (BrowserEvents.TOUCHEND.equals(event.getType())) { - if (event.getTouches().length() > 0) { - return false; - } - - if (lazySorter.isRunning()) { - // Not a long tap yet, perform single sort - lazySorter.cancel(); - lazySorter.setMultisort(false); - lazySorter.run(); - } - - } else if (BrowserEvents.TOUCHCANCEL - .equals(event.getType())) { - if (event.getChangedTouches().length() > 1) { - return false; - } - - lazySorter.cancel(); - - } else if (BrowserEvents.CLICK.equals(event.getType())) { - lazySorter.setCurrentCell(cell); - lazySorter.setMultisort(event.getShiftKey()); - lazySorter.run(); - - // Active cell handling is also monitoring the click - // event so we allow event to propagate for it - return false; - } - return true; - } - return false; - - } - - protected void removeFromRow(HeaderRow row) { - row.setRenderer(new Renderer<String>() { - @Override - public void render(FlyweightCell cell, String data) { - cleanup(cell); - } - }); - grid.refreshHeader(); - row.setRenderer(cellRenderer); - grid.refreshHeader(); - } - - /** - * Sorts the column in a direction - */ - private void sort(Cell cell, SortDirection direction, - boolean multisort) { - // Apply primary sorting on clicked column - GridColumn<?, ?> columnInstance = grid - .getColumnFromVisibleIndex(cell.getColumn()); - Sort sorting = Sort.by(columnInstance, direction); - - // Re-apply old sorting to the sort order - if (multisort) { - for (SortOrder order : grid.getSortOrder()) { - if (order.getColumn() != columnInstance) { - sorting = sorting.then(order.getColumn(), - order.getDirection()); - } - } - } - - // Perform sorting - grid.sort(sorting); - } - - /** - * Finds the sorting order for this column - */ - private SortOrder getSortingOrder(GridColumn<?, ?> column) { - for (SortOrder order : grid.getSortOrder()) { - if (order.getColumn() == column) { - return order; - } - } - return null; - } - } - - /** - * The grid the column is associated with + * the column is associated with */ private Grid<T> grid; @@ -1187,13 +993,14 @@ public class Grid<T> extends Composite implements int index = columnIndices.get(cell.getColumn()); final StaticCell metadata = staticRow.getCell(index); + // Decorate default row with sorting indicators + if (staticRow instanceof HeaderRow) { + addSortingIndicatorsToHeaderRow((HeaderRow) staticRow, cell); + } + // Assign colspan to cell before rendering cell.setColSpan(metadata.getColspan()); - // Decorates cell with possible indicators onto the cell. - // Actual content is rendered below. - staticRow.getRenderer().render(cell, null); - switch (metadata.getType()) { case TEXT: cell.getElement().setInnerText(metadata.getText()); @@ -1212,6 +1019,57 @@ public class Grid<T> extends Composite implements } } + private void addSortingIndicatorsToHeaderRow(HeaderRow headerRow, + FlyweightCell cell) { + + cleanup(cell); + + GridColumn<?, ?> column = getColumnFromVisibleIndex(cell + .getColumn()); + SortOrder sortingOrder = getSortOrder(column); + if (!headerRow.isDefault() || !column.isSortable() + || sortingOrder == null) { + // Only apply sorting indicators to sortable header columns in + // the default header row + return; + } + + Element cellElement = cell.getElement(); + + if (SortDirection.ASCENDING == sortingOrder.getDirection()) { + cellElement.addClassName("sort-asc"); + } else { + cellElement.addClassName("sort-desc"); + } + + int sortIndex = Grid.this.getSortOrder().indexOf(sortingOrder); + if (sortIndex > -1 && Grid.this.getSortOrder().size() > 1) { + // Show sort order indicator if column is + // sorted and other sorted columns also exists. + cellElement.setAttribute("sort-order", + String.valueOf(sortIndex + 1)); + } + } + + /** + * Finds the sort order for this column + */ + private SortOrder getSortOrder(GridColumn<?, ?> column) { + for (SortOrder order : Grid.this.getSortOrder()) { + if (order.getColumn() == column) { + return order; + } + } + return null; + } + + private void cleanup(FlyweightCell cell) { + Element cellElement = cell.getElement(); + cellElement.removeAttribute("sort-order"); + cellElement.removeClassName("sort-desc"); + cellElement.removeClassName("sort-asc"); + } + @Override public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) { } @@ -1333,6 +1191,9 @@ public class Grid<T> extends Composite implements refreshBody(); } }); + + // Sink header events + sinkEvents(getHeader().getConsumedEvents()); } @Override @@ -1371,7 +1232,7 @@ public class Grid<T> extends Composite implements * The updater is invoked when body rows or columns are added or removed, * the content of body cells is changed, or the body is scrolled to expose * previously hidden content. - * + * * @return the new body updater instance */ protected EscalatorUpdater createBodyUpdater() { @@ -1997,17 +1858,15 @@ public class Grid<T> extends Composite implements // FIXME getFromVisibleIndex??? GridColumn<?, T> gridColumn = columns.get(cell.getColumn()); - Renderer<?> renderer; if (container == escalator.getHeader()) { - renderer = header.getRow(cell.getRow()).getRenderer(); + if (getHeader().getRow(cell.getRow()).isDefault()) { + handleDefaultRowEvent(cell, event); + } } else if (container == escalator.getFooter()) { - renderer = footer.getRow(cell.getRow()).getRenderer(); - } else { - renderer = gridColumn.getRenderer(); - } - - if (renderer instanceof ComplexRenderer) { - ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) renderer; + // NOP + } else if (gridColumn.getRenderer() instanceof ComplexRenderer) { + ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) gridColumn + .getRenderer(); if (cplxRenderer.getConsumedEvents().contains( event.getType())) { if (cplxRenderer.onBrowserEvent(cell, event)) { @@ -2027,6 +1886,81 @@ public class Grid<T> extends Composite implements } } + private Point rowEventTouchStartingPoint; + + private boolean handleDefaultRowEvent(final Cell cell, NativeEvent event) { + if (!getColumn(cell.getColumn()).isSortable()) { + // Only handle sorting events if the column is sortable + return false; + } + + if (BrowserEvents.TOUCHSTART.equals(event.getType())) { + if (event.getTouches().length() > 1) { + return false; + } + + event.preventDefault(); + + Touch touch = event.getChangedTouches().get(0); + rowEventTouchStartingPoint = new Point(touch.getClientX(), + touch.getClientY()); + + lazySorter.setCellReference(cell); + lazySorter.setMultisort(true); + lazySorter.schedule(GridConstants.LONG_TAP_DELAY); + + } else if (BrowserEvents.TOUCHMOVE.equals(event.getType())) { + if (event.getTouches().length() > 1) { + return false; + } + + event.preventDefault(); + + Touch touch = event.getChangedTouches().get(0); + double diffX = Math.abs(touch.getClientX() + - rowEventTouchStartingPoint.getX()); + double diffY = Math.abs(touch.getClientY() + - rowEventTouchStartingPoint.getY()); + + // Cancel long tap if finger strays too far from + // starting point + if (diffX > GridConstants.LONG_TAP_THRESHOLD + || diffY > GridConstants.LONG_TAP_THRESHOLD) { + lazySorter.cancel(); + } + + } else if (BrowserEvents.TOUCHEND.equals(event.getType())) { + if (event.getTouches().length() > 0) { + return false; + } + + if (lazySorter.isRunning()) { + // Not a long tap yet, perform single sort + lazySorter.cancel(); + lazySorter.setMultisort(false); + lazySorter.run(); + } + + } else if (BrowserEvents.TOUCHCANCEL.equals(event.getType())) { + if (event.getChangedTouches().length() > 1) { + return false; + } + + lazySorter.cancel(); + + } else if (BrowserEvents.CLICK.equals(event.getType())) { + lazySorter.setCellReference(cell); + lazySorter.setMultisort(event.getShiftKey()); + lazySorter.run(); + + // Active cell handling is also monitoring the click + // event so we allow event to propagate for it + return false; + } + + return true; + } + @Override public com.google.gwt.user.client.Element getSubPartElement(String subPart) { // Parse SubPart string to type and indices @@ -2359,6 +2293,18 @@ public class Grid<T> extends Composite implements } /** + * Finds the sorting order for this column + */ + private SortOrder getSortOrder(GridColumn<?, ?> column) { + for (SortOrder order : getSortOrder()) { + if (order.getColumn() == column) { + return order; + } + } + return null; + } + + /** * 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. diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index f714848618..2867ae4d1c 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -15,8 +15,11 @@ */ package com.vaadin.client.ui.grid; +import java.util.Arrays; +import java.util.Collection; + import com.google.gwt.core.client.Scheduler; -import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRenderer; +import com.google.gwt.dom.client.BrowserEvents; /** * Represents the header section of a Grid. A header consists of a single header @@ -89,21 +92,9 @@ public class GridHeader extends GridStaticSection<GridHeader.HeaderRow> { "Cannot set a default row that does not exist in the container"); } if (defaultRow != null) { - assert defaultRow.getRenderer() instanceof SortableColumnHeaderRenderer; - - // Eclipse is wrong about this warning - javac does not accept the - // parameterized version - ((Grid.SortableColumnHeaderRenderer) defaultRow.getRenderer()) - .removeFromRow(defaultRow); - defaultRow.setDefault(false); } if (row != null) { - assert !(row.getRenderer() instanceof SortableColumnHeaderRenderer); - - row.setRenderer(getGrid().new SortableColumnHeaderRenderer(row - .getRenderer())); - row.setDefault(true); } defaultRow = row; @@ -145,4 +136,15 @@ public class GridHeader extends GridStaticSection<GridHeader.HeaderRow> { } }); } + + /** + * Returns the events consumed by the header + * + * @return a collection of BrowserEvents + */ + public Collection<String> getConsumedEvents() { + return Arrays.asList(BrowserEvents.TOUCHSTART, BrowserEvents.TOUCHMOVE, + BrowserEvents.TOUCHEND, BrowserEvents.TOUCHCANCEL, + BrowserEvents.CLICK); + } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 1be0a92b8f..8c9ada46d0 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -187,17 +187,6 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> private List<CELLTYPE> cells = new ArrayList<CELLTYPE>(); - private Renderer<String> renderer = new Renderer<String>() { - - @Override - public void render(FlyweightCell cell, String data) { - /* - * The rendering into the cell is done directly from the updater - * since it needs to handle multiple types of data. - */ - } - }; - private GridStaticSection<?> section; private Collection<List<CELLTYPE>> cellGroups = new HashSet<List<CELLTYPE>>(); @@ -359,14 +348,6 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> cells.remove(index); } - protected void setRenderer(Renderer<String> renderer) { - this.renderer = renderer; - } - - protected Renderer<String> getRenderer() { - return renderer; - } - protected abstract CELLTYPE createCell(); protected GridStaticSection<?> getSection() { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java index 346e85b994..1ee79a5d37 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java @@ -31,4 +31,14 @@ public final class GridConstants implements Serializable { * explicitly defined padding value. */ public static final int DEFAULT_PADDING = 0; + + /** + * Delay before a long tap action is triggered. Number in milliseconds. + */ + public static final int LONG_TAP_DELAY = 500; + + /** + * The threshold in pixels a finger can move while long tapping. + */ + public static final int LONG_TAP_THRESHOLD = 3; } |