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