diff options
Diffstat (limited to 'shared')
40 files changed, 2091 insertions, 15 deletions
diff --git a/shared/src/com/vaadin/shared/AbstractComponentState.java b/shared/src/com/vaadin/shared/AbstractComponentState.java index 9e21954f3e..1c32a67c70 100644 --- a/shared/src/com/vaadin/shared/AbstractComponentState.java +++ b/shared/src/com/vaadin/shared/AbstractComponentState.java @@ -18,6 +18,7 @@ package com.vaadin.shared; import java.util.List; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.SharedState; /** @@ -31,7 +32,9 @@ public class AbstractComponentState extends SharedState { public String height = ""; public String width = ""; public boolean readOnly = false; + @NoLayout public boolean immediate = false; + @NoLayout public String description = ""; // Note: for the caption, there is a difference between null and an empty // string! diff --git a/shared/src/com/vaadin/shared/annotations/NoLayout.java b/shared/src/com/vaadin/shared/annotations/NoLayout.java new file mode 100644 index 0000000000..78ff1e2984 --- /dev/null +++ b/shared/src/com/vaadin/shared/annotations/NoLayout.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * Annotation used to mark client RPC methods, state fields, or state setter + * methods that should not trigger an layout phase after changes have been + * processed. Whenever there's at least one change that is not marked with this + * annotation, the framework will assume some sizes might have changed an will + * therefore start a layout phase after applying the changes. + * <p> + * This annotation can be used for any RPC method or state property that does + * not cause the size of the component or its children to change. Please note + * that almost anything related to CSS (e.g. adding or removing a stylename) has + * the potential of causing sizes to change with appropriate style definitions + * in the application theme. + * + * @since + * + * @author Vaadin Ltd + */ +@Documented +@Target({ ElementType.METHOD, ElementType.FIELD }) +public @interface NoLayout { + // Just an empty marker annotation +} diff --git a/shared/src/com/vaadin/shared/communication/SharedState.java b/shared/src/com/vaadin/shared/communication/SharedState.java index e16fc51fae..b21a675a4a 100644 --- a/shared/src/com/vaadin/shared/communication/SharedState.java +++ b/shared/src/com/vaadin/shared/communication/SharedState.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import com.vaadin.shared.Connector; +import com.vaadin.shared.annotations.NoLayout; /** * Interface to be implemented by all shared state classes used to communicate @@ -64,6 +65,7 @@ public class SharedState implements Serializable { /** * A set of event identifiers with registered listeners. */ + @NoLayout public Set<String> registeredEventListeners = null; } diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java new file mode 100644 index 0000000000..3e5dd9a332 --- /dev/null +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.data; + +import com.vaadin.shared.annotations.NoLayout; +import com.vaadin.shared.communication.ClientRpc; + +/** + * RPC interface used for pushing container data to the client. + * + * @since + * @author Vaadin Ltd + */ +public interface DataProviderRpc extends ClientRpc { + + /** + * Sends updated row data to a client. + * <p> + * rowDataJson represents a JSON array of JSON objects in the following + * format: + * + * <pre> + * [{ + * "d": [COL_1_JSON, COL_2_json, ...], + * "k": "1" + * }, + * ... + * ] + * </pre> + * + * where COL_INDEX is the index of the column (as a string), and COL_n_JSON + * is valid JSON of the column's data. + * + * @param firstRowIndex + * the index of the first updated row + * @param rowDataJson + * the updated row data + * @see com.vaadin.shared.ui.grid.GridState#JSONKEY_DATA + * @see com.vaadin.ui.components.grid.Renderer#encode(Object) + */ + @NoLayout + public void setRowData(int firstRowIndex, String rowDataJson); + + /** + * Informs the client to remove row data. + * + * @param firstRowIndex + * the index of the first removed row + * @param count + * the number of rows removed from <code>firstRowIndex</code> and + * onwards + */ + @NoLayout + public void removeRowData(int firstRowIndex, int count); + + /** + * Informs the client to insert new row data. + * + * @param firstRowIndex + * the index of the first new row + * @param count + * the number of rows inserted at <code>firstRowIndex</code> + */ + @NoLayout + public void insertRowData(int firstRowIndex, int count); + + /** + * Resets all data and defines a new size for the data. + * <p> + * This should be used in the cases where the data has changed in some + * unverifiable way. I.e. "something happened". This will lead to a + * re-rendering of the current Grid viewport + * + * @param size + * the size of the new data set + */ + public void resetDataAndSize(int size); +} diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java new file mode 100644 index 0000000000..637a353447 --- /dev/null +++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.data; + +import com.vaadin.shared.annotations.Delayed; +import com.vaadin.shared.communication.ServerRpc; + +/** + * RPC interface used for requesting container data to the client. + * + * @since + * @author Vaadin Ltd + */ +public interface DataRequestRpc extends ServerRpc { + + /** + * Request rows from the server. + * + * @param firstRowIndex + * the index of the first requested row + * @param numberOfRows + * the number of requested rows + * @param firstCachedRowIndex + * the index of the first cached row + * @param cacheSize + * the number of cached rows + */ + public void requestRows(int firstRowIndex, int numberOfRows, + int firstCachedRowIndex, int cacheSize); + + /** + * Informs the server that an item referenced with a key pinned status has + * changed. This is a delayed call that happens along with next rpc call to + * server. + * + * @param key + * key mapping to item + * @param isPinned + * pinned status of referenced item + */ + @Delayed + public void setPinned(String key, boolean isPinned); +} diff --git a/shared/src/com/vaadin/shared/data/sort/SortDirection.java b/shared/src/com/vaadin/shared/data/sort/SortDirection.java new file mode 100644 index 0000000000..043b363226 --- /dev/null +++ b/shared/src/com/vaadin/shared/data/sort/SortDirection.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.data.sort; + +import java.io.Serializable; + +/** + * Describes sorting direction. + * + * @since + * @author Vaadin Ltd + */ +public enum SortDirection implements Serializable { + + /** + * Ascending (e.g. A-Z, 1..9) sort order + */ + ASCENDING { + @Override + public SortDirection getOpposite() { + return DESCENDING; + } + }, + + /** + * Descending (e.g. Z-A, 9..1) sort order + */ + DESCENDING { + @Override + public SortDirection getOpposite() { + return ASCENDING; + } + }; + + /** + * Get the sort direction that is the direct opposite to this one. + * + * @return a sort direction value + */ + public abstract SortDirection getOpposite(); +} diff --git a/shared/src/com/vaadin/shared/ui/AbstractEmbeddedState.java b/shared/src/com/vaadin/shared/ui/AbstractEmbeddedState.java index f5779de43d..0cb9be8702 100644 --- a/shared/src/com/vaadin/shared/ui/AbstractEmbeddedState.java +++ b/shared/src/com/vaadin/shared/ui/AbstractEmbeddedState.java @@ -16,10 +16,12 @@ package com.vaadin.shared.ui; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; public class AbstractEmbeddedState extends AbstractComponentState { public static final String SOURCE_RESOURCE = "source"; + @NoLayout public String alternateText; } diff --git a/shared/src/com/vaadin/shared/ui/AbstractMediaState.java b/shared/src/com/vaadin/shared/ui/AbstractMediaState.java index d2ef09810b..3029bedca7 100644 --- a/shared/src/com/vaadin/shared/ui/AbstractMediaState.java +++ b/shared/src/com/vaadin/shared/ui/AbstractMediaState.java @@ -19,17 +19,21 @@ import java.util.ArrayList; import java.util.List; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.URLReference; public class AbstractMediaState extends AbstractComponentState { public boolean showControls; + @NoLayout public String altText; public boolean htmlContentAllowed; + @NoLayout public boolean autoplay; + @NoLayout public boolean muted; public List<URLReference> sources = new ArrayList<URLReference>(); diff --git a/shared/src/com/vaadin/shared/ui/MediaControl.java b/shared/src/com/vaadin/shared/ui/MediaControl.java index 2311d57b16..ab31d6f95f 100644 --- a/shared/src/com/vaadin/shared/ui/MediaControl.java +++ b/shared/src/com/vaadin/shared/ui/MediaControl.java @@ -16,6 +16,7 @@ package com.vaadin.shared.ui; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.ClientRpc; /** @@ -27,10 +28,12 @@ public interface MediaControl extends ClientRpc { /** * Start playing the media. */ + @NoLayout public void play(); /** * Pause playback of the media. */ + @NoLayout public void pause(); } diff --git a/shared/src/com/vaadin/shared/ui/TabIndexState.java b/shared/src/com/vaadin/shared/ui/TabIndexState.java index eec61a0595..1afe982546 100644 --- a/shared/src/com/vaadin/shared/ui/TabIndexState.java +++ b/shared/src/com/vaadin/shared/ui/TabIndexState.java @@ -16,6 +16,7 @@ package com.vaadin.shared.ui; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; /** * Interface implemented by state classes that support tab indexes. @@ -29,6 +30,7 @@ public class TabIndexState extends AbstractComponentState { /** * The <i>tabulator index</i> of the field. */ + @NoLayout public int tabIndex = 0; } diff --git a/shared/src/com/vaadin/shared/ui/button/ButtonState.java b/shared/src/com/vaadin/shared/ui/button/ButtonState.java index 5b099572df..01ef9a038b 100644 --- a/shared/src/com/vaadin/shared/ui/button/ButtonState.java +++ b/shared/src/com/vaadin/shared/ui/button/ButtonState.java @@ -17,6 +17,7 @@ package com.vaadin.shared.ui.button; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.ui.TabIndexState; /** @@ -31,7 +32,10 @@ public class ButtonState extends TabIndexState { { primaryStyleName = "v-button"; } + @NoLayout public boolean disableOnClick = false; + @NoLayout public int clickShortcutKeyCode = 0; + @NoLayout public String iconAltText = ""; } diff --git a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java index 07726f8af0..6f10af4314 100644 --- a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java +++ b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java @@ -15,6 +15,8 @@ */ package com.vaadin.shared.ui.datefield; +import com.vaadin.shared.annotations.NoLayout; + public class PopupDateFieldState extends TextualDateFieldState { public static final String DESCRIPTION_FOR_ASSISTIVE_DEVICES = "Arrow down key opens calendar element for choosing the date"; @@ -23,5 +25,6 @@ public class PopupDateFieldState extends TextualDateFieldState { } public boolean textFieldEnabled = true; + @NoLayout public String descriptionForAssistiveDevices = DESCRIPTION_FOR_ASSISTIVE_DEVICES; } diff --git a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java index 09bfb9c1a1..bf38ee04a9 100644 --- a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java +++ b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java @@ -18,6 +18,7 @@ package com.vaadin.shared.ui.datefield; import java.util.Date; import com.vaadin.shared.AbstractFieldState; +import com.vaadin.shared.annotations.NoLayout; public class TextualDateFieldState extends AbstractFieldState { { @@ -28,11 +29,13 @@ public class TextualDateFieldState extends AbstractFieldState { * Start range that has been cleared, depending on the resolution of the * date field */ + @NoLayout public Date rangeStart = null; /* * End range that has been cleared, depending on the resolution of the date * field */ + @NoLayout public Date rangeEnd = null; } diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java new file mode 100644 index 0000000000..2ef0dfc3f8 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.ui.grid; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * The column group data shared between the server and the client + * + * @since + * @author Vaadin Ltd + */ +public class ColumnGroupState implements Serializable { + + /** + * The columns that is included in the group + */ + public List<String> columns = new ArrayList<String>(); + + /** + * The header text of the group + */ + public String header; + + /** + * The footer text of the group + */ + public String footer; +} diff --git a/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java new file mode 100644 index 0000000000..c083252754 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import com.vaadin.shared.communication.ClientRpc; + +/** + * An RPC interface for the grid editor server-to-client communications. + * + * @since + * @author Vaadin Ltd + */ +public interface EditorClientRpc extends ClientRpc { + + /** + * Tells the client to open the editor and bind data to it. + * + * @param rowIndex + * the index of the edited row + */ + void bind(int rowIndex); + + /** + * Tells the client to cancel editing and hide the editor. + * + * @param rowIndex + * the index of the edited row + */ + void cancel(int rowIndex); + + /** + * Confirms a pending {@link EditorServerRpc#bind(int) bind request} + * sent by the client. + */ + void confirmBind(); + + /** + * Confirms a pending {@link EditorServerRpc#save(int) save request} + * sent by the client. + */ + void confirmSave(); +} diff --git a/shared/src/com/vaadin/shared/ui/grid/EditorServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/EditorServerRpc.java new file mode 100644 index 0000000000..57df691547 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/EditorServerRpc.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * An RPC interface for the grid editor client-to-server communications. + * + * @since + * @author Vaadin Ltd + */ +public interface EditorServerRpc extends ServerRpc { + + /** + * Asks the server to open the editor and bind data to it. When a bind + * request is sent, it must be acknowledged with a + * {@link EditorClientRpc#confirmBind() confirm call} before the client + * can open the editor. + * + * @param rowIndex + * the index of the edited row + */ + void bind(int rowIndex); + + /** + * Asks the server to save unsaved changes in the editor to the data source. + * When a save request is sent, it must be acknowledged with a + * {@link EditorClientRpc#confirmSave() confirm call}. + * + * @param rowIndex + * the index of the edited row + */ + void save(int rowIndex); + + /** + * Tells the server to cancel editing. When sending a cancel request, the + * client does not need to wait for confirmation by the server before hiding + * the editor. + * + * @param rowIndex + * the index of the edited row + */ + void cancel(int rowIndex); +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java new file mode 100644 index 0000000000..ade9e87f36 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import com.vaadin.shared.communication.ClientRpc; + +/** + * Server-to-client RPC interface for the Grid component. + * + * @since + * @author Vaadin Ltd + */ +public interface GridClientRpc extends ClientRpc { + + /** + * Command client Grid to scroll to a specific data row. + * + * @param row + * zero-based row index. If the row index is below zero or above + * the row count of the client-side data source, a client-side + * exception will be triggered. Since this exception has no + * handling by default, an out-of-bounds value will cause a + * client-side crash. + * @param destination + * desired placement of scrolled-to row. See the documentation + * for {@link ScrollDestination} for more information. + */ + public void scrollToRow(int row, ScrollDestination destination); + + /** + * Command client Grid to scroll to the first row. + */ + public void scrollToStart(); + + /** + * Command client Grid to scroll to the last row. + */ + public void scrollToEnd(); + +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java new file mode 100644 index 0000000000..11cb133fa5 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import java.io.Serializable; + +import com.vaadin.shared.Connector; + +/** + * Column state DTO for transferring column properties from the server to the + * client + * + * @since + * @author Vaadin Ltd + */ +public class GridColumnState implements Serializable { + + public static final double DEFAULT_MAX_WIDTH = -1; + public static final double DEFAULT_MIN_WIDTH = 10.0d; + public static final int DEFAULT_EXPAND_RATIO = -1; + + public static final double DEFAULT_COLUMN_WIDTH_PX = -1; + + /** + * Id used by grid connector to map server side column with client side + * column + */ + public String id; + + /** + * Column width in pixels. Default column width is + * {@value #DEFAULT_COLUMN_WIDTH_PX}. + */ + public double width = DEFAULT_COLUMN_WIDTH_PX; + + /** + * The connector for the renderer used to render the cells in this column. + */ + public Connector rendererConnector; + + /** + * The connector for the field used to edit cells in this column when the + * editor interface is active. + */ + public Connector editorConnector; + + /** + * Are sorting indicators shown for a column. Default is false. + */ + public boolean sortable = false; + + /** How much of the remaining space this column will reserve. */ + public int expandRatio = DEFAULT_EXPAND_RATIO; + + /** + * The maximum expansion width of this column. -1 for "no maximum". If + * maxWidth is less than the calculated width, maxWidth is ignored. + */ + public double maxWidth = DEFAULT_MAX_WIDTH; + + /** + * The minimum expansion width of this column. -1 for "no minimum". If + * minWidth is less than the calculated width, minWidth will win. + */ + public double minWidth = DEFAULT_MIN_WIDTH; +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java new file mode 100644 index 0000000000..1ee79a5d37 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import java.io.Serializable; + +/** + * Container class for common constants and default values used by the Grid + * component. + * + * @since + * @author Vaadin Ltd + */ +public final class GridConstants implements Serializable { + + /** + * Default padding in pixels when scrolling programmatically, without an + * explicitly defined padding value. + */ + public static final int DEFAULT_PADDING = 0; + + /** + * Delay before a long tap action is triggered. Number in milliseconds. + */ + public static final int LONG_TAP_DELAY = 500; + + /** + * The threshold in pixels a finger can move while long tapping. + */ + public static final int LONG_TAP_THRESHOLD = 3; +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java new file mode 100644 index 0000000000..141b1ed9ca --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import java.util.List; + +import com.vaadin.shared.communication.ServerRpc; +import com.vaadin.shared.data.sort.SortDirection; + +/** + * Client-to-server RPC interface for the Grid component + * + * @since + * @author Vaadin Ltd + */ +public interface GridServerRpc extends ServerRpc { + void selectionChange(List<String> newSelection); + + void sort(String[] columnIds, SortDirection[] directions, + boolean userOriginated); + + void selectAll(); +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java new file mode 100644 index 0000000000..1f98431caf --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -0,0 +1,149 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.ui.grid; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.DelegateToWidget; +import com.vaadin.shared.data.sort.SortDirection; + +/** + * The shared state for the {@link com.vaadin.ui.components.grid.Grid} component + * + * @since + * @author Vaadin Ltd + */ +public class GridState extends AbstractComponentState { + + /** + * A description of which of the three bundled SelectionModels is currently + * in use. + * <p> + * Used as a data transfer object instead of the client/server ones, because + * they don't know about each others classes. + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode + * @see com.vaadin.client.ui.grid.Grid.SelectionMode + */ + public enum SharedSelectionMode { + /** + * Representation of a single selection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#SINGLE + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#SINGLE + */ + SINGLE, + + /** + * Representation of a multiselection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#MULTI + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#MULTI + */ + MULTI, + + /** + * Representation of a no-selection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#NONE + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#NONE + */ + NONE; + } + + /** + * The default value for height-by-rows for both GWT widgets + * {@link com.vaadin.ui.components.grid Grid} and + * {@link com.vaadin.client.ui.grid.Escalator Escalator} + */ + public static final double DEFAULT_HEIGHT_BY_ROWS = 10.0d; + + /** + * The key in which a row's data can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_DATA = "d"; + + /** + * The key in which a row's own key can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_ROWKEY = "k"; + + /** + * The key in which a row's generated style can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_ROWSTYLE = "rs"; + + /** + * The key in which a generated styles for a row's cells can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_CELLSTYLES = "cs"; + + /** + * Columns in grid. + */ + public List<GridColumnState> columns = new ArrayList<GridColumnState>(); + + /** + * Column order in grid. + */ + public List<String> columnOrder = new ArrayList<String>(); + + public GridStaticSectionState header = new GridStaticSectionState(); + + public GridStaticSectionState footer = new GridStaticSectionState(); + + /** The number of frozen columns */ + public int frozenColumnCount = 0; + + /** The height of the Grid in terms of body rows. */ + @DelegateToWidget + public double heightByRows = DEFAULT_HEIGHT_BY_ROWS; + + /** The mode by which Grid defines its height. */ + @DelegateToWidget + public HeightMode heightMode = HeightMode.CSS; + + // instantiated just to avoid NPEs + public List<String> selectedKeys = new ArrayList<String>(); + + public SharedSelectionMode selectionMode; + + /** Keys of the currently sorted columns */ + public String[] sortColumns = new String[0]; + + /** Directions for each sorted column */ + public SortDirection[] sortDirs = new SortDirection[0]; + + /** The enabled state of the editor interface */ + public boolean editorEnabled = false; + + /** Whether row data might contain generated row styles */ + public boolean hasRowStyleGenerator; + /** Whether row data might contain generated cell styles */ + public boolean hasCellStyleGenerator; + +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java new file mode 100644 index 0000000000..eae4bc8da4 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +/** + * Enumeration, specifying the content type of a Cell in a GridStaticSection. + * + * @since + * @author Vaadin Ltd + */ +public enum GridStaticCellType { + /** + * Text content + */ + TEXT, + + /** + * HTML content + */ + HTML, + + /** + * Widget content + */ + WIDGET; +}
\ No newline at end of file diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java new file mode 100644 index 0000000000..88539913d1 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.vaadin.shared.Connector; + +/** + * Shared state for Grid headers and footers. + * + * @since + * @author Vaadin Ltd + */ +public class GridStaticSectionState implements Serializable { + + public static class CellState implements Serializable { + public String text = ""; + + public String html = ""; + + public Connector connector = null; + + public GridStaticCellType type = GridStaticCellType.TEXT; + + public String columnId; + + public String styleName = null; + } + + public static class RowState implements Serializable { + public List<CellState> cells = new ArrayList<CellState>(); + + public boolean defaultRow = false; + + /** + * Map from column id set to cell state for merged state. + */ + public Map<Set<String>, CellState> cellGroups = new HashMap<Set<String>, CellState>(); + + /** + * The style name for the row. Null if none. + */ + public String styleName = null; + } + + public List<RowState> rows = new ArrayList<RowState>(); + + public boolean visible = true; +} diff --git a/shared/src/com/vaadin/shared/ui/grid/HeightMode.java b/shared/src/com/vaadin/shared/ui/grid/HeightMode.java new file mode 100644 index 0000000000..228fcbf0f4 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/HeightMode.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +/** + * The modes for height calculation that are supported by Grid ( + * {@link com.vaadin.client.ui.grid.Grid client} and + * {@link com.vaadin.ui.components.grid.Grid server}) / + * {@link com.vaadin.client.ui.grid.Escalator Escalator}. + * + * @since + * @author Vaadin Ltd + * @see com.vaadin.client.ui.grid.Grid#setHeightMode(HeightMode) + * @see com.vaadin.ui.components.grid.Grid#setHeightMode(HeightMode) + * @see com.vaadin.client.ui.grid.Escalator#setHeightMode(HeightMode) + */ +public enum HeightMode { + /** + * The height of the Component or Widget is defined by a CSS-like value. + * (e.g. "100px", "50em" or "25%") + */ + CSS, + + /** + * The height of the Component or Widget in question is defined by a number + * of rows. + */ + ROW; +} diff --git a/shared/src/com/vaadin/shared/ui/grid/Range.java b/shared/src/com/vaadin/shared/ui/grid/Range.java new file mode 100644 index 0000000000..2054845320 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/Range.java @@ -0,0 +1,431 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.ui.grid; + +import java.io.Serializable; + +/** + * An immutable representation of a range, marked by start and end points. + * <p> + * The range is treated as inclusive at the start, and exclusive at the end. + * I.e. the range [0..1[ has the length 1, and represents one integer: 0. + * <p> + * The range is considered {@link #isEmpty() empty} if the start is the same as + * the end. + * + * @since + * @author Vaadin Ltd + */ +public final class Range implements Serializable { + private final int start; + private final int end; + + /** + * Creates a range object representing a single integer. + * + * @param integer + * the number to represent as a range + * @return the range represented by <code>integer</code> + */ + public static Range withOnly(final int integer) { + return new Range(integer, integer + 1); + } + + /** + * Creates a range between two integers. + * <p> + * The range start is <em>inclusive</em> and the end is <em>exclusive</em>. + * So, a range "between" 0 and 5 represents the numbers 0, 1, 2, 3 and 4, + * but not 5. + * + * @param start + * the start of the the range, inclusive + * @param end + * the end of the range, exclusive + * @return a range representing <code>[start..end[</code> + * @throws IllegalArgumentException + * if <code>start > end</code> + */ + public static Range between(final int start, final int end) + throws IllegalArgumentException { + return new Range(start, end); + } + + /** + * Creates a range from a start point, with a given length. + * + * @param start + * the first integer to include in the range + * @param length + * the length of the resulting range + * @return a range starting from <code>start</code>, with + * <code>length</code> number of integers following + * @throws IllegalArgumentException + * if length < 0 + */ + public static Range withLength(final int start, final int length) + throws IllegalArgumentException { + if (length < 0) { + /* + * The constructor of Range will throw an exception if start > + * start+length (i.e. if length is negative). We're throwing the + * same exception type, just with a more descriptive message. + */ + throw new IllegalArgumentException("length must not be negative"); + } + return new Range(start, start + length); + } + + /** + * Creates a new range between two numbers: <code>[start..end[</code>. + * + * @param start + * the start integer, inclusive + * @param end + * the end integer, exclusive + * @throws IllegalArgumentException + * if <code>start > end</code> + */ + private Range(final int start, final int end) + throws IllegalArgumentException { + if (start > end) { + throw new IllegalArgumentException( + "start must not be greater than end"); + } + + this.start = start; + this.end = end; + } + + /** + * Returns the <em>inclusive</em> start point of this range. + * + * @return the start point of this range + */ + public int getStart() { + return start; + } + + /** + * Returns the <em>exclusive</em> end point of this range. + * + * @return the end point of this range + */ + public int getEnd() { + return end; + } + + /** + * The number of integers contained in the range. + * + * @return the number of integers contained in the range + */ + public int length() { + return getEnd() - getStart(); + } + + /** + * Checks whether the range has no elements between the start and end. + * + * @return <code>true</code> iff the range contains no elements. + */ + public boolean isEmpty() { + return getStart() >= getEnd(); + } + + /** + * Checks whether this range and another range are at least partially + * covering the same values. + * + * @param other + * the other range to check against + * @return <code>true</code> if this and <code>other</code> intersect + */ + public boolean intersects(final Range other) { + return getStart() < other.getEnd() && other.getStart() < getEnd(); + } + + /** + * Checks whether an integer is found within this range. + * + * @param integer + * an integer to test for presence in this range + * @return <code>true</code> iff <code>integer</code> is in this range + */ + public boolean contains(final int integer) { + return getStart() <= integer && integer < getEnd(); + } + + /** + * Checks whether this range is a subset of another range. + * + * @return <code>true</code> iff <code>other</code> completely wraps this + * range + */ + public boolean isSubsetOf(final Range other) { + return other.getStart() <= getStart() && getEnd() <= other.getEnd(); + } + + /** + * Overlay this range with another one, and partition the ranges according + * to how they position relative to each other. + * <p> + * The three partitions are returned as a three-element Range array: + * <ul> + * <li>Elements in this range that occur before elements in + * <code>other</code>. + * <li>Elements that are shared between the two ranges. + * <li>Elements in this range that occur after elements in + * <code>other</code>. + * </ul> + * + * @param other + * the other range to act as delimiters. + * @return a three-element Range array of partitions depicting the elements + * before (index 0), shared/inside (index 1) and after (index 2). + */ + public Range[] partitionWith(final Range other) { + final Range[] splitBefore = splitAt(other.getStart()); + final Range rangeBefore = splitBefore[0]; + final Range[] splitAfter = splitBefore[1].splitAt(other.getEnd()); + final Range rangeInside = splitAfter[0]; + final Range rangeAfter = splitAfter[1]; + return new Range[] { rangeBefore, rangeInside, rangeAfter }; + } + + /** + * Get a range that is based on this one, but offset by a number. + * + * @param offset + * the number to offset by + * @return a copy of this range, offset by <code>offset</code> + */ + public Range offsetBy(final int offset) { + if (offset == 0) { + return this; + } else { + return new Range(start + offset, end + offset); + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [" + getStart() + ".." + getEnd() + + "[" + (isEmpty() ? " (empty)" : ""); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + end; + result = prime * result + start; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Range other = (Range) obj; + if (end != other.end) { + return false; + } + if (start != other.start) { + return false; + } + return true; + } + + /** + * Checks whether this range starts before the start of another range. + * + * @param other + * the other range to compare against + * @return <code>true</code> iff this range starts before the + * <code>other</code> + */ + public boolean startsBefore(final Range other) { + return getStart() < other.getStart(); + } + + /** + * Checks whether this range ends before the start of another range. + * + * @param other + * the other range to compare against + * @return <code>true</code> iff this range ends before the + * <code>other</code> + */ + public boolean endsBefore(final Range other) { + return getEnd() <= other.getStart(); + } + + /** + * Checks whether this range ends after the end of another range. + * + * @param other + * the other range to compare against + * @return <code>true</code> iff this range ends after the + * <code>other</code> + */ + public boolean endsAfter(final Range other) { + return getEnd() > other.getEnd(); + } + + /** + * Checks whether this range starts after the end of another range. + * + * @param other + * the other range to compare against + * @return <code>true</code> iff this range starts after the + * <code>other</code> + */ + public boolean startsAfter(final Range other) { + return getStart() >= other.getEnd(); + } + + /** + * Split the range into two at a certain integer. + * <p> + * <em>Example:</em> <code>[5..10[.splitAt(7) == [5..7[, [7..10[</code> + * + * @param integer + * the integer at which to split the range into two + * @return an array of two ranges, with <code>[start..integer[</code> in the + * first element, and <code>[integer..end[</code> in the second + * element. + * <p> + * If {@code integer} is less than {@code start}, [empty, + * {@code this} ] is returned. if <code>integer</code> is equal to + * or greater than {@code end}, [{@code this}, empty] is returned + * instead. + */ + public Range[] splitAt(final int integer) { + if (integer < start) { + return new Range[] { Range.withLength(start, 0), this }; + } else if (integer >= end) { + return new Range[] { this, Range.withLength(end, 0) }; + } else { + return new Range[] { new Range(start, integer), + new Range(integer, end) }; + } + } + + /** + * Split the range into two after a certain number of integers into the + * range. + * <p> + * Calling this method is equivalent to calling + * <code>{@link #splitAt(int) splitAt}({@link #getStart()}+length);</code> + * <p> + * <em>Example:</em> + * <code>[5..10[.splitAtFromStart(2) == [5..7[, [7..10[</code> + * + * @param length + * the length at which to split this range into two + * @return an array of two ranges, having the <code>length</code>-first + * elements of this range, and the second range having the rest. If + * <code>length</code> ≤ 0, the first element will be empty, and + * the second element will be this range. If <code>length</code> + * ≥ {@link #length()}, the first element will be this range, + * and the second element will be empty. + */ + public Range[] splitAtFromStart(final int length) { + return splitAt(getStart() + length); + } + + /** + * Combines two ranges to create a range containing all values in both + * ranges, provided there are no gaps between the ranges. + * + * @param other + * the range to combine with this range + * + * @return the combined range + * + * @throws IllegalArgumentException + * if the two ranges aren't connected + */ + public Range combineWith(Range other) throws IllegalArgumentException { + if (getStart() > other.getEnd() || other.getStart() > getEnd()) { + throw new IllegalArgumentException("There is a gap between " + this + + " and " + other); + } + + return Range.between(Math.min(getStart(), other.getStart()), + Math.max(getEnd(), other.getEnd())); + } + + /** + * Creates a range that is expanded the given amounts in both ends. + * + * @param startDelta + * the amount to expand by in the beginning of the range + * @param endDelta + * the amount to expand by in the end of the range + * + * @return an expanded range + * + * @throws IllegalArgumentException + * if the new range would have <code>start > end</code> + */ + public Range expand(int startDelta, int endDelta) + throws IllegalArgumentException { + return Range.between(getStart() - startDelta, getEnd() + endDelta); + } + + /** + * Limits this range to be within the bounds of the provided range. + * <p> + * This is basically an optimized way of calculating + * <code>{@link #partitionWith(Range)}[1]</code> without the overhead of + * defining the parts that do not overlap. + * <p> + * If the two ranges do not intersect, an empty range is returned. There are + * no guarantees about the position of that range. + * + * @param bounds + * the bounds that the returned range should be limited to + * @return a bounded range + */ + public Range restrictTo(Range bounds) { + boolean startWithin = getStart() >= bounds.getStart(); + boolean endWithin = getEnd() <= bounds.getEnd(); + + if (startWithin) { + if (endWithin) { + return this; + } else { + return Range.between(getStart(), bounds.getEnd()); + } + } else { + if (endWithin) { + return Range.between(bounds.getStart(), getEnd()); + } else { + return bounds; + } + } + } +} diff --git a/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java b/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java new file mode 100644 index 0000000000..43d5fcc21b --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +/** + * Enumeration, specifying the destinations that are supported when scrolling + * rows or columns into view. + * + * @since + * @author Vaadin Ltd + */ +public enum ScrollDestination { + + /** + * Scroll as little as possible to show the target element. If the element + * fits into view, this works as START or END depending on the current + * scroll position. If the element does not fit into view, this works as + * START. + */ + ANY, + + /** + * Scrolls so that the element is shown at the start of the viewport. The + * viewport will, however, not scroll beyond its contents. + */ + START, + + /** + * Scrolls so that the element is shown in the middle of the viewport. The + * viewport will, however, not scroll beyond its contents, given more + * elements than what the viewport is able to show at once. Under no + * circumstances will the viewport scroll before its first element. + */ + MIDDLE, + + /** + * Scrolls so that the element is shown at the end of the viewport. The + * viewport will, however, not scroll before its first element. + */ + END + +} diff --git a/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java b/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java new file mode 100644 index 0000000000..658caef050 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid.renderers; + +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.communication.ServerRpc; + +public interface RendererClickRpc extends ServerRpc { + /** + * Called when a click event has occurred and there are server side + * listeners for the event. + * + * @param mouseDetails + * Details about the mouse when the event took place + */ + public void click(String rowKey, String columnId, + MouseEventDetails mouseDetails); +} diff --git a/shared/src/com/vaadin/shared/ui/panel/PanelState.java b/shared/src/com/vaadin/shared/ui/panel/PanelState.java index 6c0fcb683c..8f48fad921 100644 --- a/shared/src/com/vaadin/shared/ui/panel/PanelState.java +++ b/shared/src/com/vaadin/shared/ui/panel/PanelState.java @@ -16,11 +16,14 @@ package com.vaadin.shared.ui.panel; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; public class PanelState extends AbstractComponentState { { primaryStyleName = "v-panel"; } + @NoLayout public int tabIndex; + @NoLayout public int scrollLeft, scrollTop; } diff --git a/shared/src/com/vaadin/shared/ui/popupview/PopupViewState.java b/shared/src/com/vaadin/shared/ui/popupview/PopupViewState.java index da49e47ae8..86fda428a1 100644 --- a/shared/src/com/vaadin/shared/ui/popupview/PopupViewState.java +++ b/shared/src/com/vaadin/shared/ui/popupview/PopupViewState.java @@ -16,10 +16,12 @@ package com.vaadin.shared.ui.popupview; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; public class PopupViewState extends AbstractComponentState { public String html; + @NoLayout public boolean hideOnMouseOut; } diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java index 79ef766951..6f557489dd 100644 --- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java @@ -17,6 +17,7 @@ package com.vaadin.shared.ui.progressindicator; import com.vaadin.shared.AbstractFieldState; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.SharedState; /** @@ -32,6 +33,7 @@ public class ProgressBarState extends AbstractFieldState { primaryStyleName = PRIMARY_STYLE_NAME; } public boolean indeterminate = false; + @NoLayout public Float state = 0.0f; } diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java index 15d0a947d7..9b3cf94d4a 100644 --- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java @@ -15,6 +15,8 @@ */ package com.vaadin.shared.ui.progressindicator; +import com.vaadin.shared.annotations.NoLayout; + @Deprecated public class ProgressIndicatorState extends ProgressBarState { public static final String PRIMARY_STYLE_NAME = "v-progressindicator"; @@ -23,5 +25,6 @@ public class ProgressIndicatorState extends ProgressBarState { primaryStyleName = PRIMARY_STYLE_NAME; } + @NoLayout public int pollingInterval = 1000; } diff --git a/shared/src/com/vaadin/shared/ui/slider/SliderState.java b/shared/src/com/vaadin/shared/ui/slider/SliderState.java index 0e48a0c4e2..a96d35bc13 100644 --- a/shared/src/com/vaadin/shared/ui/slider/SliderState.java +++ b/shared/src/com/vaadin/shared/ui/slider/SliderState.java @@ -16,21 +16,26 @@ package com.vaadin.shared.ui.slider; import com.vaadin.shared.AbstractFieldState; +import com.vaadin.shared.annotations.NoLayout; public class SliderState extends AbstractFieldState { { primaryStyleName = "v-slider"; } + @NoLayout public double value; + @NoLayout public double maxValue = 100; + @NoLayout public double minValue = 0; /** * The number of fractional digits that are considered significant. Must be * non-negative. */ + @NoLayout public int resolution = 0; public SliderOrientation orientation = SliderOrientation.HORIZONTAL; diff --git a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java index 98a1d2b87f..69a3330f64 100644 --- a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java +++ b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.NoLayout; public class TabsheetState extends AbstractComponentState { public static final String PRIMARY_STYLE_NAME = "v-tabsheet"; @@ -31,6 +32,7 @@ public class TabsheetState extends AbstractComponentState { * Index of the component when switching focus - not related to Tabsheet * tabs. */ + @NoLayout public int tabIndex; public List<TabState> tabs = new ArrayList<TabState>(); diff --git a/shared/src/com/vaadin/shared/ui/textarea/TextAreaState.java b/shared/src/com/vaadin/shared/ui/textarea/TextAreaState.java index 380ee4c7fb..c1f9536278 100644 --- a/shared/src/com/vaadin/shared/ui/textarea/TextAreaState.java +++ b/shared/src/com/vaadin/shared/ui/textarea/TextAreaState.java @@ -16,6 +16,7 @@ package com.vaadin.shared.ui.textarea; import com.vaadin.shared.annotations.DelegateToWidget; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.ui.textfield.AbstractTextFieldState; public class TextAreaState extends AbstractTextFieldState { @@ -33,6 +34,7 @@ public class TextAreaState extends AbstractTextFieldState { * Tells if word-wrapping should be used in the text area. */ @DelegateToWidget + @NoLayout public boolean wordwrap = true; } diff --git a/shared/src/com/vaadin/shared/ui/textfield/AbstractTextFieldState.java b/shared/src/com/vaadin/shared/ui/textfield/AbstractTextFieldState.java index 084d02cd7b..9d4272c22f 100644 --- a/shared/src/com/vaadin/shared/ui/textfield/AbstractTextFieldState.java +++ b/shared/src/com/vaadin/shared/ui/textfield/AbstractTextFieldState.java @@ -16,6 +16,7 @@ package com.vaadin.shared.ui.textfield; import com.vaadin.shared.AbstractFieldState; +import com.vaadin.shared.annotations.NoLayout; public class AbstractTextFieldState extends AbstractFieldState { { @@ -25,6 +26,7 @@ public class AbstractTextFieldState extends AbstractFieldState { /** * Maximum character count in text field. */ + @NoLayout public int maxLength = -1; /** @@ -35,10 +37,12 @@ public class AbstractTextFieldState extends AbstractFieldState { /** * The prompt to display in an empty field. Null when disabled. */ + @NoLayout public String inputPrompt = null; /** * The text in the field */ + @NoLayout public String text = null; } diff --git a/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java b/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java index e32a27830d..fb052a25e9 100644 --- a/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java @@ -16,11 +16,14 @@ package com.vaadin.shared.ui.ui; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.ClientRpc; public interface ScrollClientRpc extends ClientRpc { + @NoLayout public void setScrollTop(int scrollTop); + @NoLayout public void setScrollLeft(int scrollLeft); } diff --git a/shared/src/com/vaadin/shared/ui/window/WindowState.java b/shared/src/com/vaadin/shared/ui/window/WindowState.java index fa73bea391..7dafba57ff 100644 --- a/shared/src/com/vaadin/shared/ui/window/WindowState.java +++ b/shared/src/com/vaadin/shared/ui/window/WindowState.java @@ -16,6 +16,7 @@ package com.vaadin.shared.ui.window; import com.vaadin.shared.Connector; +import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.ui.panel.PanelState; public class WindowState extends PanelState { @@ -23,20 +24,34 @@ public class WindowState extends PanelState { primaryStyleName = "v-window"; } + @NoLayout public boolean modal = false; + @NoLayout public boolean resizable = true; + @NoLayout public boolean resizeLazy = false; + @NoLayout public boolean draggable = true; + @NoLayout public boolean centered = false; + @NoLayout public int positionX = -1; + @NoLayout public int positionY = -1; public WindowMode windowMode = WindowMode.NORMAL; + @NoLayout public String assistivePrefix = ""; + @NoLayout public String assistivePostfix = ""; + @NoLayout public Connector[] contentDescription = new Connector[0]; + @NoLayout public WindowRole role = WindowRole.DIALOG; + @NoLayout public boolean assistiveTabStop = false; + @NoLayout public String assistiveTabStopTopText = "Top of dialog"; + @NoLayout public String assistiveTabStopBottomText = "Bottom of Dialog"; } diff --git a/shared/src/com/vaadin/shared/util/SharedUtil.java b/shared/src/com/vaadin/shared/util/SharedUtil.java index 7276f418fa..b40d8f03bb 100644 --- a/shared/src/com/vaadin/shared/util/SharedUtil.java +++ b/shared/src/com/vaadin/shared/util/SharedUtil.java @@ -60,4 +60,140 @@ public class SharedUtil implements Serializable { */ public static final String SIZE_PATTERN = "^(-?\\d*(?:\\.\\d+)?)(%|px|em|rem|ex|in|cm|mm|pt|pc)?$"; + /** + * Splits a camelCaseString into an array of words with the casing + * preserved. + * + * @since 7.4 + * @param camelCaseString + * The input string in camelCase format + * @return An array with one entry per word in the input string + */ + public static String[] splitCamelCase(String camelCaseString) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < camelCaseString.length(); i++) { + char c = camelCaseString.charAt(i); + if (Character.isUpperCase(c) && isWordComplete(camelCaseString, i)) { + sb.append(' '); + } + sb.append(c); + } + return sb.toString().split(" "); + } + + private static boolean isWordComplete(String camelCaseString, int i) { + if (i == 0) { + // Word can't end at the beginning + return false; + } else if (!Character.isUpperCase(camelCaseString.charAt(i - 1))) { + // Word ends if previous char wasn't upper case + return true; + } else if (i + 1 < camelCaseString.length() + && !Character.isUpperCase(camelCaseString.charAt(i + 1))) { + // Word ends if next char isn't upper case + return true; + } else { + return false; + } + } + + /** + * Converts a camelCaseString to a human friendly format (Camel case + * string). + * <p> + * In general splits words when the casing changes but also handles special + * cases such as consecutive upper case characters. Examples: + * <p> + * {@literal MyBeanContainer} becomes {@literal My Bean Container} + * {@literal AwesomeURLFactory} becomes {@literal Awesome URL Factory} + * {@literal SomeUriAction} becomes {@literal Some Uri Action} + * + * @since 7.4 + * @param camelCaseString + * The input string in camelCase format + * @return A human friendly version of the input + */ + public static String camelCaseToHumanFriendly(String camelCaseString) { + String[] parts = splitCamelCase(camelCaseString); + for (int i = 0; i < parts.length; i++) { + parts[i] = capitalize(parts[i]); + } + return join(parts, " "); + } + + private static boolean isAllUpperCase(String string) { + for (int i = 0; i < string.length(); i++) { + char c = string.charAt(i); + if (!Character.isUpperCase(c) && !Character.isDigit(c)) { + return false; + } + } + return true; + } + + /** + * Joins the words in the input array together into a single string by + * inserting the separator string between each word. + * + * @since 7.4 + * @param parts + * The array of words + * @param separator + * The separator string to use between words + * @return The constructed string of words and separators + */ + public static String join(String[] parts, String separator) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + sb.append(parts[i]); + sb.append(separator); + } + return sb.substring(0, sb.length() - 1); + } + + /** + * Capitalizes the first character in the given string + * + * @since 7.4 + * @param string + * The string to capitalize + * @return The capitalized string + */ + public static String capitalize(String string) { + if (string == null) { + return null; + } + + if (string.length() <= 1) { + return string.toUpperCase(); + } + + return string.substring(0, 1).toUpperCase() + string.substring(1); + } + + /** + * Converts a property id to a human friendly format. Handles nested + * properties by only considering the last part, e.g. "address.streetName" + * is equal to "streetName" for this method. + * + * @since 7.4 + * @param propertyId + * The propertyId to format + * @return A human friendly version of the property id + */ + public static String propertyIdToHumanFriendly(Object propertyId) { + String string = propertyId.toString(); + if (string.isEmpty()) { + return ""; + } + + // For nested properties, only use the last part + int dotLocation = string.lastIndexOf('.'); + if (dotLocation > 0 && dotLocation < string.length() - 1) { + string = string.substring(dotLocation + 1); + } + + return camelCaseToHumanFriendly(string); + } + } diff --git a/shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java b/shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java new file mode 100644 index 0000000000..ab67b22d0b --- /dev/null +++ b/shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java @@ -0,0 +1,406 @@ +/* + * Copyright 2000-2013 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.shared.ui.grid; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +@SuppressWarnings("static-method") +public class RangeTest { + + @Test(expected = IllegalArgumentException.class) + public void startAfterEndTest() { + Range.between(10, 9); + } + + @Test(expected = IllegalArgumentException.class) + public void negativeLengthTest() { + Range.withLength(10, -1); + } + + @Test + public void constructorEquivalenceTest() { + assertEquals("10 == [10,11[", Range.withOnly(10), Range.between(10, 11)); + assertEquals("[10,20[ == 10, length 10", Range.between(10, 20), + Range.withLength(10, 10)); + assertEquals("10 == 10, length 1", Range.withOnly(10), + Range.withLength(10, 1)); + } + + @Test + public void boundsTest() { + { + final Range range = Range.between(0, 10); + assertEquals("between(0, 10) start", 0, range.getStart()); + assertEquals("between(0, 10) end", 10, range.getEnd()); + } + + { + final Range single = Range.withOnly(10); + assertEquals("withOnly(10) start", 10, single.getStart()); + assertEquals("withOnly(10) end", 11, single.getEnd()); + } + + { + final Range length = Range.withLength(10, 5); + assertEquals("withLength(10, 5) start", 10, length.getStart()); + assertEquals("withLength(10, 5) end", 15, length.getEnd()); + } + } + + @Test + @SuppressWarnings("boxing") + public void equalsTest() { + final Range range1 = Range.between(0, 10); + final Range range2 = Range.withLength(0, 11); + + assertTrue("null", !range1.equals(null)); + assertTrue("reflexive", range1.equals(range1)); + assertEquals("symmetric", range1.equals(range2), range2.equals(range1)); + } + + @Test + public void containsTest() { + final int start = 0; + final int end = 10; + final Range range = Range.between(start, end); + + assertTrue("start should be contained", range.contains(start)); + assertTrue("start-1 should not be contained", + !range.contains(start - 1)); + assertTrue("end should not be contained", !range.contains(end)); + assertTrue("end-1 should be contained", range.contains(end - 1)); + + assertTrue("[0..10[ contains 5", Range.between(0, 10).contains(5)); + assertTrue("empty range does not contain 5", !Range.between(5, 5) + .contains(5)); + } + + @Test + public void emptyTest() { + assertTrue("[0..0[ should be empty", Range.between(0, 0).isEmpty()); + assertTrue("Range of length 0 should be empty", Range.withLength(0, 0) + .isEmpty()); + + assertTrue("[0..1[ should not be empty", !Range.between(0, 1).isEmpty()); + assertTrue("Range of length 1 should not be empty", + !Range.withLength(0, 1).isEmpty()); + } + + @Test + public void splitTest() { + final Range startRange = Range.between(0, 10); + final Range[] splitRanges = startRange.splitAt(5); + assertEquals("[0..10[ split at 5, lower", Range.between(0, 5), + splitRanges[0]); + assertEquals("[0..10[ split at 5, upper", Range.between(5, 10), + splitRanges[1]); + } + + @Test + public void split_valueBefore() { + Range range = Range.between(10, 20); + Range[] splitRanges = range.splitAt(5); + + assertEquals(Range.between(10, 10), splitRanges[0]); + assertEquals(range, splitRanges[1]); + } + + @Test + public void split_valueAfter() { + Range range = Range.between(10, 20); + Range[] splitRanges = range.splitAt(25); + + assertEquals(range, splitRanges[0]); + assertEquals(Range.between(20, 20), splitRanges[1]); + } + + @Test + public void emptySplitTest() { + final Range range = Range.between(5, 10); + final Range[] split1 = range.splitAt(0); + assertTrue("split1, [0]", split1[0].isEmpty()); + assertEquals("split1, [1]", range, split1[1]); + + final Range[] split2 = range.splitAt(15); + assertEquals("split2, [0]", range, split2[0]); + assertTrue("split2, [1]", split2[1].isEmpty()); + } + + @Test + public void lengthTest() { + assertEquals("withLength length", 5, Range.withLength(10, 5).length()); + assertEquals("between length", 5, Range.between(10, 15).length()); + assertEquals("withOnly 10 length", 1, Range.withOnly(10).length()); + } + + @Test + public void intersectsTest() { + assertTrue("[0..10[ intersects [5..15[", Range.between(0, 10) + .intersects(Range.between(5, 15))); + assertTrue("[0..10[ does not intersect [10..20[", !Range.between(0, 10) + .intersects(Range.between(10, 20))); + } + + @Test + public void intersects_emptyInside() { + assertTrue("[5..5[ does intersect with [0..10[", Range.between(5, 5) + .intersects(Range.between(0, 10))); + assertTrue("[0..10[ does intersect with [5..5[", Range.between(0, 10) + .intersects(Range.between(5, 5))); + } + + @Test + public void intersects_emptyOutside() { + assertTrue("[15..15[ does not intersect with [0..10[", + !Range.between(15, 15).intersects(Range.between(0, 10))); + assertTrue("[0..10[ does not intersect with [15..15[", + !Range.between(0, 10).intersects(Range.between(15, 15))); + } + + @Test + public void subsetTest() { + assertTrue("[5..10[ is subset of [0..20[", Range.between(5, 10) + .isSubsetOf(Range.between(0, 20))); + + final Range range = Range.between(0, 10); + assertTrue("range is subset of self", range.isSubsetOf(range)); + + assertTrue("[0..10[ is not subset of [5..15[", !Range.between(0, 10) + .isSubsetOf(Range.between(5, 15))); + } + + @Test + public void offsetTest() { + assertEquals(Range.between(5, 15), Range.between(0, 10).offsetBy(5)); + } + + @Test + public void rangeStartsBeforeTest() { + final Range former = Range.between(0, 5); + final Range latter = Range.between(1, 5); + assertTrue("former should starts before latter", + former.startsBefore(latter)); + assertTrue("latter shouldn't start before latter", + !latter.startsBefore(former)); + + assertTrue("no overlap allowed", + !Range.between(0, 5).startsBefore(Range.between(0, 10))); + } + + @Test + public void rangeStartsAfterTest() { + final Range former = Range.between(0, 5); + final Range latter = Range.between(5, 10); + assertTrue("latter should start after former", + latter.startsAfter(former)); + assertTrue("former shouldn't start after latter", + !former.startsAfter(latter)); + + assertTrue("no overlap allowed", + !Range.between(5, 10).startsAfter(Range.between(0, 6))); + } + + @Test + public void rangeEndsBeforeTest() { + final Range former = Range.between(0, 5); + final Range latter = Range.between(5, 10); + assertTrue("latter should end before former", former.endsBefore(latter)); + assertTrue("former shouldn't end before latter", + !latter.endsBefore(former)); + + assertTrue("no overlap allowed", + !Range.between(5, 10).endsBefore(Range.between(9, 15))); + } + + @Test + public void rangeEndsAfterTest() { + final Range former = Range.between(1, 5); + final Range latter = Range.between(1, 6); + assertTrue("latter should end after former", latter.endsAfter(former)); + assertTrue("former shouldn't end after latter", + !former.endsAfter(latter)); + + assertTrue("no overlap allowed", + !Range.between(0, 10).endsAfter(Range.between(5, 10))); + } + + @Test(expected = IllegalArgumentException.class) + public void combine_notOverlappingFirstSmaller() { + Range.between(0, 10).combineWith(Range.between(11, 20)); + } + + @Test(expected = IllegalArgumentException.class) + public void combine_notOverlappingSecondLarger() { + Range.between(11, 20).combineWith(Range.between(0, 10)); + } + + @Test(expected = IllegalArgumentException.class) + public void combine_firstEmptyNotOverlapping() { + Range.between(15, 15).combineWith(Range.between(0, 10)); + } + + @Test(expected = IllegalArgumentException.class) + public void combine_secondEmptyNotOverlapping() { + Range.between(0, 10).combineWith(Range.between(15, 15)); + } + + @Test + public void combine_barelyOverlapping() { + Range r1 = Range.between(0, 10); + Range r2 = Range.between(10, 20); + + // Test both ways, should give the same result + Range combined1 = r1.combineWith(r2); + Range combined2 = r2.combineWith(r1); + assertEquals(combined1, combined2); + + assertEquals(0, combined1.getStart()); + assertEquals(20, combined1.getEnd()); + } + + @Test + public void combine_subRange() { + Range r1 = Range.between(0, 10); + Range r2 = Range.between(2, 8); + + // Test both ways, should give the same result + Range combined1 = r1.combineWith(r2); + Range combined2 = r2.combineWith(r1); + assertEquals(combined1, combined2); + + assertEquals(r1, combined1); + } + + @Test + public void combine_intersecting() { + Range r1 = Range.between(0, 10); + Range r2 = Range.between(5, 15); + + // Test both ways, should give the same result + Range combined1 = r1.combineWith(r2); + Range combined2 = r2.combineWith(r1); + assertEquals(combined1, combined2); + + assertEquals(0, combined1.getStart()); + assertEquals(15, combined1.getEnd()); + + } + + @Test + public void combine_emptyInside() { + Range r1 = Range.between(0, 10); + Range r2 = Range.between(5, 5); + + // Test both ways, should give the same result + Range combined1 = r1.combineWith(r2); + Range combined2 = r2.combineWith(r1); + assertEquals(combined1, combined2); + + assertEquals(r1, combined1); + } + + @Test + public void expand_basic() { + Range r1 = Range.between(5, 10); + Range r2 = r1.expand(2, 3); + + assertEquals(Range.between(3, 13), r2); + } + + @Test + public void expand_negativeLegal() { + Range r1 = Range.between(5, 10); + + Range r2 = r1.expand(-2, -2); + assertEquals(Range.between(7, 8), r2); + + Range r3 = r1.expand(-3, -2); + assertEquals(Range.between(8, 8), r3); + + Range r4 = r1.expand(3, -8); + assertEquals(Range.between(2, 2), r4); + } + + @Test(expected = IllegalArgumentException.class) + public void expand_negativeIllegal1() { + Range r1 = Range.between(5, 10); + + // Should throw because the start would contract beyond the end + r1.expand(-3, -3); + + } + + @Test(expected = IllegalArgumentException.class) + public void expand_negativeIllegal2() { + Range r1 = Range.between(5, 10); + + // Should throw because the end would contract beyond the start + r1.expand(3, -9); + } + + @Test + public void restrictTo_fullyInside() { + Range r1 = Range.between(5, 10); + Range r2 = Range.between(4, 11); + + Range r3 = r1.restrictTo(r2); + assertTrue(r1 == r3); + } + + @Test + public void restrictTo_fullyOutside() { + Range r1 = Range.between(4, 11); + Range r2 = Range.between(5, 10); + + Range r3 = r1.restrictTo(r2); + assertTrue(r2 == r3); + } + + public void restrictTo_notInterstecting() { + Range r1 = Range.between(5, 10); + Range r2 = Range.between(15, 20); + + Range r3 = r1.restrictTo(r2); + assertTrue("Non-intersecting ranges should produce an empty result", + r3.isEmpty()); + + Range r4 = r2.restrictTo(r1); + assertTrue("Non-intersecting ranges should produce an empty result", + r4.isEmpty()); + } + + public void restrictTo_startOutside() { + Range r1 = Range.between(5, 10); + Range r2 = Range.between(7, 15); + + Range r3 = r1.restrictTo(r2); + + assertEquals(Range.between(7, 10), r3); + } + + public void restrictTo_endOutside() { + Range r1 = Range.between(5, 10); + Range r2 = Range.between(4, 7); + + Range r3 = r1.restrictTo(r2); + + assertEquals(Range.between(5, 7), r3); + } + +} diff --git a/shared/tests/src/com/vaadin/shared/util/SharedUtilTests.java b/shared/tests/src/com/vaadin/shared/util/SharedUtilTests.java index b593032bd6..208d4ca7c7 100644 --- a/shared/tests/src/com/vaadin/shared/util/SharedUtilTests.java +++ b/shared/tests/src/com/vaadin/shared/util/SharedUtilTests.java @@ -1,43 +1,79 @@ package com.vaadin.shared.util; -import org.junit.Before; -import org.junit.Test; - import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; -public class SharedUtilTests { - - private SharedUtil sut; +import org.junit.Assert; +import org.junit.Test; - @Before - public void setup() { - sut = new SharedUtil(); - } +public class SharedUtilTests { @Test public void trailingSlashIsTrimmed() { - assertThat(sut.trimTrailingSlashes("/path/"), is("/path")); + assertThat(SharedUtil.trimTrailingSlashes("/path/"), is("/path")); } @Test public void noTrailingSlashForTrimming() { - assertThat(sut.trimTrailingSlashes("/path"), is("/path")); + assertThat(SharedUtil.trimTrailingSlashes("/path"), is("/path")); } @Test public void trailingSlashesAreTrimmed() { - assertThat(sut.trimTrailingSlashes("/path///"), is("/path")); + assertThat(SharedUtil.trimTrailingSlashes("/path///"), is("/path")); } @Test public void emptyStringIsHandled() { - assertThat(sut.trimTrailingSlashes(""), is("")); + assertThat(SharedUtil.trimTrailingSlashes(""), is("")); } @Test public void rootSlashIsTrimmed() { - assertThat(sut.trimTrailingSlashes("/"), is("")); + assertThat(SharedUtil.trimTrailingSlashes("/"), is("")); } + @Test + public void camelCaseToHumanReadable() { + Assert.assertEquals("First Name", + SharedUtil.camelCaseToHumanFriendly("firstName")); + Assert.assertEquals("First Name", + SharedUtil.camelCaseToHumanFriendly("first name")); + Assert.assertEquals("First Name2", + SharedUtil.camelCaseToHumanFriendly("firstName2")); + Assert.assertEquals("First", + SharedUtil.camelCaseToHumanFriendly("first")); + Assert.assertEquals("First", + SharedUtil.camelCaseToHumanFriendly("First")); + Assert.assertEquals("Some XYZ Abbreviation", + SharedUtil.camelCaseToHumanFriendly("SomeXYZAbbreviation")); + + // Javadoc examples + Assert.assertEquals("My Bean Container", + SharedUtil.camelCaseToHumanFriendly("MyBeanContainer")); + Assert.assertEquals("Awesome URL Factory", + SharedUtil.camelCaseToHumanFriendly("AwesomeURLFactory")); + Assert.assertEquals("Some Uri Action", + SharedUtil.camelCaseToHumanFriendly("SomeUriAction")); + + } + + @Test + public void splitCamelCase() { + assertCamelCaseSplit("firstName", "first", "Name"); + assertCamelCaseSplit("fooBar", "foo", "Bar"); + assertCamelCaseSplit("fooBar", "foo", "Bar"); + assertCamelCaseSplit("fBar", "f", "Bar"); + assertCamelCaseSplit("FBar", "F", "Bar"); + assertCamelCaseSplit("MYCdi", "MY", "Cdi"); + assertCamelCaseSplit("MyCDIUI", "My", "CDIUI"); + assertCamelCaseSplit("MyCDIUITwo", "My", "CDIUI", "Two"); + assertCamelCaseSplit("first name", "first", "name"); + + } + + private void assertCamelCaseSplit(String camelCaseString, String... parts) { + String[] splitParts = SharedUtil.splitCamelCase(camelCaseString); + Assert.assertArrayEquals(parts, splitParts); + } } |