summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/base/base.scss4
-rw-r--r--WebContent/VAADIN/themes/base/escalator/escalator.scss117
-rw-r--r--WebContent/VAADIN/themes/base/grid/grid.scss3
-rw-r--r--WebContent/VAADIN/themes/reindeer-tests/styles.css4
-rw-r--r--client/src/com/vaadin/client/data/AbstractRemoteDataSource.java323
-rw-r--r--client/src/com/vaadin/client/data/DataChangeHandler.java59
-rw-r--r--client/src/com/vaadin/client/data/DataSource.java76
-rw-r--r--client/src/com/vaadin/client/data/RpcDataSourceConnector.java81
-rw-r--r--client/src/com/vaadin/client/ui/grid/Cell.java75
-rw-r--r--client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java146
-rw-r--r--client/src/com/vaadin/client/ui/grid/ColumnGroup.java184
-rw-r--r--client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java243
-rw-r--r--client/src/com/vaadin/client/ui/grid/Escalator.java4042
-rw-r--r--client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java66
-rw-r--r--client/src/com/vaadin/client/ui/grid/FlyweightCell.java205
-rw-r--r--client/src/com/vaadin/client/ui/grid/FlyweightRow.java217
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java1318
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridColumn.java54
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridConnector.java277
-rw-r--r--client/src/com/vaadin/client/ui/grid/PositionFunction.java118
-rw-r--r--client/src/com/vaadin/client/ui/grid/Renderer.java43
-rw-r--r--client/src/com/vaadin/client/ui/grid/Row.java55
-rw-r--r--client/src/com/vaadin/client/ui/grid/RowContainer.java156
-rw-r--r--client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java90
-rw-r--r--client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java38
-rw-r--r--client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java403
-rw-r--r--client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java357
-rw-r--r--client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java94
-rw-r--r--client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java42
-rw-r--r--client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java64
-rw-r--r--client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java33
-rw-r--r--client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java178
-rw-r--r--client/tests/src/com/vaadin/client/ui/grid/PartitioningTest.java104
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java148
-rw-r--r--server/src/com/vaadin/ui/components/grid/ColumnGroup.java165
-rw-r--r--server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java303
-rw-r--r--server/src/com/vaadin/ui/components/grid/Grid.java861
-rw-r--r--server/src/com/vaadin/ui/components/grid/GridColumn.java216
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java265
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java228
-rw-r--r--shared/src/com/vaadin/shared/data/DataProviderRpc.java61
-rw-r--r--shared/src/com/vaadin/shared/data/DataProviderState.java32
-rw-r--r--shared/src/com/vaadin/shared/data/DataRequestRpc.java38
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java46
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java45
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java53
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridColumnState.java55
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridConstants.java33
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java39
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridState.java64
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/Range.java378
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java55
-rw-r--r--shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java318
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html176
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java312
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java49
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java343
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java373
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java111
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridScrolling.java115
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java48
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java138
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java29
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java220
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java96
65 files changed, 0 insertions, 14682 deletions
diff --git a/WebContent/VAADIN/themes/base/base.scss b/WebContent/VAADIN/themes/base/base.scss
index 58274edacb..fd3c5d067d 100644
--- a/WebContent/VAADIN/themes/base/base.scss
+++ b/WebContent/VAADIN/themes/base/base.scss
@@ -15,10 +15,8 @@
@import "inlinedatefield/inlinedatefield.scss";
@import "dragwrapper/dragwrapper.scss";
@import "embedded/embedded.scss";
-@import "escalator/escalator.scss";
@import "fonts/fonts.scss";
@import "formlayout/formlayout.scss";
-@import "grid/grid.scss";
@import "gridlayout/gridlayout.scss";
@import "label/label.scss";
@import "link/link.scss";
@@ -92,9 +90,7 @@ $line-height: normal;
@include base-inline-datefield;
@include base-dragwrapper;
@include base-embedded;
- @include base-escalator;
@include base-formlayout;
- @include base-grid;
@include base-gridlayout;
@include base-label;
@include base-link;
diff --git a/WebContent/VAADIN/themes/base/escalator/escalator.scss b/WebContent/VAADIN/themes/base/escalator/escalator.scss
deleted file mode 100644
index 6f85a541ee..0000000000
--- a/WebContent/VAADIN/themes/base/escalator/escalator.scss
+++ /dev/null
@@ -1,117 +0,0 @@
-@mixin base-escalator($primaryStyleName : v-escalator) {
-
-$background-color: white;
-$border-color: #aaa;
-
-.#{$primaryStyleName} {
- position: relative;
- background-color: $background-color;
-}
-
-.#{$primaryStyleName}-scroller {
- position: absolute;
- overflow: auto;
- z-index: 20;
-}
-
-.#{$primaryStyleName}-scroller-horizontal {
- left: 0; /* Left position adjusted to align with frozen columns */
- right: 0;
- bottom: 0;
- overflow-y: hidden;
- -ms-overflow-y: hidden;
-}
-
-.#{$primaryStyleName}-scroller-vertical {
- right: 0;
- top: 0; /* this will be overridden by code, but it's a good default behavior */
- bottom: 0; /* this will be overridden by code, but it's a good default behavior */
- overflow-x: hidden;
- -ms-overflow-x: hidden;
-}
-
-.#{$primaryStyleName}-tablewrapper {
- position: absolute;
- overflow: hidden;
-}
-
-.#{$primaryStyleName}-tablewrapper > table {
- border-spacing: 0;
- table-layout: fixed;
- width: inherit; /* a decent default fallback */
-}
-
-.#{$primaryStyleName}-header,
-.#{$primaryStyleName}-body,
-.#{$primaryStyleName}-footer {
- position: absolute;
- left: 0;
- width: inherit;
- z-index: 10;
-}
-
-.#{$primaryStyleName}-header { top: 0; }
-.#{$primaryStyleName}-footer { bottom: 0; }
-
-.#{$primaryStyleName}-body {
- z-index: 0;
- top: 0;
-
- .#{$primaryStyleName}-row {
- position: absolute;
- top: 0;
- left: 0;
- }
-}
-
-.#{$primaryStyleName}-row {
- display: block;
-
- .v-ie8 & {
- /* IE8 doesn't let table rows be longer than body only with display block. Moar hax. */
- float: left;
- clear: left;
-
- /*
- * The inline style of margin-top from the <tbody> to offset the header's dimension is,
- * for some strange reason, inherited into each contained <tr>.
- * We need to cancel it:
- */
- margin-top: 0;
- }
-
- > td, > th {
- /* IE8 likes the bgcolor here instead of on the row */
- background-color: $background-color;
- }
-}
-
-
-.#{$primaryStyleName}-row {
- width: inherit;
-}
-
-.#{$primaryStyleName}-cell {
- display: block;
- float: left;
- border: 1px solid $border-color;
- padding: 2px;
- white-space: nowrap;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- overflow:hidden;
-
- /*
- * Because Vaadin changes the font size after the initial render, we
- * need to mention the font size here explicitly, otherwise automatic
- * row height detection gets broken.
- */
- font-size: $font-size;
-}
-
-.#{$primaryStyleName}-cell.frozen {
- position: relative;
- z-index: 0;
-}
-
-}
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss
deleted file mode 100644
index 9f7a2d8664..0000000000
--- a/WebContent/VAADIN/themes/base/grid/grid.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-@mixin base-grid($primaryStyleName : v-grid) {
- @include base-escalator($primaryStyleName);
-} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/reindeer-tests/styles.css b/WebContent/VAADIN/themes/reindeer-tests/styles.css
index 9dd88707d1..679de01b9c 100644
--- a/WebContent/VAADIN/themes/reindeer-tests/styles.css
+++ b/WebContent/VAADIN/themes/reindeer-tests/styles.css
@@ -32,7 +32,3 @@
.popup-style .v-datefield-calendarpanel-body {
background: yellow;
}
-
-#escalator .v-escalator-body .v-escalator-cell {
- height: 50px;
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
deleted file mode 100644
index 127eb80696..0000000000
--- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * 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.client.data;
-
-import java.util.HashMap;
-import java.util.List;
-
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.vaadin.client.Profiler;
-import com.vaadin.shared.ui.grid.Range;
-
-/**
- * Base implementation for data sources that fetch data from a remote system.
- * This class takes care of caching data and communicating with the data source
- * user. An implementation of this class should override
- * {@link #requestRows(int, int)} to trigger asynchronously loading of data.
- * When data is received from the server, new row data should be passed to
- * {@link #setRowData(int, List)}. {@link #setEstimatedSize(int)} should be used
- * based on estimations of how many rows are available.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @param <T>
- * the row type
- */
-public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
-
- private boolean requestPending = false;
-
- private boolean coverageCheckPending = false;
-
- private Range requestedAvailability = Range.between(0, 0);
-
- private Range cached = Range.between(0, 0);
-
- private final HashMap<Integer, T> rowCache = new HashMap<Integer, T>();
-
- private DataChangeHandler dataChangeHandler;
-
- private int estimatedSize;
-
- private final ScheduledCommand coverageChecker = new ScheduledCommand() {
- @Override
- public void execute() {
- coverageCheckPending = false;
- checkCacheCoverage();
- }
- };
-
- /**
- * Sets the estimated number of rows in the data source.
- *
- * @param estimatedSize
- * the estimated number of available rows
- */
- protected void setEstimatedSize(int estimatedSize) {
- // TODO update dataChangeHandler if size changes
- this.estimatedSize = estimatedSize;
- }
-
- private void ensureCoverageCheck() {
- if (!coverageCheckPending) {
- coverageCheckPending = true;
- Scheduler.get().scheduleDeferred(coverageChecker);
- }
- }
-
- @Override
- public void ensureAvailability(int firstRowIndex, int numberOfRows) {
- requestedAvailability = Range.withLength(firstRowIndex, numberOfRows);
-
- /*
- * Don't request any data right away since the data might be included in
- * a message that has been received but not yet fully processed.
- */
- ensureCoverageCheck();
- }
-
- private void checkCacheCoverage() {
- if (requestPending) {
- // Anyone clearing requestPending should run this method again
- return;
- }
-
- Profiler.enter("AbstractRemoteDataSource.checkCacheCoverage");
-
- if (!requestedAvailability.intersects(cached) || cached.isEmpty()) {
- /*
- * Simple case: no overlap between cached data and needed data.
- * Clear the cache and request new data
- */
- rowCache.clear();
- cached = Range.between(0, 0);
-
- handleMissingRows(requestedAvailability);
- } else {
- discardStaleCacheEntries();
-
- // Might need more rows -> request them
- Range[] availabilityPartition = requestedAvailability
- .partitionWith(cached);
- handleMissingRows(availabilityPartition[0]);
- handleMissingRows(availabilityPartition[2]);
- }
-
- Profiler.leave("AbstractRemoteDataSource.checkCacheCoverage");
- }
-
- private void discardStaleCacheEntries() {
- Range[] cacheParition = cached.partitionWith(requestedAvailability);
- dropFromCache(cacheParition[0]);
- cached = cacheParition[1];
- dropFromCache(cacheParition[2]);
- }
-
- private void dropFromCache(Range range) {
- for (int i = range.getStart(); i < range.getEnd(); i++) {
- rowCache.remove(Integer.valueOf(i));
- }
- }
-
- private void handleMissingRows(Range range) {
- if (range.isEmpty()) {
- return;
- }
- requestPending = true;
- requestRows(range.getStart(), range.length());
- }
-
- /**
- * Triggers fetching rows from the remote data source.
- * {@link #setRowData(int, List)} should be invoked with data for the
- * requested rows when they have been received.
- *
- * @param firstRowIndex
- * the index of the first row to fetch
- * @param numberOfRows
- * the number of rows to fetch
- */
- protected abstract void requestRows(int firstRowIndex, int numberOfRows);
-
- @Override
- public int getEstimatedSize() {
- return estimatedSize;
- }
-
- @Override
- public T getRow(int rowIndex) {
- return rowCache.get(Integer.valueOf(rowIndex));
- }
-
- @Override
- public void setDataChangeHandler(DataChangeHandler dataChangeHandler) {
- this.dataChangeHandler = dataChangeHandler;
-
- if (dataChangeHandler != null && !cached.isEmpty()) {
- // Push currently cached data to the implementation
- dataChangeHandler.dataUpdated(cached.getStart(), cached.length());
- }
- }
-
- /**
- * Informs this data source that updated data has been sent from the server.
- *
- * @param firstRowIndex
- * the index of the first received row
- * @param rowData
- * a list of rows, starting from <code>firstRowIndex</code>
- */
- protected void setRowData(int firstRowIndex, List<T> rowData) {
- requestPending = false;
-
- Profiler.enter("AbstractRemoteDataSource.setRowData");
-
- Range received = Range.withLength(firstRowIndex, rowData.size());
-
- Range[] partition = received.partitionWith(requestedAvailability);
-
- Range newUsefulData = partition[1];
- if (!newUsefulData.isEmpty()) {
- // Update the parts that are actually inside
- for (int i = newUsefulData.getStart(); i < newUsefulData.getEnd(); i++) {
- rowCache.put(Integer.valueOf(i), rowData.get(i - firstRowIndex));
- }
-
- if (dataChangeHandler != null) {
- Profiler.enter("AbstractRemoteDataSource.setRowData notify dataChangeHandler");
- dataChangeHandler.dataUpdated(newUsefulData.getStart(),
- newUsefulData.length());
- Profiler.leave("AbstractRemoteDataSource.setRowData notify dataChangeHandler");
- }
-
- // Potentially extend the range
- if (cached.isEmpty()) {
- cached = newUsefulData;
- } else {
- discardStaleCacheEntries();
-
- /*
- * everything might've become stale so we need to re-check for
- * emptiness.
- */
- if (!cached.isEmpty()) {
- cached = cached.combineWith(newUsefulData);
- } else {
- cached = newUsefulData;
- }
- }
- }
-
- if (!partition[0].isEmpty() || !partition[2].isEmpty()) {
- /*
- * FIXME
- *
- * Got data that we might need in a moment if the container is
- * updated before the widget settings. Support for this will be
- * implemented later on.
- */
- }
-
- // Eventually check whether all needed rows are now available
- ensureCoverageCheck();
-
- Profiler.leave("AbstractRemoteDataSource.setRowData");
- }
-
- /**
- * Informs this data source that the server has removed data.
- *
- * @param firstRowIndex
- * the index of the first removed row
- * @param count
- * the number of removed rows, starting from
- * <code>firstRowIndex</code>
- */
- protected void removeRowData(int firstRowIndex, int count) {
- Profiler.enter("AbstractRemoteDataSource.removeRowData");
-
- // pack the cached data
- for (int i = 0; i < count; i++) {
- Integer oldIndex = Integer.valueOf(firstRowIndex + count + i);
- if (rowCache.containsKey(oldIndex)) {
- Integer newIndex = Integer.valueOf(firstRowIndex + i);
- rowCache.put(newIndex, rowCache.remove(oldIndex));
- }
- }
-
- Range removedRange = Range.withLength(firstRowIndex, count);
- if (removedRange.intersects(cached)) {
- Range[] partitions = cached.partitionWith(removedRange);
- Range remainsBefore = partitions[0];
- Range transposedRemainsAfter = partitions[2].offsetBy(-removedRange
- .length());
- cached = remainsBefore.combineWith(transposedRemainsAfter);
- }
- estimatedSize -= count;
- dataChangeHandler.dataRemoved(firstRowIndex, count);
- checkCacheCoverage();
-
- Profiler.leave("AbstractRemoteDataSource.removeRowData");
- }
-
- /**
- * Informs this data source that new data has been inserted from the server.
- *
- * @param firstRowIndex
- * the destination index of the new row data
- * @param count
- * the number of rows inserted
- */
- protected void insertRowData(int firstRowIndex, int count) {
- Profiler.enter("AbstractRemoteDataSource.insertRowData");
-
- if (cached.contains(firstRowIndex)) {
- int oldCacheEnd = cached.getEnd();
- /*
- * We need to invalidate the cache from the inserted row onwards,
- * since the cache wants to be a contiguous range. It doesn't
- * support holes.
- *
- * If holes were supported, we could shift the higher part of
- * "cached" and leave a hole the size of "count" in the middle.
- */
- cached = cached.splitAt(firstRowIndex)[0];
-
- for (int i = firstRowIndex; i < oldCacheEnd; i++) {
- rowCache.remove(Integer.valueOf(i));
- }
- }
-
- else if (firstRowIndex < cached.getStart()) {
- Range oldCached = cached;
- cached = cached.offsetBy(count);
-
- for (int i = 0; i < rowCache.size(); i++) {
- Integer oldIndex = Integer.valueOf(oldCached.getEnd() - i);
- Integer newIndex = Integer.valueOf(cached.getEnd() - i);
- rowCache.put(newIndex, rowCache.remove(oldIndex));
- }
- }
-
- estimatedSize += count;
- dataChangeHandler.dataAdded(firstRowIndex, count);
- checkCacheCoverage();
-
- Profiler.leave("AbstractRemoteDataSource.insertRowData");
- }
-}
diff --git a/client/src/com/vaadin/client/data/DataChangeHandler.java b/client/src/com/vaadin/client/data/DataChangeHandler.java
deleted file mode 100644
index 4c4cc7656d..0000000000
--- a/client/src/com/vaadin/client/data/DataChangeHandler.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.client.data;
-
-/**
- * Callback interface used by {@link DataSource} to inform its user about
- * updates to the data.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface DataChangeHandler {
- /**
- * Called when the contents of the data source has changed. If the number of
- * rows has changed or if rows have been moved around,
- * {@link #dataAdded(int, int)} or {@link #dataRemoved(int, int)} should
- * ideally be used instead.
- *
- * @param firstRowIndex
- * the index of the first changed row
- * @param numberOfRows
- * the number of changed rows
- */
- public void dataUpdated(int firstRowIndex, int numberOfRows);
-
- /**
- * Called when rows have been removed from the data source.
- *
- * @param firstRowIndex
- * the index that the first removed row had prior to removal
- * @param numberOfRows
- * the number of removed rows
- */
- public void dataRemoved(int firstRowIndex, int numberOfRows);
-
- /**
- * Called when the new rows have been added to the container.
- *
- * @param firstRowIndex
- * the index of the first added row
- * @param numberOfRows
- * the number of added rows
- */
- public void dataAdded(int firstRowIndex, int numberOfRows);
-}
diff --git a/client/src/com/vaadin/client/data/DataSource.java b/client/src/com/vaadin/client/data/DataSource.java
deleted file mode 100644
index 9179b6d03d..0000000000
--- a/client/src/com/vaadin/client/data/DataSource.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.client.data;
-
-/**
- * Source of data for widgets showing lazily loaded data based on indexable
- * items (e.g. rows) of a specified type. The data source is a lazy view into a
- * larger data set.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @param <T>
- * the row type
- */
-public interface DataSource<T> {
- /**
- * Informs the data source that data for the given range is needed. A data
- * source only has one active region at a time, so calling this method
- * discards the previously set range.
- * <p>
- * This method triggers lazy loading of data if necessary. The change
- * handler registered using {@link #setDataChangeHandler(DataChangeHandler)}
- * is informed when new data has been loaded.
- *
- * @param firstRowIndex
- * the index of the first needed row
- * @param numberOfRows
- * the number of needed rows
- */
- public void ensureAvailability(int firstRowIndex, int numberOfRows);
-
- /**
- * Retrieves the data for the row at the given index. If the row data is not
- * available, returns <code>null</code>.
- * <p>
- * This method does not trigger loading of unavailable data.
- * {@link #ensureAvailability(int, int)} should be used to signal what data
- * will be needed.
- *
- * @param rowIndex
- * the index of the row to retrieve data for
- * @return data for the row; or <code>null</code> if no data is available
- */
- public T getRow(int rowIndex);
-
- /**
- * Returns the current best guess for the number of rows in the container.
- *
- * @return the current estimation of the container size
- */
- public int getEstimatedSize();
-
- /**
- * Sets a data change handler to inform when data is updated, added or
- * removed.
- *
- * @param dataChangeHandler
- * the data change handler
- */
- public void setDataChangeHandler(DataChangeHandler dataChangeHandler);
-
-}
diff --git a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java
deleted file mode 100644
index 4d22c10197..0000000000
--- a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.client.data;
-
-import java.util.List;
-
-import com.vaadin.client.ServerConnector;
-import com.vaadin.client.extensions.AbstractExtensionConnector;
-import com.vaadin.client.ui.grid.GridConnector;
-import com.vaadin.shared.data.DataProviderRpc;
-import com.vaadin.shared.data.DataProviderState;
-import com.vaadin.shared.data.DataRequestRpc;
-import com.vaadin.shared.ui.Connect;
-
-/**
- * Connects a Vaadin server-side container data source to a Grid. This is
- * currently implemented as an Extension hardcoded to support a specific
- * connector type. This will be changed once framework support for something
- * more flexible has been implemented.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-@Connect(com.vaadin.data.RpcDataProviderExtension.class)
-public class RpcDataSourceConnector extends AbstractExtensionConnector {
-
- private final AbstractRemoteDataSource<String[]> dataSource = new AbstractRemoteDataSource<String[]>() {
- @Override
- protected void requestRows(int firstRowIndex, int numberOfRows) {
- getRpcProxy(DataRequestRpc.class).requestRows(firstRowIndex,
- numberOfRows);
- }
- };
-
- @Override
- protected void extend(ServerConnector target) {
- dataSource.setEstimatedSize(getState().containerSize);
- ((GridConnector) target).getWidget().setDataSource(dataSource);
-
- registerRpc(DataProviderRpc.class, new DataProviderRpc() {
- @Override
- public void setRowData(int firstRow, List<String[]> rows) {
- dataSource.setRowData(firstRow, rows);
- }
-
- @Override
- public void removeRowData(int firstRow, int count) {
- dataSource.removeRowData(firstRow, count);
- }
-
- @Override
- public void insertRowData(int firstRow, int count) {
- dataSource.insertRowData(firstRow, count);
- }
- });
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.client.ui.AbstractConnector#getState()
- */
- @Override
- public DataProviderState getState() {
- return (DataProviderState) super.getState();
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/Cell.java b/client/src/com/vaadin/client/ui/grid/Cell.java
deleted file mode 100644
index 3d42f082a6..0000000000
--- a/client/src/com/vaadin/client/ui/grid/Cell.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.ui.HasOneWidget;
-
-/**
- * A representation of a single cell.
- * <p>
- * A Cell instance will be provided to the {@link EscalatorUpdater} responsible
- * for rendering the cells in a certain {@link RowContainer}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface Cell extends HasOneWidget {
-
- /**
- * Gets the index of the row this cell is in.
- *
- * @return the index of the row this cell is in
- */
- public int getRow();
-
- /**
- * Gets the index of the column this cell is in.
- *
- * @return the index of the column this cell is in
- */
- public int getColumn();
-
- /**
- * Gets the root element for this cell. The {@link EscalatorUpdater} may
- * update the class names of the element, add inline styles and freely
- * modify the contents.
- * <p>
- * Avoid modifying the dimensions, positioning or colspan of the cell
- * element.
- *
- * @return The root element for this cell. Never <code>null</code>.
- */
- public Element getElement();
-
- /**
- * Sets the column span of the cell.
- * <p>
- * This will overwrite any possible "colspan" attribute in the current
- * element (i.e. the object returned by {@link #getElement()}). This will
- * also handle internal bookkeeping, skip the rendering of any affected
- * adjacent cells, and make sure that the current cell's dimensions are
- * handled correctly.
- *
- * @param numberOfCells
- * the number of cells to span to the right, or <code>1</code> to
- * unset any column spans
- * @throws IllegalArgumentException
- * if <code>numberOfCells &lt; 1</code>
- */
- public void setColSpan(int numberOfCells) throws IllegalArgumentException;
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java b/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java
deleted file mode 100644
index 64104164cd..0000000000
--- a/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-/**
- * A representation of the columns in an instance of {@link Escalator}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see Escalator#getColumnConfiguration()
- */
-public interface ColumnConfiguration {
-
- /**
- * Removes columns at a certain index.
- * <p>
- * If any of the removed columns were frozen, the number of frozen columns
- * will be reduced by the number of the removed columns that were frozen.
- *
- * @param index
- * the index of the first column to be removed
- * @param numberOfColumns
- * the number of rows to remove, starting from the index
- * @throws IndexOutOfBoundsException
- * if any integer in the range
- * <code>[index..(index+numberOfColumns)]</code> is not an
- * existing column index.
- * @throws IllegalArgumentException
- * if <code>numberOfColumns</code> is less than 1.
- */
- public void removeColumns(int index, int numberOfColumns)
- throws IndexOutOfBoundsException, IllegalArgumentException;
-
- /**
- * Adds columns at a certain index.
- * <p>
- * The new columns will be inserted between the column at the index, and the
- * column before (an index of 0 means that the columns are inserted at the
- * beginning). Therefore, the columns at the index and afterwards will be
- * moved to the right.
- * <p>
- * The contents of the inserted columns will be queried from the respective
- * cell renderers in the header, body and footer.
- * <p>
- * If there are frozen columns and the first added column is to the left of
- * the last frozen column, the number of frozen columns will be increased by
- * the number of inserted columns.
- * <p>
- * <em>Note:</em> Only the contents of the inserted columns will be
- * rendered. If inserting new columns affects the contents of existing
- * columns, {@link RowContainer#refreshRows(int, int)} needs to be called as
- * appropriate.
- *
- * @param index
- * the index of the column before which new columns are inserted,
- * or {@link #getColumnCount()} to add new columns at the end
- * @param numberOfColumns
- * the number of columns to insert after the <code>index</code>
- * @throws IndexOutOfBoundsException
- * if <code>index</code> is not an integer in the range
- * <code>[0..{@link #getColumnCount()}]</code>
- * @throws IllegalArgumentException
- * if {@code numberOfColumns} is less than 1.
- */
- public void insertColumns(int index, int numberOfColumns)
- throws IndexOutOfBoundsException, IllegalArgumentException;
-
- /**
- * Returns the number of columns in the escalator.
- *
- * @return the number of columns in the escalator
- */
- public int getColumnCount();
-
- /**
- * Sets the number of leftmost columns that are not affected by horizontal
- * scrolling.
- *
- * @param count
- * the number of columns to freeze
- *
- * @throws IllegalArgumentException
- * if the column count is &lt; 0 or &gt; the number of columns
- *
- */
- public void setFrozenColumnCount(int count) throws IllegalArgumentException;
-
- /**
- * Get the number of leftmost columns that are not affected by horizontal
- * scrolling.
- *
- * @return the number of frozen columns
- */
- public int getFrozenColumnCount();
-
- /**
- * Sets (or unsets) an explicit width for a column.
- *
- * @param index
- * the index of the column for which to set a width
- * @param px
- * the number of pixels the indicated column should be, or a
- * negative number to let the escalator decide
- * @throws IllegalArgumentException
- * if <code>index</code> is not a valid column index
- */
- public void setColumnWidth(int index, int px)
- throws IllegalArgumentException;
-
- /**
- * Returns the user-defined width of a column.
- *
- * @param index
- * the index of the column for which to retrieve the width
- * @return the column's width in pixels, or a negative number if the width
- * is implicitly decided by the escalator
- * @throws IllegalArgumentException
- * if <code>index</code> is not a valid column index
- */
- public int getColumnWidth(int index) throws IllegalArgumentException;
-
- /**
- * Returns the actual width of a column.
- *
- * @param index
- * the index of the column for which to retrieve the width
- * @return the column's actual width in pixels
- * @throws IllegalArgumentException
- * if <code>index</code> is not a valid column index
- */
- public int getColumnWidthActual(int index) throws IllegalArgumentException;
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java
deleted file mode 100644
index e48656bc6b..0000000000
--- a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import com.vaadin.client.ui.grid.renderers.TextRenderer;
-
-/**
- * Column groups are used to group columns together for adding common auxiliary
- * headers and footers. Columns groups are added to {@link ColumnGroupRow
- * ColumnGroupRows}.
- *
- * @param <T>
- * The row type of the grid. The row type is the POJO type from where
- * the data is retrieved into the column cells.
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ColumnGroup<T> {
-
- /**
- * The text shown in the header
- */
- private String header;
-
- /**
- * The text shown in the footer
- */
- private String footer;
-
- /**
- * Renders the header cells for the column group
- */
- private Renderer<String> headerRenderer = new TextRenderer();
-
- /**
- * Renders the footer cells for the column group
- */
- private Renderer<String> footerRenderer = new TextRenderer();
-
- /**
- * The columns included in the group when also accounting for subgroup
- * columns
- */
- private final List<GridColumn<?, T>> columns;
-
- /**
- * The grid associated with the column group
- */
- private final Grid<T> grid;
-
- /**
- * Constructs a new column group
- */
- ColumnGroup(Grid<T> grid, Collection<GridColumn<?, T>> columns) {
- if (columns == null) {
- throw new IllegalArgumentException(
- "columns cannot be null. Pass an empty list instead.");
- }
- this.grid = grid;
- this.columns = Collections
- .unmodifiableList(new ArrayList<GridColumn<?, T>>(columns));
- }
-
- /**
- * Gets the header text.
- *
- * @return the header text
- */
- public String getHeaderCaption() {
- return header;
- }
-
- /**
- * Sets the text shown in the header.
- *
- * @param header
- * the header to set
- */
- public void setHeaderCaption(String header) {
- this.header = header;
- grid.refreshHeader();
- }
-
- /**
- * Gets the text shown in the footer.
- *
- * @return the text in the footer
- */
- public String getFooterCaption() {
- return footer;
- }
-
- /**
- * Sets the text displayed in the footer.
- *
- * @param footer
- * the footer to set
- */
- public void setFooterCaption(String footer) {
- this.footer = footer;
- grid.refreshFooter();
- }
-
- /**
- * Returns all column in this group. It includes the subgroups columns as
- * well.
- *
- * @return unmodifiable list of columns
- */
- public List<GridColumn<?, T>> getColumns() {
- return columns;
- }
-
- /**
- * Returns the renderer used for rendering the header cells
- *
- * @return a renderer that renders header cells
- */
- public Renderer<String> getHeaderRenderer() {
- return headerRenderer;
- }
-
- /**
- * Sets the renderer that renders header cells.
- *
- * @param renderer
- * The renderer to use for rendering header cells. Must not be
- * null.
- * @throws IllegalArgumentException
- * thrown when renderer is null
- */
- public void setHeaderRenderer(Renderer<String> renderer) {
- if (renderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
- this.headerRenderer = renderer;
- grid.refreshHeader();
- }
-
- /**
- * Returns the renderer used for rendering the footer cells
- *
- * @return a renderer that renders footer cells
- */
- public Renderer<String> getFooterRenderer() {
- return footerRenderer;
- }
-
- /**
- * Sets the renderer that renders footer cells.
- *
- * @param renderer
- * The renderer to use for rendering footer cells. Must not be
- * null.
- * @throws IllegalArgumentException
- * thrown when renderer is null
- */
- public void setFooterRenderer(Renderer<String> renderer) {
- if (renderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
- this.footerRenderer = renderer;
- grid.refreshFooter();
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java
deleted file mode 100644
index ebe4db508c..0000000000
--- a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A column group row represents an auxiliary header or footer row added to the
- * grid. A column group row includes column groups that group columns together.
- *
- * @param <T>
- * Row type
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ColumnGroupRow<T> {
-
- /**
- * The column groups in this row
- */
- private List<ColumnGroup<T>> groups = new ArrayList<ColumnGroup<T>>();
-
- /**
- * The grid associated with the column row
- */
- private final Grid<T> grid;
-
- /**
- * Is the header shown
- */
- private boolean headerVisible = true;
-
- /**
- * Is the footer shown
- */
- private boolean footerVisible = false;
-
- /**
- * Constructs a new column group row
- *
- * @param grid
- * Grid associated with this column
- *
- */
- ColumnGroupRow(Grid<T> grid) {
- this.grid = grid;
- }
-
- /**
- * Add a new group to the row by using column instances.
- *
- * @param columns
- * The columns that should belong to the group
- * @return a column group representing the collection of columns added to
- * the group.
- */
- public ColumnGroup<T> addGroup(GridColumn<?, T>... columns)
- throws IllegalArgumentException {
-
- for (GridColumn<?, T> column : columns) {
- if (isColumnGrouped(column)) {
- throw new IllegalArgumentException("Column "
- + String.valueOf(column.getHeaderCaption())
- + " already belongs to another group.");
- }
- }
-
- validateNewGroupProperties(Arrays.asList(columns));
-
- ColumnGroup<T> group = new ColumnGroup<T>(grid, Arrays.asList(columns));
- groups.add(group);
- grid.refreshHeader();
- grid.refreshFooter();
- return group;
- }
-
- private void validateNewGroupProperties(Collection<GridColumn<?, T>> columns) {
-
- int rowIndex = grid.getColumnGroupRows().indexOf(this);
- int parentRowIndex = rowIndex - 1;
-
- // Get the parent row of this row.
- ColumnGroupRow<T> parentRow = null;
- if (parentRowIndex > -1) {
- parentRow = grid.getColumnGroupRows().get(parentRowIndex);
- }
-
- if (parentRow == null) {
- // A parentless row is always valid and is usually the first row
- // added to the grid
- return;
- }
-
- for (GridColumn<?, T> column : columns) {
- if (parentRow.hasColumnBeenGrouped(column)) {
- /*
- * If a property has been grouped in the parent row then all of
- * the properties in the parent group also needs to be included
- * in the child group for the groups to be valid
- */
- ColumnGroup parentGroup = parentRow.getGroupForColumn(column);
- if (!columns.containsAll(parentGroup.getColumns())) {
- throw new IllegalArgumentException(
- "Grouped properties overlaps previous grouping bounderies");
- }
- }
- }
- }
-
- private boolean hasColumnBeenGrouped(GridColumn<?, T> column) {
- return getGroupForColumn(column) != null;
- }
-
- private ColumnGroup<T> getGroupForColumn(GridColumn<?, T> column) {
- for (ColumnGroup<T> group : groups) {
- if (group.getColumns().contains(column)) {
- return group;
- }
- }
- return null;
- }
-
- /**
- * Add a new group to the row by using other already greated groups
- *
- * @param groups
- * The subgroups of the group.
- * @return a column group representing the collection of columns added to
- * the group.
- *
- */
- public ColumnGroup<T> addGroup(ColumnGroup<T>... groups)
- throws IllegalArgumentException {
- assert groups != null : "groups cannot be null";
-
- Set<GridColumn<?, T>> columns = new HashSet<GridColumn<?, T>>();
- for (ColumnGroup<T> group : groups) {
- columns.addAll(group.getColumns());
- }
-
- validateNewGroupProperties(columns);
-
- ColumnGroup<T> group = new ColumnGroup<T>(grid, columns);
- this.groups.add(group);
- grid.refreshHeader();
- grid.refreshFooter();
- return group;
- }
-
- /**
- * Removes a group from the row.
- *
- * @param group
- * The group to remove
- */
- public void removeGroup(ColumnGroup<T> group) {
- groups.remove(group);
- grid.refreshHeader();
- grid.refreshFooter();
- }
-
- /**
- * Get the groups in the row
- *
- * @return unmodifiable list of groups in this row
- */
- public List<ColumnGroup<T>> getGroups() {
- return Collections.unmodifiableList(groups);
- }
-
- /**
- * Is the header visible for the row.
- *
- * @return <code>true</code> if header is visible
- */
- public boolean isHeaderVisible() {
- return headerVisible;
- }
-
- /**
- * Sets the header visible for the row.
- *
- * @param visible
- * should the header be shown
- */
- public void setHeaderVisible(boolean visible) {
- headerVisible = visible;
- grid.refreshHeader();
- }
-
- /**
- * Is the footer visible for the row.
- *
- * @return <code>true</code> if footer is visible
- */
- public boolean isFooterVisible() {
- return footerVisible;
- }
-
- /**
- * Sets the footer visible for the row.
- *
- * @param visible
- * should the footer be shown
- */
- public void setFooterVisible(boolean visible) {
- footerVisible = visible;
- grid.refreshFooter();
- }
-
- /**
- * Iterates all the column groups and checks if the columns alread has been
- * added to a group.
- */
- private boolean isColumnGrouped(GridColumn<?, T> column) {
- for (ColumnGroup<T> group : groups) {
- if (group.getColumns().contains(column)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java
deleted file mode 100644
index 6112d6b139..0000000000
--- a/client/src/com/vaadin/client/ui/grid/Escalator.java
+++ /dev/null
@@ -1,4042 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.google.gwt.animation.client.AnimationScheduler;
-import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
-import com.google.gwt.animation.client.AnimationScheduler.AnimationHandle;
-import com.google.gwt.core.client.Duration;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.logging.client.LogConfiguration;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.client.Profiler;
-import com.vaadin.client.Util;
-import com.vaadin.client.ui.grid.Escalator.JsniUtil.TouchHandlerBundle;
-import com.vaadin.client.ui.grid.PositionFunction.AbsolutePosition;
-import com.vaadin.client.ui.grid.PositionFunction.Translate3DPosition;
-import com.vaadin.client.ui.grid.PositionFunction.TranslatePosition;
-import com.vaadin.client.ui.grid.PositionFunction.WebkitTranslate3DPosition;
-import com.vaadin.client.ui.grid.ScrollbarBundle.HorizontalScrollbarBundle;
-import com.vaadin.client.ui.grid.ScrollbarBundle.VerticalScrollbarBundle;
-import com.vaadin.shared.ui.grid.Range;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-import com.vaadin.shared.util.SharedUtil;
-
-/*-
-
- Maintenance Notes! Reading these might save your day.
-
-
- == Row Container Structure
-
- AbstractRowContainer
- |-- AbstractStaticRowContainer
- | |-- HeaderRowContainer
- | `-- FooterContainer
- `-- BodyRowContainer
-
- AbstractRowContainer is intended to contain all common logic
- between RowContainers. It manages the bookkeeping of row
- count, makes sure that all individual cells are rendered
- the same way, and so on.
-
- AbstractStaticRowContainer has some special logic that is
- required by all RowContainers that don't scroll (hence the
- word "static"). HeaderRowContainer and FooterRowContainer
- are pretty thin special cases of a StaticRowContainer
- (mostly relating to positioning of the root element).
-
- BodyRowContainer could also be split into an additional
- "AbstractScrollingRowContainer", but I felt that no more
- inner classes were needed. So it contains both logic
- required for making things scroll about, and equivalent
- special cases for layouting, as are found in
- Header/FooterRowContainers.
-
-
- == The Three Indices
-
- Each RowContainer can be thought to have three levels of
- indices for any given displayed row (but the distinction
- matters primarily for the BodyRowContainer, because of the
- way it scrolls through data):
-
- - Logical index
- - Physical (or DOM) index
- - Visual index
-
- LOGICAL INDEX is the index that is linked to the data
- source. If you want your data source to represent a SQL
- database with 10 000 rows, the 7 000:th row in the SQL has a
- logical index of 6 999, since the index is 0-based (unless
- that data source does some funky logic).
-
- PHYSICAL INDEX is the index for a row that you see in a
- browser's DOM inspector. If your row is the second <tr>
- element within a <tbody> tag, it has a physical index of 1
- (because of 0-based indices). In Header and
- FooterRowContainers, you are safe to assume that the logical
- index is the same as the physical index. But because the
- BodyRowContainer never displays large data sources entirely
- in the DOM, a physical index usually has no apparent direct
- relationship with its logical index.
-
- VISUAL INDEX is the index relating to the order that you
- see a row in, in the browser, as it is rendered. The
- topmost row is 0, the second is 1, and so on. The visual
- index is similar to the physical index in the sense that
- Header and FooterRowContainers can assume a 1:1
- relationship between visual index and logical index. And
- again, BodyRowContainer has no such relationship. The
- body's visual index has additionally no apparent
- relationship with its physical index. Because the <tr> tags
- are reused in the body and visually repositioned with CSS
- as the user scrolls, the relationship between physical
- index and visual index is quickly broken. You can get an
- element's visual index via the field
- BodyRowContainer.visualRowOrder.
-
- */
-
-/**
- * A workaround-class for GWT and JSNI.
- * <p>
- * GWT is unable to handle some method calls to Java methods in inner-classes
- * from within JSNI blocks. Having that inner class implement a non-inner-class
- * (or interface), makes it possible for JSNI to indirectly refer to the inner
- * class, by invoking methods and fields in the non-inner-class.
- *
- * @see Escalator.Scroller
- */
-abstract class JsniWorkaround {
- /**
- * A JavaScript function that handles the scroll DOM event, and passes it on
- * to Java code.
- *
- * @see #createScrollListenerFunction(Escalator)
- * @see Escalator#onScroll(double,double)
- * @see Escalator.Scroller#onScroll(double, double)
- */
- protected final JavaScriptObject scrollListenerFunction;
-
- /**
- * A JavaScript function that handles the mousewheel DOM event, and passes
- * it on to Java code.
- *
- * @see #createMousewheelListenerFunction(Escalator)
- * @see Escalator#onScroll(double,double)
- * @see Escalator.Scroller#onScroll(double, double)
- */
- protected final JavaScriptObject mousewheelListenerFunction;
-
- /**
- * A JavaScript function that handles the touch start DOM event, and passes
- * it on to Java code.
- *
- * @see TouchHandlerBundle#touchStart(Escalator.JsniUtil.TouchHandlerBundle.CustomTouchEvent)
- */
- protected JavaScriptObject touchStartFunction;
-
- /**
- * A JavaScript function that handles the touch move DOM event, and passes
- * it on to Java code.
- *
- * @see TouchHandlerBundle#touchMove(Escalator.JsniUtil.TouchHandlerBundle.CustomTouchEvent)
- */
- protected JavaScriptObject touchMoveFunction;
-
- /**
- * A JavaScript function that handles the touch end and cancel DOM events,
- * and passes them on to Java code.
- *
- * @see TouchHandlerBundle#touchEnd(Escalator.JsniUtil.TouchHandlerBundle.CustomTouchEvent)
- */
- protected JavaScriptObject touchEndFunction;
-
- protected JsniWorkaround(final Escalator escalator) {
- scrollListenerFunction = createScrollListenerFunction(escalator);
- mousewheelListenerFunction = createMousewheelListenerFunction(escalator);
-
- final TouchHandlerBundle bundle = new TouchHandlerBundle(escalator);
- touchStartFunction = bundle.getTouchStartHandler();
- touchMoveFunction = bundle.getTouchMoveHandler();
- touchEndFunction = bundle.getTouchEndHandler();
- }
-
- /**
- * A method that constructs the JavaScript function that will be stored into
- * {@link #scrollListenerFunction}.
- *
- * @param esc
- * a reference to the current instance of {@link Escalator}
- * @see Escalator#onScroll(double,double)
- */
- protected abstract JavaScriptObject createScrollListenerFunction(
- Escalator esc);
-
- /**
- * A method that constructs the JavaScript function that will be stored into
- * {@link #mousewheelListenerFunction}.
- *
- * @param esc
- * a reference to the current instance of {@link Escalator}
- * @see Escalator#onScroll(double,double)
- */
- protected abstract JavaScriptObject createMousewheelListenerFunction(
- Escalator esc);
-}
-
-/**
- * A low-level table-like widget that features a scrolling virtual viewport and
- * lazily generated rows.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class Escalator extends Widget {
-
- // todo comments legend
- /*
- * [[optimize]]: There's an opportunity to rewrite the code in such a way
- * that it _might_ perform better (rememeber to measure, implement,
- * re-measure)
- */
- /*
- * [[rowheight]]: This code will require alterations that are relevant for
- * being able to support variable row heights. NOTE: these bits can most
- * often also be identified by searching for code reading the ROW_HEIGHT_PX
- * constant.
- */
- /*
- * [[API]]: Implementing this suggestion would require a change in the
- * public API. These suggestions usually don't come lightly.
- */
- /*
- * [[mpixscroll]]: This code will require alterations that are relevant for
- * supporting the scrolling through more pixels than some browsers normally
- * would support. (i.e. when we support more than "a million" pixels in the
- * escalator DOM). NOTE: these bits can most often also be identified by
- * searching for code that call scrollElem.getScrollTop();.
- */
-
- /**
- * A utility class that contains utility methods that are usually called
- * from JSNI.
- * <p>
- * The methods are moved in this class to minimize the amount of JSNI code
- * as much as feasible.
- */
- static class JsniUtil {
- public static class TouchHandlerBundle {
-
- /**
- * A <a href=
- * "http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsOverlay.html"
- * >JavaScriptObject overlay</a> for the <a
- * href="http://www.w3.org/TR/touch-events/">JavaScript
- * TouchEvent</a> object.
- * <p>
- * This needs to be used in the touch event handlers, since GWT's
- * {@link com.google.gwt.event.dom.client.TouchEvent TouchEvent}
- * can't be cast from the JSNI call, and the
- * {@link com.google.gwt.dom.client.NativeEvent NativeEvent} isn't
- * properly populated with the correct values.
- */
- private final static class CustomTouchEvent extends
- JavaScriptObject {
- protected CustomTouchEvent() {
- }
-
- public native NativeEvent getNativeEvent()
- /*-{
- return this;
- }-*/;
-
- public native int getPageX()
- /*-{
- return this.targetTouches[0].pageX;
- }-*/;
-
- public native int getPageY()
- /*-{
- return this.targetTouches[0].pageY;
- }-*/;
- }
-
- private double touches = 0;
- private int lastX = 0;
- private int lastY = 0;
- private double lastTime = 0;
- private boolean snappedScrollEnabled = true;
- private double deltaX = 0;
- private double deltaY = 0;
-
- private final Escalator escalator;
- private CustomTouchEvent latestTouchMoveEvent;
- private AnimationCallback mover = new AnimationCallback() {
- @Override
- public void execute(double timestamp) {
- if (touches != 1) {
- return;
- }
-
- final int x = latestTouchMoveEvent.getPageX();
- final int y = latestTouchMoveEvent.getPageY();
- deltaX = x - lastX;
- deltaY = y - lastY;
- lastX = x;
- lastY = y;
- lastTime = Duration.currentTimeMillis();
-
- // snap the scroll to the major axes, at first.
- if (snappedScrollEnabled) {
- final double oldDeltaX = deltaX;
- final double oldDeltaY = deltaY;
-
- /*
- * Scrolling snaps to 40 degrees vs. flick scroll's 30
- * degrees, since slow movements have poor resolution -
- * it's easy to interpret a slight angle as a steep
- * angle, since the sample rate is "unnecessarily" high.
- * 40 simply felt better than 30.
- */
- final double[] snapped = Escalator.snapDeltas(deltaX,
- deltaY, RATIO_OF_40_DEGREES);
- deltaX = snapped[0];
- deltaY = snapped[1];
-
- /*
- * if the snap failed once, let's follow the pointer
- * from now on.
- */
- if (oldDeltaX != 0 && deltaX == oldDeltaX
- && oldDeltaY != 0 && deltaY == oldDeltaY) {
- snappedScrollEnabled = false;
- }
- }
-
- moveScrollFromEvent(escalator, -deltaX, -deltaY,
- latestTouchMoveEvent.getNativeEvent());
- }
- };
- private AnimationHandle animationHandle;
-
- public TouchHandlerBundle(final Escalator escalator) {
- this.escalator = escalator;
- }
-
- public native JavaScriptObject getTouchStartHandler()
- /*-{
- // we need to store "this", since it won't be preserved on call.
- var self = this;
- return $entry(function (e) {
- self.@com.vaadin.client.ui.grid.Escalator.JsniUtil.TouchHandlerBundle::touchStart(*)(e);
- });
- }-*/;
-
- public native JavaScriptObject getTouchMoveHandler()
- /*-{
- // we need to store "this", since it won't be preserved on call.
- var self = this;
- return $entry(function (e) {
- self.@com.vaadin.client.ui.grid.Escalator.JsniUtil.TouchHandlerBundle::touchMove(*)(e);
- });
- }-*/;
-
- public native JavaScriptObject getTouchEndHandler()
- /*-{
- // we need to store "this", since it won't be preserved on call.
- var self = this;
- return $entry(function (e) {
- self.@com.vaadin.client.ui.grid.Escalator.JsniUtil.TouchHandlerBundle::touchEnd(*)(e);
- });
- }-*/;
-
- public void touchStart(final CustomTouchEvent event) {
- touches++;
- if (touches != 1) {
- return;
- }
-
- escalator.scroller.cancelFlickScroll();
-
- lastX = event.getPageX();
- lastY = event.getPageY();
-
- snappedScrollEnabled = true;
- }
-
- public void touchMove(final CustomTouchEvent event) {
- /*
- * since we only use the getPageX/Y, and calculate the diff
- * within the handler, we don't need to calculate any
- * intermediate deltas.
- */
- latestTouchMoveEvent = event;
-
- if (animationHandle != null) {
- animationHandle.cancel();
- }
- animationHandle = AnimationScheduler.get()
- .requestAnimationFrame(mover, escalator.bodyElem);
- event.getNativeEvent().preventDefault();
- }
-
- public void touchEnd(@SuppressWarnings("unused")
- final CustomTouchEvent event) {
- touches--;
-
- if (touches == 0) {
- escalator.scroller.handleFlickScroll(deltaX, deltaY,
- lastTime);
- }
- }
- }
-
- public static void moveScrollFromEvent(final Escalator escalator,
- final double deltaX, final double deltaY,
- final NativeEvent event) {
-
- if (!Double.isNaN(deltaX)) {
- escalator.horizontalScrollbar.setScrollPosByDelta((int) deltaX);
- }
-
- if (!Double.isNaN(deltaY)) {
- escalator.verticalScrollbar.setScrollPosByDelta((int) deltaY);
- }
-
- /*
- * TODO: only prevent if not scrolled to end/bottom. Or no? UX team
- * needs to decide.
- */
- final boolean warrantedYScroll = deltaY != 0
- && escalator.verticalScrollbar.showsScrollHandle();
- final boolean warrantedXScroll = deltaX != 0
- && escalator.horizontalScrollbar.showsScrollHandle();
- if (warrantedYScroll || warrantedXScroll) {
- event.preventDefault();
- }
- }
- }
-
- /**
- * The animation callback that handles the animation of a touch-scrolling
- * flick with inertia.
- */
- private class FlickScrollAnimator implements AnimationCallback {
- private static final double MIN_MAGNITUDE = 0.005;
- private static final double MAX_SPEED = 7;
-
- private double velX;
- private double velY;
- private double prevTime = 0;
- private int millisLeft;
- private double xFric;
- private double yFric;
-
- private boolean cancelled = false;
- private int lastLeft;
- private int lastTop;
-
- /**
- * Creates a new animation callback to handle touch-scrolling flick with
- * inertia.
- *
- * @param deltaX
- * the last scrolling delta in the x-axis in a touchmove
- * @param deltaY
- * the last scrolling delta in the y-axis in a touchmove
- * @param lastTime
- * the timestamp of the last touchmove
- */
- public FlickScrollAnimator(final double deltaX, final double deltaY,
- final double lastTime) {
- final double currentTimeMillis = Duration.currentTimeMillis();
- velX = Math.max(Math.min(deltaX / (currentTimeMillis - lastTime),
- MAX_SPEED), -MAX_SPEED);
- velY = Math.max(Math.min(deltaY / (currentTimeMillis - lastTime),
- MAX_SPEED), -MAX_SPEED);
-
- lastLeft = horizontalScrollbar.getScrollPos();
- lastTop = verticalScrollbar.getScrollPos();
-
- /*
- * If we're scrolling mainly in one of the four major directions,
- * and only a teeny bit to any other side, snap the scroll to that
- * major direction instead.
- */
- final double[] snapDeltas = Escalator.snapDeltas(velX, velY,
- RATIO_OF_30_DEGREES);
- velX = snapDeltas[0];
- velY = snapDeltas[1];
-
- if (velX * velX + velY * velY > MIN_MAGNITUDE) {
- millisLeft = 1500;
- xFric = velX / millisLeft;
- yFric = velY / millisLeft;
- } else {
- millisLeft = 0;
- }
-
- }
-
- @Override
- public void execute(final double timestamp) {
- if (millisLeft <= 0 || cancelled) {
- scroller.currentFlickScroller = null;
- return;
- }
-
- if (prevTime == 0) {
- prevTime = timestamp;
- AnimationScheduler.get().requestAnimationFrame(this);
- return;
- }
-
- int currentLeft = horizontalScrollbar.getScrollPos();
- int currentTop = verticalScrollbar.getScrollPos();
-
- final double timeDiff = timestamp - prevTime;
- double left = currentLeft - velX * timeDiff;
- setScrollLeft((int) left);
- velX -= xFric * timeDiff;
-
- double top = currentTop - velY * timeDiff;
- setScrollTop(top);
- velY -= yFric * timeDiff;
-
- cancelBecauseOfEdgeOrCornerMaybe();
-
- prevTime = timestamp;
- millisLeft -= timeDiff;
- lastLeft = currentLeft;
- lastTop = currentTop;
- AnimationScheduler.get().requestAnimationFrame(this);
- }
-
- private void cancelBecauseOfEdgeOrCornerMaybe() {
- if (lastLeft == horizontalScrollbar.getScrollPos()
- && lastTop == verticalScrollbar.getScrollPos()) {
- cancel();
- }
- }
-
- public void cancel() {
- cancelled = true;
- }
- }
-
- /**
- * ScrollDestination case-specific handling logic.
- */
- private static double getScrollPos(final ScrollDestination destination,
- final double targetStartPx, final double targetEndPx,
- final double viewportStartPx, final double viewportEndPx,
- final int padding) {
-
- final double viewportLength = viewportEndPx - viewportStartPx;
-
- switch (destination) {
-
- /*
- * 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.
- */
- case ANY: {
- final double startScrollPos = targetStartPx - padding;
- final double endScrollPos = targetEndPx + padding - viewportLength;
-
- if (startScrollPos < viewportStartPx) {
- return startScrollPos;
- } else if (targetEndPx + padding > viewportEndPx) {
- return endScrollPos;
- } else {
- // NOOP, it's already visible
- return viewportStartPx;
- }
- }
-
- /*
- * Scrolls so that the element is shown at the end of the viewport. The
- * viewport will, however, not scroll before its first element.
- */
- case END: {
- return targetEndPx + padding - viewportLength;
- }
-
- /*
- * 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.
- */
- case MIDDLE: {
- final double targetMiddle = targetStartPx
- + (targetEndPx - targetStartPx) / 2;
- return targetMiddle - viewportLength / 2;
- }
-
- /*
- * Scrolls so that the element is shown at the start of the viewport.
- * The viewport will, however, not scroll beyond its contents.
- */
- case START: {
- return targetStartPx - padding;
- }
-
- /*
- * Throw an error if we're here. This can only mean that
- * ScrollDestination has been carelessly amended..
- */
- default: {
- throw new IllegalArgumentException(
- "Internal: ScrollDestination has been modified, "
- + "but Escalator.getScrollPos has not been updated "
- + "to match new values.");
- }
- }
-
- }
-
- /** An inner class that handles all logic related to scrolling. */
- private class Scroller extends JsniWorkaround {
- private double lastScrollTop = 0;
- private double lastScrollLeft = 0;
- /**
- * The current flick scroll animator. This is <code>null</code> if the
- * view isn't animating a flick scroll at the moment.
- */
- private FlickScrollAnimator currentFlickScroller;
-
- public Scroller() {
- super(Escalator.this);
- }
-
- @Override
- protected native JavaScriptObject createScrollListenerFunction(
- Escalator esc)
- /*-{
- var vScroll = esc.@com.vaadin.client.ui.grid.Escalator::verticalScrollbar;
- var vScrollElem = vScroll.@com.vaadin.client.ui.grid.ScrollbarBundle::getElement()();
-
- var hScroll = esc.@com.vaadin.client.ui.grid.Escalator::horizontalScrollbar;
- var hScrollElem = hScroll.@com.vaadin.client.ui.grid.ScrollbarBundle::getElement()();
-
- return $entry(function(e) {
- var target = e.target || e.srcElement; // IE8 uses e.scrElement
-
- // in case the scroll event was native (i.e. scrollbars were dragged, or
- // the scrollTop/Left was manually modified), the bundles have old cache
- // values. We need to make sure that the caches are kept up to date.
- if (target === vScrollElem) {
- vScroll.@com.vaadin.client.ui.grid.ScrollbarBundle::updateScrollPosFromDom()();
- } else if (target === hScrollElem) {
- hScroll.@com.vaadin.client.ui.grid.ScrollbarBundle::updateScrollPosFromDom()();
- } else {
- $wnd.console.error("unexpected scroll target: "+target);
- }
-
- esc.@com.vaadin.client.ui.grid.Escalator::onScroll()();
- });
- }-*/;
-
- @Override
- protected native JavaScriptObject createMousewheelListenerFunction(
- Escalator esc)
- /*-{
- return $entry(function(e) {
- var deltaX = e.deltaX ? e.deltaX : -0.5*e.wheelDeltaX;
- var deltaY = e.deltaY ? e.deltaY : -0.5*e.wheelDeltaY;
-
- // IE8 has only delta y
- if (isNaN(deltaY)) {
- deltaY = -0.5*e.wheelDelta;
- }
-
- @com.vaadin.client.ui.grid.Escalator.JsniUtil::moveScrollFromEvent(*)(esc, deltaX, deltaY, e);
- });
- }-*/;
-
- /**
- * Recalculates the virtual viewport represented by the scrollbars, so
- * that the sizes of the scroll handles appear correct in the browser
- */
- public void recalculateScrollbarsForVirtualViewport() {
- int scrollContentHeight = body.calculateEstimatedTotalRowHeight();
- int scrollContentWidth = columnConfiguration.calculateRowWidth();
-
- double tableWrapperHeight = heightOfEscalator;
- double tableWrapperWidth = widthOfEscalator;
-
- boolean verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
- - header.heightOfSection - footer.heightOfSection;
- boolean horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth;
-
- // One dimension got scrollbars, but not the other. Recheck time!
- if (verticalScrollNeeded != horizontalScrollNeeded) {
- if (!verticalScrollNeeded && horizontalScrollNeeded) {
- verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
- - header.heightOfSection
- - footer.heightOfSection
- - horizontalScrollbar.getScrollbarThickness();
- } else {
- horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth
- - verticalScrollbar.getScrollbarThickness();
- }
- }
-
- // let's fix the table wrapper size, since it's now stable.
- if (verticalScrollNeeded) {
- tableWrapperWidth -= verticalScrollbar.getScrollbarThickness();
- }
- if (horizontalScrollNeeded) {
- tableWrapperHeight -= horizontalScrollbar
- .getScrollbarThickness();
- }
- tableWrapper.getStyle().setHeight(tableWrapperHeight, Unit.PX);
- tableWrapper.getStyle().setWidth(tableWrapperWidth, Unit.PX);
-
- verticalScrollbar.setOffsetSize((int) (tableWrapperHeight
- - footer.heightOfSection - header.heightOfSection));
- verticalScrollbar.setScrollSize(scrollContentHeight);
-
- /*
- * If decreasing the amount of frozen columns, and scrolled to the
- * right, the scroll position might reset. So we need to remember
- * the scroll position, and re-apply it once the scrollbar size has
- * been adjusted.
- */
- int prevScrollPos = horizontalScrollbar.getScrollPos();
-
- int unfrozenPixels = columnConfiguration
- .getCalculatedColumnsWidth(Range.between(
- columnConfiguration.getFrozenColumnCount(),
- columnConfiguration.getColumnCount()));
- int frozenPixels = scrollContentWidth - unfrozenPixels;
- double hScrollOffsetWidth = tableWrapperWidth - frozenPixels;
- horizontalScrollbar.setOffsetSize((int) hScrollOffsetWidth);
- horizontalScrollbar.setScrollSize(unfrozenPixels);
- horizontalScrollbar.getElement().getStyle()
- .setLeft(frozenPixels, Unit.PX);
- horizontalScrollbar.setScrollPos(prevScrollPos);
- }
-
- /**
- * Logical scrolling event handler for the entire widget.
- *
- * @param scrollLeft
- * the current number of pixels that the user has scrolled
- * from left
- * @param scrollTop
- * the current number of pixels that the user has scrolled
- * from the top
- */
- public void onScroll() {
- if (internalScrollEventCalls > 0) {
- internalScrollEventCalls--;
- return;
- }
-
- final int scrollLeft = horizontalScrollbar.getScrollPos();
- final int scrollTop = verticalScrollbar.getScrollPos();
-
- if (lastScrollLeft != scrollLeft) {
- for (int i = 0; i < columnConfiguration.frozenColumns; i++) {
- header.updateFreezePosition(i, scrollLeft);
- body.updateFreezePosition(i, scrollLeft);
- footer.updateFreezePosition(i, scrollLeft);
- }
-
- position.set(headElem, -scrollLeft, 0);
-
- /*
- * TODO [[optimize]]: cache this value in case the instanceof
- * check has undesirable overhead. This could also be a
- * candidate for some deferred binding magic so that e.g.
- * AbsolutePosition is not even considered in permutations that
- * we know support something better. That would let the compiler
- * completely remove the entire condition since it knows that
- * the if will never be true.
- */
- if (position instanceof AbsolutePosition) {
- /*
- * we don't want to put "top: 0" on the footer, since it'll
- * render wrong, as we already have
- * "bottom: $footer-height".
- */
- footElem.getStyle().setLeft(-scrollLeft, Unit.PX);
- } else {
- position.set(footElem, -scrollLeft, 0);
- }
-
- lastScrollLeft = scrollLeft;
- }
-
- body.setBodyScrollPosition(scrollLeft, scrollTop);
-
- lastScrollTop = scrollTop;
- body.updateEscalatorRowsOnScroll();
- /*
- * TODO [[optimize]]: Might avoid a reflow by first calculating new
- * scrolltop and scrolleft, then doing the escalator magic based on
- * those numbers and only updating the positions after that.
- */
- }
-
- public native void attachScrollListener(Element element)
- /*
- * Attaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.addEventListener) {
- element.addEventListener("scroll", this.@com.vaadin.client.ui.grid.JsniWorkaround::scrollListenerFunction);
- } else {
- element.attachEvent("onscroll", this.@com.vaadin.client.ui.grid.JsniWorkaround::scrollListenerFunction);
- }
- }-*/;
-
- public native void detachScrollListener(Element element)
- /*
- * Attaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.addEventListener) {
- element.removeEventListener("scroll", this.@com.vaadin.client.ui.grid.JsniWorkaround::scrollListenerFunction);
- } else {
- element.detachEvent("onscroll", this.@com.vaadin.client.ui.grid.JsniWorkaround::scrollListenerFunction);
- }
- }-*/;
-
- public native void attachMousewheelListener(Element element)
- /*
- * Attaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.addEventListener) {
- // firefox likes "wheel", while others use "mousewheel"
- var eventName = element.onwheel===undefined?"mousewheel":"wheel";
- element.addEventListener(eventName, this.@com.vaadin.client.ui.grid.JsniWorkaround::mousewheelListenerFunction);
- } else {
- // IE8
- element.attachEvent("onmousewheel", this.@com.vaadin.client.ui.grid.JsniWorkaround::mousewheelListenerFunction);
- }
- }-*/;
-
- public native void detachMousewheelListener(Element element)
- /*
- * Detaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.addEventListener) {
- // firefox likes "wheel", while others use "mousewheel"
- var eventName = element.onwheel===undefined?"mousewheel":"wheel";
- element.removeEventListener(eventName, this.@com.vaadin.client.ui.grid.JsniWorkaround::mousewheelListenerFunction);
- } else {
- // IE8
- element.detachEvent("onmousewheel", this.@com.vaadin.client.ui.grid.JsniWorkaround::mousewheelListenerFunction);
- }
- }-*/;
-
- public native void attachTouchListeners(Element element)
- /*
- * Detaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.addEventListener) {
- element.addEventListener("touchstart", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchStartFunction);
- element.addEventListener("touchmove", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchMoveFunction);
- element.addEventListener("touchend", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchEndFunction);
- element.addEventListener("touchcancel", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchEndFunction);
- } else {
- // this would be IE8, but we don't support it with touch
- }
- }-*/;
-
- public native void detachTouchListeners(Element element)
- /*
- * Detaching events with JSNI instead of the GWT event mechanism because
- * GWT didn't provide enough details in events, or triggering the event
- * handlers with GWT bindings was unsuccessful. Maybe, with more time
- * and skill, it could be done with better success. JavaScript overlay
- * types might work. This might also get rid of the JsniWorkaround
- * class.
- */
- /*-{
- if (element.removeEventListener) {
- element.removeEventListener("touchstart", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchStartFunction);
- element.removeEventListener("touchmove", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchMoveFunction);
- element.removeEventListener("touchend", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchEndFunction);
- element.removeEventListener("touchcancel", this.@com.vaadin.client.ui.grid.JsniWorkaround::touchEndFunction);
- } else {
- // this would be IE8, but we don't support it with touch
- }
- }-*/;
-
- private void cancelFlickScroll() {
- if (currentFlickScroller != null) {
- currentFlickScroller.cancel();
- }
- }
-
- /**
- * Handles a touch-based flick scroll.
- *
- * @param deltaX
- * the last scrolling delta in the x-axis in a touchmove
- * @param deltaY
- * the last scrolling delta in the y-axis in a touchmove
- * @param lastTime
- * the timestamp of the last touchmove
- */
- public void handleFlickScroll(double deltaX, double deltaY,
- double lastTime) {
- currentFlickScroller = new FlickScrollAnimator(deltaX, deltaY,
- lastTime);
- AnimationScheduler.get()
- .requestAnimationFrame(currentFlickScroller);
- }
-
- public void scrollToColumn(final int columnIndex,
- final ScrollDestination destination, final int padding) {
- assert columnIndex >= columnConfiguration.frozenColumns : "Can't scroll to a frozen column";
-
- /*
- * To cope with frozen columns, we just pretend those columns are
- * not there at all when calculating the position of the target
- * column and the boundaries of the viewport. The resulting
- * scrollLeft will be correct without compensation since the DOM
- * structure effectively means that scrollLeft also ignores the
- * frozen columns.
- */
- final int frozenPixels = columnConfiguration
- .getCalculatedColumnsWidth(Range.withLength(0,
- columnConfiguration.frozenColumns));
-
- final int targetStartPx = columnConfiguration
- .getCalculatedColumnsWidth(Range.withLength(0, columnIndex))
- - frozenPixels;
- final int targetEndPx = targetStartPx
- + columnConfiguration.getColumnWidthActual(columnIndex);
-
- final int viewportStartPx = getScrollLeft();
- int viewportEndPx = viewportStartPx + getElement().getOffsetWidth()
- - frozenPixels;
- if (verticalScrollbar.showsScrollHandle()) {
- viewportEndPx -= Util.getNativeScrollbarSize();
- }
-
- final double scrollLeft = getScrollPos(destination, targetStartPx,
- targetEndPx, viewportStartPx, viewportEndPx, padding);
-
- /*
- * note that it doesn't matter if the scroll would go beyond the
- * content, since the browser will adjust for that, and everything
- * fall into line accordingly.
- */
- setScrollLeft((int) scrollLeft);
- }
-
- public void scrollToRow(final int rowIndex,
- final ScrollDestination destination, final int padding) {
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- final int targetStartPx = body.getDefaultRowHeight() * rowIndex;
- final int targetEndPx = targetStartPx + body.getDefaultRowHeight();
-
- final double viewportStartPx = getScrollTop();
- final double viewportEndPx = viewportStartPx
- + body.calculateHeight();
-
- final double scrollTop = getScrollPos(destination, targetStartPx,
- targetEndPx, viewportStartPx, viewportEndPx, padding);
-
- /*
- * note that it doesn't matter if the scroll would go beyond the
- * content, since the browser will adjust for that, and everything
- * falls into line accordingly.
- */
- setScrollTop(scrollTop);
- }
- }
-
- private abstract class AbstractRowContainer implements RowContainer {
-
- private EscalatorUpdater updater = EscalatorUpdater.NULL;
-
- private int rows;
-
- /**
- * The table section element ({@code <thead>}, {@code <tbody>} or
- * {@code <tfoot>}) the rows (i.e. {@code <tr>} tags) are contained in.
- */
- protected final Element root;
-
- /** The height of the combined rows in the DOM. */
- protected double heightOfSection = -1;
-
- /**
- * The primary style name of the escalator. Most commonly provided by
- * Escalator as "v-escalator".
- */
- private String primaryStyleName = null;
-
- /**
- * A map containing cached values of an element's current top position.
- * <p>
- * Don't use this field directly, because it will not take proper care
- * of all the bookkeeping required.
- *
- * @deprecated Use {@link #setRowPosition(Element, int, int)},
- * {@link #getRowTop(Element)} and
- * {@link #removeRowPosition(Element)} instead.
- */
- @Deprecated
- private final Map<Element, Integer> rowTopPositionMap = new HashMap<Element, Integer>();
-
- private boolean defaultRowHeightShouldBeAutodetected = true;
-
- private int defaultRowHeight = INITIAL_DEFAULT_ROW_HEIGHT;
-
- public AbstractRowContainer(final Element rowContainerElement) {
- root = rowContainerElement;
- }
-
- /**
- * Gets the tag name of an element to represent a cell in a row.
- * <p>
- * Usually {@code "th"} or {@code "td"}.
- * <p>
- * <em>Note:</em> To actually <em>create</em> such an element, use
- * {@link #createCellElement()} instead.
- *
- * @return the tag name for the element to represent cells as
- * @see #createCellElement()
- */
- protected abstract String getCellElementTagName();
-
- @Override
- public EscalatorUpdater getEscalatorUpdater() {
- return updater;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there is no data for rows or columns
- * when this method is called.
- *
- * @see #hasColumnAndRowData()
- */
- @Override
- public void setEscalatorUpdater(final EscalatorUpdater escalatorUpdater) {
- if (escalatorUpdater == null) {
- throw new IllegalArgumentException(
- "escalator updater cannot be null");
- }
-
- updater = escalatorUpdater;
-
- if (hasColumnAndRowData() && getRowCount() > 0) {
- refreshRows(0, getRowCount());
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there are no rows in the DOM when
- * this method is called.
- *
- * @see #hasSomethingInDom()
- */
- @Override
- public void removeRows(final int index, final int numberOfRows) {
- assertArgumentsAreValidAndWithinRange(index, numberOfRows);
-
- rows -= numberOfRows;
-
- if (!isAttached()) {
- return;
- }
-
- if (hasSomethingInDom()) {
- paintRemoveRows(index, numberOfRows);
- }
- }
-
- protected abstract void paintRemoveRows(final int index,
- final int numberOfRows);
-
- private void assertArgumentsAreValidAndWithinRange(final int index,
- final int numberOfRows) throws IllegalArgumentException,
- IndexOutOfBoundsException {
- if (numberOfRows < 1) {
- throw new IllegalArgumentException(
- "Number of rows must be 1 or greater (was "
- + numberOfRows + ")");
- }
-
- if (index < 0 || index + numberOfRows > getRowCount()) {
- throw new IndexOutOfBoundsException("The given "
- + "row range (" + index + ".." + (index + numberOfRows)
- + ") was outside of the current number of rows ("
- + getRowCount() + ")");
- }
- }
-
- @Override
- public int getRowCount() {
- return rows;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there is no data for columns when
- * this method is called.
- *
- * @see #hasColumnAndRowData()
- */
- @Override
- public void insertRows(final int index, final int numberOfRows) {
- if (index < 0 || index > getRowCount()) {
- throw new IndexOutOfBoundsException("The given index (" + index
- + ") was outside of the current number of rows (0.."
- + getRowCount() + ")");
- }
-
- if (numberOfRows < 1) {
- throw new IllegalArgumentException(
- "Number of rows must be 1 or greater (was "
- + numberOfRows + ")");
- }
-
- rows += numberOfRows;
-
- /*
- * only add items in the DOM if the widget itself is attached to the
- * DOM. We can't calculate sizes otherwise.
- */
- if (isAttached()) {
- paintInsertRows(index, numberOfRows);
- }
- }
-
- /**
- * Actually add rows into the DOM, now that everything can be
- * calculated.
- *
- * @param visualIndex
- * the DOM index to add rows into
- * @param numberOfRows
- * the number of rows to insert
- * @return a list of the added row elements
- */
- protected List<Element> paintInsertRows(final int visualIndex,
- final int numberOfRows) {
- assert isAttached() : "Can't paint rows if Escalator is not attached";
-
- final List<Element> addedRows = new ArrayList<Element>();
-
- if (numberOfRows < 1) {
- return addedRows;
- }
-
- Node referenceRow;
- if (root.getChildCount() != 0 && visualIndex != 0) {
- // get the row node we're inserting stuff after
- referenceRow = root.getChild(visualIndex - 1);
- } else {
- // index is 0, so just prepend.
- referenceRow = null;
- }
-
- for (int row = visualIndex; row < visualIndex + numberOfRows; row++) {
- final int rowHeight = getDefaultRowHeight();
- final Element tr = DOM.createTR();
- addedRows.add(tr);
- tr.addClassName(getStylePrimaryName() + "-row");
- referenceRow = insertAfterReferenceAndUpdateIt(root, tr,
- referenceRow);
-
- for (int col = 0; col < columnConfiguration.getColumnCount(); col++) {
- final int colWidth = columnConfiguration
- .getColumnWidthActual(col);
- final Element cellElem = createCellElement(rowHeight,
- colWidth);
- tr.appendChild(cellElem);
-
- // Set stylename and position if new cell is frozen
- if (col < columnConfiguration.frozenColumns) {
- cellElem.addClassName("frozen");
- position.set(cellElem, scroller.lastScrollLeft, 0);
- }
- }
-
- refreshRow(tr, row);
- }
- reapplyRowWidths();
-
- recalculateSectionHeight();
-
- return addedRows;
- }
-
- private Node insertAfterReferenceAndUpdateIt(final Element parent,
- final Element elem, final Node referenceNode) {
- if (referenceNode != null) {
- parent.insertAfter(elem, referenceNode);
- } else {
- /*
- * referencenode being null means we have offset 0, i.e. make it
- * the first row
- */
- /*
- * TODO [[optimize]]: Is insertFirst or append faster for an
- * empty root?
- */
- parent.insertFirst(elem);
- }
- return elem;
- }
-
- abstract protected void recalculateSectionHeight();
-
- /**
- * Returns the estimated height of all rows in the row container.
- * <p>
- * The estimate is promised to be correct as long as there are no rows
- * with calculated heights.
- */
- protected int calculateEstimatedTotalRowHeight() {
- return getDefaultRowHeight() * getRowCount();
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there is no data for columns when
- * this method is called.
- *
- * @see #hasColumnAndRowData()
- */
- @Override
- public void refreshRows(final int index, final int numberOfRows) {
- Profiler.enter("Escalator.AbstractRowContainer.refreshRows");
-
- assertArgumentsAreValidAndWithinRange(index, numberOfRows);
-
- if (!isAttached()) {
- return;
- }
-
- /*
- * TODO [[rowheight]]: even if no rows are evaluated in the current
- * viewport, the heights of some unrendered rows might change in a
- * refresh. This would cause the scrollbar to be adjusted (in
- * scrollHeight and/or scrollTop). Do we want to take this into
- * account?
- */
- if (hasColumnAndRowData()) {
- /*
- * TODO [[rowheight]]: nudge rows down with
- * refreshRowPositions() as needed
- */
- for (int row = index; row < index + numberOfRows; row++) {
- final Node tr = getTrByVisualIndex(row);
- refreshRow(tr, row);
- }
- }
-
- Profiler.leave("Escalator.AbstractRowContainer.refreshRows");
- }
-
- void refreshRow(final Node tr, final int logicalRowIndex) {
- flyweightRow.setup((Element) tr, logicalRowIndex,
- columnConfiguration.getCalculatedColumnWidths());
- updater.updateCells(flyweightRow, flyweightRow.getCells());
-
- /*
- * the "assert" guarantees that this code is run only during
- * development/debugging.
- */
- assert flyweightRow.teardown();
- }
-
- /**
- * Create and setup an empty cell element.
- *
- * @param width
- * the width of the cell, in pixels
- * @param height
- * the height of the cell, in pixels
- *
- * @return a set-up empty cell element
- */
- @SuppressWarnings("hiding")
- public Element createCellElement(final int height, final int width) {
- final Element cellElem = DOM.createElement(getCellElementTagName());
- cellElem.getStyle().setHeight(height, Unit.PX);
- cellElem.getStyle().setWidth(width, Unit.PX);
- cellElem.addClassName(getStylePrimaryName() + "-cell");
- return cellElem;
- }
-
- /**
- * Gets the child element that is visually at a certain index
- *
- * @param index
- * the index of the element to retrieve
- * @return the element at position {@code index}
- * @throws IndexOutOfBoundsException
- * if {@code index} is not valid within {@link #root}
- */
- abstract protected Element getTrByVisualIndex(int index)
- throws IndexOutOfBoundsException;
-
- protected void paintRemoveColumns(final int offset,
- final int numberOfColumns,
- final List<ColumnConfigurationImpl.Column> removedColumns) {
- final NodeList<Node> childNodes = root.getChildNodes();
- for (int visualRowIndex = 0; visualRowIndex < childNodes
- .getLength(); visualRowIndex++) {
- final Node tr = childNodes.getItem(visualRowIndex);
-
- for (int column = 0; column < numberOfColumns; column++) {
- Element cellElement = tr.getChild(offset).cast();
- detachPossibleWidgetFromCell(cellElement);
- cellElement.removeFromParent();
- }
- }
- reapplyRowWidths();
-
- final int firstRemovedColumnLeft = columnConfiguration
- .getCalculatedColumnsWidth(Range.withLength(0, offset));
- final boolean columnsWereRemovedFromLeftOfTheViewport = scroller.lastScrollLeft > firstRemovedColumnLeft;
-
- if (columnsWereRemovedFromLeftOfTheViewport) {
- int removedColumnsPxAmount = 0;
- for (ColumnConfigurationImpl.Column removedColumn : removedColumns) {
- removedColumnsPxAmount += removedColumn
- .getCalculatedWidth();
- }
- final int leftByDiff = (int) (scroller.lastScrollLeft - removedColumnsPxAmount);
- final int newScrollLeft = Math.max(firstRemovedColumnLeft,
- leftByDiff);
- horizontalScrollbar.setScrollPos(newScrollLeft);
- }
-
- // this needs to be after the scroll position adjustment above.
- scroller.recalculateScrollbarsForVirtualViewport();
-
- /*
- * Because we might remove columns where affected by colspans, it's
- * easiest to simply redraw everything when columns are modified.
- *
- * Yes, this is a TODO [[optimize]].
- */
- if (getRowCount() > 0
- && getColumnConfiguration().getColumnCount() > 0) {
- refreshRows(0, getRowCount());
- }
- }
-
- void detachPossibleWidgetFromCell(Node cellNode) {
- // Detach possible widget
- Widget widget = getWidgetFromCell(cellNode);
- if (widget != null) {
- // Orphan.
- setParent(widget, null);
-
- // Physical detach.
- cellNode.removeChild(widget.getElement());
- }
- }
-
- protected void paintInsertColumns(final int offset,
- final int numberOfColumns, boolean frozen) {
- final NodeList<Node> childNodes = root.getChildNodes();
-
- for (int row = 0; row < childNodes.getLength(); row++) {
- final int rowHeight = getDefaultRowHeight();
- final Element tr = getTrByVisualIndex(row);
-
- Node referenceCell;
- if (offset != 0) {
- referenceCell = tr.getChild(offset - 1);
- } else {
- referenceCell = null;
- }
-
- for (int col = offset; col < offset + numberOfColumns; col++) {
- final int colWidth = columnConfiguration
- .getColumnWidthActual(col);
- final Element cellElem = createCellElement(rowHeight,
- colWidth);
- referenceCell = insertAfterReferenceAndUpdateIt(tr,
- cellElem, referenceCell);
- }
- }
- reapplyRowWidths();
-
- if (frozen) {
- for (int col = offset; col < offset + numberOfColumns; col++) {
- setColumnFrozen(col, true);
- }
- }
-
- // this needs to be before the scrollbar adjustment.
- scroller.recalculateScrollbarsForVirtualViewport();
-
- int pixelsToInsertedColumn = columnConfiguration
- .getCalculatedColumnsWidth(Range.withLength(0, offset));
- final boolean columnsWereAddedToTheLeftOfViewport = scroller.lastScrollLeft > pixelsToInsertedColumn;
-
- if (columnsWereAddedToTheLeftOfViewport) {
- int insertedColumnsWidth = columnConfiguration
- .getCalculatedColumnsWidth(Range.withLength(offset,
- numberOfColumns));
- horizontalScrollbar
- .setScrollPos((int) (scroller.lastScrollLeft + insertedColumnsWidth));
- }
-
- /*
- * Because we might insert columns where affected by colspans, it's
- * easiest to simply redraw everything when columns are modified.
- *
- * Yes, this is a TODO [[optimize]].
- */
- if (getRowCount() > 0
- && getColumnConfiguration().getColumnCount() > 1) {
- refreshRows(0, getRowCount());
- }
- }
-
- public void setColumnFrozen(int column, boolean frozen) {
- final NodeList<Node> childNodes = root.getChildNodes();
-
- for (int row = 0; row < childNodes.getLength(); row++) {
- final Element tr = childNodes.getItem(row).cast();
-
- Element cell = (Element) tr.getChild(column);
- if (frozen) {
- cell.addClassName("frozen");
- } else {
- cell.removeClassName("frozen");
- position.reset(cell);
- }
- }
-
- if (frozen) {
- updateFreezePosition(column, scroller.lastScrollLeft);
- }
- }
-
- public void updateFreezePosition(int column, double scrollLeft) {
- final NodeList<Node> childNodes = root.getChildNodes();
-
- for (int row = 0; row < childNodes.getLength(); row++) {
- final Element tr = childNodes.getItem(row).cast();
-
- Element cell = (Element) tr.getChild(column);
- position.set(cell, scrollLeft, 0);
- }
- }
-
- /**
- * Iterates through all the cells in a column and returns the width of
- * the widest element in this RowContainer.
- *
- * @param index
- * the index of the column to inspect
- * @return the pixel width of the widest element in the indicated column
- */
- public int calculateMaxColWidth(int index) {
- Element row = root.getFirstChildElement();
- int maxWidth = 0;
- while (row != null) {
- final Element cell = (Element) row.getChild(index);
- final boolean isVisible = !cell.getStyle().getDisplay()
- .equals(Display.NONE.getCssName());
- if (isVisible) {
- maxWidth = Math.max(maxWidth, cell.getScrollWidth());
- }
- row = row.getNextSiblingElement();
- }
- return maxWidth;
- }
-
- /**
- * Reapplies all the cells' widths according to the calculated widths in
- * the column configuration.
- */
- public void reapplyColumnWidths() {
- Element row = root.getFirstChildElement();
- while (row != null) {
- Element cell = row.getFirstChildElement();
- int columnIndex = 0;
- while (cell != null) {
- @SuppressWarnings("hiding")
- final int width = getCalculatedColumnWidthWithColspan(cell,
- columnIndex);
-
- /*
- * TODO Should Escalator implement ProvidesResize at some
- * point, this is where we need to do that.
- */
- cell.getStyle().setWidth(width, Unit.PX);
-
- cell = cell.getNextSiblingElement();
- columnIndex++;
- }
- row = row.getNextSiblingElement();
- }
-
- reapplyRowWidths();
- }
-
- private int getCalculatedColumnWidthWithColspan(final Element cell,
- final int columnIndex) {
- final int colspan = cell.getPropertyInt(FlyweightCell.COLSPAN_ATTR);
- Range spannedColumns = Range.withLength(columnIndex, colspan);
-
- /*
- * Since browsers don't explode with overflowing colspans, escalator
- * shouldn't either.
- */
- if (spannedColumns.getEnd() > columnConfiguration.getColumnCount()) {
- spannedColumns = Range.between(columnIndex,
- columnConfiguration.getColumnCount());
- }
- return columnConfiguration
- .getCalculatedColumnsWidth(spannedColumns);
- }
-
- /**
- * Applies the total length of the columns to each row element.
- * <p>
- * <em>Note:</em> In contrast to {@link #reapplyColumnWidths()}, this
- * method only modifies the width of the {@code <tr>} element, not the
- * cells within.
- */
- protected void reapplyRowWidths() {
- int rowWidth = columnConfiguration.calculateRowWidth();
-
- com.google.gwt.dom.client.Element row = root.getFirstChildElement();
- while (row != null) {
- row.getStyle().setWidth(rowWidth, Unit.PX);
- row = row.getNextSiblingElement();
- }
- }
-
- /**
- * The primary style name for the container.
- *
- * @param primaryStyleName
- * the style name to use as prefix for all row and cell style
- * names.
- */
- protected void setStylePrimaryName(String primaryStyleName) {
- String oldStyle = getStylePrimaryName();
- if (SharedUtil.equals(oldStyle, primaryStyleName)) {
- return;
- }
-
- this.primaryStyleName = primaryStyleName;
-
- // Update already rendered rows and cells
- Node row = root.getFirstChild();
- while (row != null) {
- Element rowElement = row.cast();
- UIObject.setStylePrimaryName(rowElement, primaryStyleName
- + "-row");
- Node cell = row.getFirstChild();
- while (cell != null) {
- Element cellElement = cell.cast();
- UIObject.setStylePrimaryName(cellElement, primaryStyleName
- + "-cell");
- cell = cell.getNextSibling();
- }
- row = row.getNextSibling();
- }
- }
-
- /**
- * Returns the primary style name of the container.
- *
- * @return The primary style name or <code>null</code> if not set.
- */
- protected String getStylePrimaryName() {
- return primaryStyleName;
- }
-
- @Override
- public void setDefaultRowHeight(int px) throws IllegalArgumentException {
- if (px < 1) {
- throw new IllegalArgumentException("Height must be positive. "
- + px + " was given.");
- }
-
- defaultRowHeightShouldBeAutodetected = false;
- defaultRowHeight = px;
- reapplyDefaultRowHeights();
- }
-
- @Override
- public int getDefaultRowHeight() {
- return defaultRowHeight;
- }
-
- /**
- * The default height of rows has (most probably) changed.
- * <p>
- * Make sure that the displayed rows with a default height are updated
- * in height and top position.
- * <p>
- * <em>Note:</em>This implementation should not call
- * {@link Escalator#recalculateElementSizes()} - it is done by the
- * discretion of the caller of this method.
- */
- protected abstract void reapplyDefaultRowHeights();
-
- protected void reapplyRowHeight(final Element tr, final int heightPx) {
- Element cellElem = tr.getFirstChildElement().cast();
- while (cellElem != null) {
- cellElem.getStyle().setHeight(heightPx, Unit.PX);
- cellElem = cellElem.getNextSiblingElement();
- }
-
- /*
- * no need to apply height to tr-element, it'll be resized
- * implicitly.
- */
- }
-
- @SuppressWarnings("boxing")
- protected void setRowPosition(final Element tr, final int x, final int y) {
- position.set(tr, x, y);
- rowTopPositionMap.put(tr, y);
- }
-
- @SuppressWarnings("boxing")
- protected int getRowTop(final Element tr) {
- return rowTopPositionMap.get(tr);
- }
-
- protected void removeRowPosition(Element tr) {
- rowTopPositionMap.remove(tr);
- }
-
- public void autodetectRowHeight() {
- Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
-
- @Override
- public void execute() {
- if (defaultRowHeightShouldBeAutodetected && isAttached()) {
- final Element detectionTr = DOM.createTR();
- detectionTr
- .setClassName(getStylePrimaryName() + "-row");
-
- final Element cellElem = DOM
- .createElement(getCellElementTagName());
- cellElem.setClassName(getStylePrimaryName() + "-cell");
- cellElem.setInnerHTML("foo");
-
- detectionTr.appendChild(cellElem);
- root.appendChild(detectionTr);
- defaultRowHeight = Math.max(1,
- cellElem.getOffsetHeight());
- root.removeChild(detectionTr);
-
- if (root.hasChildNodes()) {
- reapplyDefaultRowHeights();
- }
-
- defaultRowHeightShouldBeAutodetected = false;
- }
- }
- });
- }
- }
-
- private abstract class AbstractStaticRowContainer extends
- AbstractRowContainer {
- public AbstractStaticRowContainer(final Element headElement) {
- super(headElement);
- }
-
- @Override
- protected void paintRemoveRows(final int index, final int numberOfRows) {
- for (int i = index; i < index + numberOfRows; i++) {
- final Element tr = (Element) root.getChild(index);
- for (int c = 0; c < tr.getChildCount(); c++) {
- detachPossibleWidgetFromCell((Element) tr.getChild(c)
- .cast());
- }
- tr.removeFromParent();
- }
- recalculateSectionHeight();
- }
-
- @Override
- protected Element getTrByVisualIndex(final int index)
- throws IndexOutOfBoundsException {
- if (index >= 0 && index < root.getChildCount()) {
- return (Element) root.getChild(index);
- } else {
- throw new IndexOutOfBoundsException("No such visual index: "
- + index);
- }
- }
-
- @Override
- public void insertRows(int index, int numberOfRows) {
- super.insertRows(index, numberOfRows);
- recalculateElementSizes();
- }
-
- @Override
- public void removeRows(int index, int numberOfRows) {
- super.removeRows(index, numberOfRows);
- recalculateElementSizes();
- }
-
- @Override
- protected void reapplyDefaultRowHeights() {
- if (root.getChildCount() == 0) {
- return;
- }
-
- Profiler.enter("Escalator.AbstractStaticRowContainer.reapplyDefaultRowHeights");
-
- Element tr = root.getFirstChildElement().cast();
- while (tr != null) {
- reapplyRowHeight(tr, getDefaultRowHeight());
- tr = tr.getNextSiblingElement();
- }
-
- /*
- * Because all rows are immediately displayed in the static row
- * containers, the section's overall height has most probably
- * changed.
- */
- recalculateSectionHeight();
-
- Profiler.leave("Escalator.AbstractStaticRowContainer.reapplyDefaultRowHeights");
- }
-
- @Override
- protected void recalculateSectionHeight() {
- Profiler.enter("Escalator.AbstractStaticRowContainer.recalculateSectionHeight");
-
- int newHeight = calculateEstimatedTotalRowHeight();
- if (newHeight != heightOfSection) {
- heightOfSection = newHeight;
- sectionHeightCalculated();
- body.verifyEscalatorCount();
- }
-
- Profiler.leave("Escalator.AbstractStaticRowContainer.recalculateSectionHeight");
- }
-
- /**
- * Informs the row container that the height of its respective table
- * section has changed.
- * <p>
- * These calculations might affect some layouting logic, such as the
- * body is being offset by the footer, the footer needs to be readjusted
- * according to its height, and so on.
- * <p>
- * A table section is either header, body or footer.
- */
- protected abstract void sectionHeightCalculated();
- }
-
- private class HeaderRowContainer extends AbstractStaticRowContainer {
- public HeaderRowContainer(final Element headElement) {
- super(headElement);
- }
-
- @Override
- protected void sectionHeightCalculated() {
- bodyElem.getStyle().setMarginTop(heightOfSection, Unit.PX);
- verticalScrollbar.getElement().getStyle()
- .setTop(heightOfSection, Unit.PX);
- }
-
- @Override
- protected String getCellElementTagName() {
- return "th";
- }
-
- @Override
- public void setStylePrimaryName(String primaryStyleName) {
- super.setStylePrimaryName(primaryStyleName);
- UIObject.setStylePrimaryName(root, primaryStyleName + "-header");
- }
- }
-
- private class FooterRowContainer extends AbstractStaticRowContainer {
- public FooterRowContainer(final Element footElement) {
- super(footElement);
- }
-
- @Override
- public void setStylePrimaryName(String primaryStyleName) {
- super.setStylePrimaryName(primaryStyleName);
- UIObject.setStylePrimaryName(root, primaryStyleName + "-footer");
- }
-
- @Override
- protected String getCellElementTagName() {
- return "td";
- }
-
- @Override
- protected void sectionHeightCalculated() {
- int vscrollHeight = (int) Math.floor(heightOfEscalator
- - header.heightOfSection - footer.heightOfSection);
-
- final boolean horizontalScrollbarNeeded = columnConfiguration
- .calculateRowWidth() > widthOfEscalator;
- if (horizontalScrollbarNeeded) {
- vscrollHeight -= horizontalScrollbar.getScrollbarThickness();
- }
-
- verticalScrollbar.setOffsetSize(vscrollHeight);
- }
- }
-
- private class BodyRowContainer extends AbstractRowContainer {
- /*
- * TODO [[optimize]]: check whether a native JsArray might be faster
- * than LinkedList
- */
- /**
- * The order in which row elements are rendered visually in the browser,
- * with the help of CSS tricks. Usually has nothing to do with the DOM
- * order.
- */
- private final LinkedList<Element> visualRowOrder = new LinkedList<Element>();
-
- /**
- * The logical index of the topmost row.
- *
- * @deprecated Use the accessors {@link #setTopRowLogicalIndex(int)},
- * {@link #updateTopRowLogicalIndex(int)} and
- * {@link #getTopRowLogicalIndex()} instead
- */
- @Deprecated
- private int topRowLogicalIndex = 0;
-
- private void setTopRowLogicalIndex(int topRowLogicalIndex) {
- if (LogConfiguration.loggingIsEnabled(Level.INFO)) {
- Logger.getLogger("Escalator.BodyRowContainer").fine(
- "topRowLogicalIndex: " + this.topRowLogicalIndex
- + " -> " + topRowLogicalIndex);
- }
- assert topRowLogicalIndex >= 0 : "topRowLogicalIndex became negative";
- /*
- * if there's a smart way of evaluating and asserting the max index,
- * this would be a nice place to put it. I haven't found out an
- * effective and generic solution.
- */
-
- this.topRowLogicalIndex = topRowLogicalIndex;
- }
-
- private int getTopRowLogicalIndex() {
- return topRowLogicalIndex;
- }
-
- private void updateTopRowLogicalIndex(int diff) {
- setTopRowLogicalIndex(topRowLogicalIndex + diff);
- }
-
- public BodyRowContainer(final Element bodyElement) {
- super(bodyElement);
- }
-
- @Override
- public void setStylePrimaryName(String primaryStyleName) {
- super.setStylePrimaryName(primaryStyleName);
- UIObject.setStylePrimaryName(root, primaryStyleName + "-body");
- }
-
- public void updateEscalatorRowsOnScroll() {
- if (visualRowOrder.isEmpty()) {
- return;
- }
-
- boolean rowsWereMoved = false;
-
- final int topRowPos = getRowTop(visualRowOrder.getFirst());
- // TODO [[mpixscroll]]
- final int scrollTop = tBodyScrollTop;
- final int viewportOffset = topRowPos - scrollTop;
-
- /*
- * TODO [[optimize]] this if-else can most probably be refactored
- * into a neater block of code
- */
-
- if (viewportOffset > 0) {
- // there's empty room on top
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- int originalRowsToMove = (int) Math.ceil(viewportOffset
- / (double) getDefaultRowHeight());
- int rowsToMove = Math.min(originalRowsToMove,
- root.getChildCount());
-
- final int end = root.getChildCount();
- final int start = end - rowsToMove;
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- final int logicalRowIndex = scrollTop / getDefaultRowHeight();
- moveAndUpdateEscalatorRows(Range.between(start, end), 0,
- logicalRowIndex);
-
- updateTopRowLogicalIndex(-originalRowsToMove);
- }
-
- else if (viewportOffset + getDefaultRowHeight() <= 0) {
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
-
- /*
- * the viewport has been scrolled more than the topmost visual
- * row.
- */
-
- /*
- * Using the fact that integer division has implicit
- * floor-function to our advantage here.
- */
- int originalRowsToMove = Math.abs(viewportOffset
- / getDefaultRowHeight());
- int rowsToMove = Math.min(originalRowsToMove,
- root.getChildCount());
-
- int logicalRowIndex;
- if (rowsToMove < root.getChildCount()) {
- /*
- * We scroll so little that we can just keep adding the rows
- * below the current escalator
- */
- logicalRowIndex = getLogicalRowIndex(visualRowOrder
- .getLast()) + 1;
- } else {
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- /*
- * Since we're moving all escalator rows, we need to
- * calculate the first logical row index from the scroll
- * position.
- */
- logicalRowIndex = scrollTop / getDefaultRowHeight();
- }
-
- /*
- * Since we're moving the viewport downwards, the visual index
- * is always at the bottom. Note: Due to how
- * moveAndUpdateEscalatorRows works, this will work out even if
- * we move all the rows, and try to place them "at the end".
- */
- final int targetVisualIndex = root.getChildCount();
-
- // make sure that we don't move rows over the data boundary
- boolean aRowWasLeftBehind = false;
- if (logicalRowIndex + rowsToMove > getRowCount()) {
- /*
- * TODO [[rowheight]]: with constant row heights, there's
- * always exactly one row that will be moved beyond the data
- * source, when viewport is scrolled to the end. This,
- * however, isn't guaranteed anymore once row heights start
- * varying.
- */
- rowsToMove--;
- aRowWasLeftBehind = true;
- }
-
- moveAndUpdateEscalatorRows(Range.between(0, rowsToMove),
- targetVisualIndex, logicalRowIndex);
-
- if (aRowWasLeftBehind) {
- /*
- * To keep visualRowOrder as a spatially contiguous block of
- * rows, let's make sure that the one row we didn't move
- * visually still stays with the pack.
- */
- final Range strayRow = Range.withOnly(0);
-
- /*
- * We cannot trust getLogicalRowIndex, because it hasn't yet
- * been updated. But since we're leaving rows behind, it
- * means we've scrolled to the bottom. So, instead, we
- * simply count backwards from the end.
- */
- final int topLogicalIndex = getRowCount()
- - visualRowOrder.size();
- moveAndUpdateEscalatorRows(strayRow, 0, topLogicalIndex);
- }
-
- final int naiveNewLogicalIndex = getTopRowLogicalIndex()
- + originalRowsToMove;
- final int maxLogicalIndex = getRowCount()
- - visualRowOrder.size();
- setTopRowLogicalIndex(Math.min(naiveNewLogicalIndex,
- maxLogicalIndex));
- }
-
- if (rowsWereMoved) {
- fireRowVisibilityChangeEvent();
- }
- }
-
- @Override
- protected List<Element> paintInsertRows(final int index,
- final int numberOfRows) {
- if (numberOfRows == 0) {
- return Collections.emptyList();
- }
-
- /*
- * TODO: this method should probably only add physical rows, and not
- * populate them - let everything be populated as appropriate by the
- * logic that follows.
- *
- * This also would lead to the fact that paintInsertRows wouldn't
- * need to return anything.
- */
- final List<Element> addedRows = fillAndPopulateEscalatorRowsIfNeeded(
- index, numberOfRows);
-
- /*
- * insertRows will always change the number of rows - update the
- * scrollbar sizes.
- */
- scroller.recalculateScrollbarsForVirtualViewport();
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- final boolean addedRowsAboveCurrentViewport = index
- * getDefaultRowHeight() < getScrollTop();
- final boolean addedRowsBelowCurrentViewport = index
- * getDefaultRowHeight() > getScrollTop()
- + calculateHeight();
-
- if (addedRowsAboveCurrentViewport) {
- /*
- * We need to tweak the virtual viewport (scroll handle
- * positions, table "scroll position" and row locations), but
- * without re-evaluating any rows.
- */
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- final int yDelta = numberOfRows * getDefaultRowHeight();
- adjustScrollPosIgnoreEvents(yDelta);
- updateTopRowLogicalIndex(numberOfRows);
- }
-
- else if (addedRowsBelowCurrentViewport) {
- // NOOP, we already recalculated scrollbars.
- }
-
- else { // some rows were added inside the current viewport
-
- final int unupdatedLogicalStart = index + addedRows.size();
- final int visualOffset = getLogicalRowIndex(visualRowOrder
- .getFirst());
-
- /*
- * At this point, we have added new escalator rows, if so
- * needed.
- *
- * If more rows were added than the new escalator rows can
- * account for, we need to start to spin the escalator to update
- * the remaining rows aswell.
- */
- final int rowsStillNeeded = numberOfRows - addedRows.size();
- final Range unupdatedVisual = convertToVisual(Range.withLength(
- unupdatedLogicalStart, rowsStillNeeded));
- final int end = root.getChildCount();
- final int start = end - unupdatedVisual.length();
- final int visualTargetIndex = unupdatedLogicalStart
- - visualOffset;
- moveAndUpdateEscalatorRows(Range.between(start, end),
- visualTargetIndex, unupdatedLogicalStart);
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- // move the surrounding rows to their correct places.
- int rowTop = (unupdatedLogicalStart + (end - start))
- * getDefaultRowHeight();
- final ListIterator<Element> i = visualRowOrder
- .listIterator(visualTargetIndex + (end - start));
- while (i.hasNext()) {
- final Element tr = i.next();
- setRowPosition(tr, 0, rowTop);
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- rowTop += getDefaultRowHeight();
- }
-
- fireRowVisibilityChangeEvent();
- }
- return addedRows;
- }
-
- /**
- * Move escalator rows around, and make sure everything gets
- * appropriately repositioned and repainted.
- *
- * @param visualSourceRange
- * the range of rows to move to a new place
- * @param visualTargetIndex
- * the visual index where the rows will be placed to
- * @param logicalTargetIndex
- * the logical index to be assigned to the first moved row
- * @throws IllegalArgumentException
- * if any of <code>visualSourceRange.getStart()</code>,
- * <code>visualTargetIndex</code> or
- * <code>logicalTargetIndex</code> is a negative number; or
- * if <code>visualTargetInfo</code> is greater than the
- * number of escalator rows.
- */
- private void moveAndUpdateEscalatorRows(final Range visualSourceRange,
- final int visualTargetIndex, final int logicalTargetIndex)
- throws IllegalArgumentException {
-
- if (visualSourceRange.isEmpty()) {
- return;
- }
-
- if (visualSourceRange.getStart() < 0) {
- throw new IllegalArgumentException(
- "Logical source start must be 0 or greater (was "
- + visualSourceRange.getStart() + ")");
- } else if (logicalTargetIndex < 0) {
- throw new IllegalArgumentException(
- "Logical target must be 0 or greater");
- } else if (visualTargetIndex < 0) {
- throw new IllegalArgumentException(
- "Visual target must be 0 or greater");
- } else if (visualTargetIndex > root.getChildCount()) {
- throw new IllegalArgumentException(
- "Visual target must not be greater than the number of escalator rows");
- } else if (logicalTargetIndex + visualSourceRange.length() > getRowCount()) {
- final int logicalEndIndex = logicalTargetIndex
- + visualSourceRange.length() - 1;
- throw new IllegalArgumentException(
- "Logical target leads to rows outside of the data range ("
- + logicalTargetIndex + ".." + logicalEndIndex
- + ")");
- }
-
- /*
- * Since we move a range into another range, the indices might move
- * about. Having 10 rows, if we move 0..1 to index 10 (to the end of
- * the collection), the target range will end up being 8..9, instead
- * of 10..11.
- *
- * This applies only if we move elements forward in the collection,
- * not backward.
- */
- final int adjustedVisualTargetIndex;
- if (visualSourceRange.getStart() < visualTargetIndex) {
- adjustedVisualTargetIndex = visualTargetIndex
- - visualSourceRange.length();
- } else {
- adjustedVisualTargetIndex = visualTargetIndex;
- }
-
- if (visualSourceRange.getStart() != adjustedVisualTargetIndex) {
-
- /*
- * Reorder the rows to their correct places within
- * visualRowOrder (unless rows are moved back to their original
- * places)
- */
-
- /*
- * TODO [[optimize]]: move whichever set is smaller: the ones
- * explicitly moved, or the others. So, with 10 escalator rows,
- * if we are asked to move idx[0..8] to the end of the list,
- * it's faster to just move idx[9] to the beginning.
- */
-
- final List<Element> removedRows = new ArrayList<Element>(
- visualSourceRange.length());
- for (int i = 0; i < visualSourceRange.length(); i++) {
- final Element tr = visualRowOrder.remove(visualSourceRange
- .getStart());
- removedRows.add(tr);
- }
- visualRowOrder.addAll(adjustedVisualTargetIndex, removedRows);
- }
-
- { // Refresh the contents of the affected rows
- final ListIterator<Element> iter = visualRowOrder
- .listIterator(adjustedVisualTargetIndex);
- for (int logicalIndex = logicalTargetIndex; logicalIndex < logicalTargetIndex
- + visualSourceRange.length(); logicalIndex++) {
- final Element tr = iter.next();
- refreshRow(tr, logicalIndex);
- }
- }
-
- { // Reposition the rows that were moved
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- int newRowTop = logicalTargetIndex * getDefaultRowHeight();
-
- final ListIterator<Element> iter = visualRowOrder
- .listIterator(adjustedVisualTargetIndex);
- for (int i = 0; i < visualSourceRange.length(); i++) {
- final Element tr = iter.next();
- setRowPosition(tr, 0, newRowTop);
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- newRowTop += getDefaultRowHeight();
- }
- }
- }
-
- /**
- * Adjust the scroll position without having the scroll handler have any
- * side-effects.
- * <p>
- * <em>Note:</em> {@link Scroller#onScroll(double, double)}
- * <em>will</em> be triggered, but it will not do anything, with the
- * help of {@link Escalator#internalScrollEventCalls}.
- *
- * @param yDelta
- * the delta of pixels to scrolls. A positive value moves the
- * viewport downwards, while a negative value moves the
- * viewport upwards
- */
- public void adjustScrollPosIgnoreEvents(final int yDelta) {
- if (yDelta == 0) {
- return;
- }
-
- internalScrollEventCalls++;
- verticalScrollbar.setScrollPosByDelta(yDelta);
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- final int rowTopPos = yDelta - yDelta % getDefaultRowHeight();
- for (final Element tr : visualRowOrder) {
- setRowPosition(tr, 0, getRowTop(tr) + rowTopPos);
- }
- setBodyScrollPosition(tBodyScrollLeft, tBodyScrollTop + yDelta);
- }
-
- /**
- * Adds new physical escalator rows to the DOM at the given index if
- * there's still a need for more escalator rows.
- * <p>
- * If Escalator already is at (or beyond) max capacity, this method does
- * nothing to the DOM.
- *
- * @param index
- * the index at which to add new escalator rows.
- * <em>Note:</em>It is assumed that the index is both the
- * visual index and the logical index.
- * @param numberOfRows
- * the number of rows to add at <code>index</code>
- * @return a list of the added rows
- */
- private List<Element> fillAndPopulateEscalatorRowsIfNeeded(
- final int index, final int numberOfRows) {
-
- final int escalatorRowsStillFit = getMaxEscalatorRowCapacity()
- - root.getChildCount();
- final int escalatorRowsNeeded = Math.min(numberOfRows,
- escalatorRowsStillFit);
-
- if (escalatorRowsNeeded > 0) {
-
- final List<Element> addedRows = super.paintInsertRows(index,
- escalatorRowsNeeded);
- visualRowOrder.addAll(index, addedRows);
-
- /*
- * We need to figure out the top positions for the rows we just
- * added.
- */
- for (int i = 0; i < addedRows.size(); i++) {
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- setRowPosition(addedRows.get(i), 0, (index + i)
- * getDefaultRowHeight());
- }
-
- /* Move the other rows away from above the added escalator rows */
- for (int i = index + addedRows.size(); i < visualRowOrder
- .size(); i++) {
- final Element tr = visualRowOrder.get(i);
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- setRowPosition(tr, 0, i * getDefaultRowHeight());
- }
-
- return addedRows;
- } else {
- return new ArrayList<Element>();
- }
- }
-
- private int getMaxEscalatorRowCapacity() {
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- final int maxEscalatorRowCapacity = (int) Math
- .ceil(calculateHeight() / getDefaultRowHeight()) + 1;
-
- /*
- * maxEscalatorRowCapacity can become negative if the headers and
- * footers start to overlap. This is a crazy situation, but Vaadin
- * blinks the components a lot, so it's feasible.
- */
- return Math.max(0, maxEscalatorRowCapacity);
- }
-
- @Override
- protected void paintRemoveRows(final int index, final int numberOfRows) {
-
- final Range viewportRange = Range.withLength(
- getLogicalRowIndex(visualRowOrder.getFirst()),
- visualRowOrder.size());
-
- final Range removedRowsRange = Range
- .withLength(index, numberOfRows);
-
- final Range[] partitions = removedRowsRange
- .partitionWith(viewportRange);
- final Range removedAbove = partitions[0];
- final Range removedLogicalInside = partitions[1];
- final Range removedVisualInside = convertToVisual(removedLogicalInside);
-
- /*
- * TODO: extract the following if-block to a separate method. I'll
- * leave this be inlined for now, to make linediff-based code
- * reviewing easier. Probably will be moved in the following patch
- * set.
- */
-
- /*
- * Adjust scroll position in one of two scenarios:
- *
- * 1) Rows were removed above. Then we just need to adjust the
- * scrollbar by the height of the removed rows.
- *
- * 2) There are no logical rows above, and at least the first (if
- * not more) visual row is removed. Then we need to snap the scroll
- * position to the first visible row (i.e. reset scroll position to
- * absolute 0)
- *
- * The logic is optimized in such a way that the
- * adjustScrollPosIgnoreEvents is called only once, to avoid extra
- * reflows, and thus the code might seem a bit obscure.
- */
- final boolean firstVisualRowIsRemoved = !removedVisualInside
- .isEmpty() && removedVisualInside.getStart() == 0;
-
- if (!removedAbove.isEmpty() || firstVisualRowIsRemoved) {
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- final int yDelta = removedAbove.length()
- * getDefaultRowHeight();
- final int firstLogicalRowHeight = getDefaultRowHeight();
- final boolean removalScrollsToShowFirstLogicalRow = verticalScrollbar
- .getScrollPos() - yDelta < firstLogicalRowHeight;
-
- if (removedVisualInside.isEmpty()
- && (!removalScrollsToShowFirstLogicalRow || !firstVisualRowIsRemoved)) {
- /*
- * rows were removed from above the viewport, so all we need
- * to do is to adjust the scroll position to account for the
- * removed rows
- */
- adjustScrollPosIgnoreEvents(-yDelta);
- } else if (removalScrollsToShowFirstLogicalRow) {
- /*
- * It seems like we've removed all rows from above, and also
- * into the current viewport. This means we'll need to even
- * out the scroll position to exactly 0 (i.e. adjust by the
- * current negative scrolltop, presto!), so that it isn't
- * aligned funnily
- */
- adjustScrollPosIgnoreEvents(-verticalScrollbar
- .getScrollPos());
- }
- }
-
- // ranges evaluated, let's do things.
- if (!removedVisualInside.isEmpty()) {
- int escalatorRowCount = bodyElem.getChildCount();
-
- /*
- * If we're left with less rows than the number of escalators,
- * remove the unused ones.
- */
- final int escalatorRowsToRemove = escalatorRowCount
- - getRowCount();
- if (escalatorRowsToRemove > 0) {
- for (int i = 0; i < escalatorRowsToRemove; i++) {
- final Element tr = visualRowOrder
- .remove(removedVisualInside.getStart());
- for (int c = 0; c < tr.getChildCount(); c++) {
- detachPossibleWidgetFromCell((Element) tr.getChild(
- c).cast());
- }
- tr.removeFromParent();
- removeRowPosition(tr);
- }
- escalatorRowCount -= escalatorRowsToRemove;
-
- /*
- * Because we're removing escalator rows, we don't have
- * anything to scroll by. Let's make sure the viewport is
- * scrolled to top, to render any rows possibly left above.
- */
- body.setBodyScrollPosition(tBodyScrollLeft, 0);
-
- /*
- * We might have removed some rows from the middle, so let's
- * make sure we're not left with any holes. Also remember:
- * visualIndex == logicalIndex applies now.
- */
- final int dirtyRowsStart = removedLogicalInside.getStart();
- for (int i = dirtyRowsStart; i < escalatorRowCount; i++) {
- final Element tr = visualRowOrder.get(i);
- /*
- * FIXME [[rowheight]]: coded to work only with default
- * row heights - will not work with variable row heights
- */
- setRowPosition(tr, 0, i * getDefaultRowHeight());
- }
-
- /*
- * this is how many rows appeared into the viewport from
- * below
- */
- final int rowsToUpdateDataOn = numberOfRows
- - escalatorRowsToRemove;
- final int start = Math.max(0, escalatorRowCount
- - rowsToUpdateDataOn);
- final int end = escalatorRowCount;
- for (int i = start; i < end; i++) {
- final Element tr = visualRowOrder.get(i);
- refreshRow(tr, i);
- }
- }
-
- else {
- // No escalator rows need to be removed.
-
- /*
- * Two things (or a combination thereof) can happen:
- *
- * 1) We're scrolled to the bottom, the last rows are
- * removed. SOLUTION: moveAndUpdateEscalatorRows the
- * bottommost rows, and place them at the top to be
- * refreshed.
- *
- * 2) We're scrolled somewhere in the middle, arbitrary rows
- * are removed. SOLUTION: moveAndUpdateEscalatorRows the
- * removed rows, and place them at the bottom to be
- * refreshed.
- *
- * Since a combination can also happen, we need to handle
- * this in a smart way, all while avoiding
- * double-refreshing.
- */
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- final int contentBottom = getRowCount()
- * getDefaultRowHeight();
- final int viewportBottom = (int) (tBodyScrollTop + calculateHeight());
- if (viewportBottom <= contentBottom) {
- /*
- * We're in the middle of the row container, everything
- * is added to the bottom
- */
- paintRemoveRowsAtMiddle(removedLogicalInside,
- removedVisualInside, 0);
- }
-
- else if (contentBottom
- + (numberOfRows * getDefaultRowHeight())
- - viewportBottom < getDefaultRowHeight()) {
- /*
- * FIXME [[rowheight]]: above coded to work only with
- * default row heights - will not work with variable row
- * heights
- */
-
- /*
- * We're at the end of the row container, everything is
- * added to the top.
- */
- paintRemoveRowsAtBottom(removedLogicalInside,
- removedVisualInside);
- updateTopRowLogicalIndex(-removedLogicalInside.length());
- }
-
- else {
- /*
- * We're in a combination, where we need to both scroll
- * up AND show new rows at the bottom.
- *
- * Example: Scrolled down to show the second to last
- * row. Remove two. Viewport scrolls up, revealing the
- * row above row. The last element collapses up and into
- * view.
- *
- * Reminder: this use case handles only the case when
- * there are enough escalator rows to still render a
- * full view. I.e. all escalator rows will _always_ be
- * populated
- */
- /*-
- * 1 1 |1| <- newly rendered
- * |2| |2| |2|
- * |3| ==> |*| ==> |5| <- newly rendered
- * |4| |*|
- * 5 5
- *
- * 1 1 |1| <- newly rendered
- * |2| |*| |4|
- * |3| ==> |*| ==> |5| <- newly rendered
- * |4| |4|
- * 5 5
- */
-
- /*
- * STEP 1:
- *
- * reorganize deprecated escalator rows to bottom, but
- * don't re-render anything yet
- */
- /*-
- * 1 1 1
- * |2| |*| |4|
- * |3| ==> |*| ==> |*|
- * |4| |4| |*|
- * 5 5 5
- */
- int newTop = getRowTop(visualRowOrder
- .get(removedVisualInside.getStart()));
- for (int i = 0; i < removedVisualInside.length(); i++) {
- final Element tr = visualRowOrder
- .remove(removedVisualInside.getStart());
- visualRowOrder.addLast(tr);
- }
-
- for (int i = removedVisualInside.getStart(); i < escalatorRowCount; i++) {
- final Element tr = visualRowOrder.get(i);
- setRowPosition(tr, 0, newTop);
-
- /*
- * FIXME [[rowheight]]: coded to work only with
- * default row heights - will not work with variable
- * row heights
- */
- newTop += getDefaultRowHeight();
- }
-
- /*
- * STEP 2:
- *
- * manually scroll
- */
- /*-
- * 1 |1| <-- newly rendered (by scrolling)
- * |4| |4|
- * |*| ==> |*|
- * |*|
- * 5 5
- */
- final double newScrollTop = contentBottom
- - calculateHeight();
- setScrollTop(newScrollTop);
- /*
- * Manually call the scroll handler, so we get immediate
- * effects in the escalator.
- */
- scroller.onScroll();
- internalScrollEventCalls++;
-
- /*
- * Move the bottommost (n+1:th) escalator row to top,
- * because scrolling up doesn't handle that for us
- * automatically
- */
- moveAndUpdateEscalatorRows(
- Range.withOnly(escalatorRowCount - 1),
- 0,
- getLogicalRowIndex(visualRowOrder.getFirst()) - 1);
- updateTopRowLogicalIndex(-1);
-
- /*
- * STEP 3:
- *
- * update remaining escalator rows
- */
- /*-
- * |1| |1|
- * |4| ==> |4|
- * |*| |5| <-- newly rendered
- *
- * 5
- */
-
- /*
- * FIXME [[rowheight]]: coded to work only with default
- * row heights - will not work with variable row heights
- */
- final int rowsScrolled = (int) (Math
- .ceil((viewportBottom - (double) contentBottom)
- / getDefaultRowHeight()));
- final int start = escalatorRowCount
- - (removedVisualInside.length() - rowsScrolled);
- final Range visualRefreshRange = Range.between(start,
- escalatorRowCount);
- final int logicalTargetIndex = getLogicalRowIndex(visualRowOrder
- .getFirst()) + start;
- // in-place move simply re-renders the rows.
- moveAndUpdateEscalatorRows(visualRefreshRange, start,
- logicalTargetIndex);
- }
- }
- }
-
- updateTopRowLogicalIndex(-removedAbove.length());
-
- /*
- * this needs to be done after the escalator has been shrunk down,
- * or it won't work correctly (due to setScrollTop invocation)
- */
- scroller.recalculateScrollbarsForVirtualViewport();
-
- fireRowVisibilityChangeEvent();
- }
-
- private void paintRemoveRowsAtMiddle(final Range removedLogicalInside,
- final Range removedVisualInside, final int logicalOffset) {
- /*-
- * : : :
- * |2| |2| |2|
- * |3| ==> |*| ==> |4|
- * |4| |4| |6| <- newly rendered
- * : : :
- */
-
- final int escalatorRowCount = visualRowOrder.size();
-
- final int logicalTargetIndex = getLogicalRowIndex(visualRowOrder
- .getLast())
- - (removedVisualInside.length() - 1)
- + logicalOffset;
- moveAndUpdateEscalatorRows(removedVisualInside, escalatorRowCount,
- logicalTargetIndex);
-
- // move the surrounding rows to their correct places.
- final ListIterator<Element> iterator = visualRowOrder
- .listIterator(removedVisualInside.getStart());
-
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- int rowTop = (removedLogicalInside.getStart() + logicalOffset)
- * getDefaultRowHeight();
- for (int i = removedVisualInside.getStart(); i < escalatorRowCount
- - removedVisualInside.length(); i++) {
- final Element tr = iterator.next();
- setRowPosition(tr, 0, rowTop);
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- rowTop += getDefaultRowHeight();
- }
- }
-
- private void paintRemoveRowsAtBottom(final Range removedLogicalInside,
- final Range removedVisualInside) {
- /*-
- * :
- * : : |4| <- newly rendered
- * |5| |5| |5|
- * |6| ==> |*| ==> |7|
- * |7| |7|
- */
-
- final int logicalTargetIndex = getLogicalRowIndex(visualRowOrder
- .getFirst()) - removedVisualInside.length();
- moveAndUpdateEscalatorRows(removedVisualInside, 0,
- logicalTargetIndex);
-
- // move the surrounding rows to their correct places.
- final ListIterator<Element> iterator = visualRowOrder
- .listIterator(removedVisualInside.getEnd());
- /*
- * FIXME [[rowheight]]: coded to work only with default row heights
- * - will not work with variable row heights
- */
- int rowTop = removedLogicalInside.getStart()
- * getDefaultRowHeight();
- while (iterator.hasNext()) {
- final Element tr = iterator.next();
- setRowPosition(tr, 0, rowTop);
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- rowTop += getDefaultRowHeight();
- }
- }
-
- private int getLogicalRowIndex(final Element element) {
- assert element.getParentNode() == root : "The given element isn't a row element in the body";
- int internalIndex = visualRowOrder.indexOf(element);
- return getTopRowLogicalIndex() + internalIndex;
- }
-
- @Override
- protected void recalculateSectionHeight() {
- // NOOP for body, since it doesn't make any sense.
- }
-
- /**
- * Adjusts the row index and number to be relevant for the current
- * virtual viewport.
- * <p>
- * It converts a logical range of rows index to the matching visual
- * range, truncating the resulting range with the viewport.
- * <p>
- * <ul>
- * <li>Escalator contains logical rows 0..100
- * <li>Current viewport showing logical rows 20..29
- * <li>convertToVisual([20..29]) &rarr; [0..9]
- * <li>convertToVisual([15..24]) &rarr; [0..4]
- * <li>convertToVisual([25..29]) &rarr; [5..9]
- * <li>convertToVisual([26..39]) &rarr; [6..9]
- * <li>convertToVisual([0..5]) &rarr; [0..-1] <em>(empty)</em>
- * <li>convertToVisual([35..1]) &rarr; [0..-1] <em>(empty)</em>
- * <li>convertToVisual([0..100]) &rarr; [0..9]
- * </ul>
- *
- * @return a logical range converted to a visual range, truncated to the
- * current viewport. The first visual row has the index 0.
- */
- private Range convertToVisual(final Range logicalRange) {
- if (logicalRange.isEmpty()) {
- return logicalRange;
- } else if (visualRowOrder.isEmpty()) {
- // empty range
- return Range.withLength(0, 0);
- }
-
- /*
- * TODO [[rowheight]]: these assumptions will be totally broken with
- * variable row heights.
- */
- final int maxEscalatorRows = getMaxEscalatorRowCapacity();
- final int currentTopRowIndex = getLogicalRowIndex(visualRowOrder
- .getFirst());
-
- final Range[] partitions = logicalRange.partitionWith(Range
- .withLength(currentTopRowIndex, maxEscalatorRows));
- final Range insideRange = partitions[1];
- return insideRange.offsetBy(-currentTopRowIndex);
- }
-
- @Override
- protected String getCellElementTagName() {
- return "td";
- }
-
- /**
- * Calculates the height of the {@code <tbody>} as it should be rendered
- * in the DOM.
- */
- private double calculateHeight() {
- final int tableHeight = tableWrapper.getOffsetHeight();
- final double footerHeight = footer.heightOfSection;
- final double headerHeight = header.heightOfSection;
- return tableHeight - footerHeight - headerHeight;
- }
-
- @Override
- public void refreshRows(final int index, final int numberOfRows) {
- Profiler.enter("Escalator.BodyRowContainer.refreshRows");
-
- final Range visualRange = convertToVisual(Range.withLength(index,
- numberOfRows));
-
- if (!visualRange.isEmpty()) {
- final int firstLogicalRowIndex = getLogicalRowIndex(visualRowOrder
- .getFirst());
- for (int rowNumber = visualRange.getStart(); rowNumber < visualRange
- .getEnd(); rowNumber++) {
- refreshRow(visualRowOrder.get(rowNumber),
- firstLogicalRowIndex + rowNumber);
- }
- }
-
- Profiler.leave("Escalator.BodyRowContainer.refreshRows");
- }
-
- @Override
- protected Element getTrByVisualIndex(final int index)
- throws IndexOutOfBoundsException {
- if (index >= 0 && index < visualRowOrder.size()) {
- return visualRowOrder.get(index);
- } else {
- throw new IndexOutOfBoundsException("No such visual index: "
- + index);
- }
- }
-
- private void setBodyScrollPosition(final int scrollLeft,
- final int scrollTop) {
- tBodyScrollLeft = scrollLeft;
- tBodyScrollTop = scrollTop;
- position.set(bodyElem, -tBodyScrollLeft, -tBodyScrollTop);
- }
-
- /**
- * Make sure that there is a correct amount of escalator rows: Add more
- * if needed, or remove any superfluous ones.
- * <p>
- * This method should be called when e.g. the height of the Escalator
- * changes.
- * <p>
- * <em>Note:</em> This method will make sure that the escalator rows are
- * placed in the proper places. By default new rows are added below, but
- * if the content is scrolled down, the rows are populated on top
- * instead.
- */
- public void verifyEscalatorCount() {
- /*
- * This method indeed has a smell very similar to paintRemoveRows
- * and paintInsertRows.
- *
- * Unfortunately, those the code can't trivially be shared, since
- * there are some slight differences in the respective
- * responsibilities. The "paint" methods fake the addition and
- * removal of rows, and make sure to either push existing data out
- * of view, or draw new data into view. Only in some special cases
- * will the DOM element count change.
- *
- * This method, however, has the explicit responsibility to verify
- * that when "something" happens, we still have the correct amount
- * of escalator rows in the DOM, and if not, we make sure to modify
- * that count. Only in some special cases do we need to take into
- * account other things than simply modifying the DOM element count.
- */
-
- Profiler.enter("Escalator.BodyRowContainer.verifyEscalatorCount");
-
- if (!isAttached()) {
- return;
- }
-
- final int maxEscalatorRows = getMaxEscalatorRowCapacity();
- final int neededEscalatorRows = Math.min(maxEscalatorRows,
- body.getRowCount());
- final int neededEscalatorRowsDiff = neededEscalatorRows
- - visualRowOrder.size();
-
- if (neededEscalatorRowsDiff > 0) {
- // needs more
-
- /*
- * This is a workaround for the issue where we might be scrolled
- * to the bottom, and the widget expands beyond the content
- * range
- */
-
- final int index = visualRowOrder.size();
- final int nextLastLogicalIndex;
- if (!visualRowOrder.isEmpty()) {
- nextLastLogicalIndex = getLogicalRowIndex(visualRowOrder
- .getLast()) + 1;
- } else {
- nextLastLogicalIndex = 0;
- }
-
- final boolean contentWillFit = nextLastLogicalIndex < getRowCount()
- - neededEscalatorRowsDiff;
- if (contentWillFit) {
- final List<Element> addedRows = fillAndPopulateEscalatorRowsIfNeeded(
- index, neededEscalatorRowsDiff);
-
- /*
- * Since fillAndPopulateEscalatorRowsIfNeeded operates on
- * the assumption that index == visual index == logical
- * index, we thank for the added escalator rows, but since
- * they're painted in the wrong CSS position, we need to
- * move them to their actual locations.
- *
- * Note: this is the second (see body.paintInsertRows)
- * occasion where fillAndPopulateEscalatorRowsIfNeeded would
- * behave "more correctly" if it only would add escalator
- * rows to the DOM and appropriate bookkeping, and not
- * actually populate them :/
- */
- moveAndUpdateEscalatorRows(
- Range.withLength(index, addedRows.size()), index,
- nextLastLogicalIndex);
- } else {
- /*
- * TODO [[optimize]]
- *
- * We're scrolled so far down that all rows can't be simply
- * appended at the end, since we might start displaying
- * escalator rows that don't exist. To avoid the mess that
- * is body.paintRemoveRows, this is a dirty hack that dumbs
- * the problem down to a more basic and already-solved
- * problem:
- *
- * 1) scroll all the way up 2) add the missing escalator
- * rows 3) scroll back to the original position.
- *
- * Letting the browser scroll back to our original position
- * will automatically solve any possible overflow problems,
- * since the browser will not allow us to scroll beyond the
- * actual content.
- */
-
- final double oldScrollTop = getScrollTop();
- setScrollTop(0);
- scroller.onScroll();
- fillAndPopulateEscalatorRowsIfNeeded(index,
- neededEscalatorRowsDiff);
- setScrollTop(oldScrollTop);
- scroller.onScroll();
- internalScrollEventCalls++;
- }
- }
-
- else if (neededEscalatorRowsDiff < 0) {
- // needs less
-
- final ListIterator<Element> iter = visualRowOrder
- .listIterator(visualRowOrder.size());
- for (int i = 0; i < -neededEscalatorRowsDiff; i++) {
- final Element last = iter.previous();
- for (int c = 0; c < last.getChildCount(); c++) {
- detachPossibleWidgetFromCell((Element) last.getChild(c)
- .cast());
- }
- last.removeFromParent();
- iter.remove();
- }
-
- /*
- * If we were scrolled to the bottom so that we didn't have an
- * extra escalator row at the bottom, we'll probably end up with
- * blank space at the bottom of the escalator, and one extra row
- * above the header.
- *
- * Experimentation idea #1: calculate "scrollbottom" vs content
- * bottom and remove one row from top, rest from bottom. This
- * FAILED, since setHeight has already happened, thus we never
- * will detect ourselves having been scrolled all the way to the
- * bottom.
- */
-
- if (!visualRowOrder.isEmpty()) {
- final int firstRowTop = getRowTop(visualRowOrder.getFirst());
- /*
- * FIXME [[rowheight]]: coded to work only with default row
- * heights - will not work with variable row heights
- */
- final double firstRowMinTop = tBodyScrollTop
- - getDefaultRowHeight();
- if (firstRowTop < firstRowMinTop) {
- final int newLogicalIndex = getLogicalRowIndex(visualRowOrder
- .getLast()) + 1;
- moveAndUpdateEscalatorRows(Range.withOnly(0),
- visualRowOrder.size(), newLogicalIndex);
- }
- }
- }
-
- if (neededEscalatorRowsDiff != 0) {
- fireRowVisibilityChangeEvent();
- }
-
- Profiler.leave("Escalator.BodyRowContainer.verifyEscalatorCount");
- }
-
- @Override
- protected void reapplyDefaultRowHeights() {
- if (visualRowOrder.isEmpty()) {
- return;
- }
-
- /*
- * As an intermediate step between hard-coded row heights to crazily
- * varying row heights, Escalator will support the modification of
- * the default row height (which is applied to all rows).
- *
- * This allows us to do some assumptions and simplifications for
- * now. This code is intended to be quite short-lived, but gives
- * insight into what needs to be done when row heights change in the
- * body, in a general sense.
- *
- * TODO [[rowheight]] remove this comment once row heights may
- * genuinely vary.
- */
-
- Profiler.enter("Escalator.BodyRowContainer.reapplyDefaultRowHeights");
-
- /* step 1: resize and reposition rows */
- for (int i = 0; i < visualRowOrder.size(); i++) {
- Element tr = visualRowOrder.get(i);
- reapplyRowHeight(tr, getDefaultRowHeight());
-
- final int logicalIndex = getTopRowLogicalIndex() + i;
- setRowPosition(tr, 0, logicalIndex * getDefaultRowHeight());
- }
-
- /*
- * step 2: move scrollbar so that it corresponds to its previous
- * place
- */
-
- /*
- * This ratio needs to be calculated with the scrollsize (not max
- * scroll position) in order to align the top row with the new
- * scroll position.
- */
- double scrollRatio = (double) verticalScrollbar.getScrollPos()
- / (double) verticalScrollbar.getScrollSize();
- scroller.recalculateScrollbarsForVirtualViewport();
- internalScrollEventCalls++;
- verticalScrollbar.setScrollPos((int) (getDefaultRowHeight()
- * getRowCount() * scrollRatio));
- setBodyScrollPosition(horizontalScrollbar.getScrollPos(),
- verticalScrollbar.getScrollPos());
- scroller.onScroll();
-
- /* step 3: make sure we have the correct amount of escalator rows. */
- verifyEscalatorCount();
-
- /*
- * TODO [[rowheight]] This simply doesn't work with variable rows
- * heights.
- */
- setTopRowLogicalIndex(getRowTop(visualRowOrder.getFirst())
- / getDefaultRowHeight());
-
- Profiler.leave("Escalator.BodyRowContainer.reapplyDefaultRowHeights");
- }
- }
-
- private class ColumnConfigurationImpl implements ColumnConfiguration {
- public class Column {
- private static final int DEFAULT_COLUMN_WIDTH_PX = 100;
-
- private int definedWidth = -1;
- private int calculatedWidth = DEFAULT_COLUMN_WIDTH_PX;
-
- public void setWidth(int px) {
- definedWidth = px;
- calculatedWidth = (px >= 0) ? px : DEFAULT_COLUMN_WIDTH_PX;
- }
-
- public int getDefinedWidth() {
- return definedWidth;
- }
-
- public int getCalculatedWidth() {
- return calculatedWidth;
- }
- }
-
- private final List<Column> columns = new ArrayList<Column>();
- private int frozenColumns = 0;
-
- /**
- * A cached array of all the calculated column widths.
- *
- * @see #getCalculatedColumnWidths()
- */
- private int[] widthsArray = null;
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there are no rows in the DOM when
- * this method is called.
- *
- * @see #hasSomethingInDom()
- */
- @Override
- public void removeColumns(final int index, final int numberOfColumns) {
- assertArgumentsAreValidAndWithinRange(index, numberOfColumns);
-
- flyweightRow.removeCells(index, numberOfColumns);
-
- // Cope with removing frozen columns
- if (index < frozenColumns) {
- if (index + numberOfColumns < frozenColumns) {
- /*
- * Last removed column was frozen, meaning that all removed
- * columns were frozen. Just decrement the number of frozen
- * columns accordingly.
- */
- frozenColumns -= numberOfColumns;
- } else {
- /*
- * If last removed column was not frozen, we have removed
- * columns beyond the frozen range, so all remaining frozen
- * columns are to the left of the removed columns.
- */
- frozenColumns = index;
- }
- }
-
- List<Column> removedColumns = new ArrayList<Column>();
- for (int i = 0; i < numberOfColumns; i++) {
- removedColumns.add(columns.remove(index));
- }
-
- if (hasSomethingInDom()) {
- for (final AbstractRowContainer rowContainer : rowContainers) {
- rowContainer.paintRemoveColumns(index, numberOfColumns,
- removedColumns);
- }
- }
- }
-
- /**
- * Calculate the width of a row, as the sum of columns' widths.
- *
- * @return the width of a row, in pixels
- */
- public int calculateRowWidth() {
- return getCalculatedColumnsWidth(Range.between(0, getColumnCount()));
- }
-
- private void assertArgumentsAreValidAndWithinRange(final int index,
- final int numberOfColumns) {
- if (numberOfColumns < 1) {
- throw new IllegalArgumentException(
- "Number of columns can't be less than 1 (was "
- + numberOfColumns + ")");
- }
-
- if (index < 0 || index + numberOfColumns > getColumnCount()) {
- throw new IndexOutOfBoundsException("The given "
- + "column range (" + index + ".."
- + (index + numberOfColumns)
- + ") was outside of the current "
- + "number of columns (" + getColumnCount() + ")");
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * <em>Implementation detail:</em> This method does no DOM modifications
- * (i.e. is very cheap to call) if there is no data for rows when this
- * method is called.
- *
- * @see #hasColumnAndRowData()
- */
- @Override
- public void insertColumns(final int index, final int numberOfColumns) {
- if (index < 0 || index > getColumnCount()) {
- throw new IndexOutOfBoundsException("The given index(" + index
- + ") was outside of the current number of columns (0.."
- + getColumnCount() + ")");
- }
-
- if (numberOfColumns < 1) {
- throw new IllegalArgumentException(
- "Number of columns must be 1 or greater (was "
- + numberOfColumns);
- }
-
- flyweightRow.addCells(index, numberOfColumns);
-
- for (int i = 0; i < numberOfColumns; i++) {
- columns.add(index, new Column());
- }
-
- // Either all or none of the new columns are frozen
- boolean frozen = index < frozenColumns;
- if (frozen) {
- frozenColumns += numberOfColumns;
- }
-
- if (hasColumnAndRowData()) {
- for (final AbstractRowContainer rowContainer : rowContainers) {
- rowContainer.paintInsertColumns(index, numberOfColumns,
- frozen);
- }
- }
- }
-
- @Override
- public int getColumnCount() {
- return columns.size();
- }
-
- @Override
- public void setFrozenColumnCount(int count)
- throws IllegalArgumentException {
- if (count < 0 || count > getColumnCount()) {
- throw new IllegalArgumentException(
- "count must be between 0 and the current number of columns ("
- + columns + ")");
- }
- int oldCount = frozenColumns;
- if (count == oldCount) {
- return;
- }
-
- frozenColumns = count;
-
- if (hasSomethingInDom()) {
- // Are we freezing or unfreezing?
- boolean frozen = count > oldCount;
-
- int firstAffectedCol;
- int firstUnaffectedCol;
-
- if (frozen) {
- firstAffectedCol = oldCount;
- firstUnaffectedCol = count;
- } else {
- firstAffectedCol = count;
- firstUnaffectedCol = oldCount;
- }
-
- for (int col = firstAffectedCol; col < firstUnaffectedCol; col++) {
- header.setColumnFrozen(col, frozen);
- body.setColumnFrozen(col, frozen);
- footer.setColumnFrozen(col, frozen);
- }
- }
-
- scroller.recalculateScrollbarsForVirtualViewport();
- }
-
- @Override
- public int getFrozenColumnCount() {
- return frozenColumns;
- }
-
- @Override
- public void setColumnWidth(int index, int px)
- throws IllegalArgumentException {
- checkValidColumnIndex(index);
-
- columns.get(index).setWidth(px);
- widthsArray = null;
-
- /*
- * TODO [[optimize]]: only modify the elements that are actually
- * modified.
- */
- header.reapplyColumnWidths();
- body.reapplyColumnWidths();
- footer.reapplyColumnWidths();
- recalculateElementSizes();
- }
-
- private void checkValidColumnIndex(int index)
- throws IllegalArgumentException {
- if (!Range.withLength(0, getColumnCount()).contains(index)) {
- throw new IllegalArgumentException("The given column index ("
- + index + ") does not exist");
- }
- }
-
- @Override
- public int getColumnWidth(int index) throws IllegalArgumentException {
- checkValidColumnIndex(index);
- return columns.get(index).getDefinedWidth();
- }
-
- @Override
- public int getColumnWidthActual(int index) {
- return columns.get(index).getCalculatedWidth();
- }
-
- /**
- * Calculates the width of the columns in a given range.
- *
- * @param columns
- * the columns to calculate
- * @return the total width of the columns in the given
- * <code>columns</code>
- */
- int getCalculatedColumnsWidth(@SuppressWarnings("hiding")
- final Range columns) {
- /*
- * This is an assert instead of an exception, since this is an
- * internal method.
- */
- assert columns.isSubsetOf(Range.between(0, getColumnCount())) : "Range "
- + "was outside of current column range (i.e.: "
- + Range.between(0, getColumnCount())
- + ", but was given :"
- + columns;
-
- int sum = 0;
- for (int i = columns.getStart(); i < columns.getEnd(); i++) {
- sum += getColumnWidthActual(i);
- }
- return sum;
- }
-
- void setCalculatedColumnWidth(int index, int width) {
- columns.get(index).calculatedWidth = width;
- widthsArray = null;
- }
-
- int[] getCalculatedColumnWidths() {
- if (widthsArray == null || widthsArray.length != getColumnCount()) {
- widthsArray = new int[getColumnCount()];
- for (int i = 0; i < columns.size(); i++) {
- widthsArray[i] = columns.get(i).getCalculatedWidth();
- }
- }
- return widthsArray;
- }
- }
-
- // abs(atan(y/x))*(180/PI) = n deg, x = 1, solve y
- /**
- * The solution to
- * <code>|tan<sup>-1</sup>(<i>x</i>)|&times;(180/&pi;)&nbsp;=&nbsp;30</code>
- * .
- * <p>
- * This constant is placed in the Escalator class, instead of an inner
- * class, since even mathematical expressions aren't allowed in non-static
- * inner classes for constants.
- */
- private static final double RATIO_OF_30_DEGREES = 1 / Math.sqrt(3);
- /**
- * The solution to
- * <code>|tan<sup>-1</sup>(<i>x</i>)|&times;(180/&pi;)&nbsp;=&nbsp;40</code>
- * .
- * <p>
- * This constant is placed in the Escalator class, instead of an inner
- * class, since even mathematical expressions aren't allowed in non-static
- * inner classes for constants.
- */
- private static final double RATIO_OF_40_DEGREES = Math.tan(2 * Math.PI / 9);
-
- private static final String DEFAULT_WIDTH = "400.0px";
- private static final String DEFAULT_HEIGHT = "400.0px";
-
- private FlyweightRow flyweightRow = new FlyweightRow(this);
-
- /** The {@code <thead/>} tag. */
- private final Element headElem = DOM.createTHead();
- /** The {@code <tbody/>} tag. */
- private final Element bodyElem = DOM.createTBody();
- /** The {@code <tfoot/>} tag. */
- private final Element footElem = DOM.createTFoot();
-
- /**
- * TODO: investigate whether this field is now unnecessary, as
- * {@link ScrollbarBundle} now caches its values.
- *
- * @deprecated maybe...
- */
- @Deprecated
- private int tBodyScrollTop = 0;
-
- /**
- * TODO: investigate whether this field is now unnecessary, as
- * {@link ScrollbarBundle} now caches its values.
- *
- * @deprecated maybe...
- */
- @Deprecated
- private int tBodyScrollLeft = 0;
-
- private final VerticalScrollbarBundle verticalScrollbar = new VerticalScrollbarBundle();
- private final HorizontalScrollbarBundle horizontalScrollbar = new HorizontalScrollbarBundle();
-
- private final HeaderRowContainer header = new HeaderRowContainer(headElem);
- private final BodyRowContainer body = new BodyRowContainer(bodyElem);
- private final FooterRowContainer footer = new FooterRowContainer(footElem);
-
- private final Scroller scroller = new Scroller();
-
- private final AbstractRowContainer[] rowContainers = new AbstractRowContainer[] {
- header, body, footer };
-
- private final ColumnConfigurationImpl columnConfiguration = new ColumnConfigurationImpl();
- private final Element tableWrapper;
-
- private PositionFunction position;
-
- private int internalScrollEventCalls = 0;
-
- /** The cached width of the escalator, in pixels. */
- private double widthOfEscalator;
- /** The cached height of the escalator, in pixels. */
- private double heightOfEscalator;
-
- private static native double getPreciseWidth(Element element)
- /*-{
- if (element.getBoundingClientRect) {
- var rect = element.getBoundingClientRect();
- return rect.right - rect.left;
- } else {
- return element.offsetWidth;
- }
- }-*/;
-
- private static native double getPreciseHeight(Element element)
- /*-{
- if (element.getBoundingClientRect) {
- var rect = element.getBoundingClientRect();
- return rect.bottom - rect.top;
- } else {
- return element.offsetHeight;
- }
- }-*/;
-
- /**
- * Creates a new Escalator widget instance.
- */
- public Escalator() {
-
- detectAndApplyPositionFunction();
- getLogger().info(
- "Using " + position.getClass().getSimpleName()
- + " for position");
-
- final Element root = DOM.createDiv();
- setElement(root);
-
- root.appendChild(verticalScrollbar.getElement());
- root.appendChild(horizontalScrollbar.getElement());
- verticalScrollbar.setScrollbarThickness(Util.getNativeScrollbarSize());
- horizontalScrollbar
- .setScrollbarThickness(Util.getNativeScrollbarSize());
-
- tableWrapper = DOM.createDiv();
-
- root.appendChild(tableWrapper);
-
- final Element table = DOM.createTable();
- tableWrapper.appendChild(table);
-
- table.appendChild(headElem);
- table.appendChild(bodyElem);
- table.appendChild(footElem);
-
- setStylePrimaryName("v-escalator");
-
- // init default dimensions
- setHeight(null);
- setWidth(null);
- }
-
- @Override
- protected void onLoad() {
- super.onLoad();
-
- header.autodetectRowHeight();
- body.autodetectRowHeight();
- footer.autodetectRowHeight();
-
- header.paintInsertRows(0, header.getRowCount());
- footer.paintInsertRows(0, footer.getRowCount());
- recalculateElementSizes();
- /*
- * Note: There's no need to explicitly insert rows into the body.
- *
- * recalculateElementSizes will recalculate the height of the body. This
- * has the side-effect that as the body's size grows bigger (i.e. from 0
- * to its actual height), more escalator rows are populated. Those
- * escalator rows are then immediately rendered. This, in effect, is the
- * same thing as inserting those rows.
- *
- * In fact, having an extra paintInsertRows here would lead to duplicate
- * rows.
- */
-
- scroller.attachScrollListener(verticalScrollbar.getElement());
- scroller.attachScrollListener(horizontalScrollbar.getElement());
- scroller.attachMousewheelListener(getElement());
- scroller.attachTouchListeners(getElement());
- }
-
- @Override
- protected void onUnload() {
-
- scroller.detachScrollListener(verticalScrollbar.getElement());
- scroller.detachScrollListener(horizontalScrollbar.getElement());
- scroller.detachMousewheelListener(getElement());
- scroller.detachTouchListeners(getElement());
-
- header.paintRemoveRows(0, header.getRowCount());
- footer.paintRemoveRows(0, footer.getRowCount());
- body.paintRemoveRows(0, body.getRowCount());
-
- super.onUnload();
- }
-
- private void detectAndApplyPositionFunction() {
- /*
- * firefox has a bug in its translate operation, showing white space
- * when adjusting the scrollbar in BodyRowContainer.paintInsertRows
- */
- if (Window.Navigator.getUserAgent().contains("Firefox")) {
- position = new AbsolutePosition();
- return;
- }
-
- final Style docStyle = Document.get().getBody().getStyle();
- if (hasProperty(docStyle, "transform")) {
- if (hasProperty(docStyle, "transformStyle")) {
- position = new Translate3DPosition();
- } else {
- position = new TranslatePosition();
- }
- } else if (hasProperty(docStyle, "webkitTransform")) {
- position = new WebkitTranslate3DPosition();
- } else {
- position = new AbsolutePosition();
- }
- }
-
- private Logger getLogger() {
- return Logger.getLogger(getClass().getName());
- }
-
- private static native boolean hasProperty(Style style, String name)
- /*-{
- return style[name] !== undefined;
- }-*/;
-
- /**
- * Check whether there are both columns and any row data (for either
- * headers, body or footer).
- *
- * @return <code>true</code> iff header, body or footer has rows && there
- * are columns
- */
- private boolean hasColumnAndRowData() {
- return (header.getRowCount() > 0 || body.getRowCount() > 0 || footer
- .getRowCount() > 0) && columnConfiguration.getColumnCount() > 0;
- }
-
- /**
- * Check whether there are any cells in the DOM.
- *
- * @return <code>true</code> iff header, body or footer has any child
- * elements
- */
- private boolean hasSomethingInDom() {
- return headElem.hasChildNodes() || bodyElem.hasChildNodes()
- || footElem.hasChildNodes();
- }
-
- /**
- * Returns the representation of this Escalator header.
- *
- * @return the header. Never <code>null</code>
- */
- public RowContainer getHeader() {
- return header;
- }
-
- /**
- * Returns the representation of this Escalator body.
- *
- * @return the body. Never <code>null</code>
- */
- public RowContainer getBody() {
- return body;
- }
-
- /**
- * Returns the representation of this Escalator footer.
- *
- * @return the footer. Never <code>null</code>
- */
- public RowContainer getFooter() {
- return footer;
- }
-
- /**
- * Returns the configuration object for the columns in this Escalator.
- *
- * @return the configuration object for the columns in this Escalator. Never
- * <code>null</code>
- */
- public ColumnConfiguration getColumnConfiguration() {
- return columnConfiguration;
- }
-
- /*
- * TODO remove method once RequiresResize and the Vaadin layoutmanager
- * listening mechanisms are implemented (https://trello.com/c/r3Kh0Kfy)
- */
- @Override
- public void setWidth(final String width) {
- super.setWidth(width != null && !width.isEmpty() ? width
- : DEFAULT_WIDTH);
- recalculateElementSizes();
- }
-
- /*
- * TODO remove method once RequiresResize and the Vaadin layoutmanager
- * listening mechanisms are implemented (https://trello.com/c/r3Kh0Kfy)
- */
- @Override
- public void setHeight(final String height) {
- final int escalatorRowsBefore = body.visualRowOrder.size();
-
- super.setHeight(height != null && !height.isEmpty() ? height
- : DEFAULT_HEIGHT);
- recalculateElementSizes();
-
- if (escalatorRowsBefore != body.visualRowOrder.size()) {
- fireRowVisibilityChangeEvent();
- }
- }
-
- /**
- * Returns the vertical scroll offset. Note that this is not necessarily the
- * same as the scroll top in the DOM
- *
- * @return the logical vertical scroll offset
- */
- public double getScrollTop() {
- return verticalScrollbar.getScrollPos();
- }
-
- /**
- * Sets the vertical scroll offset. Note that this is not necessarily the
- * same as the scroll top in the DOM
- *
- * @param scrollTop
- * the number of pixels to scroll vertically
- */
- public void setScrollTop(final double scrollTop) {
- verticalScrollbar.setScrollPos((int) scrollTop);
- }
-
- /**
- * Returns the logical horizontal scroll offset. Note that this is not
- * necessarily the same as the scroll left in the DOM.
- *
- * @return the logical horizontal scroll offset
- */
- public int getScrollLeft() {
- return horizontalScrollbar.getScrollPos();
- }
-
- /**
- * Sets the logical horizontal scroll offset. Note that this is not
- * necessarily the same as the scroll left in the DOM.
- *
- * @param scrollLeft
- * the number of pixels to scroll horizontally
- */
- public void setScrollLeft(final int scrollLeft) {
- horizontalScrollbar.setScrollPos(scrollLeft);
- }
-
- /**
- * Scrolls the body horizontally so that the column at the given index is
- * visible and there is at least {@code padding} pixels to the given scroll
- * destination.
- *
- * @param columnIndex
- * the index of the column to scroll to
- * @param destination
- * where the column should be aligned visually after scrolling
- * @param padding
- * the number pixels to place between the scrolled-to column and
- * the viewport edge.
- * @throws IndexOutOfBoundsException
- * if {@code columnIndex} is not a valid index for an existing
- * column
- * @throws IllegalArgumentException
- * if {@code destination} is {@link ScrollDestination#MIDDLE}
- * and padding is nonzero, because having a padding on a
- * centered column is undefined behavior, or if the column is
- * frozen
- */
- public void scrollToColumn(final int columnIndex,
- final ScrollDestination destination, final int padding)
- throws IndexOutOfBoundsException, IllegalArgumentException {
- if (destination == ScrollDestination.MIDDLE && padding != 0) {
- throw new IllegalArgumentException(
- "You cannot have a padding with a MIDDLE destination");
- }
- verifyValidColumnIndex(columnIndex);
-
- if (columnIndex < columnConfiguration.frozenColumns) {
- throw new IllegalArgumentException("The given column index "
- + columnIndex + " is frozen.");
- }
-
- scroller.scrollToColumn(columnIndex, destination, padding);
- }
-
- private void verifyValidColumnIndex(final int columnIndex)
- throws IndexOutOfBoundsException {
- if (columnIndex < 0
- || columnIndex >= columnConfiguration.getColumnCount()) {
- throw new IndexOutOfBoundsException("The given column index "
- + columnIndex + " does not exist.");
- }
- }
-
- /**
- * Scrolls the body vertically so that the row at the given index is visible
- * and there is at least {@literal padding} pixels to the given scroll
- * destination.
- *
- * @param rowIndex
- * the index of the logical row to scroll to
- * @param destination
- * where the row should be aligned visually after scrolling
- * @param padding
- * the number pixels to place between the scrolled-to row and the
- * viewport edge.
- * @throws IndexOutOfBoundsException
- * if {@code rowIndex} is not a valid index for an existing row
- * @throws IllegalArgumentException
- * if {@code destination} is {@link ScrollDestination#MIDDLE}
- * and padding is nonzero, because having a padding on a
- * centered row is undefined behavior
- */
- public void scrollToRow(final int rowIndex,
- final ScrollDestination destination, final int padding)
- throws IndexOutOfBoundsException, IllegalArgumentException {
- if (destination == ScrollDestination.MIDDLE && padding != 0) {
- throw new IllegalArgumentException(
- "You cannot have a padding with a MIDDLE destination");
- }
- verifyValidRowIndex(rowIndex);
-
- scroller.scrollToRow(rowIndex, destination, padding);
- }
-
- private void verifyValidRowIndex(final int rowIndex) {
- if (rowIndex < 0 || rowIndex >= body.getRowCount()) {
- throw new IndexOutOfBoundsException("The given row index "
- + rowIndex + " does not exist.");
- }
- }
-
- /**
- * Recalculates the dimensions for all elements that require manual
- * calculations. Also updates the dimension caches.
- * <p>
- * <em>Note:</em> This method has the <strong>side-effect</strong>
- * automatically makes sure that an appropriate amount of escalator rows are
- * present. So, if the body area grows, more <strong>escalator rows might be
- * inserted</strong>. Conversely, if the body area shrinks,
- * <strong>escalator rows might be removed</strong>.
- */
- private void recalculateElementSizes() {
- if (!isAttached()) {
- return;
- }
-
- Profiler.enter("Escalator.recalculateElementSizes");
- widthOfEscalator = getPreciseWidth(getElement());
- heightOfEscalator = getPreciseHeight(getElement());
- for (final AbstractRowContainer rowContainer : rowContainers) {
- rowContainer.recalculateSectionHeight();
- }
-
- scroller.recalculateScrollbarsForVirtualViewport();
- body.verifyEscalatorCount();
- Profiler.leave("Escalator.recalculateElementSizes");
- }
-
- /**
- * A routing method for {@link Scroller#onScroll(double, double)}.
- * <p>
- * This is a workaround for GWT and JSNI unable to properly handle inner
- * classes, so instead we call the outer class' method, which calls the
- * inner class' respective method.
- * <p>
- * Ideally, this method would not exist, and
- * {@link Scroller#onScroll(double, double)} would be called directly.
- */
- private void onScroll() {
- scroller.onScroll();
- }
-
- /**
- * Snap deltas of x and y to the major four axes (up, down, left, right)
- * with a threshold of a number of degrees from those axes.
- *
- * @param deltaX
- * the delta in the x axis
- * @param deltaY
- * the delta in the y axis
- * @param thresholdRatio
- * the threshold in ratio (0..1) between x and y for when to snap
- * @return a two-element array: <code>[snappedX, snappedY]</code>
- */
- private static double[] snapDeltas(final double deltaX,
- final double deltaY, final double thresholdRatio) {
-
- final double[] array = new double[2];
- if (deltaX != 0 && deltaY != 0) {
- final double aDeltaX = Math.abs(deltaX);
- final double aDeltaY = Math.abs(deltaY);
- final double yRatio = aDeltaY / aDeltaX;
- final double xRatio = aDeltaX / aDeltaY;
-
- array[0] = (xRatio < thresholdRatio) ? 0 : deltaX;
- array[1] = (yRatio < thresholdRatio) ? 0 : deltaY;
- } else {
- array[0] = deltaX;
- array[1] = deltaY;
- }
-
- return array;
- }
-
- /**
- * Adds an event handler that gets notified when the range of visible rows
- * changes e.g. because of scrolling.
- *
- * @param rowVisibilityChangeHandler
- * the event handler
- * @return a handler registration for the added handler
- */
- public HandlerRegistration addRowVisibilityChangeHandler(
- RowVisibilityChangeHandler rowVisibilityChangeHandler) {
- return addHandler(rowVisibilityChangeHandler,
- RowVisibilityChangeEvent.TYPE);
- }
-
- private void fireRowVisibilityChangeEvent() {
- if (!body.visualRowOrder.isEmpty()) {
- int visibleRangeStart = body.getLogicalRowIndex(body.visualRowOrder
- .getFirst());
- int visibleRangeEnd = body.getLogicalRowIndex(body.visualRowOrder
- .getLast()) + 1;
-
- int visibleRowCount = visibleRangeEnd - visibleRangeStart;
-
- fireEvent(new RowVisibilityChangeEvent(visibleRangeStart,
- visibleRowCount));
- } else {
- fireEvent(new RowVisibilityChangeEvent(0, 0));
- }
- }
-
- /**
- * Accesses the package private method Widget#setParent()
- *
- * @param widget
- * The widget to access
- * @param parent
- * The parent to set
- */
- static native final void setParent(Widget widget, Widget parent)
- /*-{
- widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
- }-*/;
-
- /**
- * Returns the widget from a cell node or <code>null</code> if there is no
- * widget in the cell
- *
- * @param cellNode
- * The cell node
- */
- static Widget getWidgetFromCell(Node cellNode) {
- Node possibleWidgetNode = cellNode.getFirstChild();
- if (possibleWidgetNode != null
- && possibleWidgetNode.getNodeType() == Node.ELEMENT_NODE) {
- @SuppressWarnings("deprecation")
- com.google.gwt.user.client.Element castElement = (com.google.gwt.user.client.Element) possibleWidgetNode
- .cast();
- return Util.findWidget(castElement, null);
- }
- return null;
- }
-
- /**
- * Forces the escalator to recalculate the widths of its columns.
- * <p>
- * All columns that haven't been assigned an explicit width will be resized
- * to fit all currently visible contents.
- *
- * @see ColumnConfiguration#setColumnWidth(int, int)
- */
- public void calculateColumnWidths() {
- boolean widthsHaveChanged = false;
- for (int colIndex = 0; colIndex < columnConfiguration.getColumnCount(); colIndex++) {
- if (columnConfiguration.getColumnWidth(colIndex) >= 0) {
- continue;
- }
-
- final int oldColumnWidth = columnConfiguration
- .getColumnWidthActual(colIndex);
-
- int maxColumnWidth = 0;
- maxColumnWidth = Math.max(maxColumnWidth,
- header.calculateMaxColWidth(colIndex));
- maxColumnWidth = Math.max(maxColumnWidth,
- body.calculateMaxColWidth(colIndex));
- maxColumnWidth = Math.max(maxColumnWidth,
- footer.calculateMaxColWidth(colIndex));
-
- Logger.getLogger("Escalator.calculateColumnWidths").info(
- "#" + colIndex + ": " + maxColumnWidth + "px");
-
- if (oldColumnWidth != maxColumnWidth) {
- columnConfiguration.setCalculatedColumnWidth(colIndex,
- maxColumnWidth);
- widthsHaveChanged = true;
- }
- }
-
- if (widthsHaveChanged) {
- header.reapplyColumnWidths();
- body.reapplyColumnWidths();
- footer.reapplyColumnWidths();
- recalculateElementSizes();
- }
- }
-
- @Override
- public void setStylePrimaryName(String style) {
- super.setStylePrimaryName(style);
-
- verticalScrollbar.setStylePrimaryName(style);
- horizontalScrollbar.setStylePrimaryName(style);
-
- UIObject.setStylePrimaryName(tableWrapper, style + "-tablewrapper");
-
- header.setStylePrimaryName(style);
- body.setStylePrimaryName(style);
- footer.setStylePrimaryName(style);
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java
deleted file mode 100644
index 283517fcc4..0000000000
--- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-
-/**
- * A functional interface that allows client code to define how a certain row in
- * Escalator will be displayed. The contents of an escalator's header, body and
- * footer are rendered by their respective updaters.
- * <p>
- * The updater is responsible for internally handling all remote communication,
- * should the displayed data need to be fetched remotely.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see RowContainer#setEscalatorUpdater(EscalatorUpdater)
- * @see Escalator#getHeader()
- * @see Escalator#getBody()
- * @see Escalator#getFooter()
- */
-public interface EscalatorUpdater {
- /** An {@link EscalatorUpdater} that doesn't render anything. */
- public static final EscalatorUpdater NULL = new EscalatorUpdater() {
- @Override
- public void updateCells(final Row row,
- final Iterable<Cell> cellsToUpdate) {
- // NOOP
- }
- };
-
- /**
- * Renders a row contained in a row container.
- * <p>
- * <em>Note:</em> If rendering of cells is deferred (e.g. because
- * asynchronous data retrieval), this method is responsible for explicitly
- * displaying some placeholder data (empty content is valid). Because the
- * cells (and rows) in an escalator are recycled, failing to reset a cell
- * will lead to invalid data being displayed in the escalator.
- * <p>
- * For performance reasons, the escalator will never autonomously clear any
- * data in a cell.
- *
- * @param row
- * information about the row to update. <em>Note:</em> You should
- * not store nor reuse this reference
- * @param cellsToUpdate
- * a collection of cells which need to be updated. <em>Note:</em>
- * You should neither store nor reuse the reference to the list,
- * nor to the individual cells
- */
- public void updateCells(Row row, Iterable<Cell> cellsToUpdate);
-}
diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java
deleted file mode 100644
index 296a70934b..0000000000
--- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.List;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.user.client.ui.IsWidget;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.client.ui.grid.FlyweightRow.CellIterator;
-
-/**
- * An internal implementation of the {@link Cell} interface.
- * <p>
- * These instances are populated into a {@link FlyweightRow} instance, and
- * intended to be reused when rendering cells in an escalator.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see FlyweightRow#getCells()
- * @see FlyweightRow#addCells(int, int)
- * @see FlyweightRow#removeCells(int, int)
- */
-class FlyweightCell implements Cell {
- static final String COLSPAN_ATTR = "colSpan";
-
- private final int column;
- private final FlyweightRow row;
-
- private CellIterator currentIterator = null;
-
- private final Escalator escalator;
-
- public FlyweightCell(final FlyweightRow row, final int column,
- Escalator escalator) {
- this.row = row;
- this.column = column;
- this.escalator = escalator;
- }
-
- @Override
- public int getRow() {
- assertSetup();
- return row.getRow();
- }
-
- @Override
- public int getColumn() {
- assertSetup();
- return column;
- }
-
- @Override
- public Element getElement() {
- return (Element) row.getElement().getChild(column);
- }
-
- void setup(final CellIterator cellIterator) {
- currentIterator = cellIterator;
-
- final Element e = getElement();
- e.setPropertyInt(COLSPAN_ATTR, 1);
- e.getStyle().setWidth(row.getColumnWidth(column), Unit.PX);
- e.getStyle().clearDisplay();
- }
-
- /**
- * Tear down the state of the Cell.
- * <p>
- * This is an internal check method, to prevent retrieving uninitialized
- * data by calling {@link #getRow()}, {@link #getColumn()} or
- * {@link #getElement()} at an improper time.
- * <p>
- * This should only be used with asserts ("
- * <code>assert flyweightCell.teardown()</code> ") so that the code is never
- * run when asserts aren't enabled.
- *
- * @return always <code>true</code>
- * @see FlyweightRow#teardown()
- */
- boolean teardown() {
- currentIterator = null;
- return true;
- }
-
- /**
- * Asserts that the flyweight cell has properly been set up before trying to
- * access any of its data.
- */
- private void assertSetup() {
- assert currentIterator != null : "FlyweightCell was not properly "
- + "initialized. This is either a bug in Grid/Escalator "
- + "or a Cell reference has been stored and reused "
- + "inappropriately.";
- }
-
- @Override
- public void setColSpan(final int numberOfCells) {
- /*-
- * This will default to 1 if unset, as per DOM specifications:
- * http://www.w3.org/TR/html5/tabular-data.html#attributes-common-to-td-and-th-elements
- */
- final int prevColSpan = getElement().getPropertyInt(COLSPAN_ATTR);
- if (numberOfCells == 1 && prevColSpan == 1) {
- return;
- }
-
- getElement().setPropertyInt(COLSPAN_ATTR, numberOfCells);
- adjustCellWidthForSpan(numberOfCells);
- hideOrRevealAdjacentCellElements(numberOfCells, prevColSpan);
- currentIterator.setSkipNext(numberOfCells - 1);
- }
-
- private void adjustCellWidthForSpan(final int numberOfCells) {
- final int cellsToTheRight = currentIterator.rawPeekNext(
- numberOfCells - 1).size();
-
- final int selfWidth = row.getColumnWidth(column);
- int widthsOfColumnsToTheRight = 0;
- for (int i = 0; i < cellsToTheRight; i++) {
- widthsOfColumnsToTheRight += row.getColumnWidth(column + i + 1);
- }
- getElement().getStyle().setWidth(selfWidth + widthsOfColumnsToTheRight,
- Unit.PX);
- }
-
- private void hideOrRevealAdjacentCellElements(final int numberOfCells,
- final int prevColSpan) {
- final int affectedCellsNumber = Math.max(prevColSpan, numberOfCells);
- final List<FlyweightCell> affectedCells = currentIterator
- .rawPeekNext(affectedCellsNumber - 1);
- if (prevColSpan < numberOfCells) {
- for (int i = 0; i < affectedCells.size(); i++) {
- affectedCells.get(prevColSpan + i - 1).getElement().getStyle()
- .setDisplay(Display.NONE);
- }
- } else if (prevColSpan > numberOfCells) {
- for (int i = 0; i < affectedCells.size(); i++) {
- affectedCells.get(numberOfCells + i - 1).getElement()
- .getStyle().clearDisplay();
- }
- }
- }
-
- @Override
- public Widget getWidget() {
- return Escalator.getWidgetFromCell(getElement());
- }
-
- @Override
- public void setWidget(Widget widget) {
-
- Widget oldWidget = getWidget();
-
- // Validate
- if (oldWidget == widget) {
- return;
- }
-
- // Detach old child.
- if (oldWidget != null) {
- // Orphan.
- Escalator.setParent(oldWidget, null);
-
- // Physical detach.
- getElement().removeChild(oldWidget.getElement());
- }
-
- // Remove any previous text nodes from previous
- // setInnerText/setInnerHTML
- getElement().removeAllChildren();
-
- // Attach new child.
- if (widget != null) {
- // Detach new child from old parent.
- widget.removeFromParent();
-
- // Physical attach.
- getElement().appendChild(widget.getElement());
-
- Escalator.setParent(widget, escalator);
- }
- }
-
- @Override
- public void setWidget(IsWidget w) {
- setWidget(Widget.asWidgetOrNull(w));
- }
-
-}
diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java b/client/src/com/vaadin/client/ui/grid/FlyweightRow.java
deleted file mode 100644
index 6bfd368c6b..0000000000
--- a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Node;
-
-/**
- * An internal implementation of the {@link Row} interface.
- * <p>
- * There is only one instance per Escalator. This is designed to be re-used when
- * rendering rows.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see Escalator.AbstractRowContainer#refreshRow(Node, int)
- */
-class FlyweightRow implements Row {
-
- static class CellIterator implements Iterator<Cell> {
- /** A defensive copy of the cells in the current row. */
- private final ArrayList<FlyweightCell> cells;
- private int cursor = 0;
- private int skipNext = 0;
-
- public CellIterator(final Collection<FlyweightCell> cells) {
- this.cells = new ArrayList<FlyweightCell>(cells);
- }
-
- @Override
- public boolean hasNext() {
- return cursor + skipNext < cells.size();
- }
-
- @Override
- public FlyweightCell next() {
- // if we needed to skip some cells since the last invocation.
- for (int i = 0; i < skipNext; i++) {
- cells.remove(cursor);
- }
- skipNext = 0;
-
- final FlyweightCell cell = cells.get(cursor++);
- cell.setup(this);
- return cell;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException(
- "Cannot remove cells via iterator");
- }
-
- /**
- * Sets the number of cells to skip when {@link #next()} is called the
- * next time. Cell hiding is also handled eagerly in this method.
- *
- * @param colspan
- * the number of cells to skip on next invocation of
- * {@link #next()}
- */
- public void setSkipNext(final int colspan) {
- assert colspan > 0 : "Number of cells didn't make sense: "
- + colspan;
- skipNext = colspan;
- }
-
- /**
- * Gets the next <code>n</code> cells in the iterator, ignoring any
- * possibly spanned cells.
- *
- * @param n
- * the number of next cells to retrieve
- * @return A list of next <code>n</code> cells, or less if there aren't
- * enough cells to retrieve
- */
- public List<FlyweightCell> rawPeekNext(final int n) {
- final int from = Math.min(cursor, cells.size());
- final int to = Math.min(cursor + n, cells.size());
- return cells.subList(from, to);
- }
- }
-
- private static final int BLANK = Integer.MIN_VALUE;
-
- private int row;
- private Element element;
- private int[] columnWidths = null;
- private final Escalator escalator;
- private final List<FlyweightCell> cells = new ArrayList<FlyweightCell>();
-
- public FlyweightRow(final Escalator escalator) {
- this.escalator = escalator;
- }
-
- @Override
- public Escalator getEscalator() {
- return escalator;
- }
-
- void setup(final Element e, final int row, int[] columnWidths) {
- element = e;
- this.row = row;
- this.columnWidths = columnWidths;
- }
-
- /**
- * Tear down the state of the Row.
- * <p>
- * This is an internal check method, to prevent retrieving uninitialized
- * data by calling {@link #getRow()}, {@link #getElement()} or
- * {@link #getCells()} at an improper time.
- * <p>
- * This should only be used with asserts ("
- * <code>assert flyweightRow.teardown()</code> ") so that the code is never
- * run when asserts aren't enabled.
- *
- * @return always <code>true</code>
- */
- boolean teardown() {
- element = null;
- row = BLANK;
- columnWidths = null;
- for (final FlyweightCell cell : cells) {
- assert cell.teardown();
- }
- return true;
- }
-
- @Override
- public int getRow() {
- assertSetup();
- return row;
- }
-
- @Override
- public Element getElement() {
- assertSetup();
- return element;
- }
-
- void addCells(final int index, final int numberOfColumns) {
- for (int i = 0; i < numberOfColumns; i++) {
- final int col = index + i;
- cells.add(col, new FlyweightCell(this, col, escalator));
- }
- updateRestOfCells(index + numberOfColumns);
- }
-
- void removeCells(final int index, final int numberOfColumns) {
- for (int i = 0; i < numberOfColumns; i++) {
- cells.remove(index);
- }
- updateRestOfCells(index);
- }
-
- private void updateRestOfCells(final int startPos) {
- // update the column number for the cells to the right
- for (int col = startPos; col < cells.size(); col++) {
- cells.set(col, new FlyweightCell(this, col, escalator));
- }
- }
-
- /**
- * Get flyweight cells for the client code to render.
- *
- * @return a list of {@link FlyweightCell FlyweightCells}. They are
- * generified into {@link Cell Cells}, because Java's generics
- * system isn't expressive enough.
- * @see #setup(Element, int)
- * @see #teardown()
- */
- Iterable<Cell> getCells() {
- assertSetup();
- return new Iterable<Cell>() {
- @Override
- public Iterator<Cell> iterator() {
- return new CellIterator(cells);
- }
- };
- }
-
- /**
- * Asserts that the flyweight row has properly been set up before trying to
- * access any of its data.
- */
- private void assertSetup() {
- assert element != null && row != BLANK && columnWidths != null : "Flyweight row was not "
- + "properly initialized. Make sure the setup-method is "
- + "called before retrieving data. This is either a bug "
- + "in Escalator, or the instance of the flyweight row "
- + "has been stored and accessed.";
- }
-
- int getColumnWidth(int column) {
- assertSetup();
- return columnWidths[column];
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
deleted file mode 100644
index 02aa194655..0000000000
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ /dev/null
@@ -1,1318 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Logger;
-
-import com.google.gwt.core.shared.GWT;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HasVisibility;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.client.data.DataChangeHandler;
-import com.vaadin.client.data.DataSource;
-import com.vaadin.client.ui.grid.renderers.TextRenderer;
-import com.vaadin.shared.ui.grid.GridConstants;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-import com.vaadin.shared.util.SharedUtil;
-
-/**
- * A data grid view that supports columns and lazy loading of data rows from a
- * data source.
- *
- * <h3>Columns</h3>
- * <p>
- * The {@link GridColumn} class defines the renderer used to render a cell in
- * the grid. Implement {@link GridColumn#getValue(Object)} to retrieve the cell
- * value from the row object and return the cell renderer to render that cell.
- * </p>
- * <p>
- * {@link GridColumn}s contain other properties like the width of the column and
- * the visiblity of the column. If you want to change a column's properties
- * after it has been added to the grid you can get a column object for a
- * specific column index using {@link Grid#getColumn(int)}.
- * </p>
- * <p>
- *
- * TODO Explain about headers/footers once the multiple header/footer api has
- * been implemented
- *
- * <h3>Data sources</h3>
- * <p>
- * TODO Explain about what a data source is and how it should be implemented.
- * </p>
- *
- * @param <T>
- * The row type of the grid. The row type is the POJO type from where
- * the data is retrieved into the column cells.
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class Grid<T> extends Composite {
-
- /**
- * Escalator used internally by grid to render the rows
- */
- private Escalator escalator = GWT.create(Escalator.class);
-
- /**
- * List of columns in the grid. Order defines the visible order.
- */
- private final List<GridColumn<?, T>> columns = new ArrayList<GridColumn<?, T>>();
-
- /**
- * The datasource currently in use. <em>Note:</em> it is <code>null</code>
- * on initialization, but not after that.
- */
- private DataSource<T> dataSource;
-
- /**
- * The column groups rows added to the grid
- */
- private final List<ColumnGroupRow<T>> columnGroupRows = new ArrayList<ColumnGroupRow<T>>();
-
- /**
- * Are the headers for the columns visible
- */
- private boolean columnHeadersVisible = true;
-
- /**
- * Are the footers for the columns visible
- */
- private boolean columnFootersVisible = false;
-
- /**
- * The last column frozen counter from the left
- */
- private GridColumn<?, T> lastFrozenColumn;
-
- /**
- * Base class for grid columns internally used by the Grid. The user should
- * use {@link GridColumn} when creating new columns.
- *
- * @param <C>
- * the column type
- *
- * @param <T>
- * the row type
- */
- static abstract class AbstractGridColumn<C, T> implements HasVisibility {
-
- /**
- * The grid the column is associated with
- */
- private Grid<T> grid;
-
- /**
- * Should the column be visible in the grid
- */
- private boolean visible = true;
-
- /**
- * The text displayed in the header of the column
- */
- private String header;
-
- /**
- * Text displayed in the column footer
- */
- private String footer;
-
- /**
- * Width of column in pixels
- */
- private int width = 100;
-
- /**
- * Renderer for rendering a value into the cell
- */
- private Renderer<C> bodyRenderer = new Renderer<C>() {
-
- @Override
- public void renderCell(Cell cell, C value) {
- if (value instanceof Widget) {
- cell.setWidget((Widget) value);
- } else if (value instanceof String) {
- cell.getElement().setInnerText(value.toString());
- } else {
- throw new IllegalArgumentException(
- "Cell value cannot be converted into a String. Please use a custom renderer to convert the value.");
- }
- }
- };
-
- /**
- * Renderer for rendering the header cell value into the cell
- */
- private Renderer<String> headerRenderer = new TextRenderer();
-
- /**
- * Renderer for rendering the footer cell value into the cell
- */
- private Renderer<String> footerRenderer = new TextRenderer();
-
- /**
- * Constructs a new column.
- */
- public AbstractGridColumn() {
-
- }
-
- /**
- * Constructs a new column with a custom renderer.
- *
- * @param renderer
- * The renderer to use for rendering the cells
- */
- public AbstractGridColumn(Renderer<C> renderer) {
- if (renderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
- this.bodyRenderer = renderer;
- }
-
- /**
- * Constructs a new column with custom renderers for rows, header and
- * footer cells.
- *
- * @param bodyRenderer
- * The renderer to use for rendering body cells
- * @param headerRenderer
- * The renderer to use for rendering header cells
- * @param footerRenderer
- * The renderer to use for rendering footer cells
- */
- public AbstractGridColumn(Renderer<C> bodyRenderer,
- Renderer<String> headerRenderer, Renderer<String> footerRenderer) {
- this(bodyRenderer);
- if (headerRenderer == null || footerRenderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
-
- this.headerRenderer = headerRenderer;
- this.footerRenderer = footerRenderer;
- }
-
- /**
- * Internally used by the grid to set itself
- *
- * @param grid
- */
- private void setGrid(Grid<T> grid) {
- if (this.grid != null && grid != null) {
- // Trying to replace grid
- throw new IllegalStateException(
- "Column already is attached to grid. Remove the column first from the grid and then add it.");
- }
-
- this.grid = grid;
-
- setVisible(this.visible);
- setWidth(this.width);
- setHeaderCaption(this.header);
- setFooterCaption(this.footer);
- }
-
- /**
- * Gets text in the header of the column. By default the header caption
- * is empty.
- *
- * @return the text displayed in the column caption
- */
- public String getHeaderCaption() {
- return header;
- }
-
- /**
- * Returns the renderer used for rendering the header cells
- *
- * @return a renderer that renders header cells
- */
- public Renderer<String> getHeaderRenderer() {
- return headerRenderer;
- }
-
- /**
- * Sets the renderer that renders header cells. Should not be null.
- *
- * @param renderer
- * The renderer to use for rendering header cells.
- */
- public void setHeaderRenderer(Renderer<String> renderer) {
- if (renderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
- headerRenderer = renderer;
- if (grid != null) {
- grid.refreshHeader();
- }
- }
-
- /**
- * Returns the renderer used for rendering the footer cells
- *
- * @return a renderer that renders footer cells
- */
- public Renderer<String> getFooterRenderer() {
- return footerRenderer;
- }
-
- /**
- * Sets the renderer that renders footer cells. Should not be null.
- *
- * @param renderer
- * The renderer to use for rendering footer cells.
- */
- public void setFooterRenderer(Renderer<String> renderer) {
- if (renderer == null) {
- throw new IllegalArgumentException("Renderer cannot be null.");
- }
- footerRenderer = renderer;
- if (grid != null) {
- grid.refreshFooter();
- }
- }
-
- /**
- * Sets the text in the header of the column.
- *
- * @param caption
- * the text displayed in the column header
- */
- public void setHeaderCaption(String caption) {
- if (SharedUtil.equals(caption, header)) {
- return;
- }
-
- header = caption;
-
- if (grid != null) {
- grid.refreshHeader();
- }
- }
-
- /**
- * Gets text in the footer of the column. By default the footer caption
- * is empty.
- *
- * @return The text displayed in the footer of the column
- */
- public String getFooterCaption() {
- return footer;
- }
-
- /**
- * Sets text in the footer of the column.
- *
- * @param caption
- * the text displayed in the footer of the column
- */
- public void setFooterCaption(String caption) {
- if (SharedUtil.equals(caption, footer)) {
- return;
- }
-
- footer = caption;
-
- if (grid != null) {
- grid.refreshFooter();
- }
- }
-
- /**
- * Is the column visible. By default all columns are visible.
- *
- * @return <code>true</code> if the column is visible
- */
- @Override
- public boolean isVisible() {
- return visible;
- }
-
- /**
- * Sets a column as visible in the grid.
- *
- * @param visible
- * <code>true</code> if the column should be displayed in the
- * grid
- */
- @Override
- public void setVisible(boolean visible) {
- if (this.visible == visible) {
- return;
- }
-
- this.visible = visible;
-
- // Remove column
- if (grid != null) {
- int index = findIndexOfColumn();
- ColumnConfiguration conf = grid.escalator
- .getColumnConfiguration();
-
- if (visible) {
- conf.insertColumns(index, 1);
- } else {
- conf.removeColumns(index, 1);
- }
- }
-
- }
-
- /**
- * Returns the data that should be rendered into the cell. By default
- * returning Strings and Widgets are supported. If the return type is a
- * String then it will be treated as preformatted text.
- * <p>
- * To support other types you will need to pass a custom renderer to the
- * column via the column constructor.
- *
- * @param row
- * The row object that provides the cell content.
- *
- * @return The cell content
- */
- public abstract C getValue(T row);
-
- /**
- * The renderer to render the cell width. By default renders the data as
- * a String or adds the widget into the cell if the column type is of
- * widget type.
- *
- * @return The renderer to render the cell content with
- */
- public Renderer<C> getRenderer() {
- return bodyRenderer;
- }
-
- /**
- * Finds the index of this column instance
- *
- */
- private int findIndexOfColumn() {
- return grid.findVisibleColumnIndex((GridColumn<?, T>) this);
- }
-
- /**
- * Sets the pixel width of the column. Use a negative value for the grid
- * to autosize column based on content and available space
- *
- * @param pixels
- * the width in pixels or negative for auto sizing
- */
- public void setWidth(int pixels) {
- this.width = pixels;
-
- if (grid != null && isVisible()) {
- int index = findIndexOfColumn();
- ColumnConfiguration conf = grid.escalator
- .getColumnConfiguration();
- conf.setColumnWidth(index, pixels);
- }
- }
-
- /**
- * Returns the pixel width of the column
- *
- * @return pixel width of the column
- */
- public int getWidth() {
- if (grid == null) {
- return this.width;
- } else {
- int index = findIndexOfColumn();
- ColumnConfiguration conf = grid.escalator
- .getColumnConfiguration();
- return conf.getColumnWidth(index);
- }
- }
- }
-
- /**
- * Base class for header / footer escalator updater
- */
- protected abstract class HeaderFooterEscalatorUpdater implements
- EscalatorUpdater {
-
- /**
- * The row container which contains the header or footer rows
- */
- private RowContainer rows;
-
- /**
- * Should the index be counted from 0-> or 0<-
- */
- private boolean inverted;
-
- /**
- * Constructs an updater for updating a header / footer
- *
- * @param rows
- * The row container
- * @param inverted
- * Should index counting be inverted
- */
- public HeaderFooterEscalatorUpdater(RowContainer rows, boolean inverted) {
- this.rows = rows;
- this.inverted = inverted;
- }
-
- /**
- * Gets the header/footer caption value
- *
- * @param column
- * The column to get the value for.
- *
- * @return The value that should be rendered for the column caption
- */
- public abstract String getColumnValue(GridColumn<?, T> column);
-
- /**
- * Gets the group caption value
- *
- * @param group
- * The group for with the caption value should be returned
- * @return The value that should be rendered for the column caption
- */
- public abstract String getGroupValue(ColumnGroup<T> group);
-
- /**
- * Is the row visible in the header/footer
- *
- * @param row
- * the row to check
- *
- * @return <code>true</code> if the row should be visible
- */
- public abstract boolean isRowVisible(ColumnGroupRow<T> row);
-
- /**
- * Should the first row be visible
- *
- * @return <code>true</code> if the first row should be visible
- */
- public abstract boolean firstRowIsVisible();
-
- /**
- * The renderer that renders the cell
- *
- * @param column
- * The column for which the cell should be rendered
- *
- * @return renderer used for rendering
- */
- public abstract Renderer<String> getRenderer(GridColumn<?, T> column);
-
- /**
- * The renderer that renders the cell for column groups
- *
- * @param group
- * The group that should be rendered
- * @return renderer used for rendering
- */
- public abstract Renderer<String> getGroupRenderer(ColumnGroup<T> group);
-
- @Override
- public void updateCells(Row row, Iterable<Cell> cellsToUpdate) {
-
- int rowIndex;
- if (inverted) {
- rowIndex = rows.getRowCount() - row.getRow() - 1;
- } else {
- rowIndex = row.getRow();
- }
-
- if (firstRowIsVisible() && rowIndex == 0) {
- // column headers
- for (Cell cell : cellsToUpdate) {
- GridColumn<?, T> column = getColumnFromVisibleIndex(cell
- .getColumn());
- if (column != null) {
- getRenderer(column).renderCell(cell,
- getColumnValue(column));
- }
- }
-
- } else if (columnGroupRows.size() > 0) {
- // Adjust for headers
- if (firstRowIsVisible()) {
- rowIndex--;
- }
-
- // Adjust for previous invisible header rows
- ColumnGroupRow<T> groupRow = null;
- for (int i = 0, realIndex = 0; i < columnGroupRows.size(); i++) {
- groupRow = columnGroupRows.get(i);
- if (isRowVisible(groupRow)) {
- if (realIndex == rowIndex) {
- rowIndex = realIndex;
- break;
- }
- realIndex++;
- }
- }
-
- assert groupRow != null;
-
- for (Cell cell : cellsToUpdate) {
- GridColumn<?, T> column = getColumnFromVisibleIndex(cell
- .getColumn());
- ColumnGroup<T> group = getGroupForColumn(groupRow, column);
- Element cellElement = cell.getElement();
-
- if (group != null) {
- getGroupRenderer(group).renderCell(cell,
- getGroupValue(group));
- cell.setColSpan(group.getColumns().size());
- } else {
- // Cells are reused
- cellElement.setInnerHTML(null);
- cell.setColSpan(1);
- }
- }
- }
- }
- }
-
- /**
- * Creates a new instance.
- */
- public Grid() {
- initWidget(escalator);
-
- setStylePrimaryName("v-grid");
-
- escalator.getHeader().setEscalatorUpdater(createHeaderUpdater());
- escalator.getBody().setEscalatorUpdater(createBodyUpdater());
- escalator.getFooter().setEscalatorUpdater(createFooterUpdater());
-
- refreshHeader();
- refreshFooter();
-
- escalator
- .addRowVisibilityChangeHandler(new RowVisibilityChangeHandler() {
- @Override
- public void onRowVisibilityChange(
- RowVisibilityChangeEvent event) {
- if (dataSource != null) {
- dataSource.ensureAvailability(
- event.getFirstVisibleRow(),
- event.getVisibleRowCount());
- }
- }
- });
-
- }
-
- @Override
- public void setStylePrimaryName(String style) {
- super.setStylePrimaryName(style);
- escalator.setStylePrimaryName(style);
-
- }
-
- /**
- * Creates the header updater that updates the escalator header rows from
- * the column and column group rows.
- *
- * @return the updater that updates the data in the escalator.
- */
- private EscalatorUpdater createHeaderUpdater() {
- return new HeaderFooterEscalatorUpdater(escalator.getHeader(), true) {
-
- @Override
- public boolean isRowVisible(ColumnGroupRow<T> row) {
- return row.isHeaderVisible();
- }
-
- @Override
- public String getGroupValue(ColumnGroup<T> group) {
- return group.getHeaderCaption();
- }
-
- @Override
- public String getColumnValue(GridColumn<?, T> column) {
- return column.getHeaderCaption();
- }
-
- @Override
- public boolean firstRowIsVisible() {
- return isColumnHeadersVisible();
- }
-
- @Override
- public Renderer<String> getRenderer(GridColumn<?, T> column) {
- return column.getHeaderRenderer();
- }
-
- @Override
- public Renderer<String> getGroupRenderer(ColumnGroup<T> group) {
- return group.getHeaderRenderer();
- }
- };
- }
-
- private EscalatorUpdater createBodyUpdater() {
- return new EscalatorUpdater() {
-
- @Override
- public void updateCells(Row row, Iterable<Cell> cellsToUpdate) {
- int rowIndex = row.getRow();
- if (dataSource == null) {
- setCellsLoading(cellsToUpdate);
- return;
- }
-
- T rowData = dataSource.getRow(rowIndex);
- if (rowData == null) {
- setCellsLoading(cellsToUpdate);
- return;
- }
-
- for (Cell cell : cellsToUpdate) {
- GridColumn column = getColumnFromVisibleIndex(cell
- .getColumn());
- if (column != null) {
- Object value = column.getValue(rowData);
- column.getRenderer().renderCell(cell, value);
- }
- }
- }
-
- private void setCellsLoading(Iterable<Cell> cellsToUpdate) {
- for (Cell cell : cellsToUpdate) {
- cell.getElement().setInnerText("...");
- }
- }
- };
- }
-
- /**
- * Creates the footer updater that updates the escalator footer rows from
- * the column and column group rows.
- *
- * @return the updater that updates the data in the escalator.
- */
- private EscalatorUpdater createFooterUpdater() {
- return new HeaderFooterEscalatorUpdater(escalator.getFooter(), false) {
-
- @Override
- public boolean isRowVisible(ColumnGroupRow<T> row) {
- return row.isFooterVisible();
- }
-
- @Override
- public String getGroupValue(ColumnGroup<T> group) {
- return group.getFooterCaption();
- }
-
- @Override
- public String getColumnValue(GridColumn<?, T> column) {
- return column.getFooterCaption();
- }
-
- @Override
- public boolean firstRowIsVisible() {
- return isColumnFootersVisible();
- }
-
- @Override
- public Renderer<String> getRenderer(GridColumn<?, T> column) {
- return column.getFooterRenderer();
- }
-
- @Override
- public Renderer<String> getGroupRenderer(ColumnGroup<T> group) {
- return group.getFooterRenderer();
- }
- };
- }
-
- /**
- * Refreshes header or footer rows on demand
- *
- * @param rows
- * The row container
- * @param firstRowIsVisible
- * is the first row visible
- * @param isHeader
- * <code>true</code> if we refreshing the header, else assumed
- * the footer
- */
- private void refreshRowContainer(RowContainer rows,
- boolean firstRowIsVisible, boolean isHeader) {
-
- // Count needed rows
- int totalRows = firstRowIsVisible ? 1 : 0;
- for (ColumnGroupRow<T> row : columnGroupRows) {
- if (isHeader ? row.isHeaderVisible() : row.isFooterVisible()) {
- totalRows++;
- }
- }
-
- // Add or Remove rows on demand
- int rowDiff = totalRows - rows.getRowCount();
- if (rowDiff > 0) {
- rows.insertRows(0, rowDiff);
- } else if (rowDiff < 0) {
- rows.removeRows(0, -rowDiff);
- }
-
- // Refresh all the rows
- if (rows.getRowCount() > 0) {
- rows.refreshRows(0, rows.getRowCount());
- }
- }
-
- /**
- * Refreshes all header rows
- */
- void refreshHeader() {
- refreshRowContainer(escalator.getHeader(), isColumnHeadersVisible(),
- true);
- }
-
- /**
- * Refreshes all footer rows
- */
- void refreshFooter() {
- refreshRowContainer(escalator.getFooter(), isColumnFootersVisible(),
- false);
- }
-
- /**
- * Adds a column as the last column in the grid.
- *
- * @param column
- * the column to add
- */
- public void addColumn(GridColumn<?, T> column) {
- ColumnConfiguration conf = escalator.getColumnConfiguration();
- addColumn(column, conf.getColumnCount());
- }
-
- /**
- * Inserts a column into a specific position in the grid.
- *
- * @param index
- * the index where the column should be inserted into
- * @param column
- * the column to add
- */
- public void addColumn(GridColumn<?, T> column, int index) {
-
- // Register column with grid
- columns.add(index, column);
-
- // Insert column into escalator
- if (column.isVisible()) {
- int visibleIndex = findVisibleColumnIndex(column);
- ColumnConfiguration conf = escalator.getColumnConfiguration();
- conf.insertColumns(visibleIndex, 1);
- }
-
- // Register this grid instance with the column
- ((AbstractGridColumn<?, T>) column).setGrid(this);
-
- if (lastFrozenColumn != null
- && ((AbstractGridColumn<?, T>) lastFrozenColumn)
- .findIndexOfColumn() < index) {
- refreshFrozenColumns();
- }
- }
-
- private int findVisibleColumnIndex(GridColumn<?, T> column) {
- int idx = 0;
- for (GridColumn<?, T> c : columns) {
- if (c == column) {
- return idx;
- } else if (c.isVisible()) {
- idx++;
- }
- }
- return -1;
- }
-
- private GridColumn<?, T> getColumnFromVisibleIndex(int index) {
- int idx = -1;
- for (GridColumn<?, T> c : columns) {
- if (c.isVisible()) {
- idx++;
- }
- if (index == idx) {
- return c;
- }
- }
- return null;
- }
-
- /**
- * Removes a column from the grid.
- *
- * @param column
- * the column to remove
- */
- public void removeColumn(GridColumn<?, T> column) {
-
- int columnIndex = columns.indexOf(column);
- int visibleIndex = findVisibleColumnIndex(column);
- columns.remove(columnIndex);
-
- // de-register column with grid
- ((AbstractGridColumn<?, T>) column).setGrid(null);
-
- if (column.isVisible()) {
- ColumnConfiguration conf = escalator.getColumnConfiguration();
- conf.removeColumns(visibleIndex, 1);
- }
-
- if (column.equals(lastFrozenColumn)) {
- setLastFrozenColumn(null);
- } else {
- refreshFrozenColumns();
- }
- }
-
- /**
- * Returns the amount of columns in the grid.
- *
- * @return The number of columns in the grid
- */
- public int getColumnCount() {
- return columns.size();
- }
-
- /**
- * Returns a list of columns in the grid.
- *
- * @return A unmodifiable list of the columns in the grid
- */
- public List<GridColumn<?, T>> getColumns() {
- return Collections.unmodifiableList(new ArrayList<GridColumn<?, T>>(
- columns));
- }
-
- /**
- * Returns a column by its index in the grid.
- *
- * @param index
- * the index of the column
- * @return The column in the given index
- * @throws IllegalArgumentException
- * if the column index does not exist in the grid
- */
- public GridColumn<?, T> getColumn(int index)
- throws IllegalArgumentException {
- if (index < 0 || index >= columns.size()) {
- throw new IllegalStateException("Column not found.");
- }
- return columns.get(index);
- }
-
- /**
- * Set the column headers visible.
- *
- * <p>
- * A column header is a single cell header on top of each column reserved
- * for a specific header for that column. The column header can be set by
- * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be
- * merged with other column headers.
- * </p>
- *
- * <p>
- * All column headers occupy the first header row of the grid. If you do not
- * wish to show the column headers in the grid you should hide the row by
- * setting visibility of the header row to <code>false</code>.
- * </p>
- *
- * <p>
- * If you want to merge the column headers into groups you can use
- * {@link ColumnGroupRow}s to group columns together and give them a common
- * header. See {@link #addColumnGroupRow()} for details.
- * </p>
- *
- * <p>
- * The header row is by default visible.
- * </p>
- *
- * @param visible
- * <code>true</code> if header rows should be visible
- */
- public void setColumnHeadersVisible(boolean visible) {
- if (visible == isColumnHeadersVisible()) {
- return;
- }
- columnHeadersVisible = visible;
- refreshHeader();
- }
-
- /**
- * Are the column headers visible
- *
- * @return <code>true</code> if they are visible
- */
- public boolean isColumnHeadersVisible() {
- return columnHeadersVisible;
- }
-
- /**
- * Set the column footers visible.
- *
- * <p>
- * A column footer is a single cell footer below of each column reserved for
- * a specific footer for that column. The column footer can be set by
- * {@link GridColumn#setFooterCaption(String)} and column footers cannot be
- * merged with other column footers.
- * </p>
- *
- * <p>
- * All column footers occupy the first footer row of the grid. If you do not
- * wish to show the column footers in the grid you should hide the row by
- * setting visibility of the footer row to <code>false</code>.
- * </p>
- *
- * <p>
- * If you want to merge the column footers into groups you can use
- * {@link ColumnGroupRow}s to group columns together and give them a common
- * footer. See {@link #addColumnGroupRow()} for details.
- * </p>
- *
- * <p>
- * The footer row is by default hidden.
- * </p>
- *
- * @param visible
- * <code>true</code> if the footer row should be visible
- */
- public void setColumnFootersVisible(boolean visible) {
- if (visible == isColumnFootersVisible()) {
- return;
- }
- this.columnFootersVisible = visible;
- refreshFooter();
- }
-
- /**
- * Are the column footers visible
- *
- * @return <code>true</code> if they are visible
- *
- */
- public boolean isColumnFootersVisible() {
- return columnFootersVisible;
- }
-
- /**
- * Adds a new column group row to the grid.
- *
- * <p>
- * Column group rows are rendered in the header and footer of the grid.
- * Column group rows are made up of column groups which groups together
- * columns for adding a common auxiliary header or footer for the columns.
- * </p>
- *
- * Example usage:
- *
- * <pre>
- * // Add a new column group row to the grid
- * ColumnGroupRow row = grid.addColumnGroupRow();
- *
- * // Group &quot;Column1&quot; and &quot;Column2&quot; together to form a header in the row
- * ColumnGroup column12 = row.addGroup(&quot;Column1&quot;, &quot;Column2&quot;);
- *
- * // Set a common header for &quot;Column1&quot; and &quot;Column2&quot;
- * column12.setHeader(&quot;Column 1&amp;2&quot;);
- *
- * // Set a common footer for &quot;Column1&quot; and &quot;Column2&quot;
- * column12.setFooter(&quot;Column 1&amp;2&quot;);
- * </pre>
- *
- * @return a column group row instance you can use to add column groups
- */
- public ColumnGroupRow<T> addColumnGroupRow() {
- ColumnGroupRow<T> row = new ColumnGroupRow<T>(this);
- columnGroupRows.add(row);
- refreshHeader();
- refreshFooter();
- return row;
- }
-
- /**
- * Adds a new column group row to the grid at a specific index.
- *
- * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example
- * usage
- *
- * @param rowIndex
- * the index where the column group row should be added
- * @return a column group row instance you can use to add column groups
- */
- public ColumnGroupRow<T> addColumnGroupRow(int rowIndex) {
- ColumnGroupRow<T> row = new ColumnGroupRow<T>(this);
- columnGroupRows.add(rowIndex, row);
- refreshHeader();
- refreshFooter();
- return row;
- }
-
- /**
- * Removes a column group row
- *
- * @param row
- * The row to remove
- */
- public void removeColumnGroupRow(ColumnGroupRow<T> row) {
- columnGroupRows.remove(row);
- refreshHeader();
- refreshFooter();
- }
-
- /**
- * Get the column group rows
- *
- * @return a unmodifiable list of column group rows
- *
- */
- public List<ColumnGroupRow<T>> getColumnGroupRows() {
- return Collections.unmodifiableList(new ArrayList<ColumnGroupRow<T>>(
- columnGroupRows));
- }
-
- /**
- * Returns the column group for a row and column
- *
- * @param row
- * The row of the column
- * @param column
- * the column to get the group for
- * @return A column group for the row and column or <code>null</code> if not
- * found.
- */
- private ColumnGroup<T> getGroupForColumn(ColumnGroupRow<T> row,
- GridColumn<?, T> column) {
- for (ColumnGroup<T> group : row.getGroups()) {
- List<GridColumn<?, T>> columns = group.getColumns();
- if (columns.contains(column)) {
- return group;
- }
- }
- return null;
- }
-
- @Override
- public void setHeight(String height) {
- escalator.setHeight(height);
- }
-
- @Override
- public void setWidth(String width) {
- escalator.setWidth(width);
- }
-
- /**
- * Sets the data source used by this grid.
- *
- * @param dataSource
- * the data source to use, not null
- * @throws IllegalArgumentException
- * if <code>dataSource</code> is <code>null</code>
- */
- public void setDataSource(DataSource<T> dataSource)
- throws IllegalArgumentException {
- if (dataSource == null) {
- throw new IllegalArgumentException("dataSource can't be null.");
- }
-
- if (this.dataSource != null) {
- this.dataSource.setDataChangeHandler(null);
- }
-
- this.dataSource = dataSource;
- dataSource.setDataChangeHandler(new DataChangeHandler() {
- @Override
- public void dataUpdated(int firstIndex, int numberOfItems) {
- escalator.getBody().refreshRows(firstIndex, numberOfItems);
- }
-
- @Override
- public void dataRemoved(int firstIndex, int numberOfItems) {
- escalator.getBody().removeRows(firstIndex, numberOfItems);
- }
-
- @Override
- public void dataAdded(int firstIndex, int numberOfItems) {
- escalator.getBody().insertRows(firstIndex, numberOfItems);
- }
- });
-
- int previousRowCount = escalator.getBody().getRowCount();
- if (previousRowCount != 0) {
- escalator.getBody().removeRows(0, previousRowCount);
- }
-
- int estimatedSize = dataSource.getEstimatedSize();
- if (estimatedSize > 0) {
- escalator.getBody().insertRows(0, estimatedSize);
- }
- }
-
- /**
- * Sets the rightmost frozen column in the grid.
- * <p>
- * All columns up to and including the given column will be frozen in place
- * when the grid is scrolled sideways.
- *
- * @param lastFrozenColumn
- * the rightmost column to freeze, or <code>null</code> to not
- * have any columns frozen
- * @throws IllegalArgumentException
- * if {@code lastFrozenColumn} is not a column from this grid
- */
- public void setLastFrozenColumn(GridColumn<?, T> lastFrozenColumn) {
- this.lastFrozenColumn = lastFrozenColumn;
- refreshFrozenColumns();
- }
-
- private void refreshFrozenColumns() {
- final int frozenCount;
- if (lastFrozenColumn != null) {
- frozenCount = columns.indexOf(lastFrozenColumn) + 1;
- if (frozenCount == 0) {
- throw new IllegalArgumentException(
- "The given column isn't attached to this grid");
- }
- } else {
- frozenCount = 0;
- }
-
- escalator.getColumnConfiguration().setFrozenColumnCount(frozenCount);
- }
-
- /**
- * Gets the rightmost frozen column in the grid.
- * <p>
- * <em>Note:</em> Most usually, this method returns the very value set with
- * {@link #setLastFrozenColumn(GridColumn)}. This value, however, can be
- * reset to <code>null</code> if the column is removed from this grid.
- *
- * @return the rightmost frozen column in the grid, or <code>null</code> if
- * no columns are frozen.
- */
- public GridColumn<?, T> getLastFrozenColumn() {
- return lastFrozenColumn;
- }
-
- public HandlerRegistration addRowVisibilityChangeHandler(
- RowVisibilityChangeHandler handler) {
- /*
- * Reusing Escalator's RowVisibilityChangeHandler, since a scroll
- * concept is too abstract. e.g. the event needs to be re-sent when the
- * widget is resized.
- */
- return escalator.addRowVisibilityChangeHandler(handler);
- }
-
- /**
- * Scrolls to a certain row, using {@link ScrollDestination#ANY}.
- *
- * @param rowIndex
- * zero-based index of the row to scroll to.
- * @throws IllegalArgumentException
- * if rowIndex is below zero, or above the maximum value
- * supported by the data source.
- */
- public void scrollToRow(int rowIndex) throws IllegalArgumentException {
- scrollToRow(rowIndex, ScrollDestination.ANY,
- GridConstants.DEFAULT_PADDING);
- }
-
- /**
- * Scrolls to a certain row, using user-specified scroll destination.
- *
- * @param rowIndex
- * zero-based index of the row to scroll to.
- * @param destination
- * desired destination placement of scrolled-to-row. See
- * {@link ScrollDestination} for more information.
- * @throws IllegalArgumentException
- * if rowIndex is below zero, or above the maximum value
- * supported by the data source.
- */
- public void scrollToRow(int rowIndex, ScrollDestination destination)
- throws IllegalArgumentException {
- scrollToRow(rowIndex, destination,
- destination == ScrollDestination.MIDDLE ? 0
- : GridConstants.DEFAULT_PADDING);
- }
-
- /**
- * Scrolls to a certain row using only user-specified parameters.
- *
- * @param rowIndex
- * zero-based index of the row to scroll to.
- * @param destination
- * desired destination placement of scrolled-to-row. See
- * {@link ScrollDestination} for more information.
- * @param paddingPx
- * number of pixels to overscroll. Behavior depends on
- * destination.
- * @throws IllegalArgumentException
- * if {@code destination} is {@link ScrollDestination#MIDDLE}
- * and padding is nonzero, because having a padding on a
- * centered row is undefined behavior, or if rowIndex is below
- * zero or above the row count of the data source.
- */
- private void scrollToRow(int rowIndex, ScrollDestination destination,
- int paddingPx) throws IllegalArgumentException {
- int maxsize = escalator.getBody().getRowCount() - 1;
-
- if (rowIndex < 0) {
- throw new IllegalArgumentException("Row index (" + rowIndex
- + ") is below zero!");
- }
-
- if (rowIndex > maxsize) {
- throw new IllegalArgumentException("Row index (" + rowIndex
- + ") is above maximum (" + maxsize + ")!");
- }
-
- escalator.scrollToRow(rowIndex, destination, paddingPx);
- }
-
- /**
- * Scrolls to the beginning of the very first row.
- */
- public void scrollToStart() {
- scrollToRow(0, ScrollDestination.START);
- }
-
- /**
- * Scrolls to the end of the very last row.
- */
- public void scrollToEnd() {
- scrollToRow(escalator.getBody().getRowCount() - 1,
- ScrollDestination.END);
- }
-
- private static final Logger getLogger() {
- return Logger.getLogger(Grid.class.getName());
- }
-
-}
diff --git a/client/src/com/vaadin/client/ui/grid/GridColumn.java b/client/src/com/vaadin/client/ui/grid/GridColumn.java
deleted file mode 100644
index afd80a5f5a..0000000000
--- a/client/src/com/vaadin/client/ui/grid/GridColumn.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-/**
- * Represents a column in the {@link Grid}.
- *
- * @param <C>
- * The column type
- *
- * @param <T>
- * The row type
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public abstract class GridColumn<C, T> extends Grid.AbstractGridColumn<C, T> {
-
- /*
- * This class is a convenience class so you do not have to reference
- * Grid.AbstractGridColumn in your production code. The real implementation
- * should be in the abstract class.
- */
-
- /**
- * Constructs a new column.
- */
- public GridColumn() {
- super();
- }
-
- /**
- * Constructs a new column with a custom renderer.
- *
- * @param renderer
- * The renderer to use for rendering the cells
- */
- public GridColumn(Renderer<C> renderer) {
- super(renderer);
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java
deleted file mode 100644
index 5e0664667d..0000000000
--- a/client/src/com/vaadin/client/ui/grid/GridConnector.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.vaadin.client.communication.StateChangeEvent;
-import com.vaadin.client.ui.AbstractComponentConnector;
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.grid.ColumnGroupRowState;
-import com.vaadin.shared.ui.grid.ColumnGroupState;
-import com.vaadin.shared.ui.grid.GridClientRpc;
-import com.vaadin.shared.ui.grid.GridColumnState;
-import com.vaadin.shared.ui.grid.GridServerRpc;
-import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-
-/**
- * Connects the client side {@link Grid} widget with the server side
- * {@link com.vaadin.ui.components.grid.Grid} component.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-@Connect(com.vaadin.ui.components.grid.Grid.class)
-public class GridConnector extends AbstractComponentConnector {
-
- /**
- * Custom implementation of the custom grid column using a String[] to
- * represent the cell value and String as a column type.
- */
- private class CustomGridColumn extends GridColumn<String, String[]> {
-
- private final int columnIndex;
-
- public CustomGridColumn(int columnIndex) {
- this.columnIndex = columnIndex;
- }
-
- @Override
- public String getValue(String[] obj) {
- return obj[columnIndex];
- }
- }
-
- /**
- * Maps a generated column id to a grid column instance
- */
- private Map<String, CustomGridColumn> columnIdToColumn = new HashMap<String, CustomGridColumn>();
-
- @Override
- protected Grid<String[]> createWidget() {
- // FIXME Shouldn't be needed after #12873 has been fixed.
- return new Grid<String[]>();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Grid<String[]> getWidget() {
- return (Grid<String[]>) super.getWidget();
- }
-
- @Override
- public GridState getState() {
- return (GridState) super.getState();
- }
-
- @Override
- protected void init() {
- super.init();
- getWidget().addRowVisibilityChangeHandler(
- new RowVisibilityChangeHandler() {
- @Override
- public void onRowVisibilityChange(
- RowVisibilityChangeEvent event) {
- getRpcProxy(GridServerRpc.class).setVisibleRows(
- event.getFirstVisibleRow(),
- event.getVisibleRowCount());
- }
- });
-
- registerRpc(GridClientRpc.class, new GridClientRpc() {
- @Override
- public void scrollToStart() {
- getWidget().scrollToStart();
- }
-
- @Override
- public void scrollToEnd() {
- getWidget().scrollToEnd();
- }
-
- @Override
- public void scrollToRow(int row, ScrollDestination destination) {
- getWidget().scrollToRow(row, destination);
- }
- });
- }
-
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
-
- // Column updates
- if (stateChangeEvent.hasPropertyChanged("columns")) {
-
- int totalColumns = getState().columns.size();
-
- // Remove old columns
- purgeRemovedColumns();
-
- int currentColumns = getWidget().getColumnCount();
-
- // Add new columns
- for (int columnIndex = currentColumns; columnIndex < totalColumns; columnIndex++) {
- addColumnFromStateChangeEvent(columnIndex);
- }
-
- // Update old columns
- for (int columnIndex = 0; columnIndex < currentColumns; columnIndex++) {
- // FIXME Currently updating all column header / footers when a
- // change in made in one column. When the framework supports
- // quering a specific item in a list then it should do so here.
- updateColumnFromStateChangeEvent(columnIndex);
- }
- }
-
- // Header
- if (stateChangeEvent.hasPropertyChanged("columnHeadersVisible")) {
- getWidget()
- .setColumnHeadersVisible(getState().columnHeadersVisible);
- }
-
- // Footer
- if (stateChangeEvent.hasPropertyChanged("columnFootersVisible")) {
- getWidget()
- .setColumnFootersVisible(getState().columnFootersVisible);
- }
-
- // Column row groups
- if (stateChangeEvent.hasPropertyChanged("columnGroupRows")) {
- updateColumnGroupsFromStateChangeEvent();
- }
-
- if (stateChangeEvent.hasPropertyChanged("lastFrozenColumnId")) {
- String frozenColId = getState().lastFrozenColumnId;
- if (frozenColId != null) {
- CustomGridColumn column = columnIdToColumn.get(frozenColId);
- assert column != null : "Column to be frozen could not be found (id:"
- + frozenColId + ")";
- getWidget().setLastFrozenColumn(column);
- } else {
- getWidget().setLastFrozenColumn(null);
- }
- }
- }
-
- /**
- * Updates a column from a state change event.
- *
- * @param columnIndex
- * The index of the column to update
- */
- private void updateColumnFromStateChangeEvent(int columnIndex) {
- GridColumn<?, String[]> column = getWidget().getColumn(columnIndex);
- GridColumnState columnState = getState().columns.get(columnIndex);
- updateColumnFromState(column, columnState);
- }
-
- /**
- * Adds a new column to the grid widget from a state change event
- *
- * @param columnIndex
- * The index of the column, according to how it
- */
- private void addColumnFromStateChangeEvent(int columnIndex) {
- GridColumnState state = getState().columns.get(columnIndex);
- CustomGridColumn column = new CustomGridColumn(columnIndex);
- updateColumnFromState(column, state);
-
- columnIdToColumn.put(state.id, column);
-
- getWidget().addColumn(column, columnIndex);
- }
-
- /**
- * Updates the column values from a state
- *
- * @param column
- * The column to update
- * @param state
- * The state to get the data from
- */
- private static void updateColumnFromState(GridColumn<?, String[]> column,
- GridColumnState state) {
- column.setVisible(state.visible);
- column.setHeaderCaption(state.header);
- column.setFooterCaption(state.footer);
- column.setWidth(state.width);
- }
-
- /**
- * Removes any orphan columns that has been removed from the state from the
- * grid
- */
- private void purgeRemovedColumns() {
-
- // Get columns still registered in the state
- Set<String> columnsInState = new HashSet<String>();
- for (GridColumnState columnState : getState().columns) {
- columnsInState.add(columnState.id);
- }
-
- // Remove column no longer in state
- Iterator<String> columnIdIterator = columnIdToColumn.keySet()
- .iterator();
- while (columnIdIterator.hasNext()) {
- String id = columnIdIterator.next();
- if (!columnsInState.contains(id)) {
- CustomGridColumn column = columnIdToColumn.get(id);
- columnIdIterator.remove();
- getWidget().removeColumn(column);
- }
- }
- }
-
- /**
- * Updates the column groups from a state change
- */
- private void updateColumnGroupsFromStateChangeEvent() {
-
- // FIXME When something changes the header/footer rows will be
- // re-created. At some point we should optimize this so partial updates
- // can be made on the header/footer.
- for (ColumnGroupRow<String[]> row : getWidget().getColumnGroupRows()) {
- getWidget().removeColumnGroupRow(row);
- }
-
- for (ColumnGroupRowState rowState : getState().columnGroupRows) {
- ColumnGroupRow<String[]> row = getWidget().addColumnGroupRow();
- row.setFooterVisible(rowState.footerVisible);
- row.setHeaderVisible(rowState.headerVisible);
-
- for (ColumnGroupState groupState : rowState.groups) {
- List<GridColumn<String, String[]>> columns = new ArrayList<GridColumn<String, String[]>>();
- for (String columnId : groupState.columns) {
- CustomGridColumn column = columnIdToColumn.get(columnId);
- columns.add(column);
- }
- ColumnGroup<String[]> group = row.addGroup(columns
- .toArray(new GridColumn[columns.size()]));
- group.setFooterCaption(groupState.footer);
- group.setHeaderCaption(groupState.header);
- }
- }
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/PositionFunction.java b/client/src/com/vaadin/client/ui/grid/PositionFunction.java
deleted file mode 100644
index e41e533996..0000000000
--- a/client/src/com/vaadin/client/ui/grid/PositionFunction.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style.Unit;
-
-/**
- * A functional interface that can be used for positioning elements in the DOM.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-interface PositionFunction {
- /**
- * A position function using "transform: translate3d(x,y,z)" to position
- * elements in the DOM.
- */
- public static class Translate3DPosition implements PositionFunction {
- @Override
- public void set(Element e, double x, double y) {
- e.getStyle().setProperty("transform",
- "translate3d(" + x + "px, " + y + "px, 0)");
- }
-
- @Override
- public void reset(Element e) {
- e.getStyle().clearProperty("transform");
- }
- }
-
- /**
- * A position function using "transform: translate(x,y)" to position
- * elements in the DOM.
- */
- public static class TranslatePosition implements PositionFunction {
- @Override
- public void set(Element e, double x, double y) {
- e.getStyle().setProperty("transform",
- "translate(" + x + "px," + y + "px)");
- }
-
- @Override
- public void reset(Element e) {
- e.getStyle().clearProperty("transform");
- }
- }
-
- /**
- * A position function using "-webkit-transform: translate3d(x,y,z)" to
- * position elements in the DOM.
- */
- public static class WebkitTranslate3DPosition implements PositionFunction {
- @Override
- public void set(Element e, double x, double y) {
- e.getStyle().setProperty("webkitTransform",
- "translate3d(" + x + "px," + y + "px,0)");
- }
-
- @Override
- public void reset(Element e) {
- e.getStyle().clearProperty("webkitTransform");
- }
- }
-
- /**
- * A position function using "left: x" and "top: y" to position elements in
- * the DOM.
- */
- public static class AbsolutePosition implements PositionFunction {
- @Override
- public void set(Element e, double x, double y) {
- e.getStyle().setLeft(x, Unit.PX);
- e.getStyle().setTop(y, Unit.PX);
- }
-
- @Override
- public void reset(Element e) {
- e.getStyle().clearLeft();
- e.getStyle().clearTop();
- }
- }
-
- /**
- * Position an element in an (x,y) coordinate system in the DOM.
- *
- * @param e
- * the element to position. Never <code>null</code>.
- * @param x
- * the x coordinate, in pixels
- * @param y
- * the y coordinate, in pixels
- */
- void set(Element e, double x, double y);
-
- /**
- * Resets any previously applied positioning, clearing the used style
- * attributes.
- *
- * @param e
- * the element for which to reset the positioning
- */
- void reset(Element e);
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/grid/Renderer.java b/client/src/com/vaadin/client/ui/grid/Renderer.java
deleted file mode 100644
index 3312ec87e4..0000000000
--- a/client/src/com/vaadin/client/ui/grid/Renderer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-/**
- * Renderer for rending a value &lt;T&gt; into cell.
- * <p>
- * You can add a renderer to any column by overring the
- * {@link GridColumn#getRenderer()} method and returning your own renderer. You
- * can retrieve the cell element using {@link Cell#getElement()}.
- *
- * @param <T>
- * The column type
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface Renderer<T> {
-
- /**
- * Called whenever the {@link Grid} updates a cell
- *
- * @param cell
- * The cell that gets updated
- *
- * @param data
- * The column data object
- */
- public void renderCell(Cell cell, T data);
-}
diff --git a/client/src/com/vaadin/client/ui/grid/Row.java b/client/src/com/vaadin/client/ui/grid/Row.java
deleted file mode 100644
index 209da58fec..0000000000
--- a/client/src/com/vaadin/client/ui/grid/Row.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.dom.client.Element;
-
-/**
- * A representation of a row in an {@link Escalator}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface Row {
- /**
- * Gets the escalator containing the row.
- *
- * @return the escalator containing the row
- */
- public Escalator getEscalator();
-
- /**
- * Gets the row index.
- *
- * @return the row index
- */
- public int getRow();
-
- /**
- * Gets the root element for this row.
- * <p>
- * The {@link EscalatorUpdater} may update the class names of the element
- * and add inline styles, but may not modify the contained DOM structure.
- * <p>
- * If you wish to modify the cells within this row element, access them via
- * the <code>List&lt;{@link Cell}&gt;</code> objects passed in to
- * {@code EscalatorUpdater.updateCells(Row, List)}
- *
- * @return the root element of the row
- */
- public Element getElement();
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/grid/RowContainer.java b/client/src/com/vaadin/client/ui/grid/RowContainer.java
deleted file mode 100644
index 0312164569..0000000000
--- a/client/src/com/vaadin/client/ui/grid/RowContainer.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-/**
- * A representation of the rows in each of the sections (header, body and
- * footer) in an {@link Escalator}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see Escalator#getHeader()
- * @see Escalator#getBody()
- * @see Escalator#getFooter()
- */
-public interface RowContainer {
-
- /**
- * An arbitrary pixel height of a row, before any autodetection for the row
- * height has been made.
- * */
- public static final int INITIAL_DEFAULT_ROW_HEIGHT = 20;
-
- /**
- * Returns the current {@link EscalatorUpdater} used to render cells.
- *
- * @return the current escalator updater
- */
- public EscalatorUpdater getEscalatorUpdater();
-
- /**
- * Sets the {@link EscalatorUpdater} to use when displaying data in the
- * escalator.
- *
- * @param escalatorUpdater
- * the escalator updater to use to render cells. May not be
- * <code>null</code>
- * @throws IllegalArgumentException
- * if {@code cellRenderer} is <code>null</code>
- * @see EscalatorUpdater#NULL
- */
- public void setEscalatorUpdater(EscalatorUpdater escalatorUpdater)
- throws IllegalArgumentException;
-
- /**
- * Removes rows at a certain index in the current row container.
- *
- * @param index
- * the index of the first row to be removed
- * @param numberOfRows
- * the number of rows to remove, starting from the index
- * @throws IndexOutOfBoundsException
- * if any integer number in the range
- * <code>[index..(index+numberOfRows)]</code> is not an existing
- * row index
- * @throws IllegalArgumentException
- * if {@code numberOfRows} is less than 1.
- */
- public void removeRows(int index, int numberOfRows)
- throws IndexOutOfBoundsException, IllegalArgumentException;
-
- /**
- * Adds rows at a certain index in this row container.
- * <p>
- * The new rows will be inserted between the row at the index, and the row
- * before (an index of 0 means that the rows are inserted at the beginning).
- * Therefore, the rows currently at the index and afterwards will be moved
- * downwards.
- * <p>
- * The contents of the inserted rows will subsequently be queried from the
- * escalator updater.
- * <p>
- * <em>Note:</em> Only the contents of the inserted rows will be rendered.
- * If inserting new rows affects the contents of existing rows,
- * {@link #refreshRows(int, int)} needs to be called for those rows
- * separately.
- *
- * @param index
- * the index of the row before which new rows are inserted, or
- * {@link #getRowCount()} to add rows at the end
- * @param numberOfRows
- * the number of rows to insert after the <code>index</code>
- * @see #setEscalatorUpdater(EscalatorUpdater)
- * @throws IndexOutOfBoundsException
- * if <code>index</code> is not an integer in the range
- * <code>[0..{@link #getRowCount()}]</code>
- * @throws IllegalArgumentException
- * if {@code numberOfRows} is less than 1.
- */
- public void insertRows(int index, int numberOfRows)
- throws IndexOutOfBoundsException, IllegalArgumentException;
-
- /**
- * Refreshes a range of rows in the current row container.
- * <p>
- * The data for the refreshed rows are queried from the current cell
- * renderer.
- *
- * @param index
- * the index of the first row that will be updated
- * @param numberOfRows
- * the number of rows to update, starting from the index
- * @see #setEscalatorUpdater(EscalatorUpdater)
- * @throws IndexOutOfBoundsException
- * if any integer number in the range
- * <code>[index..(index+numberOfColumns)]</code> is not an
- * existing column index.
- * @throws IllegalArgumentException
- * if {@code numberOfRows} is less than 1.
- */
- public void refreshRows(int index, int numberOfRows)
- throws IndexOutOfBoundsException, IllegalArgumentException;
-
- /**
- * Gets the number of rows in the current row container.
- *
- * @return the number of rows in the current row container
- */
- public int getRowCount();
-
- /**
- * The default height of the rows in this RowContainer.
- *
- * @param px
- * the default height in pixels of the rows in this RowContainer
- * @throws IllegalArgumentException
- * if <code>px &lt; 1</code>
- * @see #getDefaultRowHeight()
- */
- public void setDefaultRowHeight(int px) throws IllegalArgumentException;
-
- /**
- * Returns the default height of the rows in this RowContainer.
- * <p>
- * This value will be equal to {@link #INITIAL_DEFAULT_ROW_HEIGHT} if the
- * {@link Escalator} has not yet had a chance to autodetect the row height,
- * or no explicit value has yet given via {@link #setDefaultRowHeight(int)}
- *
- * @return the default height of the rows in this RowContainer, in pixels
- * @see #setDefaultRowHeight(int)
- */
- public int getDefaultRowHeight();
-}
diff --git a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java
deleted file mode 100644
index 0e9652e215..0000000000
--- a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.event.shared.GwtEvent;
-
-/**
- * Event fired when the range of visible rows changes e.g. because of scrolling.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class RowVisibilityChangeEvent extends
- GwtEvent<RowVisibilityChangeHandler> {
- /**
- * The type of this event.
- */
- public static final Type<RowVisibilityChangeHandler> TYPE = new Type<RowVisibilityChangeHandler>();
-
- private final int firstVisibleRow;
- private final int visibleRowCount;
-
- /**
- * Creates a new row visibility change event
- *
- * @param firstVisibleRow
- * the index of the first visible row
- * @param visibleRowCount
- * the number of visible rows
- */
- public RowVisibilityChangeEvent(int firstVisibleRow, int visibleRowCount) {
- this.firstVisibleRow = firstVisibleRow;
- this.visibleRowCount = visibleRowCount;
- }
-
- /**
- * Gets the index of the first row that is at least partially visible.
- *
- * @return the index of the first visible row
- */
- public int getFirstVisibleRow() {
- return firstVisibleRow;
- }
-
- /**
- * Gets the number of at least partially visible rows.
- *
- * @return the number of visible rows
- */
- public int getVisibleRowCount() {
- return visibleRowCount;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.event.shared.GwtEvent#getAssociatedType()
- */
- @Override
- public Type<RowVisibilityChangeHandler> getAssociatedType() {
- return TYPE;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event.shared
- * .EventHandler)
- */
- @Override
- protected void dispatch(RowVisibilityChangeHandler handler) {
- handler.onRowVisibilityChange(this);
- }
-
-}
diff --git a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java
deleted file mode 100644
index dd24521499..0000000000
--- a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.event.shared.EventHandler;
-
-/**
- * Event handler that gets notified when the range of visible rows changes e.g.
- * because of scrolling.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface RowVisibilityChangeHandler extends EventHandler {
-
- /**
- * Called when the range of visible rows changes e.g. because of scrolling.
- *
- * @param event
- * the row visibility change event describing the change
- */
- void onRowVisibilityChange(RowVisibilityChangeEvent event);
-
-}
diff --git a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java b/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java
deleted file mode 100644
index b9267178c1..0000000000
--- a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style.Overflow;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.user.client.DOM;
-
-/**
- * An element-like bundle representing a configurable and visual scrollbar in
- * one axis.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see VerticalScrollbarBundle
- * @see HorizontalScrollbarBundle
- */
-abstract class ScrollbarBundle {
-
- /**
- * The pixel size for OSX's invisible scrollbars.
- * <p>
- * Touch devices don't show a scrollbar at all, so the scrollbar size is
- * irrelevant in their case. There doesn't seem to be any other popular
- * platforms that has scrollbars similar to OSX. Thus, this behavior is
- * tailored for OSX only, until additional platforms start behaving this
- * way.
- */
- private static final int OSX_INVISIBLE_SCROLLBAR_FAKE_SIZE_PX = 13;
-
- /**
- * A representation of a single vertical scrollbar.
- *
- * @see VerticalScrollbarBundle#getElement()
- */
- final static class VerticalScrollbarBundle extends ScrollbarBundle {
-
- @Override
- public void setStylePrimaryName(String primaryStyleName) {
- super.setStylePrimaryName(primaryStyleName);
- root.addClassName(primaryStyleName + "-scroller-vertical");
- }
-
- @Override
- protected void internalSetScrollPos(int px) {
- root.setScrollTop(px);
- }
-
- @Override
- protected int internalGetScrollPos() {
- return root.getScrollTop();
- }
-
- @Override
- protected void internalSetScrollSize(int px) {
- scrollSizeElement.getStyle().setHeight(px, Unit.PX);
- }
-
- @Override
- public int getScrollSize() {
- return scrollSizeElement.getOffsetHeight();
- }
-
- @Override
- protected void internalSetOffsetSize(int px) {
- root.getStyle().setHeight(px, Unit.PX);
- }
-
- @Override
- public int getOffsetSize() {
- return root.getOffsetHeight();
- }
-
- @Override
- protected void internalSetScrollbarThickness(int px) {
- root.getStyle().setWidth(px, Unit.PX);
- scrollSizeElement.getStyle().setWidth(px, Unit.PX);
- }
-
- @Override
- protected int internalGetScrollbarThickness() {
- return root.getOffsetWidth();
- }
-
- @Override
- protected void forceScrollbar(boolean enable) {
- if (enable) {
- root.getStyle().setOverflowY(Overflow.SCROLL);
- } else {
- root.getStyle().clearOverflowY();
- }
- }
- }
-
- /**
- * A representation of a single horizontal scrollbar.
- *
- * @see HorizontalScrollbarBundle#getElement()
- */
- final static class HorizontalScrollbarBundle extends ScrollbarBundle {
-
- @Override
- public void setStylePrimaryName(String primaryStyleName) {
- super.setStylePrimaryName(primaryStyleName);
- root.addClassName(primaryStyleName + "-scroller-horizontal");
- }
-
- @Override
- protected void internalSetScrollPos(int px) {
- root.setScrollLeft(px);
- }
-
- @Override
- protected int internalGetScrollPos() {
- return root.getScrollLeft();
- }
-
- @Override
- protected void internalSetScrollSize(int px) {
- scrollSizeElement.getStyle().setWidth(px, Unit.PX);
- }
-
- @Override
- public int getScrollSize() {
- return scrollSizeElement.getOffsetWidth();
- }
-
- @Override
- protected void internalSetOffsetSize(int px) {
- root.getStyle().setWidth(px, Unit.PX);
- }
-
- @Override
- public int getOffsetSize() {
- return root.getOffsetWidth();
- }
-
- @Override
- protected void internalSetScrollbarThickness(int px) {
- root.getStyle().setHeight(px, Unit.PX);
- scrollSizeElement.getStyle().setHeight(px, Unit.PX);
- }
-
- @Override
- protected int internalGetScrollbarThickness() {
- return root.getOffsetHeight();
- }
-
- @Override
- protected void forceScrollbar(boolean enable) {
- if (enable) {
- root.getStyle().setOverflowX(Overflow.SCROLL);
- } else {
- root.getStyle().clearOverflowX();
- }
- }
- }
-
- protected final Element root = DOM.createDiv();
- protected final Element scrollSizeElement = DOM.createDiv();
- protected boolean isInvisibleScrollbar = false;
-
- private int scrollPos = 0;
- private int maxScrollPos = 0;
-
- private ScrollbarBundle() {
- root.appendChild(scrollSizeElement);
- }
-
- /**
- * Sets the primary style name
- *
- * @param primaryStyleName
- * The primary style name to use
- */
- public void setStylePrimaryName(String primaryStyleName) {
- root.setClassName(primaryStyleName + "-scroller");
- }
-
- /**
- * Gets the root element of this scrollbar-composition.
- *
- * @return the root element
- */
- public final Element getElement() {
- return root;
- }
-
- /**
- * Modifies the scroll position of this scrollbar by a number of pixels
- *
- * @param delta
- * the delta in pixels to change the scroll position by
- */
- public final void setScrollPosByDelta(int delta) {
- if (delta != 0) {
- setScrollPos(getScrollPos() + delta);
- }
- }
-
- /**
- * Modifies {@link #root root's} dimensions in the axis the scrollbar is
- * representing.
- *
- * @param px
- * the new size of {@link #root} in the dimension this scrollbar
- * is representing
- */
- protected abstract void internalSetOffsetSize(int px);
-
- /**
- * Sets the length of the scrollbar.
- *
- * @param px
- * the length of the scrollbar in pixels
- */
- public final void setOffsetSize(int px) {
- internalSetOffsetSize(px);
- forceScrollbar(showsScrollHandle());
- recalculateMaxScrollPos();
- }
-
- /**
- * Force the scrollbar to be visible with CSS. In practice, this means to
- * set either <code>overflow-x</code> or <code>overflow-y</code> to "
- * <code>scroll</code>" in the scrollbar's direction.
- * <p>
- * This is an IE8 workaround, since it doesn't always show scrollbars with
- * <code>overflow: auto</code> enabled.
- */
- protected abstract void forceScrollbar(boolean enable);
-
- /**
- * Gets the length of the scrollbar
- *
- * @return the length of the scrollbar in pixels
- */
- public abstract int getOffsetSize();
-
- /**
- * Sets the scroll position of the scrollbar in the axis the scrollbar is
- * representing.
- *
- * @param px
- * the new scroll position in pixels
- */
- public final void setScrollPos(int px) {
- int oldScrollPos = scrollPos;
- scrollPos = Math.max(0, Math.min(maxScrollPos, px));
-
- if (oldScrollPos != scrollPos) {
- internalSetScrollPos(px);
- }
- }
-
- protected abstract void internalSetScrollPos(int px);
-
- /**
- * Gets the scroll position of the scrollbar in the axis the scrollbar is
- * representing.
- *
- * @return the new scroll position in pixels
- */
- public final int getScrollPos() {
- assert internalGetScrollPos() == scrollPos : "calculated scroll position ("
- + scrollPos
- + ") did not match the DOM element scroll position ("
- + internalGetScrollPos() + ")";
- return scrollPos;
- }
-
- protected abstract int internalGetScrollPos();
-
- /**
- * Modifies {@link #scrollSizeElement scrollSizeElement's} dimensions in
- * such a way that the scrollbar is able to scroll a certain number of
- * pixels in the axis it is representing.
- *
- * @param px
- * the new size of {@link #scrollSizeElement} in the dimension
- * this scrollbar is representing
- */
- protected abstract void internalSetScrollSize(int px);
-
- /**
- * Sets the amount of pixels the scrollbar needs to be able to scroll
- * through.
- *
- * @param px
- * the number of pixels the scrollbar should be able to scroll
- * through
- */
- public final void setScrollSize(int px) {
- internalSetScrollSize(px);
- forceScrollbar(showsScrollHandle());
- recalculateMaxScrollPos();
- }
-
- /**
- * Gets the amount of pixels the scrollbar needs to be able to scroll
- * through.
- *
- * @return the number of pixels the scrollbar should be able to scroll
- * through
- */
- public abstract int getScrollSize();
-
- /**
- * Modifies {@link #scrollSizeElement scrollSizeElement's} dimensions in the
- * opposite axis to what the scrollbar is representing.
- *
- * @param px
- * the dimension that {@link #scrollSizeElement} should take in
- * the opposite axis to what the scrollbar is representing
- */
- protected abstract void internalSetScrollbarThickness(int px);
-
- /**
- * Sets the scrollbar's thickness.
- * <p>
- * If the thickness is set to 0, the scrollbar will be treated as an
- * "invisible" scrollbar. This means, the DOM structure will be given a
- * non-zero size, but {@link #getScrollbarThickness()} will still return the
- * value 0.
- *
- * @param px
- * the scrollbar's thickness in pixels
- */
- public final void setScrollbarThickness(int px) {
- isInvisibleScrollbar = (px == 0);
- internalSetScrollbarThickness(px != 0 ? px
- : OSX_INVISIBLE_SCROLLBAR_FAKE_SIZE_PX);
- }
-
- /**
- * Gets the scrollbar's thickness as defined in the DOM.
- *
- * @return the scrollbar's thickness as defined in the DOM, in pixels
- */
- protected abstract int internalGetScrollbarThickness();
-
- /**
- * Gets the scrollbar's thickness.
- * <p>
- * This value will differ from the value in the DOM, if the thickness was
- * set to 0 with {@link #setScrollbarThickness(int)}, as the scrollbar is
- * then treated as "invisible."
- *
- * @return the scrollbar's thickness in pixels
- */
- public final int getScrollbarThickness() {
- if (!isInvisibleScrollbar) {
- return internalGetScrollbarThickness();
- } else {
- return 0;
- }
- }
-
- /**
- * Checks whether the scrollbar's handle is visible.
- * <p>
- * In other words, this method checks whether the contents is larger than
- * can visually fit in the element.
- *
- * @return <code>true</code> iff the scrollbar's handle is visible
- */
- public boolean showsScrollHandle() {
- return getOffsetSize() < getScrollSize();
- }
-
- public void recalculateMaxScrollPos() {
- int scrollSize = getScrollSize();
- int offsetSize = getOffsetSize();
- maxScrollPos = Math.max(0, scrollSize - offsetSize);
-
- // make sure that the correct max scroll position is maintained.
- setScrollPos(scrollPos);
- }
-
- /**
- * This is a method that JSNI can call to synchronize the object state from
- * the DOM.
- */
- @SuppressWarnings("unused")
- private final void updateScrollPosFromDom() {
- scrollPos = internalGetScrollPos();
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java
deleted file mode 100644
index 0a3edbd349..0000000000
--- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * 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.client.ui.grid.datasources;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-import com.vaadin.client.data.DataChangeHandler;
-import com.vaadin.client.data.DataSource;
-
-/**
- * A simple list based on an in-memory data source for simply adding a list of
- * row pojos to the grid. Based on a wrapped list instance which supports adding
- * and removing of items.
- *
- * <p>
- * Usage:
- *
- * <pre>
- * ListDataSource&lt;Integer&gt; ds = new ListDataSource&lt;Integer&gt;(1, 2, 3, 4);
- *
- * // Add item to the data source
- * ds.asList().add(5);
- *
- * // Remove item from the data source
- * ds.asList().remove(3);
- *
- * // Add multiple items
- * ds.asList().addAll(Arrays.asList(5, 6, 7));
- * </pre>
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ListDataSource<T> implements DataSource<T> {
-
- /**
- * Wraps the datasource list and notifies the change handler of changing to
- * the list
- */
- private class ListWrapper implements List<T> {
-
- @Override
- public int size() {
- return ds.size();
- }
-
- @Override
- public boolean isEmpty() {
- return ds.isEmpty();
- }
-
- @Override
- public boolean contains(Object o) {
- return contains(o);
- }
-
- @Override
- public Iterator<T> iterator() {
- return new ListWrapperIterator(ds.iterator());
- }
-
- @Override
- public Object[] toArray() {
- return ds.toArray();
- }
-
- @Override
- public <T> T[] toArray(T[] a) {
- return toArray(a);
- }
-
- @Override
- public boolean add(T e) {
- if (ds.add(e)) {
- if (changeHandler != null) {
- changeHandler.dataAdded(ds.size() - 1, 1);
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean remove(Object o) {
- int index = ds.indexOf(o);
- if (ds.remove(o)) {
- if (changeHandler != null) {
- changeHandler.dataRemoved(index, 1);
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean containsAll(Collection<?> c) {
- return ds.containsAll(c);
- }
-
- @Override
- public boolean addAll(Collection<? extends T> c) {
- int idx = ds.size();
- if (ds.addAll(c)) {
- if (changeHandler != null) {
- changeHandler.dataAdded(idx, c.size());
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean addAll(int index, Collection<? extends T> c) {
- if (ds.addAll(index, c)) {
- if (changeHandler != null) {
- changeHandler.dataAdded(index, c.size());
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- if (ds.removeAll(c)) {
- if (changeHandler != null) {
- // Have to update the whole list as the removal does not
- // have to be a continuous range
- changeHandler.dataUpdated(0, ds.size());
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- if (ds.retainAll(c)) {
- if (changeHandler != null) {
- // Have to update the whole list as the retain does not
- // have to be a continuous range
- changeHandler.dataUpdated(0, ds.size());
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void clear() {
- int size = ds.size();
- ds.clear();
- if (changeHandler != null) {
- changeHandler.dataRemoved(0, size);
- }
- }
-
- @Override
- public T get(int index) {
- return ds.get(index);
- }
-
- @Override
- public T set(int index, T element) {
- T prev = ds.set(index, element);
- if (changeHandler != null) {
- changeHandler.dataUpdated(index, 1);
- }
- return prev;
- }
-
- @Override
- public void add(int index, T element) {
- ds.add(index, element);
- if (changeHandler != null) {
- changeHandler.dataAdded(index, 1);
- }
- }
-
- @Override
- public T remove(int index) {
- T removed = ds.remove(index);
- if (changeHandler != null) {
- changeHandler.dataRemoved(index, 1);
- }
- return removed;
- }
-
- @Override
- public int indexOf(Object o) {
- return ds.indexOf(o);
- }
-
- @Override
- public int lastIndexOf(Object o) {
- return ds.lastIndexOf(o);
- }
-
- @Override
- public ListIterator<T> listIterator() {
- // TODO could be implemented by a custom iterator.
- throw new UnsupportedOperationException(
- "List iterators not supported at this time.");
- }
-
- @Override
- public ListIterator<T> listIterator(int index) {
- // TODO could be implemented by a custom iterator.
- throw new UnsupportedOperationException(
- "List iterators not supported at this time.");
- }
-
- @Override
- public List<T> subList(int fromIndex, int toIndex) {
- throw new UnsupportedOperationException("Sub lists not supported.");
- }
- }
-
- /**
- * Iterator returned by {@link ListWrapper}
- */
- private class ListWrapperIterator implements Iterator<T> {
-
- private final Iterator<T> iterator;
-
- /**
- * Constructs a new iterator
- */
- public ListWrapperIterator(Iterator<T> iterator) {
- this.iterator = iterator;
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public T next() {
- return iterator.next();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException(
- "Iterator.remove() is not supported by this iterator.");
- }
- }
-
- /**
- * Datasource for providing row pojo's
- */
- private final List<T> ds;
-
- /**
- * Wrapper that wraps the data source
- */
- private final ListWrapper wrapper;
-
- /**
- * Handler for listening to changes in the underlying list.
- */
- private DataChangeHandler changeHandler;
-
- /**
- * Constructs a new list data source.
- * <p>
- * Note: Modifications to the original list will not be reflected in the
- * data source after the data source has been constructed. To add or remove
- * items to the data source after it has been constructed use
- * {@link ListDataSource#asList()}.
- *
- *
- * @param datasource
- * The list to use for providing the data to the grid
- */
- public ListDataSource(List<T> datasource) {
- if (datasource == null) {
- throw new IllegalArgumentException("datasource cannot be null");
- }
- ds = new ArrayList<T>(datasource);
- wrapper = new ListWrapper();
- }
-
- /**
- * Constructs a data source with a set of rows. You can dynamically add and
- * remove rows from the data source via the list you get from
- * {@link ListDataSource#asList()}
- *
- * @param rows
- * The rows to initially add to the data source
- */
- public ListDataSource(T... rows) {
- if (rows == null) {
- ds = new ArrayList<T>();
- } else {
- ds = new ArrayList<T>(Arrays.asList(rows));
- }
- wrapper = new ListWrapper();
- }
-
- @Override
- public void ensureAvailability(int firstRowIndex, int numberOfRows) {
- if (firstRowIndex >= ds.size()) {
- throw new IllegalStateException(
- "Trying to fetch rows outside of array");
- }
- }
-
- @Override
- public T getRow(int rowIndex) {
- return ds.get(rowIndex);
- }
-
- @Override
- public int getEstimatedSize() {
- return ds.size();
- }
-
- @Override
- public void setDataChangeHandler(DataChangeHandler dataChangeHandler) {
- this.changeHandler = dataChangeHandler;
- }
-
- /**
- * Gets the list that backs this datasource. Any changes made to this list
- * will be reflected in the datasource.
- * <p>
- * Note: The list is not the same list as passed into the data source via
- * the constructor.
- *
- * @return Returns a list implementation that wraps the real list that backs
- * the data source and provides events for the data source
- * listeners.
- */
- public List<T> asList() {
- return wrapper;
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java
deleted file mode 100644
index d1f770f414..0000000000
--- a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.client.ui.grid.renderers;
-
-import java.util.Date;
-
-import com.google.gwt.i18n.client.DateTimeFormat;
-import com.google.gwt.i18n.client.TimeZone;
-import com.vaadin.client.ui.grid.Cell;
-import com.vaadin.client.ui.grid.Renderer;
-
-/**
- * A renderer for rendering dates into cells
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class DateRenderer implements Renderer<Date> {
-
- private DateTimeFormat format = DateTimeFormat.getShortDateTimeFormat();
-
- private TimeZone timeZone = TimeZone.createTimeZone(new Date()
- .getTimezoneOffset());
-
- @Override
- public void renderCell(Cell cell, Date date) {
- String dateStr = format.format(date, timeZone);
- cell.getElement().setInnerText(dateStr);
- }
-
- /**
- * Gets the format of how the date is formatted.
- *
- * @return the format
- * @see <a
- * href="http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/client/DateTimeFormat.html">GWT
- * documentation on DateTimeFormat</a>
- */
- public DateTimeFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format used for formatting the dates.
- *
- * @param format
- * the format to set
- * @see <a
- * href="http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/client/DateTimeFormat.html">GWT
- * documentation on DateTimeFormat</a>
- */
- public void setFormat(DateTimeFormat format) {
- if (format == null) {
- throw new IllegalArgumentException("Format should not be null");
- }
- this.format = format;
- }
-
- /**
- * Returns the time zone of the date.
- *
- * @return the time zone
- */
- public TimeZone getTimeZone() {
- return timeZone;
- }
-
- /**
- * Sets the time zone of the the date. By default uses the time zone of the
- * browser.
- *
- * @param timeZone
- * the timeZone to set
- */
- public void setTimeZone(TimeZone timeZone) {
- if (timeZone == null) {
- throw new IllegalArgumentException("Timezone should not be null");
- }
- this.timeZone = timeZone;
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java
deleted file mode 100644
index 0787dc2332..0000000000
--- a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.client.ui.grid.renderers;
-
-import com.google.gwt.safehtml.shared.SafeHtml;
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
-import com.vaadin.client.ui.grid.Cell;
-import com.vaadin.client.ui.grid.Renderer;
-
-/**
- * Renders a string as HTML into a cell.
- * <p>
- * The html string is rendered as is without any escaping. It is up to the
- * developer to ensure that the html string honors the {@link SafeHtml}
- * contract. For more information see
- * {@link SafeHtmlUtils#fromSafeConstant(String)}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @see SafeHtmlUtils#fromSafeConstant(String)
- */
-public class HtmlRenderer implements Renderer<String> {
-
- @Override
- public void renderCell(Cell cell, String htmlString) {
- cell.getElement().setInnerSafeHtml(
- SafeHtmlUtils.fromSafeConstant(htmlString));
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java
deleted file mode 100644
index f4efea33a5..0000000000
--- a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.client.ui.grid.renderers;
-
-import com.google.gwt.i18n.client.NumberFormat;
-import com.vaadin.client.ui.grid.Cell;
-import com.vaadin.client.ui.grid.Renderer;
-
-/**
- * Renders a number into a cell using a specific {@link NumberFormat}. By
- * default uses the default number format returned by
- * {@link NumberFormat#getDecimalFormat()}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- * @param <T>
- * The number type to render.
- */
-public class NumberRenderer<T extends Number> implements Renderer<T> {
-
- private NumberFormat format = NumberFormat.getDecimalFormat();
-
- /**
- * Gets the number format that the number should be formatted in.
- *
- * @return the number format used to render the number
- */
- public NumberFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the number format to use for formatting the number.
- *
- * @param format
- * the format to use
- * @throws IllegalArgumentException
- * when the format is null
- */
- public void setFormat(NumberFormat format) throws IllegalArgumentException {
- if (format == null) {
- throw new IllegalArgumentException("Format cannot be null");
- }
- this.format = format;
- }
-
- @Override
- public void renderCell(Cell cell, Number number) {
- cell.getElement().setInnerText(format.format(number));
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java
deleted file mode 100644
index 1f06a555c3..0000000000
--- a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.client.ui.grid.renderers;
-
-import com.vaadin.client.ui.grid.Cell;
-import com.vaadin.client.ui.grid.Renderer;
-
-/**
- * Renderer that renders text into a cell.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class TextRenderer implements Renderer<String> {
-
- @Override
- public void renderCell(Cell cell, String text) {
- cell.getElement().setInnerText(text);
- }
-}
diff --git a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java
deleted file mode 100644
index 5c5e88bf69..0000000000
--- a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-
-import org.easymock.EasyMock;
-import org.junit.Test;
-
-import com.vaadin.client.data.DataChangeHandler;
-import com.vaadin.client.ui.grid.datasources.ListDataSource;
-
-/**
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ListDataSourceTest {
-
- @Test
- public void testDataSourceConstruction() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- assertEquals(4, ds.getEstimatedSize());
- assertEquals(0, (int) ds.getRow(0));
- assertEquals(1, (int) ds.getRow(1));
- assertEquals(2, (int) ds.getRow(2));
- assertEquals(3, (int) ds.getRow(3));
-
- ds = new ListDataSource<Integer>(Arrays.asList(0, 1, 2, 3));
-
- assertEquals(4, ds.getEstimatedSize());
- assertEquals(0, (int) ds.getRow(0));
- assertEquals(1, (int) ds.getRow(1));
- assertEquals(2, (int) ds.getRow(2));
- assertEquals(3, (int) ds.getRow(3));
- }
-
- @Test
- public void testListAddOperation() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- DataChangeHandler handler = EasyMock
- .createNiceMock(DataChangeHandler.class);
- ds.setDataChangeHandler(handler);
-
- handler.dataAdded(4, 1);
- EasyMock.expectLastCall();
-
- EasyMock.replay(handler);
-
- ds.asList().add(4);
-
- assertEquals(5, ds.getEstimatedSize());
- assertEquals(0, (int) ds.getRow(0));
- assertEquals(1, (int) ds.getRow(1));
- assertEquals(2, (int) ds.getRow(2));
- assertEquals(3, (int) ds.getRow(3));
- assertEquals(4, (int) ds.getRow(4));
- }
-
- @Test
- public void testListAddAllOperation() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- DataChangeHandler handler = EasyMock
- .createNiceMock(DataChangeHandler.class);
- ds.setDataChangeHandler(handler);
-
- handler.dataAdded(4, 3);
- EasyMock.expectLastCall();
-
- EasyMock.replay(handler);
-
- ds.asList().addAll(Arrays.asList(4, 5, 6));
-
- assertEquals(7, ds.getEstimatedSize());
- assertEquals(0, (int) ds.getRow(0));
- assertEquals(1, (int) ds.getRow(1));
- assertEquals(2, (int) ds.getRow(2));
- assertEquals(3, (int) ds.getRow(3));
- assertEquals(4, (int) ds.getRow(4));
- assertEquals(5, (int) ds.getRow(5));
- assertEquals(6, (int) ds.getRow(6));
- }
-
- @Test
- public void testListRemoveOperation() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- DataChangeHandler handler = EasyMock
- .createNiceMock(DataChangeHandler.class);
- ds.setDataChangeHandler(handler);
-
- handler.dataRemoved(3, 1);
- EasyMock.expectLastCall();
-
- EasyMock.replay(handler);
-
- ds.asList().remove(2);
-
- assertEquals(3, ds.getEstimatedSize());
- assertEquals(0, (int) ds.getRow(0));
- assertEquals(1, (int) ds.getRow(1));
- assertEquals(3, (int) ds.getRow(2));
- }
-
- @Test
- public void testListRemoveAllOperation() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- DataChangeHandler handler = EasyMock
- .createNiceMock(DataChangeHandler.class);
- ds.setDataChangeHandler(handler);
-
- handler.dataRemoved(0, 3);
- EasyMock.expectLastCall();
-
- EasyMock.replay(handler);
-
- ds.asList().removeAll(Arrays.asList(0, 2, 3));
-
- assertEquals(1, ds.getEstimatedSize());
- assertEquals(1, (int) ds.getRow(0));
- }
-
- @Test
- public void testListClearOperation() throws Exception {
-
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
-
- DataChangeHandler handler = EasyMock
- .createNiceMock(DataChangeHandler.class);
- ds.setDataChangeHandler(handler);
-
- handler.dataRemoved(0, 4);
- EasyMock.expectLastCall();
-
- EasyMock.replay(handler);
-
- ds.asList().clear();
-
- assertEquals(0, ds.getEstimatedSize());
- }
-
- @Test(expected = IllegalStateException.class)
- public void testFetchingNonExistantItem() {
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
- ds.ensureAvailability(5, 1);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testUnsupportedIteratorRemove() {
- ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
- ds.asList().iterator().remove();
- }
-
-}
diff --git a/client/tests/src/com/vaadin/client/ui/grid/PartitioningTest.java b/client/tests/src/com/vaadin/client/ui/grid/PartitioningTest.java
deleted file mode 100644
index e97bb339e4..0000000000
--- a/client/tests/src/com/vaadin/client/ui/grid/PartitioningTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.client.ui.grid;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.vaadin.shared.ui.grid.Range;
-
-@SuppressWarnings("static-method")
-public class PartitioningTest {
-
- @Test
- public void selfRangeTest() {
- final Range range = Range.between(0, 10);
- final Range[] partitioning = range.partitionWith(range);
-
- assertTrue("before is empty", partitioning[0].isEmpty());
- assertTrue("inside is self", partitioning[1].equals(range));
- assertTrue("after is empty", partitioning[2].isEmpty());
- }
-
- @Test
- public void beforeRangeTest() {
- final Range beforeRange = Range.between(0, 10);
- final Range afterRange = Range.between(10, 20);
- final Range[] partitioning = beforeRange.partitionWith(afterRange);
-
- assertTrue("before is self", partitioning[0].equals(beforeRange));
- assertTrue("inside is empty", partitioning[1].isEmpty());
- assertTrue("after is empty", partitioning[2].isEmpty());
- }
-
- @Test
- public void afterRangeTest() {
- final Range beforeRange = Range.between(0, 10);
- final Range afterRange = Range.between(10, 20);
- final Range[] partitioning = afterRange.partitionWith(beforeRange);
-
- assertTrue("before is empty", partitioning[0].isEmpty());
- assertTrue("inside is empty", partitioning[1].isEmpty());
- assertTrue("after is self", partitioning[2].equals(afterRange));
- }
-
- @Test
- public void beforeAndInsideRangeTest() {
- final Range beforeRange = Range.between(0, 10);
- final Range afterRange = Range.between(5, 15);
- final Range[] partitioning = beforeRange.partitionWith(afterRange);
-
- assertEquals("before", Range.between(0, 5), partitioning[0]);
- assertEquals("inside", Range.between(5, 10), partitioning[1]);
- assertTrue("after is empty", partitioning[2].isEmpty());
- }
-
- @Test
- public void insideRangeTest() {
- final Range fullRange = Range.between(0, 20);
- final Range insideRange = Range.between(5, 15);
- final Range[] partitioning = insideRange.partitionWith(fullRange);
-
- assertTrue("before is empty", partitioning[0].isEmpty());
- assertEquals("inside", Range.between(5, 15), partitioning[1]);
- assertTrue("after is empty", partitioning[2].isEmpty());
- }
-
- @Test
- public void insideAndBelowTest() {
- final Range beforeRange = Range.between(0, 10);
- final Range afterRange = Range.between(5, 15);
- final Range[] partitioning = afterRange.partitionWith(beforeRange);
-
- assertTrue("before is empty", partitioning[0].isEmpty());
- assertEquals("inside", Range.between(5, 10), partitioning[1]);
- assertEquals("after", Range.between(10, 15), partitioning[2]);
- }
-
- @Test
- public void aboveAndBelowTest() {
- final Range fullRange = Range.between(0, 20);
- final Range insideRange = Range.between(5, 15);
- final Range[] partitioning = fullRange.partitionWith(insideRange);
-
- assertEquals("before", Range.between(0, 5), partitioning[0]);
- assertEquals("inside", Range.between(5, 15), partitioning[1]);
- assertEquals("after", Range.between(15, 20), partitioning[2]);
- }
-}
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
deleted file mode 100644
index b22e6a209b..0000000000
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.data;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import com.vaadin.data.Container.Indexed;
-import com.vaadin.server.AbstractExtension;
-import com.vaadin.shared.data.DataProviderRpc;
-import com.vaadin.shared.data.DataProviderState;
-import com.vaadin.shared.data.DataRequestRpc;
-import com.vaadin.ui.components.grid.Grid;
-
-/**
- * Provides Vaadin server-side container data source to a
- * {@link com.vaadin.client.ui.grid.GridConnector}. This is currently
- * implemented as an Extension hardcoded to support a specific connector type.
- * This will be changed once framework support for something more flexible has
- * been implemented.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class RpcDataProviderExtension extends AbstractExtension {
-
- private final Indexed container;
-
- /**
- * Creates a new data provider using the given container.
- *
- * @param container
- * the container to make available
- */
- public RpcDataProviderExtension(Indexed container) {
- this.container = container;
-
- // TODO support for reacting to events from the container added later
-
- registerRpc(new DataRequestRpc() {
- @Override
- public void requestRows(int firstRow, int numberOfRows) {
- pushRows(firstRow, numberOfRows);
- }
- });
-
- getState().containerSize = container.size();
- }
-
- private void pushRows(int firstRow, int numberOfRows) {
- List<?> itemIds = container.getItemIds(firstRow, numberOfRows);
- Collection<?> propertyIds = container.getContainerPropertyIds();
- List<String[]> rows = new ArrayList<String[]>(itemIds.size());
- for (Object itemId : itemIds) {
- rows.add(getRowData(propertyIds, itemId));
- }
- getRpcProxy(DataProviderRpc.class).setRowData(firstRow, rows);
- }
-
- private String[] getRowData(Collection<?> propertyIds, Object itemId) {
- Item item = container.getItem(itemId);
- String[] row = new String[propertyIds.size()];
-
- int i = 0;
- for (Object propertyId : propertyIds) {
- Object value = item.getItemProperty(propertyId).getValue();
- String stringValue = String.valueOf(value);
- row[i++] = stringValue;
- }
- return row;
- }
-
- @Override
- protected DataProviderState getState() {
- return (DataProviderState) super.getState();
- }
-
- /**
- * Makes the data source available to the given {@link Grid} component.
- *
- * @param component
- * the remote data grid component to extend
- */
- public void extend(Grid component) {
- super.extend(component);
- }
-
- /**
- * Informs the client side that new rows have been inserted into the data
- * source.
- *
- * @param index
- * the index at which new rows have been inserted
- * @param count
- * the number of rows inserted at <code>index</code>
- */
- public void insertRowData(int index, int count) {
- getState().containerSize += count;
- getRpcProxy(DataProviderRpc.class).insertRowData(index, count);
- }
-
- /**
- * Informs the client side that rows have been removed from the data source.
- *
- * @param firstIndex
- * the index of the first row removed
- * @param count
- * the number of rows removed
- */
- public void removeRowData(int firstIndex, int count) {
- getState().containerSize -= count;
- getRpcProxy(DataProviderRpc.class).removeRowData(firstIndex, count);
- }
-
- /**
- * Informs the client side that data of a row has been modified in the data
- * source.
- *
- * @param index
- * the index of the row that was updated
- */
- public void updateRowData(int index) {
- /*
- * TODO: ignore duplicate requests for the same index during the same
- * roundtrip.
- */
- Object itemId = container.getIdByIndex(index);
- String[] row = getRowData(container.getContainerPropertyIds(), itemId);
- getRpcProxy(DataProviderRpc.class).setRowData(index,
- Collections.singletonList(row));
- }
-}
diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java
deleted file mode 100644
index 6b14ef81d4..0000000000
--- a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.ui.components.grid;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import com.vaadin.shared.ui.grid.ColumnGroupState;
-
-/**
- * Column groups are used to group columns together for adding common auxiliary
- * headers and footers. Columns groups are added to {@link ColumnGroupRow}'s.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ColumnGroup implements Serializable {
-
- /**
- * List of property ids belonging to this group
- */
- private List<Object> columns;
-
- /**
- * The grid the column group is associated with
- */
- private final Grid grid;
-
- /**
- * The column group row the column group is attached to
- */
- private final ColumnGroupRow row;
-
- /**
- * The common state between the server and the client
- */
- private final ColumnGroupState state;
-
- /**
- * Constructs a new column group
- *
- * @param grid
- * the grid the column group is associated with
- * @param state
- * the state representing the data of the grid. Sent to the
- * client
- * @param propertyIds
- * the property ids of the columns that belongs to the group
- * @param groups
- * the sub groups who should be included in this group
- *
- */
- ColumnGroup(Grid grid, ColumnGroupRow row, ColumnGroupState state,
- List<Object> propertyIds) {
- if (propertyIds == null) {
- throw new IllegalArgumentException(
- "propertyIds cannot be null. Use empty list instead.");
- }
-
- this.state = state;
- this.row = row;
- columns = Collections.unmodifiableList(new ArrayList<Object>(
- propertyIds));
- this.grid = grid;
- }
-
- /**
- * Sets the text displayed in the header of the column group.
- *
- * @param header
- * the text displayed in the header of the column
- */
- public void setHeaderCaption(String header) {
- checkGroupIsAttached();
- state.header = header;
- grid.markAsDirty();
- }
-
- /**
- * Sets the text displayed in the header of the column group.
- *
- * @return the text displayed in the header of the column
- */
- public String getHeaderCaption() {
- checkGroupIsAttached();
- return state.header;
- }
-
- /**
- * Sets the text displayed in the footer of the column group.
- *
- * @param footer
- * the text displayed in the footer of the column
- */
- public void setFooterCaption(String footer) {
- checkGroupIsAttached();
- state.footer = footer;
- grid.markAsDirty();
- }
-
- /**
- * The text displayed in the footer of the column group.
- *
- * @return the text displayed in the footer of the column
- */
- public String getFooterCaption() {
- checkGroupIsAttached();
- return state.footer;
- }
-
- /**
- * Is a property id in this group or in some sub group of this group.
- *
- * @param propertyId
- * the property id to check for
- * @return <code>true</code> if the property id is included in this group.
- */
- public boolean isColumnInGroup(Object propertyId) {
- if (columns.contains(propertyId)) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns a list of property ids where all also the child groups property
- * ids are included.
- *
- * @return a unmodifiable list with all the columns in the group. Includes
- * any subgroup columns as well.
- */
- public List<Object> getColumns() {
- return columns;
- }
-
- /**
- * Checks if column group is attached to a row and throws an
- * {@link IllegalStateException} if it is not.
- *
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- protected void checkGroupIsAttached() throws IllegalStateException {
- if (!row.getState().groups.contains(state)) {
- throw new IllegalStateException(
- "Column Group has been removed from the row.");
- }
- }
-}
diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java b/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java
deleted file mode 100644
index b90b4df2c5..0000000000
--- a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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.ui.components.grid;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.vaadin.server.KeyMapper;
-import com.vaadin.shared.ui.grid.ColumnGroupRowState;
-import com.vaadin.shared.ui.grid.ColumnGroupState;
-
-/**
- * A column group row represents an auxiliary header or footer row added to the
- * grid. A column group row includes column groups that group columns together.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ColumnGroupRow implements Serializable {
-
- /**
- * The common state shared between the client and server
- */
- private final ColumnGroupRowState state;
-
- /**
- * The column groups in this row
- */
- private List<ColumnGroup> groups = new ArrayList<ColumnGroup>();
-
- /**
- * Grid that the group row belongs to
- */
- private final Grid grid;
-
- /**
- * The column keys used to identify the column on the client side
- */
- private final KeyMapper<Object> columnKeys;
-
- /**
- * Constructs a new column group
- *
- * @param grid
- * The grid that the column group is associated to
- * @param state
- * The shared state which contains the data shared between server
- * and client
- * @param columnKeys
- * The column key mapper for converting property ids to client
- * side column identifiers
- */
- ColumnGroupRow(Grid grid, ColumnGroupRowState state,
- KeyMapper<Object> columnKeys) {
- this.grid = grid;
- this.columnKeys = columnKeys;
- this.state = state;
- }
-
- /**
- * Gets the shared state for the column group row. Used internally to send
- * the group row to the client.
- *
- * @return The current state of the row
- */
- ColumnGroupRowState getState() {
- return state;
- }
-
- /**
- * Add a new group to the row by using property ids for the columns.
- *
- * @param propertyIds
- * The property ids of the columns that should be included in the
- * group. A column can only belong in group on a row at a time.
- * @return a column group representing the collection of columns added to
- * the group
- */
- public ColumnGroup addGroup(Object... propertyIds)
- throws IllegalArgumentException {
- assert propertyIds != null : "propertyIds cannot be null.";
-
- for (Object propertyId : propertyIds) {
- if (hasColumnBeenGrouped(propertyId)) {
- throw new IllegalArgumentException("Column "
- + String.valueOf(propertyId)
- + " already belongs to another group.");
- }
- }
-
- validateNewGroupProperties(Arrays.asList(propertyIds));
-
- ColumnGroupState state = new ColumnGroupState();
- for (Object propertyId : propertyIds) {
- assert propertyId != null : "null items in columns array not supported.";
- state.columns.add(columnKeys.key(propertyId));
- }
- this.state.groups.add(state);
-
- ColumnGroup group = new ColumnGroup(grid, this, state,
- Arrays.asList(propertyIds));
- groups.add(group);
-
- grid.markAsDirty();
- return group;
- }
-
- private void validateNewGroupProperties(List<Object> propertyIds)
- throws IllegalArgumentException {
-
- /*
- * Validate parent grouping
- */
- int rowIndex = grid.getColumnGroupRows().indexOf(this);
- int parentRowIndex = rowIndex - 1;
-
- // Get the parent row of this row.
- ColumnGroupRow parentRow = null;
- if (parentRowIndex > -1) {
- parentRow = grid.getColumnGroupRows().get(parentRowIndex);
- }
-
- if (parentRow == null) {
- // A parentless row is always valid and is usually the first row
- // added to the grid
- return;
- }
-
- for (Object id : propertyIds) {
- if (parentRow.hasColumnBeenGrouped(id)) {
- /*
- * If a property has been grouped in the parent row then all of
- * the properties in the parent group also needs to be included
- * in the child group for the groups to be valid
- */
- ColumnGroup parentGroup = parentRow.getGroupForProperty(id);
- if (!propertyIds.containsAll(parentGroup.getColumns())) {
- throw new IllegalArgumentException(
- "Grouped properties overlaps previous grouping bounderies");
- }
- }
- }
- }
-
- /**
- * Add a new group to the row by using column instances.
- *
- * @param columns
- * the columns that should belong to the group
- * @return a column group representing the collection of columns added to
- * the group
- */
- public ColumnGroup addGroup(GridColumn... columns)
- throws IllegalArgumentException {
- assert columns != null : "columns cannot be null";
-
- List<Object> propertyIds = new ArrayList<Object>();
- for (GridColumn column : columns) {
- assert column != null : "null items in columns array not supported.";
-
- String columnId = column.getState().id;
- Object propertyId = grid.getPropertyIdByColumnId(columnId);
- propertyIds.add(propertyId);
- }
- return addGroup(propertyIds.toArray());
- }
-
- /**
- * Add a new group to the row by using other already greated groups
- *
- * @param groups
- * the subgroups of the group
- * @return a column group representing the collection of columns added to
- * the group
- *
- */
- public ColumnGroup addGroup(ColumnGroup... groups)
- throws IllegalArgumentException {
- assert groups != null : "groups cannot be null";
-
- // Gather all groups columns into one list
- List<Object> propertyIds = new ArrayList<Object>();
- for (ColumnGroup group : groups) {
- propertyIds.addAll(group.getColumns());
- }
-
- validateNewGroupProperties(propertyIds);
-
- ColumnGroupState state = new ColumnGroupState();
- ColumnGroup group = new ColumnGroup(grid, this, state, propertyIds);
- this.groups.add(group);
-
- // Update state
- for (Object propertyId : group.getColumns()) {
- state.columns.add(columnKeys.key(propertyId));
- }
- this.state.groups.add(state);
-
- grid.markAsDirty();
- return group;
- }
-
- /**
- * Removes a group from the row. Does not remove the group from subgroups,
- * to remove it from the subgroup invoke removeGroup on the subgroup.
- *
- * @param group
- * the group to remove
- */
- public void removeGroup(ColumnGroup group) {
- int index = groups.indexOf(group);
- groups.remove(index);
- state.groups.remove(index);
- grid.markAsDirty();
- }
-
- /**
- * Get the groups in the row.
- *
- * @return unmodifiable list of groups in this row
- */
- public List<ColumnGroup> getGroups() {
- return Collections.unmodifiableList(groups);
- }
-
- /**
- * Checks if a property id has been added to a group in this row.
- *
- * @param propertyId
- * the property id to check for
- * @return <code>true</code> if the column is included in a group
- */
- private boolean hasColumnBeenGrouped(Object propertyId) {
- return getGroupForProperty(propertyId) != null;
- }
-
- private ColumnGroup getGroupForProperty(Object propertyId) {
- for (ColumnGroup group : groups) {
- if (group.isColumnInGroup(propertyId)) {
- return group;
- }
- }
- return null;
- }
-
- /**
- * Is the header visible for the row.
- *
- * @return <code>true</code> if header is visible
- */
- public boolean isHeaderVisible() {
- return state.headerVisible;
- }
-
- /**
- * Sets the header visible for the row.
- *
- * @param visible
- * should the header be shown
- */
- public void setHeaderVisible(boolean visible) {
- state.headerVisible = visible;
- grid.markAsDirty();
- }
-
- /**
- * Is the footer visible for the row.
- *
- * @return <code>true</code> if footer is visible
- */
- public boolean isFooterVisible() {
- return state.footerVisible;
- }
-
- /**
- * Sets the footer visible for the row.
- *
- * @param visible
- * should the footer be shown
- */
- public void setFooterVisible(boolean visible) {
- state.footerVisible = visible;
- grid.markAsDirty();
- }
-
-}
diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java
deleted file mode 100644
index 4126ec6d93..0000000000
--- a/server/src/com/vaadin/ui/components/grid/Grid.java
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * 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.ui.components.grid;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import com.vaadin.data.Container;
-import com.vaadin.data.Container.Indexed.ItemAddEvent;
-import com.vaadin.data.Container.Indexed.ItemRemoveEvent;
-import com.vaadin.data.Container.ItemSetChangeEvent;
-import com.vaadin.data.Container.ItemSetChangeListener;
-import com.vaadin.data.Container.ItemSetChangeNotifier;
-import com.vaadin.data.Container.PropertySetChangeEvent;
-import com.vaadin.data.Container.PropertySetChangeListener;
-import com.vaadin.data.Container.PropertySetChangeNotifier;
-import com.vaadin.data.Item;
-import com.vaadin.data.Property;
-import com.vaadin.data.Property.ValueChangeEvent;
-import com.vaadin.data.Property.ValueChangeListener;
-import com.vaadin.data.Property.ValueChangeNotifier;
-import com.vaadin.data.RpcDataProviderExtension;
-import com.vaadin.server.KeyMapper;
-import com.vaadin.shared.ui.grid.ColumnGroupRowState;
-import com.vaadin.shared.ui.grid.GridClientRpc;
-import com.vaadin.shared.ui.grid.GridColumnState;
-import com.vaadin.shared.ui.grid.GridServerRpc;
-import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.Range;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-import com.vaadin.ui.AbstractComponent;
-import com.vaadin.ui.Component;
-
-/**
- * Data grid component
- *
- * <h3>Lazy loading</h3> TODO To be revised when the data data source
- * implementation has been don.
- *
- * <h3>Columns</h3> The grid columns are based on the property ids of the
- * underlying data source. Each property id represents one column in the grid.
- * To retrive a column in the grid you can use {@link Grid#getColumn(Object)}
- * with the property id of the column. A grid column contains properties like
- * the width, the footer and header captions of the column.
- *
- * <h3>Auxiliary headers and footers</h3> TODO To be revised when column
- * grouping is implemented.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class Grid extends AbstractComponent {
-
- /**
- * A helper class that handles the client-side Escalator logic relating to
- * making sure that whatever is currently visible to the user, is properly
- * initialized and otherwise handled on the server side (as far as
- * requried).
- * <p>
- * This bookeeping includes, but is not limited to:
- * <ul>
- * <li>listening to the currently visible {@link Property Properties'} value
- * changes on the server side and sending those back to the client; and
- * <li>attaching and detaching {@link Component Components} from the Vaadin
- * Component hierarchy.
- * </ul>
- */
- private final class ActiveRowHandler {
- /**
- * A map from itemId to the value change listener used for all of its
- * properties
- */
- private final Map<Object, GridValueChangeListener> valueChangeListeners = new HashMap<Object, GridValueChangeListener>();
-
- /**
- * The currently active range. Practically, it's the range of row
- * indices being displayed currently.
- */
- private Range activeRange = Range.withLength(0, 0);
-
- /**
- * A hook for making sure that appropriate data is "active". All other
- * rows should be "inactive".
- * <p>
- * "Active" can mean different things in different contexts. For
- * example, only the Properties in the active range need
- * ValueChangeListeners. Also, whenever a row with a Component becomes
- * active, it needs to be attached (and conversely, when inactive, it
- * needs to be detached).
- *
- * @param firstActiveRow
- * the first active row
- * @param activeRowCount
- * the number of active rows
- */
- public void setActiveRows(int firstActiveRow, int activeRowCount) {
-
- final Range newActiveRange = Range.withLength(firstActiveRow,
- activeRowCount);
-
- // TODO [[Components]] attach and detach components
-
- /*-
- * Example
- *
- * New Range: [3, 4, 5, 6, 7]
- * Old Range: [1, 2, 3, 4, 5]
- * Result: [1, 2][3, 4, 5] []
- */
- final Range[] depractionPartition = activeRange
- .partitionWith(newActiveRange);
- removeValueChangeListeners(depractionPartition[0]);
- removeValueChangeListeners(depractionPartition[2]);
-
- /*-
- * Example
- *
- * Old Range: [1, 2, 3, 4, 5]
- * New Range: [3, 4, 5, 6, 7]
- * Result: [] [3, 4, 5][6, 7]
- */
- final Range[] activationPartition = newActiveRange
- .partitionWith(activeRange);
- addValueChangeListeners(activationPartition[0]);
- addValueChangeListeners(activationPartition[2]);
-
- activeRange = newActiveRange;
- }
-
- private void addValueChangeListeners(Range range) {
- for (int i = range.getStart(); i < range.getEnd(); i++) {
-
- final Object itemId = datasource.getIdByIndex(i);
- final Item item = datasource.getItem(itemId);
-
- if (valueChangeListeners.containsKey(itemId)) {
- /*
- * This might occur when items are removed from above the
- * viewport, the escalator scrolls up to compensate, but the
- * same items remain in the view: It looks as if one row was
- * scrolled, when in fact the whole viewport was shifted up.
- */
- continue;
- }
-
- GridValueChangeListener listener = new GridValueChangeListener(
- itemId);
- valueChangeListeners.put(itemId, listener);
-
- for (final Object propertyId : item.getItemPropertyIds()) {
- final Property<?> property = item
- .getItemProperty(propertyId);
- if (property instanceof ValueChangeNotifier) {
- ((ValueChangeNotifier) property)
- .addValueChangeListener(listener);
- }
- }
- }
- }
-
- private void removeValueChangeListeners(Range range) {
- for (int i = range.getStart(); i < range.getEnd(); i++) {
- final Object itemId = datasource.getIdByIndex(i);
- final Item item = datasource.getItem(itemId);
- final GridValueChangeListener listener = valueChangeListeners
- .remove(itemId);
-
- if (listener != null) {
- for (final Object propertyId : item.getItemPropertyIds()) {
- final Property<?> property = item
- .getItemProperty(propertyId);
-
- /*
- * Because listener != null, we can be certain that this
- * property is a ValueChangeNotifier: It wouldn't be
- * inserted in addValueChangeListeners if the property
- * wasn't a suitable type. I.e. No need for "instanceof"
- * check.
- */
- ((ValueChangeNotifier) property)
- .removeValueChangeListener(listener);
- }
- }
- }
- }
-
- public void clear() {
- removeValueChangeListeners(activeRange);
- /*
- * we're doing an assert for emptiness there (instead of a
- * carte-blanche ".clear()"), to be absolutely sure that everything
- * is cleaned up properly, and that we have no dangling listeners.
- */
- assert valueChangeListeners.isEmpty() : "GridValueChangeListeners are leaking";
-
- activeRange = Range.withLength(0, 0);
- }
-
- /**
- * Manages removed properties in active rows.
- *
- * @param removedPropertyIds
- * the property ids that have been removed from the container
- */
- public void propertiesRemoved(Collection<Object> removedPropertyIds) {
- /*
- * no-op, for now.
- *
- * The Container should be responsible for cleaning out any
- * ValueChangeListeners from removed Properties. Components will
- * benefit from this, however.
- */
- }
-
- /**
- * Manages added properties in active rows.
- *
- * @param addedPropertyIds
- * the property ids that have been added to the container
- */
- public void propertiesAdded(Collection<Object> addedPropertyIds) {
- for (int i = activeRange.getStart(); i < activeRange.getEnd(); i++) {
- final Object itemId = datasource.getIdByIndex(i);
- final Item item = datasource.getItem(itemId);
- final GridValueChangeListener listener = valueChangeListeners
- .get(itemId);
- assert (listener != null) : "a listener should've been pre-made by addValueChangeListeners";
-
- for (final Object propertyId : addedPropertyIds) {
- final Property<?> property = item
- .getItemProperty(propertyId);
- if (property instanceof ValueChangeNotifier) {
- ((ValueChangeNotifier) property)
- .addValueChangeListener(listener);
- }
- }
- }
- }
-
- /**
- * Handles the insertion of rows.
- * <p>
- * This method's responsibilities are to:
- * <ul>
- * <li>shift the internal bookkeeping by <code>count</code> if the
- * insertion happens above currently active range
- * <li>ignore rows inserted below the currently active range
- * <li>shift (and deactivate) rows pushed out of view
- * <li>activate rows that are inserted in the current viewport
- * </ul>
- *
- * @param firstIndex
- * the index of the first inserted rows
- * @param count
- * the number of rows inserted at <code>firstIndex</code>
- */
- public void insertRows(int firstIndex, int count) {
- if (firstIndex < activeRange.getStart()) {
- activeRange = activeRange.offsetBy(count);
- } else if (firstIndex < activeRange.getEnd()) {
- final Range deprecatedRange = Range.withLength(
- activeRange.getEnd(), count);
- removeValueChangeListeners(deprecatedRange);
-
- final Range freshRange = Range.between(firstIndex, count);
- addValueChangeListeners(freshRange);
- } else {
- // out of view, noop
- }
- }
-
- /**
- * Removes a single item by its id.
- *
- * @param itemId
- * the id of the removed id. <em>Note:</em> this item does
- * not exist anymore in the datasource
- */
- public void removeItemId(Object itemId) {
- final GridValueChangeListener removedListener = valueChangeListeners
- .remove(itemId);
- if (removedListener != null) {
- /*
- * We removed an item from somewhere in the visible range, so we
- * make the active range shorter. The empty hole will be filled
- * by the client-side code when it asks for more information.
- */
- activeRange = Range.withLength(activeRange.getStart(),
- activeRange.length() - 1);
- }
- }
- }
-
- /**
- * A class to listen to changes in property values in the Container added
- * with {@link Grid#setContainerDatasource(Container.Indexed)}, and notifies
- * the data source to update the client-side representation of the modified
- * item.
- * <p>
- * One instance of this class can (and should) be reused for all the
- * properties in an item, since this class will inform that the entire row
- * needs to be re-evaluated (in contrast to a property-based change
- * management)
- * <p>
- * Since there's no Container-wide possibility to listen to any kind of
- * value changes, an instance of this class needs to be attached to each and
- * every Item's Property in the container.
- *
- * @see Grid#addValueChangeListener(Container, Object, Object)
- * @see Grid#valueChangeListeners
- */
- private class GridValueChangeListener implements ValueChangeListener {
- private final Object itemId;
-
- public GridValueChangeListener(Object itemId) {
- /*
- * Using an assert instead of an exception throw, just to optimize
- * prematurely
- */
- assert itemId != null : "null itemId not accepted";
- this.itemId = itemId;
- }
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- datasourceExtension.updateRowData(datasource.indexOfId(itemId));
- }
- }
-
- /**
- * The data source attached to the grid
- */
- private Container.Indexed datasource;
-
- /**
- * Property id to column instance mapping
- */
- private final Map<Object, GridColumn> columns = new HashMap<Object, GridColumn>();
-
- /**
- * Key generator for column server-to-client communication
- */
- private final KeyMapper<Object> columnKeys = new KeyMapper<Object>();
-
- /**
- * The column groups added to the grid
- */
- private final List<ColumnGroupRow> columnGroupRows = new ArrayList<ColumnGroupRow>();
-
- /**
- * Property listener for listening to changes in data source properties.
- */
- private final PropertySetChangeListener propertyListener = new PropertySetChangeListener() {
-
- @Override
- public void containerPropertySetChange(PropertySetChangeEvent event) {
- Collection<?> properties = new HashSet<Object>(event.getContainer()
- .getContainerPropertyIds());
-
- // Cleanup columns that are no longer in grid
- List<Object> removedColumns = new LinkedList<Object>();
- for (Object columnId : columns.keySet()) {
- if (!properties.contains(columnId)) {
- removedColumns.add(columnId);
- }
- }
- for (Object columnId : removedColumns) {
- GridColumn column = columns.remove(columnId);
- columnKeys.remove(columnId);
- getState().columns.remove(column.getState());
- }
- activeRowHandler.propertiesRemoved(removedColumns);
-
- // Add new columns
- HashSet<Object> addedPropertyIds = new HashSet<Object>();
- for (Object propertyId : properties) {
- if (!columns.containsKey(propertyId)) {
- appendColumn(propertyId);
- addedPropertyIds.add(propertyId);
- }
- }
- activeRowHandler.propertiesAdded(addedPropertyIds);
-
- Object frozenPropertyId = columnKeys
- .get(getState(false).lastFrozenColumnId);
- if (!columns.containsKey(frozenPropertyId)) {
- setLastFrozenPropertyId(null);
- }
- }
- };
-
- private ItemSetChangeListener itemListener = new ItemSetChangeListener() {
- @Override
- public void containerItemSetChange(ItemSetChangeEvent event) {
-
- if (event instanceof ItemAddEvent) {
- ItemAddEvent addEvent = (ItemAddEvent) event;
- int firstIndex = addEvent.getFirstIndex();
- int count = addEvent.getAddedItemsCount();
- datasourceExtension.insertRowData(firstIndex, count);
- activeRowHandler.insertRows(firstIndex, count);
- }
-
- else if (event instanceof ItemRemoveEvent) {
- ItemRemoveEvent removeEvent = (ItemRemoveEvent) event;
- int firstIndex = removeEvent.getFirstIndex();
- int count = removeEvent.getRemovedItemsCount();
- datasourceExtension.removeRowData(firstIndex, count);
-
- /*
- * Unfortunately, there's no sane way of getting the rest of the
- * removed itemIds.
- *
- * Fortunately, the only time _currently_ an event with more
- * than one removed item seems to be when calling
- * AbstractInMemoryContainer.removeAllElements(). Otherwise,
- * it's only removing one item at a time.
- *
- * We _could_ have a backup of all the itemIds, and compare to
- * that one, but we really really don't want to go there.
- */
- activeRowHandler.removeItemId(removeEvent.getFirstItemId());
- }
-
- else {
- // TODO no diff info available, redraw everything
- throw new UnsupportedOperationException("bare "
- + "ItemSetChangeEvents are currently "
- + "not supported, use a container that "
- + "uses AddItemEvents and RemoveItemEvents.");
- }
- }
- };
-
- private RpcDataProviderExtension datasourceExtension;
-
- private final ActiveRowHandler activeRowHandler = new ActiveRowHandler();
-
- /**
- * Creates a new Grid using the given datasource.
- *
- * @param datasource
- * the data source for the grid
- */
- public Grid(Container.Indexed datasource) {
- setContainerDatasource(datasource);
-
- registerRpc(new GridServerRpc() {
- @Override
- public void setVisibleRows(int firstVisibleRow, int visibleRowCount) {
- activeRowHandler
- .setActiveRows(firstVisibleRow, visibleRowCount);
- }
- });
- }
-
- /**
- * Sets the grid data source.
- *
- * @param container
- * The container data source. Cannot be null.
- * @throws IllegalArgumentException
- * if the data source is null
- */
- public void setContainerDatasource(Container.Indexed container) {
- if (container == null) {
- throw new IllegalArgumentException(
- "Cannot set the datasource to null");
- }
- if (datasource == container) {
- return;
- }
-
- // Remove old listeners
- if (datasource instanceof PropertySetChangeNotifier) {
- ((PropertySetChangeNotifier) datasource)
- .removePropertySetChangeListener(propertyListener);
- }
- if (datasource instanceof ItemSetChangeNotifier) {
- ((ItemSetChangeNotifier) datasource)
- .removeItemSetChangeListener(itemListener);
- }
- activeRowHandler.clear();
-
- if (datasourceExtension != null) {
- removeExtension(datasourceExtension);
- }
-
- datasource = container;
- datasourceExtension = new RpcDataProviderExtension(container);
- datasourceExtension.extend(this);
-
- // Listen to changes in properties and remove columns if needed
- if (datasource instanceof PropertySetChangeNotifier) {
- ((PropertySetChangeNotifier) datasource)
- .addPropertySetChangeListener(propertyListener);
- }
- if (datasource instanceof ItemSetChangeNotifier) {
- ((ItemSetChangeNotifier) datasource)
- .addItemSetChangeListener(itemListener);
- }
- /*
- * activeRowHandler will be updated by the client-side request that
- * occurs on container change - no need to actively re-insert any
- * ValueChangeListeners at this point.
- */
-
- getState().columns.clear();
- setLastFrozenPropertyId(null);
-
- // Add columns
- for (Object propertyId : datasource.getContainerPropertyIds()) {
- if (!columns.containsKey(propertyId)) {
- GridColumn column = appendColumn(propertyId);
-
- // Add by default property id as column header
- column.setHeaderCaption(String.valueOf(propertyId));
- }
- }
-
- }
-
- /**
- * Returns the grid data source.
- *
- * @return the container data source of the grid
- */
- public Container.Indexed getContainerDatasource() {
- return datasource;
- }
-
- /**
- * Returns a column based on the property id
- *
- * @param propertyId
- * the property id of the column
- * @return the column or <code>null</code> if not found
- */
- public GridColumn getColumn(Object propertyId) {
- return columns.get(propertyId);
- }
-
- /**
- * Sets the header rows visible.
- *
- * @param visible
- * <code>true</code> if the header rows should be visible
- */
- public void setColumnHeadersVisible(boolean visible) {
- getState().columnHeadersVisible = visible;
- }
-
- /**
- * Are the header rows visible?
- *
- * @return <code>true</code> if the headers of the columns are visible
- */
- public boolean isColumnHeadersVisible() {
- return getState(false).columnHeadersVisible;
- }
-
- /**
- * Sets the footer rows visible.
- *
- * @param visible
- * <code>true</code> if the footer rows should be visible
- */
- public void setColumnFootersVisible(boolean visible) {
- getState().columnFootersVisible = visible;
- }
-
- /**
- * Are the footer rows visible.
- *
- * @return <code>true</code> if the footer rows should be visible
- */
- public boolean isColumnFootersVisible() {
- return getState(false).columnFootersVisible;
- }
-
- /**
- * <p>
- * Adds a new column group to the grid.
- *
- * <p>
- * Column group rows are rendered in the header and footer of the grid.
- * Column group rows are made up of column groups which groups together
- * columns for adding a common auxiliary header or footer for the columns.
- * </p>
- * </p>
- *
- * <p>
- * Example usage:
- *
- * <pre>
- * // Add a new column group row to the grid
- * ColumnGroupRow row = grid.addColumnGroupRow();
- *
- * // Group &quot;Column1&quot; and &quot;Column2&quot; together to form a header in the row
- * ColumnGroup column12 = row.addGroup(&quot;Column1&quot;, &quot;Column2&quot;);
- *
- * // Set a common header for &quot;Column1&quot; and &quot;Column2&quot;
- * column12.setHeader(&quot;Column 1&amp;2&quot;);
- * </pre>
- *
- * </p>
- *
- * @return a column group instance you can use to add column groups
- */
- public ColumnGroupRow addColumnGroupRow() {
- ColumnGroupRowState state = new ColumnGroupRowState();
- ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys);
- columnGroupRows.add(row);
- getState().columnGroupRows.add(state);
- return row;
- }
-
- /**
- * Adds a new column group to the grid at a specific index
- *
- * @param rowIndex
- * the index of the row
- * @return a column group instance you can use to add column groups
- */
- public ColumnGroupRow addColumnGroupRow(int rowIndex) {
- ColumnGroupRowState state = new ColumnGroupRowState();
- ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys);
- columnGroupRows.add(rowIndex, row);
- getState().columnGroupRows.add(rowIndex, state);
- return row;
- }
-
- /**
- * Removes a column group.
- *
- * @param row
- * the row to remove
- */
- public void removeColumnGroupRow(ColumnGroupRow row) {
- columnGroupRows.remove(row);
- getState().columnGroupRows.remove(row.getState());
- }
-
- /**
- * Gets the column group rows.
- *
- * @return an unmodifiable list of column group rows
- */
- public List<ColumnGroupRow> getColumnGroupRows() {
- return Collections.unmodifiableList(new ArrayList<ColumnGroupRow>(
- columnGroupRows));
- }
-
- /**
- * Used internally by the {@link Grid} to get a {@link GridColumn} by
- * referencing its generated state id. Also used by {@link GridColumn} to
- * verify if it has been detached from the {@link Grid}.
- *
- * @param columnId
- * the client id generated for the column when the column is
- * added to the grid
- * @return the column with the id or <code>null</code> if not found
- */
- GridColumn getColumnByColumnId(String columnId) {
- Object propertyId = getPropertyIdByColumnId(columnId);
- return getColumn(propertyId);
- }
-
- /**
- * Used internally by the {@link Grid} to get a property id by referencing
- * the columns generated state id.
- *
- * @param columnId
- * The state id of the column
- * @return The column instance or null if not found
- */
- Object getPropertyIdByColumnId(String columnId) {
- return columnKeys.get(columnId);
- }
-
- @Override
- protected GridState getState() {
- return (GridState) super.getState();
- }
-
- @Override
- protected GridState getState(boolean markAsDirty) {
- return (GridState) super.getState(markAsDirty);
- }
-
- /**
- * Creates a new column based on a property id and appends it as the last
- * column.
- *
- * @param datasourcePropertyId
- * The property id of a property in the datasource
- */
- private GridColumn appendColumn(Object datasourcePropertyId) {
- if (datasourcePropertyId == null) {
- throw new IllegalArgumentException("Property id cannot be null");
- }
- assert datasource.getContainerPropertyIds().contains(
- datasourcePropertyId) : "Datasource should contain the property id";
-
- GridColumnState columnState = new GridColumnState();
- columnState.id = columnKeys.key(datasourcePropertyId);
- getState().columns.add(columnState);
-
- GridColumn column = new GridColumn(this, columnState);
- columns.put(datasourcePropertyId, column);
-
- return column;
- }
-
- /**
- * Sets (or unsets) the rightmost frozen column in the grid.
- * <p>
- * All columns up to and including the given column will be frozen in place
- * when the grid is scrolled sideways.
- *
- * @param lastFrozenColumn
- * the rightmost column to freeze, or <code>null</code> to not
- * have any columns frozen
- * @throws IllegalArgumentException
- * if {@code lastFrozenColumn} is not a column from this grid
- */
- void setLastFrozenColumn(GridColumn lastFrozenColumn) {
- /*
- * TODO: If and when Grid supports column reordering or insertion of
- * columns before other columns, make sure to mention that adding
- * columns before lastFrozenColumn will change the frozen column count
- */
-
- if (lastFrozenColumn == null) {
- getState().lastFrozenColumnId = null;
- } else if (columns.containsValue(lastFrozenColumn)) {
- getState().lastFrozenColumnId = lastFrozenColumn.getState().id;
- } else {
- throw new IllegalArgumentException(
- "The given column isn't attached to this grid");
- }
- }
-
- /**
- * Sets (or unsets) the rightmost frozen column in the grid.
- * <p>
- * All columns up to and including the indicated property will be frozen in
- * place when the grid is scrolled sideways.
- * <p>
- * <em>Note:</em> If the container used by this grid supports a propertyId
- * <code>null</code>, it can never be defined as the last frozen column, as
- * a <code>null</code> parameter will always reset the frozen columns in
- * Grid.
- *
- * @param propertyId
- * the property id corresponding to the column that should be the
- * last frozen column, or <code>null</code> to not have any
- * columns frozen.
- * @throws IllegalArgumentException
- * if {@code lastFrozenColumn} is not a column from this grid
- */
- public void setLastFrozenPropertyId(Object propertyId) {
- final GridColumn column;
- if (propertyId == null) {
- column = null;
- } else {
- column = getColumn(propertyId);
- if (column == null) {
- throw new IllegalArgumentException(
- "property id does not exist.");
- }
- }
- setLastFrozenColumn(column);
- }
-
- /**
- * Gets the rightmost frozen column in the grid.
- * <p>
- * <em>Note:</em> Most often, this method returns the very value set with
- * {@link #setLastFrozenPropertyId(Object)}. This value, however, can be
- * reset to <code>null</code> if the column is detached from this grid.
- *
- * @return the rightmost frozen column in the grid, or <code>null</code> if
- * no columns are frozen.
- */
- public Object getLastFrozenPropertyId() {
- return columnKeys.get(getState().lastFrozenColumnId);
- }
-
- /**
- * Scrolls to a certain item, using {@link ScrollDestination#ANY}.
- *
- * @param itemId
- * id of item to scroll to.
- * @throws IllegalArgumentException
- * if the provided id is not recognized by the data source.
- */
- public void scrollToItem(Object itemId) throws IllegalArgumentException {
- scrollToItem(itemId, ScrollDestination.ANY);
- }
-
- /**
- * Scrolls to a certain item, using user-specified scroll destination.
- *
- * @param itemId
- * id of item to scroll to.
- * @param destination
- * value specifying desired position of scrolled-to row.
- * @throws IllegalArgumentException
- * if the provided id is not recognized by the data source.
- */
- public void scrollToItem(Object itemId, ScrollDestination destination)
- throws IllegalArgumentException {
-
- int row = datasource.indexOfId(itemId);
-
- if (row == -1) {
- throw new IllegalArgumentException(
- "Item with specified ID does not exist in data source");
- }
-
- GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
- clientRPC.scrollToRow(row, destination);
- }
-
- /**
- * Scrolls to the beginning of the first data row.
- */
- public void scrollToStart() {
- GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
- clientRPC.scrollToStart();
- }
-
- /**
- * Scrolls to the end of the last data row.
- */
- public void scrollToEnd() {
- GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
- clientRPC.scrollToEnd();
- }
-}
diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java
deleted file mode 100644
index 852db21275..0000000000
--- a/server/src/com/vaadin/ui/components/grid/GridColumn.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * 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.ui.components.grid;
-
-import java.io.Serializable;
-
-import com.vaadin.shared.ui.grid.GridColumnState;
-
-/**
- * A column in the grid. Can be obtained by calling
- * {@link Grid#getColumn(Object propertyId)}.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class GridColumn implements Serializable {
-
- /**
- * The state of the column shared to the client
- */
- private final GridColumnState state;
-
- /**
- * The grid this column is associated with
- */
- private final Grid grid;
-
- /**
- * Internally used constructor.
- *
- * @param grid
- * The grid this column belongs to. Should not be null.
- * @param state
- * the shared state of this column
- */
- GridColumn(Grid grid, GridColumnState state) {
- this.grid = grid;
- this.state = state;
- }
-
- /**
- * Returns the serializable state of this column that is sent to the client
- * side connector.
- *
- * @return the internal state of the column
- */
- GridColumnState getState() {
- return state;
- }
-
- /**
- * Returns the caption of the header. By default the header caption is the
- * property id of the column.
- *
- * @return the text in the header
- *
- * @throws IllegalStateException
- * if the column no longer is attached to the grid
- */
- public String getHeaderCaption() throws IllegalStateException {
- checkColumnIsAttached();
- return state.header;
- }
-
- /**
- * Sets the caption of the header.
- *
- * @param caption
- * the text to show in the caption
- *
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public void setHeaderCaption(String caption) throws IllegalStateException {
- checkColumnIsAttached();
- state.header = caption;
- grid.markAsDirty();
- }
-
- /**
- * Returns the caption of the footer. By default the captions are
- * <code>null</code>.
- *
- * @return the text in the footer
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public String getFooterCaption() throws IllegalStateException {
- checkColumnIsAttached();
- return state.footer;
- }
-
- /**
- * Sets the caption of the footer.
- *
- * @param caption
- * the text to show in the caption
- *
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public void setFooterCaption(String caption) throws IllegalStateException {
- checkColumnIsAttached();
- state.footer = caption;
- grid.markAsDirty();
- }
-
- /**
- * Returns the width (in pixels). By default a column is 100px wide.
- *
- * @return the width in pixels of the column
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public int getWidth() throws IllegalStateException {
- checkColumnIsAttached();
- return state.width;
- }
-
- /**
- * Sets the width (in pixels).
- *
- * @param pixelWidth
- * the new pixel width of the column
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- * @throws IllegalArgumentException
- * thrown if pixel width is less than zero
- */
- public void setWidth(int pixelWidth) throws IllegalStateException,
- IllegalArgumentException {
- checkColumnIsAttached();
- if (pixelWidth < 0) {
- throw new IllegalArgumentException(
- "Pixel width should be greated than 0");
- }
- state.width = pixelWidth;
- grid.markAsDirty();
- }
-
- /**
- * Marks the column width as undefined meaning that the grid is free to
- * resize the column based on the cell contents and available space in the
- * grid.
- */
- public void setWidthUndefined() {
- checkColumnIsAttached();
- state.width = -1;
- grid.markAsDirty();
- }
-
- /**
- * Is this column visible in the grid. By default all columns are visible.
- *
- * @return <code>true</code> if the column is visible
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public boolean isVisible() throws IllegalStateException {
- checkColumnIsAttached();
- return state.visible;
- }
-
- /**
- * Set the visibility of this column
- *
- * @param visible
- * is the column visible
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- public void setVisible(boolean visible) throws IllegalStateException {
- checkColumnIsAttached();
- state.visible = visible;
- grid.markAsDirty();
- }
-
- /**
- * Checks if column is attached and throws an {@link IllegalStateException}
- * if it is not
- *
- * @throws IllegalStateException
- * if the column is no longer attached to any grid
- */
- protected void checkColumnIsAttached() throws IllegalStateException {
- if (grid.getColumnByColumnId(state.id) == null) {
- throw new IllegalStateException("Column no longer exists.");
- }
- }
-
- /**
- * Sets this column as the last frozen column in its grid.
- *
- * @throws IllegalArgumentException
- * if the column is no longer attached to any grid
- * @see Grid#setLastFrozenColumn(GridColumn)
- */
- public void setLastFrozenColumn() {
- checkColumnIsAttached();
- grid.setLastFrozenColumn(this);
- }
-}
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java
deleted file mode 100644
index 4350bf1a7b..0000000000
--- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * 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.tests.server.component.grid;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.vaadin.data.util.IndexedContainer;
-import com.vaadin.server.KeyMapper;
-import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.ui.components.grid.ColumnGroup;
-import com.vaadin.ui.components.grid.ColumnGroupRow;
-import com.vaadin.ui.components.grid.Grid;
-
-/**
- *
- * @since
- * @author Vaadin Ltd
- */
-public class GridColumnGroups {
-
- private Grid grid;
-
- private GridState state;
-
- private Method getStateMethod;
-
- private Field columnIdGeneratorField;
-
- private KeyMapper<Object> columnIdMapper;
-
- @Before
- public void setup() throws Exception {
- IndexedContainer ds = new IndexedContainer();
- for (int c = 0; c < 10; c++) {
- ds.addContainerProperty("column" + c, String.class, "");
- }
- grid = new Grid(ds);
-
- getStateMethod = Grid.class.getDeclaredMethod("getState");
- getStateMethod.setAccessible(true);
-
- state = (GridState) getStateMethod.invoke(grid);
-
- columnIdGeneratorField = Grid.class.getDeclaredField("columnKeys");
- columnIdGeneratorField.setAccessible(true);
-
- columnIdMapper = (KeyMapper<Object>) columnIdGeneratorField.get(grid);
- }
-
- @Test
- public void testColumnGroupRows() throws Exception {
-
- // No column group rows by default
- List<ColumnGroupRow> rows = grid.getColumnGroupRows();
- assertEquals(0, rows.size());
-
- // Add some rows
- ColumnGroupRow row1 = grid.addColumnGroupRow();
- ColumnGroupRow row3 = grid.addColumnGroupRow();
- ColumnGroupRow row2 = grid.addColumnGroupRow(1);
-
- rows = grid.getColumnGroupRows();
- assertEquals(3, rows.size());
- assertEquals(row1, rows.get(0));
- assertEquals(row2, rows.get(1));
- assertEquals(row3, rows.get(2));
-
- // Header should be visible by default, footer should not
- assertTrue(row1.isHeaderVisible());
- assertFalse(row1.isFooterVisible());
-
- row1.setHeaderVisible(false);
- assertFalse(row1.isHeaderVisible());
- row1.setHeaderVisible(true);
- assertTrue(row1.isHeaderVisible());
-
- row1.setFooterVisible(true);
- assertTrue(row1.isFooterVisible());
- row1.setFooterVisible(false);
- assertFalse(row1.isFooterVisible());
-
- row1.setHeaderVisible(true);
- row1.setFooterVisible(true);
- assertTrue(row1.isHeaderVisible());
- assertTrue(row1.isFooterVisible());
-
- row1.setHeaderVisible(false);
- row1.setFooterVisible(false);
- assertFalse(row1.isHeaderVisible());
- assertFalse(row1.isFooterVisible());
- }
-
- @Test
- public void testColumnGroupsInState() throws Exception {
-
- // Add a new row
- ColumnGroupRow row = grid.addColumnGroupRow();
- assertTrue(state.columnGroupRows.size() == 1);
-
- // Add a group by property id
- ColumnGroup columns12 = row.addGroup("column1", "column2");
- assertTrue(state.columnGroupRows.get(0).groups.size() == 1);
-
- // Set header of column
- columns12.setHeaderCaption("Column12");
- assertEquals("Column12",
- state.columnGroupRows.get(0).groups.get(0).header);
-
- // Set footer of column
- columns12.setFooterCaption("Footer12");
- assertEquals("Footer12",
- state.columnGroupRows.get(0).groups.get(0).footer);
-
- // Add another group by column instance
- ColumnGroup columns34 = row.addGroup(grid.getColumn("column3"),
- grid.getColumn("column4"));
- assertTrue(state.columnGroupRows.get(0).groups.size() == 2);
-
- // add another group row
- ColumnGroupRow row2 = grid.addColumnGroupRow();
- assertTrue(state.columnGroupRows.size() == 2);
-
- // add a group by combining the two previous groups
- ColumnGroup columns1234 = row2.addGroup(columns12, columns34);
- assertTrue(columns1234.getColumns().size() == 4);
-
- // Insert a group as the second group
- ColumnGroupRow newRow2 = grid.addColumnGroupRow(1);
- assertTrue(state.columnGroupRows.size() == 3);
- }
-
- @Test
- public void testAddingColumnGroups() throws Exception {
-
- ColumnGroupRow row = grid.addColumnGroupRow();
-
- // By property id
- ColumnGroup columns01 = row.addGroup("column0", "column1");
- assertEquals(2, columns01.getColumns().size());
- assertEquals("column0", columns01.getColumns().get(0));
- assertTrue(columns01.isColumnInGroup("column0"));
- assertEquals("column1", columns01.getColumns().get(1));
- assertTrue(columns01.isColumnInGroup("column1"));
-
- // By grid column
- ColumnGroup columns23 = row.addGroup(grid.getColumn("column2"),
- grid.getColumn("column3"));
- assertEquals(2, columns23.getColumns().size());
- assertEquals("column2", columns23.getColumns().get(0));
- assertTrue(columns23.isColumnInGroup("column2"));
- assertEquals("column3", columns23.getColumns().get(1));
- assertTrue(columns23.isColumnInGroup("column3"));
-
- // Combine groups
- ColumnGroupRow row2 = grid.addColumnGroupRow();
- ColumnGroup columns0123 = row2.addGroup(columns01, columns23);
- assertEquals(4, columns0123.getColumns().size());
- assertEquals("column0", columns0123.getColumns().get(0));
- assertTrue(columns0123.isColumnInGroup("column0"));
- assertEquals("column1", columns0123.getColumns().get(1));
- assertTrue(columns0123.isColumnInGroup("column1"));
- assertEquals("column2", columns0123.getColumns().get(2));
- assertTrue(columns0123.isColumnInGroup("column2"));
- assertEquals("column3", columns0123.getColumns().get(3));
- assertTrue(columns0123.isColumnInGroup("column3"));
- }
-
- @Test
- public void testColumnGroupHeadersAndFooters() throws Exception {
-
- ColumnGroupRow row = grid.addColumnGroupRow();
- ColumnGroup group = row.addGroup("column1", "column2");
-
- // Header
- assertNull(group.getHeaderCaption());
- group.setHeaderCaption("My header");
- assertEquals("My header", group.getHeaderCaption());
- group.setHeaderCaption(null);
- assertNull(group.getHeaderCaption());
-
- // Footer
- assertNull(group.getFooterCaption());
- group.setFooterCaption("My footer");
- assertEquals("My footer", group.getFooterCaption());
- group.setFooterCaption(null);
- assertNull(group.getFooterCaption());
- }
-
- @Test
- public void testColumnGroupDetachment() throws Exception {
-
- ColumnGroupRow row = grid.addColumnGroupRow();
- ColumnGroup group = row.addGroup("column1", "column2");
-
- // Remove group
- row.removeGroup(group);
-
- try {
- group.setHeaderCaption("Header");
- fail("Should throw exception for setting header caption on detached group");
- } catch (IllegalStateException ise) {
-
- }
-
- try {
- group.setFooterCaption("Footer");
- fail("Should throw exception for setting footer caption on detached group");
- } catch (IllegalStateException ise) {
-
- }
- }
-
- @Test
- public void testColumnGroupLimits() throws Exception {
-
- ColumnGroupRow row = grid.addColumnGroupRow();
- row.addGroup("column1", "column2");
- row.addGroup("column3", "column4");
-
- try {
- row.addGroup("column2", "column3");
- fail("Adding a group with already grouped properties should throw exception");
- } catch (IllegalArgumentException iae) {
-
- }
-
- ColumnGroupRow row2 = grid.addColumnGroupRow();
-
- try {
- row2.addGroup("column2", "column3");
- fail("Adding a group that breaks previous grouping boundaries should throw exception");
- } catch (IllegalArgumentException iae) {
-
- }
-
- // This however should not throw an exception as it spans completely
- // over the parent rows groups
- row2.addGroup("column1", "column2", "column3", "column4");
-
- }
-}
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
deleted file mode 100644
index da07611b48..0000000000
--- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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.tests.server.component.grid;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.vaadin.data.util.IndexedContainer;
-import com.vaadin.server.KeyMapper;
-import com.vaadin.shared.ui.grid.GridColumnState;
-import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.ui.components.grid.Grid;
-import com.vaadin.ui.components.grid.GridColumn;
-
-public class GridColumns {
-
- private Grid grid;
-
- private GridState state;
-
- private Method getStateMethod;
-
- private Field columnIdGeneratorField;
-
- private KeyMapper<Object> columnIdMapper;
-
- @Before
- public void setup() throws Exception {
- IndexedContainer ds = new IndexedContainer();
- for (int c = 0; c < 10; c++) {
- ds.addContainerProperty("column" + c, String.class, "");
- }
- grid = new Grid(ds);
-
- getStateMethod = Grid.class.getDeclaredMethod("getState");
- getStateMethod.setAccessible(true);
-
- state = (GridState) getStateMethod.invoke(grid);
-
- columnIdGeneratorField = Grid.class.getDeclaredField("columnKeys");
- columnIdGeneratorField.setAccessible(true);
-
- columnIdMapper = (KeyMapper<Object>) columnIdGeneratorField.get(grid);
- }
-
- @Test
- public void testColumnGeneration() throws Exception {
-
- for (Object propertyId : grid.getContainerDatasource()
- .getContainerPropertyIds()) {
-
- // All property ids should get a column
- GridColumn column = grid.getColumn(propertyId);
- assertNotNull(column);
-
- // Property id should be the column header by default
- assertEquals(propertyId.toString(), column.getHeaderCaption());
- }
- }
-
- @Test
- public void testModifyingColumnProperties() throws Exception {
-
- // Modify first column
- GridColumn column = grid.getColumn("column1");
- assertNotNull(column);
-
- column.setFooterCaption("CustomFooter");
- assertEquals("CustomFooter", column.getFooterCaption());
- assertEquals(column.getFooterCaption(),
- getColumnState("column1").footer);
-
- column.setHeaderCaption("CustomHeader");
- assertEquals("CustomHeader", column.getHeaderCaption());
- assertEquals(column.getHeaderCaption(),
- getColumnState("column1").header);
-
- column.setVisible(false);
- assertFalse(column.isVisible());
- assertFalse(getColumnState("column1").visible);
-
- column.setVisible(true);
- assertTrue(column.isVisible());
- assertTrue(getColumnState("column1").visible);
-
- column.setWidth(100);
- assertEquals(100, column.getWidth());
- assertEquals(column.getWidth(), getColumnState("column1").width);
-
- try {
- column.setWidth(-1);
- fail("Setting width to -1 should throw exception");
- } catch (IllegalArgumentException iae) {
-
- }
-
- assertEquals(100, column.getWidth());
- assertEquals(100, getColumnState("column1").width);
- }
-
- @Test
- public void testRemovingColumn() throws Exception {
-
- GridColumn column = grid.getColumn("column1");
- assertNotNull(column);
-
- // Remove column
- grid.getContainerDatasource().removeContainerProperty("column1");
-
- try {
- column.setHeaderCaption("asd");
-
- fail("Succeeded in modifying a detached column");
- } catch (IllegalStateException ise) {
- // Detached state should throw exception
- }
-
- try {
- column.setFooterCaption("asd");
- fail("Succeeded in modifying a detached column");
- } catch (IllegalStateException ise) {
- // Detached state should throw exception
- }
-
- try {
- column.setVisible(false);
- fail("Succeeded in modifying a detached column");
- } catch (IllegalStateException ise) {
- // Detached state should throw exception
- }
-
- try {
- column.setWidth(123);
- fail("Succeeded in modifying a detached column");
- } catch (IllegalStateException ise) {
- // Detached state should throw exception
- }
-
- assertNull(grid.getColumn("column1"));
- assertNull(getColumnState("column1"));
- }
-
- @Test
- public void testAddingColumn() throws Exception {
- grid.getContainerDatasource().addContainerProperty("columnX",
- String.class, "");
- GridColumn column = grid.getColumn("columnX");
- assertNotNull(column);
- }
-
- @Test
- public void testHeaderVisiblility() throws Exception {
-
- assertTrue(grid.isColumnHeadersVisible());
- assertTrue(state.columnHeadersVisible);
-
- grid.setColumnHeadersVisible(false);
- assertFalse(grid.isColumnHeadersVisible());
- assertFalse(state.columnHeadersVisible);
-
- grid.setColumnHeadersVisible(true);
- assertTrue(grid.isColumnHeadersVisible());
- assertTrue(state.columnHeadersVisible);
- }
-
- @Test
- public void testFooterVisibility() throws Exception {
-
- assertFalse(grid.isColumnFootersVisible());
- assertFalse(state.columnFootersVisible);
-
- grid.setColumnFootersVisible(false);
- assertFalse(grid.isColumnFootersVisible());
- assertFalse(state.columnFootersVisible);
-
- grid.setColumnFootersVisible(true);
- assertTrue(grid.isColumnFootersVisible());
- assertTrue(state.columnFootersVisible);
- }
-
- @Test
- public void testFrozenColumnByPropertyId() {
- assertNull("Grid should not start with a frozen column",
- grid.getLastFrozenPropertyId());
-
- Object propertyId = grid.getContainerDatasource()
- .getContainerPropertyIds().iterator().next();
- grid.setLastFrozenPropertyId(propertyId);
- assertEquals(propertyId, grid.getLastFrozenPropertyId());
-
- grid.getContainerDatasource().removeContainerProperty(propertyId);
- assertNull(grid.getLastFrozenPropertyId());
- }
-
- private GridColumnState getColumnState(Object propertyId) {
- String columnId = columnIdMapper.key(propertyId);
- for (GridColumnState columnState : state.columns) {
- if (columnState.id.equals(columnId)) {
- return columnState;
- }
- }
- return null;
- }
-
-}
diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java
deleted file mode 100644
index 79e3f17f8d..0000000000
--- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.data;
-
-import java.util.List;
-
-import com.vaadin.shared.communication.ClientRpc;
-
-/**
- * RPC interface used for pushing container data to the client.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface DataProviderRpc extends ClientRpc {
-
- /**
- * Sends updated row data to a client.
- *
- * @param firstRowIndex
- * the index of the first updated row
- * @param rowData
- * the updated row data
- */
- public void setRowData(int firstRowIndex, List<String[]> rowData);
-
- /**
- * 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
- */
- 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>
- */
- public void insertRowData(int firstRowIndex, int count);
-}
diff --git a/shared/src/com/vaadin/shared/data/DataProviderState.java b/shared/src/com/vaadin/shared/data/DataProviderState.java
deleted file mode 100644
index 2eabe0b0e1..0000000000
--- a/shared/src/com/vaadin/shared/data/DataProviderState.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.data;
-
-import com.vaadin.shared.communication.SharedState;
-
-/**
- * Shared state used by client-side data sources.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class DataProviderState extends SharedState {
- /**
- * The size of the container.
- */
- public int containerSize;
-}
diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java
deleted file mode 100644
index eaf17df8f6..0000000000
--- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.data;
-
-import com.vaadin.shared.communication.ServerRpc;
-
-/**
- * RPC interface used for requesting container data to the client.
- *
- * @since 7.2
- * @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
- */
- public void requestRows(int firstRowIndex, int numberOfRows);
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java
deleted file mode 100644
index a8e0f87457..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The column group row data shared between the server and client
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class ColumnGroupRowState implements Serializable {
-
- /**
- * The groups that has been added to the row
- */
- public List<ColumnGroupState> groups = new ArrayList<ColumnGroupState>();
-
- /**
- * Is the header shown
- */
- public boolean headerVisible = true;
-
- /**
- * Is the footer shown
- */
- public boolean footerVisible = false;
-
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java
deleted file mode 100644
index 3992b6611f..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The column group data shared between the server and the client
- *
- * @since 7.2
- * @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/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java
deleted file mode 100644
index 00cc93d371..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 com.vaadin.shared.communication.ClientRpc;
-
-/**
- * Server-to-client RPC interface for the Grid component.
- *
- * @since 7.2
- * @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
deleted file mode 100644
index 0301c5ead2..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 java.io.Serializable;
-
-/**
- * Column state DTO for transferring column properties from the server to the
- * client
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class GridColumnState implements Serializable {
-
- /**
- * Id used by grid connector to map server side column with client side
- * column
- */
- public String id;
-
- /**
- * Header caption for the column
- */
- public String header;
-
- /**
- * Footer caption for the column
- */
- public String footer;
-
- /**
- * Has the column been hidden. By default the column is visible.
- */
- public boolean visible = true;
-
- /**
- * Column width in pixels. Default column width is 100px.
- */
- public int width = 100;
-
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
deleted file mode 100644
index 5b88fad5a8..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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;
-
-/**
- * Container class for common constants and default values used by the Grid
- * component.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public final class GridConstants {
-
- /**
- * Default padding in pixels when scrolling programmatically, without an
- * explicitly defined padding value.
- */
- public static final int DEFAULT_PADDING = 0;
-
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
deleted file mode 100644
index db0a31ed2c..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 com.vaadin.shared.communication.ServerRpc;
-
-/**
- * TODO
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public interface GridServerRpc extends ServerRpc {
-
- /**
- * TODO
- *
- * @param firstVisibleRow
- * the index of the first visible row
- * @param visibleRowCount
- * the number of rows visible, counted from
- * <code>firstVisibleRow</code>
- */
- void setVisibleRows(int firstVisibleRow, int visibleRowCount);
-
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
deleted file mode 100644
index 93e602a539..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/GridState.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 java.util.ArrayList;
-import java.util.List;
-
-import com.vaadin.shared.AbstractComponentState;
-
-/**
- * The shared state for the {@link com.vaadin.ui.components.grid.Grid} component
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class GridState extends AbstractComponentState {
- {
- // FIXME Grid currently does not support undefined size
- width = "400px";
- height = "400px";
- }
-
- /**
- * Columns in grid. Column order implicitly deferred from list order.
- */
- public List<GridColumnState> columns = new ArrayList<GridColumnState>();
-
- /**
- * Is the column header row visible
- */
- public boolean columnHeadersVisible = true;
-
- /**
- * Is the column footer row visible
- */
- public boolean columnFootersVisible = false;
-
- /**
- * The column groups added to the grid
- */
- public List<ColumnGroupRowState> columnGroupRows = new ArrayList<ColumnGroupRowState>();
-
- /**
- * The id for the last frozen column.
- *
- * @see GridColumnState#id
- */
- public String lastFrozenColumnId = null;
-
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/Range.java b/shared/src/com/vaadin/shared/ui/grid/Range.java
deleted file mode 100644
index 3114a79c82..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/Range.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * 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;
-
-/**
- * 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 7.2
- * @author Vaadin Ltd
- */
-public final class Range {
- 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 &gt; 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 &lt; 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 &gt; 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> &leq; 0, the first element will be empty, and
- * the second element will be this range. If <code>length</code>
- * &geq; {@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()));
- }
-}
diff --git a/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java b/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java
deleted file mode 100644
index decc2fab5f..0000000000
--- a/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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;
-
-/**
- * Enumeration, specifying the destinations that are supported when scrolling
- * rows or columns into view.
- *
- * @since 7.2
- * @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/tests/src/com/vaadin/shared/ui/grid/RangeTest.java b/shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java
deleted file mode 100644
index b042cee509..0000000000
--- a/shared/tests/src/com/vaadin/shared/ui/grid/RangeTest.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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);
- }
-
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html
deleted file mode 100644
index 70aa0fe195..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://localhost:8888/" />
-<title>BasicEscalator</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">BasicEscalator</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.grid.BasicEscalator?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
- <td>Row 0: 0,0 (0)</td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[17]/domChild[9]</td>
- <td>Cell: 9,17 (179)</td>
-</tr>
-<tr>
- <td>verifyTextNotPresent</td>
- <td>Cell: 0,100</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyTextNotPresent</td>
- <td>Cell: 0,101</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]</td>
- <td>0</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[1]/VTextField[0]</td>
- <td>1</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[18]/domChild[0]</td>
- <td>Row 0: 0,100 (190)</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]</td>
- <td>11</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[17]/domChild[0]</td>
- <td>Row 11: 0,101 (200)</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]</td>
- <td>0</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[1]/VTextField[0]</td>
- <td>100</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[16]/domChild[0]</td>
- <td>Row 0: 0,102 (210)</td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]</td>
- <td>Row 16: 0,118 (370)</td>
-</tr>
-<tr>
- <td>scroll</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[0]</td>
- <td>1109</td>
-</tr>
-<tr>
- <td>verifyTextPresent</td>
- <td>Row 56: 0,158</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyTextPresent</td>
- <td>Row 72: 0,174</td>
- <td></td>
-</tr>
-<tr>
- <td>scroll</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[0]</td>
- <td>3690</td>
-</tr>
-<tr>
- <td>verifyTextPresent</td>
- <td>Row 201: 0,99</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[0]/VTextField[0]</td>
- <td>201</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[1]/VTextField[0]</td>
- <td>1</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]</td>
- <td>Row 200: 0,98 (960)</td>
-</tr>
-<tr>
- <td>verifyTextNotPresent</td>
- <td>Row 201:</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[0]/VTextField[0]</td>
- <td>0</td>
-</tr>
-<tr>
- <td>type</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[1]/VTextField[0]</td>
- <td>2</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[2]/VButton[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[16]/domChild[0]</td>
- <td>Row 184: 10,82 (974)</td>
-</tr>
-<tr>
- <td>verifyText</td>
- <td>vaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]</td>
- <td>Row 200: 10,98 (1006)</td>
-</tr>
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java
deleted file mode 100644
index 61d263f433..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import java.util.Random;
-
-import com.vaadin.annotations.Widgetset;
-import com.vaadin.server.VaadinRequest;
-import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.tests.widgetset.TestingWidgetSet;
-import com.vaadin.tests.widgetset.server.grid.TestGrid;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.ui.HorizontalLayout;
-import com.vaadin.ui.Layout;
-import com.vaadin.ui.NativeSelect;
-import com.vaadin.ui.TextField;
-
-/**
- * @since 7.2
- * @author Vaadin Ltd
- */
-@Widgetset(TestingWidgetSet.NAME)
-public class BasicEscalator extends AbstractTestUI {
- public static final String ESCALATOR = "escalator";
- public static final String INSERT_ROWS_OFFSET = "iro";
- public static final String INSERT_ROWS_AMOUNT = "ira";
- public static final String INSERT_ROWS_BUTTON = "irb";
-
- private final Random random = new Random();
-
- @Override
- protected void setup(final VaadinRequest request) {
- final TestGrid grid = new TestGrid();
- grid.setId(ESCALATOR);
- addComponent(grid);
-
- final Layout insertRowsLayout = new HorizontalLayout();
- final TextField insertRowsOffset = new TextField();
- insertRowsOffset.setId(INSERT_ROWS_OFFSET);
- insertRowsLayout.addComponent(insertRowsOffset);
- final TextField insertRowsAmount = new TextField();
- insertRowsAmount.setId(INSERT_ROWS_AMOUNT);
- insertRowsLayout.addComponent(insertRowsAmount);
- insertRowsLayout.addComponent(new Button("insert rows",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- final int offset = Integer.parseInt(insertRowsOffset
- .getValue());
- final int amount = Integer.parseInt(insertRowsAmount
- .getValue());
- grid.insertRows(offset, amount);
- }
- }) {
- {
- setId(INSERT_ROWS_BUTTON);
- }
- });
- addComponent(insertRowsLayout);
-
- final Layout removeRowsLayout = new HorizontalLayout();
- final TextField removeRowsOffset = new TextField();
- removeRowsLayout.addComponent(removeRowsOffset);
- final TextField removeRowsAmount = new TextField();
- removeRowsLayout.addComponent(removeRowsAmount);
- removeRowsLayout.addComponent(new Button("remove rows",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- final int offset = Integer.parseInt(removeRowsOffset
- .getValue());
- final int amount = Integer.parseInt(removeRowsAmount
- .getValue());
- grid.removeRows(offset, amount);
- }
- }));
- addComponent(removeRowsLayout);
-
- final Layout insertColumnsLayout = new HorizontalLayout();
- final TextField insertColumnsOffset = new TextField();
- insertColumnsLayout.addComponent(insertColumnsOffset);
- final TextField insertColumnsAmount = new TextField();
- insertColumnsLayout.addComponent(insertColumnsAmount);
- insertColumnsLayout.addComponent(new Button("insert columns",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- final int offset = Integer.parseInt(insertColumnsOffset
- .getValue());
- final int amount = Integer.parseInt(insertColumnsAmount
- .getValue());
- grid.insertColumns(offset, amount);
- }
- }));
- addComponent(insertColumnsLayout);
-
- final Layout removeColumnsLayout = new HorizontalLayout();
- final TextField removeColumnsOffset = new TextField();
- removeColumnsLayout.addComponent(removeColumnsOffset);
- final TextField removeColumnsAmount = new TextField();
- removeColumnsLayout.addComponent(removeColumnsAmount);
- removeColumnsLayout.addComponent(new Button("remove columns",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- final int offset = Integer.parseInt(removeColumnsOffset
- .getValue());
- final int amount = Integer.parseInt(removeColumnsAmount
- .getValue());
- grid.removeColumns(offset, amount);
- }
- }));
- addComponent(removeColumnsLayout);
-
- final HorizontalLayout rowScroll = new HorizontalLayout();
- final NativeSelect destination = new NativeSelect();
- destination.setNullSelectionAllowed(false);
- destination.addItem("any");
- destination.setValue("any");
- destination.addItem("start");
- destination.addItem("end");
- destination.addItem("middle");
- rowScroll.addComponent(destination);
- final TextField rowIndex = new TextField();
- rowScroll.addComponent(rowIndex);
- final TextField rowPadding = new TextField();
- rowScroll.addComponent(rowPadding);
- rowScroll.addComponent(new Button("scroll to row",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- int index;
- try {
- index = Integer.parseInt(rowIndex.getValue());
- } catch (NumberFormatException e) {
- index = 0;
- }
-
- int padding;
- try {
- padding = Integer.parseInt(rowPadding.getValue());
- } catch (NumberFormatException e) {
- padding = 0;
- }
-
- grid.scrollToRow(index,
- (String) destination.getValue(), padding);
- }
- }));
- addComponent(rowScroll);
-
- final HorizontalLayout colScroll = new HorizontalLayout();
- final NativeSelect colDestination = new NativeSelect();
- colDestination.setNullSelectionAllowed(false);
- colDestination.addItem("any");
- colDestination.setValue("any");
- colDestination.addItem("start");
- colDestination.addItem("end");
- colDestination.addItem("middle");
- colScroll.addComponent(colDestination);
- final TextField colIndex = new TextField();
- colScroll.addComponent(colIndex);
- final TextField colPadding = new TextField();
- colScroll.addComponent(colPadding);
- colScroll.addComponent(new Button("scroll to column",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- int index;
- try {
- index = Integer.parseInt(colIndex.getValue());
- } catch (NumberFormatException e) {
- index = 0;
- }
-
- int padding;
- try {
- padding = Integer.parseInt(colPadding.getValue());
- } catch (NumberFormatException e) {
- padding = 0;
- }
-
- grid.scrollToColumn(index,
- (String) colDestination.getValue(), padding);
- }
- }));
- addComponent(colScroll);
-
- final TextField freezeCount = new TextField();
- freezeCount.setConverter(Integer.class);
- freezeCount.setNullRepresentation("");
- addComponent(new HorizontalLayout(freezeCount, new Button(
- "set frozen columns", new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.setFrozenColumns(((Integer) freezeCount
- .getConvertedValue()).intValue());
- freezeCount.setValue(null);
- }
- })));
-
- addComponent(new Button("Resize randomly", new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- int width = random.nextInt(300) + 500;
- int height = random.nextInt(300) + 200;
- grid.setWidth(width + "px");
- grid.setHeight(height + "px");
- }
- }));
-
- addComponent(new Button("Random headers count",
- new Button.ClickListener() {
- private int headers = 1;
-
- @Override
- public void buttonClick(ClickEvent event) {
- int diff = 0;
- while (diff == 0) {
- final int nextHeaders = random.nextInt(4);
- diff = nextHeaders - headers;
- headers = nextHeaders;
- }
- if (diff > 0) {
- grid.insertHeaders(0, diff);
- } else if (diff < 0) {
- grid.removeHeaders(0, -diff);
- }
- }
- }));
-
- addComponent(new Button("Random footers count",
- new Button.ClickListener() {
- private int footers = 1;
-
- @Override
- public void buttonClick(ClickEvent event) {
- int diff = 0;
- while (diff == 0) {
- final int nextFooters = random.nextInt(4);
- diff = nextFooters - footers;
- footers = nextFooters;
- }
- if (diff > 0) {
- grid.insertFooters(0, diff);
- } else if (diff < 0) {
- grid.removeFooters(0, -diff);
- }
- }
- }));
-
- final Layout resizeColumnsLayout = new HorizontalLayout();
- final TextField resizeColumnIndex = new TextField();
- resizeColumnsLayout.addComponent(resizeColumnIndex);
- final TextField resizeColumnPx = new TextField();
- resizeColumnsLayout.addComponent(resizeColumnPx);
- resizeColumnsLayout.addComponent(new Button("resize column",
- new Button.ClickListener() {
- @Override
- public void buttonClick(final ClickEvent event) {
- final int index = Integer.parseInt(resizeColumnIndex
- .getValue());
- final int px = Integer.parseInt(resizeColumnPx
- .getValue());
- grid.setColumnWidth(index, px);
- }
- }));
- addComponent(resizeColumnsLayout);
-
- addComponent(new Button("Autoresize columns",
- new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.calculateColumnWidths();
- }
- }));
-
- addComponent(new Button("Randomize row heights",
- new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.randomizeDefaultRowHeight();
- }
- }));
- }
-
- @Override
- protected String getTestDescription() {
- return null;
- }
-
- @Override
- protected Integer getTicketNumber() {
- return null;
- }
-
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java
deleted file mode 100644
index 5afe826196..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import org.junit.Test;
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebElement;
-
-import com.vaadin.tests.tb3.MultiBrowserTest;
-
-public class BasicEscalatorTest extends MultiBrowserTest {
-
- @Test
- public void testNormalHeight() throws Exception {
- openTestURL();
- compareScreen("normalHeight");
- }
-
- @Test
- public void testModifiedHeight() throws Exception {
- openTestURLWithTheme("reindeer-tests");
- compareScreen("modifiedHeight");
- }
-
- private WebElement getFirstBodyRowCell() {
- return getDriver().findElement(
- By.xpath("//tbody/tr[@class='v-escalator-row'][1]/td[1]"));
- }
-
- private void openTestURLWithTheme(String themeName) {
- String testUrl = getTestUrl();
- testUrl += (testUrl.contains("?")) ? "&" : "?";
- testUrl += "theme=" + themeName;
- getDriver().get(testUrl);
- }
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
deleted file mode 100644
index c28feb8d10..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-
-import com.vaadin.data.Item;
-import com.vaadin.data.util.IndexedContainer;
-import com.vaadin.tests.components.AbstractComponentTest;
-import com.vaadin.ui.components.grid.ColumnGroup;
-import com.vaadin.ui.components.grid.ColumnGroupRow;
-import com.vaadin.ui.components.grid.Grid;
-import com.vaadin.ui.components.grid.GridColumn;
-
-/**
- * Tests the basic features like columns, footers and headers
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class GridBasicFeatures extends AbstractComponentTest<Grid> {
-
- private final int COLUMNS = 10;
-
- private int columnGroupRows = 0;
-
- private final int ROWS = 1000;
-
- private IndexedContainer ds;
-
- @Override
- protected Grid constructComponent() {
-
- // Build data source
- ds = new IndexedContainer();
-
- for (int col = 0; col < COLUMNS; col++) {
- ds.addContainerProperty(getColumnProperty(col), String.class, "");
- }
-
- for (int row = 0; row < ROWS; row++) {
- Item item = ds.addItem(Integer.valueOf(row));
- for (int col = 0; col < COLUMNS; col++) {
- item.getItemProperty(getColumnProperty(col)).setValue(
- "(" + row + ", " + col + ")");
- }
- }
-
- // Create grid
- Grid grid = new Grid(ds);
-
- // Add footer values (header values are automatically created)
- for (int col = 0; col < COLUMNS; col++) {
- grid.getColumn(getColumnProperty(col)).setFooterCaption(
- "Footer " + col);
- }
-
- // Set varying column widths
- for (int col = 0; col < COLUMNS; col++) {
- grid.getColumn("Column" + col).setWidth(100 + col * 50);
- }
-
- createGridActions();
-
- createColumnActions();
-
- createHeaderActions();
-
- createFooterActions();
-
- createColumnGroupActions();
-
- createRowActions();
-
- return grid;
- }
-
- protected void createGridActions() {
- LinkedHashMap<String, String> primaryStyleNames = new LinkedHashMap<String, String>();
- primaryStyleNames.put("v-grid", "v-grid");
- primaryStyleNames.put("v-escalator", "v-escalator");
- primaryStyleNames.put("my-grid", "my-grid");
-
- createMultiClickAction("Primary style name", "State",
- primaryStyleNames, new Command<Grid, String>() {
-
- @Override
- public void execute(Grid grid, String value, Object data) {
- grid.setPrimaryStyleName(value);
-
- }
- }, primaryStyleNames.get("v-grid"));
- }
-
- protected void createHeaderActions() {
- createCategory("Headers", null);
-
- createBooleanAction("Visible", "Headers", true,
- new Command<Grid, Boolean>() {
-
- @Override
- public void execute(Grid grid, Boolean value, Object data) {
- grid.setColumnHeadersVisible(value);
- }
- });
- }
-
- protected void createFooterActions() {
- createCategory("Footers", null);
-
- createBooleanAction("Visible", "Footers", false,
- new Command<Grid, Boolean>() {
-
- @Override
- public void execute(Grid grid, Boolean value, Object data) {
- grid.setColumnFootersVisible(value);
- }
- });
- }
-
- protected void createColumnActions() {
- createCategory("Columns", null);
-
- for (int c = 0; c < COLUMNS; c++) {
- createCategory(getColumnProperty(c), "Columns");
-
- createBooleanAction("Visible", getColumnProperty(c), true,
- new Command<Grid, Boolean>() {
-
- @Override
- public void execute(Grid grid, Boolean value,
- Object columnIndex) {
- Object propertyId = (new ArrayList(grid
- .getContainerDatasource()
- .getContainerPropertyIds())
- .get((Integer) columnIndex));
- GridColumn column = grid.getColumn(propertyId);
- column.setVisible(!column.isVisible());
- }
- }, c);
-
- createClickAction("Remove", getColumnProperty(c),
- new Command<Grid, String>() {
-
- @Override
- public void execute(Grid grid, String value, Object data) {
- grid.getContainerDatasource()
- .removeContainerProperty("Column" + data);
- }
- }, null, c);
-
- createClickAction("Freeze", getColumnProperty(c),
- new Command<Grid, String>() {
-
- @Override
- public void execute(Grid grid, String value, Object data) {
- grid.setLastFrozenPropertyId("Column" + data);
- }
- }, null, c);
-
- createCategory("Column" + c + " Width", getColumnProperty(c));
-
- createClickAction("Auto", "Column" + c + " Width",
- new Command<Grid, Integer>() {
-
- @Override
- public void execute(Grid grid, Integer value,
- Object columnIndex) {
- Object propertyId = (new ArrayList(grid
- .getContainerDatasource()
- .getContainerPropertyIds())
- .get((Integer) columnIndex));
- GridColumn column = grid.getColumn(propertyId);
- column.setWidthUndefined();
- }
- }, -1, c);
-
- for (int w = 50; w < 300; w += 50) {
- createClickAction(w + "px", "Column" + c + " Width",
- new Command<Grid, Integer>() {
-
- @Override
- public void execute(Grid grid, Integer value,
- Object columnIndex) {
- Object propertyId = (new ArrayList(grid
- .getContainerDatasource()
- .getContainerPropertyIds())
- .get((Integer) columnIndex));
- GridColumn column = grid.getColumn(propertyId);
- column.setWidth(value);
- }
- }, w, c);
- }
- }
- }
-
- private static String getColumnProperty(int c) {
- return "Column" + c;
- }
-
- protected void createColumnGroupActions() {
- createCategory("Column groups", null);
-
- createClickAction("Add group row", "Column groups",
- new Command<Grid, String>() {
-
- @Override
- public void execute(Grid grid, String value, Object data) {
- final ColumnGroupRow row = grid.addColumnGroupRow();
- columnGroupRows++;
- createCategory("Column group row " + columnGroupRows,
- "Column groups");
-
- createBooleanAction("Header Visible",
- "Column group row " + columnGroupRows, true,
- new Command<Grid, Boolean>() {
-
- @Override
- public void execute(Grid grid,
- Boolean value, Object columnIndex) {
- row.setHeaderVisible(value);
- }
- }, row);
-
- createBooleanAction("Footer Visible",
- "Column group row " + columnGroupRows, false,
- new Command<Grid, Boolean>() {
-
- @Override
- public void execute(Grid grid,
- Boolean value, Object columnIndex) {
- row.setFooterVisible(value);
- }
- }, row);
-
- for (int i = 0; i < COLUMNS; i++) {
- final int columnIndex = i;
- createClickAction("Group Column " + columnIndex
- + " & " + (columnIndex + 1),
- "Column group row " + columnGroupRows,
- new Command<Grid, Integer>() {
-
- @Override
- public void execute(Grid c,
- Integer value, Object data) {
- final ColumnGroup group = row
- .addGroup(
- "Column" + value,
- "Column"
- + (value + 1));
-
- group.setHeaderCaption("Column "
- + value + " & "
- + (value + 1));
-
- group.setFooterCaption("Column "
- + value + " & "
- + (value + 1));
- }
- }, i, row);
- }
- }
- }, null, null);
-
- }
-
- protected void createRowActions() {
- createCategory("Body rows", null);
-
- createClickAction("Add first row", "Body rows",
- new Command<Grid, String>() {
- @Override
- public void execute(Grid c, String value, Object data) {
- Item item = ds.addItemAt(0, new Object());
- for (int i = 0; i < COLUMNS; i++) {
- item.getItemProperty(getColumnProperty(i))
- .setValue("newcell: " + i);
- }
- }
- }, null);
-
- createClickAction("Remove first row", "Body rows",
- new Command<Grid, String>() {
- @Override
- public void execute(Grid c, String value, Object data) {
- Object firstItemId = ds.getIdByIndex(0);
- ds.removeItem(firstItemId);
- }
- }, null);
-
- createClickAction("Modify first row (getItemProperty)", "Body rows",
- new Command<Grid, String>() {
- @Override
- public void execute(Grid c, String value, Object data) {
- Object firstItemId = ds.getIdByIndex(0);
- Item item = ds.getItem(firstItemId);
- for (int i = 0; i < COLUMNS; i++) {
- item.getItemProperty(getColumnProperty(i))
- .setValue("modified: " + i);
- }
- }
- }, null);
-
- createClickAction("Modify first row (getContainerProperty)",
- "Body rows", new Command<Grid, String>() {
- @Override
- public void execute(Grid c, String value, Object data) {
- Object firstItemId = ds.getIdByIndex(0);
- for (Object containerPropertyId : ds
- .getContainerPropertyIds()) {
- ds.getContainerProperty(firstItemId,
- containerPropertyId).setValue(
- "modified: " + containerPropertyId);
- }
- }
- }, null);
- }
-
- @Override
- protected Integer getTicketNumber() {
- return 12829;
- }
-
- @Override
- protected Class<Grid> getTestClass() {
- return Grid.class;
- }
-
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java
deleted file mode 100644
index bc43f2be98..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-
-import org.junit.Test;
-import org.openqa.selenium.By;
-import org.openqa.selenium.NoSuchElementException;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.interactions.Actions;
-
-import com.vaadin.tests.tb3.MultiBrowserTest;
-
-/**
- *
- * @since
- * @author Vaadin Ltd
- */
-public class GridBasicFeaturesTest extends MultiBrowserTest {
-
- @Test
- public void testColumnHeaderCaptions() throws Exception {
- openTestURL();
-
- // Column headers should be visible
- List<WebElement> cells = getGridHeaderRowCells();
- assertEquals(10, cells.size());
- assertEquals("Column0", cells.get(0).getText());
- assertEquals("Column1", cells.get(1).getText());
- assertEquals("Column2", cells.get(2).getText());
- }
-
- @Test
- public void testColumnFooterCaptions() throws Exception {
- openTestURL();
-
- // footer row should by default be hidden
- List<WebElement> cells = getGridFooterRowCells();
- assertEquals(0, cells.size());
-
- // Open footer row
- selectMenuPath("Component", "Footers", "Visible");
-
- // Footers should now be visible
- cells = getGridFooterRowCells();
- assertEquals(10, cells.size());
- assertEquals("Footer 0", cells.get(0).getText());
- assertEquals("Footer 1", cells.get(1).getText());
- assertEquals("Footer 2", cells.get(2).getText());
- }
-
- @Test
- public void testColumnGroupHeaders() throws Exception {
- openTestURL();
-
- // Hide column headers for this test
- selectMenuPath("Component", "Headers", "Visible");
-
- List<WebElement> cells = getGridHeaderRowCells();
-
- // header row should be empty
- assertEquals(0, cells.size());
-
- // add a group row
- selectMenuPath("Component", "Column groups", "Add group row");
-
- // Empty group row cells should be present
- cells = getGridHeaderRowCells();
- assertEquals(10, cells.size());
-
- // Group columns 0 & 1
- selectMenuPath("Component", "Column groups", "Column group row 1",
- "Group Column 0 & 1");
-
- cells = getGridHeaderRowCells();
- assertEquals("Column 0 & 1", cells.get(0).getText());
- }
-
- @Test
- public void testColumnGroupFooters() throws Exception {
- openTestURL();
-
- // add a group row
- selectMenuPath("Component", "Column groups", "Add group row");
-
- // Set footer visible
- selectMenuPath("Component", "Column groups", "Column group row 1",
- "Footer Visible");
-
- // Group columns 0 & 1
- selectMenuPath("Component", "Column groups", "Column group row 1",
- "Group Column 0 & 1");
-
- List<WebElement> cells = getGridFooterRowCells();
- assertEquals("Column 0 & 1", cells.get(0).getText());
- }
-
- @Test
- public void testGroupingSameColumnsOnRowThrowsException() throws Exception {
- openTestURL();
-
- // add a group row
- selectMenuPath("Component", "Column groups", "Add group row");
-
- // Group columns 0 & 1
- selectMenuPath("Component", "Column groups", "Column group row 1",
- "Group Column 0 & 1");
-
- // Group columns 1 & 2 shoud fail
- selectMenuPath("Component", "Column groups", "Column group row 1",
- "Group Column 1 & 2");
-
- assertTrue(getLogRow(0)
- .contains(
- "Exception occured, java.lang.IllegalArgumentExceptionColumn Column1 already belongs to another group."));
- }
-
- @Test
- public void testHidingColumn() throws Exception {
- openTestURL();
-
- // Column 0 should be visible
- List<WebElement> cells = getGridHeaderRowCells();
- assertEquals("Column0", cells.get(0).getText());
-
- // Hide column 0
- selectMenuPath("Component", "Columns", "Column0", "Visible");
-
- // Column 1 should now be the first cell
- cells = getGridHeaderRowCells();
- assertEquals("Column1", cells.get(0).getText());
- }
-
- @Test
- public void testRemovingColumn() throws Exception {
- openTestURL();
-
- // Column 0 should be visible
- List<WebElement> cells = getGridHeaderRowCells();
- assertEquals("Column0", cells.get(0).getText());
-
- // Hide column 0
- selectMenuPath("Component", "Columns", "Column0", "Remove");
-
- // Column 1 should now be the first cell
- cells = getGridHeaderRowCells();
- assertEquals("Column1", cells.get(0).getText());
- }
-
- @Test
- public void testFreezingColumn() throws Exception {
- openTestURL();
-
- // Freeze column 2
- selectMenuPath("Component", "Columns", "Column2", "Freeze");
-
- WebElement cell = getBodyCellByRowAndColumn(1, 1);
- assertTrue(cell.getAttribute("class").contains("frozen"));
-
- cell = getBodyCellByRowAndColumn(1, 2);
- assertTrue(cell.getAttribute("class").contains("frozen"));
- }
-
- @Test
- public void testInitialColumnWidths() throws Exception {
- openTestURL();
-
- // Default borders and margins implemented by escalator
- int cellBorder = 1 + 1;
- int cellMargin = 2 + 2;
-
- WebElement cell = getBodyCellByRowAndColumn(1, 1);
- assertEquals((100 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
-
- cell = getBodyCellByRowAndColumn(1, 2);
- assertEquals((150 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
-
- cell = getBodyCellByRowAndColumn(1, 3);
- assertEquals((200 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
- }
-
- @Test
- public void testColumnWidths() throws Exception {
- openTestURL();
-
- // Default borders and margins implemented by escalator
- int cellBorder = 1 + 1;
- int cellMargin = 2 + 2;
-
- // Default column width is 100px
- WebElement cell = getBodyCellByRowAndColumn(1, 1);
- assertEquals((100 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
-
- // Set first column to be 200px wide
- selectMenuPath("Component", "Columns", "Column0", "Column0 Width",
- "200px");
-
- cell = getBodyCellByRowAndColumn(1, 1);
- assertEquals((200 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
-
- // Set second column to be 150px wide
- selectMenuPath("Component", "Columns", "Column1", "Column1 Width",
- "150px");
- cell = getBodyCellByRowAndColumn(1, 2);
- assertEquals((150 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
-
- // Set first column to be auto sized (defaults to 100px currently)
- selectMenuPath("Component", "Columns", "Column0", "Column0 Width",
- "Auto");
-
- cell = getBodyCellByRowAndColumn(1, 1);
- assertEquals((100 - cellBorder - cellMargin) + "px",
- cell.getCssValue("width"));
- }
-
- @Test
- public void testPrimaryStyleNames() throws Exception {
- openTestURL();
-
- // v-grid is default primary style namea
- assertPrimaryStylename("v-grid");
-
- selectMenuPath("Component", "State", "Primary style name",
- "v-escalator");
- assertPrimaryStylename("v-escalator");
-
- selectMenuPath("Component", "State", "Primary style name", "my-grid");
- assertPrimaryStylename("my-grid");
-
- selectMenuPath("Component", "State", "Primary style name", "v-grid");
- assertPrimaryStylename("v-grid");
- }
-
- /**
- * Test that the current view is updated when a server-side container change
- * occurs (without scrolling back and forth)
- */
- @Test
- public void testItemSetChangeEvent() throws Exception {
- openTestURL();
-
- final By newRow = By.xpath("//td[text()='newcell: 0']");
-
- assertTrue("Unexpected initial state", !elementIsFound(newRow));
-
- selectMenuPath("Component", "Body rows", "Add first row");
- assertTrue("Add row failed", elementIsFound(newRow));
-
- selectMenuPath("Component", "Body rows", "Remove first row");
- assertTrue("Remove row failed", !elementIsFound(newRow));
- }
-
- /**
- * Test that the current view is updated when a property's value is reflect
- * to the client, when the value is modified server-side.
- */
- @Test
- public void testPropertyValueChangeEvent() throws Exception {
- openTestURL();
-
- assertEquals("Unexpected cell initial state", "(0, 0)",
- getBodyCellByRowAndColumn(1, 1).getText());
-
- selectMenuPath("Component", "Body rows",
- "Modify first row (getItemProperty)");
- assertEquals("(First) modification with getItemProperty failed",
- "modified: 0", getBodyCellByRowAndColumn(1, 1).getText());
-
- selectMenuPath("Component", "Body rows",
- "Modify first row (getContainerProperty)");
- assertEquals("(Second) modification with getItemProperty failed",
- "modified: Column0", getBodyCellByRowAndColumn(1, 1).getText());
- }
-
- private boolean elementIsFound(By locator) {
- try {
- return driver.findElement(locator) != null;
- } catch (NoSuchElementException e) {
- return false;
- }
- }
-
- private void assertPrimaryStylename(String stylename) {
- assertTrue(getGridElement().getAttribute("class").contains(stylename));
-
- String tableWrapperStyleName = getTableWrapper().getAttribute("class");
- assertTrue(tableWrapperStyleName.contains(stylename + "-tablewrapper"));
-
- String hscrollStyleName = getHorizontalScroller().getAttribute("class");
- assertTrue(hscrollStyleName.contains(stylename + "-scroller"));
- assertTrue(hscrollStyleName
- .contains(stylename + "-scroller-horizontal"));
-
- String vscrollStyleName = getVerticalScroller().getAttribute("class");
- assertTrue(vscrollStyleName.contains(stylename + "-scroller"));
- assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical"));
- }
-
- private WebElement getBodyCellByRowAndColumn(int row, int column) {
- return getDriver().findElement(
- By.xpath("//div[@id='testComponent']//tbody/tr[" + row
- + "]/td[" + column + "]"));
- }
-
- private void selectSubMenu(String menuCaption) {
- selectMenu(menuCaption);
- new Actions(getDriver()).moveByOffset(100, 0).build().perform();
- }
-
- private void selectMenu(String menuCaption) {
- getDriver().findElement(
- By.xpath("//span[text() = '" + menuCaption + "']")).click();
- }
-
- private void selectMenuPath(String... menuCaptions) {
- selectMenu(menuCaptions[0]);
- for (int i = 1; i < menuCaptions.length; i++) {
- selectSubMenu(menuCaptions[i]);
- }
- }
-
- private WebElement getVerticalScroller() {
- return getDriver().findElement(
- By.xpath("//div[@id='testComponent']/div[1]"));
- }
-
- private WebElement getHorizontalScroller() {
- return getDriver().findElement(
- By.xpath("//div[@id='testComponent']/div[2]"));
- }
-
- private WebElement getTableWrapper() {
- return getDriver().findElement(
- By.xpath("//div[@id='testComponent']/div[3]"));
- }
-
- private WebElement getGridElement() {
- return getDriver().findElement(By.id("testComponent"));
- }
-
- private List<WebElement> getGridHeaderRowCells() {
- return getDriver().findElements(
- By.xpath("//div[@id='testComponent']//thead//th"));
- }
-
- private List<WebElement> getGridFooterRowCells() {
- return getDriver().findElements(
- By.xpath("//div[@id='testComponent']//tfoot//td"));
- }
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java
deleted file mode 100644
index 66e7651f76..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import com.vaadin.data.util.IndexedContainer;
-import com.vaadin.server.VaadinRequest;
-import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.ui.components.grid.ColumnGroup;
-import com.vaadin.ui.components.grid.ColumnGroupRow;
-import com.vaadin.ui.components.grid.Grid;
-import com.vaadin.ui.components.grid.GridColumn;
-
-/**
- *
- * @since
- * @author Vaadin Ltd
- */
-public class GridColumnGroups extends AbstractTestUI {
-
- private final int COLUMNS = 4;
-
- @Override
- protected void setup(VaadinRequest request) {
-
- // Setup grid
- IndexedContainer ds = new IndexedContainer();
- for (int col = 0; col < COLUMNS; col++) {
- ds.addContainerProperty("Column" + col, String.class, "");
- }
- Grid grid = new Grid(ds);
- addComponent(grid);
-
- /*-
- * ---------------------------------------------
- * | Header 1 | <- Auxiliary row 2
- * |-------------------------------------------|
- * | Header 2 | Header 3 | <- Auxiliary row 1
- * |-------------------------------------------|
- * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column headers
- * --------------------------------------------|
- * | ... | ... | ... | ... |
- * | ... | ... | ... | ... |
- * --------------------------------------------|
- * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column footers
- * --------------------------------------------|
- * | Footer 2 | Footer 3 | <- Auxiliary row 1
- * --------------------------------------------|
- * | Footer 1 | <- Auxiliary row 2
- * ---------------------------------------------
- -*/
-
- // Set column footers (headers are generated automatically)
- grid.setColumnFootersVisible(true);
- for (Object propertyId : ds.getContainerPropertyIds()) {
- GridColumn column = grid.getColumn(propertyId);
- column.setFooterCaption(String.valueOf(propertyId));
- }
-
- // First auxiliary row
- ColumnGroupRow auxRow1 = grid.addColumnGroupRow();
-
- // Using property id to create a column group
- ColumnGroup columns12 = auxRow1.addGroup("Column0", "Column1");
- columns12.setHeaderCaption("Header 2");
- columns12.setFooterCaption("Footer 2");
-
- // Using grid columns to create a column group
- GridColumn column3 = grid.getColumn("Column2");
- GridColumn column4 = grid.getColumn("Column3");
- ColumnGroup columns34 = auxRow1.addGroup(column3, column4);
- columns34.setHeaderCaption("Header 3");
- columns34.setFooterCaption("Footer 3");
-
- // Second auxiliary row
- ColumnGroupRow auxRow2 = grid.addColumnGroupRow();
-
- // Using previous groups to create a column group
- ColumnGroup columns1234 = auxRow2.addGroup(columns12, columns34);
- columns1234.setHeaderCaption("Header 1");
- columns1234.setFooterCaption("Footer 1");
-
- }
-
- @Override
- protected String getTestDescription() {
- return "Grid should support headers and footer groups";
- }
-
- @Override
- protected Integer getTicketNumber() {
- return 12894;
- }
-
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java
deleted file mode 100644
index d514fbd0c5..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.tests.components.grid;
-
-import com.vaadin.data.Item;
-import com.vaadin.data.util.IndexedContainer;
-import com.vaadin.server.VaadinRequest;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.ui.Button.ClickListener;
-import com.vaadin.ui.HorizontalLayout;
-import com.vaadin.ui.VerticalLayout;
-import com.vaadin.ui.components.grid.Grid;
-
-/**
- *
- */
-@SuppressWarnings("serial")
-public class GridScrolling extends AbstractTestUI {
-
- private Grid grid;
-
- private IndexedContainer ds;
-
- @Override
- @SuppressWarnings("unchecked")
- protected void setup(VaadinRequest request) {
- // Build data source
- ds = new IndexedContainer();
-
- for (int col = 0; col < 5; col++) {
- ds.addContainerProperty("col" + col, String.class, "");
- }
-
- for (int row = 0; row < 65536; row++) {
- Item item = ds.addItem(Integer.valueOf(row));
- for (int col = 0; col < 5; col++) {
- item.getItemProperty("col" + col).setValue(
- "(" + row + ", " + col + ")");
- }
- }
-
- grid = new Grid(ds);
-
- HorizontalLayout hl = new HorizontalLayout();
- hl.addComponent(grid);
- hl.setMargin(true);
- hl.setSpacing(true);
-
- VerticalLayout vl = new VerticalLayout();
- vl.setSpacing(true);
-
- // Add scroll buttons
- Button scrollUpButton = new Button("Top", new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.scrollToStart();
- }
- });
- scrollUpButton.setSizeFull();
- vl.addComponent(scrollUpButton);
-
- for (int i = 1; i < 7; ++i) {
- final int row = (ds.size() / 7) * i;
- Button scrollButton = new Button("Scroll to row " + row,
- new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.scrollToItem(Integer.valueOf(row),
- ScrollDestination.MIDDLE);
- }
- });
- scrollButton.setSizeFull();
- vl.addComponent(scrollButton);
- }
-
- Button scrollDownButton = new Button("Bottom", new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- grid.scrollToEnd();
- }
- });
- scrollDownButton.setSizeFull();
- vl.addComponent(scrollDownButton);
-
- hl.addComponent(vl);
- addComponent(hl);
- }
-
- @Override
- protected String getTestDescription() {
- return "Test Grid programmatic scrolling features";
- }
-
- @Override
- protected Integer getTicketNumber() {
- return 13327;
- }
-
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java
deleted file mode 100644
index ae2799d228..0000000000
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.tests.widgetset.client.grid;
-
-import com.vaadin.shared.communication.ClientRpc;
-
-public interface TestGridClientRpc extends ClientRpc {
- void insertRows(int offset, int amount);
-
- void removeRows(int offset, int amount);
-
- void insertColumns(int offset, int amount);
-
- void removeColumns(int offset, int amount);
-
- void scrollToRow(int index, String destination, int padding);
-
- void scrollToColumn(int index, String destination, int padding);
-
- void setFrozenColumns(int frozenColumns);
-
- void insertHeaders(int index, int amount);
-
- void removeHeaders(int index, int amount);
-
- void insertFooters(int index, int amount);
-
- void removeFooters(int index, int amount);
-
- void setColumnWidth(int index, int px);
-
- void calculateColumnWidths();
-
- void randomRowHeight();
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java
deleted file mode 100644
index e2d88c57f2..0000000000
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.tests.widgetset.client.grid;
-
-import com.google.gwt.user.client.Random;
-import com.vaadin.client.ui.AbstractComponentConnector;
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-import com.vaadin.tests.widgetset.server.grid.TestGrid;
-
-/**
- * @since 7.2
- * @author Vaadin Ltd
- */
-@Connect(TestGrid.class)
-public class TestGridConnector extends AbstractComponentConnector {
- @Override
- protected void init() {
- super.init();
- registerRpc(TestGridClientRpc.class, new TestGridClientRpc() {
- @Override
- public void insertRows(int offset, int amount) {
- getWidget().insertRows(offset, amount);
- }
-
- @Override
- public void removeRows(int offset, int amount) {
- getWidget().removeRows(offset, amount);
- }
-
- @Override
- public void removeColumns(int offset, int amount) {
- getWidget().removeColumns(offset, amount);
- }
-
- @Override
- public void insertColumns(int offset, int amount) {
- getWidget().insertColumns(offset, amount);
- }
-
- @Override
- public void scrollToRow(int index, String destination, int padding) {
- getWidget().scrollToRow(index, getDestination(destination),
- padding);
- }
-
- @Override
- public void scrollToColumn(int index, String destination,
- int padding) {
- getWidget().scrollToColumn(index, getDestination(destination),
- padding);
- }
-
- private ScrollDestination getDestination(String destination) {
- final ScrollDestination d;
- if (destination.equals("start")) {
- d = ScrollDestination.START;
- } else if (destination.equals("middle")) {
- d = ScrollDestination.MIDDLE;
- } else if (destination.equals("end")) {
- d = ScrollDestination.END;
- } else {
- d = ScrollDestination.ANY;
- }
- return d;
- }
-
- @Override
- public void setFrozenColumns(int frozenColumns) {
- getWidget().getColumnConfiguration().setFrozenColumnCount(
- frozenColumns);
- }
-
- @Override
- public void insertHeaders(int index, int amount) {
- getWidget().getHeader().insertRows(index, amount);
- }
-
- @Override
- public void removeHeaders(int index, int amount) {
- getWidget().getHeader().removeRows(index, amount);
- }
-
- @Override
- public void insertFooters(int index, int amount) {
- getWidget().getFooter().insertRows(index, amount);
- }
-
- @Override
- public void removeFooters(int index, int amount) {
- getWidget().getFooter().removeRows(index, amount);
- }
-
- @Override
- public void setColumnWidth(int index, int px) {
- getWidget().getColumnConfiguration().setColumnWidth(index, px);
- }
-
- @Override
- public void calculateColumnWidths() {
- getWidget().calculateColumnWidths();
- }
-
- @Override
- public void randomRowHeight() {
- getWidget().getHeader().setDefaultRowHeight(
- Random.nextInt(20) + 20);
- getWidget().getBody().setDefaultRowHeight(
- Random.nextInt(20) + 20);
- getWidget().getFooter().setDefaultRowHeight(
- Random.nextInt(20) + 20);
- }
- });
- }
-
- @Override
- public VTestGrid getWidget() {
- return (VTestGrid) super.getWidget();
- }
-
- @Override
- public TestGridState getState() {
- return (TestGridState) super.getState();
- }
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java
deleted file mode 100644
index 73d6ba311c..0000000000
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.tests.widgetset.client.grid;
-
-import com.vaadin.shared.AbstractComponentState;
-
-/**
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class TestGridState extends AbstractComponentState {
- public static final String DEFAULT_HEIGHT = "400.0px";
-
- /* TODO: this should be "100%" before setting final. */
- public static final String DEFAULT_WIDTH = "800.0px";
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java
deleted file mode 100644
index 28e650edc1..0000000000
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.vaadin.tests.widgetset.client.grid;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.google.gwt.user.client.ui.Composite;
-import com.vaadin.client.ui.grid.Cell;
-import com.vaadin.client.ui.grid.ColumnConfiguration;
-import com.vaadin.client.ui.grid.Escalator;
-import com.vaadin.client.ui.grid.EscalatorUpdater;
-import com.vaadin.client.ui.grid.Row;
-import com.vaadin.client.ui.grid.RowContainer;
-import com.vaadin.shared.ui.grid.ScrollDestination;
-
-public class VTestGrid extends Composite {
-
- private static class Data {
- private int columnCounter = 0;
- private int rowCounter = 0;
- private final List<Integer> columns = new ArrayList<Integer>();
- private final List<Integer> rows = new ArrayList<Integer>();
-
- @SuppressWarnings("boxing")
- public void insertRows(final int offset, final int amount) {
- final List<Integer> newRows = new ArrayList<Integer>();
- for (int i = 0; i < amount; i++) {
- newRows.add(rowCounter++);
- }
- rows.addAll(offset, newRows);
- }
-
- @SuppressWarnings("boxing")
- public void insertColumns(final int offset, final int amount) {
- final List<Integer> newColumns = new ArrayList<Integer>();
- for (int i = 0; i < amount; i++) {
- newColumns.add(columnCounter++);
- }
- columns.addAll(offset, newColumns);
- }
-
- public EscalatorUpdater createHeaderUpdater() {
- return new EscalatorUpdater() {
- @Override
- public void updateCells(final Row row,
- final Iterable<Cell> cellsToUpdate) {
- for (final Cell cell : cellsToUpdate) {
- if (cell.getColumn() % 3 == 0) {
- cell.setColSpan(2);
- }
-
- final Integer columnName = columns
- .get(cell.getColumn());
- cell.getElement().setInnerText("Header " + columnName);
- }
- }
- };
- }
-
- public EscalatorUpdater createFooterUpdater() {
- return new EscalatorUpdater() {
- @Override
- public void updateCells(final Row row,
- final Iterable<Cell> cellsToUpdate) {
- for (final Cell cell : cellsToUpdate) {
- if (cell.getColumn() % 3 == 1) {
- cell.setColSpan(2);
- }
-
- final Integer columnName = columns
- .get(cell.getColumn());
- cell.getElement().setInnerText("Footer " + columnName);
- }
- }
- };
- }
-
- public EscalatorUpdater createBodyUpdater() {
- return new EscalatorUpdater() {
- private int i = 0;
-
- public void renderCell(final Cell cell) {
- final Integer columnName = columns.get(cell.getColumn());
- final Integer rowName = rows.get(cell.getRow());
- final String cellInfo = columnName + "," + rowName + " ("
- + i + ")";
-
- if (cell.getColumn() > 0) {
- cell.getElement().setInnerText("Cell: " + cellInfo);
- } else {
- cell.getElement().setInnerText(
- "Row " + cell.getRow() + ": " + cellInfo);
- }
-
- if (cell.getColumn() % 3 == cell.getRow() % 3) {
- cell.setColSpan(3);
- }
-
- final double c = i * .1;
- final int r = (int) ((Math.cos(c) + 1) * 128);
- final int g = (int) ((Math.cos(c / Math.PI) + 1) * 128);
- final int b = (int) ((Math.cos(c / (Math.PI * 2)) + 1) * 128);
- cell.getElement()
- .getStyle()
- .setBackgroundColor(
- "rgb(" + r + "," + g + "," + b + ")");
- if ((r * .8 + g * 1.3 + b * .9) / 3 < 127) {
- cell.getElement().getStyle().setColor("white");
- } else {
- cell.getElement().getStyle().clearColor();
- }
-
- i++;
- }
-
- @Override
- public void updateCells(final Row row,
- final Iterable<Cell> cellsToUpdate) {
- for (final Cell cell : cellsToUpdate) {
- renderCell(cell);
- }
- }
- };
- }
-
- public void removeRows(final int offset, final int amount) {
- for (int i = 0; i < amount; i++) {
- rows.remove(offset);
- }
- }
-
- public void removeColumns(final int offset, final int amount) {
- for (int i = 0; i < amount; i++) {
- columns.remove(offset);
- }
- }
- }
-
- private final Escalator escalator = new Escalator();
- private final Data data = new Data();
-
- public VTestGrid() {
- initWidget(escalator);
- final RowContainer header = escalator.getHeader();
- header.setEscalatorUpdater(data.createHeaderUpdater());
- header.insertRows(0, 1);
-
- final RowContainer footer = escalator.getFooter();
- footer.setEscalatorUpdater(data.createFooterUpdater());
- footer.insertRows(0, 1);
-
- escalator.getBody().setEscalatorUpdater(data.createBodyUpdater());
-
- insertRows(0, 100);
- insertColumns(0, 10);
-
- setWidth(TestGridState.DEFAULT_WIDTH);
- setHeight(TestGridState.DEFAULT_HEIGHT);
-
- }
-
- public void insertRows(final int offset, final int number) {
- data.insertRows(offset, number);
- escalator.getBody().insertRows(offset, number);
- }
-
- public void insertColumns(final int offset, final int number) {
- data.insertColumns(offset, number);
- escalator.getColumnConfiguration().insertColumns(offset, number);
- }
-
- public ColumnConfiguration getColumnConfiguration() {
- return escalator.getColumnConfiguration();
- }
-
- public void scrollToRow(final int index,
- final ScrollDestination destination, final int padding) {
- escalator.scrollToRow(index, destination, padding);
- }
-
- public void scrollToColumn(final int index,
- final ScrollDestination destination, final int padding) {
- escalator.scrollToColumn(index, destination, padding);
- }
-
- public void removeRows(final int offset, final int amount) {
- data.removeRows(offset, amount);
- escalator.getBody().removeRows(offset, amount);
- }
-
- public void removeColumns(final int offset, final int amount) {
- data.removeColumns(offset, amount);
- escalator.getColumnConfiguration().removeColumns(offset, amount);
- }
-
- @Override
- public void setWidth(String width) {
- escalator.setWidth(width);
- }
-
- @Override
- public void setHeight(String height) {
- escalator.setHeight(height);
- }
-
- public RowContainer getHeader() {
- return escalator.getHeader();
- }
-
- public RowContainer getBody() {
- return escalator.getBody();
- }
-
- public RowContainer getFooter() {
- return escalator.getFooter();
- }
-
- public void calculateColumnWidths() {
- escalator.calculateColumnWidths();
- }
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java
deleted file mode 100644
index 4e218ebba1..0000000000
--- a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.tests.widgetset.server.grid;
-
-import com.vaadin.tests.widgetset.client.grid.TestGridClientRpc;
-import com.vaadin.tests.widgetset.client.grid.TestGridState;
-import com.vaadin.ui.AbstractComponent;
-
-/**
- * @since 7.2
- * @author Vaadin Ltd
- */
-public class TestGrid extends AbstractComponent {
- public TestGrid() {
- setWidth(TestGridState.DEFAULT_WIDTH);
- setHeight(TestGridState.DEFAULT_HEIGHT);
- }
-
- @Override
- protected TestGridState getState() {
- return (TestGridState) super.getState();
- }
-
- public void insertRows(int offset, int amount) {
- rpc().insertRows(offset, amount);
- }
-
- public void removeRows(int offset, int amount) {
- rpc().removeRows(offset, amount);
- }
-
- public void insertColumns(int offset, int amount) {
- rpc().insertColumns(offset, amount);
- }
-
- public void removeColumns(int offset, int amount) {
- rpc().removeColumns(offset, amount);
- }
-
- private TestGridClientRpc rpc() {
- return getRpcProxy(TestGridClientRpc.class);
- }
-
- public void scrollToRow(int index, String destination, int padding) {
- rpc().scrollToRow(index, destination, padding);
- }
-
- public void scrollToColumn(int index, String destination, int padding) {
- rpc().scrollToColumn(index, destination, padding);
- }
-
- public void setFrozenColumns(int frozenColumns) {
- rpc().setFrozenColumns(frozenColumns);
- }
-
- public void insertHeaders(int index, int amount) {
- rpc().insertHeaders(index, amount);
- }
-
- public void removeHeaders(int index, int amount) {
- rpc().removeHeaders(index, amount);
- }
-
- public void insertFooters(int index, int amount) {
- rpc().insertFooters(index, amount);
- }
-
- public void removeFooters(int index, int amount) {
- rpc().removeFooters(index, amount);
- }
-
- public void setColumnWidth(int index, int px) {
- rpc().setColumnWidth(index, px);
- }
-
- public void calculateColumnWidths() {
- rpc().calculateColumnWidths();
- }
-
- public void randomizeDefaultRowHeight() {
- rpc().randomRowHeight();
- }
-}