summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJohannes Dahlström <johannesd@vaadin.com>2014-08-19 16:23:04 +0300
committerJohannes Dahlström <johannesd@vaadin.com>2014-08-29 08:54:15 +0000
commit63735b6f70d41c642f3d043bbba88093e6c2fba7 (patch)
tree43bc4308ef1edc6a4f1ebdb865be8629d2308126 /client
parent1de6a75497bae315dfcb70c272225a6d3ea0af19 (diff)
downloadvaadin-framework-63735b6f70d41c642f3d043bbba88093e6c2fba7.tar.gz
vaadin-framework-63735b6f70d41c642f3d043bbba88093e6c2fba7.zip
Initial client-side editor row implementation (#13334)
Only shows a bare grey row for now. Enter opens editor for active row, Esc hides editor. TODO * Double-click to edit does not work * Scrolling to edit hidden row does not work * EditorRowHandler to bind data+widgets * Server-side integration * Commit/discard buttons Change-Id: I0ae678b086493b0e46ab7c1db99eb92049318d6f
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ui/grid/EditorRow.java207
-rw-r--r--client/src/com/vaadin/client/ui/grid/Escalator.java2
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java135
3 files changed, 309 insertions, 35 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java
new file mode 100644
index 0000000000..45374962b7
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java
@@ -0,0 +1,207 @@
+/*
+ * 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;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.TableCellElement;
+import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.DOM;
+import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer;
+import com.vaadin.shared.ui.grid.ScrollDestination;
+
+/**
+ * An editor UI for Grid rows. A single Grid row at a time can be opened for
+ * editing.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class EditorRow<T> {
+
+ public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER;
+ public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE;
+
+ public enum State {
+ INACTIVE, ACTIVATING, ACTIVE, COMMITTING
+ }
+
+ private DivElement editorOverlay = DivElement.as(DOM.createDiv());
+
+ private Grid<T> grid;
+
+ private boolean enabled = false;
+ private State state = State.INACTIVE;
+ private int rowIndex = -1;
+ private String styleName = null;
+
+ public int getRow() {
+ return rowIndex;
+ }
+
+ /**
+ * Opens the editor over the row with the given index.
+ *
+ * @param rowIndex
+ * the index of the row to be edited
+ *
+ * @throws IllegalStateException
+ * if this editor row is not enabled or if it is already in edit
+ * mode
+ */
+ public void editRow(int rowIndex) {
+ if (!enabled) {
+ throw new IllegalStateException(
+ "Cannot edit row: EditorRow is not enabled");
+ }
+ if (state != State.INACTIVE) {
+ throw new IllegalStateException(
+ "Cannot edit row: EditorRow already in edit mode");
+ }
+
+ this.rowIndex = rowIndex;
+
+ state = State.ACTIVATING;
+
+ boolean rowVisible = grid.getEscalator().getVisibleRowRange()
+ .contains(rowIndex);
+
+ if (!rowVisible) {
+ grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE);
+ } else {
+ grid.getEscalator().getBody().refreshRows(rowIndex, 1);
+ }
+ }
+
+ /**
+ * Cancels the currently active edit and hides the editor.
+ *
+ * @throws IllegalStateException
+ * if this editor row is not in edit mode
+ */
+ public void cancel() {
+ if (state == State.INACTIVE) {
+ throw new IllegalStateException(
+ "Cannot cancel edit: EditorRow is not in edit mode");
+ }
+ state = State.INACTIVE;
+ hideOverlay();
+
+ grid.getEscalator().getBody().refreshRows(rowIndex, 1);
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Sets the enabled state of this editor row.
+ *
+ * @param enabled
+ * true if enabled, false otherwise
+ *
+ * @throws IllegalStateException
+ * if in edit mode and trying to disable
+ */
+ public void setEnabled(boolean enabled) {
+ if (enabled == false && state != State.INACTIVE) {
+ throw new IllegalStateException(
+ "Cannot disable: EditorRow is in edit mode");
+ }
+ this.enabled = enabled;
+ }
+
+ protected void setGrid(Grid<T> grid) {
+ this.grid = grid;
+ }
+
+ protected State getState() {
+ return state;
+ }
+
+ protected void setState(State state) {
+ this.state = state;
+ }
+
+ /**
+ * Opens the editor overlay over the given table row.
+ *
+ * @param tr
+ * the row to be edited
+ */
+ protected void showOverlay(TableRowElement tr) {
+
+ DivElement tableWrapper = DivElement.as(tr.getParentElement()
+ .getParentElement().getParentElement());
+
+ AbstractRowContainer body = (AbstractRowContainer) grid.getEscalator()
+ .getBody();
+
+ int rowTop = body.getRowTop(tr);
+ int bodyTop = body.getElement().getAbsoluteTop();
+ int wrapperTop = tableWrapper.getAbsoluteTop();
+
+ setBounds(editorOverlay, tr.getOffsetLeft(), rowTop + bodyTop
+ - wrapperTop, tr.getOffsetWidth(), tr.getOffsetHeight());
+
+ for (int i = 0; i < tr.getCells().getLength(); i++) {
+ Element cell = createCell(tr.getCells().getItem(i));
+ editorOverlay.appendChild(cell);
+ }
+
+ tableWrapper.appendChild(editorOverlay);
+ }
+
+ protected void hideOverlay() {
+ editorOverlay.removeFromParent();
+ }
+
+ protected void setStylePrimaryName(String primaryName) {
+ if (styleName != null) {
+ editorOverlay.removeClassName(styleName);
+ }
+ styleName = primaryName + "-editor-row";
+ editorOverlay.addClassName(styleName);
+ }
+
+ /**
+ * Creates an editor row cell corresponding to the given table cell. The
+ * returned element is empty and has the same dimensions and position as the
+ * table cell.
+ *
+ * @param td
+ * the table cell used as a reference
+ * @return an editor row cell corresponding to the given cell
+ */
+ protected Element createCell(TableCellElement td) {
+ DivElement cell = DivElement.as(DOM.createDiv());
+ setBounds(cell, td.getOffsetLeft(), td.getOffsetTop(),
+ td.getOffsetWidth(), td.getOffsetHeight());
+ return cell;
+ }
+
+ private static void setBounds(Element e, int left, int top, int width,
+ int height) {
+ Style style = e.getStyle();
+ style.setLeft(left, Unit.PX);
+ style.setTop(top, Unit.PX);
+ style.setWidth(width, Unit.PX);
+ style.setHeight(height, Unit.PX);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java
index ceff55e303..f686ec03ca 100644
--- a/client/src/com/vaadin/client/ui/grid/Escalator.java
+++ b/client/src/com/vaadin/client/ui/grid/Escalator.java
@@ -1058,7 +1058,7 @@ public class Escalator extends Widget {
}
}
- private abstract class AbstractRowContainer implements RowContainer {
+ protected abstract class AbstractRowContainer implements RowContainer {
private EscalatorUpdater updater = EscalatorUpdater.NULL;
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index 9c12b37bb5..89bf7fbc2b 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -49,6 +49,7 @@ import com.vaadin.client.Util;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.SubPartAware;
+import com.vaadin.client.ui.grid.EditorRow.State;
import com.vaadin.client.ui.grid.GridFooter.FooterRow;
import com.vaadin.client.ui.grid.GridHeader.HeaderRow;
import com.vaadin.client.ui.grid.GridStaticSection.StaticCell;
@@ -665,6 +666,8 @@ public class Grid<T> extends Composite implements
private final LazySorter lazySorter = new LazySorter();
+ private final EditorRow<T> editorRow = GWT.create(EditorRow.class);
+
/**
* Enumeration for easy setting of selection mode.
*/
@@ -937,7 +940,7 @@ public class Grid<T> extends Composite implements
@Override
public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
int rowIndex = row.getRow();
- Element rowElement = row.getElement();
+ TableRowElement rowElement = row.getElement();
T rowData = dataSource.getRow(rowIndex);
boolean hasData = rowData != null;
@@ -972,8 +975,8 @@ public class Grid<T> extends Composite implements
Renderer renderer = column.getRenderer();
- // Hide cell content if needed
if (renderer instanceof ComplexRenderer) {
+ // Hide cell content if needed
ComplexRenderer clxRenderer = (ComplexRenderer) renderer;
if (hasData) {
if (!usedToHaveData) {
@@ -999,6 +1002,13 @@ public class Grid<T> extends Composite implements
cell.getElement().removeAllChildren();
}
}
+
+ if (rowIndex == editorRow.getRow()) {
+ if (editorRow.getState() == State.ACTIVATING) {
+ editorRow.setState(State.ACTIVE);
+ editorRow.showOverlay(rowElement);
+ }
+ }
}
@Override
@@ -1225,6 +1235,8 @@ public class Grid<T> extends Composite implements
footer.setGrid(this);
+ editorRow.setGrid(this);
+
setSelectionMode(SelectionMode.SINGLE);
escalator.addScrollHandler(new ScrollHandler() {
@@ -1267,6 +1279,8 @@ public class Grid<T> extends Composite implements
public void setStylePrimaryName(String style) {
super.setStylePrimaryName(style);
escalator.setStylePrimaryName(style);
+ editorRow.setStylePrimaryName(style);
+
rowHasDataStyleName = getStylePrimaryName() + "-row-has-data";
rowSelectedStyleName = getStylePrimaryName() + "-row-selected";
cellActiveStyleName = getStylePrimaryName() + "-cell-active";
@@ -1582,6 +1596,14 @@ public class Grid<T> extends Composite implements
return footer;
}
+ public EditorRow<T> getEditorRow() {
+ return editorRow;
+ }
+
+ protected Escalator getEscalator() {
+ return escalator;
+ }
+
/**
* {@inheritDoc}
* <p>
@@ -1930,45 +1952,90 @@ public class Grid<T> extends Composite implements
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
+
EventTarget target = event.getEventTarget();
- if (Element.is(target)) {
- Element e = Element.as(target);
- RowContainer container = escalator.findRowContainer(e);
- Cell cell = null;
- if (container != null) {
- cell = container.getCell(e);
- if (cell != null) {
- // FIXME getFromVisibleIndex???
- GridColumn<?, T> gridColumn = columns.get(cell.getColumn());
-
- if (container == escalator.getHeader()) {
- if (getHeader().getRow(cell.getRow()).isDefault()) {
- handleDefaultRowEvent(cell, event);
- }
- } else if (container == escalator.getFooter()) {
- // NOP
- } else if (gridColumn.getRenderer() instanceof ComplexRenderer) {
- ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) gridColumn
- .getRenderer();
- if (cplxRenderer.getConsumedEvents().contains(
- event.getType())) {
- if (cplxRenderer.onBrowserEvent(cell, event)) {
- return;
- }
- }
- }
+
+ if (!Element.is(target)) {
+ return;
+ }
+
+ Element e = Element.as(target);
+ RowContainer container = escalator.findRowContainer(e);
+ Cell cell = container != null ? container.getCell(e) : null;
+
+ if (doEditorRowEvent(event, container, cell)) {
+ return;
+ }
+
+ if (container == escalator.getHeader()) {
+ if (getHeader().getRow(cell.getRow()).isDefault()) {
+ handleDefaultRowEvent(cell, event);
+ }
+ }
+
+ if (doRendererEvent(event, container, cell)) {
+ return;
+ }
+
+ if (doActiveCellEvent(event, container, cell)) {
+ return;
+ }
+ }
+
+ private boolean doEditorRowEvent(Event event, RowContainer container,
+ Cell cell) {
+ if (editorRow.getState() != State.INACTIVE) {
+ if (event.getTypeInt() == Event.ONKEYDOWN
+ && event.getKeyCode() == EditorRow.KEYCODE_HIDE) {
+ editorRow.cancel();
+ }
+ return true;
+ }
+ if (editorRow.isEnabled()) {
+ if (event.getTypeInt() == Event.ONDBLCLICK) {
+ if (container == escalator.getBody() && cell != null) {
+ editorRow.editRow(cell.getRow());
+ return true;
}
+ } else if (event.getTypeInt() == Event.ONKEYDOWN
+ && event.getKeyCode() == EditorRow.KEYCODE_SHOW) {
+ editorRow.editRow(activeCellHandler.activeRow);
+ return true;
}
+ }
+ return false;
+ }
+
+ private boolean doRendererEvent(Event event, RowContainer container,
+ Cell cell) {
+
+ if (container == escalator.getBody() && cell != null) {
+ GridColumn<?, T> gridColumn = getColumnFromVisibleIndex(cell
+ .getColumn());
- Collection<String> navigation = activeCellHandler
- .getNavigationEvents();
- if (navigation.contains(event.getType())
- && (Util.getFocusedElement() == getElement() || cell != null)) {
- activeCellHandler.handleNavigationEvent(event, cell);
+ if (gridColumn.getRenderer() instanceof ComplexRenderer) {
+ ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) gridColumn
+ .getRenderer();
+ if (cplxRenderer.getConsumedEvents().contains(event.getType())) {
+ if (cplxRenderer.onBrowserEvent(cell, event)) {
+ return true;
+ }
+ }
}
+ }
+ return false;
+ }
- handleGridNavigation(event, cell);
+ private boolean doActiveCellEvent(Event event, RowContainer container,
+ Cell cell) {
+ Collection<String> navigation = activeCellHandler.getNavigationEvents();
+ if (navigation.contains(event.getType())
+ && (Util.getFocusedElement() == getElement() || cell != null)) {
+ activeCellHandler.handleNavigationEvent(event, cell);
}
+ handleGridNavigation(event, cell);
+
+ return false;
}
private void handleGridNavigation(Event event, Cell cell) {