aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2015-09-04 15:05:27 +0300
committerArtur Signell <artur@vaadin.com>2015-09-04 15:05:27 +0300
commitf46be1b2792755cb7d9b111068dd6cf202398c4a (patch)
tree74f7098faee688cc1f1ca1b6ffe9e912338bbcaf /server/src/com/vaadin/ui
parente603ea3cf91e5dd0893b766f27d400947527fba9 (diff)
parentebceef4d44bcd61605fa92fcf7be8d3678537599 (diff)
downloadvaadin-framework-f46be1b2792755cb7d9b111068dd6cf202398c4a.tar.gz
vaadin-framework-f46be1b2792755cb7d9b111068dd6cf202398c4a.zip
Merge remote-tracking branch 'origin/master' into reconnect-dialog
Change-Id: Ie622160a83116c83b255a26bec297f73f3223ac7
Diffstat (limited to 'server/src/com/vaadin/ui')
-rw-r--r--server/src/com/vaadin/ui/AbstractFocusable.java134
-rw-r--r--server/src/com/vaadin/ui/Button.java105
-rw-r--r--server/src/com/vaadin/ui/Grid.java924
-rw-r--r--server/src/com/vaadin/ui/HorizontalLayout.java7
-rw-r--r--server/src/com/vaadin/ui/Table.java90
-rw-r--r--server/src/com/vaadin/ui/VerticalLayout.java7
-rw-r--r--server/src/com/vaadin/ui/Window.java238
-rw-r--r--server/src/com/vaadin/ui/renderers/ImageRenderer.java2
-rw-r--r--server/src/com/vaadin/ui/themes/ValoTheme.java2
9 files changed, 1155 insertions, 354 deletions
diff --git a/server/src/com/vaadin/ui/AbstractFocusable.java b/server/src/com/vaadin/ui/AbstractFocusable.java
new file mode 100644
index 0000000000..ad3b96f29b
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbstractFocusable.java
@@ -0,0 +1,134 @@
+/*
+ * 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.ui;
+
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
+import com.vaadin.shared.ui.TabIndexState;
+import com.vaadin.ui.Component.Focusable;
+
+/**
+ * An abstract base class for focusable components. Includes API for setting the
+ * tab index, programmatic focusing, and adding focus and blur listeners.
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public abstract class AbstractFocusable extends AbstractComponent implements
+ Focusable, FocusNotifier, BlurNotifier {
+
+ protected AbstractFocusable() {
+ registerRpc(new FocusAndBlurServerRpcImpl(this) {
+ @Override
+ protected void fireEvent(Event event) {
+ AbstractFocusable.this.fireEvent(event);
+ }
+ });
+ }
+
+ @Override
+ public void addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(BlurListener listener) {
+ addBlurListener(listener);
+ }
+
+ @Override
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(BlurListener listener) {
+ removeBlurListener(listener);
+
+ }
+
+ @Override
+ public void addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #addFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(FocusListener listener) {
+ addFocusListener(listener);
+ }
+
+ @Override
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(FocusListener listener) {
+ removeFocusListener(listener);
+ }
+
+ @Override
+ public void focus() {
+ super.focus();
+ }
+
+ @Override
+ public int getTabIndex() {
+ return getState(false).tabIndex;
+ }
+
+ @Override
+ public void setTabIndex(int tabIndex) {
+ getState().tabIndex = tabIndex;
+ }
+
+ @Override
+ protected TabIndexState getState() {
+ return (TabIndexState) super.getState();
+ }
+
+ @Override
+ protected TabIndexState getState(boolean markAsDirty) {
+ return (TabIndexState) super.getState(markAsDirty);
+ }
+}
diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java
index 6beb6ed686..a918780a60 100644
--- a/server/src/com/vaadin/ui/Button.java
+++ b/server/src/com/vaadin/ui/Button.java
@@ -24,12 +24,7 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import com.vaadin.event.Action;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.BlurEvent;
-import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
-import com.vaadin.event.FieldEvents.FocusEvent;
-import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
@@ -38,7 +33,6 @@ import com.vaadin.server.Resource;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.ButtonState;
-import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.util.ReflectTools;
@@ -50,8 +44,7 @@ import com.vaadin.util.ReflectTools;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class Button extends AbstractComponent implements
- FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable,
+public class Button extends AbstractFocusable implements
Action.ShortcutNotifier {
private ButtonServerRpc rpc = new ButtonServerRpc() {
@@ -72,20 +65,11 @@ public class Button extends AbstractComponent implements
}
};
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) {
-
- @Override
- protected void fireEvent(Event event) {
- Button.this.fireEvent(event);
- }
- };
-
/**
* Creates a new push button.
*/
public Button() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
}
/**
@@ -393,67 +377,6 @@ public class Button extends AbstractComponent implements
fireEvent(new Button.ClickEvent(this, details));
}
- @Override
- public void addBlurListener(BlurListener listener) {
- addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
- BlurListener.blurMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void addListener(BlurListener listener) {
- addBlurListener(listener);
- }
-
- @Override
- public void removeBlurListener(BlurListener listener) {
- removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(BlurListener listener) {
- removeBlurListener(listener);
- }
-
- @Override
- public void addFocusListener(FocusListener listener) {
- addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
- FocusListener.focusMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void addListener(FocusListener listener) {
- addFocusListener(listener);
- }
-
- @Override
- public void removeFocusListener(FocusListener listener) {
- removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(FocusListener listener) {
- removeFocusListener(listener);
- }
-
/*
* Actions
*/
@@ -575,32 +498,6 @@ public class Button extends AbstractComponent implements
getState().disableOnClick = disableOnClick;
}
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#getTabIndex()
- */
- @Override
- public int getTabIndex() {
- return getState(false).tabIndex;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
- */
- @Override
- public void setTabIndex(int tabIndex) {
- getState().tabIndex = tabIndex;
- }
-
- @Override
- public void focus() {
- // Overridden only to make public
- super.focus();
- }
-
@Override
protected ButtonState getState() {
return (ButtonState) super.getState();
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index e9469c5bca..215df3a6a3 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -31,6 +31,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -45,14 +46,17 @@ import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.collect.Sets.SetView;
import com.vaadin.data.Container;
import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.Container.ItemSetChangeEvent;
+import com.vaadin.data.Container.ItemSetChangeListener;
+import com.vaadin.data.Container.ItemSetChangeNotifier;
import com.vaadin.data.Container.PropertySetChangeEvent;
import com.vaadin.data.Container.PropertySetChangeListener;
import com.vaadin.data.Container.PropertySetChangeNotifier;
import com.vaadin.data.Container.Sortable;
+import com.vaadin.data.DataGenerator;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.RpcDataProviderExtension;
-import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper;
import com.vaadin.data.RpcDataProviderExtension.DetailComponentManager;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.fieldgroup.DefaultFieldGroupFieldFactory;
@@ -77,6 +81,7 @@ import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.Extension;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.VaadinSession;
@@ -89,13 +94,16 @@ import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridConstants;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode;
import com.vaadin.shared.ui.grid.GridStaticCellType;
import com.vaadin.shared.ui.grid.GridStaticSectionState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.shared.ui.grid.ScrollDestination;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
@@ -106,7 +114,6 @@ import com.vaadin.ui.renderers.TextRenderer;
import com.vaadin.util.ReflectTools;
import elemental.json.Json;
-import elemental.json.JsonArray;
import elemental.json.JsonObject;
import elemental.json.JsonValue;
@@ -172,7 +179,7 @@ import elemental.json.JsonValue;
* @since 7.4
* @author Vaadin Ltd
*/
-public class Grid extends AbstractComponent implements SelectionNotifier,
+public class Grid extends AbstractFocusable implements SelectionNotifier,
SortNotifier, SelectiveRenderer, ItemClickNotifier {
/**
@@ -511,6 +518,100 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Interface for an editor event listener
+ */
+ public interface EditorListener extends Serializable {
+
+ public static final Method EDITOR_OPEN_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorOpened",
+ EditorOpenEvent.class);
+ public static final Method EDITOR_MOVE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorMoved",
+ EditorMoveEvent.class);
+ public static final Method EDITOR_CLOSE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorClosed",
+ EditorCloseEvent.class);
+
+ /**
+ * Called when an editor is opened
+ *
+ * @param e
+ * an editor open event object
+ */
+ public void editorOpened(EditorOpenEvent e);
+
+ /**
+ * Called when an editor is reopened without closing it first
+ *
+ * @param e
+ * an editor move event object
+ */
+ public void editorMoved(EditorMoveEvent e);
+
+ /**
+ * Called when an editor is closed
+ *
+ * @param e
+ * an editor close event object
+ */
+ public void editorClosed(EditorCloseEvent e);
+
+ }
+
+ /**
+ * Base class for editor related events
+ */
+ public static abstract class EditorEvent extends Component.Event {
+
+ private Object itemID;
+
+ protected EditorEvent(Grid source, Object itemID) {
+ super(source);
+ this.itemID = itemID;
+ }
+
+ /**
+ * Get the item (row) for which this editor was opened
+ */
+ public Object getItem() {
+ return itemID;
+ }
+
+ }
+
+ /**
+ * This event gets fired when an editor is opened
+ */
+ public static class EditorOpenEvent extends EditorEvent {
+
+ public EditorOpenEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is opened while another row is being
+ * edited (i.e. editor focus moves elsewhere)
+ */
+ public static class EditorMoveEvent extends EditorEvent {
+
+ public EditorMoveEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is dismissed or closed by other
+ * means.
+ */
+ public static class EditorCloseEvent extends EditorEvent {
+
+ public EditorCloseEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
* Default error handler for the editor
*
*/
@@ -611,8 +712,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* The server-side interface that controls Grid's selection state.
+ * SelectionModel should extend {@link AbstractGridExtension}.
*/
- public interface SelectionModel extends Serializable {
+ public interface SelectionModel extends Serializable, Extension {
/**
* Checks whether an item is selected or not.
*
@@ -631,6 +733,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* Injects the current {@link Grid} instance into the SelectionModel.
+ * This method should usually call the extend method of
+ * {@link AbstractExtension}.
* <p>
* <em>Note:</em> This method should not be called manually.
*
@@ -872,10 +976,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* A base class for SelectionModels that contains some of the logic that is
* reusable.
*/
- public static abstract class AbstractSelectionModel implements
- SelectionModel {
+ public static abstract class AbstractSelectionModel extends
+ AbstractGridExtension implements SelectionModel, DataGenerator {
protected final LinkedHashSet<Object> selection = new LinkedHashSet<Object>();
- protected Grid grid = null;
@Override
public boolean isSelected(final Object itemId) {
@@ -889,7 +992,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void setGrid(final Grid grid) {
- this.grid = grid;
+ if (grid != null) {
+ extend(grid);
+ }
}
/**
@@ -903,7 +1008,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
protected void checkItemIdExists(Object itemId)
throws IllegalArgumentException {
- if (!grid.getContainerDataSource().containsId(itemId)) {
+ if (!getParentGrid().getContainerDataSource().containsId(itemId)) {
throw new IllegalArgumentException("Given item id (" + itemId
+ ") does not exist in the container");
}
@@ -945,7 +1050,19 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
protected void fireSelectionEvent(
final Collection<Object> oldSelection,
final Collection<Object> newSelection) {
- grid.fireSelectionEvent(oldSelection, newSelection);
+ getParentGrid().fireSelectionEvent(oldSelection, newSelection);
+ }
+
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ if (isSelected(itemId)) {
+ rowData.put(GridState.JSONKEY_SELECTED, true);
+ }
+ }
+
+ @Override
+ protected Object getItemId(String rowKey) {
+ return rowKey != null ? super.getItemId(rowKey) : null;
}
}
@@ -954,8 +1071,25 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public static class SingleSelectionModel extends AbstractSelectionModel
implements SelectionModel.Single {
+
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new SingleSelectionModelServerRpc() {
+
+ @Override
+ public void select(String rowKey) {
+ SingleSelectionModel.this.select(getItemId(rowKey), false);
+ }
+ });
+ }
+
@Override
public boolean select(final Object itemId) {
+ return select(itemId, true);
+ }
+
+ protected boolean select(final Object itemId, boolean refresh) {
if (itemId == null) {
return deselect(getSelectedRow());
}
@@ -967,7 +1101,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (modified) {
final Collection<Object> deselected;
if (selectedRow != null) {
- deselectInternal(selectedRow, false);
+ deselectInternal(selectedRow, false, true);
deselected = Collections.singleton(selectedRow);
} else {
deselected = Collections.emptySet();
@@ -976,19 +1110,28 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
fireSelectionEvent(deselected, selection);
}
+ if (refresh) {
+ refreshRow(itemId);
+ }
+
return modified;
}
private boolean deselect(final Object itemId) {
- return deselectInternal(itemId, true);
+ return deselectInternal(itemId, true, true);
}
private boolean deselectInternal(final Object itemId,
- boolean fireEventIfNeeded) {
+ boolean fireEventIfNeeded, boolean refresh) {
final boolean modified = selection.remove(itemId);
- if (fireEventIfNeeded && modified) {
- fireSelectionEvent(Collections.singleton(itemId),
- Collections.emptySet());
+ if (modified) {
+ if (refresh) {
+ refreshRow(itemId);
+ }
+ if (fireEventIfNeeded) {
+ fireSelectionEvent(Collections.singleton(itemId),
+ Collections.emptySet());
+ }
}
return modified;
}
@@ -1014,23 +1157,25 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void setDeselectAllowed(boolean deselectAllowed) {
- grid.getState().singleSelectDeselectAllowed = deselectAllowed;
+ getState().deselectAllowed = deselectAllowed;
}
@Override
public boolean isDeselectAllowed() {
- return grid.getState(false).singleSelectDeselectAllowed;
+ return getState().deselectAllowed;
+ }
+
+ @Override
+ protected SingleSelectionModelState getState() {
+ return (SingleSelectionModelState) super.getState();
}
}
/**
* A default implementation for a {@link SelectionModel.None}
*/
- public static class NoSelectionModel implements SelectionModel.None {
- @Override
- public void setGrid(final Grid grid) {
- // NOOP, not needed for anything
- }
+ public static class NoSelectionModel extends AbstractSelectionModel
+ implements SelectionModel.None {
@Override
public boolean isSelected(final Object itemId) {
@@ -1069,6 +1214,41 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
private int selectionLimit = DEFAULT_MAX_SELECTIONS;
@Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new MultiSelectionModelServerRpc() {
+
+ @Override
+ public void select(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.select(items, false);
+ }
+
+ @Override
+ public void deselect(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.deselect(items, false);
+ }
+
+ @Override
+ public void selectAll() {
+ MultiSelectionModel.this.selectAll(false);
+ }
+
+ @Override
+ public void deselectAll() {
+ MultiSelectionModel.this.deselectAll(false);
+ }
+ });
+ }
+
+ @Override
public boolean select(final Object... itemIds)
throws IllegalArgumentException {
if (itemIds != null) {
@@ -1089,6 +1269,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public boolean select(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return select(itemIds, true);
+ }
+
+ protected boolean select(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1113,6 +1297,15 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
fireSelectionEvent(oldSelection, selection);
}
+
+ updateAllSelectedState();
+
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return selectionWillChange;
}
@@ -1166,6 +1359,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public boolean deselect(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return deselect(itemIds, true);
+ }
+
+ protected boolean deselect(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1178,15 +1375,28 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
selection.removeAll(itemIds);
fireSelectionEvent(oldSelection, selection);
}
+
+ updateAllSelectedState();
+
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return hasCommonElements;
}
@Override
public boolean selectAll() {
+ return selectAll(true);
+ }
+
+ protected boolean selectAll(boolean refresh) {
// select will fire the event
- final Indexed container = grid.getContainerDataSource();
+ final Indexed container = getParentGrid().getContainerDataSource();
if (container != null) {
- return select(container.getItemIds());
+ return select(container.getItemIds(), refresh);
} else if (selection.isEmpty()) {
return false;
} else {
@@ -1195,14 +1405,18 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* but I guess the only theoretically correct course of
* action...
*/
- return deselectAll();
+ return deselectAll(false);
}
}
@Override
public boolean deselectAll() {
+ return deselectAll(true);
+ }
+
+ protected boolean deselectAll(boolean refresh) {
// deselect will fire the event
- return deselect(getSelectedRows());
+ return deselect(getSelectedRows(), refresh);
}
/**
@@ -1258,6 +1472,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
fireSelectionEvent(oldSelection, selection);
}
+ updateAllSelectedState();
+
return changed;
}
@@ -1271,6 +1487,17 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
"Vararg array of itemIds may not be null");
}
}
+
+ private void updateAllSelectedState() {
+ if (getState().allSelected != selection.size() >= selectionLimit) {
+ getState().allSelected = selection.size() >= selectionLimit;
+ }
+ }
+
+ @Override
+ protected MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
}
/**
@@ -1415,39 +1642,174 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
- * Callback interface for generating custom style names for data rows
+ * A callback interface for generating custom style names for Grid rows.
*
* @see Grid#setRowStyleGenerator(RowStyleGenerator)
*/
public interface RowStyleGenerator extends Serializable {
/**
- * Called by Grid to generate a style name for a row
+ * Called by Grid to generate a style name for a row.
*
- * @param rowReference
- * The row to generate a style for
+ * @param row
+ * the row to generate a style for
* @return the style name to add to this row, or {@code null} to not set
* any style
*/
- public String getStyle(RowReference rowReference);
+ public String getStyle(RowReference row);
}
/**
- * Callback interface for generating custom style names for cells
+ * A callback interface for generating custom style names for Grid cells.
*
* @see Grid#setCellStyleGenerator(CellStyleGenerator)
*/
public interface CellStyleGenerator extends Serializable {
/**
- * Called by Grid to generate a style name for a column
+ * Called by Grid to generate a style name for a column.
*
- * @param cellReference
- * The cell to generate a style for
+ * @param cell
+ * the cell to generate a style for
* @return the style name to add to this cell, or {@code null} to not
* set any style
*/
- public String getStyle(CellReference cellReference);
+ public String getStyle(CellReference cell);
+ }
+
+ /**
+ * A callback interface for generating optional descriptions (tooltips) for
+ * Grid rows. If a description is generated for a row, it is used for all
+ * the cells in the row for which a {@link CellDescriptionGenerator cell
+ * description} is not generated.
+ *
+ * @see Grid#setRowDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public interface RowDescriptionGenerator extends Serializable {
+
+ /**
+ * Called by Grid to generate a description (tooltip) for a row. The
+ * description may contain HTML which is rendered directly; if this is
+ * not desired the returned string must be escaped by the implementing
+ * method.
+ *
+ * @param row
+ * the row to generate a description for
+ * @return the row description or {@code null} for no description
+ */
+ public String getDescription(RowReference row);
+ }
+
+ /**
+ * A callback interface for generating optional descriptions (tooltips) for
+ * Grid cells. If a cell has both a {@link RowDescriptionGenerator row
+ * description} and a cell description, the latter has precedence.
+ *
+ * @see Grid#setCellDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public interface CellDescriptionGenerator extends Serializable {
+
+ /**
+ * Called by Grid to generate a description (tooltip) for a cell. The
+ * description may contain HTML which is rendered directly; if this is
+ * not desired the returned string must be escaped by the implementing
+ * method.
+ *
+ * @param cell
+ * the cell to generate a description for
+ * @return the cell description or {@code null} for no description
+ */
+ public String getDescription(CellReference cell);
+ }
+
+ /**
+ * Class for generating all row and cell related data for the essential
+ * parts of Grid.
+ */
+ private class RowDataGenerator implements DataGenerator {
+
+ private void put(String key, String value, JsonObject object) {
+ if (value != null && !value.isEmpty()) {
+ object.put(key, value);
+ }
+ }
+
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ RowReference row = new RowReference(Grid.this);
+ row.set(itemId);
+
+ if (rowStyleGenerator != null) {
+ String style = rowStyleGenerator.getStyle(row);
+ put(GridState.JSONKEY_ROWSTYLE, style, rowData);
+ }
+
+ if (rowDescriptionGenerator != null) {
+ String description = rowDescriptionGenerator
+ .getDescription(row);
+ put(GridState.JSONKEY_ROWDESCRIPTION, description, rowData);
+
+ }
+
+ JsonObject cellStyles = Json.createObject();
+ JsonObject cellData = Json.createObject();
+ JsonObject cellDescriptions = Json.createObject();
+
+ CellReference cell = new CellReference(row);
+
+ for (Column column : getColumns()) {
+ cell.set(column.getPropertyId());
+
+ writeData(cell, cellData);
+ writeStyles(cell, cellStyles);
+ writeDescriptions(cell, cellDescriptions);
+ }
+
+ if (cellDescriptionGenerator != null
+ && cellDescriptions.keys().length > 0) {
+ rowData.put(GridState.JSONKEY_CELLDESCRIPTION, cellDescriptions);
+ }
+
+ if (cellStyleGenerator != null && cellStyles.keys().length > 0) {
+ rowData.put(GridState.JSONKEY_CELLSTYLES, cellStyles);
+ }
+
+ rowData.put(GridState.JSONKEY_DATA, cellData);
+ }
+
+ private void writeStyles(CellReference cell, JsonObject styles) {
+ if (cellStyleGenerator != null) {
+ String style = cellStyleGenerator.getStyle(cell);
+ put(columnKeys.key(cell.getPropertyId()), style, styles);
+ }
+ }
+
+ private void writeDescriptions(CellReference cell,
+ JsonObject descriptions) {
+ if (cellDescriptionGenerator != null) {
+ String description = cellDescriptionGenerator
+ .getDescription(cell);
+ put(columnKeys.key(cell.getPropertyId()), description,
+ descriptions);
+ }
+ }
+
+ private void writeData(CellReference cell, JsonObject data) {
+ Column column = getColumn(cell.getPropertyId());
+ Converter<?, ?> converter = column.getConverter();
+ Renderer<?> renderer = column.getRenderer();
+
+ Item item = cell.getItem();
+ Object modelValue = item.getItemProperty(cell.getPropertyId())
+ .getValue();
+
+ data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer
+ .encodeValue(modelValue, renderer, converter, getLocale()));
+ }
}
/**
@@ -3281,7 +3643,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* currently extends the AbstractExtension superclass, but this fact should
* be regarded as an implementation detail and subject to change in a future
* major or minor Vaadin revision.
- *
+ *
* @param <T>
* the type this renderer knows how to present
*/
@@ -3354,7 +3716,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* is desired. For instance, a {@code Renderer<Date>} could first turn a
* date value into a formatted string and return
* {@code encode(dateString, String.class)}.
- *
+ *
* @param value
* the value to be encoded
* @param type
@@ -3365,11 +3727,79 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return JsonCodec.encode(value, null, type,
getUI().getConnectorTracker()).getEncodedValue();
}
+
+ /**
+ * Converts and encodes the given data model property value using the
+ * given converter and renderer. This method is public only for testing
+ * purposes.
+ *
+ * @param renderer
+ * the renderer to use
+ * @param converter
+ * the converter to use
+ * @param modelValue
+ * the value to convert and encode
+ * @param locale
+ * the locale to use in conversion
+ * @return an encoded value ready to be sent to the client
+ */
+ public static <T> JsonValue encodeValue(Object modelValue,
+ Renderer<T> renderer, Converter<?, ?> converter, Locale locale) {
+ Class<T> presentationType = renderer.getPresentationType();
+ T presentationValue;
+
+ if (converter == null) {
+ try {
+ presentationValue = presentationType.cast(modelValue);
+ } catch (ClassCastException e) {
+ if (presentationType == String.class) {
+ // If there is no converter, just fallback to using
+ // toString(). modelValue can't be null as
+ // Class.cast(null) will always succeed
+ presentationValue = (T) modelValue.toString();
+ } else {
+ throw new Converter.ConversionException(
+ "Unable to convert value of type "
+ + modelValue.getClass().getName()
+ + " to presentation type "
+ + presentationType.getName()
+ + ". No converter is set and the types are not compatible.");
+ }
+ }
+ } else {
+ assert presentationType.isAssignableFrom(converter
+ .getPresentationType());
+ @SuppressWarnings("unchecked")
+ Converter<T, Object> safeConverter = (Converter<T, Object>) converter;
+ presentationValue = safeConverter
+ .convertToPresentation(modelValue,
+ safeConverter.getPresentationType(), locale);
+ }
+
+ JsonValue encodedValue;
+ try {
+ encodedValue = renderer.encode(presentationValue);
+ } catch (Exception e) {
+ getLogger().log(Level.SEVERE, "Unable to encode data", e);
+ encodedValue = renderer.encode(null);
+ }
+
+ return encodedValue;
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(AbstractRenderer.class.getName());
+ }
+
}
/**
* An abstract base class for server-side Grid extensions.
- *
+ * <p>
+ * Note: If the extension is an instance of {@link DataGenerator} it will
+ * automatically register itself to {@link RpcDataProviderExtension} of
+ * extended Grid. On remove this registration is automatically removed.
+ *
* @since 7.5
*/
public static abstract class AbstractGridExtension extends
@@ -3384,7 +3814,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* Constructs a new Grid extension and extends given Grid.
- *
+ *
* @param grid
* a grid instance
*/
@@ -3393,6 +3823,26 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
extend(grid);
}
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+
+ if (this instanceof DataGenerator) {
+ getParentGrid().datasourceExtension
+ .addDataGenerator((DataGenerator) this);
+ }
+ }
+
+ @Override
+ public void remove() {
+ if (this instanceof DataGenerator) {
+ getParentGrid().datasourceExtension
+ .removeDataGenerator((DataGenerator) this);
+ }
+
+ super.remove();
+ }
+
/**
* Gets the item id for a row key.
* <p>
@@ -3405,7 +3855,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* @return the item id corresponding to {@code key}
*/
protected Object getItemId(String rowKey) {
- return getParentGrid().getKeyMapper().getItemId(rowKey);
+ return getParentGrid().getKeyMapper().get(rowKey);
}
/**
@@ -3434,11 +3884,27 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (getParent() instanceof Grid) {
Grid grid = (Grid) getParent();
return grid;
+ } else if (getParent() == null) {
+ throw new IllegalStateException(
+ "Renderer is not attached to any parent");
} else {
throw new IllegalStateException(
- "Renderers can be used only with Grid");
+ "Renderers can be used only with Grid. Extended "
+ + getParent().getClass().getSimpleName()
+ + " instead");
}
}
+
+ /**
+ * Resends the row data for given item id to the client.
+ *
+ * @since
+ * @param itemId
+ * row to refresh
+ */
+ protected void refreshRow(Object itemId) {
+ getParentGrid().datasourceExtension.updateRowData(itemId);
+ }
}
/**
@@ -3514,6 +3980,13 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
};
+ private final ItemSetChangeListener editorClosingItemSetListener = new ItemSetChangeListener() {
+ @Override
+ public void containerItemSetChange(ItemSetChangeEvent event) {
+ cancelEditor();
+ }
+ };
+
private RpcDataProviderExtension datasourceExtension;
/**
@@ -3539,6 +4012,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
private CellStyleGenerator cellStyleGenerator;
private RowStyleGenerator rowStyleGenerator;
+ private CellDescriptionGenerator cellDescriptionGenerator;
+ private RowDescriptionGenerator rowDescriptionGenerator;
+
/**
* <code>true</code> if Grid is using the internal IndexedContainer created
* in Grid() constructor, or <code>false</code> if the user has set their
@@ -3628,117 +4104,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
private void initGrid() {
setSelectionMode(getDefaultSelectionMode());
- addSelectionListener(new SelectionListener() {
- @Override
- public void select(SelectionEvent event) {
- if (applyingSelectionFromClient) {
- /*
- * Avoid sending changes back to the client if they
- * originated from the client. Instead, the RPC handler is
- * responsible for keeping track of the resulting selection
- * state and notifying the client if it doens't match the
- * expectation.
- */
- return;
- }
-
- /*
- * The rows are pinned here to ensure that the client gets the
- * correct key from server when the selected row is first
- * loaded.
- *
- * Once the client has gotten info that it is supposed to select
- * a row, it will pin the data from the client side as well and
- * it will be unpinned once it gets deselected. Nothing on the
- * server side should ever unpin anything from KeyMapper.
- * Pinning is mostly a client feature and is only used when
- * selecting something from the server side.
- */
- for (Object addedItemId : event.getAdded()) {
- if (!getKeyMapper().isPinned(addedItemId)) {
- getKeyMapper().pin(addedItemId);
- }
- }
-
- getState().selectedKeys = getKeyMapper().getKeys(
- getSelectedRows());
- }
- });
registerRpc(new GridServerRpc() {
@Override
- public void select(List<String> selection) {
- Collection<Object> receivedSelection = getKeyMapper()
- .getItemIds(selection);
-
- applyingSelectionFromClient = true;
- try {
- SelectionModel selectionModel = getSelectionModel();
- if (selectionModel instanceof SelectionModel.Single
- && selection.size() <= 1) {
- Object select = null;
- if (selection.size() == 1) {
- select = getKeyMapper().getItemId(selection.get(0));
- }
- ((SelectionModel.Single) selectionModel).select(select);
- } else if (selectionModel instanceof SelectionModel.Multi) {
- ((SelectionModel.Multi) selectionModel)
- .setSelected(receivedSelection);
- } else {
- throw new IllegalStateException("SelectionModel "
- + selectionModel.getClass().getSimpleName()
- + " does not support selecting the given "
- + selection.size() + " items.");
- }
- } finally {
- applyingSelectionFromClient = false;
- }
-
- Collection<Object> actualSelection = getSelectedRows();
-
- // Make sure all selected rows are pinned
- for (Object itemId : actualSelection) {
- if (!getKeyMapper().isPinned(itemId)) {
- getKeyMapper().pin(itemId);
- }
- }
-
- // Don't mark as dirty since this might be the expected state
- getState(false).selectedKeys = getKeyMapper().getKeys(
- actualSelection);
-
- JsonObject diffState = getUI().getConnectorTracker()
- .getDiffState(Grid.this);
-
- final String diffstateKey = "selectedKeys";
-
- assert diffState.hasKey(diffstateKey) : "Field name has changed";
-
- if (receivedSelection.equals(actualSelection)) {
- /*
- * We ended up with the same selection state that the client
- * sent us. There's nothing to send back to the client, just
- * update the diffstate so subsequent changes will be
- * detected.
- */
- JsonArray diffSelected = Json.createArray();
- for (String rowKey : getState(false).selectedKeys) {
- diffSelected.set(diffSelected.length(), rowKey);
- }
- diffState.put(diffstateKey, diffSelected);
- } else {
- /*
- * Actual selection is not what the client expects. Make
- * sure the client gets a state change event by clearing the
- * diffstate and marking as dirty
- */
- diffState.remove(diffstateKey);
- markAsDirty();
- }
- }
-
- @Override
public void sort(String[] columnIds, SortDirection[] directions,
boolean userOriginated) {
assert columnIds.length == directions.length;
@@ -3767,16 +4136,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
@Override
- public void selectAll() {
- assert getSelectionModel() instanceof SelectionModel.Multi : "Not a multi selection model!";
-
- ((SelectionModel.Multi) getSelectionModel()).selectAll();
- }
-
- @Override
public void itemClick(String rowKey, String columnId,
MouseEventDetails details) {
- Object itemId = getKeyMapper().getItemId(rowKey);
+ Object itemId = getKeyMapper().get(rowKey);
Item item = datasource.getItem(itemId);
Object propertyId = getPropertyIdByColumnId(columnId);
fireEvent(new ItemClickEvent(Grid.this, item, itemId,
@@ -3858,10 +4220,21 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
@Override
- public void sendDetailsComponents(int fetchId) {
- getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges(
- detailComponentManager.getAndResetConnectorChanges(),
- fetchId);
+ public void editorOpen(String rowKey) {
+ fireEvent(new EditorOpenEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
+ }
+
+ @Override
+ public void editorMove(String rowKey) {
+ fireEvent(new EditorMoveEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
+ }
+
+ @Override
+ public void editorClose(String rowKey) {
+ fireEvent(new EditorCloseEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
}
});
@@ -3869,28 +4242,37 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void bind(int rowIndex) {
- Exception exception = null;
try {
Object id = getContainerDataSource().getIdByIndex(rowIndex);
- if (editedItemId == null) {
- editedItemId = id;
- }
- if (editedItemId.equals(id)) {
- doEditItem();
+ final boolean opening = editedItemId == null;
+
+ final boolean moving = !opening && !editedItemId.equals(id);
+
+ final boolean allowMove = !isEditorBuffered()
+ && getEditorFieldGroup().isValid();
+
+ if (opening || !moving || allowMove) {
+ doBind(id);
+ } else {
+ failBind(null);
}
} catch (Exception e) {
- exception = e;
+ failBind(e);
}
+ }
- if (exception != null) {
- handleError(exception);
- doCancelEditor();
- getEditorRpc().confirmBind(false);
- } else {
- doEditItem();
- getEditorRpc().confirmBind(true);
+ private void doBind(Object id) {
+ editedItemId = id;
+ doEditItem();
+ getEditorRpc().confirmBind(true);
+ }
+
+ private void failBind(Exception e) {
+ if (e != null) {
+ handleError(e);
}
+ getEditorRpc().confirmBind(false);
}
@Override
@@ -3999,10 +4381,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
removeExtension(datasourceExtension);
}
- datasource = container;
-
resetEditor();
+ datasource = container;
+
//
// Adjust sort order
//
@@ -4031,7 +4413,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
datasourceExtension = new RpcDataProviderExtension(container);
- datasourceExtension.extend(this, columnKeys);
+ datasourceExtension.extend(this);
+ datasourceExtension.addDataGenerator(new RowDataGenerator());
detailComponentManager = datasourceExtension
.getDetailComponentManager();
@@ -4049,6 +4432,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
((PropertySetChangeNotifier) datasource)
.addPropertySetChangeListener(propertyListener);
}
+
/*
* activeRowHandler will be updated by the client-side request that
* occurs on container change - no need to actively re-insert any
@@ -4643,25 +5027,11 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (this.selectionModel != selectionModel) {
// this.selectionModel is null on init
if (this.selectionModel != null) {
- this.selectionModel.reset();
- this.selectionModel.setGrid(null);
+ this.selectionModel.remove();
}
this.selectionModel = selectionModel;
- this.selectionModel.setGrid(this);
- this.selectionModel.reset();
-
- if (selectionModel.getClass().equals(SingleSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.SINGLE;
- } else if (selectionModel.getClass().equals(
- MultiSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.MULTI;
- } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.NONE;
- } else {
- throw new UnsupportedOperationException("Grid currently "
- + "supports only its own bundled selection models");
- }
+ selectionModel.setGrid(this);
}
}
@@ -4928,7 +5298,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*
* @return the key mapper being used by the data source
*/
- DataProviderKeyMapper getKeyMapper() {
+ KeyMapper<Object> getKeyMapper() {
return datasourceExtension.getKeyMapper();
}
@@ -5489,6 +5859,73 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Sets the {@code CellDescriptionGenerator} instance for generating
+ * optional descriptions (tooltips) for individual Grid cells. If a
+ * {@link RowDescriptionGenerator} is also set, the row description it
+ * generates is displayed for cells for which {@code generator} returns
+ * null.
+ *
+ * @param generator
+ * the description generator to use or {@code null} to remove a
+ * previously set generator if any
+ *
+ * @see #setRowDescriptionGenerator(RowDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public void setCellDescriptionGenerator(CellDescriptionGenerator generator) {
+ cellDescriptionGenerator = generator;
+ getState().hasDescriptions = (generator != null || rowDescriptionGenerator != null);
+ datasourceExtension.refreshCache();
+ }
+
+ /**
+ * Returns the {@code CellDescriptionGenerator} instance used to generate
+ * descriptions (tooltips) for Grid cells.
+ *
+ * @return the description generator or {@code null} if no generator is set
+ *
+ * @since 7.6
+ */
+ public CellDescriptionGenerator getCellDescriptionGenerator() {
+ return cellDescriptionGenerator;
+ }
+
+ /**
+ * Sets the {@code RowDescriptionGenerator} instance for generating optional
+ * descriptions (tooltips) for Grid rows. If a
+ * {@link CellDescriptionGenerator} is also set, the row description
+ * generated by {@code generator} is used for cells for which the cell
+ * description generator returns null.
+ *
+ *
+ * @param generator
+ * the description generator to use or {@code null} to remove a
+ * previously set generator if any
+ *
+ * @see #setCellDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public void setRowDescriptionGenerator(RowDescriptionGenerator generator) {
+ rowDescriptionGenerator = generator;
+ getState().hasDescriptions = (generator != null || cellDescriptionGenerator != null);
+ datasourceExtension.refreshCache();
+ }
+
+ /**
+ * Returns the {@code RowDescriptionGenerator} instance used to generate
+ * descriptions (tooltips) for Grid rows
+ *
+ * @return the description generator or {@code} null if no generator is set
+ *
+ * @since 7.6
+ */
+ public RowDescriptionGenerator getRowDescriptionGenerator() {
+ return rowDescriptionGenerator;
+ }
+
+ /**
* Sets the style generator that is used for generating styles for cells
*
* @param cellStyleGenerator
@@ -5497,8 +5934,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) {
this.cellStyleGenerator = cellStyleGenerator;
- getState().hasCellStyleGenerator = (cellStyleGenerator != null);
-
datasourceExtension.refreshCache();
}
@@ -5521,8 +5956,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public void setRowStyleGenerator(RowStyleGenerator rowStyleGenerator) {
this.rowStyleGenerator = rowStyleGenerator;
- getState().hasRowStyleGenerator = (rowStyleGenerator != null);
-
datasourceExtension.refreshCache();
}
@@ -5732,10 +6165,14 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* Opens the editor interface for the provided item. Scrolls the Grid to
* bring the item to view if it is not already visible.
*
+ * Note that any cell content rendered by a WidgetRenderer will not be
+ * visible in the editor row.
+ *
* @param itemId
* the id of the item to edit
* @throws IllegalStateException
- * if the editor is not enabled or already editing an item
+ * if the editor is not enabled or already editing an item in
+ * buffered mode
* @throws IllegalArgumentException
* if the {@code itemId} is not in the backing container
* @see #setEditorEnabled(boolean)
@@ -5744,8 +6181,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
IllegalArgumentException {
if (!isEditorEnabled()) {
throw new IllegalStateException("Item editor is not enabled");
- } else if (editedItemId != null) {
- throw new IllegalStateException("Editing item + " + itemId
+ } else if (isEditorBuffered() && editedItemId != null) {
+ throw new IllegalStateException("Editing item " + itemId
+ " failed. Item editor is already editing item "
+ editedItemId);
} else if (!getContainerDataSource().containsId(itemId)) {
@@ -5773,6 +6210,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
f.markAsDirtyRecursive();
}
+ if (datasource instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) datasource)
+ .addItemSetChangeListener(editorClosingItemSetListener);
+ }
}
private void setEditorField(Object propertyId, Field<?> field) {
@@ -5822,6 +6263,11 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
editorFieldGroup.discard();
editorFieldGroup.setItemDataSource(null);
+ if (datasource instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) datasource)
+ .removeItemSetChangeListener(editorClosingItemSetListener);
+ }
+
// Mark Grid as dirty so the client side gets to know that the editors
// are no longer attached
markAsDirty();
@@ -5971,6 +6417,70 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return getState(false).editorCancelCaption;
}
+ /**
+ * Add an editor event listener
+ *
+ * @param listener
+ * the event listener object to add
+ */
+ public void addEditorListener(EditorListener listener) {
+ addListener(GridConstants.EDITOR_OPEN_EVENT_ID, EditorOpenEvent.class,
+ listener, EditorListener.EDITOR_OPEN_METHOD);
+ addListener(GridConstants.EDITOR_MOVE_EVENT_ID, EditorMoveEvent.class,
+ listener, EditorListener.EDITOR_MOVE_METHOD);
+ addListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener,
+ EditorListener.EDITOR_CLOSE_METHOD);
+ }
+
+ /**
+ * Remove an editor event listener
+ *
+ * @param listener
+ * the event listener object to remove
+ */
+ public void removeEditorListener(EditorListener listener) {
+ removeListener(GridConstants.EDITOR_OPEN_EVENT_ID,
+ EditorOpenEvent.class, listener);
+ removeListener(GridConstants.EDITOR_MOVE_EVENT_ID,
+ EditorMoveEvent.class, listener);
+ removeListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener);
+ }
+
+ /**
+ * Sets the buffered editor mode. The default mode is buffered (
+ * <code>true</code>).
+ *
+ * @since 7.6
+ * @param editorBuffered
+ * <code>true</code> to enable buffered editor,
+ * <code>false</code> to disable it
+ * @throws IllegalStateException
+ * If editor is active while attempting to change the buffered
+ * mode.
+ */
+ public void setEditorBuffered(boolean editorBuffered)
+ throws IllegalStateException {
+ if (isEditorActive()) {
+ throw new IllegalStateException(
+ "Can't change editor unbuffered mode while editor is active.");
+ }
+ getState().editorBuffered = editorBuffered;
+ editorFieldGroup.setBuffered(editorBuffered);
+ }
+
+ /**
+ * Gets the buffered editor mode.
+ *
+ * @since 7.6
+ * @return <code>true</code> if buffered editor is enabled,
+ * <code>false</code> otherwise
+ */
+ public boolean isEditorBuffered() {
+ return getState(false).editorBuffered;
+ }
+
@Override
public void addItemClickListener(ItemClickListener listener) {
addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
@@ -6063,8 +6573,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
this.detailsGenerator = detailsGenerator;
datasourceExtension.refreshDetails();
- getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges(
- detailComponentManager.getAndResetConnectorChanges(), -1);
}
/**
@@ -6088,6 +6596,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* to hide them
*/
public void setDetailsVisible(Object itemId, boolean visible) {
+ if (DetailsGenerator.NULL.equals(detailsGenerator)) {
+ return;
+ }
datasourceExtension.setDetailsVisible(itemId, visible);
}
@@ -6265,6 +6776,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
result.add("footer-visible");
result.add("editor-error-handler");
result.add("height-mode");
+
return result;
}
}
diff --git a/server/src/com/vaadin/ui/HorizontalLayout.java b/server/src/com/vaadin/ui/HorizontalLayout.java
index 54569570b9..616fa09225 100644
--- a/server/src/com/vaadin/ui/HorizontalLayout.java
+++ b/server/src/com/vaadin/ui/HorizontalLayout.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.ui;
+import com.vaadin.shared.ui.orderedlayout.HorizontalLayoutState;
+
/**
* Horizontal layout
*
@@ -48,4 +50,9 @@ public class HorizontalLayout extends AbstractOrderedLayout {
addComponents(children);
}
+ @Override
+ protected HorizontalLayoutState getState() {
+ return (HorizontalLayoutState) super.getState();
+ }
+
}
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index 42c4beab6c..10d1c45ab6 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -69,6 +69,7 @@ import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.ui.declarative.DesignException;
+import com.vaadin.util.ReflectTools;
/**
* <p>
@@ -1310,6 +1311,8 @@ public class Table extends AbstractSelect implements Action.Container,
* the desired collapsedness.
* @throws IllegalStateException
* if column collapsing is not allowed
+ * @throws IllegalArgumentException
+ * if the property id does not exist
*/
public void setColumnCollapsed(Object propertyId, boolean collapsed)
throws IllegalStateException {
@@ -1319,11 +1322,20 @@ public class Table extends AbstractSelect implements Action.Container,
if (collapsed && noncollapsibleColumns.contains(propertyId)) {
throw new IllegalStateException("The column is noncollapsible!");
}
+ if (!getContainerPropertyIds().contains(propertyId)
+ && !columnGenerators.containsKey(propertyId)) {
+ throw new IllegalArgumentException("Property '" + propertyId
+ + "' was not found in the container");
+ }
if (collapsed) {
- collapsedColumns.add(propertyId);
+ if (collapsedColumns.add(propertyId)) {
+ fireColumnCollapseEvent(propertyId);
+ }
} else {
- collapsedColumns.remove(propertyId);
+ if (collapsedColumns.remove(propertyId)) {
+ fireColumnCollapseEvent(propertyId);
+ }
}
// Assures the visual refresh
@@ -3182,6 +3194,10 @@ public class Table extends AbstractSelect implements Action.Container,
}
}
+ private void fireColumnCollapseEvent(Object propertyId) {
+ fireEvent(new ColumnCollapseEvent(this, propertyId));
+ }
+
private void fireColumnResizeEvent(Object propertyId, int previousWidth,
int currentWidth) {
/*
@@ -5742,6 +5758,53 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
+ * This event is fired when the collapse state of a column changes
+ */
+ public static class ColumnCollapseEvent extends Component.Event {
+
+ public static final Method METHOD = ReflectTools.findMethod(
+ ColumnCollapseListener.class, "columnCollapseStateChange",
+ ColumnCollapseEvent.class);
+ private Object propertyId;
+
+ /**
+ * Constructor
+ *
+ * @param source
+ * The source of the event
+ * @param propertyId
+ * The id of the column
+ */
+ public ColumnCollapseEvent(Component source, Object propertyId) {
+ super(source);
+ this.propertyId = propertyId;
+ }
+
+ /**
+ * Gets the id of the column whose collapse state changed
+ *
+ * @return the property id of the column
+ */
+ public Object getPropertyId() {
+ return propertyId;
+ }
+ }
+
+ /**
+ * Interface for listening to column collapse events.
+ */
+ public interface ColumnCollapseListener extends Serializable {
+
+ /**
+ * This method is triggered when the collapse state for a column has
+ * changed
+ *
+ * @param event
+ */
+ public void columnCollapseStateChange(ColumnCollapseEvent event);
+ }
+
+ /**
* Adds a column reorder listener to the Table. A column reorder listener is
* called when a user reorders columns.
*
@@ -5783,6 +5846,29 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
+ * Adds a column collapse listener to the Table. A column collapse listener
+ * is called when the collapsed state of a column changes.
+ *
+ * @param listener
+ * The listener to attach
+ */
+ public void addColumnCollapseListener(ColumnCollapseListener listener) {
+ addListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID,
+ ColumnCollapseEvent.class, listener, ColumnCollapseEvent.METHOD);
+ }
+
+ /**
+ * Removes a column reorder listener from the Table.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeColumnCollapseListener(ColumnCollapseListener listener) {
+ removeListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID,
+ ColumnCollapseEvent.class, listener);
+ }
+
+ /**
* Set the item description generator which generates tooltips for cells and
* rows in the Table
*
diff --git a/server/src/com/vaadin/ui/VerticalLayout.java b/server/src/com/vaadin/ui/VerticalLayout.java
index 12819e50bc..7002fbc7e6 100644
--- a/server/src/com/vaadin/ui/VerticalLayout.java
+++ b/server/src/com/vaadin/ui/VerticalLayout.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.ui;
+import com.vaadin.shared.ui.orderedlayout.VerticalLayoutState;
+
/**
* Vertical layout
*
@@ -48,4 +50,9 @@ public class VerticalLayout extends AbstractOrderedLayout {
this();
addComponents(children);
}
+
+ @Override
+ protected VerticalLayoutState getState() {
+ return (VerticalLayoutState) super.getState();
+ }
}
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index 61ba5826b8..fd5565f900 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -74,7 +75,7 @@ import com.vaadin.util.ReflectTools;
* @author Vaadin Ltd.
* @since 3.0
*/
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "deprecation" })
public class Window extends Panel implements FocusNotifier, BlurNotifier,
LegacyComponent {
@@ -102,6 +103,11 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
};
/**
+ * Holds registered CloseShortcut instances for query and later removal
+ */
+ private List<CloseShortcut> closeShortcuts = new ArrayList<CloseShortcut>(4);
+
+ /**
* Creates a new, empty window
*/
public Window() {
@@ -130,6 +136,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
super(caption, content);
registerRpc(rpc);
setSizeUndefined();
+ setCloseShortcut(KeyCode.ESCAPE);
}
/* ********************************************************************* */
@@ -828,14 +835,22 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
}
}
- /*
- * Actions
- */
- protected CloseShortcut closeShortcut;
-
/**
- * Makes is possible to close the window by pressing the given
- * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
+ * This is the old way of adding a keyboard shortcut to close a
+ * {@link Window} - to preserve compatibility with existing code under the
+ * new functionality, this method now first removes all registered close
+ * shortcuts, then adds the default ESCAPE shortcut key, and then attempts
+ * to add the shortcut provided as parameters to this method. This method,
+ * and its companion {@link #removeCloseShortcut()}, are now considered
+ * deprecated, as their main function is to preserve exact backwards
+ * compatibility with old code. For all new code, use the new keyboard
+ * shortcuts API: {@link #addCloseShortcut(int,int...)},
+ * {@link #removeCloseShortcut(int,int...)},
+ * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
+ * and {@link #getCloseShortcuts()}.
+ * <p>
+ * Original description: Makes it possible to close the window by pressing
+ * the given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
* Note that this shortcut only reacts while the window has focus, closing
* itself - if you want to close a window from a UI, use
* {@link UI#addAction(com.vaadin.event.Action)} of the UI instead.
@@ -843,29 +858,137 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
* @param keyCode
* the keycode for invoking the shortcut
* @param modifiers
- * the (optional) modifiers for invoking the shortcut, null for
- * none
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ *
+ * @deprecated Use {@link #addCloseShortcut(int, int...)} instead.
*/
+ @Deprecated
public void setCloseShortcut(int keyCode, int... modifiers) {
- if (closeShortcut != null) {
- removeAction(closeShortcut);
- }
- closeShortcut = new CloseShortcut(this, keyCode, modifiers);
- addAction(closeShortcut);
+ removeCloseShortcut();
+ addCloseShortcut(keyCode, modifiers);
}
/**
- * Removes the keyboard shortcut previously set with
- * {@link #setCloseShortcut(int, int...)}.
+ * Removes all keyboard shortcuts previously set with
+ * {@link #setCloseShortcut(int, int...)} and
+ * {@link #addCloseShortcut(int, int...)}, then adds the default
+ * {@link KeyCode#ESCAPE} shortcut.
+ * <p>
+ * This is the old way of removing the (single) keyboard close shortcut, and
+ * is retained only for exact backwards compatibility. For all new code, use
+ * the new keyboard shortcuts API: {@link #addCloseShortcut(int,int...)},
+ * {@link #removeCloseShortcut(int,int...)},
+ * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
+ * and {@link #getCloseShortcuts()}.
+ *
+ * @deprecated Use {@link #removeCloseShortcut(int, int...)} instead.
*/
+ @Deprecated
public void removeCloseShortcut() {
- if (closeShortcut != null) {
- removeAction(closeShortcut);
- closeShortcut = null;
+ for (int i = 0; i < closeShortcuts.size(); ++i) {
+ CloseShortcut sc = closeShortcuts.get(i);
+ removeAction(sc);
+ }
+ closeShortcuts.clear();
+ addCloseShortcut(KeyCode.ESCAPE);
+ }
+
+ /**
+ * Adds a close shortcut - pressing this key while holding down all (if any)
+ * modifiers specified while this Window is in focus will close the Window.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ */
+ public void addCloseShortcut(int keyCode, int... modifiers) {
+
+ // Ignore attempts to re-add existing shortcuts
+ if (hasCloseShortcut(keyCode, modifiers)) {
+ return;
+ }
+
+ // Actually add the shortcut
+ CloseShortcut shortcut = new CloseShortcut(this, keyCode, modifiers);
+ addAction(shortcut);
+ closeShortcuts.add(shortcut);
+ }
+
+ /**
+ * Removes a close shortcut previously added with
+ * {@link #addCloseShortcut(int, int...)}.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ */
+ public void removeCloseShortcut(int keyCode, int... modifiers) {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ if (shortcut.equals(keyCode, modifiers)) {
+ removeAction(shortcut);
+ closeShortcuts.remove(shortcut);
+ return;
+ }
}
}
/**
+ * Removes all close shortcuts. This includes the default ESCAPE shortcut.
+ * It is up to the user to add back any and all keyboard close shortcuts
+ * they may require. For more fine-grained control over shortcuts, use
+ * {@link #removeCloseShortcut(int, int...)}.
+ *
+ * @since
+ */
+ public void removeAllCloseShortcuts() {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ removeAction(shortcut);
+ }
+ closeShortcuts.clear();
+ }
+
+ /**
+ * Checks if a close window shortcut key has already been registered.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ * @return true, if an exactly matching shortcut has been registered.
+ */
+ public boolean hasCloseShortcut(int keyCode, int... modifiers) {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ if (shortcut.equals(keyCode, modifiers)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an unmodifiable collection of {@link CloseShortcut} objects
+ * currently registered with this {@link Window}. This method is provided
+ * mainly so that users can implement their own serialization routines. To
+ * check if a certain combination of keys has been registered as a close
+ * shortcut, use the {@link #hasCloseShortcut(int, int...)} method instead.
+ *
+ * @since
+ * @return an unmodifiable Collection of CloseShortcut objects.
+ */
+ public Collection<CloseShortcut> getCloseShortcuts() {
+ return Collections.unmodifiableCollection(closeShortcuts);
+ }
+
+ /**
* A {@link ShortcutListener} specifically made to define a keyboard
* shortcut that closes the window.
*
@@ -930,6 +1053,25 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
public void handleAction(Object sender, Object target) {
window.close();
}
+
+ public boolean equals(int keyCode, int... modifiers) {
+ if (keyCode != getKeyCode()) {
+ return false;
+ }
+
+ if (getModifiers() != null) {
+ int[] mods = null;
+ if (modifiers != null) {
+ // Modifiers provided by the parent ShortcutAction class
+ // are guaranteed to be sorted. We still need to sort
+ // the modifiers passed in as argument.
+ mods = Arrays.copyOf(modifiers, modifiers.length);
+ Arrays.sort(mods);
+ }
+ return Arrays.equals(mods, getModifiers());
+ }
+ return true;
+ }
}
/*
@@ -1244,11 +1386,26 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
setPositionX(Integer.parseInt(position[0]));
setPositionY(Integer.parseInt(position[1]));
}
+
+ // Parse shortcuts if defined, otherwise rely on default behavior
if (design.hasAttr("close-shortcut")) {
- ShortcutAction shortcut = DesignAttributeHandler
- .readAttribute("close-shortcut", design.attributes(),
- ShortcutAction.class);
- setCloseShortcut(shortcut.getKeyCode(), shortcut.getModifiers());
+
+ // Parse shortcuts
+ String[] shortcutStrings = DesignAttributeHandler.readAttribute(
+ "close-shortcut", design.attributes(), String.class).split(
+ "\\s+");
+
+ removeAllCloseShortcuts();
+
+ for (String part : shortcutStrings) {
+ if (!part.isEmpty()) {
+ ShortcutAction shortcut = DesignAttributeHandler
+ .getFormatter().parse(part.trim(),
+ ShortcutAction.class);
+ addCloseShortcut(shortcut.getKeyCode(),
+ shortcut.getModifiers());
+ }
+ }
}
}
@@ -1302,19 +1459,24 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
DesignAttributeHandler.writeAttribute("position", design.attributes(),
getPosition(), def.getPosition(), String.class);
- CloseShortcut shortcut = getCloseShortcut();
- if (shortcut != null) {
- // TODO What if several close shortcuts??
-
- CloseShortcut defShortcut = def.getCloseShortcut();
- if (defShortcut == null
- || shortcut.getKeyCode() != defShortcut.getKeyCode()
- || !Arrays.equals(shortcut.getModifiers(),
- defShortcut.getModifiers())) {
- DesignAttributeHandler.writeAttribute("close-shortcut",
- design.attributes(), shortcut, null,
- CloseShortcut.class);
+ // Process keyboard shortcuts
+ if (closeShortcuts.size() == 1 && hasCloseShortcut(KeyCode.ESCAPE)) {
+ // By default, we won't write anything if we're relying on default
+ // shortcut behavior
+ } else {
+ // Dump all close shortcuts to a string...
+ String attrString = "";
+
+ // TODO: add canonical support for array data in XML attributes
+ for (CloseShortcut shortcut : closeShortcuts) {
+ String shortcutString = DesignAttributeHandler.getFormatter()
+ .format(shortcut, CloseShortcut.class);
+ attrString += shortcutString + " ";
}
+
+ // Write everything except the last "," to the design
+ DesignAttributeHandler.writeAttribute("close-shortcut",
+ design.attributes(), attrString.trim(), null, String.class);
}
for (Component c : getAssistiveDescription()) {
@@ -1328,10 +1490,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
return getPositionX() + "," + getPositionY();
}
- private CloseShortcut getCloseShortcut() {
- return closeShortcut;
- }
-
@Override
protected Collection<String> getCustomAttributes() {
Collection<String> result = super.getCustomAttributes();
diff --git a/server/src/com/vaadin/ui/renderers/ImageRenderer.java b/server/src/com/vaadin/ui/renderers/ImageRenderer.java
index 2fb872583e..ad7d5cae2b 100644
--- a/server/src/com/vaadin/ui/renderers/ImageRenderer.java
+++ b/server/src/com/vaadin/ui/renderers/ImageRenderer.java
@@ -58,7 +58,7 @@ public class ImageRenderer extends ClickableRenderer<Resource> {
if (!(resource == null || resource instanceof ExternalResource || resource instanceof ThemeResource)) {
throw new IllegalArgumentException(
"ImageRenderer only supports ExternalResource and ThemeResource ("
- + resource.getClass().getSimpleName() + "given )");
+ + resource.getClass().getSimpleName() + " given)");
}
return encode(ResourceReference.create(resource, this, null),
diff --git a/server/src/com/vaadin/ui/themes/ValoTheme.java b/server/src/com/vaadin/ui/themes/ValoTheme.java
index 1285bf7f67..3a9986c632 100644
--- a/server/src/com/vaadin/ui/themes/ValoTheme.java
+++ b/server/src/com/vaadin/ui/themes/ValoTheme.java
@@ -709,7 +709,7 @@ public class ValoTheme {
* area is scrolled. Suitable with the {@link #PANEL_BORDERLESS} style. Can
* be combined with any other Panel style.
*/
- public static final String PANEL_SCROLL_INDICATOR = "scroll-indicator";
+ public static final String PANEL_SCROLL_INDICATOR = "scroll-divider";
/**
* Inset panel style. Can be combined with any other Panel style.