aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2014-07-14 16:40:30 +0300
committerVaadin Code Review <review@vaadin.com>2014-07-15 11:23:41 +0000
commitf89d015e9252d4470afa6008fd3f004809129b89 (patch)
treee3470afedf20c4c51849a5a7bb2d11d5d3ed8a24
parent3582b43415c7ddd587451f565a5ae70fea8bb51d (diff)
downloadvaadin-framework-f89d015e9252d4470afa6008fd3f004809129b89.tar.gz
vaadin-framework-f89d015e9252d4470afa6008fd3f004809129b89.zip
Implement active cell painting and mouse interaction (#13334)
Change-Id: Iecb9db0fe6ea9ef0409e2ac0a294ac3508277251
-rw-r--r--WebContent/VAADIN/themes/base/grid/grid.scss13
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java91
-rw-r--r--client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java8
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java66
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java3
6 files changed, 172 insertions, 12 deletions
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss
index 2955f7ecd3..88c7754a10 100644
--- a/WebContent/VAADIN/themes/base/grid/grid.scss
+++ b/WebContent/VAADIN/themes/base/grid/grid.scss
@@ -19,8 +19,19 @@
right: 5px;
}
+ .#{$primaryStyleName}-cell-active {
+ border-color: blue;
+ }
+
+ .#{$primaryStyleName}-header-active {
+ background: lightgray;
+ }
+
+ .#{$primaryStyleName}-row-active > td {
+ background: rgb(244,244,244);
+ }
}
-
+
.#{$primaryStyleName}-row-selected > td {
background: lightblue;
}
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index d03197e2ef..471f62cdeb 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -235,6 +235,9 @@ public class Grid<T> extends Composite implements
private String rowHasDataStyleName;
private String rowSelectedStyleName;
+ private String cellActiveStyleName;
+ private String rowActiveStyleName;
+ private String headerFooterFocusedStyleName;
/**
* Current selection model.
@@ -242,6 +245,12 @@ public class Grid<T> extends Composite implements
private SelectionModel<T> selectionModel;
/**
+ * Current active cell.
+ */
+ private int activeRow = 0;
+ private int activeColumn = 0;
+
+ /**
* Enumeration for easy setting of selection mode.
*/
public enum SelectionMode {
@@ -430,14 +439,14 @@ public class Grid<T> extends Composite implements
}
@Override
- public void onBrowserEvent(final Cell cell, NativeEvent event) {
+ 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;
+ return false;
}
event.preventDefault();
@@ -452,7 +461,7 @@ public class Grid<T> extends Composite implements
} else if (BrowserEvents.TOUCHMOVE.equals(event.getType())) {
if (event.getTouches().length() > 1) {
- return;
+ return false;
}
event.preventDefault();
@@ -472,7 +481,7 @@ public class Grid<T> extends Composite implements
} else if (BrowserEvents.TOUCHEND.equals(event.getType())) {
if (event.getTouches().length() > 0) {
- return;
+ return false;
}
if (lazySorter.isRunning()) {
@@ -485,7 +494,7 @@ public class Grid<T> extends Composite implements
} else if (BrowserEvents.TOUCHCANCEL
.equals(event.getType())) {
if (event.getChangedTouches().length() > 1) {
- return;
+ return false;
}
lazySorter.cancel();
@@ -496,7 +505,10 @@ public class Grid<T> extends Composite implements
lazySorter.setMultisort(event.getShiftKey());
lazySorter.run();
}
+ return true;
}
+ return false;
+
}
/**
@@ -986,6 +998,10 @@ public class Grid<T> extends Composite implements
getRenderer(column)
.render(cell, getColumnValue(column));
}
+
+ setStyleName(cell.getElement(),
+ headerFooterFocusedStyleName,
+ activeColumn == cell.getColumn());
}
} else if (columnGroupRows.size() > 0) {
@@ -1023,6 +1039,10 @@ public class Grid<T> extends Composite implements
// Cells are reused
cellElement.setInnerHTML(null);
cell.setColSpan(1);
+
+ setStyleName(cell.getElement(),
+ headerFooterFocusedStyleName,
+ activeColumn == cell.getColumn());
}
}
}
@@ -1060,6 +1080,7 @@ public class Grid<T> extends Composite implements
refreshHeader();
refreshFooter();
+ sinkEvents(Event.ONMOUSEDOWN);
setSelectionMode(SelectionMode.SINGLE);
escalator
@@ -1092,6 +1113,9 @@ public class Grid<T> extends Composite implements
escalator.setStylePrimaryName(style);
rowHasDataStyleName = getStylePrimaryName() + "-row-has-data";
rowSelectedStyleName = getStylePrimaryName() + "-row-selected";
+ cellActiveStyleName = getStylePrimaryName() + "-cell-active";
+ headerFooterFocusedStyleName = getStylePrimaryName() + "-header-active";
+ rowActiveStyleName = getStylePrimaryName() + "-row-active";
}
/**
@@ -1194,6 +1218,9 @@ public class Grid<T> extends Composite implements
setStyleName(rowElement, rowSelectedStyleName, false);
}
+ setStyleName(rowElement, rowActiveStyleName,
+ rowIndex == activeRow);
+
for (FlyweightCell cell : cellsToUpdate) {
GridColumn<?, T> column = getColumnFromVisibleIndex(cell
.getColumn());
@@ -1201,6 +1228,9 @@ public class Grid<T> extends Composite implements
assert column != null : "Column was not found from cell ("
+ cell.getColumn() + "," + cell.getRow() + ")";
+ setStyleName(cell.getElement(), cellActiveStyleName,
+ isActiveCell(cell));
+
Renderer renderer = column.getRenderer();
// Hide cell content if needed
@@ -1232,6 +1262,11 @@ public class Grid<T> extends Composite implements
}
}
+ private boolean isActiveCell(FlyweightCell cell) {
+ return cell.getRow() == activeRow
+ && cell.getColumn() == activeColumn;
+ }
+
@Override
public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
for (FlyweightCell cell : cellsToDetach) {
@@ -2095,8 +2130,19 @@ public class Grid<T> extends Composite implements
}
if (renderer instanceof ComplexRenderer) {
- ((ComplexRenderer<?>) renderer).onBrowserEvent(cell,
- event);
+ ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) renderer;
+ if (cplxRenderer.getConsumedEvents().contains(
+ event.getType())) {
+ if (cplxRenderer.onBrowserEvent(cell, event)) {
+ return;
+ }
+ }
+ }
+
+ // TODO: Support active cells in Headers and Footers,
+ // 14.07.2014, Teemu Suo-Anttila
+ if (event.getTypeInt() == Event.ONMOUSEDOWN) {
+ setActiveCell(cell);
}
}
}
@@ -2202,11 +2248,13 @@ public class Grid<T> extends Composite implements
if (this.selectColumnRenderer != null) {
removeColumnSkipSelectionColumnCheck(selectionColumn);
+ --activeColumn;
}
this.selectColumnRenderer = selectColumnRenderer;
if (selectColumnRenderer != null) {
+ ++activeColumn;
selectionColumn = new SelectionColumn(selectColumnRenderer);
// FIXME: this needs to be done elsewhere, requires design...
@@ -2215,6 +2263,7 @@ public class Grid<T> extends Composite implements
selectionColumn.initDone();
} else {
selectionColumn = null;
+ refreshBody();
}
}
@@ -2452,4 +2501,32 @@ public class Grid<T> extends Composite implements
fireEvent(new SortEvent<T>(this,
Collections.unmodifiableList(sortOrder)));
}
+
+ /**
+ * Set currently active cell used for keyboard navigation. Note that active
+ * cell is not {@code activeElement}.
+ *
+ * @param cell
+ * a cell object
+ */
+ public void setActiveCell(Cell cell) {
+ int oldRow = activeRow;
+ int oldColumn = activeColumn;
+
+ activeRow = cell.getRow();
+ activeColumn = cell.getColumn();
+
+ if (oldRow != activeRow) {
+ escalator.getBody().refreshRows(oldRow, 1);
+ escalator.getBody().refreshRows(activeRow, 1);
+ }
+
+ if (oldColumn != activeColumn) {
+ if (oldRow == activeRow) {
+ escalator.getBody().refreshRows(oldRow, 1);
+ }
+ refreshHeader();
+ refreshFooter();
+ }
+ }
}
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java
index 6a1f1c3041..d5dd845e92 100644
--- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java
+++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java
@@ -86,6 +86,9 @@ public abstract class ComplexRenderer<T> implements Renderer<T> {
* <p>
* The events that triggers this needs to be returned by the
* {@link #getConsumedEvents()} method.
+ * <p>
+ * Returns boolean telling if the event has been completely handled and
+ * should not cause any other actions.
*
* @param cell
* Object containing information about the cell the event was
@@ -93,9 +96,10 @@ public abstract class ComplexRenderer<T> implements Renderer<T> {
*
* @param event
* The original DOM event
+ * @return true if event should not be handled by grid
*/
- public void onBrowserEvent(Cell cell, NativeEvent event) {
- // Implement if needed
+ public boolean onBrowserEvent(Cell cell, NativeEvent event) {
+ return false;
}
/**
diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java
index 3754c51f18..aa063a34e7 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java
@@ -482,7 +482,7 @@ public class MultiSelectionRenderer<T> extends ComplexRenderer<Boolean> {
}
@Override
- public void onBrowserEvent(final Cell cell, final NativeEvent event) {
+ public boolean onBrowserEvent(final Cell cell, final NativeEvent event) {
if (BrowserEvents.TOUCHSTART.equals(event.getType())
|| BrowserEvents.MOUSEDOWN.equals(event.getType())) {
injectNativeHandler();
@@ -491,6 +491,7 @@ public class MultiSelectionRenderer<T> extends ComplexRenderer<Boolean> {
autoScrollHandler.start(logicalRowIndex);
event.preventDefault();
event.stopPropagation();
+ return true;
} else {
throw new IllegalStateException("received unexpected event: "
+ event.getType());
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java
new file mode 100644
index 0000000000..927b941131
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.tests.components.grid;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridKeyboardNavigationTest extends MultiBrowserTest {
+
+ @Override
+ protected Class<?> getUIClass() {
+ return GridBasicFeatures.class;
+ }
+
+ @Test
+ public void testCellActiveOnClick() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ assertTrue("Body cell 0, 0 is not active on init.",
+ cellIsActive(grid, 0, 0));
+ grid.getCell(5, 2).click();
+ assertFalse("Body cell 0, 0 was still active after clicking",
+ cellIsActive(grid, 0, 0));
+ assertTrue("Body cell 5, 2 is not active after clicking",
+ cellIsActive(grid, 5, 2));
+ }
+
+ @Test
+ public void testCellNotActiveWhenRendererHandlesEvent() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ assertTrue("Body cell 0, 0 is not active on init.",
+ cellIsActive(grid, 0, 0));
+ grid.getHeaderCell(0, 3).click();
+ assertTrue("Body cell 0, 0 is not active after click on header.",
+ cellIsActive(grid, 0, 0));
+ }
+
+ private boolean cellIsActive(GridElement grid, int row, int col) {
+ return grid.getCell(row, col).getAttribute("class")
+ .contains("-cell-active");
+ }
+
+ private GridElement getGridElement() {
+ return $(GridElement.class).first();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java
index 40dbbeb370..9ee05cb036 100644
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java
@@ -58,11 +58,12 @@ public class RowAwareRendererConnector extends AbstractRendererConnector<Void> {
}
@Override
- public void onBrowserEvent(Cell cell, NativeEvent event) {
+ public boolean onBrowserEvent(Cell cell, NativeEvent event) {
int row = cell.getRow();
String key = getRowKey(row);
getRpcProxy(RowAwareRendererRpc.class).clicky(key);
cell.getElement().setInnerText("row: " + row + ", key: " + key);
+ return true;
}
}