diff options
author | Artur Signell <artur@vaadin.com> | 2016-08-19 08:25:29 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2016-08-23 05:37:28 +0000 |
commit | 7daee066ae8b69ead326f6caccd17d6f0bfd9462 (patch) | |
tree | cf3b01efe74665c7d849e1d698a1ed857f47b28e /compatibility-server/src | |
parent | 8328038b3c695da27f6247fc9b33ed97c0e0d771 (diff) | |
download | vaadin-framework-7daee066ae8b69ead326f6caccd17d6f0bfd9462.tar.gz vaadin-framework-7daee066ae8b69ead326f6caccd17d6f0bfd9462.zip |
Move Container to compatibility package
Change-Id: I32bbf4891d6aca9dc9ee8f1b7ae733bc28b4cd30
Diffstat (limited to 'compatibility-server/src')
19 files changed, 3911 insertions, 0 deletions
diff --git a/compatibility-server/src/main/java/com/vaadin/event/DataBoundTransferable.java b/compatibility-server/src/main/java/com/vaadin/event/DataBoundTransferable.java new file mode 100644 index 0000000000..d4b4a5ba6b --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/event/DataBoundTransferable.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2016 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.event; + +import java.util.Map; + +import com.vaadin.ui.Component; +import com.vaadin.v7.data.Container; + +/** + * Parent class for {@link Transferable} implementations that have a Vaadin + * container as a data source. The transfer is associated with an item + * (identified by its Id) and optionally also a property identifier (e.g. a + * table column identifier when transferring a single table cell). + * + * The component must implement the interface + * {@link com.vaadin.v7.data.Container.Viewer}. + * + * In most cases, receivers of data transfers should depend on this class + * instead of its concrete subclasses. + * + * @since 6.3 + */ +public abstract class DataBoundTransferable extends TransferableImpl { + + public DataBoundTransferable(Component sourceComponent, + Map<String, Object> rawVariables) { + super(sourceComponent, rawVariables); + } + + /** + * Returns the identifier of the item being transferred. + * + * @return item identifier + */ + public abstract Object getItemId(); + + /** + * Returns the optional property identifier that the transfer concerns. + * + * This can be e.g. the table column from which a drag operation originated. + * + * @return property identifier + */ + public abstract Object getPropertyId(); + + /** + * Returns the container data source from which the transfer occurs. + * + * {@link com.vaadin.v7.data.Container.Viewer#getContainerDataSource()} is used + * to obtain the underlying container of the source component. + * + * @return Container + */ + public Container getSourceContainer() { + Component sourceComponent = getSourceComponent(); + if (sourceComponent instanceof Container.Viewer) { + return ((Container.Viewer) sourceComponent) + .getContainerDataSource(); + } else { + // this should not happen + return null; + } + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Collapsible.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Collapsible.java new file mode 100644 index 0000000000..a5d63c5a50 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Collapsible.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2016 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.v7.data; + +import com.vaadin.v7.data.Container.Hierarchical; +import com.vaadin.v7.data.Container.Ordered; + +/** + * Container needed by large lazy loading hierarchies displayed e.g. in + * TreeTable. + * <p> + * Container of this type gets notified when a subtree is opened/closed in a + * component displaying its content. This allows container to lazy load subtrees + * and release memory when a sub-tree is no longer displayed. + * <p> + * Methods from {@link Container.Ordered} (and from {@linkContainer.Indexed} if + * implemented) are expected to work as in "preorder" of the currently visible + * hierarchy. This means for example that the return value of size method + * changes when subtree is collapsed/expanded. In other words items in collapsed + * sub trees should be "ignored" by container when the container is accessed + * with methods introduced in {@link Container.Ordered} or + * {@linkContainer.Indexed}. From the accessors point of view, items in + * collapsed subtrees don't exist. + * <p> + * + */ +public interface Collapsible extends Hierarchical, Ordered { + + /** + * <p> + * Collapsing the {@link Item} indicated by <code>itemId</code> hides all + * children, and their respective children, from the {@link Container}. + * </p> + * + * <p> + * If called on a leaf {@link Item}, this method does nothing. + * </p> + * + * @param itemId + * the identifier of the collapsed {@link Item} + * @param collapsed + * <code>true</code> if you want to collapse the children below + * this {@link Item}. <code>false</code> if you want to + * uncollapse the children. + */ + public void setCollapsed(Object itemId, boolean collapsed); + + /** + * <p> + * Checks whether the {@link Item}, identified by <code>itemId</code> is + * collapsed or not. + * </p> + * + * <p> + * If an {@link Item} is "collapsed" its children are not included in + * methods used to list Items in this container. + * </p> + * + * @param itemId + * The {@link Item}'s identifier that is to be checked. + * @return <code>true</code> iff the {@link Item} identified by + * <code>itemId</code> is currently collapsed, otherwise + * <code>false</code>. + */ + public boolean isCollapsed(Object itemId); + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Container.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Container.java new file mode 100644 index 0000000000..c280525dcd --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Container.java @@ -0,0 +1,1255 @@ +/* + * Copyright 2000-2016 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.v7.data; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +import com.vaadin.v7.data.util.filter.SimpleStringFilter; +import com.vaadin.v7.data.util.filter.UnsupportedFilterException; + +/** + * <p> + * A specialized set of identified Items. Basically the Container is a set of + * {@link Item}s, but it imposes certain constraints on its contents. These + * constraints state the following: + * </p> + * + * <ul> + * <li>All Items in the Container must have the same number of Properties. + * <li>All Items in the Container must have the same Property ID's (see + * {@link Item#getItemPropertyIds()}). + * <li>All Properties in the Items corresponding to the same Property ID must + * have the same data type. + * <li>All Items within a container are uniquely identified by their non-null + * IDs. + * </ul> + * + * <p> + * The Container can be visualized as a representation of a relational database + * table. Each Item in the Container represents a row in the table, and all + * cells in a column (identified by a Property ID) have the same data type. Note + * that as with the cells in a database table, no Property in a Container may be + * empty, though they may contain <code>null</code> values. + * </p> + * + * <p> + * Note that though uniquely identified, the Items in a Container are not + * necessarily {@link Container.Ordered ordered} or {@link Container.Indexed + * indexed}. + * </p> + * + * <p> + * Containers can derive Item ID's from the item properties or use other, + * container specific or user specified identifiers. + * </p> + * + * <p> + * If a container is {@link Filterable filtered} or {@link Sortable sorted}, + * most of the the methods of the container interface and its subinterfaces + * (container size, {@link #containsId(Object)}, iteration and indices etc.) + * relate to the filtered and sorted view, not to the full container contents. + * See individual method javadoc for exceptions to this (adding and removing + * items). + * </p> + * + * <p> + * <img src=doc-files/Container_full.gif> + * </p> + * + * <p> + * The Container interface is split to several subinterfaces so that a class can + * implement only the ones it needs. + * </p> + * + * @author Vaadin Ltd + * @since 3.0 + */ +public interface Container extends Serializable { + + /** + * Gets the {@link Item} with the given Item ID from the Container. If the + * Container does not contain the requested Item, <code>null</code> is + * returned. + * <p> + * Containers should not return Items that are filtered out. + * + * @param itemId + * ID of the {@link Item} to retrieve + * @return the {@link Item} with the given ID or <code>null</code> if the + * Item is not found in the Container + */ + public Item getItem(Object itemId); + + /** + * Gets the ID's of all Properties stored in the Container. The ID's cannot + * be modified through the returned collection. + * + * @return unmodifiable collection of Property IDs + */ + public Collection<?> getContainerPropertyIds(); + + /** + * Gets the ID's of all visible (after filtering and sorting) Items stored + * in the Container. The ID's cannot be modified through the returned + * collection. + * <p> + * If the container is {@link Ordered}, the collection returned by this + * method should follow that order. If the container is {@link Sortable}, + * the items should be in the sorted order. + * <p> + * Calling this method for large lazy containers can be an expensive + * operation and should be avoided when practical. + * + * @return unmodifiable collection of Item IDs + */ + public Collection<?> getItemIds(); + + /** + * Gets the Property identified by the given itemId and propertyId from the + * Container. If the Container does not contain the item or it is filtered + * out, or the Container does not have the Property, <code>null</code> is + * returned. + * + * @param itemId + * ID of the visible Item which contains the Property + * @param propertyId + * ID of the Property to retrieve + * @return Property with the given ID or <code>null</code> + */ + public Property getContainerProperty(Object itemId, Object propertyId); + + /** + * Gets the data type of all Properties identified by the given Property ID. + * + * @param propertyId + * ID identifying the Properties + * @return data type of the Properties + */ + public Class<?> getType(Object propertyId); + + /** + * Gets the number of visible Items in the Container. + * <p> + * Filtering can hide items so that they will not be visible through the + * container API. + * + * @return number of Items in the Container + */ + public int size(); + + /** + * Tests if the Container contains the specified Item. + * <p> + * Filtering can hide items so that they will not be visible through the + * container API, and this method should respect visibility of items (i.e. + * only indicate visible items as being in the container) if feasible for + * the container. + * + * @param itemId + * ID the of Item to be tested + * @return boolean indicating if the Container holds the specified Item + */ + public boolean containsId(Object itemId); + + /** + * Creates a new Item with the given ID in the Container. + * + * <p> + * The new Item is returned, and it is ready to have its Properties + * modified. Returns <code>null</code> if the operation fails or the + * Container already contains a Item with the given ID. + * </p> + * + * <p> + * This functionality is optional. + * </p> + * + * @param itemId + * ID of the Item to be created + * @return Created new Item, or <code>null</code> in case of a failure + * @throws UnsupportedOperationException + * if adding an item with an explicit item ID is not supported + * by the container + */ + public Item addItem(Object itemId) throws UnsupportedOperationException; + + /** + * Creates a new Item into the Container, and assign it an automatic ID. + * + * <p> + * The new ID is returned, or <code>null</code> if the operation fails. + * After a successful call you can use the {@link #getItem(Object ItemId) + * <code>getItem</code>}method to fetch the Item. + * </p> + * + * <p> + * This functionality is optional. + * </p> + * + * @return ID of the newly created Item, or <code>null</code> in case of a + * failure + * @throws UnsupportedOperationException + * if adding an item without an explicit item ID is not + * supported by the container + */ + public Object addItem() throws UnsupportedOperationException; + + /** + * Removes the Item identified by <code>ItemId</code> from the Container. + * + * <p> + * Containers that support filtering should also allow removing an item that + * is currently filtered out. + * </p> + * + * <p> + * This functionality is optional. + * </p> + * + * @param itemId + * ID of the Item to remove + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the container does not support removing individual items + */ + public boolean removeItem(Object itemId) + throws UnsupportedOperationException; + + /** + * Adds a new Property to all Items in the Container. The Property ID, data + * type and default value of the new Property are given as parameters. + * <p> + * This functionality is optional. + * + * @param propertyId + * ID of the Property + * @param type + * Data type of the new Property + * @param defaultValue + * The value all created Properties are initialized to + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the container does not support explicitly adding container + * properties + */ + public boolean addContainerProperty(Object propertyId, Class<?> type, + Object defaultValue) throws UnsupportedOperationException; + + /** + * Removes a Property specified by the given Property ID from the Container. + * Note that the Property will be removed from all Items in the Container. + * <p> + * This functionality is optional. + * + * @param propertyId + * ID of the Property to remove + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the container does not support removing container + * properties + */ + public boolean removeContainerProperty(Object propertyId) + throws UnsupportedOperationException; + + /** + * Removes all Items from the Container. + * + * <p> + * Note that Property ID and type information is preserved. This + * functionality is optional. + * </p> + * + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the container does not support removing all items + */ + public boolean removeAllItems() throws UnsupportedOperationException; + + /** + * Interface for Container classes whose {@link Item}s can be traversed in + * order. + * + * <p> + * If the container is filtered or sorted, the traversal applies to the + * filtered and sorted view. + * </p> + * <p> + * The <code>addItemAfter()</code> methods should apply filters to the added + * item after inserting it, possibly hiding it immediately. If the container + * is being sorted, they may add items at the correct sorted position + * instead of the given position. See also {@link Filterable} and + * {@link Sortable} for more information. + * </p> + */ + public interface Ordered extends Container { + + /** + * Gets the ID of the Item following the Item that corresponds to + * <code>itemId</code>. If the given Item is the last or not found in + * the Container, <code>null</code> is returned. + * + * @param itemId + * ID of a visible Item in the Container + * @return ID of the next visible Item or <code>null</code> + */ + public Object nextItemId(Object itemId); + + /** + * Gets the ID of the Item preceding the Item that corresponds to + * <code>itemId</code>. If the given Item is the first or not found in + * the Container, <code>null</code> is returned. + * + * @param itemId + * ID of a visible Item in the Container + * @return ID of the previous visible Item or <code>null</code> + */ + public Object prevItemId(Object itemId); + + /** + * Gets the ID of the first Item in the Container. + * + * @return ID of the first visible Item in the Container + */ + public Object firstItemId(); + + /** + * Gets the ID of the last Item in the Container.. + * + * @return ID of the last visible Item in the Container + */ + public Object lastItemId(); + + /** + * Tests if the Item corresponding to the given Item ID is the first + * Item in the Container. + * + * @param itemId + * ID of an Item in the Container + * @return <code>true</code> if the Item is first visible item in the + * Container, <code>false</code> if not + */ + public boolean isFirstId(Object itemId); + + /** + * Tests if the Item corresponding to the given Item ID is the last Item + * in the Container. + * + * @return <code>true</code> if the Item is last visible item in the + * Container, <code>false</code> if not + */ + public boolean isLastId(Object itemId); + + /** + * Adds a new item after the given item. + * <p> + * Adding an item after null item adds the item as first item of the + * ordered container. + * </p> + * + * @see Ordered Ordered: adding items in filtered or sorted containers + * + * @param previousItemId + * Id of the visible item in ordered container after which to + * insert the new item. + * @return item id the the created new item or null if the operation + * fails. + * @throws UnsupportedOperationException + * if the operation is not supported by the container + */ + public Object addItemAfter(Object previousItemId) + throws UnsupportedOperationException; + + /** + * Adds a new item after the given item. + * <p> + * Adding an item after null item adds the item as first item of the + * ordered container. + * </p> + * + * @see Ordered Ordered: adding items in filtered or sorted containers + * + * @param previousItemId + * Id of the visible item in ordered container after which to + * insert the new item. + * @param newItemId + * Id of the new item to be added. + * @return new item or null if the operation fails. + * @throws UnsupportedOperationException + * if the operation is not supported by the container + */ + public Item addItemAfter(Object previousItemId, Object newItemId) + throws UnsupportedOperationException; + + } + + /** + * Interface for Container classes whose {@link Item}s can be sorted. + * <p> + * When an {@link Ordered} or {@link Indexed} container is sorted, all + * relevant operations of these interfaces should only use the filtered and + * sorted contents and the filtered indices to the container. Indices or + * item identifiers in the public API refer to the visible view unless + * otherwise stated. However, the <code>addItem*()</code> methods may add + * items that will be filtered out after addition or moved to another + * position based on sorting. + * </p> + * <p> + * How sorting is performed when a {@link Hierarchical} container implements + * {@link Sortable} is implementation specific and should be documented in + * the implementing class. However, the recommended approach is sorting the + * roots and the sets of children of each item separately. + * </p> + * <p> + * Depending on the container type, sorting a container may permanently + * change the internal order of items in the container. + * </p> + */ + public interface Sortable extends Ordered { + + /** + * Sorts the container items. + * <p> + * Sorting a container can irreversibly change the order of its items or + * only change the order temporarily, depending on the container. + * + * @param propertyId + * Array of container property IDs, whose values are used to + * sort the items in container as primary, secondary, ... + * sorting criterion. All of the item IDs must be in the + * collection returned by + * {@link #getSortableContainerPropertyIds()} + * @param ascending + * Array of sorting order flags corresponding to each + * property ID used in sorting. If this array is shorter than + * propertyId array, ascending order is assumed for items + * where the order is not specified. Use <code>true</code> to + * sort in ascending order, <code>false</code> to use + * descending order. + */ + void sort(Object[] propertyId, boolean[] ascending); + + /** + * Gets the container property IDs which can be used to sort the items. + * + * @return the IDs of the properties that can be used for sorting the + * container + */ + Collection<?> getSortableContainerPropertyIds(); + + } + + /** + * Interface for Container classes whose {@link Item}s can be accessed by + * their position in the container. + * <p> + * If the container is filtered or sorted, all indices refer to the filtered + * and sorted view. However, the <code>addItemAt()</code> methods may add + * items that will be filtered out after addition or moved to another + * position based on sorting. + * </p> + */ + public interface Indexed extends Ordered { + + /** + * Gets the index of the Item corresponding to the itemId. The following + * is <code>true</code> for the returned index: 0 <= index < size(), or + * index = -1 if there is no visible item with that id in the container. + * + * @param itemId + * ID of an Item in the Container + * @return index of the Item, or -1 if (the filtered and sorted view of) + * the Container does not include the Item + */ + public int indexOfId(Object itemId); + + /** + * Get the item id for the item at the position given by + * <code>index</code>. + * <p> + * + * @param index + * the index of the requested item id + * @return the item id of the item at the given index + * @throws IndexOutOfBoundsException + * if <code>index</code> is outside the range of the + * container. (i.e. + * <code>index < 0 || container.size()-1 < index</code> + * ) + */ + public Object getIdByIndex(int index); + + /** + * Get <code>numberOfItems</code> consecutive item ids from the + * container, starting with the item id at <code>startIndex</code>. + * <p> + * Implementations should return at most <code>numberOfItems</code> item + * ids, but can contain less if the container has less items than + * required to fulfill the request. The returned list must hence contain + * all of the item ids from the range: + * <p> + * <code>startIndex</code> to + * <code>max(startIndex + (numberOfItems-1), container.size()-1)</code>. + * <p> + * For quick migration to new API see: + * {@link ContainerHelpers#getItemIdsUsingGetIdByIndex(int, int, Indexed)} + * + * @param startIndex + * the index for the first item which id to include + * @param numberOfItems + * the number of consecutive item ids to get from the given + * start index, must be >= 0 + * @return List containing the requested item ids or empty list if + * <code>numberOfItems</code> == 0; not null + * + * @throws IllegalArgumentException + * if <code>numberOfItems</code> is < 0 + * @throws IndexOutOfBoundsException + * if <code>startIndex</code> is outside the range of the + * container. (i.e. + * <code>startIndex < 0 || container.size()-1 < startIndex</code> + * ) + * + * @since 7.0 + */ + public List<?> getItemIds(int startIndex, int numberOfItems); + + /** + * Adds a new item at given index (in the filtered view). + * <p> + * The indices of the item currently in the given position and all the + * following items are incremented. + * </p> + * <p> + * This method should apply filters to the added item after inserting + * it, possibly hiding it immediately. If the container is being sorted, + * the item may be added at the correct sorted position instead of the + * given position. See {@link Indexed}, {@link Ordered}, + * {@link Filterable} and {@link Sortable} for more information. + * </p> + * + * @param index + * Index (in the filtered and sorted view) to add the new + * item. + * @return item id of the created item or null if the operation fails. + * @throws UnsupportedOperationException + * if the operation is not supported by the container + */ + public Object addItemAt(int index) throws UnsupportedOperationException; + + /** + * Adds a new item at given index (in the filtered view). + * <p> + * The indexes of the item currently in the given position and all the + * following items are incremented. + * </p> + * <p> + * This method should apply filters to the added item after inserting + * it, possibly hiding it immediately. If the container is being sorted, + * the item may be added at the correct sorted position instead of the + * given position. See {@link Indexed}, {@link Filterable} and + * {@link Sortable} for more information. + * </p> + * + * @param index + * Index (in the filtered and sorted view) at which to add + * the new item. + * @param newItemId + * Id of the new item to be added. + * @return new {@link Item} or null if the operation fails. + * @throws UnsupportedOperationException + * if the operation is not supported by the container + */ + public Item addItemAt(int index, Object newItemId) + throws UnsupportedOperationException; + + /** + * An <code>Event</code> object specifying information about the added + * items. + * + * @since 7.4 + */ + public interface ItemAddEvent extends ItemSetChangeEvent { + + /** + * Gets the item id of the first added item. + * + * @return item id of the first added item + */ + public Object getFirstItemId(); + + /** + * Gets the index of the first added item. + * + * @return index of the first added item + */ + public int getFirstIndex(); + + /** + * Gets the number of the added items. + * + * @return the number of added items. + */ + public int getAddedItemsCount(); + } + + /** + * An <code>Event</code> object specifying information about the removed + * items. + * + * @since 7.4 + */ + public interface ItemRemoveEvent extends ItemSetChangeEvent { + /** + * Gets the item id of the first removed item. + * + * @return item id of the first removed item + */ + public Object getFirstItemId(); + + /** + * Gets the index of the first removed item. + * + * @return index of the first removed item + */ + public int getFirstIndex(); + + /** + * Gets the number of the removed items. + * + * @return the number of removed items + */ + public int getRemovedItemsCount(); + } + } + + /** + * <p> + * Interface for <code>Container</code> classes whose Items can be arranged + * hierarchically. This means that the Items in the container belong in a + * tree-like structure, with the following quirks: + * </p> + * + * <ul> + * <li>The Item structure may have more than one root elements + * <li>The Items in the hierarchy can be declared explicitly to be able or + * unable to have children. + * </ul> + */ + public interface Hierarchical extends Container { + + /** + * Gets the IDs of all Items that are children of the specified Item. + * The returned collection is unmodifiable. + * + * @param itemId + * ID of the Item whose children the caller is interested in + * @return An unmodifiable {@link java.util.Collection collection} + * containing the IDs of all other Items that are children in + * the container hierarchy + */ + public Collection<?> getChildren(Object itemId); + + /** + * Gets the ID of the parent Item of the specified Item. + * + * @param itemId + * ID of the Item whose parent the caller wishes to find out. + * @return the ID of the parent Item. Will be <code>null</code> if the + * specified Item is a root element. + */ + public Object getParent(Object itemId); + + /** + * Gets the IDs of all Items in the container that don't have a parent. + * Such items are called <code>root</code> Items. The returned + * collection is unmodifiable. + * + * @return An unmodifiable {@link java.util.Collection collection} + * containing IDs of all root elements of the container + */ + public Collection<?> rootItemIds(); + + /** + * <p> + * Sets the parent of an Item. The new parent item must exist and be + * able to have children. ( + * <code>{@link #areChildrenAllowed(Object)} == true</code> ). It is + * also possible to detach a node from the hierarchy (and thus make it + * root) by setting the parent <code>null</code>. + * </p> + * + * <p> + * This operation is optional. + * </p> + * + * @param itemId + * ID of the item to be set as the child of the Item + * identified with <code>newParentId</code> + * @param newParentId + * ID of the Item that's to be the new parent of the Item + * identified with <code>itemId</code> + * @return <code>true</code> if the operation succeeded, + * <code>false</code> if not + */ + public boolean setParent(Object itemId, Object newParentId) + throws UnsupportedOperationException; + + /** + * Tests if the Item with given ID can have children. + * + * @param itemId + * ID of the Item in the container whose child capability is + * to be tested + * @return <code>true</code> if the specified Item exists in the + * Container and it can have children, <code>false</code> if + * it's not found from the container or it can't have children. + */ + public boolean areChildrenAllowed(Object itemId); + + /** + * <p> + * Sets the given Item's capability to have children. If the Item + * identified with <code>itemId</code> already has children and + * <code>{@link #areChildrenAllowed(Object)}</code> is false this method + * fails and <code>false</code> is returned. + * </p> + * <p> + * The children must be first explicitly removed with + * {@link #setParent(Object itemId, Object newParentId)}or + * {@link com.vaadin.v7.data.Container#removeItem(Object itemId)}. + * </p> + * + * <p> + * This operation is optional. If it is not implemented, the method + * always returns <code>false</code>. + * </p> + * + * @param itemId + * ID of the Item in the container whose child capability is + * to be set + * @param areChildrenAllowed + * boolean value specifying if the Item can have children or + * not + * @return <code>true</code> if the operation succeeded, + * <code>false</code> if not + */ + public boolean setChildrenAllowed(Object itemId, + boolean areChildrenAllowed) + throws UnsupportedOperationException; + + /** + * Tests if the Item specified with <code>itemId</code> is a root Item. + * The hierarchical container can have more than one root and must have + * at least one unless it is empty. The + * {@link #getParent(Object itemId)} method always returns + * <code>null</code> for root Items. + * + * @param itemId + * ID of the Item whose root status is to be tested + * @return <code>true</code> if the specified Item is a root, + * <code>false</code> if not + */ + public boolean isRoot(Object itemId); + + /** + * <p> + * Tests if the Item specified with <code>itemId</code> has child Items + * or if it is a leaf. The {@link #getChildren(Object itemId)} method + * always returns <code>null</code> for leaf Items. + * </p> + * + * <p> + * Note that being a leaf does not imply whether or not an Item is + * allowed to have children. + * </p> + * + * @param itemId + * ID of the Item to be tested + * @return <code>true</code> if the specified Item has children, + * <code>false</code> if not (is a leaf) + */ + public boolean hasChildren(Object itemId); + + /** + * <p> + * Removes the Item identified by <code>ItemId</code> from the + * Container. + * </p> + * + * <p> + * Note that this does not remove any children the item might have. + * </p> + * + * @param itemId + * ID of the Item to remove + * @return <code>true</code> if the operation succeeded, + * <code>false</code> if not + */ + @Override + public boolean removeItem(Object itemId) + throws UnsupportedOperationException; + } + + /** + * Interface that is implemented by containers which allow reducing their + * visible contents based on a set of filters. This interface has been + * renamed from {@link Filterable}, and implementing the new + * {@link Filterable} instead of or in addition to {@link SimpleFilterable} + * is recommended. This interface might be removed in future Vaadin + * versions. + * <p> + * When a set of filters are set, only items that match all the filters are + * included in the visible contents of the container. Still new items that + * do not match filters can be added to the container. Multiple filters can + * be added and the container remembers the state of the filters. When + * multiple filters are added, all filters must match for an item to be + * visible in the container. + * </p> + * <p> + * When an {@link Ordered} or {@link Indexed} container is filtered, all + * operations of these interfaces should only use the filtered contents and + * the filtered indices to the container. + * </p> + * <p> + * How filtering is performed when a {@link Hierarchical} container + * implements {@link SimpleFilterable} is implementation specific and should + * be documented in the implementing class. + * </p> + * <p> + * Adding items (if supported) to a filtered {@link Ordered} or + * {@link Indexed} container should insert them immediately after the + * indicated visible item. The unfiltered position of items added at index + * 0, at index {@link com.vaadin.v7.data.Container#size()} or at an undefined + * position is up to the implementation. + * </p> + * <p> + * The functionality of SimpleFilterable can be implemented using the + * {@link Filterable} API and {@link SimpleStringFilter}. + * </p> + * + * @since 5.0 (renamed from Filterable to SimpleFilterable in 6.6) + */ + public interface SimpleFilterable extends Container, Serializable { + + /** + * Add a filter for given property. + * <p> + * The API {@link Filterable#addContainerFilter(Filter)} is recommended + * instead of this method. A {@link SimpleStringFilter} can be used with + * the new API to implement the old string filtering functionality. + * <p> + * The filter accepts items for which toString() of the value of the + * given property contains or starts with given filterString. Other + * items are not visible in the container when filtered. + * <p> + * If a container has multiple filters, only items accepted by all + * filters are visible. + * + * @param propertyId + * Property for which the filter is applied to. + * @param filterString + * String that must match the value of the property + * @param ignoreCase + * Determine if the casing can be ignored when comparing + * strings. + * @param onlyMatchPrefix + * Only match prefixes; no other matches are included. + */ + public void addContainerFilter(Object propertyId, String filterString, + boolean ignoreCase, boolean onlyMatchPrefix); + + /** + * Remove all filters from all properties. + */ + public void removeAllContainerFilters(); + + /** + * Remove all filters from the given property. + * + * @param propertyId + * for which to remove filters + */ + public void removeContainerFilters(Object propertyId); + } + + /** + * Filter interface for container filtering. + * <p> + * If a filter does not support in-memory filtering, + * {@link #passesFilter(Item)} should throw + * {@link UnsupportedOperationException}. + * <p> + * Lazy containers must be able to map filters to their internal + * representation (e.g. SQL or JPA 2.0 Criteria). + * <p> + * An {@link UnsupportedFilterException} can be thrown by the container if a + * particular filter is not supported by the container. + * <p> + * An {@link Filter} should implement {@link #equals(Object)} and + * {@link #hashCode()} correctly to avoid duplicate filter registrations + * etc. + * + * @see Filterable + * + * @since 6.6 + */ + public interface Filter extends Serializable { + + /** + * Check if an item passes the filter (in-memory filtering). + * + * @param itemId + * identifier of the item being filtered; may be null when + * the item is being added to the container + * @param item + * the item being filtered + * @return true if the item is accepted by this filter + * @throws UnsupportedOperationException + * if the filter cannot be used for in-memory filtering + */ + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedOperationException; + + /** + * Check if a change in the value of a property can affect the filtering + * result. May always return true, at the cost of performance. + * + * If the filter cannot determine whether it may depend on the property + * or not, should return true. + * + * @param propertyId + * @return true if the filtering result may/does change based on changes + * to the property identified by propertyId + */ + public boolean appliesToProperty(Object propertyId); + + } + + /** + * Interface that is implemented by containers which allow reducing their + * visible contents based on a set of filters. + * <p> + * When a set of filters are set, only items that match all the filters are + * included in the visible contents of the container. Still new items that + * do not match filters can be added to the container. Multiple filters can + * be added and the container remembers the state of the filters. When + * multiple filters are added, all filters must match for an item to be + * visible in the container. + * </p> + * <p> + * When an {@link Ordered} or {@link Indexed} container is filtered, all + * operations of these interfaces should only use the filtered and sorted + * contents and the filtered indices to the container. Indices or item + * identifiers in the public API refer to the visible view unless otherwise + * stated. However, the <code>addItem*()</code> methods may add items that + * will be filtered out after addition or moved to another position based on + * sorting. + * </p> + * <p> + * How filtering is performed when a {@link Hierarchical} container + * implements {@link Filterable} is implementation specific and should be + * documented in the implementing class. + * </p> + * <p> + * Adding items (if supported) to a filtered {@link Ordered} or + * {@link Indexed} container should insert them immediately after the + * indicated visible item. However, the unfiltered position of items added + * at index 0, at index {@link com.vaadin.v7.data.Container#size()} or at an + * undefined position is up to the implementation. + * </p> + * + * <p> + * This API replaces the old Filterable interface, renamed to + * {@link SimpleFilterable} in Vaadin 6.6. + * </p> + * + * @since 6.6 + */ + public interface Filterable extends Container, Serializable { + /** + * Adds a filter for the container. + * <p> + * If a container has multiple filters, only items accepted by all + * filters are visible. + * + * @throws UnsupportedFilterException + * if the filter is not supported by the container + */ + public void addContainerFilter(Filter filter) + throws UnsupportedFilterException; + + /** + * Removes a filter from the container. + * <p> + * This requires that the equals() method considers the filters as + * equivalent (same instance or properly implemented equals() method). + */ + public void removeContainerFilter(Filter filter); + + /** + * Remove all active filters from the container. + */ + public void removeAllContainerFilters(); + + /** + * Returns the filters which have been applied to the container + * + * @return A collection of filters which have been applied to the + * container. An empty collection if no filters have been + * applied. + * @since 7.1 + */ + public Collection<Filter> getContainerFilters(); + } + + /** + * Interface implemented by viewer classes capable of using a Container as a + * data source. + */ + public interface Viewer extends Serializable { + + /** + * Sets the Container that serves as the data source of the viewer. + * + * @param newDataSource + * The new data source Item + */ + public void setContainerDataSource(Container newDataSource); + + /** + * Gets the Container serving as the data source of the viewer. + * + * @return data source Container + */ + public Container getContainerDataSource(); + + } + + /** + * <p> + * Interface implemented by the editor classes supporting editing the + * Container. Implementing this interface means that the Container serving + * as the data source of the editor can be modified through it. + * </p> + * <p> + * Note that not implementing the <code>Container.Editor</code> interface + * does not restrict the class from editing the Container contents + * internally. + * </p> + */ + public interface Editor extends Container.Viewer, Serializable { + + } + + /* Contents change event */ + + /** + * An <code>Event</code> object specifying the Container whose Item set has + * changed (items added, removed or reordered). + * + * A simple property value change is not an item set change. + */ + public interface ItemSetChangeEvent extends Serializable { + + /** + * Gets the Property where the event occurred. + * + * @return source of the event + */ + public Container getContainer(); + } + + /** + * Container Item set change listener interface. + * <p> + * An item set change refers to addition, removal or reordering of items in + * the container. A simple property value change is not an item set change. + */ + public interface ItemSetChangeListener extends Serializable { + + /** + * Lets the listener know a Containers visible (filtered and/or sorted, + * if applicable) Item set has changed. + * + * @param event + * change event text + */ + public void containerItemSetChange(Container.ItemSetChangeEvent event); + } + + /** + * The interface for adding and removing <code>ItemSetChangeEvent</code> + * listeners. By implementing this interface a class explicitly announces + * that it will generate a <code>ItemSetChangeEvent</code> when its contents + * are modified. + * <p> + * An item set change refers to addition, removal or reordering of items in + * the container. A simple property value change is not an item set change. + * + * <p> + * Note: The general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * <code>addListener</code> and <code>removeListener</code> methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + * </p> + */ + public interface ItemSetChangeNotifier extends Serializable { + + /** + * Adds an Item set change listener for the object. + * + * @param listener + * listener to be added + */ + public void addItemSetChangeListener( + Container.ItemSetChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #addItemSetChangeListener(ItemSetChangeListener)} + **/ + @Deprecated + public void addListener(Container.ItemSetChangeListener listener); + + /** + * Removes the Item set change listener from the object. + * + * @param listener + * listener to be removed + */ + public void removeItemSetChangeListener( + Container.ItemSetChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeItemSetChangeListener(ItemSetChangeListener)} + **/ + @Deprecated + public void removeListener(Container.ItemSetChangeListener listener); + } + + /* Property set change event */ + + /** + * An <code>Event</code> object specifying the Container whose Property set + * has changed. + * <p> + * A property set change means the addition, removal or other structural + * changes to the properties of a container. Changes concerning the set of + * items in the container and their property values are not property set + * changes. + */ + public interface PropertySetChangeEvent extends Serializable { + + /** + * Retrieves the Container whose contents have been modified. + * + * @return Source Container of the event. + */ + public Container getContainer(); + } + + /** + * The listener interface for receiving <code>PropertySetChangeEvent</code> + * objects. + * <p> + * A property set change means the addition, removal or other structural + * change of the properties (supported property IDs) of a container. Changes + * concerning the set of items in the container and their property values + * are not property set changes. + */ + public interface PropertySetChangeListener extends Serializable { + + /** + * Notifies this listener that the set of property IDs supported by the + * Container has changed. + * + * @param event + * Change event. + */ + public void containerPropertySetChange( + Container.PropertySetChangeEvent event); + } + + /** + * <p> + * The interface for adding and removing <code>PropertySetChangeEvent</code> + * listeners. By implementing this interface a class explicitly announces + * that it will generate a <code>PropertySetChangeEvent</code> when the set + * of property IDs supported by the container is modified. + * </p> + * + * <p> + * A property set change means the addition, removal or other structural + * changes to the properties of a container. Changes concerning the set of + * items in the container and their property values are not property set + * changes. + * </p> + * + * <p> + * Note that the general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * <code>addListener</code> and <code>removeListener</code> methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + * </p> + */ + public interface PropertySetChangeNotifier extends Serializable { + + /** + * Registers a new Property set change listener for this Container. + * + * @param listener + * The new Listener to be registered + */ + public void addPropertySetChangeListener( + Container.PropertySetChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #addPropertySetChangeListener(PropertySetChangeListener)} + **/ + @Deprecated + public void addListener(Container.PropertySetChangeListener listener); + + /** + * Removes a previously registered Property set change listener. + * + * @param listener + * Listener to be removed + */ + public void removePropertySetChangeListener( + Container.PropertySetChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #removePropertySetChangeListener(PropertySetChangeListener)} + **/ + @Deprecated + public void removeListener( + Container.PropertySetChangeListener listener); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/ContainerHelpers.java b/compatibility-server/src/main/java/com/vaadin/v7/data/ContainerHelpers.java new file mode 100644 index 0000000000..c782f33133 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/ContainerHelpers.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2016 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.v7.data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.vaadin.v7.data.Container.Indexed; + +/** + * Contains helper methods for containers that can be used to ease development + * of containers in Vaadin. + * + * @since 7.0 + */ +public class ContainerHelpers implements Serializable { + + /** + * Get a range of item ids from the container using + * {@link Indexed#getIdByIndex(int)}. This is just a helper method to aid + * developers to quickly add the required functionality to a Container + * during development. This should not be used in a "finished product" + * unless fetching an id for an index is very inexpensive because a separate + * request will be performed for each index in the range. + * + * @param startIndex + * index of the first item id to get + * @param numberOfIds + * the number of consecutive items whose ids should be returned + * @param container + * the container from which the items should be fetched + * @return A list of item ids in the range specified + */ + public static List<?> getItemIdsUsingGetIdByIndex(int startIndex, + int numberOfIds, Container.Indexed container) { + + if (container == null) { + throw new IllegalArgumentException( + "The given container cannot be null!"); + } + + if (startIndex < 0) { + throw new IndexOutOfBoundsException( + "Start index cannot be negative! startIndex=" + startIndex); + } + + if (startIndex > container.size()) { + throw new IndexOutOfBoundsException( + "Start index exceeds container size! startIndex=" + + startIndex + " containerLastItemIndex=" + + (container.size() - 1)); + } + + if (numberOfIds < 1) { + if (numberOfIds == 0) { + return Collections.emptyList(); + } + + throw new IllegalArgumentException( + "Cannot get negative amount of items! numberOfItems=" + + numberOfIds); + } + + // not included in the range + int endIndex = startIndex + numberOfIds; + + if (endIndex > container.size()) { + endIndex = container.size(); + } + + ArrayList<Object> rangeOfIds = new ArrayList<Object>(); + for (int i = startIndex; i < endIndex; i++) { + Object idByIndex = container.getIdByIndex(i); + if (idByIndex == null) { + throw new RuntimeException( + "Unable to get item id for index: " + i + + " from container using Container.Indexed#getIdByIndex() " + + "even though container.size() > endIndex. " + + "Returned item id was null. " + + "Check your container implementation!"); + } + rangeOfIds.add(idByIndex); + } + + return Collections.unmodifiableList(rangeOfIds); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/ContainerOrderedWrapper.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ContainerOrderedWrapper.java new file mode 100644 index 0000000000..9ac8038f03 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ContainerOrderedWrapper.java @@ -0,0 +1,728 @@ +/* + * Copyright 2000-2016 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.v7.data.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import com.vaadin.v7.data.Container; +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; + +/** + * <p> + * A wrapper class for adding external ordering to containers not implementing + * the {@link com.vaadin.v7.data.Container.Ordered} interface. + * </p> + * + * <p> + * If the wrapped container is changed directly (that is, not through the + * wrapper), and does not implement Container.ItemSetChangeNotifier and/or + * Container.PropertySetChangeNotifier the hierarchy information must be updated + * with the {@link #updateOrderWrapper()} method. + * </p> + * + * @author Vaadin Ltd. + * @since 3.0 + */ +@SuppressWarnings("serial") +public class ContainerOrderedWrapper implements Container.Ordered, + Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier { + + /** + * The wrapped container + */ + private final Container container; + + /** + * Ordering information, ie. the mapping from Item ID to the next item ID. + * The last item id should not be present + */ + private Hashtable<Object, Object> next; + + /** + * Reverse ordering information for convenience and performance reasons. The + * first item id should not be present + */ + private Hashtable<Object, Object> prev; + + /** + * ID of the first Item in the container. + */ + private Object first; + + /** + * ID of the last Item in the container. + */ + private Object last; + + /** + * Is the wrapped container ordered by itself, ie. does it implement the + * Container.Ordered interface by itself? If it does, this class will use + * the methods of the underlying container directly. + */ + private boolean ordered = false; + + /** + * The last known size of the wrapped container. Used to check whether items + * have been added or removed to the wrapped container, when the wrapped + * container does not send ItemSetChangeEvents. + */ + private int lastKnownSize = -1; + + /** + * Constructs a new ordered wrapper for an existing Container. Works even if + * the to-be-wrapped container already implements the Container.Ordered + * interface. + * + * @param toBeWrapped + * the container whose contents need to be ordered. + */ + public ContainerOrderedWrapper(Container toBeWrapped) { + + container = toBeWrapped; + ordered = container instanceof Container.Ordered; + + // Checks arguments + if (container == null) { + throw new NullPointerException("Null can not be wrapped"); + } + + // Creates initial order if needed + updateOrderWrapper(); + } + + /** + * Removes the specified Item from the wrapper's internal hierarchy + * structure. + * <p> + * Note : The Item is not removed from the underlying Container. + * </p> + * + * @param id + * the ID of the Item to be removed from the ordering. + */ + private void removeFromOrderWrapper(Object id) { + if (id != null) { + final Object pid = prev.get(id); + final Object nid = next.get(id); + if (first.equals(id)) { + first = nid; + } + if (last.equals(id)) { + last = pid; + } + if (nid != null) { + if (pid == null) { + prev.remove(nid); + } else { + prev.put(nid, pid); + } + } + if (pid != null) { + if (nid == null) { + next.remove(pid); + } else { + next.put(pid, nid); + } + } + next.remove(id); + prev.remove(id); + } + } + + /** + * Registers the specified Item to the last position in the wrapper's + * internal ordering. The underlying container is not modified. + * + * @param id + * the ID of the Item to be added to the ordering. + */ + private void addToOrderWrapper(Object id) { + + // Adds the if to tail + if (last != null) { + next.put(last, id); + prev.put(id, last); + last = id; + } else { + first = last = id; + } + } + + /** + * Registers the specified Item after the specified itemId in the wrapper's + * internal ordering. The underlying container is not modified. Given item + * id must be in the container, or must be null. + * + * @param id + * the ID of the Item to be added to the ordering. + * @param previousItemId + * the Id of the previous item. + */ + private void addToOrderWrapper(Object id, Object previousItemId) { + + if (last == previousItemId || last == null) { + addToOrderWrapper(id); + } else { + if (previousItemId == null) { + next.put(id, first); + prev.put(first, id); + first = id; + } else { + prev.put(id, previousItemId); + next.put(id, next.get(previousItemId)); + prev.put(next.get(previousItemId), id); + next.put(previousItemId, id); + } + } + } + + /** + * Updates the wrapper's internal ordering information to include all Items + * in the underlying container. + * <p> + * Note : If the contents of the wrapped container change without the + * wrapper's knowledge, this method needs to be called to update the + * ordering information of the Items. + * </p> + */ + public void updateOrderWrapper() { + + if (!ordered) { + + final Collection<?> ids = container.getItemIds(); + + // Recreates ordering if some parts of it are missing + if (next == null || first == null || last == null || prev == null) { + first = null; + last = null; + next = new Hashtable<Object, Object>(); + prev = new Hashtable<Object, Object>(); + } + + // Filter out all the missing items + final LinkedList<?> l = new LinkedList<Object>(next.keySet()); + for (final Iterator<?> i = l.iterator(); i.hasNext();) { + final Object id = i.next(); + if (!container.containsId(id)) { + removeFromOrderWrapper(id); + } + } + + // Adds missing items + for (final Iterator<?> i = ids.iterator(); i.hasNext();) { + final Object id = i.next(); + if (!next.containsKey(id) && last != id) { + addToOrderWrapper(id); + } + } + } + } + + /* + * Gets the first item stored in the ordered container Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Object firstItemId() { + if (ordered) { + return ((Container.Ordered) container).firstItemId(); + } + return first; + } + + /* + * Tests if the given item is the first item in the container Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public boolean isFirstId(Object itemId) { + if (ordered) { + return ((Container.Ordered) container).isFirstId(itemId); + } + return first != null && first.equals(itemId); + } + + /* + * Tests if the given item is the last item in the container Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public boolean isLastId(Object itemId) { + if (ordered) { + return ((Container.Ordered) container).isLastId(itemId); + } + return last != null && last.equals(itemId); + } + + /* + * Gets the last item stored in the ordered container Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Object lastItemId() { + if (ordered) { + return ((Container.Ordered) container).lastItemId(); + } + return last; + } + + /* + * Gets the item that is next from the specified item. Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Object nextItemId(Object itemId) { + if (ordered) { + return ((Container.Ordered) container).nextItemId(itemId); + } + if (itemId == null) { + return null; + } + return next.get(itemId); + } + + /* + * Gets the item that is previous from the specified item. Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Object prevItemId(Object itemId) { + if (ordered) { + return ((Container.Ordered) container).prevItemId(itemId); + } + if (itemId == null) { + return null; + } + return prev.get(itemId); + } + + /** + * Registers a new Property to all Items in the Container. + * + * @param propertyId + * the ID of the new Property. + * @param type + * the Data type of the new Property. + * @param defaultValue + * the value all created Properties are initialized to. + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + */ + @Override + public boolean addContainerProperty(Object propertyId, Class<?> type, + Object defaultValue) throws UnsupportedOperationException { + + return container.addContainerProperty(propertyId, type, defaultValue); + } + + /** + * Creates a new Item into the Container, assigns it an automatic ID, and + * adds it to the ordering. + * + * @return the autogenerated ID of the new Item or <code>null</code> if the + * operation failed + * @throws UnsupportedOperationException + * if the addItem is not supported. + */ + @Override + public Object addItem() throws UnsupportedOperationException { + + final Object id = container.addItem(); + if (!ordered && id != null) { + addToOrderWrapper(id); + } + return id; + } + + /** + * Registers a new Item by its ID to the underlying container and to the + * ordering. + * + * @param itemId + * the ID of the Item to be created. + * @return the added Item or <code>null</code> if the operation failed + * @throws UnsupportedOperationException + * if the addItem is not supported. + */ + @Override + public Item addItem(Object itemId) throws UnsupportedOperationException { + final Item item = container.addItem(itemId); + if (!ordered && item != null) { + addToOrderWrapper(itemId); + } + return item; + } + + /** + * Removes all items from the underlying container and from the ordering. + * + * @return <code>true</code> if the operation succeeded, otherwise + * <code>false</code> + * @throws UnsupportedOperationException + * if the removeAllItems is not supported. + */ + @Override + public boolean removeAllItems() throws UnsupportedOperationException { + final boolean success = container.removeAllItems(); + if (!ordered && success) { + first = last = null; + next.clear(); + prev.clear(); + } + return success; + } + + /** + * Removes an Item specified by the itemId from the underlying container and + * from the ordering. + * + * @param itemId + * the ID of the Item to be removed. + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the removeItem is not supported. + */ + @Override + public boolean removeItem(Object itemId) + throws UnsupportedOperationException { + + final boolean success = container.removeItem(itemId); + if (!ordered && success) { + removeFromOrderWrapper(itemId); + } + return success; + } + + /** + * Removes the specified Property from the underlying container and from the + * ordering. + * <p> + * Note : The Property will be removed from all the Items in the Container. + * </p> + * + * @param propertyId + * the ID of the Property to remove. + * @return <code>true</code> if the operation succeeded, <code>false</code> + * if not + * @throws UnsupportedOperationException + * if the removeContainerProperty is not supported. + */ + @Override + public boolean removeContainerProperty(Object propertyId) + throws UnsupportedOperationException { + return container.removeContainerProperty(propertyId); + } + + /* + * Does the container contain the specified Item? Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public boolean containsId(Object itemId) { + return container.containsId(itemId); + } + + /* + * Gets the specified Item from the container. Don't add a JavaDoc comment + * here, we use the default documentation from implemented interface. + */ + @Override + public Item getItem(Object itemId) { + return container.getItem(itemId); + } + + /* + * Gets the ID's of all Items stored in the Container Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Collection<?> getItemIds() { + if (ordered) { + return ((Container.Ordered) container).getItemIds(); + } else if (first == null) { + return new ArrayList<Object>(); + } else { + List<Object> itemIds = new ArrayList<Object>(); + itemIds.add(first); + Object current = first; + while (next.containsKey(current)) { + current = next.get(current); + itemIds.add(current); + } + return itemIds; + } + + } + + /* + * Gets the Property identified by the given itemId and propertyId from the + * Container Don't add a JavaDoc comment here, we use the default + * documentation from implemented interface. + */ + @Override + public Property getContainerProperty(Object itemId, Object propertyId) { + return container.getContainerProperty(itemId, propertyId); + } + + /* + * Gets the ID's of all Properties stored in the Container Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public Collection<?> getContainerPropertyIds() { + return container.getContainerPropertyIds(); + } + + /* + * Gets the data type of all Properties identified by the given Property ID. + * Don't add a JavaDoc comment here, we use the default documentation from + * implemented interface. + */ + @Override + public Class<?> getType(Object propertyId) { + return container.getType(propertyId); + } + + /* + * Gets the number of Items in the Container. Don't add a JavaDoc comment + * here, we use the default documentation from implemented interface. + */ + @Override + public int size() { + int newSize = container.size(); + assert newSize >= 0; + if (lastKnownSize != -1 && newSize != lastKnownSize + && !(container instanceof Container.ItemSetChangeNotifier)) { + // Update the internal cache when the size of the container changes + // and the container is incapable of sending ItemSetChangeEvents + updateOrderWrapper(); + } + lastKnownSize = newSize; + return newSize; + } + + /* + * Registers a new Item set change listener for this Container. Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public void addItemSetChangeListener( + Container.ItemSetChangeListener listener) { + if (container instanceof Container.ItemSetChangeNotifier) { + ((Container.ItemSetChangeNotifier) container) + .addItemSetChangeListener(new PiggybackListener(listener)); + } + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addItemSetChangeListener(com.vaadin.v7.data.Container.ItemSetChangeListener)} + **/ + @Override + @Deprecated + public void addListener(Container.ItemSetChangeListener listener) { + addItemSetChangeListener(listener); + } + + /* + * Removes a Item set change listener from the object. Don't add a JavaDoc + * comment here, we use the default documentation from implemented + * interface. + */ + @Override + public void removeItemSetChangeListener( + Container.ItemSetChangeListener listener) { + if (container instanceof Container.ItemSetChangeNotifier) { + ((Container.ItemSetChangeNotifier) container) + .removeItemSetChangeListener( + new PiggybackListener(listener)); + } + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeItemSetChangeListener(com.vaadin.v7.data.Container.ItemSetChangeListener)} + **/ + @Override + @Deprecated + public void removeListener(Container.ItemSetChangeListener listener) { + removeItemSetChangeListener(listener); + } + + /* + * Registers a new Property set change listener for this Container. Don't + * add a JavaDoc comment here, we use the default documentation from + * implemented interface. + */ + @Override + public void addPropertySetChangeListener( + Container.PropertySetChangeListener listener) { + if (container instanceof Container.PropertySetChangeNotifier) { + ((Container.PropertySetChangeNotifier) container) + .addPropertySetChangeListener( + new PiggybackListener(listener)); + } + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addPropertySetChangeListener(com.vaadin.v7.data.Container.PropertySetChangeListener)} + **/ + @Override + @Deprecated + public void addListener(Container.PropertySetChangeListener listener) { + addPropertySetChangeListener(listener); + } + + /* + * Removes a Property set change listener from the object. Don't add a + * JavaDoc comment here, we use the default documentation from implemented + * interface. + */ + @Override + public void removePropertySetChangeListener( + Container.PropertySetChangeListener listener) { + if (container instanceof Container.PropertySetChangeNotifier) { + ((Container.PropertySetChangeNotifier) container) + .removePropertySetChangeListener( + new PiggybackListener(listener)); + } + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removePropertySetChangeListener(com.vaadin.v7.data.Container.PropertySetChangeListener)} + **/ + @Override + @Deprecated + public void removeListener(Container.PropertySetChangeListener listener) { + removePropertySetChangeListener(listener); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, + * java.lang.Object) + */ + @Override + public Item addItemAfter(Object previousItemId, Object newItemId) + throws UnsupportedOperationException { + + // If the previous item is not in the container, fail + if (previousItemId != null && !containsId(previousItemId)) { + return null; + } + + // Adds the item to container + final Item item = container.addItem(newItemId); + + // Puts the new item to its correct place + if (!ordered && item != null) { + addToOrderWrapper(newItemId, previousItemId); + } + + return item; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) + */ + @Override + public Object addItemAfter(Object previousItemId) + throws UnsupportedOperationException { + + // If the previous item is not in the container, fail + if (previousItemId != null && !containsId(previousItemId)) { + return null; + } + + // Adds the item to container + final Object id = container.addItem(); + + // Puts the new item to its correct place + if (!ordered && id != null) { + addToOrderWrapper(id, previousItemId); + } + + return id; + } + + /** + * This listener 'piggybacks' on the real listener in order to update the + * wrapper when needed. It proxies equals() and hashCode() to the real + * listener so that the correct listener gets removed. + * + */ + private class PiggybackListener + implements Container.PropertySetChangeListener, + Container.ItemSetChangeListener { + + Object listener; + + public PiggybackListener(Object realListener) { + listener = realListener; + } + + @Override + public void containerItemSetChange(ItemSetChangeEvent event) { + updateOrderWrapper(); + ((Container.ItemSetChangeListener) listener) + .containerItemSetChange(event); + + } + + @Override + public void containerPropertySetChange(PropertySetChangeEvent event) { + updateOrderWrapper(); + ((Container.PropertySetChangeListener) listener) + .containerPropertySetChange(event); + + } + + @Override + public boolean equals(Object obj) { + return obj == listener || (obj != null && obj.equals(listener)); + } + + @Override + public int hashCode() { + return listener.hashCode(); + } + + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/DefaultItemSorter.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/DefaultItemSorter.java new file mode 100644 index 0000000000..345d50614f --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/DefaultItemSorter.java @@ -0,0 +1,221 @@ +/* + * Copyright 2000-2016 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.v7.data.util; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +import com.vaadin.v7.data.Container; +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Container.Sortable; + +/** + * Provides a default implementation of an ItemSorter. The + * <code>DefaultItemSorter</code> adheres to the + * {@link Sortable#sort(Object[], boolean[])} rules and sorts the container + * according to the properties given using + * {@link #setSortProperties(Sortable, Object[], boolean[])}. + * <p> + * A Comparator is used for comparing the individual <code>Property</code> + * values. The comparator can be set using the constructor. If no comparator is + * provided a default comparator is used. + * + */ +public class DefaultItemSorter implements ItemSorter { + + private java.lang.Object[] sortPropertyIds; + private boolean[] sortDirections; + private Container container; + private Comparator<Object> propertyValueComparator; + + /** + * Constructs a DefaultItemSorter using the default <code>Comparator</code> + * for comparing <code>Property</code>values. + * + */ + public DefaultItemSorter() { + this(new DefaultPropertyValueComparator()); + } + + /** + * Constructs a DefaultItemSorter which uses the <code>Comparator</code> + * indicated by the <code>propertyValueComparator</code> parameter for + * comparing <code>Property</code>values. + * + * @param propertyValueComparator + * The comparator to use when comparing individual + * <code>Property</code> values + */ + public DefaultItemSorter(Comparator<Object> propertyValueComparator) { + this.propertyValueComparator = propertyValueComparator; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.ItemSorter#compare(java.lang.Object, + * java.lang.Object) + */ + @Override + public int compare(Object o1, Object o2) { + Item item1 = container.getItem(o1); + Item item2 = container.getItem(o2); + + /* + * Items can be null if the container is filtered. Null is considered + * "less" than not-null. + */ + if (item1 == null) { + if (item2 == null) { + return 0; + } else { + return 1; + } + } else if (item2 == null) { + return -1; + } + + for (int i = 0; i < sortPropertyIds.length; i++) { + + int result = compareProperty(sortPropertyIds[i], sortDirections[i], + item1, item2); + + // If order can be decided + if (result != 0) { + return result; + } + + } + + return 0; + } + + /** + * Compares the property indicated by <code>propertyId</code> in the items + * indicated by <code>item1</code> and <code>item2</code> for order. Returns + * a negative integer, zero, or a positive integer as the property value in + * the first item is less than, equal to, or greater than the property value + * in the second item. If the <code>sortDirection</code> is false the + * returned value is negated. + * <p> + * The comparator set for this <code>DefaultItemSorter</code> is used for + * comparing the two property values. + * + * @param propertyId + * The property id for the property that is used for comparison. + * @param sortDirection + * The direction of the sort. A false value negates the result. + * @param item1 + * The first item to compare. + * @param item2 + * The second item to compare. + * @return a negative, zero, or positive integer if the property value in + * the first item is less than, equal to, or greater than the + * property value in the second item. Negated if + * {@code sortDirection} is false. + */ + protected int compareProperty(Object propertyId, boolean sortDirection, + Item item1, Item item2) { + + // Get the properties to compare + final Property<?> property1 = item1.getItemProperty(propertyId); + final Property<?> property2 = item2.getItemProperty(propertyId); + + // Get the values to compare + final Object value1 = (property1 == null) ? null : property1.getValue(); + final Object value2 = (property2 == null) ? null : property2.getValue(); + + // Result of the comparison + int r = 0; + if (sortDirection) { + r = propertyValueComparator.compare(value1, value2); + } else { + r = propertyValueComparator.compare(value2, value1); + } + + return r; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.ItemSorter#setSortProperties(com.vaadin.data. + * Container .Sortable, java.lang.Object[], boolean[]) + */ + @Override + public void setSortProperties(Container.Sortable container, + Object[] propertyId, boolean[] ascending) { + this.container = container; + + // Removes any non-sortable property ids + final List<Object> ids = new ArrayList<Object>(); + final List<Boolean> orders = new ArrayList<Boolean>(); + final Collection<?> sortable = container + .getSortableContainerPropertyIds(); + for (int i = 0; i < propertyId.length; i++) { + if (sortable.contains(propertyId[i])) { + ids.add(propertyId[i]); + orders.add(Boolean + .valueOf(i < ascending.length ? ascending[i] : true)); + } + } + + sortPropertyIds = ids.toArray(); + sortDirections = new boolean[orders.size()]; + for (int i = 0; i < sortDirections.length; i++) { + sortDirections[i] = (orders.get(i)).booleanValue(); + } + + } + + /** + * Provides a default comparator used for comparing {@link Property} values. + * The <code>DefaultPropertyValueComparator</code> assumes all objects it + * compares can be cast to Comparable. + * + */ + public static class DefaultPropertyValueComparator + implements Comparator<Object>, Serializable { + + @Override + @SuppressWarnings("unchecked") + public int compare(Object o1, Object o2) { + int r = 0; + // Normal non-null comparison + if (o1 != null && o2 != null) { + // Assume the objects can be cast to Comparable, throw + // ClassCastException otherwise. + r = ((Comparable<Object>) o1).compareTo(o2); + } else if (o1 == o2) { + // Objects are equal if both are null + r = 0; + } else { + if (o1 == null) { + r = -1; // null is less than non-null + } else { + r = 1; // non-null is greater than null + } + } + + return r; + } + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/HierarchicalContainerOrderedWrapper.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/HierarchicalContainerOrderedWrapper.java new file mode 100644 index 0000000000..f25842aec9 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/HierarchicalContainerOrderedWrapper.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2016 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.v7.data.util; + +import java.util.Collection; + +import com.vaadin.v7.data.Container.Hierarchical; + +/** + * A wrapper class for adding external ordering to containers not implementing + * the {@link com.vaadin.v7.data.Container.Ordered} interface while retaining + * {@link Hierarchical} features. + * + * @see ContainerOrderedWrapper + */ +@SuppressWarnings({ "serial" }) +public class HierarchicalContainerOrderedWrapper extends ContainerOrderedWrapper + implements Hierarchical { + + private Hierarchical hierarchical; + + public HierarchicalContainerOrderedWrapper(Hierarchical toBeWrapped) { + super(toBeWrapped); + hierarchical = toBeWrapped; + } + + @Override + public boolean areChildrenAllowed(Object itemId) { + return hierarchical.areChildrenAllowed(itemId); + } + + @Override + public Collection<?> getChildren(Object itemId) { + return hierarchical.getChildren(itemId); + } + + @Override + public Object getParent(Object itemId) { + return hierarchical.getParent(itemId); + } + + @Override + public boolean hasChildren(Object itemId) { + return hierarchical.hasChildren(itemId); + } + + @Override + public boolean isRoot(Object itemId) { + return hierarchical.isRoot(itemId); + } + + @Override + public Collection<?> rootItemIds() { + return hierarchical.rootItemIds(); + } + + @Override + public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) + throws UnsupportedOperationException { + return hierarchical.setChildrenAllowed(itemId, areChildrenAllowed); + } + + @Override + public boolean setParent(Object itemId, Object newParentId) + throws UnsupportedOperationException { + return hierarchical.setParent(itemId, newParentId); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/ItemSorter.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ItemSorter.java new file mode 100644 index 0000000000..9ca21ca137 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ItemSorter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2016 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.v7.data.util; + +import java.io.Serializable; +import java.util.Comparator; + +import com.vaadin.v7.data.Container; +import com.vaadin.v7.data.Container.Sortable; + +/** + * An item comparator which is compatible with the {@link Sortable} interface. + * The <code>ItemSorter</code> interface can be used in <code>Sortable</code> + * implementations to provide a custom sorting method. + */ +public interface ItemSorter + extends Comparator<Object>, Cloneable, Serializable { + + /** + * Sets the parameters for an upcoming sort operation. The parameters + * determine what container to sort and how the <code>ItemSorter</code> + * sorts the container. + * + * @param container + * The container that will be sorted. The container must contain + * the propertyIds given in the <code>propertyId</code> + * parameter. + * @param propertyId + * The property ids used for sorting. The property ids must exist + * in the container and should only be used if they are also + * sortable, i.e include in the collection returned by + * <code>container.getSortableContainerPropertyIds()</code>. See + * {@link Sortable#sort(Object[], boolean[])} for more + * information. + * @param ascending + * Sorting order flags for each property id. See + * {@link Sortable#sort(Object[], boolean[])} for more + * information. + */ + void setSortProperties(Container.Sortable container, Object[] propertyId, + boolean[] ascending); + + /** + * Compares its two arguments for order. Returns a negative integer, zero, + * or a positive integer as the first argument is less than, equal to, or + * greater than the second. + * <p> + * The parameters for the <code>ItemSorter</code> <code>compare()</code> + * method must always be item ids which exist in the container set using + * {@link #setSortProperties(Sortable, Object[], boolean[])}. + * + * @see Comparator#compare(Object, Object) + */ + @Override + int compare(Object itemId1, Object itemId2); + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyValueGenerator.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyValueGenerator.java new file mode 100644 index 0000000000..8cc4e7ac10 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyValueGenerator.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2016 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.v7.data.util; + +import java.io.Serializable; + +import com.vaadin.data.sort.SortOrder; +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Container.Filter; +import com.vaadin.v7.data.util.filter.UnsupportedFilterException; + +/** + * PropertyValueGenerator for GeneratedPropertyContainer. + * + * @param <T> + * Property data type + * @since 7.4 + * @author Vaadin Ltd + */ +public abstract class PropertyValueGenerator<T> implements Serializable { + + /** + * Returns value for given Item. Used by GeneratedPropertyContainer when + * generating new properties. + * + * @param item + * currently handled item + * @param itemId + * item id for currently handled item + * @param propertyId + * id for this property + * @return generated value + */ + public abstract T getValue(Item item, Object itemId, Object propertyId); + + /** + * Return Property type for this generator. This function is called when + * {@link Property#getType()} is called for generated property. + * + * @return type of generated property + */ + public abstract Class<T> getType(); + + /** + * Translates sorting of the generated property in a specific direction to a + * set of property ids and directions in the underlying container. + * <p> + * SortOrder is similar to (or the same as) the SortOrder already defined + * for Grid. + * <p> + * The default implementation of this method returns an empty array, which + * means that the property will not be included in + * getSortableContainerPropertyIds(). Attempting to sort by that column + * throws UnsupportedOperationException. + * + * Returning null is not allowed. + * + * @param order + * a sort order for this property + * @return an array of sort orders describing how this property is sorted + */ + public SortOrder[] getSortProperties(SortOrder order) { + return new SortOrder[] {}; + } + + /** + * Return an updated filter that should be compatible with the underlying + * container. + * <p> + * This function is called when setting a filter for this generated + * property. Returning null from this function causes + * GeneratedPropertyContainer to discard the filter and not use it. + * <p> + * By default this function throws UnsupportedFilterException. + * + * @param filter + * original filter for this property + * @return modified filter that is compatible with the underlying container + * @throws UnsupportedFilterException + * if the implementation doesn't support modifying the provided + * filter + */ + public Filter modifyFilter(Filter filter) + throws UnsupportedFilterException { + throw new UnsupportedFilterException( + "Filter" + filter + " is not supported"); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/AbstractJunctionFilter.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/AbstractJunctionFilter.java new file mode 100644 index 0000000000..17b708a22c --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/AbstractJunctionFilter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import com.vaadin.v7.data.Container.Filter; + +/** + * Abstract base class for filters that are composed of multiple sub-filters. + * + * The method {@link #appliesToProperty(Object)} is provided to help + * implementing {@link Filter} for in-memory filters. + * + * @since 6.6 + */ +public abstract class AbstractJunctionFilter implements Filter { + + protected final Collection<Filter> filters; + + public AbstractJunctionFilter(Filter... filters) { + this.filters = Collections + .unmodifiableCollection(Arrays.asList(filters)); + } + + /** + * Returns an unmodifiable collection of the sub-filters of this composite + * filter. + * + * @return + */ + public Collection<Filter> getFilters() { + return filters; + } + + /** + * Returns true if a change in the named property may affect the filtering + * result. If some of the sub-filters are not in-memory filters, true is + * returned. + * + * By default, all sub-filters are iterated to check if any of them applies. + * If there are no sub-filters, false is returned - override in subclasses + * to change this behavior. + */ + @Override + public boolean appliesToProperty(Object propertyId) { + for (Filter filter : getFilters()) { + if (filter.appliesToProperty(propertyId)) { + return true; + } + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + AbstractJunctionFilter other = (AbstractJunctionFilter) obj; + // contents comparison with equals() + return Arrays.equals(filters.toArray(), other.filters.toArray()); + } + + @Override + public int hashCode() { + int hash = getFilters().size(); + for (Filter filter : filters) { + hash = (hash << 1) ^ filter.hashCode(); + } + return hash; + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/And.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/And.java new file mode 100644 index 0000000000..b7b5a18f3d --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/And.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Container.Filter; + +/** + * A compound {@link Filter} that accepts an item if all of its filters accept + * the item. + * + * If no filters are given, the filter should accept all items. + * + * This filter also directly supports in-memory filtering when all sub-filters + * do so. + * + * @see Or + * + * @since 6.6 + */ +public final class And extends AbstractJunctionFilter { + + /** + * + * @param filters + * filters of which the And filter will be composed + */ + public And(Filter... filters) { + super(filters); + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedFilterException { + for (Filter filter : getFilters()) { + if (!filter.passesFilter(itemId, item)) { + return false; + } + } + return true; + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Between.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Between.java new file mode 100644 index 0000000000..ec0e468554 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Between.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import java.util.Arrays; + +import com.vaadin.shared.util.SharedUtil; +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Container.Filter; + +public class Between implements Filter { + + private final Object propertyId; + private final Comparable<?> startValue; + private final Comparable<?> endValue; + + public Between(Object propertyId, Comparable<?> startValue, + Comparable<?> endValue) { + this.propertyId = propertyId; + this.startValue = startValue; + this.endValue = endValue; + } + + public Object getPropertyId() { + return propertyId; + } + + public Comparable<?> getStartValue() { + return startValue; + } + + public Comparable<?> getEndValue() { + return endValue; + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedOperationException { + Object value = item.getItemProperty(getPropertyId()).getValue(); + if (value instanceof Comparable) { + Comparable comparable = (Comparable) value; + return isAfterStartValue(comparable) + && isBeforeEndValue(comparable); + } else if (value == null) { + return getStartValue() == null && getEndValue() == null; + } + return false; + } + + @Override + public boolean appliesToProperty(Object propertyId) { + return getPropertyId() != null && getPropertyId().equals(propertyId); + } + + @Override + public int hashCode() { + return Arrays.hashCode(new Object[] { getPropertyId(), getStartValue(), + getEndValue() }); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + // Only objects of the same class can be equal + if (!getClass().equals(obj.getClass())) { + return false; + } + final Between o = (Between) obj; + + // Checks the properties one by one + boolean propertyIdEqual = SharedUtil.equals(getPropertyId(), + o.getPropertyId()); + boolean startValueEqual = SharedUtil.equals(getStartValue(), + o.getStartValue()); + boolean endValueEqual = SharedUtil.equals(getEndValue(), + o.getEndValue()); + return propertyIdEqual && startValueEqual && endValueEqual; + + } + + private boolean isAfterStartValue(Comparable comparable) { + return getStartValue() == null + || comparable.compareTo(getStartValue()) >= 0; + } + + private boolean isBeforeEndValue(Comparable comparable) { + return getEndValue() == null + || comparable.compareTo(getEndValue()) <= 0; + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Compare.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Compare.java new file mode 100644 index 0000000000..5b945ff411 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Compare.java @@ -0,0 +1,370 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Container.Filter; + +/** + * Simple container filter comparing an item property value against a given + * constant value. Use the nested classes {@link Equal}, {@link Greater}, + * {@link Less}, {@link GreaterOrEqual} and {@link LessOrEqual} instead of this + * class directly. + * + * This filter also directly supports in-memory filtering. + * + * The reference and actual values must implement {@link Comparable} and the + * class of the actual property value must be assignable from the class of the + * reference value. + * + * @since 6.6 + */ +public abstract class Compare implements Filter { + + public enum Operation { + EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL + } + + private final Object propertyId; + private final Operation operation; + private final Object value; + + /** + * A {@link Compare} filter that accepts items for which the identified + * property value is equal to <code>value</code>. + * + * For in-memory filters, {@link Comparable#compareTo(Object)} or, if not + * Comparable, {@link #equals(Object)} is used for the comparison. For other + * containers, the comparison implementation is container dependent and may + * use e.g. database comparison operations. + * + * @since 6.6 + */ + public static final class Equal extends Compare { + /** + * Construct a filter that accepts items for which the identified + * property value is equal to <code>value</code>. + * + * For in-memory filters, equals() is used for the comparison. For other + * containers, the comparison implementation is container dependent and + * may use e.g. database comparison operations. + * + * @param propertyId + * the identifier of the property whose value to compare + * against value, not null + * @param value + * the value to compare against - null values may or may not + * be supported depending on the container + */ + public Equal(Object propertyId, Object value) { + super(propertyId, value, Operation.EQUAL); + } + } + + /** + * A {@link Compare} filter that accepts items for which the identified + * property value is greater than <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} and + * {@link Comparable#compareTo(Object)} is used for the comparison. For + * other containers, the comparison implementation is container dependent + * and may use e.g. database comparison operations. + * + * @since 6.6 + */ + public static final class Greater extends Compare { + /** + * Construct a filter that accepts items for which the identified + * property value is greater than <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} + * and {@link Comparable#compareTo(Object)} is used for the comparison. + * For other containers, the comparison implementation is container + * dependent and may use e.g. database comparison operations. + * + * @param propertyId + * the identifier of the property whose value to compare + * against value, not null + * @param value + * the value to compare against - null values may or may not + * be supported depending on the container + */ + public Greater(Object propertyId, Object value) { + super(propertyId, value, Operation.GREATER); + } + } + + /** + * A {@link Compare} filter that accepts items for which the identified + * property value is less than <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} and + * {@link Comparable#compareTo(Object)} is used for the comparison. For + * other containers, the comparison implementation is container dependent + * and may use e.g. database comparison operations. + * + * @since 6.6 + */ + public static final class Less extends Compare { + /** + * Construct a filter that accepts items for which the identified + * property value is less than <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} + * and {@link Comparable#compareTo(Object)} is used for the comparison. + * For other containers, the comparison implementation is container + * dependent and may use e.g. database comparison operations. + * + * @param propertyId + * the identifier of the property whose value to compare + * against value, not null + * @param value + * the value to compare against - null values may or may not + * be supported depending on the container + */ + public Less(Object propertyId, Object value) { + super(propertyId, value, Operation.LESS); + } + } + + /** + * A {@link Compare} filter that accepts items for which the identified + * property value is greater than or equal to <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} and + * {@link Comparable#compareTo(Object)} is used for the comparison. For + * other containers, the comparison implementation is container dependent + * and may use e.g. database comparison operations. + * + * @since 6.6 + */ + public static final class GreaterOrEqual extends Compare { + /** + * Construct a filter that accepts items for which the identified + * property value is greater than or equal to <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} + * and {@link Comparable#compareTo(Object)} is used for the comparison. + * For other containers, the comparison implementation is container + * dependent and may use e.g. database comparison operations. + * + * @param propertyId + * the identifier of the property whose value to compare + * against value, not null + * @param value + * the value to compare against - null values may or may not + * be supported depending on the container + */ + public GreaterOrEqual(Object propertyId, Object value) { + super(propertyId, value, Operation.GREATER_OR_EQUAL); + } + } + + /** + * A {@link Compare} filter that accepts items for which the identified + * property value is less than or equal to <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} and + * {@link Comparable#compareTo(Object)} is used for the comparison. For + * other containers, the comparison implementation is container dependent + * and may use e.g. database comparison operations. + * + * @since 6.6 + */ + public static final class LessOrEqual extends Compare { + /** + * Construct a filter that accepts items for which the identified + * property value is less than or equal to <code>value</code>. + * + * For in-memory filters, the values must implement {@link Comparable} + * and {@link Comparable#compareTo(Object)} is used for the comparison. + * For other containers, the comparison implementation is container + * dependent and may use e.g. database comparison operations. + * + * @param propertyId + * the identifier of the property whose value to compare + * against value, not null + * @param value + * the value to compare against - null values may or may not + * be supported depending on the container + */ + public LessOrEqual(Object propertyId, Object value) { + super(propertyId, value, Operation.LESS_OR_EQUAL); + } + } + + /** + * Constructor for a {@link Compare} filter that compares the value of an + * item property with the given constant <code>value</code>. + * + * This constructor is intended to be used by the nested static classes only + * ({@link Equal}, {@link Greater}, {@link Less}, {@link GreaterOrEqual}, + * {@link LessOrEqual}). + * + * For in-memory filtering, comparisons except EQUAL require that the values + * implement {@link Comparable} and {@link Comparable#compareTo(Object)} is + * used for the comparison. The equality comparison is performed using + * {@link Object#equals(Object)}. + * + * For other containers, the comparison implementation is container + * dependent and may use e.g. database comparison operations. Therefore, the + * behavior of comparisons might differ in some cases between in-memory and + * other containers. + * + * @param propertyId + * the identifier of the property whose value to compare against + * value, not null + * @param value + * the value to compare against - null values may or may not be + * supported depending on the container + * @param operation + * the comparison {@link Operation} to use + */ + Compare(Object propertyId, Object value, Operation operation) { + this.propertyId = propertyId; + this.value = value; + this.operation = operation; + } + + @Override + public boolean passesFilter(Object itemId, Item item) { + final Property<?> p = item.getItemProperty(getPropertyId()); + if (null == p) { + return false; + } + Object value = p.getValue(); + switch (getOperation()) { + case EQUAL: + return compareEquals(value); + case GREATER: + return compareValue(value) > 0; + case LESS: + return compareValue(value) < 0; + case GREATER_OR_EQUAL: + return compareValue(value) >= 0; + case LESS_OR_EQUAL: + return compareValue(value) <= 0; + } + // all cases should have been processed above + return false; + } + + /** + * Checks if the this value equals the given value. Favors Comparable over + * equals to better support e.g. BigDecimal where equals is stricter than + * compareTo. + * + * @param otherValue + * The value to compare to + * @return true if the values are equal, false otherwise + */ + private boolean compareEquals(Object otherValue) { + if (value == null || otherValue == null) { + return (otherValue == value); + } else if (value == otherValue) { + return true; + } else if (value instanceof Comparable && otherValue.getClass() + .isAssignableFrom(getValue().getClass())) { + return ((Comparable) value).compareTo(otherValue) == 0; + } else { + return value.equals(otherValue); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected int compareValue(Object value1) { + if (null == value) { + return null == value1 ? 0 : -1; + } else if (null == value1) { + return 1; + } else if (getValue() instanceof Comparable) { + if (value1.getClass().isInstance(getValue())) { + return -((Comparable) getValue()).compareTo(value1); + } else if (getValue().getClass().isInstance(value1)) { + // isInstance returns true if value1 is a sub-type of + // getValue(), i.e. value1 must here be Comparable + return ((Comparable) value1).compareTo(getValue()); + } + + } + throw new IllegalArgumentException("Could not compare the arguments: " + + value1 + ", " + getValue()); + } + + @Override + public boolean appliesToProperty(Object propertyId) { + return getPropertyId().equals(propertyId); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + // Only objects of the same class can be equal + if (!getClass().equals(obj.getClass())) { + return false; + } + final Compare o = (Compare) obj; + + // Checks the properties one by one + if (getPropertyId() != o.getPropertyId() && null != o.getPropertyId() + && !o.getPropertyId().equals(getPropertyId())) { + return false; + } + if (getOperation() != o.getOperation()) { + return false; + } + return (null == getValue()) ? null == o.getValue() + : getValue().equals(o.getValue()); + } + + @Override + public int hashCode() { + return (null != getPropertyId() ? getPropertyId().hashCode() : 0) + ^ (null != getValue() ? getValue().hashCode() : 0); + } + + /** + * Returns the property id of the property to compare against the fixed + * value. + * + * @return property id (not null) + */ + public Object getPropertyId() { + return propertyId; + } + + /** + * Returns the comparison operation. + * + * @return {@link Operation} + */ + public Operation getOperation() { + return operation; + } + + /** + * Returns the value to compare the property against. + * + * @return comparison reference value + */ + public Object getValue() { + return value; + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/IsNull.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/IsNull.java new file mode 100644 index 0000000000..0a7e115255 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/IsNull.java @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Container.Filter; + +/** + * Simple container filter checking whether an item property value is null. + * + * This filter also directly supports in-memory filtering. + * + * @since 6.6 + */ +public final class IsNull implements Filter { + + private final Object propertyId; + + /** + * Constructor for a filter that compares the value of an item property with + * null. + * + * For in-memory filtering, a simple == check is performed. For other + * containers, the comparison implementation is container dependent but + * should correspond to the in-memory null check. + * + * @param propertyId + * the identifier (not null) of the property whose value to check + */ + public IsNull(Object propertyId) { + this.propertyId = propertyId; + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedOperationException { + final Property<?> p = item.getItemProperty(getPropertyId()); + if (null == p) { + return false; + } + return null == p.getValue(); + } + + @Override + public boolean appliesToProperty(Object propertyId) { + return getPropertyId().equals(propertyId); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + // Only objects of the same class can be equal + if (!getClass().equals(obj.getClass())) { + return false; + } + final IsNull o = (IsNull) obj; + + // Checks the properties one by one + return (null != getPropertyId()) + ? getPropertyId().equals(o.getPropertyId()) + : null == o.getPropertyId(); + } + + @Override + public int hashCode() { + return (null != getPropertyId() ? getPropertyId().hashCode() : 0); + } + + /** + * Returns the property id of the property tested by the filter, not null + * for valid filters. + * + * @return property id (not null) + */ + public Object getPropertyId() { + return propertyId; + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Like.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Like.java new file mode 100644 index 0000000000..5d92271afe --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Like.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Container.Filter; + +public class Like implements Filter { + private final Object propertyId; + private final String value; + private boolean caseSensitive; + + public Like(Object propertyId, String value) { + this(propertyId, value, true); + } + + public Like(Object propertyId, String value, boolean caseSensitive) { + this.propertyId = propertyId; + this.value = value; + setCaseSensitive(caseSensitive); + } + + public Object getPropertyId() { + return propertyId; + } + + public String getValue() { + return value; + } + + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + public boolean isCaseSensitive() { + return caseSensitive; + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedOperationException { + if (!item.getItemProperty(getPropertyId()).getType() + .isAssignableFrom(String.class)) { + // We can only handle strings + return false; + } + String colValue = (String) item.getItemProperty(getPropertyId()) + .getValue(); + + // Fix issue #10167 - avoid NPE and drop null property values + if (colValue == null) { + return false; + } + + String pattern = getValue().replace("%", ".*"); + if (isCaseSensitive()) { + return colValue.matches(pattern); + } + return colValue.toUpperCase().matches(pattern.toUpperCase()); + } + + @Override + public boolean appliesToProperty(Object propertyId) { + return getPropertyId() != null && getPropertyId().equals(propertyId); + } + + @Override + public int hashCode() { + return getPropertyId().hashCode() + getValue().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + // Only objects of the same class can be equal + if (!getClass().equals(obj.getClass())) { + return false; + } + final Like o = (Like) obj; + + // Checks the properties one by one + boolean propertyIdEqual = (null != getPropertyId()) + ? getPropertyId().equals(o.getPropertyId()) + : null == o.getPropertyId(); + boolean valueEqual = (null != getValue()) + ? getValue().equals(o.getValue()) : null == o.getValue(); + return propertyIdEqual && valueEqual; + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Not.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Not.java new file mode 100644 index 0000000000..d0680eb481 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Not.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Container.Filter; + +/** + * Negating filter that accepts the items rejected by another filter. + * + * This filter directly supports in-memory filtering when the negated filter + * does so. + * + * @since 6.6 + */ +public final class Not implements Filter { + private final Filter filter; + + /** + * Constructs a filter that negates a filter. + * + * @param filter + * {@link Filter} to negate, not-null + */ + public Not(Filter filter) { + this.filter = filter; + } + + /** + * Returns the negated filter. + * + * @return Filter + */ + public Filter getFilter() { + return filter; + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedOperationException { + return !filter.passesFilter(itemId, item); + } + + /** + * Returns true if a change in the named property may affect the filtering + * result. Return value is the same as {@link #appliesToProperty(Object)} + * for the negated filter. + * + * @return boolean + */ + @Override + public boolean appliesToProperty(Object propertyId) { + return filter.appliesToProperty(propertyId); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + return filter.equals(((Not) obj).getFilter()); + } + + @Override + public int hashCode() { + return filter.hashCode(); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Or.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Or.java new file mode 100644 index 0000000000..5062e6d987 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/Or.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Container.Filter; + +/** + * A compound {@link Filter} that accepts an item if any of its filters accept + * the item. + * + * If no filters are given, the filter should reject all items. + * + * This filter also directly supports in-memory filtering when all sub-filters + * do so. + * + * @see And + * + * @since 6.6 + */ +public final class Or extends AbstractJunctionFilter { + + /** + * + * @param filters + * filters of which the Or filter will be composed + */ + public Or(Filter... filters) { + super(filters); + } + + @Override + public boolean passesFilter(Object itemId, Item item) + throws UnsupportedFilterException { + for (Filter filter : getFilters()) { + if (filter.passesFilter(itemId, item)) { + return true; + } + } + return false; + } + + /** + * Returns true if a change in the named property may affect the filtering + * result. If some of the sub-filters are not in-memory filters, true is + * returned. + * + * By default, all sub-filters are iterated to check if any of them applies. + * If there are no sub-filters, true is returned as an empty Or rejects all + * items. + */ + @Override + public boolean appliesToProperty(Object propertyId) { + if (getFilters().isEmpty()) { + // empty Or filters out everything + return true; + } else { + return super.appliesToProperty(propertyId); + } + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/SimpleStringFilter.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/SimpleStringFilter.java new file mode 100644 index 0000000000..b3f7d032e1 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/SimpleStringFilter.java @@ -0,0 +1,167 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Container.Filter; + +/** + * Simple string filter for matching items that start with or contain a + * specified string. The matching can be case-sensitive or case-insensitive. + * + * This filter also directly supports in-memory filtering. When performing + * in-memory filtering, values of other types are converted using toString(), + * but other (lazy container) implementations do not need to perform such + * conversions and might not support values of different types. + * + * Note that this filter is modeled after the pre-6.6 filtering mechanisms, and + * might not be very efficient e.g. for database filtering. + * + * TODO this might still change + * + * @since 6.6 + */ +public final class SimpleStringFilter implements Filter { + + final Object propertyId; + final String filterString; + final boolean ignoreCase; + final boolean onlyMatchPrefix; + + public SimpleStringFilter(Object propertyId, String filterString, + boolean ignoreCase, boolean onlyMatchPrefix) { + this.propertyId = propertyId; + this.filterString = ignoreCase ? filterString.toLowerCase() + : filterString; + this.ignoreCase = ignoreCase; + this.onlyMatchPrefix = onlyMatchPrefix; + } + + @Override + public boolean passesFilter(Object itemId, Item item) { + final Property<?> p = item.getItemProperty(propertyId); + if (p == null) { + return false; + } + Object propertyValue = p.getValue(); + if (propertyValue == null) { + return false; + } + final String value = ignoreCase ? propertyValue.toString().toLowerCase() + : propertyValue.toString(); + if (onlyMatchPrefix) { + if (!value.startsWith(filterString)) { + return false; + } + } else { + if (!value.contains(filterString)) { + return false; + } + } + return true; + } + + @Override + public boolean appliesToProperty(Object propertyId) { + return this.propertyId.equals(propertyId); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + // Only ones of the objects of the same class can be equal + if (!(obj instanceof SimpleStringFilter)) { + return false; + } + final SimpleStringFilter o = (SimpleStringFilter) obj; + + // Checks the properties one by one + if (propertyId != o.propertyId && o.propertyId != null + && !o.propertyId.equals(propertyId)) { + return false; + } + if (filterString != o.filterString && o.filterString != null + && !o.filterString.equals(filterString)) { + return false; + } + if (ignoreCase != o.ignoreCase) { + return false; + } + if (onlyMatchPrefix != o.onlyMatchPrefix) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return (propertyId != null ? propertyId.hashCode() : 0) + ^ (filterString != null ? filterString.hashCode() : 0); + } + + /** + * Returns the property identifier to which this filter applies. + * + * @return property id + */ + public Object getPropertyId() { + return propertyId; + } + + /** + * Returns the filter string. + * + * Note: this method is intended only for implementations of lazy string + * filters and may change in the future. + * + * @return filter string given to the constructor + */ + public String getFilterString() { + return filterString; + } + + /** + * Returns whether the filter is case-insensitive or case-sensitive. + * + * Note: this method is intended only for implementations of lazy string + * filters and may change in the future. + * + * @return true if performing case-insensitive filtering, false for + * case-sensitive + */ + public boolean isIgnoreCase() { + return ignoreCase; + } + + /** + * Returns true if the filter only applies to the beginning of the value + * string, false for any location in the value. + * + * Note: this method is intended only for implementations of lazy string + * filters and may change in the future. + * + * @return true if checking for matches at the beginning of the value only, + * false if matching any part of value + */ + public boolean isOnlyMatchPrefix() { + return onlyMatchPrefix; + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/UnsupportedFilterException.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/UnsupportedFilterException.java new file mode 100644 index 0000000000..68e18da32a --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/filter/UnsupportedFilterException.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2016 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.v7.data.util.filter; + +import java.io.Serializable; + +/** + * Exception for cases where a container does not support a specific type of + * filters. + * + * If possible, this should be thrown already when adding a filter to a + * container. If a problem is not detected at that point, an + * {@link UnsupportedOperationException} can be throws when attempting to + * perform filtering. + * + * @since 6.6 + */ +public class UnsupportedFilterException extends RuntimeException + implements Serializable { + public UnsupportedFilterException() { + } + + public UnsupportedFilterException(String message) { + super(message); + } + + public UnsupportedFilterException(Exception cause) { + super(cause); + } + + public UnsupportedFilterException(String message, Exception cause) { + super(message, cause); + } +} |