You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Grid.java 264KB

Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrating 7.7.1, 7.7.2, 7.7.3 to V8. commit 11c3f8bd9ea65f7a7b8da9a282c31a127bd475a6 - Test and its UI class are added (both V8 and V7). Required functionality should be available via modern GWT version. commit 729dbf96fe76e7627168ab2c9d1d71c4eb7214c8 - About update release notes. No need to be included. commit 675f38349c43ac45dae40cf33a7b1fd0f8f261ca - V8 already contains correct Import-Packages section which uses osgi.javax.servlet.version variable whise version is 3.0.0 at the moment. commit 5da7c052f55cb4703b74f38f5bb19fc3f3fa2a76 - Use Vaadin plugin 7.7.0 from 7.7.0.alpha1. Is not applicable. commit 1df80001ab6c916effa917781dba652d09d01056 - Updated tutorial to Vaadin 7.7.0. Is not applicable. The tutorial already contains correct links and updated source code snippets. commit 8b4f0ed8a894b04902a5d4258119dcdc8e76d1e0 - set-property-fallback name="user.agent" value="safari". Is already there. commit 28ed04e827669cc4dd329331dac9699bd93f70bc - Fix animation end listeners so they are always removed. Is already there. commit 408253bc3f8bd3975f0525ce6832be214a3552e9 - Use servlet context classloader when finding servlet class for websockets. Is already there. commit 7a6f250d89474849648ed2ee96a6bfb78c3b9ca8 - Fire actions before removing menu from the DOM. Is already there. commit 9b66c6eb9bebf657d3f2def8c767e0e9d51cc92c - Do not run test on IE8 as IE8 is broken. Transplanted. commit 3faa43ff39ecda56587b93f0c5e262a2907871a7 - Discard for DateField when the data source contains null. It is not applicable for V8 (There is no anymore discard method in DateField (and no datasource suport in field)). Transplanted for DateField in compatibility. commit e0c1f91a3d6d1884e07ce8d1ba957aff6a9bf29a - Fix ComboBox paging when number of items equals page length. It's already done by another fix which replaced ComboBox in compatibility package to the V7 version. commit 83a1b8a0961cc9b2d43e01757530cefd035b0a22 - Update DOM and update escalator row count in the correct order. Transplanted. commit 45f2fba8ff7a4b62680618a325d4afcebfb7a1e9 - Prevent editor from being canceled while it is being saved. Transplanted to compatibility package. Is not applicable to modern Grid. commit ad67f7f43afb0feec5e029aea90297f2abe4f2c1 - Delete broken stylesheet and revert to default style until a new stylesheet is created. Is already there. commit c970a78d42a2d8f1745df7a11a74f3731f8be9a5 - Always show loading indicator for JavaScript RPC. Transplanted. commit 2aad3416061586f7e2649160bd832eefe03702ad - Make test independent of any converters present in the factory. It's already there. commit c9ad48430be135d18fe9f30868e091dd51c57b94 - Do not include yuicompressor for Sass compiler. Transplanted. Exclusion is added into vaadin/pom.xml commit 52d01a68e91ce73306b3a1747af97e928048ecdf - Test for Firefox download disconnecting push channel. Transplanted. commit 4bc375d1d21f468e6433da3a183150e0bfe0cae4 - Handle encoded URL characters correctly when constructing widget set name. Transplanted. commit 17ba88eaf87e15e6f3c729e5c7f8e875d5f86d8d - Update version to 7.7-SNAPSHOT. Is not applicable. commit 47b7b13e5c959de3bd925693b074d85e7625a87e - Ensure Firefox always updates the grid scrollbar. Transplanted. Made changes in the logic to the test for modern Grid component. commit 4d851ba21d1b8f35685b631d2845731f8fb33252 - Calculate column widths immediately if there is data. Transplanted to both client side modules. commit 8f0b1a1dd026a756912c9f21bd2b34ea46897c7f - Skip Maven enforcer plugin during demo validation. Transplanted (one build file is affected). commit 62815353e1b9d3cd126809f5c818ad35bf913807 - Build demos from 7.7 branch (now for master branch). FW8 demos are added (one build file is affected). commit 815d72115d5aaf3676daefd5642115577e4151ef - Make test pass on all browsers. Transplanted to both V7 and V8 version tests. commit 516c428ca127e3c31b7b4d74220e4b7eed4571be - Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit b00c580ed70f682a42afbfa91f978921bb86c2cd - Use correct column index when calculating min width during resize. Transplanted into both client side classes (main and compatibility) as is. Test for V7 is transplanted as is. Test for V8 is written from scratch based on V7 version. commit 7dd91cf057eb06a09009096a8278f34aad9bd8d9 - Fix regression that broke widget set compilation in 7.7.1. It's already there. commit c665731b0b97b697e80c47955d3558c19f0c81cb - Ensure temporary layout manager state is cleared at the end of a layout phase. Transplanted to the one LayoutManager class. commit 57a965251afdb5ee9ac1913a0101d854d8215aa6 - Fix assertion error when column widths are calculated. Transplanted to both versions of the client Grid widget. commit c5c52684eb30d924cb75a632b526a0f879d5a33c - Format Java files using Eclipse Neon and Vaadin settings. Only formatting changes. Is not transplanted. f5d06d877165bf413ec71c4fc88cf46c8c57a372 - Change javadoc to a style Eclipse formatter can handle. Transplanted to both versions of the client Grid widget. commit 6033e13c20b3d6e8b6f5add0f786d5ab2e1bb3fe - Make initially disabled grid work when enabled. Transplanted to both client side modules. commit a2d6e4fb4b1fd13e9a1b88f2ab1b78d14d8b64a9 - Use requestAnimationFrame when scrolling in Grid. Transplanted to both client side modules. commit fe9438e7b77c606855cfd739dd7e30b3f8cd4165 - Specify branch also for Sampler. Is not applicable for master branch. commit 1ec5d8ef7cb8bbd82bae1c9b79a376a5dca28f48 - Update to Chrome 53. Is already there. commit 961851bfbc4844474299433c34af6c9e4323d891 - Updated link to new step 1 video in tutorial. Is already there. commit 41dc2fe1611adc70d00e6f77debb2a6d4dcdefb0 - Revert "Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit 092b4f7f3192555fe3ae22ac03a89ac2ada2a2dd - Use widget set specified by init parameter. Transplanted to the common server side classes. commit 977cec7e3107c2da306d46449dbf32f6544313be - Fix widget set builder to create widget set in correct location. Transplanted to the one ClassPathExplorer class file. commit 6c12ad89ea1064cd4cc0456baca5ee00ae76d032 - Format project pom files using correct settings. Is not transplanted: only formatting changes for POM files. commit 0aad93ecc1ce743dffc093ce7ae2ef88831f6073 - Add tests for widgetset compilation in different modes. Transplanted. New test projects. commit 0a3a1ef8321ed421be2337034fdb1cae2c434c3d - Use versions-maven-plugin 2.3 to avoid NPE while setting project version. Is already there. Change-Id: Ie3a5088f25de1772f01ea30c4a5eba0b169ee0ab
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrating 7.7.1, 7.7.2, 7.7.3 to V8. commit 11c3f8bd9ea65f7a7b8da9a282c31a127bd475a6 - Test and its UI class are added (both V8 and V7). Required functionality should be available via modern GWT version. commit 729dbf96fe76e7627168ab2c9d1d71c4eb7214c8 - About update release notes. No need to be included. commit 675f38349c43ac45dae40cf33a7b1fd0f8f261ca - V8 already contains correct Import-Packages section which uses osgi.javax.servlet.version variable whise version is 3.0.0 at the moment. commit 5da7c052f55cb4703b74f38f5bb19fc3f3fa2a76 - Use Vaadin plugin 7.7.0 from 7.7.0.alpha1. Is not applicable. commit 1df80001ab6c916effa917781dba652d09d01056 - Updated tutorial to Vaadin 7.7.0. Is not applicable. The tutorial already contains correct links and updated source code snippets. commit 8b4f0ed8a894b04902a5d4258119dcdc8e76d1e0 - set-property-fallback name="user.agent" value="safari". Is already there. commit 28ed04e827669cc4dd329331dac9699bd93f70bc - Fix animation end listeners so they are always removed. Is already there. commit 408253bc3f8bd3975f0525ce6832be214a3552e9 - Use servlet context classloader when finding servlet class for websockets. Is already there. commit 7a6f250d89474849648ed2ee96a6bfb78c3b9ca8 - Fire actions before removing menu from the DOM. Is already there. commit 9b66c6eb9bebf657d3f2def8c767e0e9d51cc92c - Do not run test on IE8 as IE8 is broken. Transplanted. commit 3faa43ff39ecda56587b93f0c5e262a2907871a7 - Discard for DateField when the data source contains null. It is not applicable for V8 (There is no anymore discard method in DateField (and no datasource suport in field)). Transplanted for DateField in compatibility. commit e0c1f91a3d6d1884e07ce8d1ba957aff6a9bf29a - Fix ComboBox paging when number of items equals page length. It's already done by another fix which replaced ComboBox in compatibility package to the V7 version. commit 83a1b8a0961cc9b2d43e01757530cefd035b0a22 - Update DOM and update escalator row count in the correct order. Transplanted. commit 45f2fba8ff7a4b62680618a325d4afcebfb7a1e9 - Prevent editor from being canceled while it is being saved. Transplanted to compatibility package. Is not applicable to modern Grid. commit ad67f7f43afb0feec5e029aea90297f2abe4f2c1 - Delete broken stylesheet and revert to default style until a new stylesheet is created. Is already there. commit c970a78d42a2d8f1745df7a11a74f3731f8be9a5 - Always show loading indicator for JavaScript RPC. Transplanted. commit 2aad3416061586f7e2649160bd832eefe03702ad - Make test independent of any converters present in the factory. It's already there. commit c9ad48430be135d18fe9f30868e091dd51c57b94 - Do not include yuicompressor for Sass compiler. Transplanted. Exclusion is added into vaadin/pom.xml commit 52d01a68e91ce73306b3a1747af97e928048ecdf - Test for Firefox download disconnecting push channel. Transplanted. commit 4bc375d1d21f468e6433da3a183150e0bfe0cae4 - Handle encoded URL characters correctly when constructing widget set name. Transplanted. commit 17ba88eaf87e15e6f3c729e5c7f8e875d5f86d8d - Update version to 7.7-SNAPSHOT. Is not applicable. commit 47b7b13e5c959de3bd925693b074d85e7625a87e - Ensure Firefox always updates the grid scrollbar. Transplanted. Made changes in the logic to the test for modern Grid component. commit 4d851ba21d1b8f35685b631d2845731f8fb33252 - Calculate column widths immediately if there is data. Transplanted to both client side modules. commit 8f0b1a1dd026a756912c9f21bd2b34ea46897c7f - Skip Maven enforcer plugin during demo validation. Transplanted (one build file is affected). commit 62815353e1b9d3cd126809f5c818ad35bf913807 - Build demos from 7.7 branch (now for master branch). FW8 demos are added (one build file is affected). commit 815d72115d5aaf3676daefd5642115577e4151ef - Make test pass on all browsers. Transplanted to both V7 and V8 version tests. commit 516c428ca127e3c31b7b4d74220e4b7eed4571be - Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit b00c580ed70f682a42afbfa91f978921bb86c2cd - Use correct column index when calculating min width during resize. Transplanted into both client side classes (main and compatibility) as is. Test for V7 is transplanted as is. Test for V8 is written from scratch based on V7 version. commit 7dd91cf057eb06a09009096a8278f34aad9bd8d9 - Fix regression that broke widget set compilation in 7.7.1. It's already there. commit c665731b0b97b697e80c47955d3558c19f0c81cb - Ensure temporary layout manager state is cleared at the end of a layout phase. Transplanted to the one LayoutManager class. commit 57a965251afdb5ee9ac1913a0101d854d8215aa6 - Fix assertion error when column widths are calculated. Transplanted to both versions of the client Grid widget. commit c5c52684eb30d924cb75a632b526a0f879d5a33c - Format Java files using Eclipse Neon and Vaadin settings. Only formatting changes. Is not transplanted. f5d06d877165bf413ec71c4fc88cf46c8c57a372 - Change javadoc to a style Eclipse formatter can handle. Transplanted to both versions of the client Grid widget. commit 6033e13c20b3d6e8b6f5add0f786d5ab2e1bb3fe - Make initially disabled grid work when enabled. Transplanted to both client side modules. commit a2d6e4fb4b1fd13e9a1b88f2ab1b78d14d8b64a9 - Use requestAnimationFrame when scrolling in Grid. Transplanted to both client side modules. commit fe9438e7b77c606855cfd739dd7e30b3f8cd4165 - Specify branch also for Sampler. Is not applicable for master branch. commit 1ec5d8ef7cb8bbd82bae1c9b79a376a5dca28f48 - Update to Chrome 53. Is already there. commit 961851bfbc4844474299433c34af6c9e4323d891 - Updated link to new step 1 video in tutorial. Is already there. commit 41dc2fe1611adc70d00e6f77debb2a6d4dcdefb0 - Revert "Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit 092b4f7f3192555fe3ae22ac03a89ac2ada2a2dd - Use widget set specified by init parameter. Transplanted to the common server side classes. commit 977cec7e3107c2da306d46449dbf32f6544313be - Fix widget set builder to create widget set in correct location. Transplanted to the one ClassPathExplorer class file. commit 6c12ad89ea1064cd4cc0456baca5ee00ae76d032 - Format project pom files using correct settings. Is not transplanted: only formatting changes for POM files. commit 0aad93ecc1ce743dffc093ce7ae2ef88831f6073 - Add tests for widgetset compilation in different modes. Transplanted. New test projects. commit 0a3a1ef8321ed421be2337034fdb1cae2c434c3d - Use versions-maven-plugin 2.3 to avoid NPE while setting project version. Is already there. Change-Id: Ie3a5088f25de1772f01ea30c4a5eba0b169ee0ab
7 years ago
Migrating 7.7.1, 7.7.2, 7.7.3 to V8. commit 11c3f8bd9ea65f7a7b8da9a282c31a127bd475a6 - Test and its UI class are added (both V8 and V7). Required functionality should be available via modern GWT version. commit 729dbf96fe76e7627168ab2c9d1d71c4eb7214c8 - About update release notes. No need to be included. commit 675f38349c43ac45dae40cf33a7b1fd0f8f261ca - V8 already contains correct Import-Packages section which uses osgi.javax.servlet.version variable whise version is 3.0.0 at the moment. commit 5da7c052f55cb4703b74f38f5bb19fc3f3fa2a76 - Use Vaadin plugin 7.7.0 from 7.7.0.alpha1. Is not applicable. commit 1df80001ab6c916effa917781dba652d09d01056 - Updated tutorial to Vaadin 7.7.0. Is not applicable. The tutorial already contains correct links and updated source code snippets. commit 8b4f0ed8a894b04902a5d4258119dcdc8e76d1e0 - set-property-fallback name="user.agent" value="safari". Is already there. commit 28ed04e827669cc4dd329331dac9699bd93f70bc - Fix animation end listeners so they are always removed. Is already there. commit 408253bc3f8bd3975f0525ce6832be214a3552e9 - Use servlet context classloader when finding servlet class for websockets. Is already there. commit 7a6f250d89474849648ed2ee96a6bfb78c3b9ca8 - Fire actions before removing menu from the DOM. Is already there. commit 9b66c6eb9bebf657d3f2def8c767e0e9d51cc92c - Do not run test on IE8 as IE8 is broken. Transplanted. commit 3faa43ff39ecda56587b93f0c5e262a2907871a7 - Discard for DateField when the data source contains null. It is not applicable for V8 (There is no anymore discard method in DateField (and no datasource suport in field)). Transplanted for DateField in compatibility. commit e0c1f91a3d6d1884e07ce8d1ba957aff6a9bf29a - Fix ComboBox paging when number of items equals page length. It's already done by another fix which replaced ComboBox in compatibility package to the V7 version. commit 83a1b8a0961cc9b2d43e01757530cefd035b0a22 - Update DOM and update escalator row count in the correct order. Transplanted. commit 45f2fba8ff7a4b62680618a325d4afcebfb7a1e9 - Prevent editor from being canceled while it is being saved. Transplanted to compatibility package. Is not applicable to modern Grid. commit ad67f7f43afb0feec5e029aea90297f2abe4f2c1 - Delete broken stylesheet and revert to default style until a new stylesheet is created. Is already there. commit c970a78d42a2d8f1745df7a11a74f3731f8be9a5 - Always show loading indicator for JavaScript RPC. Transplanted. commit 2aad3416061586f7e2649160bd832eefe03702ad - Make test independent of any converters present in the factory. It's already there. commit c9ad48430be135d18fe9f30868e091dd51c57b94 - Do not include yuicompressor for Sass compiler. Transplanted. Exclusion is added into vaadin/pom.xml commit 52d01a68e91ce73306b3a1747af97e928048ecdf - Test for Firefox download disconnecting push channel. Transplanted. commit 4bc375d1d21f468e6433da3a183150e0bfe0cae4 - Handle encoded URL characters correctly when constructing widget set name. Transplanted. commit 17ba88eaf87e15e6f3c729e5c7f8e875d5f86d8d - Update version to 7.7-SNAPSHOT. Is not applicable. commit 47b7b13e5c959de3bd925693b074d85e7625a87e - Ensure Firefox always updates the grid scrollbar. Transplanted. Made changes in the logic to the test for modern Grid component. commit 4d851ba21d1b8f35685b631d2845731f8fb33252 - Calculate column widths immediately if there is data. Transplanted to both client side modules. commit 8f0b1a1dd026a756912c9f21bd2b34ea46897c7f - Skip Maven enforcer plugin during demo validation. Transplanted (one build file is affected). commit 62815353e1b9d3cd126809f5c818ad35bf913807 - Build demos from 7.7 branch (now for master branch). FW8 demos are added (one build file is affected). commit 815d72115d5aaf3676daefd5642115577e4151ef - Make test pass on all browsers. Transplanted to both V7 and V8 version tests. commit 516c428ca127e3c31b7b4d74220e4b7eed4571be - Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit b00c580ed70f682a42afbfa91f978921bb86c2cd - Use correct column index when calculating min width during resize. Transplanted into both client side classes (main and compatibility) as is. Test for V7 is transplanted as is. Test for V8 is written from scratch based on V7 version. commit 7dd91cf057eb06a09009096a8278f34aad9bd8d9 - Fix regression that broke widget set compilation in 7.7.1. It's already there. commit c665731b0b97b697e80c47955d3558c19f0c81cb - Ensure temporary layout manager state is cleared at the end of a layout phase. Transplanted to the one LayoutManager class. commit 57a965251afdb5ee9ac1913a0101d854d8215aa6 - Fix assertion error when column widths are calculated. Transplanted to both versions of the client Grid widget. commit c5c52684eb30d924cb75a632b526a0f879d5a33c - Format Java files using Eclipse Neon and Vaadin settings. Only formatting changes. Is not transplanted. f5d06d877165bf413ec71c4fc88cf46c8c57a372 - Change javadoc to a style Eclipse formatter can handle. Transplanted to both versions of the client Grid widget. commit 6033e13c20b3d6e8b6f5add0f786d5ab2e1bb3fe - Make initially disabled grid work when enabled. Transplanted to both client side modules. commit a2d6e4fb4b1fd13e9a1b88f2ab1b78d14d8b64a9 - Use requestAnimationFrame when scrolling in Grid. Transplanted to both client side modules. commit fe9438e7b77c606855cfd739dd7e30b3f8cd4165 - Specify branch also for Sampler. Is not applicable for master branch. commit 1ec5d8ef7cb8bbd82bae1c9b79a376a5dca28f48 - Update to Chrome 53. Is already there. commit 961851bfbc4844474299433c34af6c9e4323d891 - Updated link to new step 1 video in tutorial. Is already there. commit 41dc2fe1611adc70d00e6f77debb2a6d4dcdefb0 - Revert "Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit 092b4f7f3192555fe3ae22ac03a89ac2ada2a2dd - Use widget set specified by init parameter. Transplanted to the common server side classes. commit 977cec7e3107c2da306d46449dbf32f6544313be - Fix widget set builder to create widget set in correct location. Transplanted to the one ClassPathExplorer class file. commit 6c12ad89ea1064cd4cc0456baca5ee00ae76d032 - Format project pom files using correct settings. Is not transplanted: only formatting changes for POM files. commit 0aad93ecc1ce743dffc093ce7ae2ef88831f6073 - Add tests for widgetset compilation in different modes. Transplanted. New test projects. commit 0a3a1ef8321ed421be2337034fdb1cae2c434c3d - Use versions-maven-plugin 2.3 to avoid NPE while setting project version. Is already there. Change-Id: Ie3a5088f25de1772f01ea30c4a5eba0b169ee0ab
7 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.v7.ui;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Type;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.EnumSet;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.Iterator;
  28. import java.util.LinkedHashMap;
  29. import java.util.LinkedHashSet;
  30. import java.util.LinkedList;
  31. import java.util.List;
  32. import java.util.Locale;
  33. import java.util.Map;
  34. import java.util.Map.Entry;
  35. import java.util.Set;
  36. import java.util.logging.Level;
  37. import java.util.logging.Logger;
  38. import org.jsoup.nodes.Attributes;
  39. import org.jsoup.nodes.Element;
  40. import org.jsoup.select.Elements;
  41. import com.vaadin.event.ContextClickEvent;
  42. import com.vaadin.event.FieldEvents.BlurEvent;
  43. import com.vaadin.event.FieldEvents.BlurListener;
  44. import com.vaadin.event.FieldEvents.FocusEvent;
  45. import com.vaadin.event.FieldEvents.FocusListener;
  46. import com.vaadin.server.AbstractClientConnector;
  47. import com.vaadin.server.AbstractExtension;
  48. import com.vaadin.server.EncodeResult;
  49. import com.vaadin.server.ErrorMessage;
  50. import com.vaadin.server.Extension;
  51. import com.vaadin.server.JsonCodec;
  52. import com.vaadin.server.KeyMapper;
  53. import com.vaadin.server.VaadinSession;
  54. import com.vaadin.shared.MouseEventDetails;
  55. import com.vaadin.shared.Registration;
  56. import com.vaadin.shared.data.sort.SortDirection;
  57. import com.vaadin.shared.ui.ErrorLevel;
  58. import com.vaadin.shared.util.SharedUtil;
  59. import com.vaadin.ui.AbstractComponent;
  60. import com.vaadin.ui.Component;
  61. import com.vaadin.ui.Component.Focusable;
  62. import com.vaadin.ui.ConnectorTracker;
  63. import com.vaadin.ui.SelectiveRenderer;
  64. import com.vaadin.ui.UI;
  65. import com.vaadin.ui.declarative.DesignAttributeHandler;
  66. import com.vaadin.ui.declarative.DesignContext;
  67. import com.vaadin.ui.declarative.DesignException;
  68. import com.vaadin.ui.declarative.DesignFormatter;
  69. import com.vaadin.util.ReflectTools;
  70. import com.vaadin.v7.data.Container;
  71. import com.vaadin.v7.data.Container.Indexed;
  72. import com.vaadin.v7.data.Container.ItemSetChangeEvent;
  73. import com.vaadin.v7.data.Container.ItemSetChangeListener;
  74. import com.vaadin.v7.data.Container.ItemSetChangeNotifier;
  75. import com.vaadin.v7.data.Container.PropertySetChangeEvent;
  76. import com.vaadin.v7.data.Container.PropertySetChangeListener;
  77. import com.vaadin.v7.data.Container.PropertySetChangeNotifier;
  78. import com.vaadin.v7.data.Container.Sortable;
  79. import com.vaadin.v7.data.Item;
  80. import com.vaadin.v7.data.Property;
  81. import com.vaadin.v7.data.Validator.InvalidValueException;
  82. import com.vaadin.v7.data.fieldgroup.DefaultFieldGroupFieldFactory;
  83. import com.vaadin.v7.data.fieldgroup.FieldGroup;
  84. import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException;
  85. import com.vaadin.v7.data.fieldgroup.FieldGroupFieldFactory;
  86. import com.vaadin.v7.data.sort.Sort;
  87. import com.vaadin.v7.data.sort.SortOrder;
  88. import com.vaadin.v7.data.util.IndexedContainer;
  89. import com.vaadin.v7.data.util.converter.Converter;
  90. import com.vaadin.v7.data.util.converter.ConverterUtil;
  91. import com.vaadin.v7.event.FieldEvents.BlurNotifier;
  92. import com.vaadin.v7.event.FieldEvents.FocusNotifier;
  93. import com.vaadin.v7.event.ItemClickEvent;
  94. import com.vaadin.v7.event.ItemClickEvent.ItemClickListener;
  95. import com.vaadin.v7.event.ItemClickEvent.ItemClickNotifier;
  96. import com.vaadin.v7.event.SelectionEvent;
  97. import com.vaadin.v7.event.SelectionEvent.SelectionListener;
  98. import com.vaadin.v7.event.SelectionEvent.SelectionNotifier;
  99. import com.vaadin.v7.event.SortEvent;
  100. import com.vaadin.v7.event.SortEvent.SortListener;
  101. import com.vaadin.v7.event.SortEvent.SortNotifier;
  102. import com.vaadin.v7.server.communication.data.DataGenerator;
  103. import com.vaadin.v7.server.communication.data.RpcDataProviderExtension;
  104. import com.vaadin.v7.shared.ui.grid.ColumnResizeMode;
  105. import com.vaadin.v7.shared.ui.grid.EditorClientRpc;
  106. import com.vaadin.v7.shared.ui.grid.EditorServerRpc;
  107. import com.vaadin.v7.shared.ui.grid.GridClientRpc;
  108. import com.vaadin.v7.shared.ui.grid.GridColumnState;
  109. import com.vaadin.v7.shared.ui.grid.GridConstants;
  110. import com.vaadin.v7.shared.ui.grid.GridConstants.Section;
  111. import com.vaadin.v7.shared.ui.grid.GridServerRpc;
  112. import com.vaadin.v7.shared.ui.grid.GridState;
  113. import com.vaadin.v7.shared.ui.grid.GridStaticCellType;
  114. import com.vaadin.v7.shared.ui.grid.GridStaticSectionState;
  115. import com.vaadin.v7.shared.ui.grid.GridStaticSectionState.CellState;
  116. import com.vaadin.v7.shared.ui.grid.GridStaticSectionState.RowState;
  117. import com.vaadin.v7.shared.ui.grid.HeightMode;
  118. import com.vaadin.v7.shared.ui.grid.ScrollDestination;
  119. import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelServerRpc;
  120. import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelState;
  121. import com.vaadin.v7.shared.ui.grid.selection.SingleSelectionModelServerRpc;
  122. import com.vaadin.v7.shared.ui.grid.selection.SingleSelectionModelState;
  123. import com.vaadin.v7.ui.Grid.SelectionModel.HasUserSelectionAllowed;
  124. import com.vaadin.v7.ui.renderers.HtmlRenderer;
  125. import com.vaadin.v7.ui.renderers.Renderer;
  126. import com.vaadin.v7.ui.renderers.TextRenderer;
  127. import elemental.json.Json;
  128. import elemental.json.JsonObject;
  129. import elemental.json.JsonValue;
  130. /**
  131. * A grid component for displaying tabular data.
  132. * <p>
  133. * Grid is always bound to a {@link Container.Indexed}, but is not a
  134. * {@code Container} of any kind in of itself. The contents of the given
  135. * Container is displayed with the help of {@link Renderer Renderers}.
  136. *
  137. * <h3 id="grid-headers-and-footers">Headers and Footers</h3>
  138. * <p>
  139. *
  140. *
  141. * <h3 id="grid-converters-and-renderers">Converters and Renderers</h3>
  142. * <p>
  143. * Each column has its own {@link Renderer} that displays data into something
  144. * that can be displayed in the browser. That data is first converted with a
  145. * {@link Converter} into something that the Renderer can process. This can also
  146. * be an implicit step - if a column has a simple data type, like a String, no
  147. * explicit assignment is needed.
  148. * <p>
  149. * Usually a renderer takes some kind of object, and converts it into a
  150. * HTML-formatted string.
  151. * <p>
  152. * <code><pre>
  153. * Grid grid = new Grid(myContainer);
  154. * Column column = grid.getColumn(STRING_DATE_PROPERTY);
  155. * column.setConverter(new StringToDateConverter());
  156. * column.setRenderer(new MyColorfulDateRenderer());
  157. * </pre></code>
  158. *
  159. * <h3 id="grid-lazyloading">Lazy Loading</h3>
  160. * <p>
  161. * The data is accessed as it is needed by Grid and not any sooner. In other
  162. * words, if the given Container is huge, but only the first few rows are
  163. * displayed to the user, only those (and a few more, for caching purposes) are
  164. * accessed.
  165. *
  166. * <h3 id="grid-selection-modes-and-models">Selection Modes and Models</h3>
  167. * <p>
  168. * Grid supports three selection <em>{@link SelectionMode modes}</em> (single,
  169. * multi, none), and comes bundled with one <em>{@link SelectionModel
  170. * model}</em> for each of the modes. The distinction between a selection mode
  171. * and selection model is as follows: a <em>mode</em> essentially says whether
  172. * you can have one, many or no rows selected. The model, however, has the
  173. * behavioral details of each. A single selection model may require that the
  174. * user deselects one row before selecting another one. A variant of a
  175. * multiselect might have a configurable maximum of rows that may be selected.
  176. * And so on.
  177. * <p>
  178. * <code><pre>
  179. * Grid grid = new Grid(myContainer);
  180. *
  181. * // uses the bundled SingleSelectionModel class
  182. * grid.setSelectionMode(SelectionMode.SINGLE);
  183. *
  184. * // changes the behavior to a custom selection model
  185. * grid.setSelectionModel(new MyTwoSelectionModel());
  186. * </pre></code>
  187. *
  188. * @since 7.4
  189. * @author Vaadin Ltd
  190. *
  191. * @deprecated As of 8.0 replaced by {@link com.vaadin.ui.Grid} based on the new
  192. * data binding API
  193. */
  194. @Deprecated
  195. public class Grid extends AbstractComponent
  196. implements SelectionNotifier, SortNotifier, SelectiveRenderer,
  197. ItemClickNotifier, Focusable, FocusNotifier, BlurNotifier {
  198. /**
  199. * An event listener for column visibility change events in the Grid.
  200. *
  201. * @since 7.5.0
  202. */
  203. @Deprecated
  204. public interface ColumnVisibilityChangeListener extends Serializable {
  205. /**
  206. * Called when a column has become hidden or unhidden.
  207. *
  208. * @param event
  209. */
  210. void columnVisibilityChanged(ColumnVisibilityChangeEvent event);
  211. }
  212. /**
  213. * An event that is fired when a column's visibility changes.
  214. *
  215. * @since 7.5.0
  216. */
  217. @Deprecated
  218. public static class ColumnVisibilityChangeEvent extends Component.Event {
  219. private final Column column;
  220. private final boolean userOriginated;
  221. private final boolean hidden;
  222. /**
  223. * Constructor for a column visibility change event.
  224. *
  225. * @param source
  226. * the grid from which this event originates
  227. * @param column
  228. * the column that changed its visibility
  229. * @param hidden
  230. * <code>true</code> if the column was hidden,
  231. * <code>false</code> if it became visible
  232. * @param isUserOriginated
  233. * <code>true</code> if the event was triggered by an UI
  234. * interaction
  235. */
  236. public ColumnVisibilityChangeEvent(Grid source, Column column,
  237. boolean hidden, boolean isUserOriginated) {
  238. super(source);
  239. this.column = column;
  240. this.hidden = hidden;
  241. userOriginated = isUserOriginated;
  242. }
  243. /**
  244. * Gets the column that became hidden or visible.
  245. *
  246. * @return the column that became hidden or visible.
  247. * @see Column#isHidden()
  248. */
  249. public Column getColumn() {
  250. return column;
  251. }
  252. /**
  253. * Was the column set hidden or visible.
  254. *
  255. * @return <code>true</code> if the column was hidden <code>false</code>
  256. * if it was set visible
  257. */
  258. public boolean isHidden() {
  259. return hidden;
  260. }
  261. /**
  262. * Returns <code>true</code> if the column reorder was done by the user,
  263. * <code>false</code> if not and it was triggered by server side code.
  264. *
  265. * @return <code>true</code> if event is a result of user interaction
  266. */
  267. public boolean isUserOriginated() {
  268. return userOriginated;
  269. }
  270. }
  271. /**
  272. * A callback interface for generating details for a particular row in Grid.
  273. *
  274. * @since 7.5.0
  275. * @author Vaadin Ltd
  276. * @see DetailsGenerator#NULL
  277. */
  278. @Deprecated
  279. public interface DetailsGenerator extends Serializable {
  280. /** A details generator that provides no details. */
  281. public DetailsGenerator NULL = new DetailsGenerator() {
  282. @Override
  283. public Component getDetails(RowReference rowReference) {
  284. return null;
  285. }
  286. };
  287. /**
  288. * This method is called for whenever a details row needs to be shown on
  289. * the client. Grid removes all of its references to details components
  290. * when they are no longer displayed on the client-side and will
  291. * re-request once needed again.
  292. * <p>
  293. * <em>Note:</em> If a component gets generated, it may not be manually
  294. * attached anywhere. The same details component can not be displayed
  295. * for multiple different rows.
  296. *
  297. * @param rowReference
  298. * the reference for the row for which to generate details
  299. * @return the details for the given row, or <code>null</code> to leave
  300. * the details empty.
  301. */
  302. Component getDetails(RowReference rowReference);
  303. }
  304. /**
  305. * A class that manages details components by calling
  306. * {@link DetailsGenerator} as needed. Details components are attached by
  307. * this class when the {@link RpcDataProviderExtension} is sending data to
  308. * the client. Details components are detached and forgotten when client
  309. * informs that it has dropped the corresponding item.
  310. *
  311. * @since 7.6.1
  312. */
  313. @Deprecated
  314. public static final class DetailComponentManager
  315. extends AbstractGridExtension implements DataGenerator {
  316. /**
  317. * The user-defined details generator.
  318. *
  319. * @see #setDetailsGenerator(DetailsGenerator)
  320. */
  321. private DetailsGenerator detailsGenerator;
  322. /**
  323. * This map represents all details that are currently visible on the
  324. * client. Details components get destroyed once they scroll out of
  325. * view.
  326. */
  327. private final Map<Object, Component> itemIdToDetailsComponent = new HashMap<Object, Component>();
  328. /**
  329. * Set of item ids that got <code>null</code> from DetailsGenerator when
  330. * {@link DetailsGenerator#getDetails(RowReference)} was called.
  331. */
  332. private final Set<Object> emptyDetails = new HashSet<Object>();
  333. /**
  334. * Set of item IDs for all open details rows. Contains even the ones
  335. * that are not currently visible on the client.
  336. */
  337. private final Set<Object> openDetails = new HashSet<Object>();
  338. public DetailComponentManager(Grid grid) {
  339. this(grid, DetailsGenerator.NULL);
  340. }
  341. public DetailComponentManager(Grid grid,
  342. DetailsGenerator detailsGenerator) {
  343. super(grid);
  344. setDetailsGenerator(detailsGenerator);
  345. }
  346. /**
  347. * Creates a details component with the help of the user-defined
  348. * {@link DetailsGenerator}.
  349. * <p>
  350. * This method attaches created components to the parent {@link Grid}.
  351. *
  352. * @param itemId
  353. * the item id for which to create the details component.
  354. * @throws IllegalStateException
  355. * if the current details generator provides a component
  356. * that was manually attached.
  357. */
  358. private void createDetails(Object itemId) throws IllegalStateException {
  359. assert itemId != null : "itemId was null";
  360. if (itemIdToDetailsComponent.containsKey(itemId)
  361. || emptyDetails.contains(itemId)) {
  362. // Don't overwrite existing components
  363. return;
  364. }
  365. RowReference rowReference = new RowReference(getParentGrid());
  366. rowReference.set(itemId);
  367. DetailsGenerator detailsGenerator = getParentGrid()
  368. .getDetailsGenerator();
  369. Component details = detailsGenerator.getDetails(rowReference);
  370. if (details != null) {
  371. if (details.getParent() != null) {
  372. String name = detailsGenerator.getClass().getName();
  373. throw new IllegalStateException(name
  374. + " generated a details component that already "
  375. + "was attached. (itemId: " + itemId
  376. + ", component: " + details + ")");
  377. }
  378. itemIdToDetailsComponent.put(itemId, details);
  379. addComponentToGrid(details);
  380. assert !emptyDetails.contains(itemId) : "Bookeeping thinks "
  381. + "itemId is empty even though we just created a "
  382. + "component for it (" + itemId + ")";
  383. } else {
  384. emptyDetails.add(itemId);
  385. }
  386. }
  387. /**
  388. * Destroys a details component correctly.
  389. * <p>
  390. * This method will detach the component from parent {@link Grid}.
  391. *
  392. * @param itemId
  393. * the item id for which to destroy the details component
  394. */
  395. private void destroyDetails(Object itemId) {
  396. emptyDetails.remove(itemId);
  397. Component removedComponent = itemIdToDetailsComponent
  398. .remove(itemId);
  399. if (removedComponent == null) {
  400. return;
  401. }
  402. removeComponentFromGrid(removedComponent);
  403. }
  404. /**
  405. * Recreates all visible details components.
  406. */
  407. public void refreshDetails() {
  408. Set<Object> visibleItemIds = new HashSet<Object>(
  409. itemIdToDetailsComponent.keySet());
  410. for (Object itemId : visibleItemIds) {
  411. destroyDetails(itemId);
  412. createDetails(itemId);
  413. refreshRow(itemId);
  414. }
  415. }
  416. /**
  417. * Sets details visiblity status of given item id.
  418. *
  419. * @param itemId
  420. * item id to set
  421. * @param visible
  422. * <code>true</code> if visible; <code>false</code> if not
  423. */
  424. public void setDetailsVisible(Object itemId, boolean visible) {
  425. if ((visible && openDetails.contains(itemId))
  426. || (!visible && !openDetails.contains(itemId))) {
  427. return;
  428. }
  429. if (visible) {
  430. openDetails.add(itemId);
  431. refreshRow(itemId);
  432. } else {
  433. openDetails.remove(itemId);
  434. destroyDetails(itemId);
  435. refreshRow(itemId);
  436. }
  437. }
  438. @Override
  439. public void generateData(Object itemId, Item item, JsonObject rowData) {
  440. // DetailComponentManager should not send anything if details
  441. // generator is the default null version.
  442. if (openDetails.contains(itemId)
  443. && !detailsGenerator.equals(DetailsGenerator.NULL)) {
  444. // Double check to be sure details component exists.
  445. createDetails(itemId);
  446. Component detailsComponent = itemIdToDetailsComponent
  447. .get(itemId);
  448. rowData.put(GridState.JSONKEY_DETAILS_VISIBLE,
  449. (detailsComponent != null
  450. ? detailsComponent.getConnectorId()
  451. : ""));
  452. }
  453. }
  454. @Override
  455. public void destroyData(Object itemId) {
  456. if (openDetails.contains(itemId)) {
  457. destroyDetails(itemId);
  458. }
  459. }
  460. /**
  461. * Sets a new details generator for row details.
  462. * <p>
  463. * The currently opened row details will be re-rendered.
  464. *
  465. * @param detailsGenerator
  466. * the details generator to set
  467. * @throws IllegalArgumentException
  468. * if detailsGenerator is <code>null</code>;
  469. */
  470. public void setDetailsGenerator(DetailsGenerator detailsGenerator)
  471. throws IllegalArgumentException {
  472. if (detailsGenerator == null) {
  473. throw new IllegalArgumentException(
  474. "Details generator may not be null");
  475. } else if (detailsGenerator == this.detailsGenerator) {
  476. return;
  477. }
  478. this.detailsGenerator = detailsGenerator;
  479. refreshDetails();
  480. }
  481. /**
  482. * Gets the current details generator for row details.
  483. *
  484. * @return the detailsGenerator the current details generator
  485. */
  486. public DetailsGenerator getDetailsGenerator() {
  487. return detailsGenerator;
  488. }
  489. /**
  490. * Checks whether details are visible for the given item.
  491. *
  492. * @param itemId
  493. * the id of the item for which to check details visibility
  494. * @return <code>true</code> if the details are visible
  495. */
  496. public boolean isDetailsVisible(Object itemId) {
  497. return openDetails.contains(itemId);
  498. }
  499. }
  500. /**
  501. * Custom field group that allows finding property types before an item has
  502. * been bound.
  503. */
  504. private final class CustomFieldGroup extends FieldGroup {
  505. public CustomFieldGroup() {
  506. setFieldFactory(EditorFieldFactory.get());
  507. }
  508. @Override
  509. protected Class<?> getPropertyType(Object propertyId)
  510. throws BindException {
  511. if (getItemDataSource() == null) {
  512. return datasource.getType(propertyId);
  513. } else {
  514. return super.getPropertyType(propertyId);
  515. }
  516. }
  517. @Override
  518. protected <T extends Field> T build(String caption, Class<?> dataType,
  519. Class<T> fieldType) throws BindException {
  520. T field = super.build(caption, dataType, fieldType);
  521. if (field instanceof CheckBox) {
  522. field.setCaption(null);
  523. }
  524. return field;
  525. }
  526. @Override
  527. protected void bindFields() {
  528. List<Field<?>> fields = new ArrayList<Field<?>>(getFields());
  529. Item itemDataSource = getItemDataSource();
  530. if (itemDataSource == null) {
  531. unbindFields(fields);
  532. } else {
  533. bindFields(fields, itemDataSource);
  534. }
  535. }
  536. private void unbindFields(List<Field<?>> fields) {
  537. for (Field<?> field : fields) {
  538. clearField(field);
  539. unbind(field);
  540. field.setParent(null);
  541. }
  542. }
  543. private void bindFields(List<Field<?>> fields, Item itemDataSource) {
  544. for (Field<?> field : fields) {
  545. if (itemDataSource
  546. .getItemProperty(getPropertyId(field)) != null) {
  547. bind(field, getPropertyId(field));
  548. }
  549. }
  550. }
  551. }
  552. /**
  553. * Field factory used by default in the editor.
  554. *
  555. * Aims to fields of suitable type and with suitable size for use in the
  556. * editor row.
  557. */
  558. @Deprecated
  559. public static class EditorFieldFactory
  560. extends DefaultFieldGroupFieldFactory {
  561. private static final EditorFieldFactory INSTANCE = new EditorFieldFactory();
  562. protected EditorFieldFactory() {
  563. }
  564. /**
  565. * Returns the singleton instance.
  566. *
  567. * @return the singleton instance
  568. */
  569. public static EditorFieldFactory get() {
  570. return INSTANCE;
  571. }
  572. @Override
  573. public <T extends Field> T createField(Class<?> type,
  574. Class<T> fieldType) {
  575. T f = super.createField(type, fieldType);
  576. if (f != null) {
  577. f.setWidth("100%");
  578. }
  579. return f;
  580. }
  581. @Override
  582. protected AbstractSelect createCompatibleSelect(
  583. Class<? extends AbstractSelect> fieldType) {
  584. if (anySelect(fieldType)) {
  585. return super.createCompatibleSelect(ComboBox.class);
  586. }
  587. return super.createCompatibleSelect(fieldType);
  588. }
  589. @Override
  590. protected void populateWithEnumData(AbstractSelect select,
  591. Class<? extends Enum> enumClass) {
  592. // Use enums directly and the EnumToStringConverter to be consistent
  593. // with what is shown in the Grid
  594. @SuppressWarnings("unchecked")
  595. EnumSet<?> enumSet = EnumSet.allOf(enumClass);
  596. for (Object r : enumSet) {
  597. select.addItem(r);
  598. }
  599. }
  600. }
  601. /**
  602. * Error handler for the editor.
  603. */
  604. @Deprecated
  605. public interface EditorErrorHandler extends Serializable {
  606. /**
  607. * Called when an exception occurs while the editor row is being saved.
  608. *
  609. * @param event
  610. * An event providing more information about the error
  611. */
  612. void commitError(CommitErrorEvent event);
  613. }
  614. /**
  615. * ContextClickEvent for the Grid Component.
  616. *
  617. * @since 7.6
  618. */
  619. @Deprecated
  620. public static class GridContextClickEvent extends ContextClickEvent {
  621. private final Object itemId;
  622. private final int rowIndex;
  623. private final Object propertyId;
  624. private final Section section;
  625. public GridContextClickEvent(Grid source,
  626. MouseEventDetails mouseEventDetails, Section section,
  627. int rowIndex, Object itemId, Object propertyId) {
  628. super(source, mouseEventDetails);
  629. this.itemId = itemId;
  630. this.propertyId = propertyId;
  631. this.section = section;
  632. this.rowIndex = rowIndex;
  633. }
  634. /**
  635. * Returns the item id of context clicked row.
  636. *
  637. * @return item id of clicked row; <code>null</code> if header or footer
  638. */
  639. public Object getItemId() {
  640. return itemId;
  641. }
  642. /**
  643. * Returns property id of clicked column.
  644. *
  645. * @return property id
  646. */
  647. public Object getPropertyId() {
  648. return propertyId;
  649. }
  650. /**
  651. * Return the clicked section of Grid.
  652. *
  653. * @return section of grid
  654. */
  655. public Section getSection() {
  656. return section;
  657. }
  658. /**
  659. * Returns the clicked row index relative to Grid section. In the body
  660. * of the Grid the index is the item index in the Container. Header and
  661. * Footer rows for index can be fetched with
  662. * {@link Grid#getHeaderRow(int)} and {@link Grid#getFooterRow(int)}.
  663. *
  664. * @return row index in section
  665. */
  666. public int getRowIndex() {
  667. return rowIndex;
  668. }
  669. @Override
  670. public Grid getComponent() {
  671. return (Grid) super.getComponent();
  672. }
  673. }
  674. /**
  675. * An event which is fired when saving the editor fails.
  676. */
  677. @Deprecated
  678. public static class CommitErrorEvent extends Component.Event {
  679. private CommitException cause;
  680. private Set<Column> errorColumns = new HashSet<Column>();
  681. private String userErrorMessage;
  682. public CommitErrorEvent(Grid grid, CommitException cause) {
  683. super(grid);
  684. this.cause = cause;
  685. userErrorMessage = cause.getLocalizedMessage();
  686. }
  687. /**
  688. * Retrieves the cause of the failure.
  689. *
  690. * @return the cause of the failure
  691. */
  692. public CommitException getCause() {
  693. return cause;
  694. }
  695. @Override
  696. public Grid getComponent() {
  697. return (Grid) super.getComponent();
  698. }
  699. /**
  700. * Checks if validation exceptions caused this error.
  701. *
  702. * @return true if the problem was caused by a validation error
  703. */
  704. public boolean isValidationFailure() {
  705. return cause.getCause() instanceof InvalidValueException;
  706. }
  707. /**
  708. * Marks that an error indicator should be shown for the editor of a
  709. * column.
  710. *
  711. * @param column
  712. * the column to show an error for
  713. */
  714. public void addErrorColumn(Column column) {
  715. errorColumns.add(column);
  716. }
  717. /**
  718. * Gets all the columns that have been marked as erroneous.
  719. *
  720. * @return an umodifiable collection of erroneous columns
  721. */
  722. public Collection<Column> getErrorColumns() {
  723. return Collections.unmodifiableCollection(errorColumns);
  724. }
  725. /**
  726. * Gets the error message to show to the user.
  727. *
  728. * @return error message to show
  729. */
  730. public String getUserErrorMessage() {
  731. return userErrorMessage;
  732. }
  733. /**
  734. * Sets the error message to show to the user.
  735. *
  736. * @param userErrorMessage
  737. * the user error message to set
  738. */
  739. public void setUserErrorMessage(String userErrorMessage) {
  740. this.userErrorMessage = userErrorMessage;
  741. }
  742. }
  743. /**
  744. * An event listener for column reorder events in the Grid.
  745. *
  746. * @since 7.5.0
  747. */
  748. @Deprecated
  749. public interface ColumnReorderListener extends Serializable {
  750. /**
  751. * Called when the columns of the grid have been reordered.
  752. *
  753. * @param event
  754. * An event providing more information
  755. */
  756. void columnReorder(ColumnReorderEvent event);
  757. }
  758. /**
  759. * An event that is fired when the columns are reordered.
  760. *
  761. * @since 7.5.0
  762. */
  763. @Deprecated
  764. public static class ColumnReorderEvent extends Component.Event {
  765. private final boolean userOriginated;
  766. /**
  767. *
  768. * @param source
  769. * the grid where the event originated from
  770. * @param userOriginated
  771. * <code>true</code> if event is a result of user
  772. * interaction, <code>false</code> if from API call
  773. */
  774. public ColumnReorderEvent(Grid source, boolean userOriginated) {
  775. super(source);
  776. this.userOriginated = userOriginated;
  777. }
  778. /**
  779. * Returns <code>true</code> if the column reorder was done by the user,
  780. * <code>false</code> if not and it was triggered by server side code.
  781. *
  782. * @return <code>true</code> if event is a result of user interaction
  783. */
  784. public boolean isUserOriginated() {
  785. return userOriginated;
  786. }
  787. }
  788. /**
  789. * An event listener for column resize events in the Grid.
  790. *
  791. * @since 7.6
  792. */
  793. @Deprecated
  794. public interface ColumnResizeListener extends Serializable {
  795. /**
  796. * Called when the columns of the grid have been resized.
  797. *
  798. * @param event
  799. * An event providing more information
  800. */
  801. void columnResize(ColumnResizeEvent event);
  802. }
  803. /**
  804. * An event that is fired when a column is resized, either programmatically
  805. * or by the user.
  806. *
  807. * @since 7.6
  808. */
  809. @Deprecated
  810. public static class ColumnResizeEvent extends Component.Event {
  811. private final Column column;
  812. private final boolean userOriginated;
  813. /**
  814. *
  815. * @param source
  816. * the grid where the event originated from
  817. * @param userOriginated
  818. * <code>true</code> if event is a result of user
  819. * interaction, <code>false</code> if from API call
  820. */
  821. public ColumnResizeEvent(Grid source, Column column,
  822. boolean userOriginated) {
  823. super(source);
  824. this.column = column;
  825. this.userOriginated = userOriginated;
  826. }
  827. /**
  828. * Returns the column that was resized.
  829. *
  830. * @return the resized column.
  831. */
  832. public Column getColumn() {
  833. return column;
  834. }
  835. /**
  836. * Returns <code>true</code> if the column resize was done by the user,
  837. * <code>false</code> if not and it was triggered by server side code.
  838. *
  839. * @return <code>true</code> if event is a result of user interaction
  840. */
  841. public boolean isUserOriginated() {
  842. return userOriginated;
  843. }
  844. }
  845. /**
  846. * Interface for an editor event listener.
  847. */
  848. @Deprecated
  849. public interface EditorListener extends Serializable {
  850. public static final Method EDITOR_OPEN_METHOD = ReflectTools.findMethod(
  851. EditorListener.class, "editorOpened", EditorOpenEvent.class);
  852. public static final Method EDITOR_MOVE_METHOD = ReflectTools.findMethod(
  853. EditorListener.class, "editorMoved", EditorMoveEvent.class);
  854. public static final Method EDITOR_CLOSE_METHOD = ReflectTools
  855. .findMethod(EditorListener.class, "editorClosed",
  856. EditorCloseEvent.class);
  857. /**
  858. * Called when an editor is opened.
  859. *
  860. * @param e
  861. * an editor open event object
  862. */
  863. public void editorOpened(EditorOpenEvent e);
  864. /**
  865. * Called when an editor is reopened without closing it first.
  866. *
  867. * @param e
  868. * an editor move event object
  869. */
  870. public void editorMoved(EditorMoveEvent e);
  871. /**
  872. * Called when an editor is closed.
  873. *
  874. * @param e
  875. * an editor close event object
  876. */
  877. public void editorClosed(EditorCloseEvent e);
  878. }
  879. /**
  880. * Base class for editor related events.
  881. */
  882. @Deprecated
  883. public abstract static class EditorEvent extends Component.Event {
  884. private Object itemID;
  885. protected EditorEvent(Grid source, Object itemID) {
  886. super(source);
  887. this.itemID = itemID;
  888. }
  889. /**
  890. * Get the item (row) for which this editor was opened.
  891. */
  892. public Object getItem() {
  893. return itemID;
  894. }
  895. }
  896. /**
  897. * This event gets fired when an editor is opened.
  898. */
  899. @Deprecated
  900. public static class EditorOpenEvent extends EditorEvent {
  901. public EditorOpenEvent(Grid source, Object itemID) {
  902. super(source, itemID);
  903. }
  904. }
  905. /**
  906. * This event gets fired when an editor is opened while another row is being
  907. * edited (i.e. editor focus moves elsewhere)
  908. */
  909. @Deprecated
  910. public static class EditorMoveEvent extends EditorEvent {
  911. public EditorMoveEvent(Grid source, Object itemID) {
  912. super(source, itemID);
  913. }
  914. }
  915. /**
  916. * This event gets fired when an editor is dismissed or closed by other
  917. * means.
  918. */
  919. @Deprecated
  920. public static class EditorCloseEvent extends EditorEvent {
  921. public EditorCloseEvent(Grid source, Object itemID) {
  922. super(source, itemID);
  923. }
  924. }
  925. /**
  926. * Default error handler for the editor.
  927. *
  928. */
  929. @Deprecated
  930. public class DefaultEditorErrorHandler implements EditorErrorHandler {
  931. @Override
  932. public void commitError(CommitErrorEvent event) {
  933. Map<Field<?>, InvalidValueException> invalidFields = event
  934. .getCause().getInvalidFields();
  935. if (!invalidFields.isEmpty()) {
  936. Object firstErrorPropertyId = null;
  937. Field<?> firstErrorField = null;
  938. FieldGroup fieldGroup = event.getCause().getFieldGroup();
  939. for (Column column : getColumns()) {
  940. Object propertyId = column.getPropertyId();
  941. Field<?> field = fieldGroup.getField(propertyId);
  942. if (invalidFields.keySet().contains(field)) {
  943. event.addErrorColumn(column);
  944. if (firstErrorPropertyId == null) {
  945. firstErrorPropertyId = propertyId;
  946. firstErrorField = field;
  947. }
  948. }
  949. }
  950. /*
  951. * Validation error, show first failure as
  952. * "<Column header>: <message>"
  953. */
  954. String caption = getColumn(firstErrorPropertyId)
  955. .getHeaderCaption();
  956. String message = invalidFields.get(firstErrorField)
  957. .getLocalizedMessage();
  958. event.setUserErrorMessage(caption + ": " + message);
  959. } else {
  960. com.vaadin.server.ErrorEvent.findErrorHandler(Grid.this).error(
  961. new ConnectorErrorEvent(Grid.this, event.getCause()));
  962. }
  963. }
  964. }
  965. /**
  966. * Selection modes representing built-in {@link SelectionModel
  967. * SelectionModels} that come bundled with {@link Grid}.
  968. * <p>
  969. * Passing one of these enums into
  970. * {@link Grid#setSelectionMode(SelectionMode)} is equivalent to calling
  971. * {@link Grid#setSelectionModel(SelectionModel)} with one of the built-in
  972. * implementations of {@link SelectionModel}.
  973. *
  974. * @see Grid#setSelectionMode(SelectionMode)
  975. * @see Grid#setSelectionModel(SelectionModel)
  976. */
  977. @Deprecated
  978. public enum SelectionMode {
  979. /** A SelectionMode that maps to {@link SingleSelectionModel}. */
  980. SINGLE {
  981. @Override
  982. protected SelectionModel createModel() {
  983. return new SingleSelectionModel();
  984. }
  985. },
  986. /** A SelectionMode that maps to {@link MultiSelectionModel}. */
  987. MULTI {
  988. @Override
  989. protected SelectionModel createModel() {
  990. return new MultiSelectionModel();
  991. }
  992. },
  993. /** A SelectionMode that maps to {@link NoSelectionModel}. */
  994. NONE {
  995. @Override
  996. protected SelectionModel createModel() {
  997. return new NoSelectionModel();
  998. }
  999. };
  1000. protected abstract SelectionModel createModel();
  1001. }
  1002. /**
  1003. * The server-side interface that controls Grid's selection state.
  1004. * SelectionModel should extend {@link AbstractGridExtension}.
  1005. */
  1006. @Deprecated
  1007. public interface SelectionModel extends Serializable, Extension {
  1008. /**
  1009. * Interface implemented by selection models which support disabling
  1010. * client side selection while still allowing programmatic selection on
  1011. * the server.
  1012. *
  1013. * @since 7.7.7
  1014. */
  1015. @Deprecated
  1016. public interface HasUserSelectionAllowed extends SelectionModel {
  1017. /**
  1018. * Checks if the user is allowed to change the selection.
  1019. *
  1020. * @return <code>true</code> if the user is allowed to change the
  1021. * selection, <code>false</code> otherwise
  1022. */
  1023. public boolean isUserSelectionAllowed();
  1024. /**
  1025. * Sets whether the user is allowed to change the selection.
  1026. *
  1027. * @param userSelectionAllowed
  1028. * <code>true</code> if the user is allowed to change the
  1029. * selection, <code>false</code> otherwise
  1030. */
  1031. public void setUserSelectionAllowed(boolean userSelectionAllowed);
  1032. }
  1033. /**
  1034. * Checks whether an item is selected or not.
  1035. *
  1036. * @param itemId
  1037. * the item id to check for
  1038. * @return <code>true</code> if the item is selected
  1039. */
  1040. boolean isSelected(Object itemId);
  1041. /**
  1042. * Returns a collection of all the currently selected itemIds.
  1043. *
  1044. * @return a collection of all the currently selected itemIds
  1045. */
  1046. Collection<Object> getSelectedRows();
  1047. /**
  1048. * Injects the current {@link Grid} instance into the SelectionModel.
  1049. * This method should usually call the extend method of
  1050. * {@link AbstractExtension}.
  1051. * <p>
  1052. * <em>Note:</em> This method should not be called manually.
  1053. *
  1054. * @param grid
  1055. * the Grid in which the SelectionModel currently is, or
  1056. * <code>null</code> when a selection model is being detached
  1057. * from a Grid.
  1058. */
  1059. void setGrid(Grid grid);
  1060. /**
  1061. * Resets the SelectiomModel to an initial state.
  1062. * <p>
  1063. * Most often this means that the selection state is cleared, but
  1064. * implementations are free to interpret the "initial state" as they
  1065. * wish. Some, for example, may want to keep the first selected item as
  1066. * selected.
  1067. */
  1068. void reset();
  1069. /**
  1070. * A SelectionModel that supports multiple selections to be made.
  1071. * <p>
  1072. * This interface has a contract of having the same behavior, no matter
  1073. * how the selection model is interacted with. In other words, if
  1074. * something is forbidden to do in e.g. the user interface, it must also
  1075. * be forbidden to do in the server-side and client-side APIs.
  1076. */
  1077. @Deprecated
  1078. public interface Multi extends SelectionModel {
  1079. /**
  1080. * Marks items as selected.
  1081. * <p>
  1082. * This method does not clear any previous selection state, only
  1083. * adds to it.
  1084. *
  1085. * @param itemIds
  1086. * the itemId(s) to mark as selected
  1087. * @return <code>true</code> if the selection state changed.
  1088. * <code>false</code> if all the given itemIds already were
  1089. * selected
  1090. * @throws IllegalArgumentException
  1091. * if the <code>itemIds</code> varargs array is
  1092. * <code>null</code> or given itemIds don't exist in the
  1093. * container of Grid
  1094. * @see #deselect(Object...)
  1095. */
  1096. boolean select(Object... itemIds) throws IllegalArgumentException;
  1097. /**
  1098. * Marks items as selected.
  1099. * <p>
  1100. * This method does not clear any previous selection state, only
  1101. * adds to it.
  1102. *
  1103. * @param itemIds
  1104. * the itemIds to mark as selected
  1105. * @return <code>true</code> if the selection state changed.
  1106. * <code>false</code> if all the given itemIds already were
  1107. * selected
  1108. * @throws IllegalArgumentException
  1109. * if <code>itemIds</code> is <code>null</code> or given
  1110. * itemIds don't exist in the container of Grid
  1111. * @see #deselect(Collection)
  1112. */
  1113. boolean select(Collection<?> itemIds)
  1114. throws IllegalArgumentException;
  1115. /**
  1116. * Marks items as deselected.
  1117. *
  1118. * @param itemIds
  1119. * the itemId(s) to remove from being selected
  1120. * @return <code>true</code> if the selection state changed.
  1121. * <code>false</code> if none the given itemIds were
  1122. * selected previously
  1123. * @throws IllegalArgumentException
  1124. * if the <code>itemIds</code> varargs array is
  1125. * <code>null</code>
  1126. * @see #select(Object...)
  1127. */
  1128. boolean deselect(Object... itemIds) throws IllegalArgumentException;
  1129. /**
  1130. * Marks items as deselected.
  1131. *
  1132. * @param itemIds
  1133. * the itemId(s) to remove from being selected
  1134. * @return <code>true</code> if the selection state changed.
  1135. * <code>false</code> if none the given itemIds were
  1136. * selected previously
  1137. * @throws IllegalArgumentException
  1138. * if <code>itemIds</code> is <code>null</code>
  1139. * @see #select(Collection)
  1140. */
  1141. boolean deselect(Collection<?> itemIds)
  1142. throws IllegalArgumentException;
  1143. /**
  1144. * Marks all the items in the current Container as selected.
  1145. *
  1146. * @return <code>true</code> if some items were previously not
  1147. * selected
  1148. * @see #deselectAll()
  1149. */
  1150. boolean selectAll();
  1151. /**
  1152. * Marks all the items in the current Container as deselected.
  1153. *
  1154. * @return <code>true</code> if some items were previously selected
  1155. * @see #selectAll()
  1156. */
  1157. boolean deselectAll();
  1158. /**
  1159. * Marks items as selected while deselecting all items not in the
  1160. * given Collection.
  1161. *
  1162. * @param itemIds
  1163. * the itemIds to mark as selected
  1164. * @return <code>true</code> if the selection state changed.
  1165. * <code>false</code> if all the given itemIds already were
  1166. * selected
  1167. * @throws IllegalArgumentException
  1168. * if <code>itemIds</code> is <code>null</code> or given
  1169. * itemIds don't exist in the container of Grid
  1170. */
  1171. boolean setSelected(Collection<?> itemIds)
  1172. throws IllegalArgumentException;
  1173. /**
  1174. * Marks items as selected while deselecting all items not in the
  1175. * varargs array.
  1176. *
  1177. * @param itemIds
  1178. * the itemIds to mark as selected
  1179. * @return <code>true</code> if the selection state changed.
  1180. * <code>false</code> if all the given itemIds already were
  1181. * selected
  1182. * @throws IllegalArgumentException
  1183. * if the <code>itemIds</code> varargs array is
  1184. * <code>null</code> or given itemIds don't exist in the
  1185. * container of Grid
  1186. */
  1187. boolean setSelected(Object... itemIds)
  1188. throws IllegalArgumentException;
  1189. }
  1190. /**
  1191. * A SelectionModel that supports for only single rows to be selected at
  1192. * a time.
  1193. * <p>
  1194. * This interface has a contract of having the same behavior, no matter
  1195. * how the selection model is interacted with. In other words, if
  1196. * something is forbidden to do in e.g. the user interface, it must also
  1197. * be forbidden to do in the server-side and client-side APIs.
  1198. */
  1199. @Deprecated
  1200. public interface Single extends SelectionModel {
  1201. /**
  1202. * Marks an item as selected.
  1203. *
  1204. * @param itemId
  1205. * the itemId to mark as selected; <code>null</code> for
  1206. * deselect
  1207. * @return <code>true</code> if the selection state changed.
  1208. * <code>false</code> if the itemId already was selected
  1209. * @throws IllegalStateException
  1210. * if the selection was illegal. One such reason might
  1211. * be that the given id was null, indicating a deselect,
  1212. * but implementation doesn't allow deselecting.
  1213. * re-selecting something
  1214. * @throws IllegalArgumentException
  1215. * if given itemId does not exist in the container of
  1216. * Grid
  1217. */
  1218. boolean select(Object itemId)
  1219. throws IllegalStateException, IllegalArgumentException;
  1220. /**
  1221. * Gets the item id of the currently selected item.
  1222. *
  1223. * @return the item id of the currently selected item, or
  1224. * <code>null</code> if nothing is selected
  1225. */
  1226. Object getSelectedRow();
  1227. /**
  1228. * Sets whether it's allowed to deselect the selected row through
  1229. * the UI. Deselection is allowed by default.
  1230. *
  1231. * @param deselectAllowed
  1232. * <code>true</code> if the selected row can be
  1233. * deselected without selecting another row instead;
  1234. * otherwise <code>false</code>.
  1235. */
  1236. public void setDeselectAllowed(boolean deselectAllowed);
  1237. /**
  1238. * Sets whether it's allowed to deselect the selected row through
  1239. * the UI.
  1240. *
  1241. * @return <code>true</code> if deselection is allowed; otherwise
  1242. * <code>false</code>
  1243. */
  1244. public boolean isDeselectAllowed();
  1245. }
  1246. /**
  1247. * A SelectionModel that does not allow for rows to be selected.
  1248. * <p>
  1249. * This interface has a contract of having the same behavior, no matter
  1250. * how the selection model is interacted with. In other words, if the
  1251. * developer is unable to select something programmatically, it is not
  1252. * allowed for the end-user to select anything, either.
  1253. */
  1254. @Deprecated
  1255. public interface None extends SelectionModel {
  1256. /**
  1257. * {@inheritDoc}
  1258. *
  1259. * @return always <code>false</code>.
  1260. */
  1261. @Override
  1262. public boolean isSelected(Object itemId);
  1263. /**
  1264. * {@inheritDoc}
  1265. *
  1266. * @return always an empty collection.
  1267. */
  1268. @Override
  1269. public Collection<Object> getSelectedRows();
  1270. }
  1271. }
  1272. /**
  1273. * A base class for SelectionModels that contains some of the logic that is
  1274. * reusable.
  1275. */
  1276. @Deprecated
  1277. public abstract static class AbstractSelectionModel extends
  1278. AbstractGridExtension implements SelectionModel, DataGenerator {
  1279. protected final LinkedHashSet<Object> selection = new LinkedHashSet<Object>();
  1280. @Override
  1281. public boolean isSelected(final Object itemId) {
  1282. return selection.contains(itemId);
  1283. }
  1284. @Override
  1285. public Collection<Object> getSelectedRows() {
  1286. return new ArrayList<Object>(selection);
  1287. }
  1288. @Override
  1289. public void setGrid(final Grid grid) {
  1290. if (grid != null) {
  1291. extend(grid);
  1292. }
  1293. }
  1294. /**
  1295. * Sanity check for existence of item id.
  1296. *
  1297. * @param itemId
  1298. * item id to be selected / deselected
  1299. *
  1300. * @throws IllegalArgumentException
  1301. * if item Id doesn't exist in the container of Grid
  1302. */
  1303. protected void checkItemIdExists(Object itemId)
  1304. throws IllegalArgumentException {
  1305. if (!getParentGrid().getContainerDataSource().containsId(itemId)) {
  1306. throw new IllegalArgumentException("Given item id (" + itemId
  1307. + ") does not exist in the container");
  1308. }
  1309. }
  1310. /**
  1311. * Sanity check for existence of item ids in given collection.
  1312. *
  1313. * @param itemIds
  1314. * item id collection to be selected / deselected
  1315. *
  1316. * @throws IllegalArgumentException
  1317. * if at least one item id doesn't exist in the container of
  1318. * Grid
  1319. */
  1320. protected void checkItemIdsExist(Collection<?> itemIds)
  1321. throws IllegalArgumentException {
  1322. for (Object itemId : itemIds) {
  1323. checkItemIdExists(itemId);
  1324. }
  1325. }
  1326. /**
  1327. * Fires a {@link SelectionEvent} to all the {@link SelectionListener
  1328. * SelectionListeners} currently added to the Grid in which this
  1329. * SelectionModel is.
  1330. * <p>
  1331. * Note that this is only a helper method, and routes the call all the
  1332. * way to Grid. A {@link SelectionModel} is not a
  1333. * {@link SelectionNotifier}
  1334. *
  1335. * @param oldSelection
  1336. * the complete {@link Collection} of the itemIds that were
  1337. * selected <em>before</em> this event happened
  1338. * @param newSelection
  1339. * the complete {@link Collection} of the itemIds that are
  1340. * selected <em>after</em> this event happened
  1341. */
  1342. protected void fireSelectionEvent(final Collection<Object> oldSelection,
  1343. final Collection<Object> newSelection) {
  1344. getParentGrid().fireSelectionEvent(oldSelection, newSelection);
  1345. }
  1346. @Override
  1347. public void generateData(Object itemId, Item item, JsonObject rowData) {
  1348. if (isSelected(itemId)) {
  1349. rowData.put(GridState.JSONKEY_SELECTED, true);
  1350. }
  1351. }
  1352. @Override
  1353. public void destroyData(Object itemId) {
  1354. // NO-OP
  1355. }
  1356. @Override
  1357. protected Object getItemId(String rowKey) {
  1358. return rowKey != null ? super.getItemId(rowKey) : null;
  1359. }
  1360. }
  1361. /**
  1362. * A default implementation of a
  1363. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Single
  1364. * SelectionModel.Single}.
  1365. */
  1366. @Deprecated
  1367. public static class SingleSelectionModel extends AbstractSelectionModel
  1368. implements SelectionModel.Single, HasUserSelectionAllowed {
  1369. @Override
  1370. protected void extend(AbstractClientConnector target) {
  1371. super.extend(target);
  1372. registerRpc(new SingleSelectionModelServerRpc() {
  1373. @Override
  1374. public void select(String rowKey) {
  1375. if (!isUserSelectionAllowed()) {
  1376. throw new IllegalStateException(
  1377. "Client tried to select '" + rowKey
  1378. + "' although user selection is disallowed");
  1379. }
  1380. SingleSelectionModel.this.select(getItemId(rowKey), false);
  1381. }
  1382. });
  1383. }
  1384. @Override
  1385. public boolean select(final Object itemId) {
  1386. return select(itemId, true);
  1387. }
  1388. protected boolean select(final Object itemId, boolean refresh) {
  1389. if (itemId == null) {
  1390. return deselect(getSelectedRow());
  1391. }
  1392. checkItemIdExists(itemId);
  1393. final Object selectedRow = getSelectedRow();
  1394. final boolean modified = selection.add(itemId);
  1395. if (modified) {
  1396. final Collection<Object> deselected;
  1397. if (selectedRow != null) {
  1398. deselectInternal(selectedRow, false, true);
  1399. deselected = Collections.singleton(selectedRow);
  1400. } else {
  1401. deselected = Collections.emptySet();
  1402. }
  1403. fireSelectionEvent(deselected, selection);
  1404. }
  1405. if (refresh) {
  1406. refreshRow(itemId);
  1407. }
  1408. return modified;
  1409. }
  1410. private boolean deselect(final Object itemId) {
  1411. return deselectInternal(itemId, true, true);
  1412. }
  1413. private boolean deselectInternal(final Object itemId,
  1414. boolean fireEventIfNeeded, boolean refresh) {
  1415. final boolean modified = selection.remove(itemId);
  1416. if (modified) {
  1417. if (refresh) {
  1418. refreshRow(itemId);
  1419. }
  1420. if (fireEventIfNeeded) {
  1421. fireSelectionEvent(Collections.singleton(itemId),
  1422. Collections.emptySet());
  1423. }
  1424. }
  1425. return modified;
  1426. }
  1427. @Override
  1428. public Object getSelectedRow() {
  1429. if (selection.isEmpty()) {
  1430. return null;
  1431. } else {
  1432. return selection.iterator().next();
  1433. }
  1434. }
  1435. /**
  1436. * Resets the selection state.
  1437. * <p>
  1438. * If an item is selected, it will become deselected.
  1439. */
  1440. @Override
  1441. public void reset() {
  1442. deselect(getSelectedRow());
  1443. }
  1444. @Override
  1445. public void setDeselectAllowed(boolean deselectAllowed) {
  1446. getState().deselectAllowed = deselectAllowed;
  1447. }
  1448. @Override
  1449. public boolean isDeselectAllowed() {
  1450. return getState().deselectAllowed;
  1451. }
  1452. @Override
  1453. protected SingleSelectionModelState getState() {
  1454. return (SingleSelectionModelState) super.getState();
  1455. }
  1456. @Override
  1457. protected SingleSelectionModelState getState(boolean markAsDirty) {
  1458. return (SingleSelectionModelState) super.getState(markAsDirty);
  1459. }
  1460. @Override
  1461. public boolean isUserSelectionAllowed() {
  1462. return getState(false).userSelectionAllowed;
  1463. }
  1464. @Override
  1465. public void setUserSelectionAllowed(boolean userSelectionAllowed) {
  1466. getState().userSelectionAllowed = userSelectionAllowed;
  1467. }
  1468. }
  1469. /**
  1470. * A default implementation for a
  1471. * {@link com.vaadin.v7.ui.Grid.SelectionModel.None SelectionModel.None}.
  1472. */
  1473. @Deprecated
  1474. public static class NoSelectionModel extends AbstractSelectionModel
  1475. implements SelectionModel.None {
  1476. @Override
  1477. public boolean isSelected(final Object itemId) {
  1478. return false;
  1479. }
  1480. @Override
  1481. public Collection<Object> getSelectedRows() {
  1482. return Collections.emptyList();
  1483. }
  1484. /**
  1485. * Semantically resets the selection model.
  1486. * <p>
  1487. * Effectively a no-op.
  1488. */
  1489. @Override
  1490. public void reset() {
  1491. // NOOP
  1492. }
  1493. }
  1494. /**
  1495. * A default implementation of a
  1496. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Multi SelectionModel.Multi}.
  1497. */
  1498. @Deprecated
  1499. public static class MultiSelectionModel extends AbstractSelectionModel
  1500. implements SelectionModel.Multi,
  1501. SelectionModel.HasUserSelectionAllowed {
  1502. /**
  1503. * The default selection size limit.
  1504. *
  1505. * @see #setSelectionLimit(int)
  1506. */
  1507. public static final int DEFAULT_MAX_SELECTIONS = 1000;
  1508. private int selectionLimit = DEFAULT_MAX_SELECTIONS;
  1509. @Override
  1510. protected void extend(AbstractClientConnector target) {
  1511. super.extend(target);
  1512. registerRpc(new MultiSelectionModelServerRpc() {
  1513. @Override
  1514. public void select(List<String> rowKeys) {
  1515. if (!isUserSelectionAllowed()) {
  1516. throw new IllegalStateException(
  1517. "Client tried to select '" + rowKeys
  1518. + "' although user selection is disallowed");
  1519. }
  1520. List<Object> items = new ArrayList<Object>();
  1521. for (String rowKey : rowKeys) {
  1522. items.add(getItemId(rowKey));
  1523. }
  1524. MultiSelectionModel.this.select(items, false);
  1525. }
  1526. @Override
  1527. public void deselect(List<String> rowKeys) {
  1528. if (!isUserSelectionAllowed()) {
  1529. throw new IllegalStateException(
  1530. "Client tried to deselect '" + rowKeys
  1531. + "' although user selection is disallowed");
  1532. }
  1533. List<Object> items = new ArrayList<Object>();
  1534. for (String rowKey : rowKeys) {
  1535. items.add(getItemId(rowKey));
  1536. }
  1537. MultiSelectionModel.this.deselect(items, false);
  1538. }
  1539. @Override
  1540. public void selectAll() {
  1541. if (!isUserSelectionAllowed()) {
  1542. throw new IllegalStateException(
  1543. "Client tried to select all although user selection is disallowed");
  1544. }
  1545. MultiSelectionModel.this.selectAll(false);
  1546. }
  1547. @Override
  1548. public void deselectAll() {
  1549. if (!isUserSelectionAllowed()) {
  1550. throw new IllegalStateException(
  1551. "Client tried to deselect all although user selection is disallowed");
  1552. }
  1553. MultiSelectionModel.this.deselectAll(false);
  1554. }
  1555. });
  1556. }
  1557. @Override
  1558. public boolean select(final Object... itemIds)
  1559. throws IllegalArgumentException {
  1560. if (itemIds != null) {
  1561. // select will fire the event
  1562. return select(Arrays.asList(itemIds));
  1563. } else {
  1564. throw new IllegalArgumentException(
  1565. "Vararg array of itemIds may not be null");
  1566. }
  1567. }
  1568. /**
  1569. * {@inheritDoc}
  1570. * <p>
  1571. * All items might not be selected if the limit set using
  1572. * {@link #setSelectionLimit(int)} is exceeded.
  1573. */
  1574. @Override
  1575. public boolean select(final Collection<?> itemIds)
  1576. throws IllegalArgumentException {
  1577. return select(itemIds, true);
  1578. }
  1579. protected boolean select(final Collection<?> itemIds, boolean refresh) {
  1580. if (itemIds == null) {
  1581. throw new IllegalArgumentException("itemIds may not be null");
  1582. }
  1583. // Sanity check
  1584. checkItemIdsExist(itemIds);
  1585. final boolean selectionWillChange = !selection.containsAll(itemIds)
  1586. && selection.size() < selectionLimit;
  1587. if (selectionWillChange) {
  1588. final HashSet<Object> oldSelection = new HashSet<Object>(
  1589. selection);
  1590. if (selection.size() + itemIds.size() >= selectionLimit) {
  1591. // Add one at a time if there's a risk of overflow
  1592. for (Object id : itemIds) {
  1593. if (selection.size() >= selectionLimit) {
  1594. break;
  1595. }
  1596. selection.add(id);
  1597. }
  1598. } else {
  1599. selection.addAll(itemIds);
  1600. }
  1601. fireSelectionEvent(oldSelection, selection);
  1602. }
  1603. updateAllSelectedState();
  1604. if (refresh) {
  1605. for (Object itemId : itemIds) {
  1606. refreshRow(itemId);
  1607. }
  1608. }
  1609. return selectionWillChange;
  1610. }
  1611. /**
  1612. * Sets the maximum number of rows that can be selected at once. This is
  1613. * a mechanism to prevent exhausting server memory in situations where
  1614. * users select lots of rows. If the limit is reached, newly selected
  1615. * rows will not become recorded.
  1616. * <p>
  1617. * Old selections are not discarded if the current number of selected
  1618. * row exceeds the new limit.
  1619. * <p>
  1620. * The default limit is {@value #DEFAULT_MAX_SELECTIONS} rows.
  1621. *
  1622. * @param selectionLimit
  1623. * the non-negative selection limit to set
  1624. * @throws IllegalArgumentException
  1625. * if the limit is negative
  1626. */
  1627. public void setSelectionLimit(int selectionLimit) {
  1628. if (selectionLimit < 0) {
  1629. throw new IllegalArgumentException(
  1630. "The selection limit must be non-negative");
  1631. }
  1632. this.selectionLimit = selectionLimit;
  1633. }
  1634. /**
  1635. * Gets the selection limit.
  1636. *
  1637. * @see #setSelectionLimit(int)
  1638. *
  1639. * @return the selection limit
  1640. */
  1641. public int getSelectionLimit() {
  1642. return selectionLimit;
  1643. }
  1644. @Override
  1645. public boolean deselect(final Object... itemIds)
  1646. throws IllegalArgumentException {
  1647. if (itemIds != null) {
  1648. // deselect will fire the event
  1649. return deselect(Arrays.asList(itemIds));
  1650. } else {
  1651. throw new IllegalArgumentException(
  1652. "Vararg array of itemIds may not be null");
  1653. }
  1654. }
  1655. @Override
  1656. public boolean deselect(final Collection<?> itemIds)
  1657. throws IllegalArgumentException {
  1658. return deselect(itemIds, true);
  1659. }
  1660. protected boolean deselect(final Collection<?> itemIds,
  1661. boolean refresh) {
  1662. if (itemIds == null) {
  1663. throw new IllegalArgumentException("itemIds may not be null");
  1664. }
  1665. final boolean hasCommonElements = !Collections.disjoint(itemIds,
  1666. selection);
  1667. if (hasCommonElements) {
  1668. final HashSet<Object> oldSelection = new HashSet<Object>(
  1669. selection);
  1670. selection.removeAll(itemIds);
  1671. fireSelectionEvent(oldSelection, selection);
  1672. }
  1673. updateAllSelectedState();
  1674. if (refresh) {
  1675. for (Object itemId : itemIds) {
  1676. refreshRow(itemId);
  1677. }
  1678. }
  1679. return hasCommonElements;
  1680. }
  1681. @Override
  1682. public boolean selectAll() {
  1683. return selectAll(true);
  1684. }
  1685. protected boolean selectAll(boolean refresh) {
  1686. // select will fire the event
  1687. final Indexed container = getParentGrid().getContainerDataSource();
  1688. if (container != null) {
  1689. return select(container.getItemIds(), refresh);
  1690. } else if (selection.isEmpty()) {
  1691. return false;
  1692. } else {
  1693. /*
  1694. * this should never happen (no container but has a selection),
  1695. * but I guess the only theoretically correct course of
  1696. * action...
  1697. */
  1698. return deselectAll(false);
  1699. }
  1700. }
  1701. @Override
  1702. public boolean deselectAll() {
  1703. return deselectAll(true);
  1704. }
  1705. protected boolean deselectAll(boolean refresh) {
  1706. // deselect will fire the event
  1707. return deselect(getSelectedRows(), refresh);
  1708. }
  1709. /**
  1710. * {@inheritDoc}
  1711. * <p>
  1712. * The returned Collection is in <strong>order of selection</strong>
  1713. * &ndash; the item that was first selected will be first in the
  1714. * collection, and so on. Should an item have been selected twice
  1715. * without being deselected in between, it will have remained in its
  1716. * original position.
  1717. */
  1718. @Override
  1719. public Collection<Object> getSelectedRows() {
  1720. // overridden only for JavaDoc
  1721. return super.getSelectedRows();
  1722. }
  1723. /**
  1724. * Resets the selection model.
  1725. * <p>
  1726. * Equivalent to calling {@link #deselectAll()}
  1727. */
  1728. @Override
  1729. public void reset() {
  1730. deselectAll();
  1731. }
  1732. @Override
  1733. public boolean setSelected(Collection<?> itemIds)
  1734. throws IllegalArgumentException {
  1735. if (itemIds == null) {
  1736. throw new IllegalArgumentException("itemIds may not be null");
  1737. }
  1738. checkItemIdsExist(itemIds);
  1739. boolean changed = false;
  1740. Set<Object> selectedRows = new HashSet<Object>(itemIds);
  1741. final Collection<Object> oldSelection = getSelectedRows();
  1742. Set<Object> added = getDifference(selectedRows, selection);
  1743. if (!added.isEmpty()) {
  1744. changed = true;
  1745. selection.addAll(added);
  1746. for (Object id : added) {
  1747. refreshRow(id);
  1748. }
  1749. }
  1750. Set<Object> removed = getDifference(selection, selectedRows);
  1751. if (!removed.isEmpty()) {
  1752. changed = true;
  1753. selection.removeAll(removed);
  1754. for (Object id : removed) {
  1755. refreshRow(id);
  1756. }
  1757. }
  1758. if (changed) {
  1759. fireSelectionEvent(oldSelection, selection);
  1760. }
  1761. updateAllSelectedState();
  1762. return changed;
  1763. }
  1764. /**
  1765. * Compares two sets and returns a set containing all values that are
  1766. * present in the first, but not in the second.
  1767. *
  1768. * @param set1
  1769. * first item set
  1770. * @param set2
  1771. * second item set
  1772. * @return all values from set1 which are not present in set2
  1773. */
  1774. private static Set<Object> getDifference(Set<Object> set1,
  1775. Set<Object> set2) {
  1776. Set<Object> diff = new HashSet<Object>(set1);
  1777. diff.removeAll(set2);
  1778. return diff;
  1779. }
  1780. @Override
  1781. public boolean setSelected(Object... itemIds)
  1782. throws IllegalArgumentException {
  1783. if (itemIds != null) {
  1784. return setSelected(Arrays.asList(itemIds));
  1785. } else {
  1786. throw new IllegalArgumentException(
  1787. "Vararg array of itemIds may not be null");
  1788. }
  1789. }
  1790. private void updateAllSelectedState() {
  1791. int totalRowCount = getParentGrid().datasource.size();
  1792. int rows = Math.min(totalRowCount, selectionLimit);
  1793. if (totalRowCount == 0) {
  1794. getState().allSelected = false;
  1795. } else {
  1796. getState().allSelected = selection.size() >= rows;
  1797. }
  1798. }
  1799. @Override
  1800. protected MultiSelectionModelState getState() {
  1801. return (MultiSelectionModelState) super.getState();
  1802. }
  1803. @Override
  1804. protected MultiSelectionModelState getState(boolean markAsDirty) {
  1805. return (MultiSelectionModelState) super.getState(markAsDirty);
  1806. }
  1807. @Override
  1808. public boolean isUserSelectionAllowed() {
  1809. return getState(false).userSelectionAllowed;
  1810. }
  1811. @Override
  1812. public void setUserSelectionAllowed(boolean userSelectionAllowed) {
  1813. getState().userSelectionAllowed = userSelectionAllowed;
  1814. }
  1815. }
  1816. /**
  1817. * A data class which contains information which identifies a row in a
  1818. * {@link Grid}.
  1819. * <p>
  1820. * Since this class follows the <code>Flyweight</code>-pattern any instance
  1821. * of this object is subject to change without the user knowing it and so
  1822. * should not be stored anywhere outside of the method providing these
  1823. * instances.
  1824. */
  1825. @Deprecated
  1826. public static class RowReference implements Serializable {
  1827. private final Grid grid;
  1828. private Object itemId;
  1829. /**
  1830. * Creates a new row reference for the given grid.
  1831. *
  1832. * @param grid
  1833. * the grid that the row belongs to
  1834. */
  1835. public RowReference(Grid grid) {
  1836. this.grid = grid;
  1837. }
  1838. /**
  1839. * Sets the identifying information for this row.
  1840. *
  1841. * @param itemId
  1842. * the item id of the row
  1843. */
  1844. public void set(Object itemId) {
  1845. this.itemId = itemId;
  1846. }
  1847. /**
  1848. * Gets the grid that contains the referenced row.
  1849. *
  1850. * @return the grid that contains referenced row
  1851. */
  1852. public Grid getGrid() {
  1853. return grid;
  1854. }
  1855. /**
  1856. * Gets the item id of the row.
  1857. *
  1858. * @return the item id of the row
  1859. */
  1860. public Object getItemId() {
  1861. return itemId;
  1862. }
  1863. /**
  1864. * Gets the item for the row.
  1865. *
  1866. * @return the item for the row
  1867. */
  1868. public Item getItem() {
  1869. return grid.getContainerDataSource().getItem(itemId);
  1870. }
  1871. }
  1872. /**
  1873. * A data class which contains information which identifies a cell in a
  1874. * {@link Grid}.
  1875. * <p>
  1876. * Since this class follows the <code>Flyweight</code>-pattern any instance
  1877. * of this object is subject to change without the user knowing it and so
  1878. * should not be stored anywhere outside of the method providing these
  1879. * instances.
  1880. */
  1881. @Deprecated
  1882. public static class CellReference implements Serializable {
  1883. private final RowReference rowReference;
  1884. private Object propertyId;
  1885. public CellReference(RowReference rowReference) {
  1886. this.rowReference = rowReference;
  1887. }
  1888. /**
  1889. * Sets the identifying information for this cell.
  1890. *
  1891. * @param propertyId
  1892. * the property id of the column
  1893. */
  1894. public void set(Object propertyId) {
  1895. this.propertyId = propertyId;
  1896. }
  1897. /**
  1898. * Gets the grid that contains the referenced cell.
  1899. *
  1900. * @return the grid that contains referenced cell
  1901. */
  1902. public Grid getGrid() {
  1903. return rowReference.getGrid();
  1904. }
  1905. /**
  1906. * @return the property id of the column
  1907. */
  1908. public Object getPropertyId() {
  1909. return propertyId;
  1910. }
  1911. /**
  1912. * @return the property for the cell
  1913. */
  1914. public Property<?> getProperty() {
  1915. return getItem().getItemProperty(propertyId);
  1916. }
  1917. /**
  1918. * Gets the item id of the row of the cell.
  1919. *
  1920. * @return the item id of the row
  1921. */
  1922. public Object getItemId() {
  1923. return rowReference.getItemId();
  1924. }
  1925. /**
  1926. * Gets the item for the row of the cell.
  1927. *
  1928. * @return the item for the row
  1929. */
  1930. public Item getItem() {
  1931. return rowReference.getItem();
  1932. }
  1933. /**
  1934. * Gets the value of the cell.
  1935. *
  1936. * @return the value of the cell
  1937. */
  1938. public Object getValue() {
  1939. return getProperty().getValue();
  1940. }
  1941. }
  1942. /**
  1943. * A callback interface for generating custom style names for Grid rows.
  1944. *
  1945. * @see Grid#setRowStyleGenerator(RowStyleGenerator)
  1946. */
  1947. @Deprecated
  1948. public interface RowStyleGenerator extends Serializable {
  1949. /**
  1950. * Called by Grid to generate a style name for a row.
  1951. *
  1952. * @param row
  1953. * the row to generate a style for
  1954. * @return the style name to add to this row, or {@code null} to not set
  1955. * any style
  1956. */
  1957. public String getStyle(RowReference row);
  1958. }
  1959. /**
  1960. * A callback interface for generating custom style names for Grid cells.
  1961. *
  1962. * @see Grid#setCellStyleGenerator(CellStyleGenerator)
  1963. */
  1964. @Deprecated
  1965. public interface CellStyleGenerator extends Serializable {
  1966. /**
  1967. * Called by Grid to generate a style name for a column.
  1968. *
  1969. * @param cell
  1970. * the cell to generate a style for
  1971. * @return the style name to add to this cell, or {@code null} to not
  1972. * set any style
  1973. */
  1974. public String getStyle(CellReference cell);
  1975. }
  1976. /**
  1977. * A callback interface for generating optional descriptions (tooltips) for
  1978. * Grid rows. If a description is generated for a row, it is used for all
  1979. * the cells in the row for which a {@link CellDescriptionGenerator cell
  1980. * description} is not generated.
  1981. *
  1982. * @see Grid#setRowDescriptionGenerator
  1983. *
  1984. * @since 7.6
  1985. */
  1986. @Deprecated
  1987. public interface RowDescriptionGenerator extends Serializable {
  1988. /**
  1989. * Called by Grid to generate a description (tooltip) for a row. The
  1990. * description may contain HTML which is rendered directly; if this is
  1991. * not desired the returned string must be escaped by the implementing
  1992. * method.
  1993. *
  1994. * @param row
  1995. * the row to generate a description for
  1996. * @return the row description or {@code null} for no description
  1997. */
  1998. public String getDescription(RowReference row);
  1999. }
  2000. /**
  2001. * A callback interface for generating optional descriptions (tooltips) for
  2002. * Grid cells. If a cell has both a {@link RowDescriptionGenerator row
  2003. * description} and a cell description, the latter has precedence.
  2004. *
  2005. * @see Grid#setCellDescriptionGenerator(CellDescriptionGenerator)
  2006. *
  2007. * @since 7.6
  2008. */
  2009. @Deprecated
  2010. public interface CellDescriptionGenerator extends Serializable {
  2011. /**
  2012. * Called by Grid to generate a description (tooltip) for a cell. The
  2013. * description may contain HTML which is rendered directly; if this is
  2014. * not desired the returned string must be escaped by the implementing
  2015. * method.
  2016. *
  2017. * @param cell
  2018. * the cell to generate a description for
  2019. * @return the cell description or {@code null} for no description
  2020. */
  2021. public String getDescription(CellReference cell);
  2022. }
  2023. /**
  2024. * Class for generating all row and cell related data for the essential
  2025. * parts of Grid.
  2026. */
  2027. private class RowDataGenerator implements DataGenerator {
  2028. private void put(String key, String value, JsonObject object) {
  2029. if (value != null && !value.isEmpty()) {
  2030. object.put(key, value);
  2031. }
  2032. }
  2033. @Override
  2034. public void generateData(Object itemId, Item item, JsonObject rowData) {
  2035. RowReference row = new RowReference(Grid.this);
  2036. row.set(itemId);
  2037. if (rowStyleGenerator != null) {
  2038. String style = rowStyleGenerator.getStyle(row);
  2039. put(GridState.JSONKEY_ROWSTYLE, style, rowData);
  2040. }
  2041. if (rowDescriptionGenerator != null) {
  2042. String description = rowDescriptionGenerator
  2043. .getDescription(row);
  2044. put(GridState.JSONKEY_ROWDESCRIPTION, description, rowData);
  2045. }
  2046. JsonObject cellStyles = Json.createObject();
  2047. JsonObject cellData = Json.createObject();
  2048. JsonObject cellDescriptions = Json.createObject();
  2049. CellReference cell = new CellReference(row);
  2050. for (Column column : getColumns()) {
  2051. cell.set(column.getPropertyId());
  2052. writeData(cell, cellData);
  2053. writeStyles(cell, cellStyles);
  2054. writeDescriptions(cell, cellDescriptions);
  2055. }
  2056. if (cellDescriptionGenerator != null
  2057. && cellDescriptions.keys().length > 0) {
  2058. rowData.put(GridState.JSONKEY_CELLDESCRIPTION,
  2059. cellDescriptions);
  2060. }
  2061. if (cellStyleGenerator != null && cellStyles.keys().length > 0) {
  2062. rowData.put(GridState.JSONKEY_CELLSTYLES, cellStyles);
  2063. }
  2064. rowData.put(GridState.JSONKEY_DATA, cellData);
  2065. }
  2066. private void writeStyles(CellReference cell, JsonObject styles) {
  2067. if (cellStyleGenerator != null) {
  2068. String style = cellStyleGenerator.getStyle(cell);
  2069. put(columnKeys.key(cell.getPropertyId()), style, styles);
  2070. }
  2071. }
  2072. private void writeDescriptions(CellReference cell,
  2073. JsonObject descriptions) {
  2074. if (cellDescriptionGenerator != null) {
  2075. String description = cellDescriptionGenerator
  2076. .getDescription(cell);
  2077. put(columnKeys.key(cell.getPropertyId()), description,
  2078. descriptions);
  2079. }
  2080. }
  2081. private void writeData(CellReference cell, JsonObject data) {
  2082. Column column = getColumn(cell.getPropertyId());
  2083. Converter<?, ?> converter = column.getConverter();
  2084. Renderer<?> renderer = column.getRenderer();
  2085. Item item = cell.getItem();
  2086. Property itemProperty = item.getItemProperty(cell.getPropertyId());
  2087. Object modelValue = itemProperty == null ? null
  2088. : itemProperty.getValue();
  2089. data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer
  2090. .encodeValue(modelValue, renderer, converter, getLocale()));
  2091. }
  2092. @Override
  2093. public void destroyData(Object itemId) {
  2094. // NO-OP
  2095. }
  2096. }
  2097. /**
  2098. * Abstract base class for Grid header and footer sections.
  2099. *
  2100. * @since 7.6
  2101. * @param <ROWTYPE>
  2102. * the type of the rows in the section
  2103. */
  2104. @Deprecated
  2105. public abstract static class StaticSection<ROWTYPE extends StaticSection.StaticRow<?>>
  2106. implements Serializable {
  2107. /**
  2108. * Abstract base class for Grid header and footer rows.
  2109. *
  2110. * @param <CELLTYPE>
  2111. * the type of the cells in the row
  2112. */
  2113. @Deprecated
  2114. public abstract static class StaticRow<CELLTYPE extends StaticCell>
  2115. implements Serializable {
  2116. private RowState rowState = new RowState();
  2117. protected StaticSection<?> section;
  2118. private Map<Object, CELLTYPE> cells = new LinkedHashMap<Object, CELLTYPE>();
  2119. private Map<Set<CELLTYPE>, CELLTYPE> cellGroups = new HashMap<Set<CELLTYPE>, CELLTYPE>();
  2120. protected StaticRow(StaticSection<?> section) {
  2121. this.section = section;
  2122. }
  2123. protected void addCell(Object propertyId) {
  2124. CELLTYPE cell = createCell();
  2125. cell.setColumnId(
  2126. section.grid.getColumn(propertyId).getState().id);
  2127. cells.put(propertyId, cell);
  2128. rowState.cells.add(cell.getCellState());
  2129. }
  2130. protected void removeCell(Object propertyId) {
  2131. CELLTYPE cell = cells.remove(propertyId);
  2132. if (cell != null) {
  2133. Set<CELLTYPE> cellGroupForCell = getCellGroupForCell(cell);
  2134. if (cellGroupForCell != null) {
  2135. removeCellFromGroup(cell, cellGroupForCell);
  2136. }
  2137. rowState.cells.remove(cell.getCellState());
  2138. }
  2139. }
  2140. private void removeCellFromGroup(CELLTYPE cell,
  2141. Set<CELLTYPE> cellGroup) {
  2142. String columnId = cell.getColumnId();
  2143. for (Set<String> group : rowState.cellGroups.keySet()) {
  2144. if (group.contains(columnId)) {
  2145. if (group.size() > 2) {
  2146. // Update map key correctly
  2147. CELLTYPE mergedCell = cellGroups.remove(cellGroup);
  2148. cellGroup.remove(cell);
  2149. cellGroups.put(cellGroup, mergedCell);
  2150. group.remove(columnId);
  2151. } else {
  2152. rowState.cellGroups.remove(group);
  2153. cellGroups.remove(cellGroup);
  2154. }
  2155. return;
  2156. }
  2157. }
  2158. }
  2159. /**
  2160. * Creates and returns a new instance of the cell type.
  2161. *
  2162. * @return the created cell
  2163. */
  2164. protected abstract CELLTYPE createCell();
  2165. protected RowState getRowState() {
  2166. return rowState;
  2167. }
  2168. /**
  2169. * Returns the cell for the given property id on this row. If the
  2170. * column is merged returned cell is the cell for the whole group.
  2171. *
  2172. * @param propertyId
  2173. * the property id of the column
  2174. * @return the cell for the given property, merged cell for merged
  2175. * properties, null if not found
  2176. */
  2177. public CELLTYPE getCell(Object propertyId) {
  2178. CELLTYPE cell = cells.get(propertyId);
  2179. Set<CELLTYPE> cellGroup = getCellGroupForCell(cell);
  2180. if (cellGroup != null) {
  2181. cell = cellGroups.get(cellGroup);
  2182. }
  2183. return cell;
  2184. }
  2185. /**
  2186. * Merges columns cells in a row.
  2187. *
  2188. * @param propertyIds
  2189. * The property ids of columns to merge
  2190. * @return The remaining visible cell after the merge
  2191. */
  2192. public CELLTYPE join(Object... propertyIds) {
  2193. if (propertyIds.length < 2) {
  2194. throw new IllegalArgumentException(
  2195. "You need to merge at least 2 properties");
  2196. }
  2197. Set<CELLTYPE> cells = new HashSet<CELLTYPE>();
  2198. for (int i = 0; i < propertyIds.length; ++i) {
  2199. cells.add(getCell(propertyIds[i]));
  2200. }
  2201. return join(cells);
  2202. }
  2203. /**
  2204. * Merges columns cells in a row.
  2205. *
  2206. * @param cells
  2207. * The cells to merge. Must be from the same row.
  2208. * @return The remaining visible cell after the merge
  2209. */
  2210. public CELLTYPE join(CELLTYPE... cells) {
  2211. if (cells.length < 2) {
  2212. throw new IllegalArgumentException(
  2213. "You need to merge at least 2 cells");
  2214. }
  2215. return join(new HashSet<CELLTYPE>(Arrays.asList(cells)));
  2216. }
  2217. protected CELLTYPE join(Set<CELLTYPE> cells) {
  2218. for (CELLTYPE cell : cells) {
  2219. if (getCellGroupForCell(cell) != null) {
  2220. throw new IllegalArgumentException(
  2221. "Cell already merged");
  2222. } else if (!this.cells.containsValue(cell)) {
  2223. throw new IllegalArgumentException(
  2224. "Cell does not exist on this row");
  2225. }
  2226. }
  2227. // Create new cell data for the group
  2228. CELLTYPE newCell = createCell();
  2229. Set<String> columnGroup = new HashSet<String>();
  2230. for (CELLTYPE cell : cells) {
  2231. columnGroup.add(cell.getColumnId());
  2232. }
  2233. rowState.cellGroups.put(columnGroup, newCell.getCellState());
  2234. cellGroups.put(cells, newCell);
  2235. return newCell;
  2236. }
  2237. private Set<CELLTYPE> getCellGroupForCell(CELLTYPE cell) {
  2238. for (Set<CELLTYPE> group : cellGroups.keySet()) {
  2239. if (group.contains(cell)) {
  2240. return group;
  2241. }
  2242. }
  2243. return null;
  2244. }
  2245. /**
  2246. * Returns the custom style name for this row.
  2247. *
  2248. * @return the style name or null if no style name has been set
  2249. */
  2250. public String getStyleName() {
  2251. return getRowState().styleName;
  2252. }
  2253. /**
  2254. * Sets a custom style name for this row.
  2255. *
  2256. * @param styleName
  2257. * the style name to set or null to not use any style
  2258. * name
  2259. */
  2260. public void setStyleName(String styleName) {
  2261. getRowState().styleName = styleName;
  2262. }
  2263. /**
  2264. * Writes the declarative design to the given table row element.
  2265. *
  2266. * @since 7.5.0
  2267. * @param trElement
  2268. * Element to write design to
  2269. * @param designContext
  2270. * the design context
  2271. */
  2272. protected void writeDesign(Element trElement,
  2273. DesignContext designContext) {
  2274. Set<CELLTYPE> visited = new HashSet<CELLTYPE>();
  2275. for (Grid.Column column : section.grid.getColumns()) {
  2276. CELLTYPE cell = getCell(column.getPropertyId());
  2277. if (visited.contains(cell)) {
  2278. continue;
  2279. }
  2280. visited.add(cell);
  2281. Element cellElement = trElement
  2282. .appendElement(getCellTagName());
  2283. cell.writeDesign(cellElement, designContext);
  2284. for (Entry<Set<CELLTYPE>, CELLTYPE> entry : cellGroups
  2285. .entrySet()) {
  2286. if (entry.getValue() == cell) {
  2287. cellElement.attr("colspan",
  2288. "" + entry.getKey().size());
  2289. break;
  2290. }
  2291. }
  2292. }
  2293. }
  2294. /**
  2295. * Reads the declarative design from the given table row element.
  2296. *
  2297. * @since 7.5.0
  2298. * @param trElement
  2299. * Element to read design from
  2300. * @param designContext
  2301. * the design context
  2302. * @throws DesignException
  2303. * if the given table row contains unexpected children
  2304. */
  2305. protected void readDesign(Element trElement,
  2306. DesignContext designContext) throws DesignException {
  2307. Elements cellElements = trElement.children();
  2308. int totalColSpans = 0;
  2309. for (int i = 0; i < cellElements.size(); ++i) {
  2310. Element element = cellElements.get(i);
  2311. if (!element.tagName().equals(getCellTagName())) {
  2312. throw new DesignException(
  2313. "Unexpected element in tr while expecting "
  2314. + getCellTagName() + ": "
  2315. + element.tagName());
  2316. }
  2317. int columnIndex = i + totalColSpans;
  2318. int colspan = DesignAttributeHandler.readAttribute(
  2319. "colspan", element.attributes(), 1, int.class);
  2320. Set<CELLTYPE> cells = new HashSet<CELLTYPE>();
  2321. for (int c = 0; c < colspan; ++c) {
  2322. cells.add(getCell(section.grid.getColumns()
  2323. .get(columnIndex + c).getPropertyId()));
  2324. }
  2325. if (colspan > 1) {
  2326. totalColSpans += colspan - 1;
  2327. join(cells).readDesign(element, designContext);
  2328. } else {
  2329. cells.iterator().next().readDesign(element,
  2330. designContext);
  2331. }
  2332. }
  2333. }
  2334. protected abstract String getCellTagName();
  2335. void detach() {
  2336. for (CELLTYPE cell : cells.values()) {
  2337. cell.detach();
  2338. }
  2339. for (CELLTYPE cell : cellGroups.values()) {
  2340. cell.detach();
  2341. }
  2342. }
  2343. }
  2344. /**
  2345. * A header or footer cell. Has a simple textual caption.
  2346. */
  2347. @Deprecated
  2348. abstract static class StaticCell implements Serializable {
  2349. private CellState cellState = new CellState();
  2350. private StaticRow<?> row;
  2351. protected StaticCell(StaticRow<?> row) {
  2352. this.row = row;
  2353. }
  2354. void setColumnId(String id) {
  2355. cellState.columnId = id;
  2356. }
  2357. String getColumnId() {
  2358. return cellState.columnId;
  2359. }
  2360. /**
  2361. * Gets the row where this cell is.
  2362. *
  2363. * @return row for this cell
  2364. */
  2365. public StaticRow<?> getRow() {
  2366. return row;
  2367. }
  2368. protected CellState getCellState() {
  2369. return cellState;
  2370. }
  2371. /**
  2372. * Sets the text displayed in this cell.
  2373. *
  2374. * @param text
  2375. * a plain text caption
  2376. */
  2377. public void setText(String text) {
  2378. removeComponentIfPresent();
  2379. cellState.text = text;
  2380. cellState.type = GridStaticCellType.TEXT;
  2381. row.section.markAsDirty();
  2382. }
  2383. /**
  2384. * Returns the text displayed in this cell.
  2385. *
  2386. * @return the plain text caption
  2387. */
  2388. public String getText() {
  2389. if (cellState.type != GridStaticCellType.TEXT) {
  2390. throw new IllegalStateException(
  2391. "Cannot fetch Text from a cell with type "
  2392. + cellState.type);
  2393. }
  2394. return cellState.text;
  2395. }
  2396. /**
  2397. * Returns the HTML content displayed in this cell.
  2398. *
  2399. * @return the html
  2400. *
  2401. */
  2402. public String getHtml() {
  2403. if (cellState.type != GridStaticCellType.HTML) {
  2404. throw new IllegalStateException(
  2405. "Cannot fetch HTML from a cell with type "
  2406. + cellState.type);
  2407. }
  2408. return cellState.html;
  2409. }
  2410. /**
  2411. * Sets the HTML content displayed in this cell.
  2412. *
  2413. * @param html
  2414. * the html to set
  2415. */
  2416. public void setHtml(String html) {
  2417. removeComponentIfPresent();
  2418. cellState.html = html;
  2419. cellState.type = GridStaticCellType.HTML;
  2420. row.section.markAsDirty();
  2421. }
  2422. /**
  2423. * Returns the component displayed in this cell.
  2424. *
  2425. * @return the component
  2426. */
  2427. public Component getComponent() {
  2428. if (cellState.type != GridStaticCellType.WIDGET) {
  2429. throw new IllegalStateException(
  2430. "Cannot fetch Component from a cell with type "
  2431. + cellState.type);
  2432. }
  2433. return (Component) cellState.connector;
  2434. }
  2435. /**
  2436. * Sets the component displayed in this cell.
  2437. *
  2438. * @param component
  2439. * the component to set
  2440. */
  2441. public void setComponent(Component component) {
  2442. removeComponentIfPresent();
  2443. component.setParent(row.section.grid);
  2444. cellState.connector = component;
  2445. cellState.type = GridStaticCellType.WIDGET;
  2446. row.section.markAsDirty();
  2447. }
  2448. /**
  2449. * Returns the type of content stored in this cell.
  2450. *
  2451. * @return cell content type
  2452. */
  2453. public GridStaticCellType getCellType() {
  2454. return cellState.type;
  2455. }
  2456. /**
  2457. * Returns the custom style name for this cell.
  2458. *
  2459. * @return the style name or null if no style name has been set
  2460. */
  2461. public String getStyleName() {
  2462. return cellState.styleName;
  2463. }
  2464. /**
  2465. * Sets a custom style name for this cell.
  2466. *
  2467. * @param styleName
  2468. * the style name to set or null to not use any style
  2469. * name
  2470. */
  2471. public void setStyleName(String styleName) {
  2472. cellState.styleName = styleName;
  2473. row.section.markAsDirty();
  2474. }
  2475. private void removeComponentIfPresent() {
  2476. Component component = (Component) cellState.connector;
  2477. if (component != null) {
  2478. component.setParent(null);
  2479. cellState.connector = null;
  2480. }
  2481. }
  2482. /**
  2483. * Writes the declarative design to the given table cell element.
  2484. *
  2485. * @since 7.5.0
  2486. * @param cellElement
  2487. * Element to write design to
  2488. * @param designContext
  2489. * the design context
  2490. */
  2491. protected void writeDesign(Element cellElement,
  2492. DesignContext designContext) {
  2493. switch (cellState.type) {
  2494. case TEXT:
  2495. cellElement.attr("plain-text", true);
  2496. cellElement.appendText(getText());
  2497. break;
  2498. case HTML:
  2499. cellElement.append(getHtml());
  2500. break;
  2501. case WIDGET:
  2502. cellElement.appendChild(
  2503. designContext.createElement(getComponent()));
  2504. break;
  2505. }
  2506. }
  2507. /**
  2508. * Reads the declarative design from the given table cell element.
  2509. *
  2510. * @since 7.5.0
  2511. * @param cellElement
  2512. * Element to read design from
  2513. * @param designContext
  2514. * the design context
  2515. */
  2516. protected void readDesign(Element cellElement,
  2517. DesignContext designContext) {
  2518. if (!cellElement.hasAttr("plain-text")) {
  2519. if (cellElement.children().size() > 0
  2520. && cellElement.child(0).tagName().contains("-")) {
  2521. setComponent(
  2522. designContext.readDesign(cellElement.child(0)));
  2523. } else {
  2524. setHtml(cellElement.html());
  2525. }
  2526. } else {
  2527. // text – need to unescape HTML entities
  2528. setText(DesignFormatter
  2529. .decodeFromTextNode(cellElement.html()));
  2530. }
  2531. }
  2532. void detach() {
  2533. removeComponentIfPresent();
  2534. }
  2535. }
  2536. protected Grid grid;
  2537. protected List<ROWTYPE> rows = new ArrayList<ROWTYPE>();
  2538. /**
  2539. * Sets the visibility of the whole section.
  2540. *
  2541. * @param visible
  2542. * true to show this section, false to hide
  2543. */
  2544. public void setVisible(boolean visible) {
  2545. if (getSectionState().visible != visible) {
  2546. getSectionState().visible = visible;
  2547. markAsDirty();
  2548. }
  2549. }
  2550. /**
  2551. * Returns the visibility of this section.
  2552. *
  2553. * @return true if visible, false otherwise.
  2554. */
  2555. public boolean isVisible() {
  2556. return getSectionState().visible;
  2557. }
  2558. /**
  2559. * Removes the row at the given position.
  2560. *
  2561. * @param rowIndex
  2562. * the position of the row
  2563. *
  2564. * @throws IllegalArgumentException
  2565. * if no row exists at given index
  2566. * @see #removeRow(StaticRow)
  2567. * @see #addRowAt(int)
  2568. * @see #appendRow()
  2569. * @see #prependRow()
  2570. */
  2571. public ROWTYPE removeRow(int rowIndex) {
  2572. if (rowIndex >= rows.size() || rowIndex < 0) {
  2573. throw new IllegalArgumentException(
  2574. "No row at given index " + rowIndex);
  2575. }
  2576. ROWTYPE row = rows.remove(rowIndex);
  2577. row.detach();
  2578. getSectionState().rows.remove(rowIndex);
  2579. markAsDirty();
  2580. return row;
  2581. }
  2582. /**
  2583. * Removes the given row from the section.
  2584. *
  2585. * @param row
  2586. * the row to be removed
  2587. *
  2588. * @throws IllegalArgumentException
  2589. * if the row does not exist in this section
  2590. * @see #removeRow(int)
  2591. * @see #addRowAt(int)
  2592. * @see #appendRow()
  2593. * @see #prependRow()
  2594. */
  2595. public void removeRow(ROWTYPE row) {
  2596. try {
  2597. removeRow(rows.indexOf(row));
  2598. } catch (IndexOutOfBoundsException e) {
  2599. throw new IllegalArgumentException(
  2600. "Section does not contain the given row");
  2601. }
  2602. }
  2603. /**
  2604. * Gets row at given index.
  2605. *
  2606. * @param rowIndex
  2607. * 0 based index for row. Counted from top to bottom
  2608. * @return row at given index
  2609. */
  2610. public ROWTYPE getRow(int rowIndex) {
  2611. if (rowIndex >= rows.size() || rowIndex < 0) {
  2612. throw new IllegalArgumentException(
  2613. "No row at given index " + rowIndex);
  2614. }
  2615. return rows.get(rowIndex);
  2616. }
  2617. /**
  2618. * Adds a new row at the top of this section.
  2619. *
  2620. * @return the new row
  2621. * @see #appendRow()
  2622. * @see #addRowAt(int)
  2623. * @see #removeRow(StaticRow)
  2624. * @see #removeRow(int)
  2625. */
  2626. public ROWTYPE prependRow() {
  2627. return addRowAt(0);
  2628. }
  2629. /**
  2630. * Adds a new row at the bottom of this section.
  2631. *
  2632. * @return the new row
  2633. * @see #prependRow()
  2634. * @see #addRowAt(int)
  2635. * @see #removeRow(StaticRow)
  2636. * @see #removeRow(int)
  2637. */
  2638. public ROWTYPE appendRow() {
  2639. return addRowAt(rows.size());
  2640. }
  2641. /**
  2642. * Inserts a new row at the given position.
  2643. *
  2644. * @param index
  2645. * the position at which to insert the row
  2646. * @return the new row
  2647. *
  2648. * @throws IndexOutOfBoundsException
  2649. * if the index is out of bounds
  2650. * @see #appendRow()
  2651. * @see #prependRow()
  2652. * @see #removeRow(StaticRow)
  2653. * @see #removeRow(int)
  2654. */
  2655. public ROWTYPE addRowAt(int index) {
  2656. if (index > rows.size() || index < 0) {
  2657. throw new IllegalArgumentException(
  2658. "Unable to add row at index " + index);
  2659. }
  2660. ROWTYPE row = createRow();
  2661. rows.add(index, row);
  2662. getSectionState().rows.add(index, row.getRowState());
  2663. for (Object id : grid.columns.keySet()) {
  2664. row.addCell(id);
  2665. }
  2666. markAsDirty();
  2667. return row;
  2668. }
  2669. /**
  2670. * Gets the amount of rows in this section.
  2671. *
  2672. * @return row count
  2673. */
  2674. public int getRowCount() {
  2675. return rows.size();
  2676. }
  2677. protected abstract GridStaticSectionState getSectionState();
  2678. protected abstract ROWTYPE createRow();
  2679. /**
  2680. * Informs the grid that state has changed and it should be redrawn.
  2681. */
  2682. protected void markAsDirty() {
  2683. grid.markAsDirty();
  2684. }
  2685. /**
  2686. * Removes a column for given property id from the section.
  2687. *
  2688. * @param propertyId
  2689. * property to be removed
  2690. */
  2691. protected void removeColumn(Object propertyId) {
  2692. for (ROWTYPE row : rows) {
  2693. row.removeCell(propertyId);
  2694. }
  2695. }
  2696. /**
  2697. * Adds a column for given property id to the section.
  2698. *
  2699. * @param propertyId
  2700. * property to be added
  2701. */
  2702. protected void addColumn(Object propertyId) {
  2703. for (ROWTYPE row : rows) {
  2704. row.addCell(propertyId);
  2705. }
  2706. }
  2707. /**
  2708. * Performs a sanity check that section is in correct state.
  2709. *
  2710. * @throws IllegalStateException
  2711. * if merged cells are not i n continuous range
  2712. */
  2713. protected void sanityCheck() throws IllegalStateException {
  2714. List<String> columnOrder = grid.getState().columnOrder;
  2715. for (ROWTYPE row : rows) {
  2716. for (Set<String> cellGroup : row.getRowState().cellGroups
  2717. .keySet()) {
  2718. if (!checkCellGroupAndOrder(columnOrder, cellGroup)) {
  2719. throw new IllegalStateException(
  2720. "Not all merged cells were in a continuous range.");
  2721. }
  2722. }
  2723. }
  2724. }
  2725. private boolean checkCellGroupAndOrder(List<String> columnOrder,
  2726. Set<String> cellGroup) {
  2727. if (!columnOrder.containsAll(cellGroup)) {
  2728. return false;
  2729. }
  2730. for (int i = 0; i < columnOrder.size(); ++i) {
  2731. if (!cellGroup.contains(columnOrder.get(i))) {
  2732. continue;
  2733. }
  2734. for (int j = 1; j < cellGroup.size(); ++j) {
  2735. if (!cellGroup.contains(columnOrder.get(i + j))) {
  2736. return false;
  2737. }
  2738. }
  2739. return true;
  2740. }
  2741. return false;
  2742. }
  2743. /**
  2744. * Writes the declarative design to the given table section element.
  2745. *
  2746. * @since 7.5.0
  2747. * @param tableSectionElement
  2748. * Element to write design to
  2749. * @param designContext
  2750. * the design context
  2751. */
  2752. protected void writeDesign(Element tableSectionElement,
  2753. DesignContext designContext) {
  2754. for (ROWTYPE row : rows) {
  2755. row.writeDesign(tableSectionElement.appendElement("tr"),
  2756. designContext);
  2757. }
  2758. }
  2759. /**
  2760. * Writes the declarative design from the given table section element.
  2761. *
  2762. * @since 7.5.0
  2763. * @param tableSectionElement
  2764. * Element to read design from
  2765. * @param designContext
  2766. * the design context
  2767. * @throws DesignException
  2768. * if the table section contains unexpected children
  2769. */
  2770. protected void readDesign(Element tableSectionElement,
  2771. DesignContext designContext) throws DesignException {
  2772. while (rows.size() > 0) {
  2773. removeRow(0);
  2774. }
  2775. for (Element row : tableSectionElement.children()) {
  2776. if (!row.tagName().equals("tr")) {
  2777. throw new DesignException("Unexpected element in "
  2778. + tableSectionElement.tagName() + ": "
  2779. + row.tagName());
  2780. }
  2781. appendRow().readDesign(row, designContext);
  2782. }
  2783. }
  2784. }
  2785. /**
  2786. * Represents the header section of a Grid.
  2787. */
  2788. @Deprecated
  2789. protected static class Header extends StaticSection<HeaderRow> {
  2790. private HeaderRow defaultRow = null;
  2791. private final GridStaticSectionState headerState = new GridStaticSectionState();
  2792. protected Header(Grid grid) {
  2793. this.grid = grid;
  2794. grid.getState(true).header = headerState;
  2795. HeaderRow row = createRow();
  2796. rows.add(row);
  2797. setDefaultRow(row);
  2798. getSectionState().rows.add(row.getRowState());
  2799. }
  2800. /**
  2801. * Sets the default row of this header. The default row is a special
  2802. * header row providing a user interface for sorting columns.
  2803. *
  2804. * @param row
  2805. * the new default row, or null for no default row
  2806. *
  2807. * @throws IllegalArgumentException
  2808. * this header does not contain the row
  2809. */
  2810. public void setDefaultRow(HeaderRow row) {
  2811. if (row == defaultRow) {
  2812. return;
  2813. }
  2814. if (row != null && !rows.contains(row)) {
  2815. throw new IllegalArgumentException(
  2816. "Cannot set a default row that does not exist in the section");
  2817. }
  2818. if (defaultRow != null) {
  2819. defaultRow.setDefaultRow(false);
  2820. }
  2821. if (row != null) {
  2822. row.setDefaultRow(true);
  2823. }
  2824. defaultRow = row;
  2825. markAsDirty();
  2826. }
  2827. /**
  2828. * Returns the current default row of this header. The default row is a
  2829. * special header row providing a user interface for sorting columns.
  2830. *
  2831. * @return the default row or null if no default row set
  2832. */
  2833. public HeaderRow getDefaultRow() {
  2834. return defaultRow;
  2835. }
  2836. @Override
  2837. protected GridStaticSectionState getSectionState() {
  2838. return headerState;
  2839. }
  2840. @Override
  2841. protected HeaderRow createRow() {
  2842. return new HeaderRow(this);
  2843. }
  2844. @Override
  2845. public HeaderRow removeRow(int rowIndex) {
  2846. HeaderRow row = super.removeRow(rowIndex);
  2847. if (row == defaultRow) {
  2848. // Default Header Row was just removed.
  2849. setDefaultRow(null);
  2850. }
  2851. return row;
  2852. }
  2853. @Override
  2854. protected void sanityCheck() throws IllegalStateException {
  2855. super.sanityCheck();
  2856. boolean hasDefaultRow = false;
  2857. for (HeaderRow row : rows) {
  2858. if (row.getRowState().defaultRow) {
  2859. if (!hasDefaultRow) {
  2860. hasDefaultRow = true;
  2861. } else {
  2862. throw new IllegalStateException(
  2863. "Multiple default rows in header");
  2864. }
  2865. }
  2866. }
  2867. }
  2868. @Override
  2869. protected void readDesign(Element tableSectionElement,
  2870. DesignContext designContext) {
  2871. super.readDesign(tableSectionElement, designContext);
  2872. if (defaultRow == null && !rows.isEmpty()) {
  2873. grid.setDefaultHeaderRow(rows.get(0));
  2874. }
  2875. }
  2876. }
  2877. /**
  2878. * Represents a header row in Grid.
  2879. */
  2880. @Deprecated
  2881. public static class HeaderRow extends StaticSection.StaticRow<HeaderCell> {
  2882. protected HeaderRow(StaticSection<?> section) {
  2883. super(section);
  2884. }
  2885. private void setDefaultRow(boolean value) {
  2886. getRowState().defaultRow = value;
  2887. }
  2888. @Override
  2889. protected HeaderCell createCell() {
  2890. return new HeaderCell(this);
  2891. }
  2892. @Override
  2893. protected String getCellTagName() {
  2894. return "th";
  2895. }
  2896. @Override
  2897. protected void writeDesign(Element trElement,
  2898. DesignContext designContext) {
  2899. super.writeDesign(trElement, designContext);
  2900. if (section.grid.getDefaultHeaderRow() == this) {
  2901. DesignAttributeHandler.writeAttribute("default",
  2902. trElement.attributes(), true, null, boolean.class,
  2903. designContext);
  2904. }
  2905. }
  2906. @Override
  2907. protected void readDesign(Element trElement,
  2908. DesignContext designContext) {
  2909. super.readDesign(trElement, designContext);
  2910. boolean defaultRow = DesignAttributeHandler.readAttribute("default",
  2911. trElement.attributes(), false, boolean.class);
  2912. if (defaultRow) {
  2913. section.grid.setDefaultHeaderRow(this);
  2914. }
  2915. }
  2916. }
  2917. /**
  2918. * Represents a header cell in Grid. Can be a merged cell for multiple
  2919. * columns.
  2920. */
  2921. @Deprecated
  2922. public static class HeaderCell extends StaticSection.StaticCell {
  2923. protected HeaderCell(HeaderRow row) {
  2924. super(row);
  2925. }
  2926. }
  2927. /**
  2928. * Represents the footer section of a Grid. By default Footer is not
  2929. * visible.
  2930. */
  2931. @Deprecated
  2932. protected static class Footer extends StaticSection<FooterRow> {
  2933. private final GridStaticSectionState footerState = new GridStaticSectionState();
  2934. protected Footer(Grid grid) {
  2935. this.grid = grid;
  2936. grid.getState(true).footer = footerState;
  2937. }
  2938. @Override
  2939. protected GridStaticSectionState getSectionState() {
  2940. return footerState;
  2941. }
  2942. @Override
  2943. protected FooterRow createRow() {
  2944. return new FooterRow(this);
  2945. }
  2946. @Override
  2947. protected void sanityCheck() throws IllegalStateException {
  2948. super.sanityCheck();
  2949. }
  2950. }
  2951. /**
  2952. * Represents a footer row in Grid.
  2953. */
  2954. @Deprecated
  2955. public static class FooterRow extends StaticSection.StaticRow<FooterCell> {
  2956. protected FooterRow(StaticSection<?> section) {
  2957. super(section);
  2958. }
  2959. @Override
  2960. protected FooterCell createCell() {
  2961. return new FooterCell(this);
  2962. }
  2963. @Override
  2964. protected String getCellTagName() {
  2965. return "td";
  2966. }
  2967. }
  2968. /**
  2969. * Represents a footer cell in Grid.
  2970. */
  2971. @Deprecated
  2972. public static class FooterCell extends StaticSection.StaticCell {
  2973. protected FooterCell(FooterRow row) {
  2974. super(row);
  2975. }
  2976. }
  2977. /**
  2978. * A column in the grid. Can be obtained by calling
  2979. * {@link Grid#getColumn(Object propertyId)}.
  2980. */
  2981. @Deprecated
  2982. public static class Column implements Serializable {
  2983. /**
  2984. * The state of the column shared to the client
  2985. */
  2986. private final GridColumnState state;
  2987. /**
  2988. * The grid this column is associated with
  2989. */
  2990. private final Grid grid;
  2991. /**
  2992. * Backing property for column
  2993. */
  2994. private final Object propertyId;
  2995. private Converter<?, Object> converter;
  2996. /**
  2997. * A check for allowing the
  2998. * {@link #Column(Grid, GridColumnState, Object) constructor} to call
  2999. * {@link #setConverter(Converter)} with a <code>null</code>, even if
  3000. * model and renderer aren't compatible.
  3001. */
  3002. private boolean isFirstConverterAssignment = true;
  3003. /**
  3004. * Internally used constructor.
  3005. *
  3006. * @param grid
  3007. * The grid this column belongs to. Should not be null.
  3008. * @param state
  3009. * the shared state of this column
  3010. * @param propertyId
  3011. * the backing property id for this column
  3012. */
  3013. Column(Grid grid, GridColumnState state, Object propertyId) {
  3014. this.grid = grid;
  3015. this.state = state;
  3016. this.propertyId = propertyId;
  3017. internalSetRenderer(new TextRenderer());
  3018. }
  3019. /**
  3020. * Returns the serializable state of this column that is sent to the
  3021. * client side connector.
  3022. *
  3023. * @return the internal state of the column
  3024. */
  3025. GridColumnState getState() {
  3026. return state;
  3027. }
  3028. /**
  3029. * Returns the property id for the backing property of this Column.
  3030. *
  3031. * @return property id
  3032. */
  3033. public Object getPropertyId() {
  3034. return propertyId;
  3035. }
  3036. /**
  3037. * Returns the caption of the header. By default the header caption is
  3038. * the property id of the column.
  3039. *
  3040. * @return the text in the default row of header.
  3041. *
  3042. * @throws IllegalStateException
  3043. * if the column no longer is attached to the grid
  3044. */
  3045. public String getHeaderCaption() throws IllegalStateException {
  3046. checkColumnIsAttached();
  3047. return state.headerCaption;
  3048. }
  3049. /**
  3050. * Sets the caption of the header. This caption is also used as the
  3051. * hiding toggle caption, unless it is explicitly set via
  3052. * {@link #setHidingToggleCaption(String)}.
  3053. *
  3054. * @param caption
  3055. * the text to show in the caption
  3056. * @return the column itself
  3057. *
  3058. * @throws IllegalStateException
  3059. * if the column is no longer attached to any grid
  3060. */
  3061. public Column setHeaderCaption(String caption)
  3062. throws IllegalStateException {
  3063. checkColumnIsAttached();
  3064. if (caption == null) {
  3065. caption = ""; // Render null as empty
  3066. }
  3067. state.headerCaption = caption;
  3068. HeaderRow row = grid.getHeader().getDefaultRow();
  3069. if (row != null) {
  3070. row.getCell(grid.getPropertyIdByColumnId(state.id))
  3071. .setText(caption);
  3072. }
  3073. return this;
  3074. }
  3075. /**
  3076. * Gets the caption of the hiding toggle for this column.
  3077. *
  3078. * @since 7.5.0
  3079. * @see #setHidingToggleCaption(String)
  3080. * @return the caption for the hiding toggle for this column
  3081. * @throws IllegalStateException
  3082. * if the column is no longer attached to any grid
  3083. */
  3084. public String getHidingToggleCaption() throws IllegalStateException {
  3085. checkColumnIsAttached();
  3086. return state.hidingToggleCaption;
  3087. }
  3088. /**
  3089. * Sets the caption of the hiding toggle for this column. Shown in the
  3090. * toggle for this column in the grid's sidebar when the column is
  3091. * {@link #isHidable() hidable}.
  3092. * <p>
  3093. * The default value is <code>null</code>, and in that case the column's
  3094. * {@link #getHeaderCaption() header caption} is used.
  3095. * <p>
  3096. * <em>NOTE:</em> setting this to empty string might cause the hiding
  3097. * toggle to not render correctly.
  3098. *
  3099. * @since 7.5.0
  3100. * @param hidingToggleCaption
  3101. * the text to show in the column hiding toggle
  3102. * @return the column itself
  3103. * @throws IllegalStateException
  3104. * if the column is no longer attached to any grid
  3105. */
  3106. public Column setHidingToggleCaption(String hidingToggleCaption)
  3107. throws IllegalStateException {
  3108. checkColumnIsAttached();
  3109. state.hidingToggleCaption = hidingToggleCaption;
  3110. grid.markAsDirty();
  3111. return this;
  3112. }
  3113. /**
  3114. * Returns the width (in pixels). By default a column is 100px wide.
  3115. *
  3116. * @return the width in pixels of the column
  3117. * @throws IllegalStateException
  3118. * if the column is no longer attached to any grid
  3119. */
  3120. public double getWidth() throws IllegalStateException {
  3121. checkColumnIsAttached();
  3122. return state.width;
  3123. }
  3124. /**
  3125. * Sets the width (in pixels).
  3126. * <p>
  3127. * This overrides any configuration set by any of
  3128. * {@link #setExpandRatio(int)}, {@link #setMinimumWidth(double)} or
  3129. * {@link #setMaximumWidth(double)}.
  3130. *
  3131. * @param pixelWidth
  3132. * the new pixel width of the column
  3133. * @return the column itself
  3134. *
  3135. * @throws IllegalStateException
  3136. * if the column is no longer attached to any grid
  3137. * @throws IllegalArgumentException
  3138. * thrown if pixel width is less than zero
  3139. */
  3140. public Column setWidth(double pixelWidth)
  3141. throws IllegalStateException, IllegalArgumentException {
  3142. checkColumnIsAttached();
  3143. if (pixelWidth < 0) {
  3144. throw new IllegalArgumentException(
  3145. "Pixel width should be greated than 0 (in " + toString()
  3146. + ")");
  3147. }
  3148. if (state.width != pixelWidth) {
  3149. state.width = pixelWidth;
  3150. grid.markAsDirty();
  3151. grid.fireColumnResizeEvent(this, false);
  3152. }
  3153. return this;
  3154. }
  3155. /**
  3156. * Returns whether this column has an undefined width.
  3157. *
  3158. * @since 7.6
  3159. * @return whether the width is undefined
  3160. * @throws IllegalStateException
  3161. * if the column is no longer attached to any grid
  3162. */
  3163. public boolean isWidthUndefined() {
  3164. checkColumnIsAttached();
  3165. return state.width < 0;
  3166. }
  3167. /**
  3168. * Marks the column width as undefined. An undefined width means the
  3169. * grid is free to resize the column based on the cell contents and
  3170. * available space in the grid.
  3171. *
  3172. * @return the column itself
  3173. */
  3174. public Column setWidthUndefined() {
  3175. checkColumnIsAttached();
  3176. if (!isWidthUndefined()) {
  3177. state.width = -1;
  3178. grid.markAsDirty();
  3179. grid.fireColumnResizeEvent(this, false);
  3180. }
  3181. return this;
  3182. }
  3183. /**
  3184. * Checks if column is attached and throws an
  3185. * {@link IllegalStateException} if it is not.
  3186. *
  3187. * @throws IllegalStateException
  3188. * if the column is no longer attached to any grid
  3189. */
  3190. protected void checkColumnIsAttached() throws IllegalStateException {
  3191. if (grid.getColumnByColumnId(state.id) == null) {
  3192. throw new IllegalStateException("Column no longer exists.");
  3193. }
  3194. }
  3195. /**
  3196. * Sets this column as the last frozen column in its grid.
  3197. *
  3198. * @return the column itself
  3199. *
  3200. * @throws IllegalArgumentException
  3201. * if the column is no longer attached to any grid
  3202. * @see Grid#setFrozenColumnCount(int)
  3203. */
  3204. public Column setLastFrozenColumn() {
  3205. checkColumnIsAttached();
  3206. grid.setFrozenColumnCount(
  3207. grid.getState(false).columnOrder.indexOf(getState().id)
  3208. + 1);
  3209. return this;
  3210. }
  3211. /**
  3212. * Sets the renderer for this column.
  3213. * <p>
  3214. * If a suitable converter isn't defined explicitly, the session
  3215. * converter factory is used to find a compatible converter.
  3216. *
  3217. * @param renderer
  3218. * the renderer to use
  3219. * @return the column itself
  3220. *
  3221. * @throws IllegalArgumentException
  3222. * if no compatible converter could be found
  3223. *
  3224. * @see VaadinSession#getConverterFactory()
  3225. * @see ConverterUtil#getConverter(Class, Class, VaadinSession)
  3226. * @see #setConverter(Converter)
  3227. */
  3228. public Column setRenderer(Renderer<?> renderer) {
  3229. if (!internalSetRenderer(renderer)) {
  3230. throw new IllegalArgumentException(
  3231. "Could not find a converter for converting from the model type "
  3232. + getModelType()
  3233. + " to the renderer presentation type "
  3234. + renderer.getPresentationType() + " (in "
  3235. + toString() + ")");
  3236. }
  3237. return this;
  3238. }
  3239. /**
  3240. * Sets the renderer for this column and the converter used to convert
  3241. * from the property value type to the renderer presentation type.
  3242. *
  3243. * @param renderer
  3244. * the renderer to use, cannot be null
  3245. * @param converter
  3246. * the converter to use
  3247. * @return the column itself
  3248. *
  3249. * @throws IllegalArgumentException
  3250. * if the renderer is already associated with a grid column
  3251. */
  3252. public <T> Column setRenderer(Renderer<T> renderer,
  3253. Converter<? extends T, ?> converter) {
  3254. if (renderer.getParent() != null) {
  3255. throw new IllegalArgumentException(
  3256. "Cannot set a renderer that is already connected to a grid column (in "
  3257. + toString() + ")");
  3258. }
  3259. if (getRenderer() != null) {
  3260. grid.removeExtension(getRenderer());
  3261. }
  3262. grid.addRenderer(renderer);
  3263. state.rendererConnector = renderer;
  3264. setConverter(converter);
  3265. return this;
  3266. }
  3267. /**
  3268. * Sets the converter used to convert from the property value type to
  3269. * the renderer presentation type.
  3270. *
  3271. * @param converter
  3272. * the converter to use, or {@code null} to not use any
  3273. * converters
  3274. * @return the column itself
  3275. *
  3276. * @throws IllegalArgumentException
  3277. * if the types are not compatible
  3278. */
  3279. public Column setConverter(Converter<?, ?> converter)
  3280. throws IllegalArgumentException {
  3281. Class<?> modelType = getModelType();
  3282. if (converter != null) {
  3283. if (!converter.getModelType().isAssignableFrom(modelType)) {
  3284. throw new IllegalArgumentException(
  3285. "The converter model type "
  3286. + converter.getModelType()
  3287. + " is not compatible with the property type "
  3288. + modelType + " (in " + toString() + ")");
  3289. } else if (!getRenderer().getPresentationType()
  3290. .isAssignableFrom(converter.getPresentationType())) {
  3291. throw new IllegalArgumentException(
  3292. "The converter presentation type "
  3293. + converter.getPresentationType()
  3294. + " is not compatible with the renderer presentation type "
  3295. + getRenderer().getPresentationType()
  3296. + " (in " + toString() + ")");
  3297. }
  3298. } else {
  3299. /*
  3300. * Since the converter is null (i.e. will be removed), we need
  3301. * to know that the renderer and model are compatible. If not,
  3302. * we can't allow for this to happen.
  3303. *
  3304. * The constructor is allowed to call this method with null
  3305. * without any compatibility checks, therefore we have a special
  3306. * case for it.
  3307. */
  3308. Class<?> rendererPresentationType = getRenderer()
  3309. .getPresentationType();
  3310. if (!isFirstConverterAssignment && !rendererPresentationType
  3311. .isAssignableFrom(modelType)) {
  3312. throw new IllegalArgumentException(
  3313. "Cannot remove converter, "
  3314. + "as renderer's presentation type "
  3315. + rendererPresentationType.getName()
  3316. + " and column's " + "model "
  3317. + modelType.getName() + " type aren't "
  3318. + "directly compatible with each other (in "
  3319. + toString() + ")");
  3320. }
  3321. }
  3322. isFirstConverterAssignment = false;
  3323. @SuppressWarnings("unchecked")
  3324. Converter<?, Object> castConverter = (Converter<?, Object>) converter;
  3325. this.converter = castConverter;
  3326. return this;
  3327. }
  3328. /**
  3329. * Returns the renderer instance used by this column.
  3330. *
  3331. * @return the renderer
  3332. */
  3333. public Renderer<?> getRenderer() {
  3334. return (Renderer<?>) getState().rendererConnector;
  3335. }
  3336. /**
  3337. * Returns the converter instance used by this column.
  3338. *
  3339. * @return the converter
  3340. */
  3341. public Converter<?, ?> getConverter() {
  3342. return converter;
  3343. }
  3344. private <T> boolean internalSetRenderer(Renderer<T> renderer) {
  3345. Converter<? extends T, ?> converter;
  3346. if (isCompatibleWithProperty(renderer, getConverter())) {
  3347. // Use the existing converter (possibly none) if types
  3348. // compatible
  3349. converter = (Converter<? extends T, ?>) getConverter();
  3350. } else {
  3351. converter = ConverterUtil.getConverter(
  3352. renderer.getPresentationType(), getModelType(),
  3353. getSession());
  3354. }
  3355. setRenderer(renderer, converter);
  3356. return isCompatibleWithProperty(renderer, converter);
  3357. }
  3358. private VaadinSession getSession() {
  3359. UI ui = grid.getUI();
  3360. return ui != null ? ui.getSession() : null;
  3361. }
  3362. private boolean isCompatibleWithProperty(Renderer<?> renderer,
  3363. Converter<?, ?> converter) {
  3364. Class<?> type;
  3365. if (converter == null) {
  3366. type = getModelType();
  3367. } else {
  3368. type = converter.getPresentationType();
  3369. }
  3370. return renderer.getPresentationType().isAssignableFrom(type);
  3371. }
  3372. private Class<?> getModelType() {
  3373. return grid.getContainerDataSource()
  3374. .getType(grid.getPropertyIdByColumnId(state.id));
  3375. }
  3376. /**
  3377. * Sets whether this column is sortable by the user. The grid can be
  3378. * sorted by a sortable column by clicking or tapping the column's
  3379. * default header. Programmatic sorting using the Grid#sort methods is
  3380. * not affected by this setting.
  3381. *
  3382. * @param sortable
  3383. * {@code true} if the user should be able to sort the
  3384. * column, {@code false} otherwise
  3385. * @return the column itself
  3386. *
  3387. * @throws IllegalStateException
  3388. * if the data source of the Grid does not implement
  3389. * {@link Sortable}
  3390. * @throws IllegalStateException
  3391. * if the data source does not support sorting by the
  3392. * property associated with this column
  3393. */
  3394. public Column setSortable(boolean sortable) {
  3395. checkColumnIsAttached();
  3396. if (sortable) {
  3397. if (!(grid.datasource instanceof Sortable)) {
  3398. throw new IllegalStateException("Can't set column "
  3399. + toString()
  3400. + " sortable. The Container of Grid does not implement Sortable");
  3401. } else if (!((Sortable) grid.datasource)
  3402. .getSortableContainerPropertyIds()
  3403. .contains(propertyId)) {
  3404. throw new IllegalStateException("Can't set column "
  3405. + toString()
  3406. + " sortable. Container doesn't support sorting by property "
  3407. + propertyId);
  3408. }
  3409. }
  3410. state.sortable = sortable;
  3411. grid.markAsDirty();
  3412. return this;
  3413. }
  3414. /**
  3415. * Returns whether the user can sort the grid by this column.
  3416. * <p>
  3417. * <em>Note:</em> it is possible to sort by this column programmatically
  3418. * using the Grid#sort methods regardless of the returned value.
  3419. *
  3420. * @return {@code true} if the column is sortable by the user,
  3421. * {@code false} otherwise
  3422. */
  3423. public boolean isSortable() {
  3424. return state.sortable;
  3425. }
  3426. @Override
  3427. public String toString() {
  3428. return getClass().getSimpleName() + "[propertyId:"
  3429. + grid.getPropertyIdByColumnId(state.id) + "]";
  3430. }
  3431. /**
  3432. * Sets the ratio with which the column expands.
  3433. * <p>
  3434. * By default, all columns expand equally (treated as if all of them had
  3435. * an expand ratio of 1). Once at least one column gets a defined expand
  3436. * ratio, the implicit expand ratio is removed, and only the defined
  3437. * expand ratios are taken into account.
  3438. * <p>
  3439. * If a column has a defined width ({@link #setWidth(double)}), it
  3440. * overrides this method's effects.
  3441. * <p>
  3442. * <em>Example:</em> A grid with three columns, with expand ratios 0, 1
  3443. * and 2, respectively. The column with a <strong>ratio of 0 is exactly
  3444. * as wide as its contents requires</strong>. The column with a ratio of
  3445. * 1 is as wide as it needs, <strong>plus a third of any excess
  3446. * space</strong>, because we have 3 parts total, and this column
  3447. * reserves only one of those. The column with a ratio of 2, is as wide
  3448. * as it needs to be, <strong>plus two thirds</strong> of the excess
  3449. * width.
  3450. *
  3451. * @param expandRatio
  3452. * the expand ratio of this column. {@code 0} to not have it
  3453. * expand at all. A negative number to clear the expand
  3454. * value.
  3455. * @throws IllegalStateException
  3456. * if the column is no longer attached to any grid
  3457. * @see #setWidth(double)
  3458. */
  3459. public Column setExpandRatio(int expandRatio)
  3460. throws IllegalStateException {
  3461. checkColumnIsAttached();
  3462. getState().expandRatio = expandRatio;
  3463. grid.markAsDirty();
  3464. return this;
  3465. }
  3466. /**
  3467. * Returns the column's expand ratio.
  3468. *
  3469. * @return the column's expand ratio
  3470. * @see #setExpandRatio(int)
  3471. */
  3472. public int getExpandRatio() {
  3473. return getState().expandRatio;
  3474. }
  3475. /**
  3476. * Clears the expand ratio for this column.
  3477. * <p>
  3478. * Equal to calling {@link #setExpandRatio(int) setExpandRatio(-1)}
  3479. *
  3480. * @throws IllegalStateException
  3481. * if the column is no longer attached to any grid
  3482. */
  3483. public Column clearExpandRatio() throws IllegalStateException {
  3484. return setExpandRatio(-1);
  3485. }
  3486. /**
  3487. * Sets the minimum width for this column.
  3488. * <p>
  3489. * This defines the minimum guaranteed pixel width of the column
  3490. * <em>when it is set to expand</em>.
  3491. *
  3492. * @throws IllegalStateException
  3493. * if the column is no longer attached to any grid
  3494. * @see #setExpandRatio(int)
  3495. */
  3496. public Column setMinimumWidth(double pixels)
  3497. throws IllegalStateException {
  3498. checkColumnIsAttached();
  3499. final double maxwidth = getMaximumWidth();
  3500. if (pixels >= 0 && pixels > maxwidth && maxwidth >= 0) {
  3501. throw new IllegalArgumentException("New minimum width ("
  3502. + pixels + ") was greater than maximum width ("
  3503. + maxwidth + ")");
  3504. }
  3505. getState().minWidth = pixels;
  3506. grid.markAsDirty();
  3507. return this;
  3508. }
  3509. /**
  3510. * Return the minimum width for this column.
  3511. *
  3512. * @return the minimum width for this column
  3513. * @see #setMinimumWidth(double)
  3514. */
  3515. public double getMinimumWidth() {
  3516. return getState().minWidth;
  3517. }
  3518. /**
  3519. * Sets the maximum width for this column.
  3520. * <p>
  3521. * This defines the maximum allowed pixel width of the column <em>when
  3522. * it is set to expand</em>.
  3523. *
  3524. * @param pixels
  3525. * the maximum width
  3526. * @throws IllegalStateException
  3527. * if the column is no longer attached to any grid
  3528. * @see #setExpandRatio(int)
  3529. */
  3530. public Column setMaximumWidth(double pixels) {
  3531. checkColumnIsAttached();
  3532. final double minwidth = getMinimumWidth();
  3533. if (pixels >= 0 && pixels < minwidth && minwidth >= 0) {
  3534. throw new IllegalArgumentException("New maximum width ("
  3535. + pixels + ") was less than minimum width (" + minwidth
  3536. + ")");
  3537. }
  3538. getState().maxWidth = pixels;
  3539. grid.markAsDirty();
  3540. return this;
  3541. }
  3542. /**
  3543. * Returns the maximum width for this column.
  3544. *
  3545. * @return the maximum width for this column
  3546. * @see #setMaximumWidth(double)
  3547. */
  3548. public double getMaximumWidth() {
  3549. return getState().maxWidth;
  3550. }
  3551. /**
  3552. * Sets whether the properties corresponding to this column should be
  3553. * editable when the item editor is active. By default columns are
  3554. * editable.
  3555. * <p>
  3556. * Values in non-editable columns are currently not displayed when the
  3557. * editor is active, but this will probably change in the future. They
  3558. * are not automatically assigned an editor field and, if one is
  3559. * manually assigned, it is not used. Columns that cannot (or should
  3560. * not) be edited even in principle should be set non-editable.
  3561. *
  3562. * @param editable
  3563. * {@code true} if this column should be editable,
  3564. * {@code false} otherwise
  3565. * @return this column
  3566. *
  3567. * @throws IllegalStateException
  3568. * if the editor is currently active
  3569. *
  3570. * @see Grid#editItem(Object)
  3571. * @see Grid#isEditorActive()
  3572. */
  3573. public Column setEditable(boolean editable) {
  3574. checkColumnIsAttached();
  3575. if (grid.isEditorActive()) {
  3576. throw new IllegalStateException(
  3577. "Cannot change column editable status while the editor is active");
  3578. }
  3579. getState().editable = editable;
  3580. grid.markAsDirty();
  3581. return this;
  3582. }
  3583. /**
  3584. * Returns whether the properties corresponding to this column should be
  3585. * editable when the item editor is active.
  3586. *
  3587. * @return {@code true} if this column is editable, {@code false}
  3588. * otherwise
  3589. *
  3590. * @see Grid#editItem(Object)
  3591. * @see #setEditable(boolean)
  3592. */
  3593. public boolean isEditable() {
  3594. return getState().editable;
  3595. }
  3596. /**
  3597. * Sets the field component used to edit the properties in this column
  3598. * when the item editor is active. If an item has not been set, then the
  3599. * binding is postponed until the item is set using
  3600. * {@link #editItem(Object)}.
  3601. * <p>
  3602. * Setting the field to <code>null</code> clears any previously set
  3603. * field, causing a new field to be created the next time the item
  3604. * editor is opened.
  3605. *
  3606. * @param editor
  3607. * the editor field
  3608. * @return this column
  3609. */
  3610. public Column setEditorField(Field<?> editor) {
  3611. grid.setEditorField(getPropertyId(), editor);
  3612. return this;
  3613. }
  3614. /**
  3615. * Returns the editor field used to edit the properties in this column
  3616. * when the item editor is active. Returns null if the column is not
  3617. * {@link Column#isEditable() editable}.
  3618. * <p>
  3619. * When {@link #editItem(Object) editItem} is called, fields are
  3620. * automatically created and bound for any unbound properties.
  3621. * <p>
  3622. * Getting a field before the editor has been opened depends on special
  3623. * support from the {@link FieldGroup} in use. Using this method with a
  3624. * user-provided <code>FieldGroup</code> might cause
  3625. * {@link FieldGroup.BindException BindException} to be thrown.
  3626. *
  3627. * @return the bound field; or <code>null</code> if the respective
  3628. * column is not editable
  3629. *
  3630. * @throws IllegalArgumentException
  3631. * if there is no column for the provided property id
  3632. * @throws FieldGroup.BindException
  3633. * if no field has been configured and there is a problem
  3634. * building or binding
  3635. */
  3636. public Field<?> getEditorField() {
  3637. return grid.getEditorField(getPropertyId());
  3638. }
  3639. /**
  3640. * Hides or shows the column. By default columns are visible before
  3641. * explicitly hiding them.
  3642. *
  3643. * @since 7.5.0
  3644. * @param hidden
  3645. * <code>true</code> to hide the column, <code>false</code>
  3646. * to show
  3647. * @return this column
  3648. */
  3649. public Column setHidden(boolean hidden) {
  3650. if (hidden != getState().hidden) {
  3651. getState().hidden = hidden;
  3652. grid.markAsDirty();
  3653. grid.fireColumnVisibilityChangeEvent(this, hidden, false);
  3654. }
  3655. return this;
  3656. }
  3657. /**
  3658. * Returns whether this column is hidden. Default is {@code false}.
  3659. *
  3660. * @since 7.5.0
  3661. * @return <code>true</code> if the column is currently hidden,
  3662. * <code>false</code> otherwise
  3663. */
  3664. public boolean isHidden() {
  3665. return getState().hidden;
  3666. }
  3667. /**
  3668. * Sets whether this column can be hidden by the user. Hidable columns
  3669. * can be hidden and shown via the sidebar menu.
  3670. *
  3671. * @since 7.5.0
  3672. * @param hidable
  3673. * <code>true</code> if the column may be hidable by the user
  3674. * via UI interaction
  3675. * @return this column
  3676. */
  3677. public Column setHidable(boolean hidable) {
  3678. if (hidable != getState().hidable) {
  3679. getState().hidable = hidable;
  3680. grid.markAsDirty();
  3681. }
  3682. return this;
  3683. }
  3684. /**
  3685. * Returns whether this column can be hidden by the user. Default is
  3686. * {@code false}.
  3687. * <p>
  3688. * <em>Note:</em> the column can be programmatically hidden using
  3689. * {@link #setHidden(boolean)} regardless of the returned value.
  3690. *
  3691. * @since 7.5.0
  3692. * @return <code>true</code> if the user can hide the column,
  3693. * <code>false</code> if not
  3694. */
  3695. public boolean isHidable() {
  3696. return getState().hidable;
  3697. }
  3698. /**
  3699. * Sets whether this column can be resized by the user.
  3700. *
  3701. * @since 7.6
  3702. * @param resizable
  3703. * {@code true} if this column should be resizable,
  3704. * {@code false} otherwise
  3705. */
  3706. public Column setResizable(boolean resizable) {
  3707. if (resizable != getState().resizable) {
  3708. getState().resizable = resizable;
  3709. grid.markAsDirty();
  3710. }
  3711. return this;
  3712. }
  3713. /**
  3714. * Returns whether this column can be resized by the user. Default is
  3715. * {@code true}.
  3716. * <p>
  3717. * <em>Note:</em> the column can be programmatically resized using
  3718. * {@link #setWidth(double)} and {@link #setWidthUndefined()} regardless
  3719. * of the returned value.
  3720. *
  3721. * @since 7.6
  3722. * @return {@code true} if this column is resizable, {@code false}
  3723. * otherwise
  3724. */
  3725. public boolean isResizable() {
  3726. return getState().resizable;
  3727. }
  3728. /**
  3729. * Writes the design attributes for this column into given element.
  3730. *
  3731. * @since 7.5.0
  3732. *
  3733. * @param design
  3734. * Element to write attributes into
  3735. *
  3736. * @param designContext
  3737. * the design context
  3738. */
  3739. protected void writeDesign(Element design,
  3740. DesignContext designContext) {
  3741. Attributes attributes = design.attributes();
  3742. GridColumnState def = new GridColumnState();
  3743. DesignAttributeHandler.writeAttribute("property-id", attributes,
  3744. getPropertyId(), null, Object.class, designContext);
  3745. // Sortable is a special attribute that depends on the container.
  3746. DesignAttributeHandler.writeAttribute("sortable", attributes,
  3747. isSortable(), null, boolean.class, designContext);
  3748. DesignAttributeHandler.writeAttribute("editable", attributes,
  3749. isEditable(), def.editable, boolean.class, designContext);
  3750. DesignAttributeHandler.writeAttribute("resizable", attributes,
  3751. isResizable(), def.resizable, boolean.class, designContext);
  3752. DesignAttributeHandler.writeAttribute("hidable", attributes,
  3753. isHidable(), def.hidable, boolean.class, designContext);
  3754. DesignAttributeHandler.writeAttribute("hidden", attributes,
  3755. isHidden(), def.hidden, boolean.class, designContext);
  3756. DesignAttributeHandler.writeAttribute("hiding-toggle-caption",
  3757. attributes, getHidingToggleCaption(), null, String.class,
  3758. designContext);
  3759. DesignAttributeHandler.writeAttribute("width", attributes,
  3760. getWidth(), def.width, Double.class, designContext);
  3761. DesignAttributeHandler.writeAttribute("min-width", attributes,
  3762. getMinimumWidth(), def.minWidth, Double.class,
  3763. designContext);
  3764. DesignAttributeHandler.writeAttribute("max-width", attributes,
  3765. getMaximumWidth(), def.maxWidth, Double.class,
  3766. designContext);
  3767. DesignAttributeHandler.writeAttribute("expand", attributes,
  3768. getExpandRatio(), def.expandRatio, Integer.class,
  3769. designContext);
  3770. }
  3771. /**
  3772. * Reads the design attributes for this column from given element.
  3773. *
  3774. * @since 7.5.0
  3775. * @param design
  3776. * Element to read attributes from
  3777. * @param designContext
  3778. * the design context
  3779. */
  3780. protected void readDesign(Element design, DesignContext designContext) {
  3781. Attributes attributes = design.attributes();
  3782. if (design.hasAttr("sortable")) {
  3783. setSortable(DesignAttributeHandler.readAttribute("sortable",
  3784. attributes, boolean.class));
  3785. }
  3786. if (design.hasAttr("editable")) {
  3787. setEditable(DesignAttributeHandler.readAttribute("editable",
  3788. attributes, boolean.class));
  3789. }
  3790. if (design.hasAttr("resizable")) {
  3791. setResizable(DesignAttributeHandler.readAttribute("resizable",
  3792. attributes, boolean.class));
  3793. }
  3794. if (design.hasAttr("hidable")) {
  3795. setHidable(DesignAttributeHandler.readAttribute("hidable",
  3796. attributes, boolean.class));
  3797. }
  3798. if (design.hasAttr("hidden")) {
  3799. setHidden(DesignAttributeHandler.readAttribute("hidden",
  3800. attributes, boolean.class));
  3801. }
  3802. if (design.hasAttr("hiding-toggle-caption")) {
  3803. setHidingToggleCaption(DesignAttributeHandler.readAttribute(
  3804. "hiding-toggle-caption", attributes, String.class));
  3805. }
  3806. // Read size info where necessary.
  3807. if (design.hasAttr("width")) {
  3808. setWidth(DesignAttributeHandler.readAttribute("width",
  3809. attributes, Double.class));
  3810. }
  3811. if (design.hasAttr("min-width")) {
  3812. setMinimumWidth(DesignAttributeHandler
  3813. .readAttribute("min-width", attributes, Double.class));
  3814. }
  3815. if (design.hasAttr("max-width")) {
  3816. setMaximumWidth(DesignAttributeHandler
  3817. .readAttribute("max-width", attributes, Double.class));
  3818. }
  3819. if (design.hasAttr("expand")) {
  3820. if (design.attr("expand").isEmpty()) {
  3821. setExpandRatio(1);
  3822. } else {
  3823. setExpandRatio(DesignAttributeHandler.readAttribute(
  3824. "expand", attributes, Integer.class));
  3825. }
  3826. }
  3827. }
  3828. }
  3829. /**
  3830. * An abstract base class for server-side {@link Renderer Grid renderers}.
  3831. * This class currently extends the AbstractExtension superclass, but this
  3832. * fact should be regarded as an implementation detail and subject to change
  3833. * in a future major or minor Vaadin revision.
  3834. *
  3835. * @param <T>
  3836. * the type this renderer knows how to present
  3837. */
  3838. @Deprecated
  3839. public abstract static class AbstractRenderer<T>
  3840. extends AbstractGridExtension implements Renderer<T> {
  3841. private final Class<T> presentationType;
  3842. private final String nullRepresentation;
  3843. protected AbstractRenderer(Class<T> presentationType,
  3844. String nullRepresentation) {
  3845. this.presentationType = presentationType;
  3846. this.nullRepresentation = nullRepresentation;
  3847. }
  3848. protected AbstractRenderer(Class<T> presentationType) {
  3849. this(presentationType, null);
  3850. }
  3851. /**
  3852. * This method is inherited from AbstractExtension but should never be
  3853. * called directly with an AbstractRenderer.
  3854. */
  3855. @Deprecated
  3856. @Override
  3857. protected Class<Grid> getSupportedParentType() {
  3858. return Grid.class;
  3859. }
  3860. /**
  3861. * This method is inherited from AbstractExtension but should never be
  3862. * called directly with an AbstractRenderer.
  3863. */
  3864. @Deprecated
  3865. @Override
  3866. protected void extend(AbstractClientConnector target) {
  3867. super.extend(target);
  3868. }
  3869. @Override
  3870. public Class<T> getPresentationType() {
  3871. return presentationType;
  3872. }
  3873. @Override
  3874. public JsonValue encode(T value) {
  3875. if (value == null) {
  3876. return encode(getNullRepresentation(), String.class);
  3877. } else {
  3878. return encode(value, getPresentationType());
  3879. }
  3880. }
  3881. /**
  3882. * Null representation for the renderer.
  3883. *
  3884. * @return a textual representation of {@code null}
  3885. */
  3886. protected String getNullRepresentation() {
  3887. return nullRepresentation;
  3888. }
  3889. /**
  3890. * Encodes the given value to JSON.
  3891. * <p>
  3892. * This is a helper method that can be invoked by an
  3893. * {@link #encode(Object) encode(T)} override if serializing a value of
  3894. * type other than {@link #getPresentationType() the presentation type}
  3895. * is desired. For instance, a {@code Renderer<Date>} could first turn a
  3896. * date value into a formatted string and return
  3897. * {@code encode(dateString, String.class)}.
  3898. *
  3899. * @param value
  3900. * the value to be encoded
  3901. * @param type
  3902. * the type of the value
  3903. * @return a JSON representation of the given value
  3904. */
  3905. protected <U> JsonValue encode(U value, Class<U> type) {
  3906. return JsonCodec
  3907. .encode(value, null, type, getUI().getConnectorTracker())
  3908. .getEncodedValue();
  3909. }
  3910. /**
  3911. * Converts and encodes the given data model property value using the
  3912. * given converter and renderer. This method is public only for testing
  3913. * purposes.
  3914. *
  3915. * @since 7.6
  3916. * @param renderer
  3917. * the renderer to use
  3918. * @param converter
  3919. * the converter to use
  3920. * @param modelValue
  3921. * the value to convert and encode
  3922. * @param locale
  3923. * the locale to use in conversion
  3924. * @return an encoded value ready to be sent to the client
  3925. */
  3926. public static <T> JsonValue encodeValue(Object modelValue,
  3927. Renderer<T> renderer, Converter<?, ?> converter,
  3928. Locale locale) {
  3929. Class<T> presentationType = renderer.getPresentationType();
  3930. T presentationValue;
  3931. if (converter == null) {
  3932. try {
  3933. presentationValue = presentationType.cast(modelValue);
  3934. } catch (ClassCastException e) {
  3935. if (presentationType == String.class) {
  3936. // If there is no converter, just fallback to using
  3937. // toString(). modelValue can't be null as
  3938. // Class.cast(null) will always succeed
  3939. presentationValue = (T) modelValue.toString();
  3940. } else {
  3941. throw new Converter.ConversionException(
  3942. "Unable to convert value of type "
  3943. + modelValue.getClass().getName()
  3944. + " to presentation type "
  3945. + presentationType.getName()
  3946. + ". No converter is set and the types are not compatible.");
  3947. }
  3948. }
  3949. } else {
  3950. assert presentationType
  3951. .isAssignableFrom(converter.getPresentationType());
  3952. @SuppressWarnings("unchecked")
  3953. Converter<T, Object> safeConverter = (Converter<T, Object>) converter;
  3954. presentationValue = safeConverter.convertToPresentation(
  3955. modelValue, safeConverter.getPresentationType(),
  3956. locale);
  3957. }
  3958. JsonValue encodedValue;
  3959. try {
  3960. encodedValue = renderer.encode(presentationValue);
  3961. } catch (Exception e) {
  3962. getLogger().log(Level.SEVERE, "Unable to encode data", e);
  3963. encodedValue = renderer.encode(null);
  3964. }
  3965. return encodedValue;
  3966. }
  3967. private static Logger getLogger() {
  3968. return Logger.getLogger(AbstractRenderer.class.getName());
  3969. }
  3970. }
  3971. /**
  3972. * An abstract base class for server-side Grid extensions.
  3973. * <p>
  3974. * Note: If the extension is an instance of {@link DataGenerator} it will
  3975. * automatically register itself to {@link RpcDataProviderExtension} of
  3976. * extended Grid. On remove this registration is automatically removed.
  3977. *
  3978. * @since 7.5
  3979. */
  3980. @Deprecated
  3981. public abstract static class AbstractGridExtension
  3982. extends AbstractExtension {
  3983. /**
  3984. * Constructs a new Grid extension.
  3985. */
  3986. public AbstractGridExtension() {
  3987. super();
  3988. }
  3989. /**
  3990. * Constructs a new Grid extension and extends given Grid.
  3991. *
  3992. * @param grid
  3993. * a grid instance
  3994. */
  3995. public AbstractGridExtension(Grid grid) {
  3996. super();
  3997. extend(grid);
  3998. }
  3999. @Override
  4000. protected void extend(AbstractClientConnector target) {
  4001. super.extend(target);
  4002. if (this instanceof DataGenerator) {
  4003. getParentGrid().datasourceExtension
  4004. .addDataGenerator((DataGenerator) this);
  4005. }
  4006. }
  4007. @Override
  4008. public void remove() {
  4009. if (this instanceof DataGenerator) {
  4010. getParentGrid().datasourceExtension
  4011. .removeDataGenerator((DataGenerator) this);
  4012. }
  4013. super.remove();
  4014. }
  4015. /**
  4016. * Gets the item id for a row key.
  4017. * <p>
  4018. * A key is used to identify a particular row on both a server and a
  4019. * client. This method can be used to get the item id for the row key
  4020. * that the client has sent.
  4021. *
  4022. * @param rowKey
  4023. * the row key for which to retrieve an item id
  4024. * @return the item id corresponding to {@code key}
  4025. */
  4026. protected Object getItemId(String rowKey) {
  4027. return getParentGrid().getKeyMapper().get(rowKey);
  4028. }
  4029. /**
  4030. * Gets the column for a column id.
  4031. * <p>
  4032. * An id is used to identify a particular column on both a server and a
  4033. * client. This method can be used to get the column for the column id
  4034. * that the client has sent.
  4035. *
  4036. * @param columnId
  4037. * the column id for which to retrieve a column
  4038. * @return the column corresponding to {@code columnId}
  4039. */
  4040. protected Column getColumn(String columnId) {
  4041. return getParentGrid().getColumnByColumnId(columnId);
  4042. }
  4043. /**
  4044. * Gets the parent Grid of the renderer.
  4045. *
  4046. * @return parent grid
  4047. * @throws IllegalStateException
  4048. * if parent is not Grid
  4049. */
  4050. protected Grid getParentGrid() {
  4051. if (getParent() instanceof Grid) {
  4052. Grid grid = (Grid) getParent();
  4053. return grid;
  4054. } else if (getParent() == null) {
  4055. throw new IllegalStateException(
  4056. "Renderer is not attached to any parent");
  4057. } else {
  4058. throw new IllegalStateException(
  4059. "Renderers can be used only with Grid. Extended "
  4060. + getParent().getClass().getSimpleName()
  4061. + " instead");
  4062. }
  4063. }
  4064. /**
  4065. * Resends the row data for given item id to the client.
  4066. *
  4067. * @since 7.6
  4068. * @param itemId
  4069. * row to refresh
  4070. */
  4071. protected void refreshRow(Object itemId) {
  4072. getParentGrid().datasourceExtension.updateRowData(itemId);
  4073. }
  4074. /**
  4075. * Informs the parent Grid that this Extension wants to add a child
  4076. * component to it.
  4077. *
  4078. * @since 7.6
  4079. * @param c
  4080. * component
  4081. */
  4082. protected void addComponentToGrid(Component c) {
  4083. getParentGrid().addComponent(c);
  4084. }
  4085. /**
  4086. * Informs the parent Grid that this Extension wants to remove a child
  4087. * component from it.
  4088. *
  4089. * @since 7.6
  4090. * @param c
  4091. * component
  4092. */
  4093. protected void removeComponentFromGrid(Component c) {
  4094. getParentGrid().removeComponent(c);
  4095. }
  4096. }
  4097. /**
  4098. * The data source attached to the grid
  4099. */
  4100. private Container.Indexed datasource;
  4101. /**
  4102. * Property id to column instance mapping
  4103. */
  4104. private final Map<Object, Column> columns = new HashMap<Object, Column>();
  4105. /**
  4106. * Key generator for column server-to-client communication
  4107. */
  4108. private final KeyMapper<Object> columnKeys = new KeyMapper<Object>();
  4109. /**
  4110. * The current sort order
  4111. */
  4112. private final List<SortOrder> sortOrder = new ArrayList<SortOrder>();
  4113. /**
  4114. * Property listener for listening to changes in data source properties.
  4115. */
  4116. private final PropertySetChangeListener propertyListener = new PropertySetChangeListener() {
  4117. @Override
  4118. public void containerPropertySetChange(PropertySetChangeEvent event) {
  4119. Collection<?> properties = new HashSet<Object>(
  4120. event.getContainer().getContainerPropertyIds());
  4121. // Find columns that need to be removed.
  4122. List<Column> removedColumns = new LinkedList<Column>();
  4123. for (Object propertyId : columns.keySet()) {
  4124. if (!properties.contains(propertyId)) {
  4125. removedColumns.add(getColumn(propertyId));
  4126. }
  4127. }
  4128. // Actually remove columns.
  4129. for (Column column : removedColumns) {
  4130. Object propertyId = column.getPropertyId();
  4131. internalRemoveColumn(propertyId);
  4132. columnKeys.remove(propertyId);
  4133. }
  4134. datasourceExtension.columnsRemoved(removedColumns);
  4135. // Add new columns
  4136. List<Column> addedColumns = new LinkedList<Column>();
  4137. for (Object propertyId : properties) {
  4138. if (!columns.containsKey(propertyId)) {
  4139. addedColumns.add(appendColumn(propertyId));
  4140. }
  4141. }
  4142. datasourceExtension.columnsAdded(addedColumns);
  4143. if (getFrozenColumnCount() > columns.size()) {
  4144. setFrozenColumnCount(columns.size());
  4145. }
  4146. // Unset sortable for non-sortable columns.
  4147. if (datasource instanceof Sortable) {
  4148. Collection<?> sortables = ((Sortable) datasource)
  4149. .getSortableContainerPropertyIds();
  4150. for (Object propertyId : columns.keySet()) {
  4151. Column column = columns.get(propertyId);
  4152. if (!sortables.contains(propertyId)
  4153. && column.isSortable()) {
  4154. column.setSortable(false);
  4155. }
  4156. }
  4157. }
  4158. }
  4159. };
  4160. private final ItemSetChangeListener editorClosingItemSetListener = new ItemSetChangeListener() {
  4161. @Override
  4162. public void containerItemSetChange(ItemSetChangeEvent event) {
  4163. cancelEditor();
  4164. }
  4165. };
  4166. private RpcDataProviderExtension datasourceExtension;
  4167. /**
  4168. * The selection model that is currently in use. Never <code>null</code>
  4169. * after the constructor has been run.
  4170. */
  4171. private SelectionModel selectionModel;
  4172. /**
  4173. * Used to know whether selection change events originate from the server or
  4174. * the client so the selection change handler knows whether the changes
  4175. * should be sent to the client.
  4176. */
  4177. private boolean applyingSelectionFromClient;
  4178. private final Header header = new Header(this);
  4179. private final Footer footer = new Footer(this);
  4180. private Object editedItemId = null;
  4181. private boolean editorActive = false;
  4182. /**
  4183. * True while the editor is storing the field values, i.e. commiting the
  4184. * field group.
  4185. */
  4186. private boolean editorSaving = false;
  4187. private FieldGroup editorFieldGroup = new CustomFieldGroup();
  4188. /**
  4189. * Poperty ID to Field mapping that stores editor fields set by
  4190. * {@link #setEditorField(Object, Field)}.
  4191. */
  4192. private Map<Object, Field<?>> editorFields = new HashMap<Object, Field<?>>();
  4193. private CellStyleGenerator cellStyleGenerator;
  4194. private RowStyleGenerator rowStyleGenerator;
  4195. private CellDescriptionGenerator cellDescriptionGenerator;
  4196. private RowDescriptionGenerator rowDescriptionGenerator;
  4197. /**
  4198. * <code>true</code> if Grid is using the internal IndexedContainer created
  4199. * in Grid() constructor, or <code>false</code> if the user has set their
  4200. * own Container.
  4201. *
  4202. * @see #setContainerDataSource(Indexed)
  4203. * @see #Grid()
  4204. */
  4205. private boolean defaultContainer = true;
  4206. private EditorErrorHandler editorErrorHandler = new DefaultEditorErrorHandler();
  4207. private DetailComponentManager detailComponentManager = null;
  4208. private Set<Component> extensionComponents = new HashSet<Component>();
  4209. private static final Method SELECTION_CHANGE_METHOD = ReflectTools
  4210. .findMethod(SelectionListener.class, "select",
  4211. SelectionEvent.class);
  4212. private static final Method SORT_ORDER_CHANGE_METHOD = ReflectTools
  4213. .findMethod(SortListener.class, "sort", SortEvent.class);
  4214. private static final Method COLUMN_REORDER_METHOD = ReflectTools.findMethod(
  4215. ColumnReorderListener.class, "columnReorder",
  4216. ColumnReorderEvent.class);
  4217. private static final Method COLUMN_RESIZE_METHOD = ReflectTools.findMethod(
  4218. ColumnResizeListener.class, "columnResize",
  4219. ColumnResizeEvent.class);
  4220. private static final Method COLUMN_VISIBILITY_METHOD = ReflectTools
  4221. .findMethod(ColumnVisibilityChangeListener.class,
  4222. "columnVisibilityChanged",
  4223. ColumnVisibilityChangeEvent.class);
  4224. /**
  4225. * Creates a new Grid with a new {@link IndexedContainer} as the data
  4226. * source.
  4227. */
  4228. public Grid() {
  4229. this(null, null);
  4230. }
  4231. /**
  4232. * Creates a new Grid using the given data source.
  4233. *
  4234. * @param dataSource
  4235. * the indexed container to use as a data source
  4236. */
  4237. public Grid(final Container.Indexed dataSource) {
  4238. this(null, dataSource);
  4239. }
  4240. /**
  4241. * Creates a new Grid with the given caption and a new
  4242. * {@link IndexedContainer} data source.
  4243. *
  4244. * @param caption
  4245. * the caption of the grid
  4246. */
  4247. public Grid(String caption) {
  4248. this(caption, null);
  4249. }
  4250. /**
  4251. * Creates a new Grid with the given caption and data source. If the data
  4252. * source is null, a new {@link IndexedContainer} will be used.
  4253. *
  4254. * @param caption
  4255. * the caption of the grid
  4256. * @param dataSource
  4257. * the indexed container to use as a data source
  4258. */
  4259. public Grid(String caption, Container.Indexed dataSource) {
  4260. if (dataSource == null) {
  4261. internalSetContainerDataSource(new IndexedContainer());
  4262. } else {
  4263. setContainerDataSource(dataSource);
  4264. }
  4265. setCaption(caption);
  4266. initGrid();
  4267. }
  4268. /**
  4269. * Grid initial setup
  4270. */
  4271. private void initGrid() {
  4272. setSelectionMode(getDefaultSelectionMode());
  4273. registerRpc(new GridServerRpc() {
  4274. @Override
  4275. public void sort(String[] columnIds, SortDirection[] directions,
  4276. boolean userOriginated) {
  4277. assert columnIds.length == directions.length;
  4278. List<SortOrder> order = new ArrayList<SortOrder>(
  4279. columnIds.length);
  4280. for (int i = 0; i < columnIds.length; i++) {
  4281. Object propertyId = getPropertyIdByColumnId(columnIds[i]);
  4282. order.add(new SortOrder(propertyId, directions[i]));
  4283. }
  4284. setSortOrder(order, userOriginated);
  4285. if (!order.equals(getSortOrder())) {
  4286. /*
  4287. * Actual sort order is not what the client expects. Make
  4288. * sure the client gets a state change event by clearing the
  4289. * diffstate and marking as dirty
  4290. */
  4291. ConnectorTracker connectorTracker = getUI()
  4292. .getConnectorTracker();
  4293. JsonObject diffState = connectorTracker
  4294. .getDiffState(Grid.this);
  4295. diffState.remove("sortColumns");
  4296. diffState.remove("sortDirs");
  4297. markAsDirty();
  4298. }
  4299. }
  4300. @Override
  4301. public void itemClick(String rowKey, String columnId,
  4302. MouseEventDetails details) {
  4303. Object itemId = getKeyMapper().get(rowKey);
  4304. Item item = datasource.getItem(itemId);
  4305. Object propertyId = getPropertyIdByColumnId(columnId);
  4306. fireEvent(new ItemClickEvent(Grid.this, item, itemId,
  4307. propertyId, details));
  4308. }
  4309. @Override
  4310. public void columnsReordered(List<String> newColumnOrder,
  4311. List<String> oldColumnOrder) {
  4312. final String diffStateKey = "columnOrder";
  4313. ConnectorTracker connectorTracker = getUI()
  4314. .getConnectorTracker();
  4315. JsonObject diffState = connectorTracker.getDiffState(Grid.this);
  4316. // discard the change if the columns have been reordered from
  4317. // the server side, as the server side is always right
  4318. if (getState(false).columnOrder.equals(oldColumnOrder)) {
  4319. // Don't mark as dirty since client has the state already
  4320. getState(false).columnOrder = newColumnOrder;
  4321. // write changes to diffState so that possible reverting the
  4322. // column order is sent to client
  4323. assert diffState
  4324. .hasKey(diffStateKey) : "Field name has changed";
  4325. Type type = null;
  4326. try {
  4327. type = (getState(false).getClass()
  4328. .getDeclaredField(diffStateKey)
  4329. .getGenericType());
  4330. } catch (NoSuchFieldException e) {
  4331. e.printStackTrace();
  4332. } catch (SecurityException e) {
  4333. e.printStackTrace();
  4334. }
  4335. EncodeResult encodeResult = JsonCodec.encode(
  4336. getState(false).columnOrder, diffState, type,
  4337. connectorTracker);
  4338. diffState.put(diffStateKey, encodeResult.getEncodedValue());
  4339. fireColumnReorderEvent(true);
  4340. } else {
  4341. // make sure the client is reverted to the order that the
  4342. // server thinks it is
  4343. diffState.remove(diffStateKey);
  4344. markAsDirty();
  4345. }
  4346. }
  4347. @Override
  4348. public void columnVisibilityChanged(String id, boolean hidden,
  4349. boolean userOriginated) {
  4350. final Column column = getColumnByColumnId(id);
  4351. final GridColumnState columnState = column.getState();
  4352. if (columnState.hidden != hidden) {
  4353. columnState.hidden = hidden;
  4354. final String diffStateKey = "columns";
  4355. ConnectorTracker connectorTracker = getUI()
  4356. .getConnectorTracker();
  4357. JsonObject diffState = connectorTracker
  4358. .getDiffState(Grid.this);
  4359. assert diffState
  4360. .hasKey(diffStateKey) : "Field name has changed";
  4361. Type type = null;
  4362. try {
  4363. type = (getState(false).getClass()
  4364. .getDeclaredField(diffStateKey)
  4365. .getGenericType());
  4366. } catch (NoSuchFieldException e) {
  4367. e.printStackTrace();
  4368. } catch (SecurityException e) {
  4369. e.printStackTrace();
  4370. }
  4371. EncodeResult encodeResult = JsonCodec.encode(
  4372. getState(false).columns, diffState, type,
  4373. connectorTracker);
  4374. diffState.put(diffStateKey, encodeResult.getEncodedValue());
  4375. fireColumnVisibilityChangeEvent(column, hidden,
  4376. userOriginated);
  4377. }
  4378. }
  4379. @Override
  4380. public void contextClick(int rowIndex, String rowKey,
  4381. String columnId, Section section,
  4382. MouseEventDetails details) {
  4383. Object itemId = null;
  4384. if (rowKey != null) {
  4385. itemId = getKeyMapper().get(rowKey);
  4386. }
  4387. fireEvent(new GridContextClickEvent(Grid.this, details, section,
  4388. rowIndex, itemId, getPropertyIdByColumnId(columnId)));
  4389. }
  4390. @Override
  4391. public void columnResized(String id, double pixels) {
  4392. final Column column = getColumnByColumnId(id);
  4393. if (column != null && column.isResizable()) {
  4394. column.getState().width = pixels;
  4395. fireColumnResizeEvent(column, true);
  4396. markAsDirty();
  4397. }
  4398. }
  4399. });
  4400. registerRpc(new EditorServerRpc() {
  4401. @Override
  4402. public void bind(int rowIndex) {
  4403. try {
  4404. Object id = getContainerDataSource().getIdByIndex(rowIndex);
  4405. final boolean opening = editedItemId == null;
  4406. final boolean moving = !opening && !editedItemId.equals(id);
  4407. final boolean allowMove = !isEditorBuffered()
  4408. && getEditorFieldGroup().isValid();
  4409. if (opening || !moving || allowMove) {
  4410. doBind(id);
  4411. } else {
  4412. failBind(null);
  4413. }
  4414. } catch (Exception e) {
  4415. failBind(e);
  4416. }
  4417. }
  4418. private void doBind(Object id) {
  4419. editedItemId = id;
  4420. doEditItem();
  4421. getEditorRpc().confirmBind(true);
  4422. }
  4423. private void failBind(Exception e) {
  4424. if (e != null) {
  4425. handleError(e);
  4426. }
  4427. getEditorRpc().confirmBind(false);
  4428. }
  4429. @Override
  4430. public void cancel(int rowIndex) {
  4431. try {
  4432. // For future proofing even though cannot currently fail
  4433. doCancelEditor();
  4434. } catch (Exception e) {
  4435. handleError(e);
  4436. }
  4437. }
  4438. @Override
  4439. public void save(int rowIndex) {
  4440. List<String> errorColumnIds = null;
  4441. String errorMessage = null;
  4442. boolean success = false;
  4443. try {
  4444. saveEditor();
  4445. success = true;
  4446. } catch (CommitException e) {
  4447. try {
  4448. CommitErrorEvent event = new CommitErrorEvent(Grid.this,
  4449. e);
  4450. getEditorErrorHandler().commitError(event);
  4451. errorMessage = event.getUserErrorMessage();
  4452. errorColumnIds = new ArrayList<String>();
  4453. for (Column column : event.getErrorColumns()) {
  4454. errorColumnIds.add(column.state.id);
  4455. }
  4456. } catch (Exception ee) {
  4457. // A badly written error handler can throw an exception,
  4458. // which would lock up the Grid
  4459. handleError(ee);
  4460. }
  4461. } catch (Exception e) {
  4462. handleError(e);
  4463. }
  4464. getEditorRpc().confirmSave(success, errorMessage,
  4465. errorColumnIds);
  4466. }
  4467. private void handleError(Exception e) {
  4468. com.vaadin.server.ErrorEvent.findErrorHandler(Grid.this)
  4469. .error(new ConnectorErrorEvent(Grid.this, e));
  4470. }
  4471. });
  4472. }
  4473. @Override
  4474. public void beforeClientResponse(boolean initial) {
  4475. try {
  4476. header.sanityCheck();
  4477. footer.sanityCheck();
  4478. } catch (Exception e) {
  4479. e.printStackTrace();
  4480. setComponentError(new ErrorMessage() {
  4481. @Override
  4482. public ErrorLevel getErrorLevel() {
  4483. return ErrorLevel.CRITICAL;
  4484. }
  4485. @Override
  4486. public String getFormattedHtmlMessage() {
  4487. return "Incorrectly merged cells";
  4488. }
  4489. });
  4490. }
  4491. super.beforeClientResponse(initial);
  4492. }
  4493. /**
  4494. * Sets the grid data source.
  4495. * <p>
  4496. *
  4497. * <strong>Note</strong> Grid columns are based on properties and try to
  4498. * detect a correct converter for the data type. The columns are not
  4499. * reinitialized automatically if the container is changed, and if the same
  4500. * properties are present after container change, the columns are reused.
  4501. * Properties with same names, but different data types will lead to
  4502. * unpredictable behavior.
  4503. *
  4504. * @param container
  4505. * The container data source. Cannot be null.
  4506. * @throws IllegalArgumentException
  4507. * if the data source is null
  4508. */
  4509. public void setContainerDataSource(Container.Indexed container) {
  4510. defaultContainer = false;
  4511. internalSetContainerDataSource(container);
  4512. }
  4513. private void internalSetContainerDataSource(Container.Indexed container) {
  4514. if (container == null) {
  4515. throw new IllegalArgumentException(
  4516. "Cannot set the datasource to null");
  4517. }
  4518. if (datasource == container) {
  4519. return;
  4520. }
  4521. // Remove old listeners
  4522. if (datasource instanceof PropertySetChangeNotifier) {
  4523. ((PropertySetChangeNotifier) datasource)
  4524. .removePropertySetChangeListener(propertyListener);
  4525. }
  4526. if (datasourceExtension != null) {
  4527. removeExtension(datasourceExtension);
  4528. }
  4529. // Remove old DetailComponentManager
  4530. if (detailComponentManager != null) {
  4531. detailComponentManager.remove();
  4532. }
  4533. resetEditor();
  4534. datasource = container;
  4535. //
  4536. // Adjust sort order
  4537. //
  4538. if (container instanceof Container.Sortable) {
  4539. // If the container is sortable, go through the current sort order
  4540. // and match each item to the sortable properties of the new
  4541. // container. If the new container does not support an item in the
  4542. // current sort order, that item is removed from the current sort
  4543. // order list.
  4544. Collection<?> sortableProps = ((Container.Sortable) getContainerDataSource())
  4545. .getSortableContainerPropertyIds();
  4546. Iterator<SortOrder> i = sortOrder.iterator();
  4547. while (i.hasNext()) {
  4548. if (!sortableProps.contains(i.next().getPropertyId())) {
  4549. i.remove();
  4550. }
  4551. }
  4552. sort(false);
  4553. } else {
  4554. // Clear sorting order. Don't sort.
  4555. sortOrder.clear();
  4556. }
  4557. datasourceExtension = new RpcDataProviderExtension(container);
  4558. datasourceExtension.extend(this);
  4559. datasourceExtension.addDataGenerator(new RowDataGenerator());
  4560. for (Extension e : getExtensions()) {
  4561. if (e instanceof DataGenerator) {
  4562. datasourceExtension.addDataGenerator((DataGenerator) e);
  4563. }
  4564. }
  4565. if (detailComponentManager != null) {
  4566. detailComponentManager = new DetailComponentManager(this,
  4567. detailComponentManager.getDetailsGenerator());
  4568. } else {
  4569. detailComponentManager = new DetailComponentManager(this);
  4570. }
  4571. /*
  4572. * selectionModel == null when the invocation comes from the
  4573. * constructor.
  4574. */
  4575. if (selectionModel != null) {
  4576. selectionModel.reset();
  4577. }
  4578. // Listen to changes in properties and remove columns if needed
  4579. if (datasource instanceof PropertySetChangeNotifier) {
  4580. ((PropertySetChangeNotifier) datasource)
  4581. .addPropertySetChangeListener(propertyListener);
  4582. }
  4583. /*
  4584. * activeRowHandler will be updated by the client-side request that
  4585. * occurs on container change - no need to actively re-insert any
  4586. * ValueChangeListeners at this point.
  4587. */
  4588. setFrozenColumnCount(0);
  4589. if (columns.isEmpty()) {
  4590. // Add columns
  4591. for (Object propertyId : datasource.getContainerPropertyIds()) {
  4592. Column column = appendColumn(propertyId);
  4593. // Initial sorting is defined by container
  4594. if (datasource instanceof Sortable) {
  4595. column.setSortable(((Sortable) datasource)
  4596. .getSortableContainerPropertyIds()
  4597. .contains(propertyId));
  4598. } else {
  4599. column.setSortable(false);
  4600. }
  4601. }
  4602. } else {
  4603. Collection<?> properties = datasource.getContainerPropertyIds();
  4604. for (Object property : columns.keySet()) {
  4605. if (!properties.contains(property)) {
  4606. throw new IllegalStateException(
  4607. "Found at least one column in Grid that does not exist in the given container: "
  4608. + property + " with the header \""
  4609. + getColumn(property).getHeaderCaption()
  4610. + "\". "
  4611. + "Call removeAllColumns() before setContainerDataSource() if you want to reconfigure the columns based on the new container.");
  4612. }
  4613. if (!(datasource instanceof Sortable)
  4614. || !((Sortable) datasource)
  4615. .getSortableContainerPropertyIds()
  4616. .contains(property)) {
  4617. columns.get(property).setSortable(false);
  4618. }
  4619. }
  4620. }
  4621. }
  4622. /**
  4623. * Returns the grid data source.
  4624. *
  4625. * @return the container data source of the grid
  4626. */
  4627. public Container.Indexed getContainerDataSource() {
  4628. return datasource;
  4629. }
  4630. /**
  4631. * Returns a column based on the property id.
  4632. *
  4633. * @param propertyId
  4634. * the property id of the column
  4635. * @return the column or <code>null</code> if not found
  4636. */
  4637. public Column getColumn(Object propertyId) {
  4638. return columns.get(propertyId);
  4639. }
  4640. /**
  4641. * Returns a copy of currently configures columns in their current visual
  4642. * order in this Grid.
  4643. *
  4644. * @return unmodifiable copy of current columns in visual order
  4645. */
  4646. public List<Column> getColumns() {
  4647. List<Column> columns = new ArrayList<Grid.Column>();
  4648. for (String columnId : getState(false).columnOrder) {
  4649. columns.add(getColumnByColumnId(columnId));
  4650. }
  4651. return Collections.unmodifiableList(columns);
  4652. }
  4653. /**
  4654. * Adds a new Column to Grid. Also adds the property to container with data
  4655. * type String, if property for column does not exist in it. Default value
  4656. * for the new property is an empty String.
  4657. * <p>
  4658. * Note that adding a new property is only done for the default container
  4659. * that Grid sets up with the default constructor.
  4660. *
  4661. * @param propertyId
  4662. * the property id of the new column
  4663. * @return the new column
  4664. *
  4665. * @throws IllegalStateException
  4666. * if column for given property already exists in this grid
  4667. */
  4668. public Column addColumn(Object propertyId) throws IllegalStateException {
  4669. if (datasource.getContainerPropertyIds().contains(propertyId)
  4670. && !columns.containsKey(propertyId)) {
  4671. appendColumn(propertyId);
  4672. } else if (defaultContainer) {
  4673. addColumnProperty(propertyId, String.class, "");
  4674. } else {
  4675. if (columns.containsKey(propertyId)) {
  4676. throw new IllegalStateException("A column for property id '"
  4677. + propertyId + "' already exists in this grid");
  4678. } else {
  4679. throw new IllegalStateException("Property id '" + propertyId
  4680. + "' does not exist in the container");
  4681. }
  4682. }
  4683. // Inform the data provider of this new column.
  4684. Column column = getColumn(propertyId);
  4685. List<Column> addedColumns = new ArrayList<Column>();
  4686. addedColumns.add(column);
  4687. datasourceExtension.columnsAdded(addedColumns);
  4688. return column;
  4689. }
  4690. /**
  4691. * Adds a new Column to Grid. This function makes sure that the property
  4692. * with the given id and data type exists in the container. If property does
  4693. * not exists, it will be created.
  4694. * <p>
  4695. * Default value for the new property is 0 if type is Integer, Double and
  4696. * Float. If type is String, default value is an empty string. For all other
  4697. * types the default value is null.
  4698. * <p>
  4699. * Note that adding a new property is only done for the default container
  4700. * that Grid sets up with the default constructor.
  4701. *
  4702. * @param propertyId
  4703. * the property id of the new column
  4704. * @param type
  4705. * the data type for the new property
  4706. * @return the new column
  4707. *
  4708. * @throws IllegalStateException
  4709. * if column for given property already exists in this grid or
  4710. * property already exists in the container with wrong type
  4711. */
  4712. public Column addColumn(Object propertyId, Class<?> type) {
  4713. addColumnProperty(propertyId, type, null);
  4714. return getColumn(propertyId);
  4715. }
  4716. protected void addColumnProperty(Object propertyId, Class<?> type,
  4717. Object defaultValue) throws IllegalStateException {
  4718. if (!defaultContainer) {
  4719. throw new IllegalStateException(
  4720. "Container for this Grid is not a default container from Grid() constructor");
  4721. }
  4722. if (!columns.containsKey(propertyId)) {
  4723. if (!datasource.getContainerPropertyIds().contains(propertyId)) {
  4724. datasource.addContainerProperty(propertyId, type, defaultValue);
  4725. } else {
  4726. Property<?> containerProperty = datasource.getContainerProperty(
  4727. datasource.firstItemId(), propertyId);
  4728. if (containerProperty.getType() == type) {
  4729. appendColumn(propertyId);
  4730. } else {
  4731. throw new IllegalStateException(
  4732. "DataSource already has the given property "
  4733. + propertyId + " with a different type");
  4734. }
  4735. }
  4736. } else {
  4737. throw new IllegalStateException(
  4738. "Grid already has a column for property " + propertyId);
  4739. }
  4740. }
  4741. /**
  4742. * Removes all columns from this Grid.
  4743. */
  4744. public void removeAllColumns() {
  4745. List<Column> removed = new ArrayList<Column>(columns.values());
  4746. Set<Object> properties = new HashSet<Object>(columns.keySet());
  4747. for (Object propertyId : properties) {
  4748. removeColumn(propertyId);
  4749. }
  4750. datasourceExtension.columnsRemoved(removed);
  4751. }
  4752. /**
  4753. * Used internally by the {@link Grid} to get a {@link Column} by
  4754. * referencing its generated state id. Also used by {@link Column} to verify
  4755. * if it has been detached from the {@link Grid}.
  4756. *
  4757. * @param columnId
  4758. * the client id generated for the column when the column is
  4759. * added to the grid
  4760. * @return the column with the id or <code>null</code> if not found
  4761. */
  4762. Column getColumnByColumnId(String columnId) {
  4763. Object propertyId = getPropertyIdByColumnId(columnId);
  4764. return getColumn(propertyId);
  4765. }
  4766. /**
  4767. * Used internally by the {@link Grid} to get a property id by referencing
  4768. * the columns generated state id.
  4769. *
  4770. * @param columnId
  4771. * The state id of the column
  4772. * @return The column instance or null if not found
  4773. */
  4774. Object getPropertyIdByColumnId(String columnId) {
  4775. return columnKeys.get(columnId);
  4776. }
  4777. /**
  4778. * Returns whether column reordering is allowed. Default value is
  4779. * <code>false</code>.
  4780. *
  4781. * @since 7.5.0
  4782. * @return true if reordering is allowed
  4783. */
  4784. public boolean isColumnReorderingAllowed() {
  4785. return getState(false).columnReorderingAllowed;
  4786. }
  4787. /**
  4788. * Sets whether or not column reordering is allowed. Default value is
  4789. * <code>false</code>.
  4790. *
  4791. * @since 7.5.0
  4792. * @param columnReorderingAllowed
  4793. * specifies whether column reordering is allowed
  4794. */
  4795. public void setColumnReorderingAllowed(boolean columnReorderingAllowed) {
  4796. if (isColumnReorderingAllowed() != columnReorderingAllowed) {
  4797. getState().columnReorderingAllowed = columnReorderingAllowed;
  4798. }
  4799. }
  4800. @Override
  4801. protected GridState getState() {
  4802. return (GridState) super.getState();
  4803. }
  4804. @Override
  4805. protected GridState getState(boolean markAsDirty) {
  4806. return (GridState) super.getState(markAsDirty);
  4807. }
  4808. /**
  4809. * Sets the column resize mode to use. The default mode is
  4810. * {@link ColumnResizeMode#ANIMATED}.
  4811. *
  4812. * @param mode
  4813. * a ColumnResizeMode value
  4814. * @since 7.7.5
  4815. */
  4816. public void setColumnResizeMode(ColumnResizeMode mode) {
  4817. getState().columnResizeMode = mode;
  4818. }
  4819. /**
  4820. * Returns the current column resize mode. The default mode is
  4821. * {@link ColumnResizeMode#ANIMATED}.
  4822. *
  4823. * @return a ColumnResizeMode value
  4824. * @since 7.7.5
  4825. */
  4826. public ColumnResizeMode getColumnResizeMode() {
  4827. return getState(false).columnResizeMode;
  4828. }
  4829. /**
  4830. * Creates a new column based on a property id and appends it as the last
  4831. * column.
  4832. *
  4833. * @param datasourcePropertyId
  4834. * The property id of a property in the datasource
  4835. */
  4836. private Column appendColumn(Object datasourcePropertyId) {
  4837. if (datasourcePropertyId == null) {
  4838. throw new IllegalArgumentException("Property id cannot be null");
  4839. }
  4840. assert datasource.getContainerPropertyIds().contains(
  4841. datasourcePropertyId) : "Datasource should contain the property id";
  4842. GridColumnState columnState = new GridColumnState();
  4843. columnState.id = columnKeys.key(datasourcePropertyId);
  4844. Column column = new Column(this, columnState, datasourcePropertyId);
  4845. columns.put(datasourcePropertyId, column);
  4846. getState().columns.add(columnState);
  4847. getState().columnOrder.add(columnState.id);
  4848. header.addColumn(datasourcePropertyId);
  4849. footer.addColumn(datasourcePropertyId);
  4850. String humanFriendlyPropertyId = SharedUtil.propertyIdToHumanFriendly(
  4851. String.valueOf(datasourcePropertyId));
  4852. column.setHeaderCaption(humanFriendlyPropertyId);
  4853. if (datasource instanceof Sortable
  4854. && ((Sortable) datasource).getSortableContainerPropertyIds()
  4855. .contains(datasourcePropertyId)) {
  4856. column.setSortable(true);
  4857. }
  4858. return column;
  4859. }
  4860. /**
  4861. * Removes a column from Grid based on a property id.
  4862. *
  4863. * @param propertyId
  4864. * The property id of column to be removed
  4865. *
  4866. * @throws IllegalArgumentException
  4867. * if there is no column for given property id in this grid
  4868. */
  4869. public void removeColumn(Object propertyId)
  4870. throws IllegalArgumentException {
  4871. if (!columns.keySet().contains(propertyId)) {
  4872. throw new IllegalArgumentException(
  4873. "There is no column for given property id " + propertyId);
  4874. }
  4875. List<Column> removed = new ArrayList<Column>();
  4876. removed.add(getColumn(propertyId));
  4877. internalRemoveColumn(propertyId);
  4878. datasourceExtension.columnsRemoved(removed);
  4879. }
  4880. private void internalRemoveColumn(Object propertyId) {
  4881. setEditorField(propertyId, null);
  4882. header.removeColumn(propertyId);
  4883. footer.removeColumn(propertyId);
  4884. Column column = columns.remove(propertyId);
  4885. getState().columnOrder.remove(columnKeys.key(propertyId));
  4886. getState().columns.remove(column.getState());
  4887. removeExtension(column.getRenderer());
  4888. }
  4889. /**
  4890. * Sets the columns and their order for the grid. Current columns whose
  4891. * property id is not in propertyIds are removed. Similarly, a column is
  4892. * added for any property id in propertyIds that has no corresponding column
  4893. * in this Grid.
  4894. *
  4895. * @since 7.5.0
  4896. *
  4897. * @param propertyIds
  4898. * properties in the desired column order
  4899. */
  4900. public void setColumns(Object... propertyIds) {
  4901. if (SharedUtil.containsDuplicates(propertyIds)) {
  4902. throw new IllegalArgumentException(
  4903. "The propertyIds array contains duplicates: "
  4904. + SharedUtil.getDuplicates(propertyIds));
  4905. }
  4906. Set<?> removePids = new HashSet<Object>(columns.keySet());
  4907. removePids.removeAll(Arrays.asList(propertyIds));
  4908. for (Object removePid : removePids) {
  4909. removeColumn(removePid);
  4910. }
  4911. Set<?> addPids = new HashSet<Object>(Arrays.asList(propertyIds));
  4912. addPids.removeAll(columns.keySet());
  4913. for (Object propertyId : addPids) {
  4914. addColumn(propertyId);
  4915. }
  4916. setColumnOrder(propertyIds);
  4917. }
  4918. /**
  4919. * Sets a new column order for the grid. All columns which are not ordered
  4920. * here will remain in the order they were before as the last columns of
  4921. * grid.
  4922. *
  4923. * @param propertyIds
  4924. * properties in the order columns should be
  4925. */
  4926. public void setColumnOrder(Object... propertyIds) {
  4927. if (SharedUtil.containsDuplicates(propertyIds)) {
  4928. throw new IllegalArgumentException(
  4929. "The propertyIds array contains duplicates: "
  4930. + SharedUtil.getDuplicates(propertyIds));
  4931. }
  4932. List<String> columnOrder = new ArrayList<String>();
  4933. for (Object propertyId : propertyIds) {
  4934. if (columns.containsKey(propertyId)) {
  4935. columnOrder.add(columnKeys.key(propertyId));
  4936. } else {
  4937. throw new IllegalArgumentException(
  4938. "Grid does not contain column for property "
  4939. + String.valueOf(propertyId));
  4940. }
  4941. }
  4942. List<String> stateColumnOrder = getState().columnOrder;
  4943. if (stateColumnOrder.size() != columnOrder.size()) {
  4944. stateColumnOrder.removeAll(columnOrder);
  4945. columnOrder.addAll(stateColumnOrder);
  4946. }
  4947. getState().columnOrder = columnOrder;
  4948. fireColumnReorderEvent(false);
  4949. }
  4950. /**
  4951. * Sets the number of frozen columns in this grid. Setting the count to 0
  4952. * means that no data columns will be frozen, but the built-in selection
  4953. * checkbox column will still be frozen if it's in use. Setting the count to
  4954. * -1 will also disable the selection column.
  4955. * <p>
  4956. * The default value is 0.
  4957. *
  4958. * @param numberOfColumns
  4959. * the number of columns that should be frozen
  4960. *
  4961. * @throws IllegalArgumentException
  4962. * if the column count is < 0 or > the number of visible columns
  4963. */
  4964. public void setFrozenColumnCount(int numberOfColumns) {
  4965. if (numberOfColumns < -1 || numberOfColumns > columns.size()) {
  4966. throw new IllegalArgumentException(
  4967. "count must be between -1 and the current number of columns ("
  4968. + columns.size() + "): " + numberOfColumns);
  4969. }
  4970. getState().frozenColumnCount = numberOfColumns;
  4971. }
  4972. /**
  4973. * Gets the number of frozen columns in this grid. 0 means that no data
  4974. * columns will be frozen, but the built-in selection checkbox column will
  4975. * still be frozen if it's in use. -1 means that not even the selection
  4976. * column is frozen.
  4977. * <p>
  4978. * <em>NOTE:</em> this count includes {@link Column#isHidden() hidden
  4979. * columns} in the count.
  4980. *
  4981. * @see #setFrozenColumnCount(int)
  4982. *
  4983. * @return the number of frozen columns
  4984. */
  4985. public int getFrozenColumnCount() {
  4986. return getState(false).frozenColumnCount;
  4987. }
  4988. /**
  4989. * Scrolls to a certain item, using {@link ScrollDestination#ANY}.
  4990. * <p>
  4991. * If the item has visible details, its size will also be taken into
  4992. * account.
  4993. *
  4994. * @param itemId
  4995. * id of item to scroll to.
  4996. * @throws IllegalArgumentException
  4997. * if the provided id is not recognized by the data source.
  4998. */
  4999. public void scrollTo(Object itemId) throws IllegalArgumentException {
  5000. scrollTo(itemId, ScrollDestination.ANY);
  5001. }
  5002. /**
  5003. * Scrolls to a certain item, using user-specified scroll destination.
  5004. * <p>
  5005. * If the item has visible details, its size will also be taken into
  5006. * account.
  5007. *
  5008. * @param itemId
  5009. * id of item to scroll to.
  5010. * @param destination
  5011. * value specifying desired position of scrolled-to row.
  5012. * @throws IllegalArgumentException
  5013. * if the provided id is not recognized by the data source.
  5014. */
  5015. public void scrollTo(Object itemId, ScrollDestination destination)
  5016. throws IllegalArgumentException {
  5017. int row = datasource.indexOfId(itemId);
  5018. if (row == -1) {
  5019. throw new IllegalArgumentException(
  5020. "Item with specified ID does not exist in data source");
  5021. }
  5022. GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
  5023. clientRPC.scrollToRow(row, destination);
  5024. }
  5025. /**
  5026. * Scrolls to the beginning of the first data row.
  5027. */
  5028. public void scrollToStart() {
  5029. GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
  5030. clientRPC.scrollToStart();
  5031. }
  5032. /**
  5033. * Scrolls to the end of the last data row.
  5034. */
  5035. public void scrollToEnd() {
  5036. GridClientRpc clientRPC = getRpcProxy(GridClientRpc.class);
  5037. clientRPC.scrollToEnd();
  5038. }
  5039. /**
  5040. * Sets the number of rows that should be visible in Grid's body, while
  5041. * {@link #getHeightMode()} is {@link HeightMode#ROW}.
  5042. * <p>
  5043. * If Grid is currently not in {@link HeightMode#ROW}, the given value is
  5044. * remembered, and applied once the mode is applied.
  5045. *
  5046. * @param rows
  5047. * The height in terms of number of rows displayed in Grid's
  5048. * body. If Grid doesn't contain enough rows, white space is
  5049. * displayed instead. If <code>null</code> is given, then Grid's
  5050. * height is undefined
  5051. * @throws IllegalArgumentException
  5052. * if {@code rows} is zero or less
  5053. * @throws IllegalArgumentException
  5054. * if {@code rows} is {@link Double#isInfinite(double) infinite}
  5055. * @throws IllegalArgumentException
  5056. * if {@code rows} is {@link Double#isNaN(double) NaN}
  5057. */
  5058. public void setHeightByRows(double rows) {
  5059. if (rows <= 0.0d) {
  5060. throw new IllegalArgumentException(
  5061. "More than zero rows must be shown.");
  5062. } else if (Double.isInfinite(rows)) {
  5063. throw new IllegalArgumentException(
  5064. "Grid doesn't support infinite heights");
  5065. } else if (Double.isNaN(rows)) {
  5066. throw new IllegalArgumentException("NaN is not a valid row count");
  5067. }
  5068. getState().heightByRows = rows;
  5069. }
  5070. /**
  5071. * Gets the amount of rows in Grid's body that are shown, while
  5072. * {@link #getHeightMode()} is {@link HeightMode#ROW}.
  5073. *
  5074. * @return the amount of rows that are being shown in Grid's body
  5075. * @see #setHeightByRows(double)
  5076. */
  5077. public double getHeightByRows() {
  5078. return getState(false).heightByRows;
  5079. }
  5080. /**
  5081. * {@inheritDoc}
  5082. * <p>
  5083. * <em>Note:</em> This method will change the widget's size in the browser
  5084. * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}.
  5085. *
  5086. * @see #setHeightMode(HeightMode)
  5087. */
  5088. @Override
  5089. public void setHeight(float height, Unit unit) {
  5090. super.setHeight(height, unit);
  5091. }
  5092. /**
  5093. * Defines the mode in which the Grid widget's height is calculated.
  5094. * <p>
  5095. * If {@link HeightMode#CSS} is given, Grid will respect the values given
  5096. * via a {@code setHeight}-method, and behave as a traditional Component.
  5097. * <p>
  5098. * If {@link HeightMode#ROW} is given, Grid will make sure that the body
  5099. * will display as many rows as {@link #getHeightByRows()} defines.
  5100. * <em>Note:</em> If headers/footers are inserted or removed, the widget
  5101. * will resize itself to still display the required amount of rows in its
  5102. * body. It also takes the horizontal scrollbar into account.
  5103. *
  5104. * @param heightMode
  5105. * the mode in to which Grid should be set
  5106. */
  5107. public void setHeightMode(HeightMode heightMode) {
  5108. /*
  5109. * This method is a workaround for the fact that Vaadin re-applies
  5110. * widget dimensions (height/width) on each state change event. The
  5111. * original design was to have setHeight and setHeightByRow be equals,
  5112. * and whichever was called the latest was considered in effect.
  5113. *
  5114. * But, because of Vaadin always calling setHeight on the widget, this
  5115. * approach doesn't work.
  5116. */
  5117. getState().heightMode = heightMode;
  5118. }
  5119. /**
  5120. * Returns the current {@link HeightMode} the Grid is in.
  5121. * <p>
  5122. * Defaults to {@link HeightMode#CSS}.
  5123. *
  5124. * @return the current HeightMode
  5125. */
  5126. public HeightMode getHeightMode() {
  5127. return getState(false).heightMode;
  5128. }
  5129. /* Selection related methods: */
  5130. /**
  5131. * Takes a new {@link SelectionModel} into use.
  5132. * <p>
  5133. * The SelectionModel that is previously in use will have all its items
  5134. * deselected. If any items were selected, this will fire a
  5135. * {@link SelectionEvent}.
  5136. * <p>
  5137. * If the given SelectionModel is already in use, this method does nothing.
  5138. *
  5139. * @param selectionModel
  5140. * the new SelectionModel to use
  5141. * @throws IllegalArgumentException
  5142. * if {@code selectionModel} is <code>null</code>
  5143. */
  5144. public void setSelectionModel(SelectionModel selectionModel)
  5145. throws IllegalArgumentException {
  5146. if (selectionModel == null) {
  5147. throw new IllegalArgumentException(
  5148. "Selection model may not be null");
  5149. }
  5150. if (this.selectionModel != selectionModel) {
  5151. Collection<Object> oldSelection;
  5152. // this.selectionModel is null on init
  5153. if (this.selectionModel != null) {
  5154. oldSelection = this.selectionModel.getSelectedRows();
  5155. this.selectionModel.remove();
  5156. } else {
  5157. oldSelection = Collections.emptyList();
  5158. }
  5159. this.selectionModel = selectionModel;
  5160. selectionModel.setGrid(this);
  5161. Collection<Object> newSelection = this.selectionModel
  5162. .getSelectedRows();
  5163. if (!SharedUtil.equals(oldSelection, newSelection)) {
  5164. fireSelectionEvent(oldSelection, newSelection);
  5165. }
  5166. // selection is included in the row data, so the client needs to be
  5167. // updated
  5168. datasourceExtension.refreshCache();
  5169. }
  5170. }
  5171. /**
  5172. * Returns the currently used {@link SelectionModel}.
  5173. *
  5174. * @return the currently used SelectionModel
  5175. */
  5176. public SelectionModel getSelectionModel() {
  5177. return selectionModel;
  5178. }
  5179. /**
  5180. * Sets the Grid's selection mode.
  5181. * <p>
  5182. * Grid supports three selection modes: multiselect, single select and no
  5183. * selection, and this is a convenience method for choosing between one of
  5184. * them.
  5185. * <p>
  5186. * Technically, this method is a shortcut that can be used instead of
  5187. * calling {@code setSelectionModel} with a specific SelectionModel
  5188. * instance. Grid comes with three built-in SelectionModel classes, and the
  5189. * {@link SelectionMode} enum represents each of them.
  5190. * <p>
  5191. * Essentially, the two following method calls are equivalent:
  5192. * <p>
  5193. * <code><pre>
  5194. * grid.setSelectionMode(SelectionMode.MULTI);
  5195. * grid.setSelectionModel(new MultiSelectionMode());
  5196. * </pre></code>
  5197. *
  5198. *
  5199. * @param selectionMode
  5200. * the selection mode to switch to
  5201. * @return The {@link SelectionModel} instance that was taken into use
  5202. * @throws IllegalArgumentException
  5203. * if {@code selectionMode} is <code>null</code>
  5204. * @see SelectionModel
  5205. */
  5206. public SelectionModel setSelectionMode(final SelectionMode selectionMode)
  5207. throws IllegalArgumentException {
  5208. if (selectionMode == null) {
  5209. throw new IllegalArgumentException(
  5210. "selection mode may not be null");
  5211. }
  5212. final SelectionModel newSelectionModel = selectionMode.createModel();
  5213. setSelectionModel(newSelectionModel);
  5214. return newSelectionModel;
  5215. }
  5216. /**
  5217. * Checks whether an item is selected or not.
  5218. *
  5219. * @param itemId
  5220. * the item id to check for
  5221. * @return <code>true</code> if the item is selected
  5222. */
  5223. // keep this javadoc in sync with SelectionModel.isSelected
  5224. public boolean isSelected(Object itemId) {
  5225. return selectionModel.isSelected(itemId);
  5226. }
  5227. /**
  5228. * Returns a collection of all the currently selected itemIds.
  5229. * <p>
  5230. * This method is a shorthand that delegates to the
  5231. * {@link #getSelectionModel() selection model}.
  5232. *
  5233. * @return a collection of all the currently selected itemIds
  5234. */
  5235. // keep this javadoc in sync with SelectionModel.getSelectedRows
  5236. public Collection<Object> getSelectedRows() {
  5237. return getSelectionModel().getSelectedRows();
  5238. }
  5239. /**
  5240. * Gets the item id of the currently selected item.
  5241. * <p>
  5242. * This method is a shorthand that delegates to the
  5243. * {@link #getSelectionModel() selection model}. Only
  5244. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Single SelectionModel.Single}
  5245. * is supported.
  5246. *
  5247. * @return the item id of the currently selected item, or <code>null</code>
  5248. * if nothing is selected
  5249. * @throws IllegalStateException
  5250. * if the selection model does not implement
  5251. * {@code SelectionModel.Single}
  5252. */
  5253. // keep this javadoc in sync with SelectionModel.Single.getSelectedRow
  5254. public Object getSelectedRow() throws IllegalStateException {
  5255. if (selectionModel instanceof SelectionModel.Single) {
  5256. return ((SelectionModel.Single) selectionModel).getSelectedRow();
  5257. } else if (selectionModel instanceof SelectionModel.Multi) {
  5258. throw new IllegalStateException("Cannot get unique selected row: "
  5259. + "Grid is in multiselect mode "
  5260. + "(the current selection model is "
  5261. + selectionModel.getClass().getName() + ").");
  5262. } else if (selectionModel instanceof SelectionModel.None) {
  5263. throw new IllegalStateException(
  5264. "Cannot get selected row: " + "Grid selection is disabled "
  5265. + "(the current selection model is "
  5266. + selectionModel.getClass().getName() + ").");
  5267. } else {
  5268. throw new IllegalStateException("Cannot get selected row: "
  5269. + "Grid selection model does not implement "
  5270. + SelectionModel.Single.class.getName() + " or "
  5271. + SelectionModel.Multi.class.getName()
  5272. + "(the current model is "
  5273. + selectionModel.getClass().getName() + ").");
  5274. }
  5275. }
  5276. /**
  5277. * Marks an item as selected.
  5278. * <p>
  5279. * This method is a shorthand that delegates to the
  5280. * {@link #getSelectionModel() selection model}. Only
  5281. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Single SelectionModel.Single}
  5282. * and {@link com.vaadin.v7.ui.Grid.SelectionModel.Multi
  5283. * SelectionModel.Multi} are supported.
  5284. *
  5285. * @param itemId
  5286. * the itemId to mark as selected
  5287. * @return <code>true</code> if the selection state changed,
  5288. * <code>false</code> if the itemId already was selected
  5289. * @throws IllegalArgumentException
  5290. * if the {@code itemId} doesn't exist in the currently active
  5291. * Container
  5292. * @throws IllegalStateException
  5293. * if the selection was illegal. One such reason might be that
  5294. * the implementation already had an item selected, and that
  5295. * needs to be explicitly deselected before re-selecting
  5296. * something.
  5297. * @throws IllegalStateException
  5298. * if the selection model does not implement
  5299. * {@code SelectionModel.Single} or {@code SelectionModel.Multi}
  5300. */
  5301. // keep this javadoc in sync with SelectionModel.Single.select
  5302. public boolean select(Object itemId)
  5303. throws IllegalArgumentException, IllegalStateException {
  5304. if (selectionModel instanceof SelectionModel.Single) {
  5305. return ((SelectionModel.Single) selectionModel).select(itemId);
  5306. } else if (selectionModel instanceof SelectionModel.Multi) {
  5307. return ((SelectionModel.Multi) selectionModel).select(itemId);
  5308. } else if (selectionModel instanceof SelectionModel.None) {
  5309. throw new IllegalStateException("Cannot select row '" + itemId
  5310. + "': Grid selection is disabled "
  5311. + "(the current selection model is "
  5312. + selectionModel.getClass().getName() + ").");
  5313. } else {
  5314. throw new IllegalStateException("Cannot select row '" + itemId
  5315. + "': Grid selection model does not implement "
  5316. + SelectionModel.Single.class.getName() + " or "
  5317. + SelectionModel.Multi.class.getName()
  5318. + "(the current model is "
  5319. + selectionModel.getClass().getName() + ").");
  5320. }
  5321. }
  5322. /**
  5323. * Marks an item as unselected.
  5324. * <p>
  5325. * This method is a shorthand that delegates to the
  5326. * {@link #getSelectionModel() selection model}. Only
  5327. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Single SelectionModel.Single}
  5328. * and {@link com.vaadin.v7.ui.Grid.SelectionModel.Multi
  5329. * SelectionModel.Multi} are supported.
  5330. *
  5331. * @param itemId
  5332. * the itemId to remove from being selected
  5333. * @return <code>true</code> if the selection state changed,
  5334. * <code>false</code> if the itemId was already selected
  5335. * @throws IllegalArgumentException
  5336. * if the {@code itemId} doesn't exist in the currently active
  5337. * Container
  5338. * @throws IllegalStateException
  5339. * if the deselection was illegal. One such reason might be that
  5340. * the implementation requires one or more items to be selected
  5341. * at all times.
  5342. * @throws IllegalStateException
  5343. * if the selection model does not implement
  5344. * {@code SelectionModel.Single} or {code SelectionModel.Multi}
  5345. */
  5346. // keep this javadoc in sync with SelectionModel.Single.deselect
  5347. public boolean deselect(Object itemId) throws IllegalStateException {
  5348. if (selectionModel instanceof SelectionModel.Single) {
  5349. if (isSelected(itemId)) {
  5350. return ((SelectionModel.Single) selectionModel).select(null);
  5351. }
  5352. return false;
  5353. } else if (selectionModel instanceof SelectionModel.Multi) {
  5354. return ((SelectionModel.Multi) selectionModel).deselect(itemId);
  5355. } else if (selectionModel instanceof SelectionModel.None) {
  5356. throw new IllegalStateException("Cannot deselect row '" + itemId
  5357. + "': Grid selection is disabled "
  5358. + "(the current selection model is "
  5359. + selectionModel.getClass().getName() + ").");
  5360. } else {
  5361. throw new IllegalStateException("Cannot deselect row '" + itemId
  5362. + "': Grid selection model does not implement "
  5363. + SelectionModel.Single.class.getName() + " or "
  5364. + SelectionModel.Multi.class.getName()
  5365. + "(the current model is "
  5366. + selectionModel.getClass().getName() + ").");
  5367. }
  5368. }
  5369. /**
  5370. * Marks all items as unselected.
  5371. * <p>
  5372. * This method is a shorthand that delegates to the
  5373. * {@link #getSelectionModel() selection model}. Only
  5374. * {@link com.vaadin.v7.ui.Grid.SelectionModel.Single SelectionModel.Single}
  5375. * and {@link com.vaadin.v7.ui.Grid.SelectionModel.Multi
  5376. * SelectionModel.Multi} are supported.
  5377. *
  5378. * @return <code>true</code> if the selection state changed,
  5379. * <code>false</code> if the itemId was already selected
  5380. * @throws IllegalStateException
  5381. * if the deselection was illegal. One such reason might be that
  5382. * the implementation requires one or more items to be selected
  5383. * at all times.
  5384. * @throws IllegalStateException
  5385. * if the selection model does not implement
  5386. * {@code SelectionModel.Single} or {code SelectionModel.Multi}
  5387. */
  5388. public boolean deselectAll() throws IllegalStateException {
  5389. if (selectionModel instanceof SelectionModel.Single) {
  5390. if (getSelectedRow() != null) {
  5391. return deselect(getSelectedRow());
  5392. }
  5393. return false;
  5394. } else if (selectionModel instanceof SelectionModel.Multi) {
  5395. return ((SelectionModel.Multi) selectionModel).deselectAll();
  5396. } else if (selectionModel instanceof SelectionModel.None) {
  5397. throw new IllegalStateException(
  5398. "Cannot deselect all rows" + ": Grid selection is disabled "
  5399. + "(the current selection model is "
  5400. + selectionModel.getClass().getName() + ").");
  5401. } else {
  5402. throw new IllegalStateException("Cannot deselect all rows:"
  5403. + " Grid selection model does not implement "
  5404. + SelectionModel.Single.class.getName() + " or "
  5405. + SelectionModel.Multi.class.getName()
  5406. + "(the current model is "
  5407. + selectionModel.getClass().getName() + ").");
  5408. }
  5409. }
  5410. /**
  5411. * Fires a selection change event.
  5412. * <p>
  5413. * <strong>Note:</strong> This is not a method that should be called by
  5414. * application logic. This method is publicly accessible only so that
  5415. * {@link SelectionModel SelectionModels} would be able to inform Grid of
  5416. * these events.
  5417. *
  5418. * @param newSelection
  5419. * the selection that was added by this event
  5420. * @param oldSelection
  5421. * the selection that was removed by this event
  5422. */
  5423. public void fireSelectionEvent(Collection<Object> oldSelection,
  5424. Collection<Object> newSelection) {
  5425. fireEvent(new SelectionEvent(this, oldSelection, newSelection));
  5426. }
  5427. @Override
  5428. public void addSelectionListener(SelectionListener listener) {
  5429. addListener(SelectionEvent.class, listener, SELECTION_CHANGE_METHOD);
  5430. }
  5431. @Override
  5432. public void removeSelectionListener(SelectionListener listener) {
  5433. removeListener(SelectionEvent.class, listener, SELECTION_CHANGE_METHOD);
  5434. }
  5435. private void fireColumnReorderEvent(boolean userOriginated) {
  5436. fireEvent(new ColumnReorderEvent(this, userOriginated));
  5437. }
  5438. /**
  5439. * Registers a new column reorder listener.
  5440. *
  5441. * @since 7.5.0
  5442. * @param listener
  5443. * the listener to register
  5444. */
  5445. public void addColumnReorderListener(ColumnReorderListener listener) {
  5446. addListener(ColumnReorderEvent.class, listener, COLUMN_REORDER_METHOD);
  5447. }
  5448. /**
  5449. * Removes a previously registered column reorder listener.
  5450. *
  5451. * @since 7.5.0
  5452. * @param listener
  5453. * the listener to remove
  5454. */
  5455. public void removeColumnReorderListener(ColumnReorderListener listener) {
  5456. removeListener(ColumnReorderEvent.class, listener,
  5457. COLUMN_REORDER_METHOD);
  5458. }
  5459. private void fireColumnResizeEvent(Column column, boolean userOriginated) {
  5460. fireEvent(new ColumnResizeEvent(this, column, userOriginated));
  5461. }
  5462. /**
  5463. * Registers a new column resize listener.
  5464. *
  5465. * @param listener
  5466. * the listener to register
  5467. */
  5468. public void addColumnResizeListener(ColumnResizeListener listener) {
  5469. addListener(ColumnResizeEvent.class, listener, COLUMN_RESIZE_METHOD);
  5470. }
  5471. /**
  5472. * Removes a previously registered column resize listener.
  5473. *
  5474. * @param listener
  5475. * the listener to remove
  5476. */
  5477. public void removeColumnResizeListener(ColumnResizeListener listener) {
  5478. removeListener(ColumnResizeEvent.class, listener, COLUMN_RESIZE_METHOD);
  5479. }
  5480. /**
  5481. * Gets the {@link KeyMapper } being used by the data source.
  5482. *
  5483. * @return the key mapper being used by the data source
  5484. */
  5485. KeyMapper<Object> getKeyMapper() {
  5486. return datasourceExtension.getKeyMapper();
  5487. }
  5488. /**
  5489. * Adds a renderer to this grid's connector hierarchy.
  5490. *
  5491. * @param renderer
  5492. * the renderer to add
  5493. */
  5494. void addRenderer(Renderer<?> renderer) {
  5495. addExtension(renderer);
  5496. }
  5497. /**
  5498. * Sets the current sort order using the fluid Sort API. Read the
  5499. * documentation for {@link Sort} for more information.
  5500. * <p>
  5501. * <em>Note:</em> Sorting by a property that has no column in Grid will hide
  5502. * all possible sorting indicators.
  5503. *
  5504. * @param s
  5505. * a sort instance
  5506. *
  5507. * @throws IllegalStateException
  5508. * if container is not sortable (does not implement
  5509. * Container.Sortable)
  5510. * @throws IllegalArgumentException
  5511. * if trying to sort by non-existing property
  5512. */
  5513. public void sort(Sort s) {
  5514. setSortOrder(s.build());
  5515. }
  5516. /**
  5517. * Sort this Grid in ascending order by a specified property.
  5518. * <p>
  5519. * <em>Note:</em> Sorting by a property that has no column in Grid will hide
  5520. * all possible sorting indicators.
  5521. *
  5522. * @param propertyId
  5523. * a property ID
  5524. *
  5525. * @throws IllegalStateException
  5526. * if container is not sortable (does not implement
  5527. * Container.Sortable)
  5528. * @throws IllegalArgumentException
  5529. * if trying to sort by non-existing property
  5530. */
  5531. public void sort(Object propertyId) {
  5532. sort(propertyId, SortDirection.ASCENDING);
  5533. }
  5534. /**
  5535. * Sort this Grid in user-specified {@link SortOrder} by a property.
  5536. * <p>
  5537. * <em>Note:</em> Sorting by a property that has no column in Grid will hide
  5538. * all possible sorting indicators.
  5539. *
  5540. * @param propertyId
  5541. * a property ID
  5542. * @param direction
  5543. * a sort order value (ascending/descending)
  5544. *
  5545. * @throws IllegalStateException
  5546. * if container is not sortable (does not implement
  5547. * Container.Sortable)
  5548. * @throws IllegalArgumentException
  5549. * if trying to sort by non-existing property
  5550. */
  5551. public void sort(Object propertyId, SortDirection direction) {
  5552. sort(Sort.by(propertyId, direction));
  5553. }
  5554. /**
  5555. * Clear the current sort order, and re-sort the grid.
  5556. */
  5557. public void clearSortOrder() {
  5558. sortOrder.clear();
  5559. sort(false);
  5560. }
  5561. /**
  5562. * Sets the sort order to use.
  5563. * <p>
  5564. * <em>Note:</em> Sorting by a property that has no column in Grid will hide
  5565. * all possible sorting indicators.
  5566. *
  5567. * @param order
  5568. * a sort order list.
  5569. *
  5570. * @throws IllegalStateException
  5571. * if container is not sortable (does not implement
  5572. * Container.Sortable)
  5573. * @throws IllegalArgumentException
  5574. * if order is null or trying to sort by non-existing property
  5575. */
  5576. public void setSortOrder(List<SortOrder> order) {
  5577. setSortOrder(order, false);
  5578. }
  5579. private void setSortOrder(List<SortOrder> order, boolean userOriginated)
  5580. throws IllegalStateException, IllegalArgumentException {
  5581. if (!(getContainerDataSource() instanceof Container.Sortable)) {
  5582. throw new IllegalStateException(
  5583. "Attached container is not sortable (does not implement Container.Sortable)");
  5584. }
  5585. if (order == null) {
  5586. throw new IllegalArgumentException("Order list may not be null!");
  5587. }
  5588. sortOrder.clear();
  5589. Collection<?> sortableProps = ((Container.Sortable) getContainerDataSource())
  5590. .getSortableContainerPropertyIds();
  5591. for (SortOrder o : order) {
  5592. if (!sortableProps.contains(o.getPropertyId())) {
  5593. throw new IllegalArgumentException("Property "
  5594. + o.getPropertyId()
  5595. + " does not exist or is not sortable in the current container");
  5596. }
  5597. }
  5598. sortOrder.addAll(order);
  5599. sort(userOriginated);
  5600. }
  5601. /**
  5602. * Get the current sort order list.
  5603. *
  5604. * @return a sort order list
  5605. */
  5606. public List<SortOrder> getSortOrder() {
  5607. return Collections.unmodifiableList(sortOrder);
  5608. }
  5609. /**
  5610. * Apply sorting to data source.
  5611. */
  5612. private void sort(boolean userOriginated) {
  5613. Container c = getContainerDataSource();
  5614. if (c instanceof Container.Sortable) {
  5615. Container.Sortable cs = (Container.Sortable) c;
  5616. final int items = sortOrder.size();
  5617. Object[] propertyIds = new Object[items];
  5618. boolean[] directions = new boolean[items];
  5619. SortDirection[] stateDirs = new SortDirection[items];
  5620. for (int i = 0; i < items; ++i) {
  5621. SortOrder order = sortOrder.get(i);
  5622. stateDirs[i] = order.getDirection();
  5623. propertyIds[i] = order.getPropertyId();
  5624. switch (order.getDirection()) {
  5625. case ASCENDING:
  5626. directions[i] = true;
  5627. break;
  5628. case DESCENDING:
  5629. directions[i] = false;
  5630. break;
  5631. default:
  5632. throw new IllegalArgumentException("getDirection() of "
  5633. + order + " returned an unexpected value");
  5634. }
  5635. }
  5636. cs.sort(propertyIds, directions);
  5637. if (columns.keySet().containsAll(Arrays.asList(propertyIds))) {
  5638. String[] columnKeys = new String[items];
  5639. for (int i = 0; i < items; ++i) {
  5640. columnKeys[i] = this.columnKeys.key(propertyIds[i]);
  5641. }
  5642. getState().sortColumns = columnKeys;
  5643. getState(false).sortDirs = stateDirs;
  5644. } else {
  5645. // Not all sorted properties are in Grid. Remove any indicators.
  5646. getState().sortColumns = new String[] {};
  5647. getState(false).sortDirs = new SortDirection[] {};
  5648. }
  5649. fireEvent(new SortEvent(this, new ArrayList<SortOrder>(sortOrder),
  5650. userOriginated));
  5651. } else {
  5652. throw new IllegalStateException(
  5653. "Container is not sortable (does not implement Container.Sortable)");
  5654. }
  5655. }
  5656. /**
  5657. * Adds a sort order change listener that gets notified when the sort order
  5658. * changes.
  5659. *
  5660. * @param listener
  5661. * the sort order change listener to add
  5662. */
  5663. @Override
  5664. public Registration addSortListener(SortListener listener) {
  5665. addListener(SortEvent.class, listener, SORT_ORDER_CHANGE_METHOD);
  5666. return () -> removeListener(SortEvent.class, listener,
  5667. SORT_ORDER_CHANGE_METHOD);
  5668. }
  5669. /**
  5670. * Removes a sort order change listener previously added using
  5671. * {@link #addSortListener(SortListener)}.
  5672. *
  5673. * @param listener
  5674. * the sort order change listener to remove
  5675. */
  5676. @Override
  5677. public void removeSortListener(SortListener listener) {
  5678. removeListener(SortEvent.class, listener, SORT_ORDER_CHANGE_METHOD);
  5679. }
  5680. /* Grid Headers */
  5681. /**
  5682. * Returns the header section of this grid. The default header contains a
  5683. * single row displaying the column captions.
  5684. *
  5685. * @return the header
  5686. */
  5687. protected Header getHeader() {
  5688. return header;
  5689. }
  5690. /**
  5691. * Gets the header row at given index.
  5692. *
  5693. * @param rowIndex
  5694. * 0 based index for row. Counted from top to bottom
  5695. * @return header row at given index
  5696. * @throws IllegalArgumentException
  5697. * if no row exists at given index
  5698. */
  5699. public HeaderRow getHeaderRow(int rowIndex) {
  5700. return header.getRow(rowIndex);
  5701. }
  5702. /**
  5703. * Inserts a new row at the given position to the header section. Shifts the
  5704. * row currently at that position and any subsequent rows down (adds one to
  5705. * their indices).
  5706. *
  5707. * @param index
  5708. * the position at which to insert the row
  5709. * @return the new row
  5710. *
  5711. * @throws IllegalArgumentException
  5712. * if the index is less than 0 or greater than row count
  5713. * @see #appendHeaderRow()
  5714. * @see #prependHeaderRow()
  5715. * @see #removeHeaderRow(HeaderRow)
  5716. * @see #removeHeaderRow(int)
  5717. */
  5718. public HeaderRow addHeaderRowAt(int index) {
  5719. return header.addRowAt(index);
  5720. }
  5721. /**
  5722. * Adds a new row at the bottom of the header section.
  5723. *
  5724. * @return the new row
  5725. * @see #prependHeaderRow()
  5726. * @see #addHeaderRowAt(int)
  5727. * @see #removeHeaderRow(HeaderRow)
  5728. * @see #removeHeaderRow(int)
  5729. */
  5730. public HeaderRow appendHeaderRow() {
  5731. return header.appendRow();
  5732. }
  5733. /**
  5734. * Returns the current default row of the header section. The default row is
  5735. * a special header row providing a user interface for sorting columns.
  5736. * Setting a header text for column updates cells in the default header.
  5737. *
  5738. * @return the default row or null if no default row set
  5739. */
  5740. public HeaderRow getDefaultHeaderRow() {
  5741. return header.getDefaultRow();
  5742. }
  5743. /**
  5744. * Gets the row count for the header section.
  5745. *
  5746. * @return row count
  5747. */
  5748. public int getHeaderRowCount() {
  5749. return header.getRowCount();
  5750. }
  5751. /**
  5752. * Adds a new row at the top of the header section.
  5753. *
  5754. * @return the new row
  5755. * @see #appendHeaderRow()
  5756. * @see #addHeaderRowAt(int)
  5757. * @see #removeHeaderRow(HeaderRow)
  5758. * @see #removeHeaderRow(int)
  5759. */
  5760. public HeaderRow prependHeaderRow() {
  5761. return header.prependRow();
  5762. }
  5763. /**
  5764. * Removes the given row from the header section.
  5765. *
  5766. * @param row
  5767. * the row to be removed
  5768. *
  5769. * @throws IllegalArgumentException
  5770. * if the row does not exist in this section
  5771. * @see #removeHeaderRow(int)
  5772. * @see #addHeaderRowAt(int)
  5773. * @see #appendHeaderRow()
  5774. * @see #prependHeaderRow()
  5775. */
  5776. public void removeHeaderRow(HeaderRow row) {
  5777. header.removeRow(row);
  5778. }
  5779. /**
  5780. * Removes the row at the given position from the header section.
  5781. *
  5782. * @param rowIndex
  5783. * the position of the row
  5784. *
  5785. * @throws IllegalArgumentException
  5786. * if no row exists at given index
  5787. * @see #removeHeaderRow(HeaderRow)
  5788. * @see #addHeaderRowAt(int)
  5789. * @see #appendHeaderRow()
  5790. * @see #prependHeaderRow()
  5791. */
  5792. public void removeHeaderRow(int rowIndex) {
  5793. header.removeRow(rowIndex);
  5794. }
  5795. /**
  5796. * Sets the default row of the header. The default row is a special header
  5797. * row providing a user interface for sorting columns.
  5798. *
  5799. * @param row
  5800. * the new default row, or null for no default row
  5801. *
  5802. * @throws IllegalArgumentException
  5803. * header does not contain the row
  5804. */
  5805. public void setDefaultHeaderRow(HeaderRow row) {
  5806. header.setDefaultRow(row);
  5807. }
  5808. /**
  5809. * Sets the visibility of the header section.
  5810. *
  5811. * @param visible
  5812. * true to show header section, false to hide
  5813. */
  5814. public void setHeaderVisible(boolean visible) {
  5815. header.setVisible(visible);
  5816. }
  5817. /**
  5818. * Returns the visibility of the header section.
  5819. *
  5820. * @return true if visible, false otherwise.
  5821. */
  5822. public boolean isHeaderVisible() {
  5823. return header.isVisible();
  5824. }
  5825. /* Grid Footers */
  5826. /**
  5827. * Returns the footer section of this grid. The default header contains a
  5828. * single row displaying the column captions.
  5829. *
  5830. * @return the footer
  5831. */
  5832. protected Footer getFooter() {
  5833. return footer;
  5834. }
  5835. /**
  5836. * Gets the footer row at given index.
  5837. *
  5838. * @param rowIndex
  5839. * 0 based index for row. Counted from top to bottom
  5840. * @return footer row at given index
  5841. * @throws IllegalArgumentException
  5842. * if no row exists at given index
  5843. */
  5844. public FooterRow getFooterRow(int rowIndex) {
  5845. return footer.getRow(rowIndex);
  5846. }
  5847. /**
  5848. * Inserts a new row at the given position to the footer section. Shifts the
  5849. * row currently at that position and any subsequent rows down (adds one to
  5850. * their indices).
  5851. *
  5852. * @param index
  5853. * the position at which to insert the row
  5854. * @return the new row
  5855. *
  5856. * @throws IllegalArgumentException
  5857. * if the index is less than 0 or greater than row count
  5858. * @see #appendFooterRow()
  5859. * @see #prependFooterRow()
  5860. * @see #removeFooterRow(FooterRow)
  5861. * @see #removeFooterRow(int)
  5862. */
  5863. public FooterRow addFooterRowAt(int index) {
  5864. return footer.addRowAt(index);
  5865. }
  5866. /**
  5867. * Adds a new row at the bottom of the footer section.
  5868. *
  5869. * @return the new row
  5870. * @see #prependFooterRow()
  5871. * @see #addFooterRowAt(int)
  5872. * @see #removeFooterRow(FooterRow)
  5873. * @see #removeFooterRow(int)
  5874. */
  5875. public FooterRow appendFooterRow() {
  5876. return footer.appendRow();
  5877. }
  5878. /**
  5879. * Gets the row count for the footer.
  5880. *
  5881. * @return row count
  5882. */
  5883. public int getFooterRowCount() {
  5884. return footer.getRowCount();
  5885. }
  5886. /**
  5887. * Adds a new row at the top of the footer section.
  5888. *
  5889. * @return the new row
  5890. * @see #appendFooterRow()
  5891. * @see #addFooterRowAt(int)
  5892. * @see #removeFooterRow(FooterRow)
  5893. * @see #removeFooterRow(int)
  5894. */
  5895. public FooterRow prependFooterRow() {
  5896. return footer.prependRow();
  5897. }
  5898. /**
  5899. * Removes the given row from the footer section.
  5900. *
  5901. * @param row
  5902. * the row to be removed
  5903. *
  5904. * @throws IllegalArgumentException
  5905. * if the row does not exist in this section
  5906. * @see #removeFooterRow(int)
  5907. * @see #addFooterRowAt(int)
  5908. * @see #appendFooterRow()
  5909. * @see #prependFooterRow()
  5910. */
  5911. public void removeFooterRow(FooterRow row) {
  5912. footer.removeRow(row);
  5913. }
  5914. /**
  5915. * Removes the row at the given position from the footer section.
  5916. *
  5917. * @param rowIndex
  5918. * the position of the row
  5919. *
  5920. * @throws IllegalArgumentException
  5921. * if no row exists at given index
  5922. * @see #removeFooterRow(FooterRow)
  5923. * @see #addFooterRowAt(int)
  5924. * @see #appendFooterRow()
  5925. * @see #prependFooterRow()
  5926. */
  5927. public void removeFooterRow(int rowIndex) {
  5928. footer.removeRow(rowIndex);
  5929. }
  5930. /**
  5931. * Sets the visibility of the footer section.
  5932. *
  5933. * @param visible
  5934. * true to show footer section, false to hide
  5935. */
  5936. public void setFooterVisible(boolean visible) {
  5937. footer.setVisible(visible);
  5938. }
  5939. /**
  5940. * Returns the visibility of the footer section.
  5941. *
  5942. * @return true if visible, false otherwise.
  5943. */
  5944. public boolean isFooterVisible() {
  5945. return footer.isVisible();
  5946. }
  5947. private void addComponent(Component c) {
  5948. extensionComponents.add(c);
  5949. c.setParent(this);
  5950. markAsDirty();
  5951. }
  5952. private void removeComponent(Component c) {
  5953. extensionComponents.remove(c);
  5954. c.setParent(null);
  5955. markAsDirty();
  5956. }
  5957. @Override
  5958. public Iterator<Component> iterator() {
  5959. // This is a hash set to avoid adding header/footer components inside
  5960. // merged cells multiple times
  5961. LinkedHashSet<Component> componentList = new LinkedHashSet<Component>();
  5962. Header header = getHeader();
  5963. for (int i = 0; i < header.getRowCount(); ++i) {
  5964. HeaderRow row = header.getRow(i);
  5965. for (Object propId : columns.keySet()) {
  5966. HeaderCell cell = row.getCell(propId);
  5967. if (cell.getCellState().type == GridStaticCellType.WIDGET) {
  5968. componentList.add(cell.getComponent());
  5969. }
  5970. }
  5971. }
  5972. Footer footer = getFooter();
  5973. for (int i = 0; i < footer.getRowCount(); ++i) {
  5974. FooterRow row = footer.getRow(i);
  5975. for (Object propId : columns.keySet()) {
  5976. FooterCell cell = row.getCell(propId);
  5977. if (cell.getCellState().type == GridStaticCellType.WIDGET) {
  5978. componentList.add(cell.getComponent());
  5979. }
  5980. }
  5981. }
  5982. componentList.addAll(getEditorFields());
  5983. componentList.addAll(extensionComponents);
  5984. return componentList.iterator();
  5985. }
  5986. @Override
  5987. public boolean isRendered(Component childComponent) {
  5988. if (getEditorFields().contains(childComponent)) {
  5989. // Only render editor fields if the editor is open
  5990. return isEditorActive();
  5991. } else {
  5992. // TODO Header and footer components should also only be rendered if
  5993. // the header/footer is visible
  5994. return true;
  5995. }
  5996. }
  5997. EditorClientRpc getEditorRpc() {
  5998. return getRpcProxy(EditorClientRpc.class);
  5999. }
  6000. /**
  6001. * Sets the {@code CellDescriptionGenerator} instance for generating
  6002. * optional descriptions (tooltips) for individual Grid cells. If a
  6003. * {@link RowDescriptionGenerator} is also set, the row description it
  6004. * generates is displayed for cells for which {@code generator} returns
  6005. * null.
  6006. *
  6007. * @param generator
  6008. * the description generator to use or {@code null} to remove a
  6009. * previously set generator if any
  6010. *
  6011. * @see #setRowDescriptionGenerator(RowDescriptionGenerator)
  6012. *
  6013. * @since 7.6
  6014. */
  6015. public void setCellDescriptionGenerator(
  6016. CellDescriptionGenerator generator) {
  6017. cellDescriptionGenerator = generator;
  6018. getState().hasDescriptions = (generator != null
  6019. || rowDescriptionGenerator != null);
  6020. datasourceExtension.refreshCache();
  6021. }
  6022. /**
  6023. * Returns the {@code CellDescriptionGenerator} instance used to generate
  6024. * descriptions (tooltips) for Grid cells.
  6025. *
  6026. * @return the description generator or {@code null} if no generator is set
  6027. *
  6028. * @since 7.6
  6029. */
  6030. public CellDescriptionGenerator getCellDescriptionGenerator() {
  6031. return cellDescriptionGenerator;
  6032. }
  6033. /**
  6034. * Sets the {@code RowDescriptionGenerator} instance for generating optional
  6035. * descriptions (tooltips) for Grid rows. If a
  6036. * {@link CellDescriptionGenerator} is also set, the row description
  6037. * generated by {@code generator} is used for cells for which the cell
  6038. * description generator returns null.
  6039. *
  6040. *
  6041. * @param generator
  6042. * the description generator to use or {@code null} to remove a
  6043. * previously set generator if any
  6044. *
  6045. * @see #setCellDescriptionGenerator(CellDescriptionGenerator)
  6046. *
  6047. * @since 7.6
  6048. */
  6049. public void setRowDescriptionGenerator(RowDescriptionGenerator generator) {
  6050. rowDescriptionGenerator = generator;
  6051. getState().hasDescriptions = (generator != null
  6052. || cellDescriptionGenerator != null);
  6053. datasourceExtension.refreshCache();
  6054. }
  6055. /**
  6056. * Returns the {@code RowDescriptionGenerator} instance used to generate
  6057. * descriptions (tooltips) for Grid rows.
  6058. *
  6059. * @return the description generator or {@code} null if no generator is set
  6060. *
  6061. * @since 7.6
  6062. */
  6063. public RowDescriptionGenerator getRowDescriptionGenerator() {
  6064. return rowDescriptionGenerator;
  6065. }
  6066. /**
  6067. * Sets the style generator that is used for generating styles for cells.
  6068. *
  6069. * @param cellStyleGenerator
  6070. * the cell style generator to set, or <code>null</code> to
  6071. * remove a previously set generator
  6072. */
  6073. public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) {
  6074. this.cellStyleGenerator = cellStyleGenerator;
  6075. datasourceExtension.refreshCache();
  6076. }
  6077. /**
  6078. * Gets the style generator that is used for generating styles for cells.
  6079. *
  6080. * @return the cell style generator, or <code>null</code> if no generator is
  6081. * set
  6082. */
  6083. public CellStyleGenerator getCellStyleGenerator() {
  6084. return cellStyleGenerator;
  6085. }
  6086. /**
  6087. * Sets the style generator that is used for generating styles for rows.
  6088. *
  6089. * @param rowStyleGenerator
  6090. * the row style generator to set, or <code>null</code> to remove
  6091. * a previously set generator
  6092. */
  6093. public void setRowStyleGenerator(RowStyleGenerator rowStyleGenerator) {
  6094. this.rowStyleGenerator = rowStyleGenerator;
  6095. datasourceExtension.refreshCache();
  6096. }
  6097. /**
  6098. * Gets the style generator that is used for generating styles for rows.
  6099. *
  6100. * @return the row style generator, or <code>null</code> if no generator is
  6101. * set
  6102. */
  6103. public RowStyleGenerator getRowStyleGenerator() {
  6104. return rowStyleGenerator;
  6105. }
  6106. /**
  6107. * Adds a row to the underlying container. The order of the parameters
  6108. * should match the current visible column order.
  6109. * <p>
  6110. * Please note that it's generally only safe to use this method during
  6111. * initialization. After Grid has been initialized and the visible column
  6112. * order might have been changed, it's better to instead add items directly
  6113. * to the underlying container and use {@link Item#getItemProperty(Object)}
  6114. * to make sure each value is assigned to the intended property.
  6115. *
  6116. * @param values
  6117. * the cell values of the new row, in the same order as the
  6118. * visible column order, not <code>null</code>.
  6119. * @return the item id of the new row
  6120. * @throws IllegalArgumentException
  6121. * if values is null
  6122. * @throws IllegalArgumentException
  6123. * if its length does not match the number of visible columns
  6124. * @throws IllegalArgumentException
  6125. * if a parameter value is not an instance of the corresponding
  6126. * property type
  6127. * @throws UnsupportedOperationException
  6128. * if the container does not support adding new items
  6129. */
  6130. public Object addRow(Object... values) {
  6131. if (values == null) {
  6132. throw new IllegalArgumentException("Values cannot be null");
  6133. }
  6134. Indexed dataSource = getContainerDataSource();
  6135. List<String> columnOrder = getState(false).columnOrder;
  6136. if (values.length != columnOrder.size()) {
  6137. throw new IllegalArgumentException(
  6138. "There are " + columnOrder.size() + " visible columns, but "
  6139. + values.length + " cell values were provided.");
  6140. }
  6141. // First verify all parameter types
  6142. for (int i = 0; i < columnOrder.size(); i++) {
  6143. Object propertyId = getPropertyIdByColumnId(columnOrder.get(i));
  6144. Class<?> propertyType = dataSource.getType(propertyId);
  6145. if (values[i] != null && !propertyType.isInstance(values[i])) {
  6146. throw new IllegalArgumentException("Parameter " + i + "("
  6147. + values[i] + ") is not an instance of "
  6148. + propertyType.getCanonicalName());
  6149. }
  6150. }
  6151. Object itemId = dataSource.addItem();
  6152. try {
  6153. Item item = dataSource.getItem(itemId);
  6154. for (int i = 0; i < columnOrder.size(); i++) {
  6155. Object propertyId = getPropertyIdByColumnId(columnOrder.get(i));
  6156. Property<Object> property = item.getItemProperty(propertyId);
  6157. property.setValue(values[i]);
  6158. }
  6159. } catch (RuntimeException e) {
  6160. try {
  6161. dataSource.removeItem(itemId);
  6162. } catch (Exception e2) {
  6163. getLogger().log(Level.SEVERE,
  6164. "Error recovering from exception in addRow", e);
  6165. }
  6166. throw e;
  6167. }
  6168. return itemId;
  6169. }
  6170. /**
  6171. * Refreshes, i.e. causes the client side to re-render the rows with the
  6172. * given item ids.
  6173. * <p>
  6174. * Calling this for a row which is not currently rendered on the client side
  6175. * has no effect.
  6176. *
  6177. * @param itemIds
  6178. * the item id(s) of the row to refresh.
  6179. */
  6180. public void refreshRows(Object... itemIds) {
  6181. for (Object itemId : itemIds) {
  6182. datasourceExtension.updateRowData(itemId);
  6183. }
  6184. }
  6185. /**
  6186. * Refreshes, i.e. causes the client side to re-render all rows.
  6187. *
  6188. * @since 7.7.7
  6189. */
  6190. public void refreshAllRows() {
  6191. datasourceExtension.refreshCache();
  6192. }
  6193. private static Logger getLogger() {
  6194. return Logger.getLogger(Grid.class.getName());
  6195. }
  6196. /**
  6197. * Sets whether or not the item editor UI is enabled for this grid. When the
  6198. * editor is enabled, the user can open it by double-clicking a row or
  6199. * hitting enter when a row is focused. The editor can also be opened
  6200. * programmatically using the {@link #editItem(Object)} method.
  6201. *
  6202. * @param isEnabled
  6203. * <code>true</code> to enable the feature, <code>false</code>
  6204. * otherwise
  6205. * @throws IllegalStateException
  6206. * if an item is currently being edited
  6207. *
  6208. * @see #getEditedItemId()
  6209. */
  6210. public void setEditorEnabled(boolean isEnabled)
  6211. throws IllegalStateException {
  6212. if (isEditorActive()) {
  6213. throw new IllegalStateException(
  6214. "Cannot disable the editor while an item ("
  6215. + getEditedItemId() + ") is being edited");
  6216. }
  6217. if (isEditorEnabled() != isEnabled) {
  6218. getState().editorEnabled = isEnabled;
  6219. }
  6220. }
  6221. /**
  6222. * Checks whether the item editor UI is enabled for this grid.
  6223. *
  6224. * @return <code>true</code> if the editor is enabled for this grid
  6225. *
  6226. * @see #setEditorEnabled(boolean)
  6227. * @see #getEditedItemId()
  6228. */
  6229. public boolean isEditorEnabled() {
  6230. return getState(false).editorEnabled;
  6231. }
  6232. /**
  6233. * Gets the id of the item that is currently being edited.
  6234. *
  6235. * @return the id of the item that is currently being edited, or
  6236. * <code>null</code> if no item is being edited at the moment
  6237. */
  6238. public Object getEditedItemId() {
  6239. return editedItemId;
  6240. }
  6241. /**
  6242. * Gets the field group that is backing the item editor of this grid.
  6243. *
  6244. * @return the backing field group
  6245. */
  6246. public FieldGroup getEditorFieldGroup() {
  6247. return editorFieldGroup;
  6248. }
  6249. /**
  6250. * Sets the field group that is backing the item editor of this grid.
  6251. *
  6252. * @param fieldGroup
  6253. * the backing field group
  6254. *
  6255. * @throws IllegalStateException
  6256. * if the editor is currently active
  6257. */
  6258. public void setEditorFieldGroup(FieldGroup fieldGroup) {
  6259. if (isEditorActive()) {
  6260. throw new IllegalStateException(
  6261. "Cannot change field group while an item ("
  6262. + getEditedItemId() + ") is being edited");
  6263. }
  6264. editorFieldGroup = fieldGroup;
  6265. }
  6266. /**
  6267. * Returns whether an item is currently being edited in the editor.
  6268. *
  6269. * @return true if the editor is open
  6270. */
  6271. public boolean isEditorActive() {
  6272. return editorActive;
  6273. }
  6274. private void checkColumnExists(Object propertyId) {
  6275. if (getColumn(propertyId) == null) {
  6276. throw new IllegalArgumentException(
  6277. "There is no column with the property id " + propertyId);
  6278. }
  6279. }
  6280. private Field<?> getEditorField(Object propertyId) {
  6281. checkColumnExists(propertyId);
  6282. if (!getColumn(propertyId).isEditable()) {
  6283. return null;
  6284. }
  6285. Field<?> editor = editorFieldGroup.getField(propertyId);
  6286. // If field group has no field for this property, see if we have it
  6287. // stored
  6288. if (editor == null) {
  6289. editor = editorFields.get(propertyId);
  6290. if (editor != null) {
  6291. editorFieldGroup.bind(editor, propertyId);
  6292. }
  6293. }
  6294. // Otherwise try to build one
  6295. try {
  6296. if (editor == null) {
  6297. editor = editorFieldGroup.buildAndBind(propertyId);
  6298. }
  6299. } finally {
  6300. if (editor == null) {
  6301. editor = editorFieldGroup.getField(propertyId);
  6302. }
  6303. if (editor != null && editor.getParent() != Grid.this) {
  6304. assert editor.getParent() == null;
  6305. editor.setParent(this);
  6306. }
  6307. }
  6308. return editor;
  6309. }
  6310. /**
  6311. * Opens the editor interface for the provided item. Scrolls the Grid to
  6312. * bring the item to view if it is not already visible.
  6313. *
  6314. * Note that any cell content rendered by a WidgetRenderer will not be
  6315. * visible in the editor row.
  6316. *
  6317. * @param itemId
  6318. * the id of the item to edit
  6319. * @throws IllegalStateException
  6320. * if the editor is not enabled or already editing an item in
  6321. * buffered mode
  6322. * @throws IllegalArgumentException
  6323. * if the {@code itemId} is not in the backing container
  6324. * @see #setEditorEnabled(boolean)
  6325. */
  6326. public void editItem(Object itemId)
  6327. throws IllegalStateException, IllegalArgumentException {
  6328. if (!isEditorEnabled()) {
  6329. throw new IllegalStateException("Item editor is not enabled");
  6330. } else if (isEditorBuffered() && editedItemId != null) {
  6331. throw new IllegalStateException("Editing item " + itemId
  6332. + " failed. Item editor is already editing item "
  6333. + editedItemId);
  6334. } else if (!getContainerDataSource().containsId(itemId)) {
  6335. throw new IllegalArgumentException("Item with id " + itemId
  6336. + " not found in current container");
  6337. }
  6338. editedItemId = itemId;
  6339. getEditorRpc().bind(getContainerDataSource().indexOfId(itemId));
  6340. }
  6341. protected void doEditItem() {
  6342. Item item = getContainerDataSource().getItem(editedItemId);
  6343. editorFieldGroup.setItemDataSource(item);
  6344. for (Column column : getColumns()) {
  6345. column.getState().editorConnector = item
  6346. .getItemProperty(column.getPropertyId()) == null ? null
  6347. : getEditorField(column.getPropertyId());
  6348. }
  6349. editorActive = true;
  6350. // Must ensure that all fields, recursively, are sent to the client
  6351. // This is needed because the fields are hidden using isRendered
  6352. for (Field<?> f : getEditorFields()) {
  6353. f.markAsDirtyRecursive();
  6354. }
  6355. if (datasource instanceof ItemSetChangeNotifier) {
  6356. ((ItemSetChangeNotifier) datasource)
  6357. .addItemSetChangeListener(editorClosingItemSetListener);
  6358. }
  6359. }
  6360. private void setEditorField(Object propertyId, Field<?> field) {
  6361. checkColumnExists(propertyId);
  6362. Field<?> oldField = editorFieldGroup.getField(propertyId);
  6363. if (oldField != null) {
  6364. editorFieldGroup.unbind(oldField);
  6365. oldField.setParent(null);
  6366. }
  6367. if (field != null) {
  6368. field.setParent(this);
  6369. editorFieldGroup.bind(field, propertyId);
  6370. }
  6371. // Store field for this property for future reference
  6372. editorFields.put(propertyId, field);
  6373. }
  6374. /**
  6375. * Saves all changes done to the bound fields.
  6376. * <p>
  6377. * <em>Note:</em> This is a pass-through call to the backing field group.
  6378. *
  6379. * @throws CommitException
  6380. * If the commit was aborted
  6381. *
  6382. * @see FieldGroup#commit()
  6383. */
  6384. public void saveEditor() throws CommitException {
  6385. try {
  6386. editorSaving = true;
  6387. editorFieldGroup.commit();
  6388. } finally {
  6389. editorSaving = false;
  6390. }
  6391. }
  6392. /**
  6393. * Cancels the currently active edit if any. Hides the editor and discards
  6394. * possible unsaved changes in the editor fields.
  6395. */
  6396. public void cancelEditor() {
  6397. if (editorSaving) {
  6398. // If the editor is already saving the values, it's too late to
  6399. // cancel it. This prevents item set changes from propagating during
  6400. // save, causing discard to be run during commit.
  6401. return;
  6402. }
  6403. if (isEditorActive()) {
  6404. getEditorRpc()
  6405. .cancel(getContainerDataSource().indexOfId(editedItemId));
  6406. doCancelEditor();
  6407. }
  6408. }
  6409. protected void doCancelEditor() {
  6410. editedItemId = null;
  6411. editorActive = false;
  6412. editorFieldGroup.discard();
  6413. editorFieldGroup.setItemDataSource(null);
  6414. if (datasource instanceof ItemSetChangeNotifier) {
  6415. ((ItemSetChangeNotifier) datasource)
  6416. .removeItemSetChangeListener(editorClosingItemSetListener);
  6417. }
  6418. // Mark Grid as dirty so the client side gets to know that the editors
  6419. // are no longer attached
  6420. markAsDirty();
  6421. }
  6422. void resetEditor() {
  6423. if (isEditorActive()) {
  6424. /*
  6425. * Simply force cancel the editing; throwing here would just make
  6426. * Grid.setContainerDataSource semantics more complicated.
  6427. */
  6428. cancelEditor();
  6429. }
  6430. for (Field<?> editor : getEditorFields()) {
  6431. editor.setParent(null);
  6432. }
  6433. editedItemId = null;
  6434. editorActive = false;
  6435. editorFieldGroup = new CustomFieldGroup();
  6436. }
  6437. /**
  6438. * Gets a collection of all fields bound to the item editor of this grid.
  6439. * <p>
  6440. * When {@link #editItem(Object) editItem} is called, fields are
  6441. * automatically created and bound to any unbound properties.
  6442. *
  6443. * @return a collection of all the fields bound to the item editor
  6444. */
  6445. Collection<Field<?>> getEditorFields() {
  6446. Collection<Field<?>> fields = editorFieldGroup.getFields();
  6447. assert allAttached(fields);
  6448. return fields;
  6449. }
  6450. private boolean allAttached(Collection<? extends Component> components) {
  6451. for (Component component : components) {
  6452. if (component.getParent() != this) {
  6453. return false;
  6454. }
  6455. }
  6456. return true;
  6457. }
  6458. /**
  6459. * Sets the field factory for the {@link FieldGroup}. The field factory is
  6460. * only used when {@link FieldGroup} creates a new field.
  6461. * <p>
  6462. * <em>Note:</em> This is a pass-through call to the backing field group.
  6463. *
  6464. * @param fieldFactory
  6465. * The field factory to use
  6466. */
  6467. public void setEditorFieldFactory(FieldGroupFieldFactory fieldFactory) {
  6468. editorFieldGroup.setFieldFactory(fieldFactory);
  6469. }
  6470. /**
  6471. * Sets the error handler for the editor.
  6472. *
  6473. * The error handler is called whenever there is an exception in the editor.
  6474. *
  6475. * @param editorErrorHandler
  6476. * The editor error handler to use
  6477. * @throws IllegalArgumentException
  6478. * if the error handler is null
  6479. */
  6480. public void setEditorErrorHandler(EditorErrorHandler editorErrorHandler)
  6481. throws IllegalArgumentException {
  6482. if (editorErrorHandler == null) {
  6483. throw new IllegalArgumentException(
  6484. "The error handler cannot be null");
  6485. }
  6486. this.editorErrorHandler = editorErrorHandler;
  6487. }
  6488. /**
  6489. * Gets the error handler used for the editor.
  6490. *
  6491. * @see #setErrorHandler(com.vaadin.server.ErrorHandler)
  6492. * @return the editor error handler, never null
  6493. */
  6494. public EditorErrorHandler getEditorErrorHandler() {
  6495. return editorErrorHandler;
  6496. }
  6497. /**
  6498. * Gets the field factory for the {@link FieldGroup}. The field factory is
  6499. * only used when {@link FieldGroup} creates a new field.
  6500. * <p>
  6501. * <em>Note:</em> This is a pass-through call to the backing field group.
  6502. *
  6503. * @return The field factory in use
  6504. */
  6505. public FieldGroupFieldFactory getEditorFieldFactory() {
  6506. return editorFieldGroup.getFieldFactory();
  6507. }
  6508. /**
  6509. * Sets the caption on the save button in the Grid editor.
  6510. *
  6511. * @param saveCaption
  6512. * the caption to set
  6513. * @throws IllegalArgumentException
  6514. * if {@code saveCaption} is {@code null}
  6515. */
  6516. public void setEditorSaveCaption(String saveCaption)
  6517. throws IllegalArgumentException {
  6518. if (saveCaption == null) {
  6519. throw new IllegalArgumentException("Save caption cannot be null");
  6520. }
  6521. getState().editorSaveCaption = saveCaption;
  6522. }
  6523. /**
  6524. * Gets the current caption of the save button in the Grid editor.
  6525. *
  6526. * @return the current caption of the save button
  6527. */
  6528. public String getEditorSaveCaption() {
  6529. return getState(false).editorSaveCaption;
  6530. }
  6531. /**
  6532. * Sets the caption on the cancel button in the Grid editor.
  6533. *
  6534. * @param cancelCaption
  6535. * the caption to set
  6536. * @throws IllegalArgumentException
  6537. * if {@code cancelCaption} is {@code null}
  6538. */
  6539. public void setEditorCancelCaption(String cancelCaption)
  6540. throws IllegalArgumentException {
  6541. if (cancelCaption == null) {
  6542. throw new IllegalArgumentException("Cancel caption cannot be null");
  6543. }
  6544. getState().editorCancelCaption = cancelCaption;
  6545. }
  6546. /**
  6547. * Gets the current caption of the cancel button in the Grid editor.
  6548. *
  6549. * @return the current caption of the cancel button
  6550. */
  6551. public String getEditorCancelCaption() {
  6552. return getState(false).editorCancelCaption;
  6553. }
  6554. /**
  6555. * Sets the buffered editor mode. The default mode is buffered (
  6556. * <code>true</code>).
  6557. *
  6558. * @since 7.6
  6559. * @param editorBuffered
  6560. * <code>true</code> to enable buffered editor,
  6561. * <code>false</code> to disable it
  6562. * @throws IllegalStateException
  6563. * If editor is active while attempting to change the buffered
  6564. * mode.
  6565. */
  6566. public void setEditorBuffered(boolean editorBuffered)
  6567. throws IllegalStateException {
  6568. if (isEditorActive()) {
  6569. throw new IllegalStateException(
  6570. "Can't change editor unbuffered mode while editor is active.");
  6571. }
  6572. getState().editorBuffered = editorBuffered;
  6573. editorFieldGroup.setBuffered(editorBuffered);
  6574. }
  6575. /**
  6576. * Gets the buffered editor mode.
  6577. *
  6578. * @since 7.6
  6579. * @return <code>true</code> if buffered editor is enabled,
  6580. * <code>false</code> otherwise
  6581. */
  6582. public boolean isEditorBuffered() {
  6583. return getState(false).editorBuffered;
  6584. }
  6585. @Override
  6586. public void addItemClickListener(ItemClickListener listener) {
  6587. addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
  6588. listener, ItemClickEvent.ITEM_CLICK_METHOD);
  6589. }
  6590. @Override
  6591. @Deprecated
  6592. public void addListener(ItemClickListener listener) {
  6593. addItemClickListener(listener);
  6594. }
  6595. @Override
  6596. public void removeItemClickListener(ItemClickListener listener) {
  6597. removeListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
  6598. listener);
  6599. }
  6600. @Override
  6601. @Deprecated
  6602. public void removeListener(ItemClickListener listener) {
  6603. removeItemClickListener(listener);
  6604. }
  6605. /**
  6606. * Requests that the column widths should be recalculated.
  6607. * <p>
  6608. * In most cases Grid will know when column widths need to be recalculated
  6609. * but this method can be used to force recalculation in situations when
  6610. * grid does not recalculate automatically.
  6611. *
  6612. * @since 7.4.1
  6613. */
  6614. public void recalculateColumnWidths() {
  6615. getRpcProxy(GridClientRpc.class).recalculateColumnWidths();
  6616. }
  6617. /**
  6618. * Registers a new column visibility change listener.
  6619. *
  6620. * @since 7.5.0
  6621. * @param listener
  6622. * the listener to register
  6623. */
  6624. public void addColumnVisibilityChangeListener(
  6625. ColumnVisibilityChangeListener listener) {
  6626. addListener(ColumnVisibilityChangeEvent.class, listener,
  6627. COLUMN_VISIBILITY_METHOD);
  6628. }
  6629. /**
  6630. * Removes a previously registered column visibility change listener.
  6631. *
  6632. * @since 7.5.0
  6633. * @param listener
  6634. * the listener to remove
  6635. */
  6636. public void removeColumnVisibilityChangeListener(
  6637. ColumnVisibilityChangeListener listener) {
  6638. removeListener(ColumnVisibilityChangeEvent.class, listener,
  6639. COLUMN_VISIBILITY_METHOD);
  6640. }
  6641. private void fireColumnVisibilityChangeEvent(Column column, boolean hidden,
  6642. boolean isUserOriginated) {
  6643. fireEvent(new ColumnVisibilityChangeEvent(this, column, hidden,
  6644. isUserOriginated));
  6645. }
  6646. /**
  6647. * Sets a new details generator for row details.
  6648. * <p>
  6649. * The currently opened row details will be re-rendered.
  6650. *
  6651. * @since 7.5.0
  6652. * @param detailsGenerator
  6653. * the details generator to set
  6654. * @throws IllegalArgumentException
  6655. * if detailsGenerator is <code>null</code>;
  6656. */
  6657. public void setDetailsGenerator(DetailsGenerator detailsGenerator)
  6658. throws IllegalArgumentException {
  6659. detailComponentManager.setDetailsGenerator(detailsGenerator);
  6660. }
  6661. /**
  6662. * Gets the current details generator for row details.
  6663. *
  6664. * @since 7.5.0
  6665. * @return the detailsGenerator the current details generator
  6666. */
  6667. public DetailsGenerator getDetailsGenerator() {
  6668. return detailComponentManager.getDetailsGenerator();
  6669. }
  6670. /**
  6671. * Shows or hides the details for a specific item.
  6672. *
  6673. * @since 7.5.0
  6674. * @param itemId
  6675. * the id of the item for which to set details visibility
  6676. * @param visible
  6677. * <code>true</code> to show the details, or <code>false</code>
  6678. * to hide them
  6679. */
  6680. public void setDetailsVisible(Object itemId, boolean visible) {
  6681. detailComponentManager.setDetailsVisible(itemId, visible);
  6682. }
  6683. /**
  6684. * Checks whether details are visible for the given item.
  6685. *
  6686. * @since 7.5.0
  6687. * @param itemId
  6688. * the id of the item for which to check details visibility
  6689. * @return <code>true</code> if the details are visible
  6690. */
  6691. public boolean isDetailsVisible(Object itemId) {
  6692. return detailComponentManager.isDetailsVisible(itemId);
  6693. }
  6694. private static SelectionMode getDefaultSelectionMode() {
  6695. return SelectionMode.SINGLE;
  6696. }
  6697. @Override
  6698. public void readDesign(Element design, DesignContext context) {
  6699. super.readDesign(design, context);
  6700. Attributes attrs = design.attributes();
  6701. if (attrs.hasKey("editable")) {
  6702. setEditorEnabled(DesignAttributeHandler.readAttribute("editable",
  6703. attrs, boolean.class));
  6704. }
  6705. if (attrs.hasKey("rows")) {
  6706. setHeightByRows(DesignAttributeHandler.readAttribute("rows", attrs,
  6707. double.class));
  6708. setHeightMode(HeightMode.ROW);
  6709. }
  6710. if (attrs.hasKey("selection-mode")) {
  6711. setSelectionMode(DesignAttributeHandler.readAttribute(
  6712. "selection-mode", attrs, SelectionMode.class));
  6713. }
  6714. if (design.children().size() > 0) {
  6715. if (design.children().size() > 1
  6716. || !design.child(0).tagName().equals("table")) {
  6717. throw new DesignException(
  6718. "Grid needs to have a table element as its only child");
  6719. }
  6720. Element table = design.child(0);
  6721. Elements colgroups = table.getElementsByTag("colgroup");
  6722. if (colgroups.size() != 1) {
  6723. throw new DesignException(
  6724. "Table element in declarative Grid needs to have a"
  6725. + " colgroup defining the columns used in Grid");
  6726. }
  6727. int i = 0;
  6728. for (Element col : colgroups.get(0).getElementsByTag("col")) {
  6729. String propertyId = DesignAttributeHandler.readAttribute(
  6730. "property-id", col.attributes(), "property-" + i,
  6731. String.class);
  6732. addColumn(propertyId, String.class).readDesign(col, context);
  6733. ++i;
  6734. }
  6735. for (Element child : table.children()) {
  6736. if (child.tagName().equals("thead")) {
  6737. header.readDesign(child, context);
  6738. } else if (child.tagName().equals("tbody")) {
  6739. for (Element row : child.children()) {
  6740. Elements cells = row.children();
  6741. Object[] data = new String[cells.size()];
  6742. for (int c = 0; c < cells.size(); ++c) {
  6743. data[c] = cells.get(c).html();
  6744. }
  6745. addRow(data);
  6746. }
  6747. // Since inline data is used, set HTML renderer for columns
  6748. for (Column c : getColumns()) {
  6749. c.setRenderer(new HtmlRenderer());
  6750. }
  6751. } else if (child.tagName().equals("tfoot")) {
  6752. footer.readDesign(child, context);
  6753. }
  6754. }
  6755. }
  6756. // Read frozen columns after columns are read.
  6757. if (attrs.hasKey("frozen-columns")) {
  6758. setFrozenColumnCount(DesignAttributeHandler
  6759. .readAttribute("frozen-columns", attrs, int.class));
  6760. }
  6761. }
  6762. @Override
  6763. public void writeDesign(Element design, DesignContext context) {
  6764. super.writeDesign(design, context);
  6765. Attributes attrs = design.attributes();
  6766. Grid def = context.getDefaultInstance(this);
  6767. DesignAttributeHandler.writeAttribute("editable", attrs,
  6768. isEditorEnabled(), def.isEditorEnabled(), boolean.class,
  6769. context);
  6770. DesignAttributeHandler.writeAttribute("frozen-columns", attrs,
  6771. getFrozenColumnCount(), def.getFrozenColumnCount(), int.class,
  6772. context);
  6773. if (getHeightMode() == HeightMode.ROW) {
  6774. DesignAttributeHandler.writeAttribute("rows", attrs,
  6775. getHeightByRows(), def.getHeightByRows(), double.class,
  6776. context);
  6777. }
  6778. SelectionMode selectionMode = null;
  6779. if (selectionModel.getClass().equals(SingleSelectionModel.class)) {
  6780. selectionMode = SelectionMode.SINGLE;
  6781. } else if (selectionModel.getClass()
  6782. .equals(MultiSelectionModel.class)) {
  6783. selectionMode = SelectionMode.MULTI;
  6784. } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
  6785. selectionMode = SelectionMode.NONE;
  6786. }
  6787. assert selectionMode != null : "Unexpected selection model "
  6788. + selectionModel.getClass().getName();
  6789. DesignAttributeHandler.writeAttribute("selection-mode", attrs,
  6790. selectionMode, getDefaultSelectionMode(), SelectionMode.class,
  6791. context);
  6792. if (columns.isEmpty()) {
  6793. // Empty grid. Structure not needed.
  6794. return;
  6795. }
  6796. // Do structure.
  6797. Element tableElement = design.appendElement("table");
  6798. Element colGroup = tableElement.appendElement("colgroup");
  6799. List<Column> columnOrder = getColumns();
  6800. for (int i = 0; i < columnOrder.size(); ++i) {
  6801. Column column = columnOrder.get(i);
  6802. Element colElement = colGroup.appendElement("col");
  6803. column.writeDesign(colElement, context);
  6804. }
  6805. // Always write thead. Reads correctly when there no header rows
  6806. header.writeDesign(tableElement.appendElement("thead"), context);
  6807. if (context.shouldWriteData(this)) {
  6808. Element bodyElement = tableElement.appendElement("tbody");
  6809. for (Object itemId : datasource.getItemIds()) {
  6810. Element tableRow = bodyElement.appendElement("tr");
  6811. for (Column c : getColumns()) {
  6812. Object value = datasource.getItem(itemId)
  6813. .getItemProperty(c.getPropertyId()).getValue();
  6814. tableRow.appendElement("td")
  6815. .append((value != null
  6816. ? DesignFormatter
  6817. .encodeForTextNode(value.toString())
  6818. : ""));
  6819. }
  6820. }
  6821. }
  6822. if (footer.getRowCount() > 0) {
  6823. footer.writeDesign(tableElement.appendElement("tfoot"), context);
  6824. }
  6825. }
  6826. @Override
  6827. public void addBlurListener(BlurListener listener) {
  6828. addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
  6829. BlurListener.blurMethod);
  6830. }
  6831. @Override
  6832. public void removeBlurListener(BlurListener listener) {
  6833. removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
  6834. }
  6835. @Override
  6836. public void addFocusListener(FocusListener listener) {
  6837. addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
  6838. FocusListener.focusMethod);
  6839. }
  6840. @Override
  6841. public void removeFocusListener(FocusListener listener) {
  6842. removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
  6843. }
  6844. @Override
  6845. public void focus() {
  6846. super.focus();
  6847. }
  6848. @Override
  6849. public int getTabIndex() {
  6850. return getState(false).tabIndex;
  6851. }
  6852. @Override
  6853. public void setTabIndex(int tabIndex) {
  6854. getState().tabIndex = tabIndex;
  6855. }
  6856. @Override
  6857. protected Collection<String> getCustomAttributes() {
  6858. Collection<String> result = super.getCustomAttributes();
  6859. result.add("editor-enabled");
  6860. result.add("editable");
  6861. result.add("frozen-column-count");
  6862. result.add("frozen-columns");
  6863. result.add("height-by-rows");
  6864. result.add("rows");
  6865. result.add("selection-mode");
  6866. result.add("header-visible");
  6867. result.add("footer-visible");
  6868. result.add("editor-error-handler");
  6869. result.add("height-mode");
  6870. return result;
  6871. }
  6872. }