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 259KB

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