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

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
Migrating 7.7.1, 7.7.2, 7.7.3 to V8. commit 11c3f8bd9ea65f7a7b8da9a282c31a127bd475a6 - Test and its UI class are added (both V8 and V7). Required functionality should be available via modern GWT version. commit 729dbf96fe76e7627168ab2c9d1d71c4eb7214c8 - About update release notes. No need to be included. commit 675f38349c43ac45dae40cf33a7b1fd0f8f261ca - V8 already contains correct Import-Packages section which uses osgi.javax.servlet.version variable whise version is 3.0.0 at the moment. commit 5da7c052f55cb4703b74f38f5bb19fc3f3fa2a76 - Use Vaadin plugin 7.7.0 from 7.7.0.alpha1. Is not applicable. commit 1df80001ab6c916effa917781dba652d09d01056 - Updated tutorial to Vaadin 7.7.0. Is not applicable. The tutorial already contains correct links and updated source code snippets. commit 8b4f0ed8a894b04902a5d4258119dcdc8e76d1e0 - set-property-fallback name="user.agent" value="safari". Is already there. commit 28ed04e827669cc4dd329331dac9699bd93f70bc - Fix animation end listeners so they are always removed. Is already there. commit 408253bc3f8bd3975f0525ce6832be214a3552e9 - Use servlet context classloader when finding servlet class for websockets. Is already there. commit 7a6f250d89474849648ed2ee96a6bfb78c3b9ca8 - Fire actions before removing menu from the DOM. Is already there. commit 9b66c6eb9bebf657d3f2def8c767e0e9d51cc92c - Do not run test on IE8 as IE8 is broken. Transplanted. commit 3faa43ff39ecda56587b93f0c5e262a2907871a7 - Discard for DateField when the data source contains null. It is not applicable for V8 (There is no anymore discard method in DateField (and no datasource suport in field)). Transplanted for DateField in compatibility. commit e0c1f91a3d6d1884e07ce8d1ba957aff6a9bf29a - Fix ComboBox paging when number of items equals page length. It's already done by another fix which replaced ComboBox in compatibility package to the V7 version. commit 83a1b8a0961cc9b2d43e01757530cefd035b0a22 - Update DOM and update escalator row count in the correct order. Transplanted. commit 45f2fba8ff7a4b62680618a325d4afcebfb7a1e9 - Prevent editor from being canceled while it is being saved. Transplanted to compatibility package. Is not applicable to modern Grid. commit ad67f7f43afb0feec5e029aea90297f2abe4f2c1 - Delete broken stylesheet and revert to default style until a new stylesheet is created. Is already there. commit c970a78d42a2d8f1745df7a11a74f3731f8be9a5 - Always show loading indicator for JavaScript RPC. Transplanted. commit 2aad3416061586f7e2649160bd832eefe03702ad - Make test independent of any converters present in the factory. It's already there. commit c9ad48430be135d18fe9f30868e091dd51c57b94 - Do not include yuicompressor for Sass compiler. Transplanted. Exclusion is added into vaadin/pom.xml commit 52d01a68e91ce73306b3a1747af97e928048ecdf - Test for Firefox download disconnecting push channel. Transplanted. commit 4bc375d1d21f468e6433da3a183150e0bfe0cae4 - Handle encoded URL characters correctly when constructing widget set name. Transplanted. commit 17ba88eaf87e15e6f3c729e5c7f8e875d5f86d8d - Update version to 7.7-SNAPSHOT. Is not applicable. commit 47b7b13e5c959de3bd925693b074d85e7625a87e - Ensure Firefox always updates the grid scrollbar. Transplanted. Made changes in the logic to the test for modern Grid component. commit 4d851ba21d1b8f35685b631d2845731f8fb33252 - Calculate column widths immediately if there is data. Transplanted to both client side modules. commit 8f0b1a1dd026a756912c9f21bd2b34ea46897c7f - Skip Maven enforcer plugin during demo validation. Transplanted (one build file is affected). commit 62815353e1b9d3cd126809f5c818ad35bf913807 - Build demos from 7.7 branch (now for master branch). FW8 demos are added (one build file is affected). commit 815d72115d5aaf3676daefd5642115577e4151ef - Make test pass on all browsers. Transplanted to both V7 and V8 version tests. commit 516c428ca127e3c31b7b4d74220e4b7eed4571be - Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit b00c580ed70f682a42afbfa91f978921bb86c2cd - Use correct column index when calculating min width during resize. Transplanted into both client side classes (main and compatibility) as is. Test for V7 is transplanted as is. Test for V8 is written from scratch based on V7 version. commit 7dd91cf057eb06a09009096a8278f34aad9bd8d9 - Fix regression that broke widget set compilation in 7.7.1. It's already there. commit c665731b0b97b697e80c47955d3558c19f0c81cb - Ensure temporary layout manager state is cleared at the end of a layout phase. Transplanted to the one LayoutManager class. commit 57a965251afdb5ee9ac1913a0101d854d8215aa6 - Fix assertion error when column widths are calculated. Transplanted to both versions of the client Grid widget. commit c5c52684eb30d924cb75a632b526a0f879d5a33c - Format Java files using Eclipse Neon and Vaadin settings. Only formatting changes. Is not transplanted. f5d06d877165bf413ec71c4fc88cf46c8c57a372 - Change javadoc to a style Eclipse formatter can handle. Transplanted to both versions of the client Grid widget. commit 6033e13c20b3d6e8b6f5add0f786d5ab2e1bb3fe - Make initially disabled grid work when enabled. Transplanted to both client side modules. commit a2d6e4fb4b1fd13e9a1b88f2ab1b78d14d8b64a9 - Use requestAnimationFrame when scrolling in Grid. Transplanted to both client side modules. commit fe9438e7b77c606855cfd739dd7e30b3f8cd4165 - Specify branch also for Sampler. Is not applicable for master branch. commit 1ec5d8ef7cb8bbd82bae1c9b79a376a5dca28f48 - Update to Chrome 53. Is already there. commit 961851bfbc4844474299433c34af6c9e4323d891 - Updated link to new step 1 video in tutorial. Is already there. commit 41dc2fe1611adc70d00e6f77debb2a6d4dcdefb0 - Revert "Use widget set specified by init parameter. Transplanted to the one UIProvider class. commit 092b4f7f3192555fe3ae22ac03a89ac2ada2a2dd - Use widget set specified by init parameter. Transplanted to the common server side classes. commit 977cec7e3107c2da306d46449dbf32f6544313be - Fix widget set builder to create widget set in correct location. Transplanted to the one ClassPathExplorer class file. commit 6c12ad89ea1064cd4cc0456baca5ee00ae76d032 - Format project pom files using correct settings. Is not transplanted: only formatting changes for POM files. commit 0aad93ecc1ce743dffc093ce7ae2ef88831f6073 - Add tests for widgetset compilation in different modes. Transplanted. New test projects. commit 0a3a1ef8321ed421be2337034fdb1cae2c434c3d - Use versions-maven-plugin 2.3 to avoid NPE while setting project version. Is already there. Change-Id: Ie3a5088f25de1772f01ea30c4a5eba0b169ee0ab
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 years ago
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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371
  1. /*
  2. * Copyright 2000-2021 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.client.widgets;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Collection;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.HashSet;
  23. import java.util.Iterator;
  24. import java.util.LinkedHashMap;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Map.Entry;
  28. import java.util.Objects;
  29. import java.util.Optional;
  30. import java.util.Set;
  31. import java.util.TreeMap;
  32. import java.util.concurrent.atomic.AtomicInteger;
  33. import java.util.logging.Level;
  34. import java.util.logging.Logger;
  35. import java.util.stream.Stream;
  36. import com.google.gwt.core.client.Scheduler;
  37. import com.google.gwt.core.client.Scheduler.ScheduledCommand;
  38. import com.google.gwt.core.shared.GWT;
  39. import com.google.gwt.dom.client.BrowserEvents;
  40. import com.google.gwt.dom.client.DivElement;
  41. import com.google.gwt.dom.client.Document;
  42. import com.google.gwt.dom.client.Element;
  43. import com.google.gwt.dom.client.EventTarget;
  44. import com.google.gwt.dom.client.NativeEvent;
  45. import com.google.gwt.dom.client.Node;
  46. import com.google.gwt.dom.client.Style;
  47. import com.google.gwt.dom.client.Style.Display;
  48. import com.google.gwt.dom.client.Style.Unit;
  49. import com.google.gwt.dom.client.TableCellElement;
  50. import com.google.gwt.dom.client.TableRowElement;
  51. import com.google.gwt.dom.client.TableSectionElement;
  52. import com.google.gwt.dom.client.Touch;
  53. import com.google.gwt.event.dom.client.ClickHandler;
  54. import com.google.gwt.event.dom.client.KeyCodes;
  55. import com.google.gwt.event.dom.client.KeyDownEvent;
  56. import com.google.gwt.event.dom.client.KeyDownHandler;
  57. import com.google.gwt.event.dom.client.KeyEvent;
  58. import com.google.gwt.event.dom.client.MouseEvent;
  59. import com.google.gwt.event.logical.shared.CloseEvent;
  60. import com.google.gwt.event.logical.shared.CloseHandler;
  61. import com.google.gwt.event.shared.HandlerRegistration;
  62. import com.google.gwt.touch.client.Point;
  63. import com.google.gwt.user.client.DOM;
  64. import com.google.gwt.user.client.Event;
  65. import com.google.gwt.user.client.Timer;
  66. import com.google.gwt.user.client.ui.Button;
  67. import com.google.gwt.user.client.ui.CheckBox;
  68. import com.google.gwt.user.client.ui.Composite;
  69. import com.google.gwt.user.client.ui.FlowPanel;
  70. import com.google.gwt.user.client.ui.HasEnabled;
  71. import com.google.gwt.user.client.ui.HasWidgets;
  72. import com.google.gwt.user.client.ui.MenuBar;
  73. import com.google.gwt.user.client.ui.MenuItem;
  74. import com.google.gwt.user.client.ui.PopupPanel;
  75. import com.google.gwt.user.client.ui.ResizeComposite;
  76. import com.google.gwt.user.client.ui.Widget;
  77. import com.vaadin.client.BrowserInfo;
  78. import com.vaadin.client.DeferredWorker;
  79. import com.vaadin.client.Focusable;
  80. import com.vaadin.client.WidgetUtil;
  81. import com.vaadin.client.WidgetUtil.Reference;
  82. import com.vaadin.client.data.DataChangeHandler;
  83. import com.vaadin.client.data.DataSource;
  84. import com.vaadin.client.data.DataSource.RowHandle;
  85. import com.vaadin.client.renderers.ComplexRenderer;
  86. import com.vaadin.client.renderers.Renderer;
  87. import com.vaadin.client.renderers.WidgetRenderer;
  88. import com.vaadin.client.ui.FocusUtil;
  89. import com.vaadin.client.ui.SubPartAware;
  90. import com.vaadin.client.ui.dd.DragAndDropHandler;
  91. import com.vaadin.client.ui.dd.DragAndDropHandler.DragAndDropCallback;
  92. import com.vaadin.client.ui.dd.DragHandle;
  93. import com.vaadin.client.ui.dd.DragHandle.DragHandleCallback;
  94. import com.vaadin.client.widget.escalator.Cell;
  95. import com.vaadin.client.widget.escalator.ColumnConfiguration;
  96. import com.vaadin.client.widget.escalator.EscalatorUpdater;
  97. import com.vaadin.client.widget.escalator.FlyweightCell;
  98. import com.vaadin.client.widget.escalator.Row;
  99. import com.vaadin.client.widget.escalator.RowContainer;
  100. import com.vaadin.client.widget.escalator.RowVisibilityChangeHandler;
  101. import com.vaadin.client.widget.escalator.ScrollbarBundle.Direction;
  102. import com.vaadin.client.widget.escalator.Spacer;
  103. import com.vaadin.client.widget.escalator.SpacerUpdater;
  104. import com.vaadin.client.widget.escalator.events.RowHeightChangedEvent;
  105. import com.vaadin.client.widget.escalator.events.RowHeightChangedHandler;
  106. import com.vaadin.client.widget.escalator.events.SpacerIndexChangedEvent;
  107. import com.vaadin.client.widget.escalator.events.SpacerIndexChangedHandler;
  108. import com.vaadin.client.widget.escalator.events.SpacerVisibilityChangedEvent;
  109. import com.vaadin.client.widget.escalator.events.SpacerVisibilityChangedHandler;
  110. import com.vaadin.client.widget.grid.AutoScroller;
  111. import com.vaadin.client.widget.grid.AutoScroller.AutoScrollerCallback;
  112. import com.vaadin.client.widget.grid.AutoScroller.ScrollAxis;
  113. import com.vaadin.client.widget.grid.CellReference;
  114. import com.vaadin.client.widget.grid.CellStyleGenerator;
  115. import com.vaadin.client.widget.grid.DataAvailableEvent;
  116. import com.vaadin.client.widget.grid.DataAvailableHandler;
  117. import com.vaadin.client.widget.grid.DefaultEditorEventHandler;
  118. import com.vaadin.client.widget.grid.DetailsGenerator;
  119. import com.vaadin.client.widget.grid.EditorHandler;
  120. import com.vaadin.client.widget.grid.EditorHandler.EditorRequest;
  121. import com.vaadin.client.widget.grid.EventCellReference;
  122. import com.vaadin.client.widget.grid.GridEventHandler;
  123. import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator;
  124. import com.vaadin.client.widget.grid.RendererCellReference;
  125. import com.vaadin.client.widget.grid.RowReference;
  126. import com.vaadin.client.widget.grid.RowStyleGenerator;
  127. import com.vaadin.client.widget.grid.events.AbstractGridKeyEventHandler;
  128. import com.vaadin.client.widget.grid.events.AbstractGridMouseEventHandler;
  129. import com.vaadin.client.widget.grid.events.BodyClickHandler;
  130. import com.vaadin.client.widget.grid.events.BodyDoubleClickHandler;
  131. import com.vaadin.client.widget.grid.events.BodyKeyDownHandler;
  132. import com.vaadin.client.widget.grid.events.BodyKeyPressHandler;
  133. import com.vaadin.client.widget.grid.events.BodyKeyUpHandler;
  134. import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
  135. import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
  136. import com.vaadin.client.widget.grid.events.ColumnResizeEvent;
  137. import com.vaadin.client.widget.grid.events.ColumnResizeHandler;
  138. import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
  139. import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
  140. import com.vaadin.client.widget.grid.events.FooterClickHandler;
  141. import com.vaadin.client.widget.grid.events.FooterDoubleClickHandler;
  142. import com.vaadin.client.widget.grid.events.FooterKeyDownHandler;
  143. import com.vaadin.client.widget.grid.events.FooterKeyPressHandler;
  144. import com.vaadin.client.widget.grid.events.FooterKeyUpHandler;
  145. import com.vaadin.client.widget.grid.events.GridClickEvent;
  146. import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
  147. import com.vaadin.client.widget.grid.events.GridEnabledEvent;
  148. import com.vaadin.client.widget.grid.events.GridEnabledHandler;
  149. import com.vaadin.client.widget.grid.events.GridKeyDownEvent;
  150. import com.vaadin.client.widget.grid.events.GridKeyPressEvent;
  151. import com.vaadin.client.widget.grid.events.GridKeyUpEvent;
  152. import com.vaadin.client.widget.grid.events.GridSelectionAllowedEvent;
  153. import com.vaadin.client.widget.grid.events.GridSelectionAllowedHandler;
  154. import com.vaadin.client.widget.grid.events.HeaderClickHandler;
  155. import com.vaadin.client.widget.grid.events.HeaderDoubleClickHandler;
  156. import com.vaadin.client.widget.grid.events.HeaderKeyDownHandler;
  157. import com.vaadin.client.widget.grid.events.HeaderKeyPressHandler;
  158. import com.vaadin.client.widget.grid.events.HeaderKeyUpHandler;
  159. import com.vaadin.client.widget.grid.events.ScrollEvent;
  160. import com.vaadin.client.widget.grid.events.ScrollHandler;
  161. import com.vaadin.client.widget.grid.events.SelectAllEvent;
  162. import com.vaadin.client.widget.grid.events.SelectAllHandler;
  163. import com.vaadin.client.widget.grid.selection.HasSelectionHandlers;
  164. import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
  165. import com.vaadin.client.widget.grid.selection.SelectionEvent;
  166. import com.vaadin.client.widget.grid.selection.SelectionHandler;
  167. import com.vaadin.client.widget.grid.selection.SelectionModel;
  168. import com.vaadin.client.widget.grid.selection.SelectionModelWithSelectionColumn;
  169. import com.vaadin.client.widget.grid.sort.Sort;
  170. import com.vaadin.client.widget.grid.sort.SortEvent;
  171. import com.vaadin.client.widget.grid.sort.SortHandler;
  172. import com.vaadin.client.widget.grid.sort.SortOrder;
  173. import com.vaadin.client.widgets.Escalator.AbstractRowContainer;
  174. import com.vaadin.client.widgets.Escalator.SubPartArguments;
  175. import com.vaadin.client.widgets.Grid.Editor.State;
  176. import com.vaadin.client.widgets.Grid.StaticSection.StaticRow;
  177. import com.vaadin.shared.Range;
  178. import com.vaadin.shared.Registration;
  179. import com.vaadin.shared.data.sort.SortDirection;
  180. import com.vaadin.shared.ui.ContentMode;
  181. import com.vaadin.shared.ui.grid.ColumnResizeMode;
  182. import com.vaadin.shared.ui.grid.GridConstants;
  183. import com.vaadin.shared.ui.grid.GridConstants.Section;
  184. import com.vaadin.shared.ui.grid.GridStaticCellType;
  185. import com.vaadin.shared.ui.grid.HeightMode;
  186. import com.vaadin.shared.ui.grid.ScrollDestination;
  187. import com.vaadin.shared.util.SharedUtil;
  188. /**
  189. * A data grid view that supports columns and lazy loading of data rows from a
  190. * data source.
  191. *
  192. * <h1>Columns</h1>
  193. * <p>
  194. * Each column in Grid is represented by a {@link Column}. Each
  195. * {@code GridColumn} has a custom implementation for
  196. * {@link Column#getValue(Object)} that gets the row object as an argument, and
  197. * returns the value for that particular column, extracted from the row object.
  198. * <p>
  199. * Each column also has a Renderer. Its function is to take the value that is
  200. * given by the {@code GridColumn} and display it to the user. A simple column
  201. * might have a {@link com.vaadin.client.renderers.TextRenderer TextRenderer}
  202. * that simply takes in a {@code String} and displays it as the cell's content.
  203. * A more complex renderer might be
  204. * {@link com.vaadin.client.renderers.ProgressBarRenderer ProgressBarRenderer}
  205. * that takes in a floating point number, and displays a progress bar instead,
  206. * based on the given number.
  207. * <p>
  208. * <em>See:</em> {@link #addColumn(Column)}, {@link #addColumn(Column, int)} and
  209. * {@link #addColumns(Column...)}. <em>Also</em>
  210. * {@link Column#setRenderer(Renderer)}.
  211. *
  212. * <h1>Data Sources</h1>
  213. * <p>
  214. * Grid gets its data from a {@link DataSource}, providing row objects to Grid
  215. * from a user-defined endpoint. It can be either a local in-memory data source
  216. * (e.g. {@link com.vaadin.client.widget.grid.datasources.ListDataSource
  217. * ListDataSource}) or even a remote one, retrieving data from e.g. a REST API
  218. * (see {@link com.vaadin.client.data.AbstractRemoteDataSource
  219. * AbstractRemoteDataSource}).
  220. *
  221. *
  222. * @param <T>
  223. * The row type of the grid. The row type is the POJO type from where
  224. * the data is retrieved into the column cells.
  225. * @since 7.4
  226. * @author Vaadin Ltd
  227. */
  228. @SuppressWarnings("deprecation")
  229. public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
  230. SubPartAware, DeferredWorker, Focusable,
  231. com.google.gwt.user.client.ui.Focusable, HasWidgets, HasEnabled {
  232. private static final String STYLE_NAME = "v-grid";
  233. private static final String SELECT_ALL_CHECKBOX_CLASSNAME = "-select-all-checkbox";
  234. /**
  235. * Abstract base class for Grid header and footer sections.
  236. *
  237. * @since 7.5.0
  238. *
  239. * @param <ROWTYPE>
  240. * the type of the rows in the section
  241. */
  242. public abstract static class StaticSection<ROWTYPE extends StaticSection.StaticRow<?>> {
  243. /**
  244. * A header or footer cell. Has a simple textual caption.
  245. *
  246. */
  247. public static class StaticCell {
  248. private Object content = null;
  249. private int colspan = 1;
  250. private StaticSection<?> section;
  251. private GridStaticCellType type = GridStaticCellType.TEXT;
  252. private String styleName = null;
  253. private String description = null;
  254. private ContentMode descriptionContentMode = ContentMode.TEXT;
  255. /**
  256. * Sets the text displayed in this cell.
  257. *
  258. * @param text
  259. * a plain text caption
  260. */
  261. public void setText(String text) {
  262. detach();
  263. content = text;
  264. type = GridStaticCellType.TEXT;
  265. section.requestSectionRefresh();
  266. }
  267. /**
  268. * Returns the text displayed in this cell.
  269. *
  270. * @return the plain text caption
  271. */
  272. public String getText() {
  273. if (type != GridStaticCellType.TEXT) {
  274. throw new IllegalStateException(
  275. "Cannot fetch Text from a cell with type " + type);
  276. }
  277. return (String) content;
  278. }
  279. /**
  280. * Returns the section where this cell belongs.
  281. *
  282. * @return the section
  283. */
  284. protected StaticSection<?> getSection() {
  285. assert section != null;
  286. return section;
  287. }
  288. /**
  289. * Sets the section where this cell belongs. Should not be null.
  290. *
  291. * @param section
  292. * the section to set
  293. */
  294. protected void setSection(StaticSection<?> section) {
  295. this.section = section;
  296. }
  297. /**
  298. * Returns the amount of columns the cell spans. By default is 1.
  299. *
  300. * @return The amount of columns the cell spans.
  301. */
  302. public int getColspan() {
  303. return colspan;
  304. }
  305. /**
  306. * Sets the amount of columns the cell spans. Must be more or equal
  307. * to 1. By default is 1.
  308. *
  309. * @param colspan
  310. * the colspan to set
  311. */
  312. public void setColspan(int colspan) {
  313. if (colspan < 1) {
  314. throw new IllegalArgumentException(
  315. "Colspan cannot be less than 1");
  316. }
  317. this.colspan = colspan;
  318. section.requestSectionRefresh();
  319. }
  320. /**
  321. * Returns the html inside the cell.
  322. *
  323. * @throws IllegalStateException
  324. * if trying to retrive HTML from a cell with a type
  325. * other than {@link GridStaticCellType#HTML}.
  326. * @return the html content of the cell.
  327. */
  328. public String getHtml() {
  329. if (type != GridStaticCellType.HTML) {
  330. throw new IllegalStateException(
  331. "Cannot fetch HTML from a cell with type " + type);
  332. }
  333. return (String) content;
  334. }
  335. /**
  336. * Sets the content of the cell to the provided html. All previous
  337. * content is discarded and the cell type is set to
  338. * {@link GridStaticCellType#HTML}.
  339. *
  340. * @param html
  341. * The html content of the cell
  342. */
  343. public void setHtml(String html) {
  344. detach();
  345. content = html;
  346. type = GridStaticCellType.HTML;
  347. section.requestSectionRefresh();
  348. }
  349. /**
  350. * Returns the widget in the cell.
  351. *
  352. * @throws IllegalStateException
  353. * if the cell is not {@link GridStaticCellType#WIDGET}
  354. *
  355. * @return the widget in the cell
  356. */
  357. public Widget getWidget() {
  358. if (type != GridStaticCellType.WIDGET) {
  359. throw new IllegalStateException(
  360. "Cannot fetch Widget from a cell with type "
  361. + type);
  362. }
  363. return (Widget) content;
  364. }
  365. /**
  366. * Set widget as the content of the cell. The type of the cell
  367. * becomes {@link GridStaticCellType#WIDGET}. All previous content
  368. * is discarded.
  369. *
  370. * @param widget
  371. * The widget to add to the cell. Should not be
  372. * previously attached anywhere (widget.getParent ==
  373. * null).
  374. */
  375. public void setWidget(Widget widget) {
  376. if (content == widget) {
  377. return;
  378. }
  379. detach();
  380. content = widget;
  381. type = GridStaticCellType.WIDGET;
  382. section.requestSectionRefresh();
  383. }
  384. /**
  385. * Returns the type of the cell.
  386. *
  387. * @return the type of content the cell contains.
  388. */
  389. public GridStaticCellType getType() {
  390. return type;
  391. }
  392. /**
  393. * Returns the custom style name for this cell.
  394. *
  395. * @return the style name or null if no style name has been set
  396. */
  397. public String getStyleName() {
  398. return styleName;
  399. }
  400. /**
  401. * Sets a custom style name for this cell.
  402. *
  403. * @param styleName
  404. * the style name to set or null to not use any style
  405. * name
  406. */
  407. public void setStyleName(String styleName) {
  408. this.styleName = styleName;
  409. section.requestSectionRefresh();
  410. }
  411. /**
  412. * Called when the cell is detached from the row
  413. *
  414. * @since 7.6.3
  415. */
  416. void detach() {
  417. if (content instanceof Widget) {
  418. // Widget in the cell, detach it
  419. section.getGrid().detachWidget((Widget) content);
  420. }
  421. }
  422. /**
  423. * Gets the tooltip for the cell.
  424. * <p>
  425. * The tooltip is shown in the mode returned by
  426. * {@link #getDescriptionContentMode()}.
  427. *
  428. * @return the tooltip text for this cell
  429. * @since 8.4
  430. */
  431. public String getDescription() {
  432. return description;
  433. }
  434. /**
  435. * Sets the tooltip for the cell.
  436. * <p>
  437. * By default, tooltips are shown as plain text. For HTML tooltips,
  438. * see {@link #setDescription(String, ContentMode)} or
  439. * {@link #setDescriptionContentMode(ContentMode)}.
  440. *
  441. * @param description
  442. * the tooltip to show when hovering the cell
  443. * @since 8.4
  444. */
  445. public void setDescription(String description) {
  446. this.description = description;
  447. }
  448. /**
  449. * Sets the tooltip for the cell to be shown with the given content
  450. * mode.
  451. *
  452. * @see ContentMode
  453. * @param description
  454. * the tooltip to show when hovering the cell
  455. * @param descriptionContentMode
  456. * the content mode to use for the tooltip (HTML or plain
  457. * text)
  458. * @since 8.4
  459. */
  460. public void setDescription(String description,
  461. ContentMode descriptionContentMode) {
  462. setDescription(description);
  463. setDescriptionContentMode(descriptionContentMode);
  464. }
  465. /**
  466. * Gets the content mode for the tooltip.
  467. * <p>
  468. * The content mode determines how the tooltip is shown.
  469. *
  470. * @see ContentMode
  471. * @return the content mode for the tooltip
  472. * @since 8.4
  473. */
  474. public ContentMode getDescriptionContentMode() {
  475. return descriptionContentMode;
  476. }
  477. /**
  478. * Sets the content mode for the tooltip.
  479. *
  480. * @see ContentMode
  481. * @param descriptionContentMode
  482. * the content mode for the tooltip
  483. * @since 8.4
  484. */
  485. public void setDescriptionContentMode(
  486. ContentMode descriptionContentMode) {
  487. this.descriptionContentMode = descriptionContentMode;
  488. }
  489. }
  490. /**
  491. * Abstract base class for Grid header and footer rows.
  492. *
  493. * @param <CELLTYPE>
  494. * the type of the cells in the row
  495. */
  496. public abstract static class StaticRow<CELLTYPE extends StaticCell> {
  497. private Map<Column<?, ?>, CELLTYPE> cells = new HashMap<>();
  498. private StaticSection<?> section;
  499. /**
  500. * Map from cell meta data to sets of spanned columns .
  501. */
  502. private Map<CELLTYPE, Set<Column<?, ?>>> cellGroups = new HashMap<>();
  503. /**
  504. * A custom style name for the row or null if none is set.
  505. */
  506. private String styleName = null;
  507. /**
  508. * Returns the cell on given GridColumn. If the column is merged
  509. * returned cell is the cell for the whole group.
  510. *
  511. * @param column
  512. * the column in grid
  513. * @return the cell on given column, merged cell for merged columns,
  514. * null if not found
  515. */
  516. public CELLTYPE getCell(Column<?, ?> column) {
  517. CELLTYPE cell = getMergedCellForColumn(column);
  518. if (cell != null) {
  519. return cell;
  520. }
  521. return cells.get(column);
  522. }
  523. /**
  524. * Returns <code>true</code> if this row contains spanned cells.
  525. *
  526. * @since 7.5.0
  527. * @return does this row contain spanned cells
  528. */
  529. public boolean hasSpannedCells() {
  530. return !cellGroups.isEmpty();
  531. }
  532. /**
  533. * Merges columns cells in a row.
  534. *
  535. * @param columns
  536. * the columns which header should be merged
  537. * @return the remaining visible cell after the merge, or the cell
  538. * on first column if all are hidden
  539. */
  540. public CELLTYPE join(Column<?, ?>... columns) {
  541. if (columns.length <= 1) {
  542. throw new IllegalArgumentException(
  543. "You can't merge less than 2 columns together.");
  544. }
  545. HashSet<Column<?, ?>> columnGroup = new HashSet<>();
  546. // NOTE: this doesn't care about hidden columns, those are
  547. // filtered in calculateColspans()
  548. for (Column<?, ?> column : columns) {
  549. if (!cells.containsKey(column)) {
  550. throw new IllegalArgumentException(
  551. "Given column does not exists on row "
  552. + column);
  553. } else if (getMergedCellForColumn(column) != null) {
  554. throw new IllegalStateException(
  555. "Column is already in a group.");
  556. }
  557. columnGroup.add(column);
  558. }
  559. CELLTYPE joinedCell = createCell();
  560. cellGroups.put(joinedCell, columnGroup);
  561. joinedCell.setSection(getSection());
  562. calculateColspans();
  563. return joinedCell;
  564. }
  565. /**
  566. * Merges columns cells in a row.
  567. *
  568. * @param cells
  569. * The cells to merge. Must be from the same row.
  570. * @return The remaining visible cell after the merge, or the first
  571. * cell if all columns are hidden
  572. */
  573. @SuppressWarnings("unchecked")
  574. public CELLTYPE join(CELLTYPE... cells) {
  575. if (cells.length <= 1) {
  576. throw new IllegalArgumentException(
  577. "You can't merge less than 2 cells together.");
  578. }
  579. Column<?, ?>[] columns = new Column<?, ?>[cells.length];
  580. int j = 0;
  581. for (Column<?, ?> column : this.cells.keySet()) {
  582. CELLTYPE cell = this.cells.get(column);
  583. if (!this.cells.containsValue(cells[j])) {
  584. throw new IllegalArgumentException(
  585. "Given cell does not exists on row");
  586. } else if (cell.equals(cells[j])) {
  587. columns[j++] = column;
  588. if (j == cells.length) {
  589. break;
  590. }
  591. }
  592. }
  593. return join(columns);
  594. }
  595. private CELLTYPE getMergedCellForColumn(Column<?, ?> column) {
  596. for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups
  597. .entrySet()) {
  598. if (entry.getValue().contains(column)) {
  599. return entry.getKey();
  600. }
  601. }
  602. return null;
  603. }
  604. /**
  605. * Returns the size of the cell group for the given column. Zero if
  606. * no cell group is set.
  607. *
  608. * @param column
  609. * the column whose cell group size is being investigated
  610. * @return size of the cell group, default is {@code 0}
  611. */
  612. protected int getSizeOfCellGroup(Column<?, ?> column) {
  613. for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups
  614. .entrySet()) {
  615. if (entry.getValue().contains(column)) {
  616. return entry.getValue().size();
  617. }
  618. }
  619. return 0;
  620. }
  621. void calculateColspans() {
  622. // Reset all cells
  623. for (CELLTYPE cell : this.cells.values()) {
  624. cell.setColspan(1);
  625. }
  626. // Set colspan for grouped cells
  627. for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups
  628. .entrySet()) {
  629. CELLTYPE mergedCell = entry.getKey();
  630. if (!checkMergedCellIsContinuous(entry.getValue())) {
  631. // on error simply break the merged cell
  632. mergedCell.setColspan(1);
  633. } else {
  634. int colSpan = 0;
  635. for (Column<?, ?> column : entry.getValue()) {
  636. if (!column.isHidden()) {
  637. colSpan++;
  638. }
  639. }
  640. // colspan can't be 0
  641. mergedCell.setColspan(Math.max(1, colSpan));
  642. }
  643. }
  644. }
  645. private boolean checkMergedCellIsContinuous(
  646. Set<Column<?, ?>> mergedCell) {
  647. // no matter if hidden or not, just check for continuous order
  648. final List<Column<?, ?>> columnOrder = new ArrayList<>(
  649. section.grid.getColumns());
  650. if (!columnOrder.containsAll(mergedCell)) {
  651. return false;
  652. }
  653. for (int i = 0; i < columnOrder.size(); ++i) {
  654. if (!mergedCell.contains(columnOrder.get(i))) {
  655. continue;
  656. }
  657. for (int j = 1; j < mergedCell.size(); ++j) {
  658. if (!mergedCell.contains(columnOrder.get(i + j))) {
  659. return false;
  660. }
  661. }
  662. return true;
  663. }
  664. return false;
  665. }
  666. /**
  667. * Creates and adds a cell to this row for the given column.
  668. *
  669. * @param column
  670. * the column that requires a new cell
  671. */
  672. protected void addCell(Column<?, ?> column) {
  673. CELLTYPE cell = createCell();
  674. cell.setSection(getSection());
  675. cells.put(column, cell);
  676. }
  677. /**
  678. * Removes a cell for the given column from this row.
  679. *
  680. * @param column
  681. * the column that should have its cell reference cleared
  682. */
  683. protected void removeCell(Column<?, ?> column) {
  684. cells.remove(column);
  685. }
  686. /**
  687. * Creates a cell of a type that matches this row.
  688. *
  689. * @return a new cell
  690. */
  691. protected abstract CELLTYPE createCell();
  692. /**
  693. * Returns the section where this row belongs.
  694. *
  695. * @return the section
  696. */
  697. protected StaticSection<?> getSection() {
  698. return section;
  699. }
  700. /**
  701. * Sets the section where this row belongs. Should not be null.
  702. *
  703. * @param section
  704. * the section to set
  705. */
  706. protected void setSection(StaticSection<?> section) {
  707. this.section = section;
  708. }
  709. /**
  710. * Returns the custom style name for this row.
  711. *
  712. * @return the style name or null if no style name has been set
  713. */
  714. public String getStyleName() {
  715. return styleName;
  716. }
  717. /**
  718. * Sets a custom style name for this row.
  719. *
  720. * @param styleName
  721. * the style name to set or null to not use any style
  722. * name
  723. */
  724. public void setStyleName(String styleName) {
  725. this.styleName = styleName;
  726. section.requestSectionRefresh();
  727. }
  728. /**
  729. * Called when the row is detached from the grid
  730. *
  731. * @since 7.6.3
  732. */
  733. void detach() {
  734. // Avoid calling detach twice for a merged cell
  735. HashSet<CELLTYPE> cells = new HashSet<>();
  736. for (Column<?, ?> column : getSection().grid.getColumns()) {
  737. cells.add(getCell(column));
  738. }
  739. for (CELLTYPE cell : cells) {
  740. cell.detach();
  741. }
  742. }
  743. }
  744. private Grid<?> grid;
  745. private List<ROWTYPE> rows = new ArrayList<>();
  746. private boolean visible = true;
  747. /**
  748. * Creates and returns a new instance of the row type.
  749. *
  750. * @return the created row
  751. */
  752. protected abstract ROWTYPE createRow();
  753. /**
  754. * Informs the grid that this section should be re-rendered.
  755. * <p>
  756. * <b>Note</b> that re-render means calling update() on each cell,
  757. * preAttach()/postAttach()/preDetach()/postDetach() is not called as
  758. * the cells are not removed from the DOM.
  759. */
  760. protected abstract void requestSectionRefresh();
  761. /**
  762. * Sets the visibility of the whole section.
  763. *
  764. * @param visible
  765. * true to show this section, false to hide
  766. */
  767. public void setVisible(boolean visible) {
  768. if (this.visible != visible) {
  769. this.visible = visible;
  770. requestSectionRefresh();
  771. }
  772. }
  773. /**
  774. * Returns the visibility of this section.
  775. *
  776. * @return true if visible, false otherwise.
  777. */
  778. public boolean isVisible() {
  779. return visible;
  780. }
  781. /**
  782. * Inserts a new row at the given position. Shifts the row currently at
  783. * that position and any subsequent rows down (adds one to their
  784. * indices).
  785. *
  786. * @param index
  787. * the position at which to insert the row
  788. * @return the new row
  789. *
  790. * @throws IndexOutOfBoundsException
  791. * if the index is out of bounds
  792. * @see #appendRow()
  793. * @see #prependRow()
  794. * @see #removeRow(int)
  795. * @see #removeRow(StaticRow)
  796. */
  797. public ROWTYPE addRowAt(int index) {
  798. ROWTYPE row = createRow();
  799. row.setSection(this);
  800. for (int i = 0; i < getGrid().getColumnCount(); ++i) {
  801. row.addCell(grid.getColumn(i));
  802. }
  803. rows.add(index, row);
  804. requestSectionRefresh();
  805. return row;
  806. }
  807. /**
  808. * Adds a new row at the top of this section.
  809. *
  810. * @return the new row
  811. * @see #appendRow()
  812. * @see #addRowAt(int)
  813. * @see #removeRow(int)
  814. * @see #removeRow(StaticRow)
  815. */
  816. public ROWTYPE prependRow() {
  817. return addRowAt(0);
  818. }
  819. /**
  820. * Adds a new row at the bottom of this section.
  821. *
  822. * @return the new row
  823. * @see #prependRow()
  824. * @see #addRowAt(int)
  825. * @see #removeRow(int)
  826. * @see #removeRow(StaticRow)
  827. */
  828. public ROWTYPE appendRow() {
  829. return addRowAt(rows.size());
  830. }
  831. /**
  832. * Removes the row at the given position.
  833. *
  834. * @param index
  835. * the position of the row
  836. *
  837. * @throws IndexOutOfBoundsException
  838. * if the index is out of bounds
  839. * @see #addRowAt(int)
  840. * @see #appendRow()
  841. * @see #prependRow()
  842. * @see #removeRow(StaticRow)
  843. */
  844. public void removeRow(int index) {
  845. ROWTYPE row = rows.remove(index);
  846. row.detach();
  847. requestSectionRefresh();
  848. }
  849. /**
  850. * Removes the given row from the section.
  851. *
  852. * @param row
  853. * the row to be removed
  854. *
  855. * @throws IllegalArgumentException
  856. * if the row does not exist in this section
  857. * @see #addRowAt(int)
  858. * @see #appendRow()
  859. * @see #prependRow()
  860. * @see #removeRow(int)
  861. */
  862. public void removeRow(ROWTYPE row) {
  863. try {
  864. removeRow(rows.indexOf(row));
  865. } catch (IndexOutOfBoundsException e) {
  866. throw new IllegalArgumentException(
  867. "Section does not contain the given row");
  868. }
  869. }
  870. /**
  871. * Returns the row at the given position.
  872. *
  873. * @param index
  874. * the position of the row
  875. * @return the row with the given index
  876. *
  877. * @throws IndexOutOfBoundsException
  878. * if the index is out of bounds
  879. */
  880. public ROWTYPE getRow(int index) {
  881. try {
  882. return rows.get(index);
  883. } catch (IndexOutOfBoundsException e) {
  884. throw new IllegalArgumentException(
  885. "Row with index " + index + " does not exist");
  886. }
  887. }
  888. /**
  889. * Returns the number of rows in this section.
  890. *
  891. * @return the number of rows
  892. */
  893. public int getRowCount() {
  894. return rows.size();
  895. }
  896. /**
  897. * Returns the current list of rows within this section.
  898. *
  899. * @return list of rows
  900. */
  901. protected List<ROWTYPE> getRows() {
  902. return rows;
  903. }
  904. /**
  905. * Returns how many visible rows there are within this section (all or
  906. * nothing, visibility cannot be set on the row level).
  907. *
  908. * @return amount of visible rows
  909. */
  910. protected int getVisibleRowCount() {
  911. return isVisible() ? getRowCount() : 0;
  912. }
  913. /**
  914. * Adds cells for the given column to all the rows within this section.
  915. *
  916. * @param column
  917. * the column that requires cells
  918. */
  919. protected void addColumn(Column<?, ?> column) {
  920. for (ROWTYPE row : rows) {
  921. row.addCell(column);
  922. }
  923. }
  924. /**
  925. * Removes cells for the given column from all the rows within this
  926. * section.
  927. *
  928. * @param column
  929. * the column that should have its cells removed
  930. */
  931. protected void removeColumn(Column<?, ?> column) {
  932. for (ROWTYPE row : rows) {
  933. row.removeCell(column);
  934. }
  935. }
  936. /**
  937. * Sets the grid this section belongs to. Should not be null.
  938. *
  939. * @param grid
  940. * the parent grid
  941. */
  942. protected void setGrid(Grid<?> grid) {
  943. this.grid = grid;
  944. }
  945. /**
  946. * Returns the grid this section belongs to.
  947. *
  948. * @return the parent grid
  949. */
  950. protected Grid<?> getGrid() {
  951. assert grid != null;
  952. return grid;
  953. }
  954. /**
  955. * Triggers column span calculation for all the rows within this section
  956. * that contain spanned cells.
  957. */
  958. protected void updateColSpans() {
  959. for (ROWTYPE row : rows) {
  960. if (row.hasSpannedCells()) {
  961. row.calculateColspans();
  962. }
  963. }
  964. }
  965. }
  966. /**
  967. * Represents the header section of a Grid. A header consists of a single
  968. * header row containing a header cell for each column. Each cell has a
  969. * simple textual caption.
  970. */
  971. protected static class Header extends StaticSection<HeaderRow> {
  972. private HeaderRow defaultRow;
  973. private boolean markAsDirty = false;
  974. @Override
  975. public void removeRow(int index) {
  976. HeaderRow removedRow = getRow(index);
  977. super.removeRow(index);
  978. if (removedRow == defaultRow) {
  979. setDefaultRow(null);
  980. }
  981. }
  982. /**
  983. * Sets the default row of this header. The default row is a special
  984. * header row providing a user interface for sorting columns.
  985. *
  986. * @param row
  987. * the new default row, or null for no default row
  988. *
  989. * @throws IllegalArgumentException
  990. * this header does not contain the row
  991. */
  992. public void setDefaultRow(HeaderRow row) {
  993. if (row == defaultRow) {
  994. return;
  995. }
  996. if (row != null && !getRows().contains(row)) {
  997. throw new IllegalArgumentException(
  998. "Cannot set a default row that does not exist in the container");
  999. }
  1000. if (defaultRow != null) {
  1001. defaultRow.setDefault(false);
  1002. }
  1003. if (row != null) {
  1004. row.setDefault(true);
  1005. }
  1006. defaultRow = row;
  1007. requestSectionRefresh();
  1008. }
  1009. /**
  1010. * Returns the current default row of this header. The default row is a
  1011. * special header row providing a user interface for sorting columns.
  1012. *
  1013. * @return the default row or null if no default row set
  1014. */
  1015. public HeaderRow getDefaultRow() {
  1016. return defaultRow;
  1017. }
  1018. @Override
  1019. protected HeaderRow createRow() {
  1020. return new HeaderRow();
  1021. }
  1022. @Override
  1023. protected void requestSectionRefresh() {
  1024. markAsDirty = true;
  1025. /*
  1026. * Defer the refresh so if we multiple times call refreshSection()
  1027. * (for example when updating cell values) we only get one actual
  1028. * refresh in the end.
  1029. */
  1030. Scheduler.get().scheduleFinally(() -> {
  1031. if (markAsDirty) {
  1032. markAsDirty = false;
  1033. getGrid().refreshHeader();
  1034. }
  1035. });
  1036. }
  1037. /**
  1038. * Returns the events consumed by the header.
  1039. *
  1040. * @return a collection of BrowserEvents
  1041. */
  1042. public Collection<String> getConsumedEvents() {
  1043. return Arrays.asList(BrowserEvents.TOUCHSTART,
  1044. BrowserEvents.TOUCHMOVE, BrowserEvents.TOUCHEND,
  1045. BrowserEvents.TOUCHCANCEL, BrowserEvents.CLICK);
  1046. }
  1047. @Override
  1048. protected void addColumn(Column<?, ?> column) {
  1049. super.addColumn(column);
  1050. // Add default content for new columns.
  1051. if (defaultRow != null) {
  1052. column.setDefaultHeaderContent(defaultRow.getCell(column));
  1053. }
  1054. }
  1055. }
  1056. /**
  1057. * A single row in a grid header section.
  1058. *
  1059. */
  1060. public static class HeaderRow extends StaticSection.StaticRow<HeaderCell> {
  1061. private boolean isDefault = false;
  1062. /**
  1063. * Sets whether this is the default header row or not. Setting this
  1064. * value to {@code true} resets the cell contents for this row to column
  1065. * header captions. Setting this value to {@code false} doesn't update
  1066. * the cell contents.
  1067. *
  1068. * @param isDefault
  1069. * {@code true} if this row should be default header row,
  1070. * {@code false} otherwise
  1071. */
  1072. protected void setDefault(boolean isDefault) {
  1073. this.isDefault = isDefault;
  1074. if (isDefault) {
  1075. for (Column<?, ?> column : getSection().grid.getColumns()) {
  1076. column.setDefaultHeaderContent(getCell(column));
  1077. }
  1078. }
  1079. }
  1080. /**
  1081. * Returns whether this is the default header row or not.
  1082. *
  1083. * @return {@code true} if this row is the default header row,
  1084. * {@code false} otherwise
  1085. */
  1086. public boolean isDefault() {
  1087. return isDefault;
  1088. }
  1089. @Override
  1090. protected HeaderCell createCell() {
  1091. return new HeaderCell();
  1092. }
  1093. }
  1094. /**
  1095. * A single cell in a grid header row. Has a caption and, if it's in a
  1096. * default row, a drag handle.
  1097. */
  1098. public static class HeaderCell extends StaticSection.StaticCell {
  1099. }
  1100. /**
  1101. * Represents the footer section of a Grid. The footer is always empty.
  1102. */
  1103. protected static class Footer extends StaticSection<FooterRow> {
  1104. private boolean markAsDirty = false;
  1105. @Override
  1106. protected FooterRow createRow() {
  1107. return new FooterRow();
  1108. }
  1109. @Override
  1110. protected void requestSectionRefresh() {
  1111. markAsDirty = true;
  1112. /*
  1113. * Defer the refresh so if we multiple times call refreshSection()
  1114. * (for example when updating cell values) we only get one actual
  1115. * refresh in the end.
  1116. */
  1117. Scheduler.get().scheduleFinally(() -> {
  1118. if (markAsDirty) {
  1119. markAsDirty = false;
  1120. getGrid().refreshFooter();
  1121. }
  1122. });
  1123. }
  1124. }
  1125. /**
  1126. * A single cell in a grid Footer row. Has a textual caption.
  1127. *
  1128. */
  1129. public static class FooterCell extends StaticSection.StaticCell {
  1130. }
  1131. /**
  1132. * A single row in a grid Footer section.
  1133. *
  1134. */
  1135. public static class FooterRow extends StaticSection.StaticRow<FooterCell> {
  1136. @Override
  1137. protected FooterCell createCell() {
  1138. return new FooterCell();
  1139. }
  1140. }
  1141. private static class EditorRequestImpl<T> implements EditorRequest<T> {
  1142. /**
  1143. * A callback interface used to notify the invoker of the editor handler
  1144. * of completed editor requests.
  1145. *
  1146. * @param <T>
  1147. * the row data type
  1148. */
  1149. public static interface RequestCallback<T> {
  1150. /**
  1151. * The method that must be called when the request has been
  1152. * processed correctly.
  1153. *
  1154. * @param request
  1155. * the original request object
  1156. */
  1157. public void onSuccess(EditorRequest<T> request);
  1158. /**
  1159. * The method that must be called when processing the request has
  1160. * produced an aborting error.
  1161. *
  1162. * @param request
  1163. * the original request object
  1164. */
  1165. public void onError(EditorRequest<T> request);
  1166. }
  1167. private Grid<T> grid;
  1168. private final int rowIndex;
  1169. private final int columnIndexDOM;
  1170. private RequestCallback<T> callback;
  1171. private boolean completed = false;
  1172. public EditorRequestImpl(Grid<T> grid, int rowIndex, int columnIndexDOM,
  1173. RequestCallback<T> callback) {
  1174. this.grid = grid;
  1175. this.rowIndex = rowIndex;
  1176. this.columnIndexDOM = columnIndexDOM;
  1177. this.callback = callback;
  1178. }
  1179. @Override
  1180. public int getRowIndex() {
  1181. return rowIndex;
  1182. }
  1183. @Override
  1184. public int getColumnIndex() {
  1185. return columnIndexDOM;
  1186. }
  1187. @Override
  1188. public T getRow() {
  1189. return grid.getDataSource().getRow(rowIndex);
  1190. }
  1191. @Override
  1192. public Grid<T> getGrid() {
  1193. return grid;
  1194. }
  1195. @Override
  1196. public Widget getWidget(Grid.Column<?, T> column) {
  1197. Widget w = grid.getEditorWidget(column);
  1198. assert w != null;
  1199. return w;
  1200. }
  1201. private void complete(String errorMessage,
  1202. Collection<Column<?, T>> errorColumns) {
  1203. if (completed) {
  1204. throw new IllegalStateException(
  1205. "An EditorRequest must be completed exactly once");
  1206. }
  1207. completed = true;
  1208. if (errorColumns == null) {
  1209. errorColumns = Collections.emptySet();
  1210. }
  1211. grid.getEditor().setEditorError(errorMessage, errorColumns);
  1212. }
  1213. @Override
  1214. public void success() {
  1215. complete(null, null);
  1216. if (callback != null) {
  1217. callback.onSuccess(this);
  1218. }
  1219. }
  1220. @Override
  1221. public void failure() {
  1222. complete("", null);
  1223. if (callback != null) {
  1224. callback.onError(this);
  1225. }
  1226. }
  1227. @Override
  1228. public boolean isCompleted() {
  1229. return completed;
  1230. }
  1231. }
  1232. /**
  1233. * A wrapper for native DOM events originating from Grid. In addition to the
  1234. * native event, contains a {@link CellReference} instance specifying which
  1235. * cell the event originated from.
  1236. *
  1237. * @since 7.6
  1238. * @param <T>
  1239. * The row type of the grid
  1240. */
  1241. public static class GridEvent<T> {
  1242. private Event event;
  1243. private EventCellReference<T> cell;
  1244. private boolean handled = false;
  1245. /**
  1246. * Constructs a new {@link GridEvent}.
  1247. *
  1248. * @param event
  1249. * a native event
  1250. * @param cell
  1251. * the cell the event targets
  1252. */
  1253. protected GridEvent(Event event, EventCellReference<T> cell) {
  1254. this.event = event;
  1255. this.cell = cell;
  1256. }
  1257. /**
  1258. * Returns the wrapped DOM event.
  1259. *
  1260. * @return the DOM event
  1261. */
  1262. public Event getDomEvent() {
  1263. return event;
  1264. }
  1265. /**
  1266. * Returns the Grid cell this event originated from.
  1267. *
  1268. * @return the event cell
  1269. */
  1270. public EventCellReference<T> getCell() {
  1271. return cell;
  1272. }
  1273. /**
  1274. * Returns the Grid instance this event originated from.
  1275. *
  1276. * @return the grid
  1277. */
  1278. public Grid<T> getGrid() {
  1279. return cell.getGrid();
  1280. }
  1281. /**
  1282. * Check whether this event has already been marked as handled.
  1283. *
  1284. * @return whether this event has already been marked as handled
  1285. */
  1286. public boolean isHandled() {
  1287. return handled;
  1288. }
  1289. /**
  1290. * Set the status of this event. Setting to {@code true} effectively
  1291. * marks this event as having already been handled.
  1292. *
  1293. * @param handled
  1294. * {@code true} if the event has already been handled,
  1295. * {@code false} otherwise
  1296. */
  1297. public void setHandled(boolean handled) {
  1298. this.handled = handled;
  1299. }
  1300. }
  1301. /**
  1302. * A wrapper for native DOM events related to the {@link Editor Grid editor}
  1303. * .
  1304. *
  1305. * @since 7.6
  1306. * @param <T>
  1307. * the row type of the grid
  1308. */
  1309. public static class EditorDomEvent<T> extends GridEvent<T> {
  1310. private final Widget editorWidget;
  1311. /**
  1312. * Constructs a new {@link EditorDomEvent}.
  1313. *
  1314. * @param event
  1315. * a native event
  1316. * @param cell
  1317. * the cell the event targets
  1318. * @param editorWidget
  1319. * the editor widget of that cell
  1320. */
  1321. protected EditorDomEvent(Event event, EventCellReference<T> cell,
  1322. Widget editorWidget) {
  1323. super(event, cell);
  1324. this.editorWidget = editorWidget;
  1325. }
  1326. /**
  1327. * Returns the editor of the Grid this event originated from.
  1328. *
  1329. * @return the related editor instance
  1330. */
  1331. public Editor<T> getEditor() {
  1332. return getGrid().getEditor();
  1333. }
  1334. /**
  1335. * Returns the currently focused editor widget.
  1336. *
  1337. * @return the focused editor widget or {@code null} if not editable
  1338. */
  1339. public Widget getEditorWidget() {
  1340. return editorWidget;
  1341. }
  1342. /**
  1343. * Returns the row index the editor is open at. If the editor is not
  1344. * open, returns -1.
  1345. *
  1346. * @return the index of the edited row or -1 if editor is not open
  1347. */
  1348. public int getRowIndex() {
  1349. return getEditor().rowIndex;
  1350. }
  1351. /**
  1352. * Returns the DOM column index (excluding hidden columns) the editor
  1353. * was opened at. If the editor is not open, returns -1.
  1354. *
  1355. * @return the column index or -1 if editor is not open
  1356. */
  1357. public int getFocusedColumnIndex() {
  1358. return getEditor().focusedColumnIndexDOM;
  1359. }
  1360. }
  1361. /**
  1362. * An editor UI for Grid rows. A single Grid row at a time can be opened for
  1363. * editing.
  1364. *
  1365. * @since 7.6
  1366. * @param <T>
  1367. * the row type of the grid
  1368. */
  1369. public static class Editor<T> implements DeferredWorker {
  1370. /**
  1371. * @deprecated use {@link DefaultEditorEventHandler#KEYCODE_OPEN}
  1372. * instead
  1373. */
  1374. @Deprecated
  1375. public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER;
  1376. /**
  1377. * @deprecated use {@link DefaultEditorEventHandler#KEYCODE_CLOSE}
  1378. * instead
  1379. */
  1380. @Deprecated
  1381. public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE;
  1382. private static final String ERROR_CLASS_NAME = "error";
  1383. private static final String NOT_EDITABLE_CLASS_NAME = "not-editable";
  1384. /**
  1385. * A handler for events related to the Grid editor. Responsible for
  1386. * opening, moving or closing the editor based on the received event.
  1387. *
  1388. * @since 7.6
  1389. * @author Vaadin Ltd
  1390. * @param <T>
  1391. * the row type of the grid
  1392. */
  1393. public interface EventHandler<T> {
  1394. /**
  1395. * Handles editor-related events in an appropriate way. Opens,
  1396. * moves, or closes the editor based on the given event.
  1397. *
  1398. * @param event
  1399. * the received event
  1400. * @return true if the event was handled and nothing else should be
  1401. * done, false otherwise
  1402. */
  1403. boolean handleEvent(EditorDomEvent<T> event);
  1404. /**
  1405. * Confirms the valid status of the binder so as to determine
  1406. * whether to allow pending navigation action.
  1407. *
  1408. * @param isValid
  1409. * {@code true} if the binder value is valid
  1410. */
  1411. void confirmValidity(boolean isValid);
  1412. }
  1413. /**
  1414. * The internal state options for the editor.
  1415. */
  1416. protected enum State {
  1417. /** Editor is closed or disabled and as such not in edit mode. */
  1418. INACTIVE,
  1419. /**
  1420. * Editor is getting activated. If activation is successful, next
  1421. * state will be {@link State#BINDING} .
  1422. */
  1423. ACTIVATING,
  1424. /**
  1425. * Editor binding is being set up. If binding is successful, next
  1426. * state will be {@link State#ACTIVE}.
  1427. */
  1428. BINDING,
  1429. /** Editor is open and enabled and in edit mode. */
  1430. ACTIVE,
  1431. /**
  1432. * Editor is saving changes. If saving is successful, state will be
  1433. * updated to {@link State#INACTIVE}.
  1434. */
  1435. SAVING
  1436. }
  1437. private Grid<T> grid;
  1438. private EditorHandler<T> handler;
  1439. private EventHandler<T> eventHandler = GWT
  1440. .create(DefaultEditorEventHandler.class);
  1441. private DivElement editorOverlay = DivElement.as(DOM.createDiv());
  1442. private DivElement cellWrapper = DivElement.as(DOM.createDiv());
  1443. private DivElement frozenCellWrapper = DivElement.as(DOM.createDiv());
  1444. private DivElement messageAndButtonsWrapper = DivElement
  1445. .as(DOM.createDiv());
  1446. private DivElement messageWrapper = DivElement.as(DOM.createDiv());
  1447. private DivElement buttonsWrapper = DivElement.as(DOM.createDiv());
  1448. // Element which contains the error message for the editor
  1449. // Should only be added to the DOM when there's a message to show
  1450. private DivElement message = DivElement.as(DOM.createDiv());
  1451. private Map<Column<?, T>, Widget> columnToWidget = new HashMap<>();
  1452. private List<HandlerRegistration> focusHandlers = new ArrayList<>();
  1453. private boolean enabled = false;
  1454. private State state = State.INACTIVE;
  1455. private int rowIndex = -1;
  1456. private int focusedColumnIndexDOM = -1;
  1457. private String styleName = null;
  1458. private HandlerRegistration hScrollHandler;
  1459. private final Button saveButton;
  1460. private final Button cancelButton;
  1461. private static final int SAVE_TIMEOUT_MS = 5000;
  1462. private final Timer saveTimeout = new Timer() {
  1463. @Override
  1464. public void run() {
  1465. getLogger().warning(
  1466. "Editor save action is taking longer than expected ("
  1467. + SAVE_TIMEOUT_MS + "ms). Does your "
  1468. + EditorHandler.class.getSimpleName()
  1469. + " remember to call success() or fail()?");
  1470. }
  1471. };
  1472. private final EditorRequestImpl.RequestCallback<T> saveRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
  1473. @Override
  1474. public void onSuccess(EditorRequest<T> request) {
  1475. if (state == State.SAVING) {
  1476. cleanup();
  1477. cancel(true);
  1478. grid.clearSortOrder();
  1479. }
  1480. }
  1481. @Override
  1482. public void onError(EditorRequest<T> request) {
  1483. if (state == State.SAVING) {
  1484. cleanup();
  1485. }
  1486. }
  1487. private void cleanup() {
  1488. state = State.ACTIVE;
  1489. setButtonsEnabled(true);
  1490. saveTimeout.cancel();
  1491. }
  1492. };
  1493. private static final int BIND_TIMEOUT_MS = 5000;
  1494. private final Timer bindTimeout = new Timer() {
  1495. @Override
  1496. public void run() {
  1497. getLogger().warning(
  1498. "Editor bind action is taking longer than expected ("
  1499. + BIND_TIMEOUT_MS + "ms). Does your "
  1500. + EditorHandler.class.getSimpleName()
  1501. + " remember to call success() or fail()?");
  1502. }
  1503. };
  1504. private final EditorRequestImpl.RequestCallback<T> bindRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
  1505. @Override
  1506. public void onSuccess(EditorRequest<T> request) {
  1507. if (state == State.BINDING) {
  1508. state = State.ACTIVE;
  1509. bindTimeout.cancel();
  1510. rowIndex = request.getRowIndex();
  1511. focusedColumnIndexDOM = request.getColumnIndex();
  1512. if (focusedColumnIndexDOM >= 0) {
  1513. // Update internal focus of Grid
  1514. grid.focusCell(rowIndex, focusedColumnIndexDOM);
  1515. }
  1516. showOverlay();
  1517. }
  1518. }
  1519. @Override
  1520. public void onError(EditorRequest<T> request) {
  1521. if (state == State.BINDING) {
  1522. if (rowIndex == -1) {
  1523. doCancel();
  1524. } else {
  1525. state = State.ACTIVE;
  1526. // TODO: Maybe restore focus?
  1527. }
  1528. bindTimeout.cancel();
  1529. }
  1530. }
  1531. };
  1532. /** A set of all the columns that display an error flag. */
  1533. private final Set<Column<?, T>> columnErrors = new HashSet<>();
  1534. private boolean buffered = true;
  1535. /** Original position of editor */
  1536. private double originalTop;
  1537. /** Original scroll position of grid when editor was opened */
  1538. private double originalScrollTop;
  1539. private RowHandle<T> pinnedRowHandle;
  1540. /**
  1541. * Constructs a new {@link Editor}.
  1542. */
  1543. public Editor() {
  1544. saveButton = new Button();
  1545. saveButton.setText(GridConstants.DEFAULT_SAVE_CAPTION);
  1546. saveButton.addClickHandler(event -> {
  1547. save();
  1548. FocusUtil.setFocus(grid, true);
  1549. });
  1550. cancelButton = new Button();
  1551. cancelButton.setText(GridConstants.DEFAULT_CANCEL_CAPTION);
  1552. cancelButton.addClickHandler(event -> {
  1553. cancel();
  1554. FocusUtil.setFocus(grid, true);
  1555. });
  1556. }
  1557. /**
  1558. * Sets an error message for the editor, or removes it if the given
  1559. * message is {@code null}. If the editor is in edit mode or currently
  1560. * processing a save operation, updates the editor cells to show error
  1561. * styles for the given columns and clears error styles from any other
  1562. * columns.
  1563. *
  1564. * @param errorMessage
  1565. * the message to set, or {@code null} if no message should
  1566. * be shown
  1567. * @param errorColumns
  1568. * the columns that currently contain errors
  1569. */
  1570. public void setEditorError(String errorMessage,
  1571. Collection<Column<?, T>> errorColumns) {
  1572. if (errorMessage == null) {
  1573. message.removeFromParent();
  1574. } else {
  1575. message.setInnerText(errorMessage);
  1576. if (message.getParentElement() == null) {
  1577. messageWrapper.appendChild(message);
  1578. }
  1579. }
  1580. // In unbuffered mode only show message wrapper if there is an error
  1581. if (!isBuffered()) {
  1582. setMessageAndButtonsWrapperVisible(errorMessage != null);
  1583. }
  1584. if (state == State.ACTIVE || state == State.SAVING) {
  1585. for (Column<?, T> c : grid.getColumns()) {
  1586. grid.getEditor().setEditorColumnError(c,
  1587. errorColumns.contains(c));
  1588. }
  1589. }
  1590. }
  1591. /**
  1592. * Returns the index of the row that is currently assigned to the
  1593. * editor. If the editor is open and in the edit mode, that row's
  1594. * contents can be edited via the editor cells. -1 if the editor is
  1595. * closed.
  1596. *
  1597. * @return currently assigned row index, or -1 if not set
  1598. */
  1599. public int getRow() {
  1600. return rowIndex;
  1601. }
  1602. /**
  1603. * If a cell of this Grid had focus once this editRow call was
  1604. * triggered, the editor component at the previously focused column
  1605. * index will be focused.
  1606. *
  1607. * If a Grid cell was not focused prior to calling this method, it will
  1608. * be equivalent to {@code editRow(rowIndex, -1)}.
  1609. *
  1610. * @param rowIndex
  1611. * the index of the row to be edited
  1612. *
  1613. * @see #editRow(int, int)
  1614. */
  1615. public void editRow(int rowIndex) {
  1616. // Focus the last focused column in the editor if grid or its child
  1617. // was focused before the edit request
  1618. Cell focusedCell = grid.cellFocusHandler.getFocusedCell();
  1619. Element focusedElement = WidgetUtil.getFocusedElement();
  1620. if (focusedCell != null && focusedElement != null
  1621. && grid.getElement().isOrHasChild(focusedElement)) {
  1622. editRow(rowIndex, focusedCell.getColumn());
  1623. } else {
  1624. editRow(rowIndex, -1);
  1625. }
  1626. }
  1627. /**
  1628. * Opens the editor over the row with the given index and attempts to
  1629. * focus the editor widget in the given column index. Does not move
  1630. * focus if the widget is not focusable or if the column index is -1.
  1631. *
  1632. * @param rowIndex
  1633. * the index of the row to be edited
  1634. * @param columnIndexDOM
  1635. * the column index (excluding hidden columns) of the editor
  1636. * widget that should be initially focused or -1 to not set
  1637. * focus
  1638. *
  1639. * @throws IllegalStateException
  1640. * if this editor is not enabled
  1641. * @throws IllegalStateException
  1642. * if this editor is already in edit mode and in buffered
  1643. * mode
  1644. *
  1645. * @since 7.5
  1646. */
  1647. public void editRow(final int rowIndex, final int columnIndexDOM) {
  1648. if (!enabled) {
  1649. throw new IllegalStateException(
  1650. "Cannot edit row: editor is not enabled");
  1651. }
  1652. if (isWorkPending()) {
  1653. // Request pending a response, don't move try to start another
  1654. // request.
  1655. return;
  1656. }
  1657. if (state != State.INACTIVE && this.rowIndex != rowIndex) {
  1658. if (isBuffered()) {
  1659. throw new IllegalStateException(
  1660. "Cannot edit row: editor already in edit mode");
  1661. } else if (!columnErrors.isEmpty()) {
  1662. // Don't move row if errors are present
  1663. // FIXME: Should attempt bind if error field values have
  1664. // changed.
  1665. return;
  1666. }
  1667. }
  1668. if (columnIndexDOM >= grid.getVisibleColumns().size()) {
  1669. throw new IllegalArgumentException(
  1670. "Edited column index " + columnIndexDOM
  1671. + " was bigger than visible column count.");
  1672. }
  1673. if (this.rowIndex == rowIndex
  1674. && focusedColumnIndexDOM == columnIndexDOM) {
  1675. // NO-OP
  1676. return;
  1677. }
  1678. if (this.rowIndex == rowIndex) {
  1679. if (focusedColumnIndexDOM != columnIndexDOM) {
  1680. if (columnIndexDOM >= grid.getFrozenColumnCount()) {
  1681. // Scroll to new focused column.
  1682. grid.getEscalator().scrollToColumn(columnIndexDOM,
  1683. ScrollDestination.ANY, 0);
  1684. }
  1685. focusedColumnIndexDOM = columnIndexDOM;
  1686. }
  1687. updateHorizontalScrollPosition();
  1688. // Update Grid internal focus and focus widget if possible
  1689. if (focusedColumnIndexDOM >= 0) {
  1690. grid.focusCell(rowIndex, focusedColumnIndexDOM);
  1691. focusColumn(focusedColumnIndexDOM);
  1692. }
  1693. // No need to request anything from the editor handler.
  1694. return;
  1695. }
  1696. state = State.ACTIVATING;
  1697. grid.scrollToRow(rowIndex, ScrollDestination.ANY,
  1698. () -> show(rowIndex, columnIndexDOM));
  1699. }
  1700. /**
  1701. * Cancels the currently active edit and hides the editor. Any changes
  1702. * that are not {@link #save() saved} are lost.
  1703. *
  1704. * @throws IllegalStateException
  1705. * if this editor is not enabled
  1706. * @throws IllegalStateException
  1707. * if this editor is not in edit mode
  1708. */
  1709. public void cancel() {
  1710. cancel(false);
  1711. }
  1712. private void cancel(boolean afterSave) {
  1713. if (!enabled) {
  1714. throw new IllegalStateException(
  1715. "Cannot cancel edit: editor is not enabled");
  1716. }
  1717. if (state == State.INACTIVE) {
  1718. throw new IllegalStateException(
  1719. "Cannot cancel edit: editor is not in edit mode");
  1720. }
  1721. handler.cancel(new EditorRequestImpl<>(grid, rowIndex,
  1722. focusedColumnIndexDOM, null), afterSave);
  1723. doCancel();
  1724. }
  1725. private void doCancel() {
  1726. hideOverlay();
  1727. state = State.INACTIVE;
  1728. rowIndex = -1;
  1729. focusedColumnIndexDOM = -1;
  1730. grid.getEscalator().setScrollLocked(Direction.VERTICAL, false);
  1731. updateSelectionCheckboxesAsNeeded(true);
  1732. }
  1733. private void updateSelectionCheckboxesAsNeeded(boolean isEnabled) {
  1734. // FIXME: This is too much guessing. Define a better way to do this.
  1735. if (grid.selectionColumn != null && grid.selectionColumn
  1736. .getRenderer() instanceof MultiSelectionRenderer) {
  1737. grid.refreshBody();
  1738. HeaderCell cell = grid.getDefaultHeaderRow()
  1739. .getCell(grid.selectionColumn);
  1740. // if lazy provider, then no checkbox
  1741. if (cell.getType() == GridStaticCellType.WIDGET) {
  1742. CheckBox checkBox = (CheckBox) grid.getDefaultHeaderRow()
  1743. .getCell(grid.selectionColumn).getWidget();
  1744. checkBox.setEnabled(isEnabled);
  1745. }
  1746. }
  1747. }
  1748. /**
  1749. * Saves any unsaved changes to the data source and hides the editor.
  1750. *
  1751. * @throws IllegalStateException
  1752. * if this editor is not enabled
  1753. * @throws IllegalStateException
  1754. * if this editor is not in edit mode
  1755. */
  1756. public void save() {
  1757. if (!enabled) {
  1758. throw new IllegalStateException(
  1759. "Cannot save: editor is not enabled");
  1760. }
  1761. if (state != State.ACTIVE) {
  1762. throw new IllegalStateException(
  1763. "Cannot save: editor is not in edit mode");
  1764. }
  1765. state = State.SAVING;
  1766. setButtonsEnabled(false);
  1767. saveTimeout.schedule(SAVE_TIMEOUT_MS);
  1768. EditorRequest<T> request = new EditorRequestImpl<>(grid, rowIndex,
  1769. focusedColumnIndexDOM, saveRequestCallback);
  1770. handler.save(request);
  1771. updateSelectionCheckboxesAsNeeded(true);
  1772. }
  1773. /**
  1774. * Returns the handler responsible for binding data and editor widgets
  1775. * to this editor.
  1776. *
  1777. * @return the editor handler or null if not set
  1778. */
  1779. public EditorHandler<T> getHandler() {
  1780. return handler;
  1781. }
  1782. /**
  1783. * Sets the handler responsible for binding data and editor widgets to
  1784. * this editor.
  1785. *
  1786. * @param rowHandler
  1787. * the new editor handler
  1788. *
  1789. * @throws IllegalStateException
  1790. * if this editor is currently in edit mode
  1791. */
  1792. public void setHandler(EditorHandler<T> rowHandler) {
  1793. if (state != State.INACTIVE) {
  1794. throw new IllegalStateException(
  1795. "Cannot set EditorHandler: editor is currently in edit mode");
  1796. }
  1797. handler = rowHandler;
  1798. }
  1799. /**
  1800. * Returns the enabled state of this editor.
  1801. *
  1802. * @return {@code true} if enabled, {@code false} otherwise
  1803. */
  1804. public boolean isEnabled() {
  1805. return enabled;
  1806. }
  1807. /**
  1808. * Sets the enabled state of this editor.
  1809. *
  1810. * @param enabled
  1811. * {@code true} if enabled, {@code false} otherwise
  1812. *
  1813. * @throws IllegalStateException
  1814. * if in edit mode and trying to disable
  1815. * @throws IllegalStateException
  1816. * if the editor handler is not set
  1817. */
  1818. public void setEnabled(boolean enabled) {
  1819. if (!enabled && state != State.INACTIVE) {
  1820. throw new IllegalStateException(
  1821. "Cannot disable: editor is in edit mode");
  1822. } else if (enabled && getHandler() == null) {
  1823. throw new IllegalStateException(
  1824. "Cannot enable: EditorHandler not set");
  1825. }
  1826. this.enabled = enabled;
  1827. }
  1828. /**
  1829. * If the Editor is still activating, proceeds to the binding phase.
  1830. * Otherwise does nothing.
  1831. *
  1832. * @param rowIndex
  1833. * the index of the row to be edited
  1834. * @param columnIndex
  1835. * the column index (excluding hidden columns) of the editor
  1836. * widget that should be initially focused or -1 to not set
  1837. * focus
  1838. */
  1839. protected void show(int rowIndex, int columnIndex) {
  1840. if (state == State.ACTIVATING) {
  1841. state = State.BINDING;
  1842. bindTimeout.schedule(BIND_TIMEOUT_MS);
  1843. EditorRequest<T> request = new EditorRequestImpl<>(grid,
  1844. rowIndex, columnIndex, bindRequestCallback);
  1845. handler.bind(request);
  1846. grid.getEscalator().setScrollLocked(Direction.VERTICAL,
  1847. isBuffered());
  1848. updateSelectionCheckboxesAsNeeded(false);
  1849. }
  1850. }
  1851. /**
  1852. * Sets the grid this editor belongs to. Should not be null. Should only
  1853. * be called once.
  1854. *
  1855. * @param grid
  1856. * the parent grid
  1857. */
  1858. protected void setGrid(final Grid<T> grid) {
  1859. assert grid != null : "Grid cannot be null";
  1860. assert this.grid == null : "Can only attach editor to Grid once";
  1861. this.grid = grid;
  1862. }
  1863. /**
  1864. * Returns the internal state of the editor.
  1865. *
  1866. * @return the state
  1867. */
  1868. protected State getState() {
  1869. return state;
  1870. }
  1871. /**
  1872. * Sets the internal state of the editor.
  1873. *
  1874. * @param state
  1875. * the state to set
  1876. */
  1877. protected void setState(State state) {
  1878. this.state = state;
  1879. }
  1880. /**
  1881. * Returns the editor widget associated with the given column. If the
  1882. * editor is not active or the column is not
  1883. * {@link Grid.Column#isEditable() editable}, returns null.
  1884. *
  1885. * @param column
  1886. * the column
  1887. * @return the widget if the editor is open and the column is editable,
  1888. * null otherwise
  1889. */
  1890. protected Widget getWidget(Column<?, T> column) {
  1891. return columnToWidget.get(column);
  1892. }
  1893. /**
  1894. * Equivalent to {@code showOverlay()}. The argument is ignored.
  1895. *
  1896. * @param unused
  1897. * ignored argument
  1898. *
  1899. * @deprecated As of 7.5, use {@link #showOverlay()} instead.
  1900. */
  1901. @Deprecated
  1902. protected void showOverlay(TableRowElement unused) {
  1903. showOverlay();
  1904. }
  1905. /**
  1906. * Opens the editor overlay over the grid row indicated by
  1907. * {@link #getRow()}.
  1908. *
  1909. * @since 7.5
  1910. */
  1911. protected void showOverlay() {
  1912. // Ensure overlay is hidden initially
  1913. hideOverlay();
  1914. DivElement gridElement = DivElement.as(grid.getElement());
  1915. TableRowElement tr = grid.getEscalator().getBody()
  1916. .getRowElement(rowIndex);
  1917. hScrollHandler = grid.addScrollHandler(event -> {
  1918. updateHorizontalScrollPosition();
  1919. updateVerticalScrollPosition();
  1920. });
  1921. addEditorAndContents(gridElement, tr);
  1922. updateSizeAndPosition(gridElement, tr);
  1923. }
  1924. private void addEditorAndContents(DivElement gridElement,
  1925. TableRowElement tr) {
  1926. gridElement.appendChild(editorOverlay);
  1927. editorOverlay.appendChild(frozenCellWrapper);
  1928. editorOverlay.appendChild(cellWrapper);
  1929. editorOverlay.appendChild(messageAndButtonsWrapper);
  1930. updateBufferedStyleName();
  1931. updateSelectedStyleName();
  1932. int frozenColumns = grid.getVisibleFrozenColumnCount();
  1933. double frozenColumnsWidth = 0;
  1934. double cellHeight = 0;
  1935. for (int i = 0; i < tr.getCells().getLength(); i++) {
  1936. Element cell = createCell(tr.getCells().getItem(i));
  1937. cellHeight = Math.max(cellHeight,
  1938. WidgetUtil.getRequiredHeightBoundingClientRectDouble(
  1939. tr.getCells().getItem(i)));
  1940. Column<?, T> column = grid.getVisibleColumn(i);
  1941. if (i < frozenColumns) {
  1942. frozenCellWrapper.appendChild(cell);
  1943. frozenColumnsWidth += WidgetUtil
  1944. .getRequiredWidthBoundingClientRectDouble(
  1945. tr.getCells().getItem(i));
  1946. } else {
  1947. cellWrapper.appendChild(cell);
  1948. }
  1949. if (column.isEditable()) {
  1950. Widget editor = getHandler().getWidget(column);
  1951. if (editor != null) {
  1952. columnToWidget.put(column, editor);
  1953. grid.attachWidget(editor, cell);
  1954. }
  1955. if (i == focusedColumnIndexDOM) {
  1956. focusColumn(focusedColumnIndexDOM);
  1957. }
  1958. } else {
  1959. cell.addClassName(NOT_EDITABLE_CLASS_NAME);
  1960. cell.addClassName(tr.getCells().getItem(i).getClassName());
  1961. // If the focused or frozen stylename is present it should
  1962. // not be inherited by the editor cell as it is not useful
  1963. // in the editor and would look broken without additional
  1964. // style rules. This is a bit of a hack.
  1965. cell.removeClassName(grid.cellFocusStyleName);
  1966. cell.removeClassName("frozen");
  1967. if (column == grid.selectionColumn) {
  1968. // Duplicate selection column CheckBox
  1969. pinnedRowHandle = grid.getDataSource().getHandle(
  1970. grid.getDataSource().getRow(rowIndex));
  1971. pinnedRowHandle.pin();
  1972. // We need to duplicate the selection CheckBox for the
  1973. // editor overlay since the original one is hidden by
  1974. // the overlay
  1975. final CheckBox checkBox = GWT.create(CheckBox.class);
  1976. checkBox.setStylePrimaryName(grid.getStylePrimaryName()
  1977. + "-selection-checkbox");
  1978. // label of checkbox should only be visible for
  1979. // assistive devices
  1980. checkBox.addStyleName("v-assistive-device-only-label");
  1981. checkBox.setValue(
  1982. grid.isSelected(pinnedRowHandle.getRow()));
  1983. checkBox.sinkEvents(Event.ONCLICK);
  1984. checkBox.addClickHandler(event -> {
  1985. T row = pinnedRowHandle.getRow();
  1986. if (grid.isSelected(row)) {
  1987. grid.deselect(row);
  1988. } else {
  1989. grid.select(row);
  1990. }
  1991. });
  1992. grid.attachWidget(checkBox, cell);
  1993. columnToWidget.put(column, checkBox);
  1994. // Only enable CheckBox in non-buffered mode
  1995. checkBox.setEnabled(!isBuffered());
  1996. } else if (!(column
  1997. .getRenderer() instanceof WidgetRenderer)) {
  1998. // Copy non-widget content directly
  1999. cell.setInnerHTML(
  2000. tr.getCells().getItem(i).getInnerHTML());
  2001. }
  2002. }
  2003. }
  2004. setBounds(frozenCellWrapper, 0, 0, frozenColumnsWidth, 0);
  2005. setBounds(cellWrapper, frozenColumnsWidth, 0,
  2006. tr.getOffsetWidth() - frozenColumnsWidth, cellHeight);
  2007. // Only add these elements once
  2008. if (!messageAndButtonsWrapper.isOrHasChild(messageWrapper)) {
  2009. messageAndButtonsWrapper.appendChild(messageWrapper);
  2010. messageAndButtonsWrapper.appendChild(buttonsWrapper);
  2011. }
  2012. if (isBuffered()) {
  2013. grid.attachWidget(saveButton, buttonsWrapper);
  2014. grid.attachWidget(cancelButton, buttonsWrapper);
  2015. }
  2016. setMessageAndButtonsWrapperVisible(isBuffered());
  2017. }
  2018. private void updateSizeAndPosition(DivElement gridElement,
  2019. TableRowElement tr) {
  2020. updateHorizontalScrollPosition();
  2021. AbstractRowContainer body = (AbstractRowContainer) grid
  2022. .getEscalator().getBody();
  2023. double rowTop = body.getRowTop(tr);
  2024. int bodyTop = body.getElement().getAbsoluteTop();
  2025. int gridTop = gridElement.getAbsoluteTop();
  2026. double overlayTop = rowTop + bodyTop - gridTop;
  2027. originalScrollTop = grid.getScrollTop();
  2028. if (!isBuffered() || buttonsShouldBeRenderedBelow(tr)) {
  2029. // Default case, editor buttons are below the edited row
  2030. editorOverlay.getStyle().setTop(overlayTop, Unit.PX);
  2031. originalTop = overlayTop;
  2032. editorOverlay.getStyle().clearBottom();
  2033. } else {
  2034. // Move message and buttons wrapper on top of cell wrapper if
  2035. // there is not enough space visible space under and fix the
  2036. // overlay from the bottom
  2037. editorOverlay.insertFirst(messageAndButtonsWrapper);
  2038. int gridHeight = grid.getElement().getOffsetHeight();
  2039. double borderHeight = WidgetUtil
  2040. .getBorderBottomThickness(editorOverlay);
  2041. editorOverlay.getStyle().setBottom(gridHeight - overlayTop
  2042. - tr.getOffsetHeight() + borderHeight, Unit.PX);
  2043. editorOverlay.getStyle().clearTop();
  2044. }
  2045. // Do not render over the vertical scrollbar
  2046. editorOverlay.getStyle().setWidth(grid.escalator.getInnerWidth(),
  2047. Unit.PX);
  2048. }
  2049. private void focusColumn(int columnIndexDOM) {
  2050. if (columnIndexDOM < 0
  2051. || columnIndexDOM >= grid.getVisibleColumns().size()) {
  2052. // NO-OP
  2053. return;
  2054. }
  2055. Widget editor = getWidget(grid.getVisibleColumn(columnIndexDOM));
  2056. if (editor instanceof Focusable) {
  2057. ((Focusable) editor).focus();
  2058. } else if (editor instanceof com.google.gwt.user.client.ui.Focusable) {
  2059. ((com.google.gwt.user.client.ui.Focusable) editor)
  2060. .setFocus(true);
  2061. } else {
  2062. grid.focus();
  2063. }
  2064. }
  2065. private boolean buttonsShouldBeRenderedBelow(TableRowElement tr) {
  2066. TableSectionElement tfoot = grid.escalator.getFooter().getElement();
  2067. double tfootPageTop = WidgetUtil.getBoundingClientRect(tfoot)
  2068. .getTop();
  2069. double trPageBottom = WidgetUtil.getBoundingClientRect(tr)
  2070. .getBottom();
  2071. int messageAndButtonsHeight = messageAndButtonsWrapper
  2072. .getOffsetHeight();
  2073. double bottomOfButtons = trPageBottom + messageAndButtonsHeight;
  2074. return bottomOfButtons < tfootPageTop;
  2075. }
  2076. /**
  2077. * Hides the editor overlay and clears its contents.
  2078. */
  2079. protected void hideOverlay() {
  2080. if (editorOverlay.getParentElement() == null) {
  2081. return;
  2082. }
  2083. if (pinnedRowHandle != null) {
  2084. pinnedRowHandle.unpin();
  2085. pinnedRowHandle = null;
  2086. }
  2087. for (HandlerRegistration r : focusHandlers) {
  2088. r.removeHandler();
  2089. }
  2090. focusHandlers.clear();
  2091. for (Widget w : columnToWidget.values()) {
  2092. setParent(w, null);
  2093. }
  2094. columnToWidget.clear();
  2095. if (isBuffered()) {
  2096. grid.detachWidget(saveButton);
  2097. grid.detachWidget(cancelButton);
  2098. }
  2099. editorOverlay.removeAllChildren();
  2100. cellWrapper.removeAllChildren();
  2101. frozenCellWrapper.removeAllChildren();
  2102. editorOverlay.removeFromParent();
  2103. hScrollHandler.removeHandler();
  2104. clearEditorColumnErrors();
  2105. }
  2106. private void updateBufferedStyleName() {
  2107. if (isBuffered()) {
  2108. editorOverlay.removeClassName("unbuffered");
  2109. editorOverlay.addClassName("buffered");
  2110. } else {
  2111. editorOverlay.removeClassName("buffered");
  2112. editorOverlay.addClassName("unbuffered");
  2113. }
  2114. }
  2115. private void updateSelectedStyleName() {
  2116. // Add class name with selected modifier if the editor is being
  2117. // opened on selected row, see #11634
  2118. String selectedStylename = styleName + "-selected";
  2119. if (grid.isSelected(grid.getDataSource().getRow(getRow()))) {
  2120. cellWrapper.addClassName(selectedStylename);
  2121. } else {
  2122. cellWrapper.removeClassName(selectedStylename);
  2123. }
  2124. }
  2125. /**
  2126. * Sets the editor's primary style name and updates all dependent style
  2127. * names.
  2128. *
  2129. * @param primaryName
  2130. * the new primary style name
  2131. */
  2132. protected void setStylePrimaryName(String primaryName) {
  2133. if (styleName != null) {
  2134. editorOverlay.removeClassName(styleName);
  2135. cellWrapper.removeClassName(styleName + "-cells");
  2136. frozenCellWrapper.removeClassName(styleName + "-cells");
  2137. messageAndButtonsWrapper.removeClassName(styleName + "-footer");
  2138. messageWrapper.removeClassName(styleName + "-message");
  2139. buttonsWrapper.removeClassName(styleName + "-buttons");
  2140. saveButton.removeStyleName(styleName + "-save");
  2141. cancelButton.removeStyleName(styleName + "-cancel");
  2142. }
  2143. styleName = primaryName + "-editor";
  2144. editorOverlay.setClassName(styleName);
  2145. cellWrapper.setClassName(styleName + "-cells");
  2146. frozenCellWrapper.setClassName(styleName + "-cells frozen");
  2147. messageAndButtonsWrapper.setClassName(styleName + "-footer");
  2148. messageWrapper.setClassName(styleName + "-message");
  2149. buttonsWrapper.setClassName(styleName + "-buttons");
  2150. saveButton.setStyleName(styleName + "-save");
  2151. cancelButton.setStyleName(styleName + "-cancel");
  2152. }
  2153. /**
  2154. * Creates an editor cell corresponding to the given table cell. The
  2155. * returned element is empty and has the same dimensions and position as
  2156. * the table cell.
  2157. *
  2158. * @param td
  2159. * the table cell used as a reference
  2160. * @return an editor cell corresponding to the given cell
  2161. */
  2162. protected Element createCell(TableCellElement td) {
  2163. DivElement cell = DivElement.as(DOM.createDiv());
  2164. double width = WidgetUtil
  2165. .getRequiredWidthBoundingClientRectDouble(td);
  2166. double height = WidgetUtil
  2167. .getRequiredHeightBoundingClientRectDouble(td);
  2168. setBounds(cell, td.getOffsetLeft(), td.getOffsetTop(), width,
  2169. height);
  2170. return cell;
  2171. }
  2172. private static void setBounds(Element e, double left, double top,
  2173. double width, double height) {
  2174. Style style = e.getStyle();
  2175. style.setLeft(left, Unit.PX);
  2176. style.setTop(top, Unit.PX);
  2177. style.setWidth(width, Unit.PX);
  2178. style.setHeight(height, Unit.PX);
  2179. }
  2180. private void updateHorizontalScrollPosition() {
  2181. double scrollLeft = grid.getScrollLeft();
  2182. cellWrapper.getStyle().setLeft(
  2183. frozenCellWrapper.getOffsetWidth() - scrollLeft, Unit.PX);
  2184. }
  2185. /**
  2186. * Moves the editor overlay on scroll so that it stays on top of the
  2187. * edited row. This will also snap the editor to top or bottom of the
  2188. * row container if the edited row is scrolled out of the visible area.
  2189. */
  2190. private void updateVerticalScrollPosition() {
  2191. if (isBuffered()) {
  2192. return;
  2193. }
  2194. double newScrollTop = grid.getScrollTop();
  2195. int gridTop = grid.getElement().getAbsoluteTop();
  2196. int editorHeight = editorOverlay.getOffsetHeight();
  2197. Escalator escalator = grid.getEscalator();
  2198. TableSectionElement header = escalator.getHeader().getElement();
  2199. int footerTop = escalator.getFooter().getElement().getAbsoluteTop();
  2200. int headerBottom = header.getAbsoluteBottom();
  2201. double newTop = originalTop - (newScrollTop - originalScrollTop);
  2202. if (newTop + gridTop < headerBottom) {
  2203. // Snap editor to top of the row container
  2204. newTop = header.getOffsetHeight();
  2205. } else if (newTop + gridTop > footerTop - editorHeight) {
  2206. // Snap editor to the bottom of the row container
  2207. newTop = footerTop - editorHeight - gridTop;
  2208. }
  2209. editorOverlay.getStyle().setTop(newTop, Unit.PX);
  2210. }
  2211. /**
  2212. * Sets the editor's buttons enabled. Does not update the enabled status
  2213. * of the grid this editor belongs to, nor ask the enabled status from
  2214. * it.
  2215. *
  2216. * @param enabled
  2217. * {@code true} to enable the buttons, {@code false} to
  2218. * disable them
  2219. */
  2220. protected void setGridEnabled(boolean enabled) {
  2221. // TODO: This should be informed to handler as well so possible
  2222. // fields can be disabled.
  2223. setButtonsEnabled(enabled);
  2224. }
  2225. private void setButtonsEnabled(boolean enabled) {
  2226. saveButton.setEnabled(enabled);
  2227. cancelButton.setEnabled(enabled);
  2228. }
  2229. /**
  2230. * Sets the caption of the save button. Should not be {@code null}.
  2231. *
  2232. * @param saveCaption
  2233. * the new caption text
  2234. * @throws IllegalArgumentException
  2235. * if the given text is {@code null}
  2236. */
  2237. public void setSaveCaption(String saveCaption)
  2238. throws IllegalArgumentException {
  2239. if (saveCaption == null) {
  2240. throw new IllegalArgumentException(
  2241. "Save caption cannot be null");
  2242. }
  2243. saveButton.setText(saveCaption);
  2244. }
  2245. /**
  2246. * Returns the caption of the save button.
  2247. *
  2248. * @return the caption text
  2249. */
  2250. public String getSaveCaption() {
  2251. return saveButton.getText();
  2252. }
  2253. /**
  2254. * Sets the caption of the cancel button. Should not be {@code null}.
  2255. *
  2256. * @param cancelCaption
  2257. * the new caption text
  2258. * @throws IllegalArgumentException
  2259. * if the given text is {@code null}
  2260. */
  2261. public void setCancelCaption(String cancelCaption)
  2262. throws IllegalArgumentException {
  2263. if (cancelCaption == null) {
  2264. throw new IllegalArgumentException(
  2265. "Cancel caption cannot be null");
  2266. }
  2267. cancelButton.setText(cancelCaption);
  2268. }
  2269. /**
  2270. * Returns the caption of the cancel button.
  2271. *
  2272. * @return the caption text
  2273. */
  2274. public String getCancelCaption() {
  2275. return cancelButton.getText();
  2276. }
  2277. /**
  2278. * If the given column is indicated to have an error in the editor, sets
  2279. * the error styles to the corresponding editor cell and lists the
  2280. * column as having an error. Otherwise removes the error styles from
  2281. * the cell and removes the column from the error collection.
  2282. *
  2283. * @param column
  2284. * the column which should have its editor error status
  2285. * updated
  2286. * @param hasError
  2287. * {@code true} if the cell should get error styles,
  2288. * {@code false} if the error styles should be removed from
  2289. * the cell
  2290. */
  2291. public void setEditorColumnError(Column<?, T> column,
  2292. boolean hasError) {
  2293. if (state != State.ACTIVE && state != State.SAVING) {
  2294. throw new IllegalStateException("Cannot set cell error "
  2295. + "status: editor is neither active nor saving.");
  2296. }
  2297. if (isEditorColumnError(column) == hasError) {
  2298. return;
  2299. }
  2300. Element editorCell = getWidget(column).getElement()
  2301. .getParentElement();
  2302. if (hasError) {
  2303. editorCell.addClassName(ERROR_CLASS_NAME);
  2304. columnErrors.add(column);
  2305. } else {
  2306. editorCell.removeClassName(ERROR_CLASS_NAME);
  2307. columnErrors.remove(column);
  2308. }
  2309. }
  2310. /**
  2311. * Clears all editor error styles from the editor cells and clears the
  2312. * error column collection.
  2313. */
  2314. public void clearEditorColumnErrors() {
  2315. /*
  2316. * editorOverlay has no children if it's not active, effectively
  2317. * making this loop a NOOP.
  2318. */
  2319. Element e = editorOverlay.getFirstChildElement();
  2320. while (e != null) {
  2321. e.removeClassName(ERROR_CLASS_NAME);
  2322. e = e.getNextSiblingElement();
  2323. }
  2324. columnErrors.clear();
  2325. }
  2326. /**
  2327. * Returns true if the column has been listed as containing an error.
  2328. *
  2329. * @param column
  2330. * the column whose error status is checked
  2331. * @return {@code true} if the column is listed as containing an error,
  2332. * {@code false} otherwise
  2333. */
  2334. public boolean isEditorColumnError(Column<?, T> column) {
  2335. return columnErrors.contains(column);
  2336. }
  2337. /**
  2338. * Sets the buffered mode. When the editor is in buffered mode, edits
  2339. * are only committed when the user clicks the save button. In
  2340. * unbuffered mode valid changes are automatically committed.
  2341. *
  2342. * @param buffered
  2343. * {@code true} if editor should be buffered, {@code false}
  2344. * otherwise
  2345. */
  2346. public void setBuffered(boolean buffered) {
  2347. this.buffered = buffered;
  2348. setMessageAndButtonsWrapperVisible(buffered);
  2349. }
  2350. /**
  2351. * Returns whether this editor is buffered or not.
  2352. *
  2353. * @return {@code true} if editor is buffered, {@code false} otherwise
  2354. *
  2355. * @see #setBuffered(boolean)
  2356. */
  2357. public boolean isBuffered() {
  2358. return buffered;
  2359. }
  2360. private void setMessageAndButtonsWrapperVisible(boolean visible) {
  2361. if (visible) {
  2362. messageAndButtonsWrapper.getStyle().clearDisplay();
  2363. } else {
  2364. messageAndButtonsWrapper.getStyle().setDisplay(Display.NONE);
  2365. }
  2366. }
  2367. /**
  2368. * Sets the event handler for this Editor.
  2369. *
  2370. * @since 7.6
  2371. * @param handler
  2372. * the new event handler
  2373. */
  2374. public void setEventHandler(EventHandler<T> handler) {
  2375. eventHandler = handler;
  2376. }
  2377. /**
  2378. * Returns the event handler of this Editor.
  2379. *
  2380. * @since 7.6
  2381. * @return the current event handler
  2382. */
  2383. public EventHandler<T> getEventHandler() {
  2384. return eventHandler;
  2385. }
  2386. @Override
  2387. public boolean isWorkPending() {
  2388. return saveTimeout.isRunning() || bindTimeout.isRunning();
  2389. }
  2390. /**
  2391. * Returns the column index of the editor cell that contains the given
  2392. * element, or -1 if the element can't be found within the editor cells.
  2393. *
  2394. * @param e
  2395. * the element to be located
  2396. * @return the column index of the associated editor cell, or -1 if not
  2397. * found
  2398. */
  2399. protected int getElementColumn(Element e) {
  2400. int frozenCells = frozenCellWrapper.getChildCount();
  2401. if (frozenCellWrapper.isOrHasChild(e)) {
  2402. for (int i = 0; i < frozenCells; ++i) {
  2403. if (frozenCellWrapper.getChild(i).isOrHasChild(e)) {
  2404. return i;
  2405. }
  2406. }
  2407. }
  2408. if (cellWrapper.isOrHasChild(e)) {
  2409. for (int i = 0; i < cellWrapper.getChildCount(); ++i) {
  2410. if (cellWrapper.getChild(i).isOrHasChild(e)) {
  2411. return i + frozenCells;
  2412. }
  2413. }
  2414. }
  2415. return -1;
  2416. }
  2417. }
  2418. /**
  2419. * Event class for key events that happen within the grid.
  2420. *
  2421. * @param <HANDLER>
  2422. * the event handler type
  2423. */
  2424. public abstract static class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler>
  2425. extends KeyEvent<HANDLER> {
  2426. /**
  2427. * @since 7.7.9
  2428. */
  2429. public AbstractGridKeyEvent() {
  2430. }
  2431. /**
  2432. * @param grid
  2433. * the grid where the event occurred
  2434. * @param targetCell
  2435. * the cell that the event targeted
  2436. *
  2437. * @deprecated This constructor's arguments are no longer used. Use the
  2438. * no-args constructor instead.
  2439. */
  2440. @Deprecated
  2441. public AbstractGridKeyEvent(Grid<?> grid, CellReference<?> targetCell) {
  2442. }
  2443. /**
  2444. * Returns the {@link BrowserEvents} type that corresponds with this
  2445. * event.
  2446. *
  2447. * @return the browser event type
  2448. */
  2449. protected abstract String getBrowserEventType();
  2450. /**
  2451. * Gets the Grid instance for this event, if it originated from a Grid.
  2452. *
  2453. * @return the grid this event originated from, or {@code null} if this
  2454. * event did not originate from a grid
  2455. */
  2456. public Grid<?> getGrid() {
  2457. EventTarget target = getNativeEvent().getEventTarget();
  2458. if (!Element.is(target)) {
  2459. return null;
  2460. }
  2461. return WidgetUtil.findWidget(Element.as(target), Grid.class, false);
  2462. }
  2463. /**
  2464. * Gets the reference of target cell for this event, if this event
  2465. * originated from a Grid.
  2466. *
  2467. * @return target cell, or {@code null} if this event did not originate
  2468. * from a grid
  2469. */
  2470. public CellReference<?> getFocusedCell() {
  2471. return getGrid().getEventCell();
  2472. }
  2473. @Override
  2474. protected void dispatch(HANDLER handler) {
  2475. EventTarget target = getNativeEvent().getEventTarget();
  2476. Grid<?> grid = getGrid();
  2477. if (Element.is(target) && grid != null) {
  2478. final RowContainer container = Stream
  2479. .of(grid.escalator.getHeader(),
  2480. grid.escalator.getBody(),
  2481. grid.escalator.getFooter())
  2482. .filter(c -> c.getCell(target.cast()) != null)
  2483. .findFirst()
  2484. .orElse(grid.cellFocusHandler.containerWithFocus);
  2485. Section section = Section.FOOTER;
  2486. if (container == grid.escalator.getHeader()) {
  2487. section = Section.HEADER;
  2488. } else if (container == getGrid().escalator.getBody()) {
  2489. section = Section.BODY;
  2490. }
  2491. // Don't handle event of child widget unless the column has been
  2492. // explicitly permitted to do so
  2493. if (grid.isElementInChildWidget(Element.as(target))) {
  2494. Cell cell = container.getCell(target.cast());
  2495. if (cell != null) {
  2496. Column<?, ?> column = grid
  2497. .getVisibleColumn(cell.getColumn());
  2498. if (column == null || !column.isHandleWidgetEvents()) {
  2499. return;
  2500. }
  2501. }
  2502. }
  2503. doDispatch(handler, section);
  2504. }
  2505. }
  2506. /**
  2507. * The given handler processes the event if the handler type matches the
  2508. * given section.
  2509. *
  2510. * @param handler
  2511. * handler
  2512. * @param section
  2513. * the section where the target element is located
  2514. */
  2515. protected abstract void doDispatch(HANDLER handler, Section section);
  2516. }
  2517. /**
  2518. * Event class for mouse events that happen within the grid.
  2519. *
  2520. * @param <HANDLER>
  2521. * the event handler type
  2522. */
  2523. public abstract static class AbstractGridMouseEvent<HANDLER extends AbstractGridMouseEventHandler>
  2524. extends MouseEvent<HANDLER> {
  2525. /**
  2526. * @since 7.7.9
  2527. */
  2528. public AbstractGridMouseEvent() {
  2529. }
  2530. /**
  2531. * @param grid
  2532. * the grid where the event occurred
  2533. * @param targetCell
  2534. * the cell that the event targeted
  2535. *
  2536. * @deprecated This constructor's arguments are no longer used. Use the
  2537. * no-args constructor instead.
  2538. */
  2539. @Deprecated
  2540. public AbstractGridMouseEvent(Grid<?> grid,
  2541. CellReference<?> targetCell) {
  2542. }
  2543. /**
  2544. * Returns the {@link BrowserEvents} type that corresponds with this
  2545. * event.
  2546. *
  2547. * @return the browser event type
  2548. */
  2549. protected abstract String getBrowserEventType();
  2550. /**
  2551. * Gets the Grid instance for this event, if it originated from a Grid.
  2552. *
  2553. * @return the grid this event originated from, or {@code null} if this
  2554. * event did not originate from a grid
  2555. */
  2556. public Grid<?> getGrid() {
  2557. EventTarget target = getNativeEvent().getEventTarget();
  2558. if (!Element.is(target)) {
  2559. return null;
  2560. }
  2561. return WidgetUtil.findWidget(Element.as(target), Grid.class, false);
  2562. }
  2563. /**
  2564. * Gets the reference of target cell for this event, if this event
  2565. * originated from a Grid.
  2566. *
  2567. * @return target cell, or {@code null} if this event did not originate
  2568. * from a grid
  2569. */
  2570. public CellReference<?> getTargetCell() {
  2571. Grid<?> grid = getGrid();
  2572. if (grid == null) {
  2573. return null;
  2574. }
  2575. return grid.getEventCell();
  2576. }
  2577. @Override
  2578. protected void dispatch(HANDLER handler) {
  2579. EventTarget target = getNativeEvent().getEventTarget();
  2580. if (!Element.is(target)) {
  2581. // Target is not an element
  2582. return;
  2583. }
  2584. Grid<?> grid = getGrid();
  2585. if (grid == null) {
  2586. // Target is not an element of a grid
  2587. return;
  2588. }
  2589. Element targetElement = Element.as(target);
  2590. if (ignoreEventFromTarget(grid, targetElement)) {
  2591. // Event on this target should be ignored
  2592. return;
  2593. }
  2594. final RowContainer container = grid.escalator
  2595. .findRowContainer(targetElement);
  2596. if (container == null) {
  2597. // No container for given element
  2598. return;
  2599. }
  2600. Section section = Section.FOOTER;
  2601. if (container == grid.escalator.getHeader()) {
  2602. section = Section.HEADER;
  2603. } else if (container == grid.escalator.getBody()) {
  2604. section = Section.BODY;
  2605. }
  2606. doDispatch(handler, section);
  2607. }
  2608. /**
  2609. * Returns whether the mouse event on the target element should be
  2610. * ignored.
  2611. *
  2612. * @param grid
  2613. * the {@code Grid} instance from which the event originated
  2614. * @param targetElement
  2615. * the element from which the event originated
  2616. * @return {@code true} if the event should be ignored, {@code false} if
  2617. * it should be handled
  2618. * @since 8.2
  2619. */
  2620. protected boolean ignoreEventFromTarget(Grid<?> grid,
  2621. Element targetElement) {
  2622. boolean childWidget = grid.isElementInChildWidget(targetElement);
  2623. boolean handleWidgetEvent = false;
  2624. RowContainer container = grid.getEscalator()
  2625. .findRowContainer(targetElement);
  2626. if (container != null) {
  2627. Cell cell = container.getCell(targetElement);
  2628. if (cell != null) {
  2629. Column<?, ?> column = grid
  2630. .getVisibleColumn(cell.getColumn());
  2631. handleWidgetEvent = column != null
  2632. && column.isHandleWidgetEvents();
  2633. }
  2634. }
  2635. return childWidget && !handleWidgetEvent;
  2636. }
  2637. /**
  2638. * The given handler processes the event if the handler type matches the
  2639. * given section.
  2640. *
  2641. * @param handler
  2642. * handler
  2643. * @param section
  2644. * the section where the target element is located
  2645. */
  2646. protected abstract void doDispatch(HANDLER handler, Section section);
  2647. }
  2648. private static final String CUSTOM_STYLE_PROPERTY_NAME = "customStyle";
  2649. /**
  2650. * An initial height that is given to new details rows before rendering the
  2651. * appropriate widget that we then can be measure
  2652. *
  2653. * @see Grid.GridSpacerUpdater
  2654. */
  2655. private static final double DETAILS_ROW_INITIAL_HEIGHT = 50;
  2656. private EventCellReference<T> eventCell = new EventCellReference<T>(this);
  2657. /**
  2658. * Focus handler for Grid's cells. Updates focus style names and handles
  2659. * focus scrolling.
  2660. */
  2661. private class CellFocusHandler {
  2662. private RowContainer containerWithFocus = escalator.getBody();
  2663. private int rowWithFocus = 0;
  2664. private Range cellFocusRange = Range.withLength(0, 1);
  2665. private int lastFocusedBodyRow = 0;
  2666. private int lastFocusedHeaderRow = 0;
  2667. private int lastFocusedFooterRow = 0;
  2668. private TableCellElement cellWithFocusStyle = null;
  2669. private TableRowElement rowWithFocusStyle = null;
  2670. public CellFocusHandler() {
  2671. sinkEvents(getNavigationEvents());
  2672. }
  2673. private Cell getFocusedCell() {
  2674. return new Cell(rowWithFocus, cellFocusRange.getStart(),
  2675. cellWithFocusStyle);
  2676. }
  2677. /**
  2678. * Sets style names for given cell when needed.
  2679. */
  2680. public void updateFocusedCellStyle(FlyweightCell cell,
  2681. RowContainer cellContainer) {
  2682. int cellRow = cell.getRow();
  2683. int cellColumn = cell.getColumn();
  2684. int colSpan = cell.getColSpan();
  2685. boolean columnHasFocus = Range.withLength(cellColumn, colSpan)
  2686. .intersects(cellFocusRange);
  2687. if (cellContainer == containerWithFocus) {
  2688. // Cell is in the current container
  2689. if (cellRow == rowWithFocus && columnHasFocus) {
  2690. if (cellWithFocusStyle != cell.getElement()) {
  2691. // Cell is correct but it does not have focused style
  2692. if (cellWithFocusStyle != null) {
  2693. // Remove old focus style
  2694. setStyleName(cellWithFocusStyle, cellFocusStyleName,
  2695. false);
  2696. }
  2697. cellWithFocusStyle = cell.getElement();
  2698. // Add focus style to correct cell.
  2699. setStyleName(cellWithFocusStyle, cellFocusStyleName,
  2700. true);
  2701. }
  2702. } else if (cellWithFocusStyle == cell.getElement()) {
  2703. // Due to escalator reusing cells, a new cell has the same
  2704. // element but is not the focused cell.
  2705. setStyleName(cellWithFocusStyle, cellFocusStyleName, false);
  2706. cellWithFocusStyle = null;
  2707. }
  2708. }
  2709. }
  2710. /**
  2711. * Sets focus style for the given row if needed.
  2712. *
  2713. * @param row
  2714. * a row object
  2715. */
  2716. public void updateFocusedRowStyle(Row row) {
  2717. if (rowWithFocus == row.getRow()
  2718. && containerWithFocus == escalator.getBody()) {
  2719. if (row.getElement() != rowWithFocusStyle) {
  2720. // Row should have focus style but does not have it.
  2721. if (rowWithFocusStyle != null) {
  2722. setStyleName(rowWithFocusStyle, rowFocusStyleName,
  2723. false);
  2724. }
  2725. rowWithFocusStyle = row.getElement();
  2726. setStyleName(rowWithFocusStyle, rowFocusStyleName, true);
  2727. }
  2728. } else if (rowWithFocusStyle == row.getElement()
  2729. || containerWithFocus != escalator.getBody()
  2730. && rowWithFocusStyle != null) {
  2731. // Remove focus style.
  2732. setStyleName(rowWithFocusStyle, rowFocusStyleName, false);
  2733. rowWithFocusStyle = null;
  2734. }
  2735. }
  2736. /**
  2737. * Sets the currently focused.
  2738. * <p>
  2739. * <em>NOTE:</em> the column index is the index in DOM, not the logical
  2740. * column index which includes hidden columns.
  2741. *
  2742. * @param rowIndex
  2743. * the index of the row having focus
  2744. * @param columnIndexDOM
  2745. * the index of the cell having focus
  2746. * @param container
  2747. * the row container having focus
  2748. */
  2749. private void setCellFocus(int rowIndex, int columnIndexDOM,
  2750. RowContainer container) {
  2751. if (container == null || rowIndex == rowWithFocus
  2752. && cellFocusRange.contains(columnIndexDOM)
  2753. && container == this.containerWithFocus) {
  2754. return;
  2755. }
  2756. int oldRow = rowWithFocus;
  2757. rowWithFocus = rowIndex;
  2758. Range oldRange = cellFocusRange;
  2759. if (container == escalator.getBody()) {
  2760. scrollToRow(rowWithFocus);
  2761. cellFocusRange = Range.withLength(columnIndexDOM, 1);
  2762. } else {
  2763. int i = 0;
  2764. Element cell = container.getRowElement(rowWithFocus)
  2765. .getFirstChildElement();
  2766. do {
  2767. int colSpan = cell
  2768. .getPropertyInt(FlyweightCell.COLSPAN_ATTR);
  2769. Range cellRange = Range.withLength(i, colSpan);
  2770. if (cellRange.contains(columnIndexDOM)) {
  2771. cellFocusRange = cellRange;
  2772. break;
  2773. }
  2774. cell = cell.getNextSiblingElement();
  2775. ++i;
  2776. } while (cell != null);
  2777. }
  2778. if (columnIndexDOM >= escalator.getColumnConfiguration()
  2779. .getFrozenColumnCount()) {
  2780. escalator.scrollToColumn(columnIndexDOM, ScrollDestination.ANY,
  2781. 10);
  2782. }
  2783. if (this.containerWithFocus == container) {
  2784. if (oldRange.equals(cellFocusRange) && oldRow != rowWithFocus) {
  2785. refreshRow(oldRow);
  2786. } else {
  2787. refreshHeader();
  2788. refreshFooter();
  2789. }
  2790. } else {
  2791. RowContainer oldContainer = this.containerWithFocus;
  2792. this.containerWithFocus = container;
  2793. if (oldContainer == escalator.getBody()) {
  2794. lastFocusedBodyRow = oldRow;
  2795. } else if (oldContainer == escalator.getHeader()) {
  2796. lastFocusedHeaderRow = oldRow;
  2797. } else {
  2798. lastFocusedFooterRow = oldRow;
  2799. }
  2800. if (!oldRange.equals(cellFocusRange)) {
  2801. refreshHeader();
  2802. refreshFooter();
  2803. if (oldContainer == escalator.getBody()) {
  2804. oldContainer.refreshRows(oldRow, 1);
  2805. }
  2806. } else {
  2807. oldContainer.refreshRows(oldRow, 1);
  2808. }
  2809. }
  2810. refreshRow(rowWithFocus);
  2811. }
  2812. /**
  2813. * Sets focus on a cell.
  2814. *
  2815. * <p>
  2816. * <em>Note</em>: cell focus is not the same as JavaScript's
  2817. * {@code document.activeElement}.
  2818. *
  2819. * @param cell
  2820. * a cell object
  2821. */
  2822. public void setCellFocus(CellReference<T> cell) {
  2823. setCellFocus(cell.getRowIndex(), cell.getColumnIndexDOM(),
  2824. escalator.findRowContainer(cell.getElement()));
  2825. }
  2826. /**
  2827. * Gets list of events that can be used for cell focusing.
  2828. *
  2829. * @return list of navigation related event types
  2830. */
  2831. public Collection<String> getNavigationEvents() {
  2832. return Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.CLICK);
  2833. }
  2834. /**
  2835. * Handle events that can move the cell focus.
  2836. */
  2837. public void handleNavigationEvent(Event event, CellReference<T> cell) {
  2838. if (event.getType().equals(BrowserEvents.CLICK)) {
  2839. setCellFocus(cell);
  2840. // Grid should have focus when clicked.
  2841. getElement().focus();
  2842. } else if (event.getType().equals(BrowserEvents.KEYDOWN)) {
  2843. int newRow = rowWithFocus;
  2844. RowContainer newContainer = containerWithFocus;
  2845. int newColumn = cellFocusRange.getStart();
  2846. switch (event.getKeyCode()) {
  2847. case KeyCodes.KEY_DOWN:
  2848. ++newRow;
  2849. break;
  2850. case KeyCodes.KEY_UP:
  2851. --newRow;
  2852. break;
  2853. case KeyCodes.KEY_RIGHT:
  2854. if (cellFocusRange.getEnd() >= getVisibleColumns().size()) {
  2855. return;
  2856. }
  2857. newColumn = cellFocusRange.getEnd();
  2858. break;
  2859. case KeyCodes.KEY_LEFT:
  2860. if (newColumn == 0) {
  2861. return;
  2862. }
  2863. --newColumn;
  2864. break;
  2865. case KeyCodes.KEY_TAB:
  2866. if (event.getShiftKey()) {
  2867. newContainer = getPreviousContainer(containerWithFocus);
  2868. } else {
  2869. newContainer = getNextContainer(containerWithFocus);
  2870. }
  2871. if (newContainer == containerWithFocus) {
  2872. return;
  2873. }
  2874. break;
  2875. case KeyCodes.KEY_HOME:
  2876. if (newContainer.getRowCount() > 0) {
  2877. newRow = 0;
  2878. }
  2879. break;
  2880. case KeyCodes.KEY_END:
  2881. if (newContainer.getRowCount() > 0) {
  2882. newRow = newContainer.getRowCount() - 1;
  2883. }
  2884. break;
  2885. case KeyCodes.KEY_PAGEDOWN:
  2886. case KeyCodes.KEY_PAGEUP:
  2887. if (newContainer.getRowCount() > 0) {
  2888. boolean down = event
  2889. .getKeyCode() == KeyCodes.KEY_PAGEDOWN;
  2890. // If there is a visible focused cell, scroll by one
  2891. // page from its position. Otherwise, use the first or
  2892. // the last visible row as the scroll start position.
  2893. // This avoids jumping when using both keyboard and the
  2894. // scroll bar for scrolling.
  2895. int firstVisible = getFirstVisibleRowIndex();
  2896. int lastVisible = getLastVisibleRowIndex();
  2897. if (newRow < firstVisible || newRow > lastVisible) {
  2898. newRow = down ? lastVisible : firstVisible;
  2899. }
  2900. // Scroll by a little less than the visible area to
  2901. // account for the possibility that the top and the
  2902. // bottom row are only partially visible.
  2903. int moveFocusBy = Math.max(1,
  2904. lastVisible - firstVisible - 1);
  2905. moveFocusBy *= down ? 1 : -1;
  2906. newRow += moveFocusBy;
  2907. newRow = Math.max(0, Math
  2908. .min(newContainer.getRowCount() - 1, newRow));
  2909. }
  2910. break;
  2911. default:
  2912. return;
  2913. }
  2914. if (newContainer != containerWithFocus) {
  2915. if (newContainer == escalator.getBody()) {
  2916. newRow = lastFocusedBodyRow;
  2917. } else if (newContainer == escalator.getHeader()) {
  2918. newRow = lastFocusedHeaderRow;
  2919. } else {
  2920. newRow = lastFocusedFooterRow;
  2921. }
  2922. } else if (newRow < 0) {
  2923. newContainer = getPreviousContainer(newContainer);
  2924. if (newContainer == containerWithFocus) {
  2925. newRow = 0;
  2926. } else if (newContainer == escalator.getBody()) {
  2927. newRow = getLastVisibleRowIndex();
  2928. } else {
  2929. newRow = newContainer.getRowCount() - 1;
  2930. }
  2931. } else if (newRow >= containerWithFocus.getRowCount()) {
  2932. newContainer = getNextContainer(newContainer);
  2933. if (newContainer == containerWithFocus) {
  2934. newRow = containerWithFocus.getRowCount() - 1;
  2935. } else if (newContainer == escalator.getBody()) {
  2936. newRow = getFirstVisibleRowIndex();
  2937. } else {
  2938. newRow = 0;
  2939. }
  2940. }
  2941. if (newContainer.getRowCount() == 0) {
  2942. /*
  2943. * There are no rows in the container. Can't change the
  2944. * focused cell.
  2945. */
  2946. return;
  2947. }
  2948. event.preventDefault();
  2949. event.stopPropagation();
  2950. setCellFocus(newRow, newColumn, newContainer);
  2951. }
  2952. }
  2953. private RowContainer getPreviousContainer(RowContainer current) {
  2954. if (current == escalator.getFooter()) {
  2955. current = escalator.getBody();
  2956. } else if (current == escalator.getBody()) {
  2957. current = escalator.getHeader();
  2958. } else {
  2959. return current;
  2960. }
  2961. if (current.getRowCount() == 0) {
  2962. return getPreviousContainer(current);
  2963. }
  2964. return current;
  2965. }
  2966. private RowContainer getNextContainer(RowContainer current) {
  2967. if (current == escalator.getHeader()) {
  2968. current = escalator.getBody();
  2969. } else if (current == escalator.getBody()) {
  2970. current = escalator.getFooter();
  2971. } else {
  2972. return current;
  2973. }
  2974. if (current.getRowCount() == 0) {
  2975. return getNextContainer(current);
  2976. }
  2977. return current;
  2978. }
  2979. private void refreshRow(int row) {
  2980. containerWithFocus.refreshRows(row, 1);
  2981. }
  2982. /**
  2983. * Offsets the focused cell's range.
  2984. *
  2985. * @param offset
  2986. * offset for fixing focused cell's range
  2987. */
  2988. public void offsetRangeBy(int offset) {
  2989. cellFocusRange = cellFocusRange.offsetBy(offset);
  2990. }
  2991. /**
  2992. * Informs {@link CellFocusHandler} that certain range of rows has been
  2993. * added to the Grid body. {@link CellFocusHandler} will fix indices
  2994. * accordingly.
  2995. *
  2996. * @param added
  2997. * a range of added rows
  2998. */
  2999. public void rowsAddedToBody(Range added) {
  3000. boolean bodyHasFocus = containerWithFocus == escalator.getBody();
  3001. boolean insertionIsAboveFocusedCell = added
  3002. .getStart() < rowWithFocus;
  3003. if (bodyHasFocus && insertionIsAboveFocusedCell) {
  3004. rowWithFocus += added.length();
  3005. rowWithFocus = Math.min(rowWithFocus,
  3006. escalator.getBody().getRowCount() - 1);
  3007. refreshRow(rowWithFocus);
  3008. }
  3009. }
  3010. /**
  3011. * Informs {@link CellFocusHandler} that certain range of rows has been
  3012. * removed from the Grid body. {@link CellFocusHandler} will fix indices
  3013. * accordingly.
  3014. *
  3015. * @param removed
  3016. * a range of removed rows
  3017. */
  3018. public void rowsRemovedFromBody(Range removed) {
  3019. if (containerWithFocus != escalator.getBody()) {
  3020. return;
  3021. } else if (!removed.contains(rowWithFocus)) {
  3022. if (removed.getStart() > rowWithFocus) {
  3023. return;
  3024. }
  3025. rowWithFocus = rowWithFocus - removed.length();
  3026. } else {
  3027. if (containerWithFocus.getRowCount() > removed.getEnd()) {
  3028. rowWithFocus = removed.getStart();
  3029. } else if (removed.getStart() > 0) {
  3030. rowWithFocus = removed.getStart() - 1;
  3031. } else {
  3032. if (escalator.getHeader().getRowCount() > 0) {
  3033. rowWithFocus = Math.min(lastFocusedHeaderRow,
  3034. escalator.getHeader().getRowCount() - 1);
  3035. containerWithFocus = escalator.getHeader();
  3036. } else if (escalator.getFooter().getRowCount() > 0) {
  3037. rowWithFocus = Math.min(lastFocusedFooterRow,
  3038. escalator.getFooter().getRowCount() - 1);
  3039. containerWithFocus = escalator.getFooter();
  3040. }
  3041. }
  3042. }
  3043. refreshRow(rowWithFocus);
  3044. }
  3045. }
  3046. /**
  3047. * A column that contains CheckBoxes for representing Grid's row selection.
  3048. * By default only used with MultiSelectionModel.
  3049. *
  3050. */
  3051. public final class SelectionColumn extends Column<Boolean, T>
  3052. implements GridEnabledHandler, GridSelectionAllowedHandler {
  3053. private boolean initDone = false;
  3054. private boolean selected = false;
  3055. private CheckBox selectAllCheckBox;
  3056. private boolean selectAllCheckBoxVisible;
  3057. private HeaderCell selectionCell;
  3058. SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
  3059. super(selectColumnRenderer);
  3060. addEnabledHandler(this);
  3061. addSelectionAllowedHandler(this);
  3062. }
  3063. void initDone() {
  3064. setWidth(-1);
  3065. setEditable(false);
  3066. setResizable(false);
  3067. updateEnable();
  3068. initDone = true;
  3069. }
  3070. @Override
  3071. protected void setDefaultHeaderContent(HeaderCell selectionCell) {
  3072. this.selectionCell = selectionCell;
  3073. if (selectAllCheckBox == null) {
  3074. // there is no checkbox yet -> create it
  3075. selectAllCheckBox = GWT.create(CheckBox.class);
  3076. selectAllCheckBox.setStylePrimaryName(
  3077. getStylePrimaryName() + SELECT_ALL_CHECKBOX_CLASSNAME);
  3078. // label of checkbox should only be visible for assistive
  3079. // devices
  3080. selectAllCheckBox.addStyleName("v-assistive-device-only-label");
  3081. selectAllCheckBox.addValueChangeHandler(event -> {
  3082. selected = event.getValue();
  3083. fireEvent(new SelectAllEvent<>(getSelectionModel(),
  3084. selected));
  3085. });
  3086. selectAllCheckBox.setText("Selects all rows of the table.");
  3087. selectAllCheckBox.setValue(selected);
  3088. addHeaderClickHandler(this::onHeaderClickEvent);
  3089. // Select all with space when "select all" cell is active
  3090. addHeaderKeyUpHandler(this::onHeaderKeyUpEvent);
  3091. } else {
  3092. // checkbox exists, but default header row has changed -> clear
  3093. // rows
  3094. for (HeaderRow row : header.getRows()) {
  3095. if (row.getCell(this)
  3096. .getType() == GridStaticCellType.WIDGET) {
  3097. // Detach from old header.
  3098. row.getCell(this).setText("");
  3099. }
  3100. }
  3101. }
  3102. // attach the checkbox to default row depending on visibility
  3103. doSetSelectAllCheckBoxVisible();
  3104. }
  3105. @Override
  3106. public Column<Boolean, T> setWidth(double pixels) {
  3107. if (pixels != getWidth() && initDone) {
  3108. throw new UnsupportedOperationException("The selection "
  3109. + "column cannot be modified after init");
  3110. } else {
  3111. super.setWidth(pixels);
  3112. }
  3113. return this;
  3114. }
  3115. @Override
  3116. public Boolean getValue(T row) {
  3117. return Boolean.valueOf(isSelected(row));
  3118. }
  3119. @Override
  3120. public Column<Boolean, T> setExpandRatio(int ratio) {
  3121. throw new UnsupportedOperationException(
  3122. "can't change the expand ratio of the selection column");
  3123. }
  3124. @Override
  3125. public int getExpandRatio() {
  3126. return 0;
  3127. }
  3128. @Override
  3129. public Column<Boolean, T> setMaximumWidth(double pixels) {
  3130. throw new UnsupportedOperationException(
  3131. "can't change the maximum width of the selection column");
  3132. }
  3133. @Override
  3134. public double getMaximumWidth() {
  3135. return -1;
  3136. }
  3137. @Override
  3138. public Column<Boolean, T> setMinimumWidth(double pixels) {
  3139. throw new UnsupportedOperationException(
  3140. "can't change the minimum width of the selection column");
  3141. }
  3142. @Override
  3143. public double getMinimumWidth() {
  3144. return -1;
  3145. }
  3146. @Override
  3147. public Column<Boolean, T> setEditable(boolean editable) {
  3148. if (initDone) {
  3149. throw new UnsupportedOperationException(
  3150. "can't set the selection column editable");
  3151. }
  3152. super.setEditable(editable);
  3153. return this;
  3154. }
  3155. @Override
  3156. public void onEnabled(boolean enabled) {
  3157. updateEnable();
  3158. }
  3159. /**
  3160. * Sets the select all checkbox visible in the default header row for
  3161. * selection column.
  3162. *
  3163. * @param selectAllCheckBoxVisible
  3164. * {@code true} for visible, {@code false} for not
  3165. */
  3166. public void setSelectAllCheckBoxVisible(
  3167. boolean selectAllCheckBoxVisible) {
  3168. if (this.selectAllCheckBoxVisible != selectAllCheckBoxVisible) {
  3169. this.selectAllCheckBoxVisible = selectAllCheckBoxVisible;
  3170. doSetSelectAllCheckBoxVisible();
  3171. }
  3172. }
  3173. /**
  3174. * Returns whether the select all checkbox is visible or not.
  3175. *
  3176. * @return {@code true} for visible, {@code false} for not
  3177. */
  3178. public boolean isSelectAllCheckBoxVisible() {
  3179. return selectAllCheckBoxVisible;
  3180. }
  3181. /**
  3182. * Returns the select all checkbox, which is present in the default
  3183. * header if the used selection model is of type
  3184. * {@link SelectionModelWithSelectionColumn}.
  3185. *
  3186. * To handle select all, add {@link SelectAllHandler} the grid with
  3187. * {@link #addSelectAllHandler(SelectAllHandler)}.
  3188. *
  3189. * @return the select all checkbox, or an empty optional if not in use
  3190. */
  3191. public Optional<CheckBox> getSelectAllCheckBox() {
  3192. return Optional.ofNullable(selectionColumn == null ? null
  3193. : selectionColumn.selectAllCheckBox);
  3194. }
  3195. /**
  3196. * Sets the select all checkbox visible or hidden.
  3197. */
  3198. protected void doSetSelectAllCheckBoxVisible() {
  3199. if (selectAllCheckBox == null || selectionCell == null) {
  3200. // There is no default header row to display select all checkbox
  3201. return;
  3202. }
  3203. if (selectAllCheckBoxVisible) {
  3204. selectionCell.setWidget(selectAllCheckBox);
  3205. } else {
  3206. selectionCell.setText("");
  3207. }
  3208. }
  3209. private void updateEnable() {
  3210. if (selectAllCheckBox != null) {
  3211. selectAllCheckBox.setEnabled(isEnabled()
  3212. && getSelectionModel().isSelectionAllowed());
  3213. }
  3214. }
  3215. private void onHeaderClickEvent(GridClickEvent event) {
  3216. if (selectAllCheckBox.isEnabled()) {
  3217. CellReference<?> targetCell = event.getTargetCell();
  3218. int defaultRowIndex = getHeader().getRows()
  3219. .indexOf(getDefaultHeaderRow());
  3220. if (targetCell.getColumnIndex() == 0
  3221. && targetCell.getRowIndex() == defaultRowIndex) {
  3222. selectAllCheckBox.setValue(!selectAllCheckBox.getValue(),
  3223. true);
  3224. }
  3225. }
  3226. }
  3227. private void onHeaderKeyUpEvent(GridKeyUpEvent event) {
  3228. if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE
  3229. || !selectAllCheckBox.isEnabled()) {
  3230. return;
  3231. }
  3232. HeaderRow targetHeaderRow = getHeader()
  3233. .getRow(event.getFocusedCell().getRowIndex());
  3234. if (!targetHeaderRow.isDefault()) {
  3235. return;
  3236. }
  3237. if (event.getFocusedCell().getColumn() == SelectionColumn.this) {
  3238. // Send events to ensure state is updated
  3239. selectAllCheckBox.setValue(!selectAllCheckBox.getValue(), true);
  3240. }
  3241. }
  3242. @Override
  3243. public void onSelectionAllowed(GridSelectionAllowedEvent event) {
  3244. updateEnable();
  3245. }
  3246. }
  3247. /**
  3248. * Helper class for performing sorting through the user interface. Controls
  3249. * the sort() method, reporting USER as the event originator. This is a
  3250. * completely internal class, and is, as such, safe to re-name should a more
  3251. * descriptive name come to mind.
  3252. */
  3253. private final class UserSorter {
  3254. private final Timer timer;
  3255. private boolean scheduledMultisort;
  3256. private Column<?, T> column;
  3257. private UserSorter() {
  3258. timer = new Timer() {
  3259. @Override
  3260. public void run() {
  3261. scheduledMultisort = true;
  3262. }
  3263. };
  3264. }
  3265. /**
  3266. * Toggle sorting for a cell. If the multisort parameter is set to true,
  3267. * the cell's sort order is modified as a natural part of a multi-sort
  3268. * chain. If false, the sorting order is set to ASCENDING for that
  3269. * cell's column. If that column was already the only sorted column in
  3270. * the Grid, the sort direction is flipped.
  3271. *
  3272. * @param cell
  3273. * a valid cell reference
  3274. * @param multisort
  3275. * whether the sort command should act as a multi-sort stack
  3276. * or not
  3277. */
  3278. public void sort(Column<?, ?> column, boolean multisort) {
  3279. if (!columns.contains(column)) {
  3280. throw new IllegalArgumentException(
  3281. "Given column is not a column in this grid. " + column);
  3282. }
  3283. if (!column.isSortable()) {
  3284. return;
  3285. }
  3286. final SortOrder so = getSortOrder(column);
  3287. if (multisort) {
  3288. // If the sort order exists, replace existing value with its
  3289. // opposite
  3290. if (so != null) {
  3291. final int idx = sortOrder.indexOf(so);
  3292. sortOrder.set(idx, so.getOpposite());
  3293. } else {
  3294. // If it doesn't, just add a new sort order to the end of
  3295. // the list
  3296. sortOrder.add(new SortOrder(column));
  3297. }
  3298. } else {
  3299. // Since we're doing single column sorting, first clear the
  3300. // list. Then, if the sort order existed, add its opposite,
  3301. // otherwise just add a new sort value
  3302. int items = sortOrder.size();
  3303. sortOrder.clear();
  3304. if (so != null && items == 1) {
  3305. sortOrder.add(so.getOpposite());
  3306. } else {
  3307. sortOrder.add(new SortOrder(column));
  3308. }
  3309. }
  3310. // sortOrder has been changed; tell the Grid to re-sort itself by
  3311. // user request.
  3312. Grid.this.sort(true);
  3313. }
  3314. /**
  3315. * Invoked on touchstart, marks itself that we will perform sorting on
  3316. * touchend. By default single sort is performed, however on long touch
  3317. * we will perform multitouch.
  3318. *
  3319. * Actual sorting is only performed after {@link #onTouchEnd()} is
  3320. * invoked.
  3321. *
  3322. * @param delay
  3323. * delay, in milliseconds
  3324. */
  3325. public void awaitForTouchEnd(int delay) {
  3326. cancelAwaitForTouchEnd();
  3327. column = eventCell.getColumn();
  3328. scheduledMultisort = false;
  3329. timer.schedule(delay);
  3330. }
  3331. /**
  3332. * Notifies that the finger has been lifted from the tablet/mobile.
  3333. * Depending on how much time has passed, we need to perform singlesort
  3334. * or multisort.
  3335. *
  3336. * Does nothing if the await has been canceled by a call to
  3337. * {@link #cancelAwaitForTouchEnd()}.
  3338. */
  3339. public void onTouchEnd() {
  3340. if (column != null) {
  3341. sort(column, scheduledMultisort);
  3342. cancelAwaitForTouchEnd();
  3343. }
  3344. }
  3345. /**
  3346. * Cancel a scheduled sort.
  3347. */
  3348. public void cancelAwaitForTouchEnd() {
  3349. timer.cancel();
  3350. column = null;
  3351. }
  3352. }
  3353. /**
  3354. * @see Grid#autoColumnWidthsRecalculator
  3355. */
  3356. private class AutoColumnWidthsRecalculator {
  3357. private double lastCalculatedInnerWidth = -1;
  3358. private final ScheduledCommand calculateCommand = new ScheduledCommand() {
  3359. @Override
  3360. public void execute() {
  3361. if (!isScheduled) {
  3362. // something cancelled running this.
  3363. return;
  3364. }
  3365. if (header.markAsDirty || footer.markAsDirty) {
  3366. if (rescheduleCount < 10) {
  3367. /*
  3368. * Headers and footers are rendered as finally, this way
  3369. * we re-schedule this loop as finally, at the end of
  3370. * the queue, so that the headers have a chance to
  3371. * render themselves.
  3372. */
  3373. Scheduler.get().scheduleFinally(this);
  3374. rescheduleCount++;
  3375. } else {
  3376. /*
  3377. * We've tried too many times reschedule finally. Seems
  3378. * like something is being deferred. Let the queue
  3379. * execute and retry again.
  3380. */
  3381. rescheduleCount = 0;
  3382. Scheduler.get().scheduleDeferred(this);
  3383. }
  3384. } else if (currentDataAvailable.isEmpty()
  3385. && (dataSource.isWaitingForData()
  3386. || escalator.getBody().getRowCount() > 0)) {
  3387. Scheduler.get().scheduleDeferred(this);
  3388. } else {
  3389. calculate();
  3390. }
  3391. }
  3392. };
  3393. private int rescheduleCount = 0;
  3394. private boolean isScheduled;
  3395. /**
  3396. * Calculates and applies column widths, taking into account fixed
  3397. * widths and column expand rules.
  3398. *
  3399. * @see Column#setWidth(double)
  3400. * @see Column#setExpandRatio(int)
  3401. * @see Column#setMinimumWidth(double)
  3402. * @see Column#setMaximumWidth(double)
  3403. */
  3404. public void schedule() {
  3405. if (!isScheduled && isAttached() && !(currentDataAvailable.isEmpty()
  3406. && escalator.getBody().getRowCount() > 0)) {
  3407. isScheduled = true;
  3408. Scheduler.get().scheduleFinally(calculateCommand);
  3409. }
  3410. }
  3411. private void calculate() {
  3412. isScheduled = false;
  3413. rescheduleCount = 0;
  3414. assert !(currentDataAvailable.isEmpty() && dataSource
  3415. .isWaitingForData()) : "Trying to calculate column widths without data while data is still being fetched.";
  3416. // Make SelectAllCheckbox visible
  3417. getSelectionColumn().ifPresent(col -> {
  3418. if (getDefaultHeaderRow() == null) {
  3419. return;
  3420. }
  3421. HeaderCell headerCell = getDefaultHeaderRow().getCell(col);
  3422. if (headerCell.getType().equals(GridStaticCellType.WIDGET)) {
  3423. // SelectAllCheckbox is present already
  3424. return;
  3425. }
  3426. headerCell.setWidget(col.selectAllCheckBox);
  3427. refreshHeader(); // Paint.
  3428. });
  3429. if (columnsAreGuaranteedToBeWiderThanGrid()) {
  3430. applyColumnWidths();
  3431. } else {
  3432. applyColumnWidthsWithExpansion();
  3433. }
  3434. // Hide the SelectAllCheckbox if needed
  3435. getSelectionColumn()
  3436. .ifPresent(SelectionColumn::doSetSelectAllCheckBoxVisible);
  3437. // Update latest width to prevent recalculate on height change.
  3438. lastCalculatedInnerWidth = escalator.getInnerWidth();
  3439. }
  3440. private boolean columnsAreGuaranteedToBeWiderThanGrid() {
  3441. double freeSpace = escalator.getInnerWidth();
  3442. for (Column<?, ?> column : getVisibleColumns()) {
  3443. /*
  3444. * Check the width and min width and ensure that no column can
  3445. * be expected to be narrower than what the resize handler
  3446. * requires, if one is present.
  3447. */
  3448. if (column.getWidth() >= 0) {
  3449. if (column.isResizable() && resizeHandleWidth > 0) {
  3450. freeSpace -= Math.max(resizeHandleWidth,
  3451. column.getWidth());
  3452. } else {
  3453. freeSpace -= column.getWidth();
  3454. }
  3455. } else if (column.getMinimumWidth() >= 0) {
  3456. if (column.isResizable() && resizeHandleWidth > 0) {
  3457. freeSpace -= Math.max(resizeHandleWidth,
  3458. column.getMinimumWidth());
  3459. } else {
  3460. freeSpace -= column.getMinimumWidth();
  3461. }
  3462. } else if (column.isResizable() && resizeHandleWidth > 0) {
  3463. freeSpace -= resizeHandleWidth;
  3464. }
  3465. }
  3466. return freeSpace < 0;
  3467. }
  3468. private void applyColumnWidths() {
  3469. /* Step 1: Apply all column widths as they are. */
  3470. Map<Integer, Double> selfWidths = new LinkedHashMap<>();
  3471. List<Column<?, T>> columns = getVisibleColumns();
  3472. for (int index = 0; index < columns.size(); index++) {
  3473. selfWidths.put(index, columns.get(index).getWidth());
  3474. }
  3475. Grid.this.escalator.getColumnConfiguration()
  3476. .setColumnWidths(selfWidths, true);
  3477. /*
  3478. * Step 2: Make sure that each column ends up obeying their min/max
  3479. * width constraints if defined as autowidth. If constraints are
  3480. * violated, fix it.
  3481. */
  3482. Map<Integer, Double> constrainedWidths = new LinkedHashMap<>();
  3483. for (int index = 0; index < columns.size(); index++) {
  3484. Column<?, T> column = columns.get(index);
  3485. boolean hasAutoWidth = column.getWidth() < 0;
  3486. if (!hasAutoWidth) {
  3487. continue;
  3488. }
  3489. // TODO: bug: these don't honor the CSS max/min. :(
  3490. double actualWidth = column.getWidthActual();
  3491. if (actualWidth < getMinWidth(column)) {
  3492. constrainedWidths.put(index, column.getMinimumWidth());
  3493. } else if (actualWidth > getMaxWidth(column)) {
  3494. constrainedWidths.put(index, column.getMaximumWidth());
  3495. }
  3496. }
  3497. Grid.this.escalator.getColumnConfiguration()
  3498. .setColumnWidths(constrainedWidths, true);
  3499. }
  3500. @SuppressWarnings("unchecked")
  3501. private void applyColumnWidthsWithExpansion() {
  3502. boolean defaultExpandRatios = true;
  3503. int totalRatios = 0;
  3504. double reservedPixels = 0;
  3505. final Set<Column<?, T>> columnsToExpand = new HashSet<>();
  3506. List<Column<?, T>> nonFixedColumns = new ArrayList<>();
  3507. Map<Integer, Double> columnSizes = new HashMap<>();
  3508. final List<Column<?, T>> visibleColumns = getVisibleColumns();
  3509. /*
  3510. * Set all fixed widths and also calculate the size-to-fit widths
  3511. * for the autocalculated columns.
  3512. *
  3513. * This way we know with how many pixels we have left to expand the
  3514. * rest.
  3515. */
  3516. for (Column<?, T> column : visibleColumns) {
  3517. final double widthAsIs = column.getWidth();
  3518. final boolean isFixedWidth = widthAsIs >= 0;
  3519. defaultExpandRatios = defaultExpandRatios
  3520. && (column.getExpandRatio() == -1
  3521. || column == selectionColumn);
  3522. if (isFixedWidth) {
  3523. // Check for min & max width just to be sure we don't break
  3524. // the limits
  3525. double widthFixed = Math.max(
  3526. Math.min(getMaxWidth(column), widthAsIs),
  3527. column.getMinimumWidth());
  3528. if (column.isResizable() && resizeHandleWidth > 0) {
  3529. // Ensure the resize handle fits
  3530. widthFixed = Math.max(widthFixed, resizeHandleWidth);
  3531. }
  3532. columnSizes.put(visibleColumns.indexOf(column), widthFixed);
  3533. reservedPixels += widthFixed;
  3534. } else {
  3535. nonFixedColumns.add(column);
  3536. columnSizes.put(visibleColumns.indexOf(column), -1.0d);
  3537. }
  3538. }
  3539. /*
  3540. * Set column sizes so that it's possible to measure non-fixed
  3541. * actual sizes without previously applied expand ratio tweaks, but
  3542. * don't trigger the element size recalculation before the rest of
  3543. * this method has also been processed.
  3544. */
  3545. setColumnSizes(columnSizes, false);
  3546. for (Column<?, T> column : nonFixedColumns) {
  3547. final int expandRatio = defaultExpandRatios ? 1
  3548. : column.getExpandRatio();
  3549. final double maxWidth = getMaxWidth(column);
  3550. double newWidth;
  3551. if (column.isMinimumWidthFromContent()) {
  3552. if (column.isResizable() && resizeHandleWidth > 0) {
  3553. // Ensure the resize handle fits
  3554. newWidth = Math.max(
  3555. Math.min(maxWidth, column.getWidthActual()),
  3556. resizeHandleWidth);
  3557. } else {
  3558. newWidth = Math.min(maxWidth, column.getWidthActual());
  3559. }
  3560. } else {
  3561. if (column.isResizable() && resizeHandleWidth > 0) {
  3562. // Ensure the resize handle fits
  3563. newWidth = resizeHandleWidth;
  3564. } else {
  3565. newWidth = 0;
  3566. }
  3567. }
  3568. boolean shouldExpand = newWidth < maxWidth && expandRatio > 0
  3569. && column != selectionColumn;
  3570. if (shouldExpand) {
  3571. totalRatios += expandRatio;
  3572. columnsToExpand.add(column);
  3573. }
  3574. reservedPixels += newWidth;
  3575. columnSizes.put(visibleColumns.indexOf(column), newWidth);
  3576. }
  3577. /*
  3578. * Now that we know how many pixels we need at the very least, we
  3579. * can distribute the remaining pixels to all columns according to
  3580. * their expand ratios.
  3581. */
  3582. double pixelsToDistribute = escalator.getInnerWidth()
  3583. - reservedPixels;
  3584. if (pixelsToDistribute <= 0 || totalRatios <= 0) {
  3585. if (pixelsToDistribute <= 0) {
  3586. // Set column sizes for expanding columns
  3587. setColumnSizes(columnSizes, true);
  3588. }
  3589. /*
  3590. * If pixelsToDistribute > 0 the element size recalculation
  3591. * isn't done at all, even if some column sizes were set
  3592. * earlier, but this doesn't appear to be detrimental while
  3593. * attempting to trigger the recalculation here breaks a
  3594. * GridEditRow test.
  3595. */
  3596. return;
  3597. }
  3598. Object[] result = handleMaximumWidths(totalRatios,
  3599. pixelsToDistribute, defaultExpandRatios, columnsToExpand,
  3600. visibleColumns, columnSizes);
  3601. if (result.length != 3) {
  3602. // everything handled already
  3603. return;
  3604. }
  3605. // update values based on maximum width handling
  3606. totalRatios = (int) result[0];
  3607. pixelsToDistribute = (double) result[1];
  3608. columnSizes = (Map<Integer, Double>) result[2];
  3609. assert pixelsToDistribute > 0 : "We've run out of pixels to distribute ("
  3610. + pixelsToDistribute + "px to " + totalRatios
  3611. + " ratios between " + columnsToExpand.size() + " columns)";
  3612. assert totalRatios > 0 && !columnsToExpand
  3613. .isEmpty() : "Bookkeeping out of sync. Ratios: "
  3614. + totalRatios + " Columns: "
  3615. + columnsToExpand.size();
  3616. /*
  3617. * If we still have anything left, distribute the remaining pixels
  3618. * to the remaining columns.
  3619. */
  3620. columnSizes = distributeRemainingPixels(totalRatios,
  3621. pixelsToDistribute, defaultExpandRatios, columnsToExpand,
  3622. visibleColumns, columnSizes);
  3623. columnSizes = handleMinimumWidths(defaultExpandRatios,
  3624. columnsToExpand, visibleColumns, columnSizes);
  3625. // Finally set all the column sizes.
  3626. setColumnSizes(columnSizes, true);
  3627. }
  3628. private Object[] handleMaximumWidths(int totalRatios,
  3629. double pixelsToDistribute, final boolean defaultExpandRatios,
  3630. final Set<Column<?, T>> columnsToExpand,
  3631. final List<Column<?, T>> visibleColumns,
  3632. final Map<Integer, Double> columnSizes) {
  3633. /*
  3634. * Check for columns that hit their max width. Adjust
  3635. * pixelsToDistribute and totalRatios accordingly. Recheck. Stop
  3636. * when no new columns hit their max width
  3637. */
  3638. boolean aColumnHasMaxedOut;
  3639. do {
  3640. aColumnHasMaxedOut = false;
  3641. final double widthPerRatio = pixelsToDistribute / totalRatios;
  3642. final Iterator<Column<?, T>> i = columnsToExpand.iterator();
  3643. while (i.hasNext()) {
  3644. final Column<?, T> column = i.next();
  3645. final int expandRatio = getExpandRatio(column,
  3646. defaultExpandRatios);
  3647. final int columnIndex = visibleColumns.indexOf(column);
  3648. final double autoWidth = columnSizes.get(columnIndex);
  3649. final double maxWidth = getMaxWidth(column);
  3650. double expandedWidth = autoWidth
  3651. + widthPerRatio * expandRatio;
  3652. if (maxWidth <= expandedWidth) {
  3653. i.remove();
  3654. totalRatios -= expandRatio;
  3655. aColumnHasMaxedOut = true;
  3656. pixelsToDistribute -= maxWidth - autoWidth;
  3657. columnSizes.put(columnIndex, maxWidth);
  3658. }
  3659. }
  3660. } while (aColumnHasMaxedOut);
  3661. if (totalRatios <= 0 && columnsToExpand.isEmpty()) {
  3662. setColumnSizes(columnSizes, true);
  3663. // nothing left to handle
  3664. return new Object[] {};
  3665. }
  3666. // this must return exactly 3 objects in this precise order
  3667. return new Object[] { totalRatios, pixelsToDistribute,
  3668. columnSizes };
  3669. }
  3670. private Map<Integer, Double> distributeRemainingPixels(int totalRatios,
  3671. final double pixelsToDistribute,
  3672. final boolean defaultExpandRatios,
  3673. final Set<Column<?, T>> columnsToExpand,
  3674. final List<Column<?, T>> visibleColumns,
  3675. final Map<Integer, Double> columnSizes) {
  3676. final double widthPerRatio;
  3677. int leftOver = 0;
  3678. if (BrowserInfo.getBrowserString().contains("PhantomJS")) {
  3679. // These browsers report subpixels as integers. this usually
  3680. // results into issues..
  3681. widthPerRatio = (int) (pixelsToDistribute / totalRatios);
  3682. leftOver = (int) (pixelsToDistribute
  3683. - widthPerRatio * totalRatios);
  3684. } else {
  3685. widthPerRatio = pixelsToDistribute / totalRatios;
  3686. }
  3687. for (Column<?, T> column : columnsToExpand) {
  3688. final int expandRatio = getExpandRatio(column,
  3689. defaultExpandRatios);
  3690. final int columnIndex = visibleColumns.indexOf(column);
  3691. final double autoWidth = columnSizes.get(columnIndex);
  3692. double totalWidth = autoWidth + widthPerRatio * expandRatio;
  3693. if (leftOver > 0) {
  3694. totalWidth += 1;
  3695. leftOver--;
  3696. }
  3697. columnSizes.put(columnIndex, totalWidth);
  3698. totalRatios -= expandRatio;
  3699. }
  3700. assert totalRatios == 0 : "Bookkeeping error: there were still some ratios left undistributed: "
  3701. + totalRatios;
  3702. return columnSizes;
  3703. }
  3704. private Map<Integer, Double> handleMinimumWidths(
  3705. final boolean defaultExpandRatios,
  3706. final Set<Column<?, T>> columnsToExpand,
  3707. final List<Column<?, T>> visibleColumns,
  3708. final Map<Integer, Double> columnSizes) {
  3709. /*
  3710. * Check the guarantees for minimum width and scoot back the columns
  3711. * that don't care.
  3712. */
  3713. boolean minWidthsCausedReflows;
  3714. do {
  3715. minWidthsCausedReflows = false;
  3716. /*
  3717. * First, let's check which columns were too cramped, and expand
  3718. * them. Also keep track on how many pixels we grew - we need to
  3719. * remove those pixels from other columns
  3720. */
  3721. double pixelsToRemoveFromOtherColumns = 0;
  3722. for (Column<?, T> column : visibleColumns) {
  3723. /*
  3724. * We can't iterate over columnsToExpand, even though that
  3725. * would be convenient. This is because some column without
  3726. * an expand ratio might still have a min width - those
  3727. * wouldn't show up in that set.
  3728. */
  3729. double minWidth = getMinWidth(column);
  3730. final int columnIndex = visibleColumns.indexOf(column);
  3731. double currentWidth = columnSizes.get(columnIndex);
  3732. boolean hasAutoWidth = column.getWidth() < 0;
  3733. if (hasAutoWidth && currentWidth < minWidth) {
  3734. columnSizes.put(columnIndex, minWidth);
  3735. pixelsToRemoveFromOtherColumns += minWidth
  3736. - currentWidth;
  3737. minWidthsCausedReflows = true;
  3738. /*
  3739. * Remove this column form the set if it exists. This
  3740. * way we make sure that it doesn't get shrunk in the
  3741. * next step.
  3742. */
  3743. columnsToExpand.remove(column);
  3744. }
  3745. }
  3746. /*
  3747. * Now we need to shrink the remaining columns according to
  3748. * their ratios. Recalculate the sum of remaining ratios.
  3749. */
  3750. int totalRatios = 0;
  3751. for (Column<?, ?> column : columnsToExpand) {
  3752. totalRatios += getExpandRatio(column, defaultExpandRatios);
  3753. }
  3754. final double pixelsToRemovePerRatio = pixelsToRemoveFromOtherColumns
  3755. / totalRatios;
  3756. for (Column<?, T> column : columnsToExpand) {
  3757. final double pixelsToRemove = pixelsToRemovePerRatio
  3758. * getExpandRatio(column, defaultExpandRatios);
  3759. int colIndex = visibleColumns.indexOf(column);
  3760. columnSizes.put(colIndex,
  3761. columnSizes.get(colIndex) - pixelsToRemove);
  3762. }
  3763. } while (minWidthsCausedReflows);
  3764. return columnSizes;
  3765. }
  3766. private void setColumnSizes(Map<Integer, Double> columnSizes,
  3767. boolean recalculateElementSizes) {
  3768. // Set all widths at once
  3769. escalator.getColumnConfiguration().setColumnWidths(columnSizes,
  3770. recalculateElementSizes);
  3771. }
  3772. private int getExpandRatio(Column<?, ?> column,
  3773. boolean defaultExpandRatios) {
  3774. int expandRatio = column.getExpandRatio();
  3775. if (expandRatio > 0) {
  3776. return expandRatio;
  3777. } else if (expandRatio < 0) {
  3778. assert defaultExpandRatios : "No columns should've expanded";
  3779. return 1;
  3780. } else {
  3781. assert false : "this method should've not been called at all if expandRatio is 0";
  3782. return 0;
  3783. }
  3784. }
  3785. /**
  3786. * Returns the maximum width of the column, or {@link Double#MAX_VALUE}
  3787. * if defined as negative.
  3788. */
  3789. private double getMaxWidth(Column<?, ?> column) {
  3790. double maxWidth = column.getMaximumWidth();
  3791. if (maxWidth >= 0) {
  3792. return maxWidth;
  3793. } else {
  3794. return Double.MAX_VALUE;
  3795. }
  3796. }
  3797. /**
  3798. * Returns the minimum width of the column, or {@link Double#MIN_VALUE}
  3799. * if defined as negative.
  3800. */
  3801. private double getMinWidth(Column<?, ?> column) {
  3802. double minWidth = column.getMinimumWidth();
  3803. if (minWidth >= 0) {
  3804. return minWidth;
  3805. } else {
  3806. return Double.MIN_VALUE;
  3807. }
  3808. }
  3809. /**
  3810. * Check whether the auto width calculation is currently scheduled.
  3811. *
  3812. * @return <code>true</code> if auto width calculation is currently
  3813. * scheduled
  3814. */
  3815. public boolean isScheduled() {
  3816. return isScheduled;
  3817. }
  3818. }
  3819. private class GridSpacerUpdater implements SpacerUpdater {
  3820. private static final String STRIPE_CLASSNAME = "stripe";
  3821. private final Map<Element, Widget> elementToWidgetMap = new HashMap<>();
  3822. @Override
  3823. public void init(Spacer spacer) {
  3824. initTheming(spacer);
  3825. int rowIndex = spacer.getRow();
  3826. Widget detailsWidget = null;
  3827. try {
  3828. detailsWidget = detailsGenerator.getDetails(rowIndex);
  3829. } catch (Throwable e) {
  3830. getLogger().log(Level.SEVERE,
  3831. "Exception while generating details for row "
  3832. + rowIndex,
  3833. e);
  3834. }
  3835. final double spacerHeight;
  3836. Element spacerElement = spacer.getElement();
  3837. if (detailsWidget == null) {
  3838. spacerElement.removeAllChildren();
  3839. spacerHeight = DETAILS_ROW_INITIAL_HEIGHT;
  3840. } else {
  3841. Element element = detailsWidget.getElement();
  3842. spacerElement.appendChild(element);
  3843. setParent(detailsWidget, Grid.this);
  3844. Widget previousWidget = elementToWidgetMap.put(element,
  3845. detailsWidget);
  3846. assert previousWidget == null : "Overwrote a pre-existing widget on row "
  3847. + rowIndex + " without proper removal first.";
  3848. /*
  3849. * Once we have the content properly inside the DOM, we should
  3850. * re-measure it to make sure that it's the correct height.
  3851. *
  3852. * This is rather tricky, since the row (tr) will get the
  3853. * height, but the spacer cell (td) has the borders, which
  3854. * should go on top of the previous row and next row.
  3855. */
  3856. final double contentHeight;
  3857. if (detailsGenerator instanceof HeightAwareDetailsGenerator) {
  3858. HeightAwareDetailsGenerator sadg = (HeightAwareDetailsGenerator) detailsGenerator;
  3859. contentHeight = sadg.getDetailsHeight(rowIndex);
  3860. } else {
  3861. contentHeight = WidgetUtil
  3862. .getRequiredHeightBoundingClientRectDouble(element);
  3863. }
  3864. double borderTopAndBottomHeight = WidgetUtil
  3865. .getBorderTopAndBottomThickness(spacerElement);
  3866. double measuredHeight = 0d;
  3867. if (contentHeight > 0) {
  3868. measuredHeight = contentHeight + borderTopAndBottomHeight;
  3869. } else {
  3870. Scheduler.get().scheduleFinally(() -> {
  3871. // make sure the spacer hasn't got removed
  3872. if (spacer.getElement().getParentElement() != null) {
  3873. // re-check the height
  3874. double confirmedContentHeight = WidgetUtil
  3875. .getRequiredHeightBoundingClientRectDouble(
  3876. element);
  3877. if (confirmedContentHeight > 0) {
  3878. double confirmedMeasuredHeight = confirmedContentHeight
  3879. + WidgetUtil
  3880. .getBorderTopAndBottomThickness(
  3881. spacer.getElement());
  3882. escalator.getBody().setSpacer(spacer.getRow(),
  3883. confirmedMeasuredHeight);
  3884. if (getHeightMode() == HeightMode.UNDEFINED) {
  3885. setHeightByRows(getEscalator().getBody()
  3886. .getRowCount());
  3887. }
  3888. }
  3889. }
  3890. });
  3891. }
  3892. assert getElement().isOrHasChild(
  3893. spacerElement) : "The spacer element wasn't in the DOM during measurement, but was assumed to be.";
  3894. spacerHeight = measuredHeight;
  3895. }
  3896. escalator.getBody().setSpacer(rowIndex, spacerHeight);
  3897. if (getHeightMode() == HeightMode.UNDEFINED) {
  3898. setHeightByRows(getEscalator().getBody().getRowCount());
  3899. }
  3900. }
  3901. @Override
  3902. public void destroy(Spacer spacer) {
  3903. Element spacerElement = spacer.getElement();
  3904. assert getElement().isOrHasChild(spacerElement) : "Trying "
  3905. + "to destroy a spacer that is not connected to this "
  3906. + "Grid's DOM. (row: " + spacer.getRow() + ", element: "
  3907. + spacerElement + ")";
  3908. Widget detailsWidget = elementToWidgetMap
  3909. .remove(spacerElement.getFirstChildElement());
  3910. if (detailsWidget != null) {
  3911. /*
  3912. * The widget may be null here if the previous generator
  3913. * returned a null widget.
  3914. */
  3915. assert spacerElement.getFirstChild() != null : "The "
  3916. + "details row to destroy did not contain a widget - "
  3917. + "probably removed by something else without "
  3918. + "permission? (row: " + spacer.getRow() + ", element: "
  3919. + spacerElement + ")";
  3920. setParent(detailsWidget, null);
  3921. spacerElement.removeAllChildren();
  3922. if (getHeightMode() == HeightMode.UNDEFINED) {
  3923. setHeightByRows(getEscalator().getBody().getRowCount());
  3924. }
  3925. }
  3926. }
  3927. private void initTheming(Spacer spacer) {
  3928. Element spacerRoot = spacer.getElement();
  3929. if (spacer.getRow() % 2 == 1) {
  3930. spacerRoot.getParentElement().addClassName(STRIPE_CLASSNAME);
  3931. } else {
  3932. spacerRoot.getParentElement().removeClassName(STRIPE_CLASSNAME);
  3933. }
  3934. }
  3935. }
  3936. /**
  3937. * Sidebar displaying toggles for hidable columns and custom widgets
  3938. * provided by the application.
  3939. * <p>
  3940. * The button for opening the sidebar is automatically visible inside the
  3941. * grid, if it contains any column hiding options or custom widgets. The
  3942. * column hiding toggles and custom widgets become visible once the sidebar
  3943. * has been opened.
  3944. *
  3945. * @since 7.5.0
  3946. */
  3947. private static class Sidebar extends Composite implements HasEnabled {
  3948. private final ClickHandler openCloseButtonHandler = event -> {
  3949. if (!isOpen()) {
  3950. open();
  3951. } else {
  3952. close();
  3953. }
  3954. };
  3955. private final FlowPanel rootContainer;
  3956. private final FlowPanel content;
  3957. private final MenuBar menuBar;
  3958. private final Button openCloseButton;
  3959. private final Grid<?> grid;
  3960. private Overlay overlay;
  3961. private Sidebar(Grid<?> grid) {
  3962. this.grid = grid;
  3963. rootContainer = new FlowPanel();
  3964. initWidget(rootContainer);
  3965. openCloseButton = new Button();
  3966. openCloseButton.addClickHandler(openCloseButtonHandler);
  3967. rootContainer.add(openCloseButton);
  3968. content = new FlowPanel() {
  3969. @Override
  3970. public boolean remove(Widget w) {
  3971. // Check here to catch child.removeFromParent() calls
  3972. boolean removed = super.remove(w);
  3973. if (removed) {
  3974. updateVisibility();
  3975. }
  3976. return removed;
  3977. }
  3978. };
  3979. createOverlay();
  3980. menuBar = new MenuBar(true) {
  3981. @Override
  3982. public MenuItem insertItem(MenuItem item, int beforeIndex)
  3983. throws IndexOutOfBoundsException {
  3984. if (getParent() == null) {
  3985. content.insert(this, 0);
  3986. updateVisibility();
  3987. }
  3988. return super.insertItem(item, beforeIndex);
  3989. }
  3990. @Override
  3991. public void removeItem(MenuItem item) {
  3992. super.removeItem(item);
  3993. if (getItems().isEmpty()) {
  3994. menuBar.removeFromParent();
  3995. }
  3996. }
  3997. @Override
  3998. public void onBrowserEvent(Event event) {
  3999. // selecting a item with enter will lose the focus and
  4000. // selected item, which means that further keyboard
  4001. // selection won't work unless we do this:
  4002. if (event.getTypeInt() == Event.ONKEYDOWN
  4003. && event.getKeyCode() == KeyCodes.KEY_ENTER) {
  4004. final MenuItem item = getSelectedItem();
  4005. super.onBrowserEvent(event);
  4006. Scheduler.get().scheduleDeferred(() -> {
  4007. selectItem(item);
  4008. focus();
  4009. });
  4010. } else {
  4011. super.onBrowserEvent(event);
  4012. }
  4013. }
  4014. };
  4015. KeyDownHandler keyDownHandler = event -> {
  4016. if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
  4017. close();
  4018. }
  4019. };
  4020. openCloseButton.addDomHandler(keyDownHandler,
  4021. KeyDownEvent.getType());
  4022. menuBar.addDomHandler(keyDownHandler, KeyDownEvent.getType());
  4023. }
  4024. /**
  4025. * Creates and initializes the overlay.
  4026. */
  4027. private void createOverlay() {
  4028. overlay = GWT.create(Overlay.class);
  4029. overlay.setOwner(grid);
  4030. overlay.setAutoHideEnabled(true);
  4031. overlay.addStyleDependentName("popup");
  4032. overlay.add(content);
  4033. overlay.addAutoHidePartner(rootContainer.getElement());
  4034. overlay.addCloseHandler(new CloseHandler<PopupPanel>() {
  4035. @Override
  4036. public void onClose(CloseEvent<PopupPanel> event) {
  4037. removeStyleName("open");
  4038. addStyleName("closed");
  4039. }
  4040. });
  4041. overlay.setFitInWindow(true);
  4042. }
  4043. /**
  4044. * Opens the sidebar if not yet opened. Opening the sidebar has no
  4045. * effect if it is empty.
  4046. */
  4047. public void open() {
  4048. if (!isOpen() && isInDOM()) {
  4049. addStyleName("open");
  4050. removeStyleName("closed");
  4051. overlay.showRelativeTo(rootContainer);
  4052. }
  4053. }
  4054. /**
  4055. * Closes the sidebar if not yet closed.
  4056. */
  4057. public void close() {
  4058. overlay.hide();
  4059. }
  4060. /**
  4061. * Returns whether the sidebar is open or not.
  4062. *
  4063. * @return <code>true</code> if open, <code>false</code> if not
  4064. */
  4065. public boolean isOpen() {
  4066. return overlay != null && overlay.isShowing();
  4067. }
  4068. @Override
  4069. public void setStylePrimaryName(String styleName) {
  4070. super.setStylePrimaryName(styleName);
  4071. overlay.setStylePrimaryName(styleName);
  4072. content.setStylePrimaryName(styleName + "-content");
  4073. openCloseButton.setStylePrimaryName(styleName + "-button");
  4074. if (isOpen()) {
  4075. addStyleName("open");
  4076. removeStyleName("closed");
  4077. } else {
  4078. removeStyleName("open");
  4079. addStyleName("closed");
  4080. }
  4081. }
  4082. @Override
  4083. public void addStyleName(String style) {
  4084. super.addStyleName(style);
  4085. overlay.addStyleName(style);
  4086. }
  4087. @Override
  4088. public void removeStyleName(String style) {
  4089. super.removeStyleName(style);
  4090. overlay.removeStyleName(style);
  4091. }
  4092. private void setHeightToHeaderCellHeight() {
  4093. RowContainer header = grid.escalator.getHeader();
  4094. if (!WidgetUtil.isDisplayed(header.getElement())
  4095. || header.getRowCount() == 0
  4096. || !header.getRowElement(0).hasChildNodes()) {
  4097. getLogger().info(
  4098. "No header cell available when calculating sidebar button height");
  4099. // If the Grid is hidden with styles when this is called the
  4100. // border height will be off, but it's usually only a matter of
  4101. // a pixel or so. Removing a style name cannot trigger a full
  4102. // refresh of the layout, it's developer's responsibility to do
  4103. // that where needed.
  4104. double height = header.getDefaultRowHeight()
  4105. - WidgetUtil.measureVerticalBorder(getElement()) / 2;
  4106. openCloseButton.setHeight(height + "px");
  4107. return;
  4108. }
  4109. // Use actual height instead of expected height in case the height
  4110. // is modified by styles.
  4111. Element firstHeaderCell = header.getRowElement(0)
  4112. .getFirstChildElement();
  4113. double height = WidgetUtil
  4114. .getRequiredHeightBoundingClientRectDouble(firstHeaderCell)
  4115. - WidgetUtil.measureVerticalBorder(getElement()) / 2;
  4116. openCloseButton.setHeight(height + "px");
  4117. }
  4118. private void updateVisibility() {
  4119. final boolean hasWidgets = content.getWidgetCount() > 0;
  4120. final boolean isVisible = isInDOM();
  4121. if (isVisible && !hasWidgets) {
  4122. Grid.setParent(this, null);
  4123. getElement().removeFromParent();
  4124. } else if (!isVisible && hasWidgets) {
  4125. close();
  4126. grid.getElement().appendChild(getElement());
  4127. Grid.setParent(this, grid);
  4128. }
  4129. }
  4130. private boolean isInDOM() {
  4131. return getParent() != null;
  4132. }
  4133. @Override
  4134. protected void onAttach() {
  4135. super.onAttach();
  4136. // Make sure the button will get correct height whenever the Sidebar
  4137. // is added to the Grid.
  4138. setHeightToHeaderCellHeight();
  4139. }
  4140. @Override
  4141. public boolean isEnabled() {
  4142. return openCloseButton.isEnabled();
  4143. }
  4144. @Override
  4145. public void setEnabled(boolean enabled) {
  4146. if (!enabled && isOpen()) {
  4147. close();
  4148. }
  4149. openCloseButton.setEnabled(enabled);
  4150. }
  4151. }
  4152. /**
  4153. * UI and functionality related to hiding columns with toggles in the
  4154. * sidebar.
  4155. */
  4156. private final class ColumnHider {
  4157. /** Map from columns to their hiding toggles, component might change */
  4158. private Map<Column<?, T>, MenuItem> columnToHidingToggleMap = new HashMap<>();
  4159. /**
  4160. * When column is being hidden with a toggle, do not refresh toggles for
  4161. * no reason. Also helps for keeping the keyboard navigation working.
  4162. */
  4163. private boolean hidingColumn;
  4164. /**
  4165. * When several columns are set hidable, don't reset the Sidebar for
  4166. * every column separately.
  4167. */
  4168. private boolean toggleUpdateTriggered;
  4169. private void updateColumnHidable(final Column<?, T> column) {
  4170. if (column.isHidable()) {
  4171. MenuItem toggle = columnToHidingToggleMap.get(column);
  4172. if (toggle == null) {
  4173. toggle = createToggle(column);
  4174. }
  4175. toggle.setStyleName("hidden", column.isHidden());
  4176. } else if (columnToHidingToggleMap.containsKey(column)) {
  4177. sidebar.menuBar
  4178. .removeItem(columnToHidingToggleMap.remove(column));
  4179. }
  4180. updateTogglesOrder();
  4181. }
  4182. private MenuItem createToggle(final Column<?, T> column) {
  4183. MenuItem toggle = new MenuItem(createHTML(column), true, () -> {
  4184. hidingColumn = true;
  4185. column.setHidden(!column.isHidden(), true);
  4186. hidingColumn = false;
  4187. });
  4188. toggle.addStyleName("column-hiding-toggle");
  4189. columnToHidingToggleMap.put(column, toggle);
  4190. return toggle;
  4191. }
  4192. private String createHTML(Column<?, T> column) {
  4193. final StringBuilder buf = new StringBuilder();
  4194. buf.append("<span class=\"");
  4195. if (column.isHidden()) {
  4196. buf.append("v-off");
  4197. } else {
  4198. buf.append("v-on");
  4199. }
  4200. buf.append("\"><div>");
  4201. String caption = column.getHidingToggleCaption();
  4202. if (caption == null) {
  4203. caption = column.headerCaption;
  4204. }
  4205. buf.append(caption);
  4206. buf.append("</div></span>");
  4207. return buf.toString();
  4208. }
  4209. private void updateTogglesOrder() {
  4210. if (!hidingColumn && !toggleUpdateTriggered) {
  4211. // This method is called whenever a column is set hidable. If
  4212. // there are multiple hidable columns, it will get called
  4213. // separately for all of them. There is no need to update the
  4214. // order more than once and no other layouting is dependent on
  4215. // the Sidebar layouting getting finished first, so wait until
  4216. // all calls have arrived before proceeding further.
  4217. toggleUpdateTriggered = true;
  4218. Scheduler.get().scheduleFinally(() -> {
  4219. int lastIndex = 0;
  4220. for (Column<?, T> column : getColumns()) {
  4221. if (column.isHidable()) {
  4222. final MenuItem menuItem = columnToHidingToggleMap
  4223. .get(column);
  4224. sidebar.menuBar.removeItem(menuItem);
  4225. sidebar.menuBar.insertItem(menuItem, lastIndex++);
  4226. }
  4227. }
  4228. toggleUpdateTriggered = false;
  4229. });
  4230. }
  4231. }
  4232. private void updateHidingToggle(Column<?, T> column) {
  4233. if (column.isHidable()) {
  4234. MenuItem toggle = columnToHidingToggleMap.get(column);
  4235. toggle.setHTML(createHTML(column));
  4236. toggle.setStyleName("hidden", column.isHidden());
  4237. } // else we can just ignore
  4238. }
  4239. private void removeColumnHidingToggle(Column<?, T> column) {
  4240. sidebar.menuBar.removeItem(columnToHidingToggleMap.get(column));
  4241. }
  4242. }
  4243. /**
  4244. * Escalator used internally by grid to render the rows
  4245. */
  4246. private Escalator escalator = GWT.create(Escalator.class);
  4247. private final Header header = GWT.create(Header.class);
  4248. private final Footer footer = GWT.create(Footer.class);
  4249. private final Sidebar sidebar = new Sidebar(this);
  4250. /**
  4251. * List of columns in the grid. Order defines the visible order.
  4252. */
  4253. private List<Column<?, T>> columns = new ArrayList<>();
  4254. /**
  4255. * The datasource currently in use. <em>Note:</em> it is <code>null</code>
  4256. * on initialization, but not after that.
  4257. */
  4258. private DataSource<T> dataSource;
  4259. private Registration changeHandler;
  4260. private boolean recalculateColumnWidthsNeeded = false;
  4261. /**
  4262. * Currently available row range in DataSource.
  4263. */
  4264. private Range currentDataAvailable = Range.withLength(0, 0);
  4265. /**
  4266. * The number of frozen columns, 0 freezes the selection column if
  4267. * displayed, -1 also prevents selection col from freezing.
  4268. */
  4269. private int frozenColumnCount = 0;
  4270. /**
  4271. * Current sort order. The (private) sort() method reads this list to
  4272. * determine the order in which to present rows.
  4273. */
  4274. private List<SortOrder> sortOrder = new ArrayList<>();
  4275. private Renderer<Boolean> selectColumnRenderer = null;
  4276. private SelectionColumn selectionColumn;
  4277. private String rowStripeStyleName;
  4278. private String rowHasDataStyleName;
  4279. private String rowSelectedStyleName;
  4280. private String cellFocusStyleName;
  4281. private String rowFocusStyleName;
  4282. /**
  4283. * Current selection model.
  4284. */
  4285. private SelectionModel<T> selectionModel;
  4286. /**
  4287. * Focus handler for Grid's cells. Updates focus style names and handles
  4288. * focus scrolling.
  4289. */
  4290. protected final CellFocusHandler cellFocusHandler;
  4291. private final UserSorter sorter = new UserSorter();
  4292. private final Editor<T> editor = GWT.create(Editor.class);
  4293. /**
  4294. * The cell a click event originated from
  4295. * <p>
  4296. * This is a workaround to make Chrome work like Firefox. In Chrome,
  4297. * normally if you start a drag on one cell and release on:
  4298. * <ul>
  4299. * <li>that same cell, the click event is that <code>&lt;td></code>.
  4300. * <li>a cell on that same row, the click event is the parent
  4301. * <code>&lt;tr></code>.
  4302. * <li>a cell on another row, the click event is the table section ancestor
  4303. * ({@code <thead>}, {@code <tbody>} or {@code <tfoot>}).
  4304. * </ul>
  4305. *
  4306. * @see #onBrowserEvent(Event)
  4307. */
  4308. private Cell cellOnPrevMouseDown;
  4309. /**
  4310. * A scheduled command to re-evaluate the widths of <em>all columns</em>
  4311. * that have calculated widths. Most probably called because
  4312. * minwidth/maxwidth/expandratio has changed.
  4313. */
  4314. private final AutoColumnWidthsRecalculator autoColumnWidthsRecalculator = new AutoColumnWidthsRecalculator();
  4315. private boolean enabled = true;
  4316. private DetailsGenerator detailsGenerator = DetailsGenerator.NULL;
  4317. private GridSpacerUpdater gridSpacerUpdater = new GridSpacerUpdater();
  4318. /** A set keeping track of the indices of all currently open details */
  4319. private Set<Integer> visibleDetails = new HashSet<>();
  4320. /** A set of indices of details to reopen after detach and on attach */
  4321. private final Set<Integer> reattachVisibleDetails = new HashSet<>();
  4322. private boolean columnReorderingAllowed;
  4323. private ColumnHider columnHider = new ColumnHider();
  4324. private DragAndDropHandler dndHandler = new DragAndDropHandler();
  4325. private AutoScroller autoScroller = new AutoScroller(this);
  4326. private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED;
  4327. private final List<GridEventHandler<T>> browserEventHandlers = new ArrayList<>();
  4328. private CellStyleGenerator<T> cellStyleGenerator;
  4329. private RowStyleGenerator<T> rowStyleGenerator;
  4330. private RowReference<T> rowReference = new RowReference<>(this);
  4331. private CellReference<T> cellReference = new CellReference<>(rowReference);
  4332. @SuppressWarnings("unchecked")
  4333. private RendererCellReference rendererCellReference = new RendererCellReference(
  4334. (RowReference<Object>) rowReference);
  4335. private boolean refreshBodyRequested = false;
  4336. private double resizeHandleWidth = 0;
  4337. private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() {
  4338. private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() {
  4339. @Override
  4340. public void onAutoScroll(int scrollDiff) {
  4341. autoScrollX = scrollDiff;
  4342. onDragUpdate(null);
  4343. }
  4344. @Override
  4345. public void onAutoScrollReachedMin() {
  4346. // make sure the drop marker is visible on the left
  4347. autoScrollX = 0;
  4348. updateDragDropMarker(clientX);
  4349. }
  4350. @Override
  4351. public void onAutoScrollReachedMax() {
  4352. // make sure the drop marker is visible on the right
  4353. autoScrollX = 0;
  4354. updateDragDropMarker(clientX);
  4355. }
  4356. };
  4357. /**
  4358. * Elements for displaying the dragged column(s) and drop marker
  4359. * properly
  4360. */
  4361. private Element table;
  4362. private Element tableHeader;
  4363. /** Marks the column drop location */
  4364. private Element dropMarker;
  4365. /** A copy of the dragged column(s), moves with cursor. */
  4366. private Element dragElement;
  4367. /** Tracks index of the column whose left side the drop would occur */
  4368. private int latestColumnDropIndex;
  4369. /**
  4370. * Map of possible drop positions for the column and the corresponding
  4371. * column index.
  4372. */
  4373. private final TreeMap<Double, Integer> possibleDropPositions = new TreeMap<>();
  4374. /**
  4375. * Makes sure that drag cancel doesn't cause anything unwanted like sort
  4376. */
  4377. private HandlerRegistration columnSortPreventRegistration;
  4378. private int clientX;
  4379. /** How much the grid is being auto scrolled while dragging. */
  4380. private int autoScrollX;
  4381. /** Captures the value of the focused column before reordering */
  4382. private int focusedColumnIndex;
  4383. /** Offset caused by the drag and drop marker width */
  4384. private double dropMarkerWidthOffset;
  4385. private void initHeaderDragElementDOM() {
  4386. if (table == null) {
  4387. tableHeader = DOM.createTHead();
  4388. dropMarker = DOM.createDiv();
  4389. tableHeader.appendChild(dropMarker);
  4390. table = DOM.createTable();
  4391. table.appendChild(tableHeader);
  4392. table.setClassName("header-drag-table");
  4393. }
  4394. // update the style names on each run in case primary name has been
  4395. // modified
  4396. tableHeader.setClassName(
  4397. escalator.getHeader().getElement().getClassName());
  4398. dropMarker.setClassName(getStylePrimaryName() + "-drop-marker");
  4399. int topOffset = 0;
  4400. for (int i = 0; i < eventCell.getRowIndex(); i++) {
  4401. topOffset += escalator.getHeader().getRowElement(i)
  4402. .getFirstChildElement().getOffsetHeight();
  4403. }
  4404. tableHeader.getStyle().setTop(topOffset, Unit.PX);
  4405. getElement().appendChild(table);
  4406. dropMarkerWidthOffset = WidgetUtil
  4407. .getRequiredWidthBoundingClientRectDouble(dropMarker) / 2;
  4408. }
  4409. @Override
  4410. public void onDragUpdate(Event e) {
  4411. if (e != null) {
  4412. clientX = WidgetUtil.getTouchOrMouseClientX(e);
  4413. autoScrollX = 0;
  4414. }
  4415. resolveDragElementHorizontalPosition(clientX);
  4416. updateDragDropMarker(clientX);
  4417. }
  4418. private void updateDragDropMarker(final int clientX) {
  4419. final double scrollLeft = getScrollLeft();
  4420. final double cursorXCoordinate = clientX
  4421. - escalator.getHeader().getElement().getAbsoluteLeft();
  4422. final Entry<Double, Integer> cellEdgeOnRight = possibleDropPositions
  4423. .ceilingEntry(cursorXCoordinate);
  4424. final Entry<Double, Integer> cellEdgeOnLeft = possibleDropPositions
  4425. .floorEntry(cursorXCoordinate);
  4426. final double diffToRightEdge = cellEdgeOnRight == null
  4427. ? Double.MAX_VALUE
  4428. : cellEdgeOnRight.getKey() - cursorXCoordinate;
  4429. final double diffToLeftEdge = cellEdgeOnLeft == null
  4430. ? Double.MAX_VALUE
  4431. : cursorXCoordinate - cellEdgeOnLeft.getKey();
  4432. double dropMarkerLeft = 0 - scrollLeft;
  4433. if (diffToRightEdge > diffToLeftEdge) {
  4434. latestColumnDropIndex = cellEdgeOnLeft.getValue();
  4435. dropMarkerLeft += cellEdgeOnLeft.getKey();
  4436. } else {
  4437. latestColumnDropIndex = cellEdgeOnRight.getValue();
  4438. dropMarkerLeft += cellEdgeOnRight.getKey();
  4439. }
  4440. dropMarkerLeft += autoScrollX;
  4441. final double frozenColumnsWidth = autoScroller
  4442. .getFrozenColumnsWidth();
  4443. final double rightBoundaryForDrag = getSidebarBoundaryComparedTo(
  4444. dropMarkerLeft);
  4445. final int visibleColumns = getVisibleColumns().size();
  4446. // First check if the drop marker should move left because of the
  4447. // sidebar opening button. this only the case if the grid is
  4448. // scrolled to the right
  4449. if (latestColumnDropIndex == visibleColumns
  4450. && rightBoundaryForDrag < dropMarkerLeft
  4451. && dropMarkerLeft <= escalator.getInnerWidth()) {
  4452. dropMarkerLeft = rightBoundaryForDrag - dropMarkerWidthOffset;
  4453. } else if (
  4454. // Check if the drop marker shouldn't be shown at all
  4455. dropMarkerLeft < frozenColumnsWidth || dropMarkerLeft > Math
  4456. .min(rightBoundaryForDrag, escalator.getInnerWidth())
  4457. || dropMarkerLeft < 0) {
  4458. dropMarkerLeft = -10000000;
  4459. }
  4460. dropMarker.getStyle().setLeft(dropMarkerLeft, Unit.PX);
  4461. }
  4462. private void resolveDragElementHorizontalPosition(final int clientX) {
  4463. double left = clientX - table.getAbsoluteLeft();
  4464. // Do not show the drag element beyond a spanned header cell
  4465. // limitation
  4466. final Double leftBound = possibleDropPositions.firstKey();
  4467. final Double rightBound = possibleDropPositions.lastKey();
  4468. final double scrollLeft = getScrollLeft();
  4469. if (left + scrollLeft < leftBound) {
  4470. left = leftBound - scrollLeft + autoScrollX;
  4471. } else if (left + scrollLeft > rightBound) {
  4472. left = rightBound - scrollLeft + autoScrollX;
  4473. }
  4474. // Do not show the drag element beyond the grid
  4475. final double sidebarBoundary = getSidebarBoundaryComparedTo(left);
  4476. final double gridBoundary = escalator.getInnerWidth();
  4477. final double rightBoundary = Math.min(sidebarBoundary,
  4478. gridBoundary);
  4479. // Do not show on left of the frozen columns (even if scrolled)
  4480. final int frozenColumnsWidth = (int) autoScroller
  4481. .getFrozenColumnsWidth();
  4482. left = Math.max(frozenColumnsWidth, Math.min(left, rightBoundary));
  4483. left -= dragElement.getClientWidth() / 2;
  4484. dragElement.getStyle().setLeft(left, Unit.PX);
  4485. }
  4486. private boolean isSidebarOnDraggedRow() {
  4487. return eventCell.getRowIndex() == 0 && sidebar.isInDOM()
  4488. && !sidebar.isOpen();
  4489. }
  4490. /**
  4491. * Returns the sidebar left coordinate, in relation to the grid. Or
  4492. * Double.MAX_VALUE if it doesn't cause a boundary.
  4493. */
  4494. private double getSidebarBoundaryComparedTo(double left) {
  4495. if (isSidebarOnDraggedRow()) {
  4496. double absoluteLeft = left + getElement().getAbsoluteLeft();
  4497. double sidebarLeft = sidebar.getElement().getAbsoluteLeft();
  4498. double diff = absoluteLeft - sidebarLeft;
  4499. if (diff > 0) {
  4500. return left - diff;
  4501. }
  4502. }
  4503. return Double.MAX_VALUE;
  4504. }
  4505. @Override
  4506. public boolean onDragStart(Event e) {
  4507. calculatePossibleDropPositions();
  4508. if (possibleDropPositions.isEmpty()) {
  4509. return false;
  4510. }
  4511. initHeaderDragElementDOM();
  4512. // needs to clone focus and sorting indicators too (UX)
  4513. dragElement = DOM.clone(eventCell.getElement(), true);
  4514. dragElement.getStyle().clearWidth();
  4515. dropMarker.getStyle().setProperty("height",
  4516. dragElement.getStyle().getHeight());
  4517. tableHeader.appendChild(dragElement);
  4518. // mark the column being dragged for styling
  4519. eventCell.getElement().addClassName("dragged");
  4520. // mark the floating cell, for styling & testing
  4521. dragElement.addClassName("dragged-column-header");
  4522. // start the auto scroll handler
  4523. autoScroller.setScrollArea(60);
  4524. autoScroller.start(e, ScrollAxis.HORIZONTAL, autoScrollerCallback);
  4525. return true;
  4526. }
  4527. @Override
  4528. public void onDragEnd() {
  4529. table.removeFromParent();
  4530. dragElement.removeFromParent();
  4531. eventCell.getElement().removeClassName("dragged");
  4532. }
  4533. @Override
  4534. public void onDrop() {
  4535. final int draggedColumnIndex = eventCell.getColumnIndex();
  4536. final StaticRow<?> draggedCellRow = header
  4537. .getRow(eventCell.getRowIndex());
  4538. int colspan = draggedCellRow
  4539. .getSizeOfCellGroup(getColumn(draggedColumnIndex));
  4540. colspan = colspan == 0 ? 1 : colspan;
  4541. if (latestColumnDropIndex != draggedColumnIndex
  4542. && latestColumnDropIndex != draggedColumnIndex + colspan) {
  4543. List<Column<?, T>> columns = getColumns();
  4544. List<Column<?, T>> reordered = new ArrayList<>();
  4545. if (draggedColumnIndex < latestColumnDropIndex) {
  4546. reordered.addAll(columns.subList(0, draggedColumnIndex));
  4547. reordered.addAll(
  4548. columns.subList(draggedColumnIndex + colspan,
  4549. latestColumnDropIndex));
  4550. reordered.addAll(columns.subList(draggedColumnIndex,
  4551. draggedColumnIndex + colspan));
  4552. reordered.addAll(columns.subList(latestColumnDropIndex,
  4553. columns.size()));
  4554. } else {
  4555. reordered.addAll(columns.subList(0, latestColumnDropIndex));
  4556. reordered.addAll(columns.subList(draggedColumnIndex,
  4557. draggedColumnIndex + colspan));
  4558. reordered.addAll(columns.subList(latestColumnDropIndex,
  4559. draggedColumnIndex));
  4560. reordered.addAll(columns.subList(
  4561. draggedColumnIndex + colspan, columns.size()));
  4562. }
  4563. // since setColumnOrder will add it anyway!
  4564. reordered.remove(selectionColumn);
  4565. // capture focused cell column before reorder
  4566. Cell focusedCell = cellFocusHandler.getFocusedCell();
  4567. if (focusedCell != null) {
  4568. // take hidden columns into account
  4569. focusedColumnIndex = getColumns()
  4570. .indexOf(getVisibleColumn(focusedCell.getColumn()));
  4571. }
  4572. @SuppressWarnings("unchecked")
  4573. Column<?, T>[] array = reordered
  4574. .toArray(new Column[reordered.size()]);
  4575. setColumnOrder(true, array);
  4576. transferCellFocusOnDrop();
  4577. } // else no reordering
  4578. }
  4579. private void transferCellFocusOnDrop() {
  4580. final Cell focusedCell = cellFocusHandler.getFocusedCell();
  4581. if (focusedCell != null && focusedCell.getElement() != null) {
  4582. final int focusedColumnIndexDOM = focusedCell.getColumn();
  4583. final int focusedRowIndex = focusedCell.getRow();
  4584. final int draggedColumnIndex = eventCell.getColumnIndex();
  4585. // transfer focus if it was effected by the new column order
  4586. final RowContainer rowContainer = escalator
  4587. .findRowContainer(focusedCell.getElement());
  4588. if (focusedColumnIndex == draggedColumnIndex) {
  4589. // move with the dragged column
  4590. int adjustedDropIndex = latestColumnDropIndex > draggedColumnIndex
  4591. ? latestColumnDropIndex - 1
  4592. : latestColumnDropIndex;
  4593. // remove hidden columns from indexing
  4594. adjustedDropIndex = getVisibleColumns()
  4595. .indexOf(getColumn(adjustedDropIndex));
  4596. cellFocusHandler.setCellFocus(focusedRowIndex,
  4597. adjustedDropIndex, rowContainer);
  4598. } else if (latestColumnDropIndex <= focusedColumnIndex
  4599. && draggedColumnIndex > focusedColumnIndex) {
  4600. cellFocusHandler.setCellFocus(focusedRowIndex,
  4601. focusedColumnIndexDOM + 1, rowContainer);
  4602. } else if (latestColumnDropIndex > focusedColumnIndex
  4603. && draggedColumnIndex < focusedColumnIndex) {
  4604. cellFocusHandler.setCellFocus(focusedRowIndex,
  4605. focusedColumnIndexDOM - 1, rowContainer);
  4606. }
  4607. }
  4608. }
  4609. @Override
  4610. public void onDragCancel() {
  4611. // cancel next click so that we may prevent column sorting if
  4612. // mouse was released on top of the dragged cell
  4613. if (columnSortPreventRegistration == null) {
  4614. columnSortPreventRegistration = Event
  4615. .addNativePreviewHandler(event -> {
  4616. if (event.getTypeInt() == Event.ONCLICK) {
  4617. event.cancel();
  4618. event.getNativeEvent().preventDefault();
  4619. columnSortPreventRegistration.removeHandler();
  4620. columnSortPreventRegistration = null;
  4621. }
  4622. });
  4623. }
  4624. autoScroller.stop();
  4625. }
  4626. /**
  4627. * Returns the amount of frozen columns. The selection column is always
  4628. * considered frozen, since it can't be moved.
  4629. */
  4630. private int getSelectionAndFrozenColumnCount() {
  4631. // no matter if selection column is frozen or not, it is considered
  4632. // frozen for column dnd reorder
  4633. if (getSelectionModel() instanceof SelectionModelWithSelectionColumn) {
  4634. return Math.max(0, getFrozenColumnCount()) + 1;
  4635. } else {
  4636. return Math.max(0, getFrozenColumnCount());
  4637. }
  4638. }
  4639. private void calculatePossibleDropPositions() {
  4640. possibleDropPositions.clear();
  4641. final int draggedColumnIndex = eventCell.getColumnIndex();
  4642. final StaticRow<?> draggedCellRow = header
  4643. .getRow(eventCell.getRowIndex());
  4644. final int draggedColumnRightIndex = draggedColumnIndex
  4645. + draggedCellRow.getCell(eventCell.getColumn())
  4646. .getColspan();
  4647. final int frozenColumns = getSelectionAndFrozenColumnCount();
  4648. final Range draggedCellRange = Range.between(draggedColumnIndex,
  4649. draggedColumnRightIndex);
  4650. /*
  4651. * If the dragged cell intersects with a spanned cell in any other
  4652. * header or footer row, then the drag is limited inside that
  4653. * spanned cell. The same rules apply: the cell can't be dropped
  4654. * inside another spanned cell. The left and right bounds keep track
  4655. * of the edges of the most limiting spanned cell.
  4656. */
  4657. int leftBound = -1;
  4658. int rightBound = getColumnCount() + 1;
  4659. final HashSet<Integer> unavailableColumnDropIndices = new HashSet<>();
  4660. final List<StaticRow<?>> rows = new ArrayList<>();
  4661. rows.addAll(header.getRows());
  4662. rows.addAll(footer.getRows());
  4663. for (StaticRow<?> row : rows) {
  4664. if (!row.hasSpannedCells()) {
  4665. continue;
  4666. }
  4667. final boolean isDraggedCellRow = row.equals(draggedCellRow);
  4668. for (int cellColumnIndex = frozenColumns; cellColumnIndex < getColumnCount(); cellColumnIndex++) {
  4669. int colspan = row
  4670. .getSizeOfCellGroup(getColumn(cellColumnIndex));
  4671. if (colspan <= 1) {
  4672. continue;
  4673. }
  4674. final int cellColumnRightIndex = cellColumnIndex + colspan;
  4675. final Range cellRange = Range.between(cellColumnIndex,
  4676. cellColumnRightIndex);
  4677. final boolean intersects = draggedCellRange
  4678. .intersects(cellRange);
  4679. if (intersects && !isDraggedCellRow) {
  4680. // if the currently iterated cell is inside or same as
  4681. // the dragged cell, then it doesn't restrict the drag
  4682. if (cellRange.isSubsetOf(draggedCellRange)) {
  4683. cellColumnIndex = cellColumnRightIndex - 1;
  4684. continue;
  4685. }
  4686. /*
  4687. * if the dragged cell is a spanned cell and it crosses
  4688. * with the currently iterated cell without sharing
  4689. * either start or end then not possible to drag the
  4690. * cell.
  4691. */
  4692. if (!draggedCellRange.isSubsetOf(cellRange)) {
  4693. return;
  4694. }
  4695. // the spanned cell overlaps the dragged cell (but is
  4696. // not the dragged cell)
  4697. if (cellColumnIndex <= draggedColumnIndex
  4698. && cellColumnIndex > leftBound) {
  4699. leftBound = cellColumnIndex;
  4700. }
  4701. if (cellColumnRightIndex < rightBound) {
  4702. rightBound = cellColumnRightIndex;
  4703. }
  4704. cellColumnIndex = cellColumnRightIndex - 1;
  4705. } else {
  4706. // can't drop inside a spanned cell, or this is the
  4707. // dragged cell
  4708. while (colspan > 1) {
  4709. cellColumnIndex++;
  4710. colspan--;
  4711. unavailableColumnDropIndices.add(cellColumnIndex);
  4712. }
  4713. }
  4714. }
  4715. }
  4716. if (leftBound == rightBound - 1) {
  4717. return;
  4718. }
  4719. double position = autoScroller.getFrozenColumnsWidth();
  4720. // iterate column indices and add possible drop positions
  4721. for (int i = frozenColumns; i < getColumnCount(); i++) {
  4722. Column<?, T> column = getColumn(i);
  4723. if (!unavailableColumnDropIndices.contains(i)
  4724. && !column.isHidden()) {
  4725. if (leftBound != -1) {
  4726. if (i >= leftBound && i <= rightBound) {
  4727. possibleDropPositions.put(position, i);
  4728. }
  4729. } else {
  4730. possibleDropPositions.put(position, i);
  4731. }
  4732. }
  4733. position += column.getWidthActual();
  4734. }
  4735. if (leftBound == -1) {
  4736. // add the right side of the last column as columns.size()
  4737. possibleDropPositions.put(position, getColumnCount());
  4738. }
  4739. }
  4740. };
  4741. /**
  4742. * Base class for grid columns internally used by the Grid. The user should
  4743. * use {@link Column} when creating new columns.
  4744. *
  4745. * @param <C>
  4746. * the column type
  4747. *
  4748. * @param <T>
  4749. * the row type
  4750. */
  4751. public abstract static class Column<C, T> {
  4752. /**
  4753. * Default renderer for GridColumns. Renders everything into text
  4754. * through {@link Object#toString()}.
  4755. */
  4756. private final class DefaultTextRenderer implements Renderer<Object> {
  4757. boolean warned = false;
  4758. private static final String DEFAULT_RENDERER_WARNING = "This column uses a dummy default TextRenderer. "
  4759. + "A more suitable renderer should be set using the setRenderer() method.";
  4760. @Override
  4761. public void render(RendererCellReference cell, Object data) {
  4762. if (!warned && !(data instanceof String)) {
  4763. getLogger().warning(
  4764. Column.this + ": " + DEFAULT_RENDERER_WARNING);
  4765. warned = true;
  4766. }
  4767. final String text;
  4768. if (data == null) {
  4769. text = "";
  4770. } else {
  4771. text = data.toString();
  4772. }
  4773. cell.getElement().setInnerText(text);
  4774. }
  4775. }
  4776. /**
  4777. * the column is associated with
  4778. */
  4779. private Grid<T> grid;
  4780. /**
  4781. * Width of column in pixels as {@link #setWidth(double)} has been
  4782. * called
  4783. */
  4784. private double widthUser = GridConstants.DEFAULT_COLUMN_WIDTH_PX;
  4785. /**
  4786. * Renderer for rendering a value into the cell
  4787. */
  4788. private Renderer<? super C> bodyRenderer;
  4789. private boolean sortable = false;
  4790. private boolean editable = true;
  4791. private boolean resizable = true;
  4792. private boolean hidden = false;
  4793. private boolean hidable = false;
  4794. private String headerCaption = "";
  4795. private String assistiveCaption = null;
  4796. private String hidingToggleCaption = null;
  4797. private boolean handleWidgetEvents = false;
  4798. private double minimumWidthPx = GridConstants.DEFAULT_MIN_WIDTH;
  4799. private double maximumWidthPx = GridConstants.DEFAULT_MAX_WIDTH;
  4800. private int expandRatio = GridConstants.DEFAULT_EXPAND_RATIO;
  4801. private boolean minimumWidthFromContent = true;
  4802. /**
  4803. * Constructs a new column with a simple TextRenderer.
  4804. */
  4805. public Column() {
  4806. setRenderer(new DefaultTextRenderer());
  4807. }
  4808. /**
  4809. * Constructs a new column with a simple TextRenderer.
  4810. *
  4811. * @param caption
  4812. * The header caption for this column
  4813. *
  4814. * @throws IllegalArgumentException
  4815. * if given header caption is null
  4816. */
  4817. public Column(String caption) throws IllegalArgumentException {
  4818. this();
  4819. setHeaderCaption(caption);
  4820. }
  4821. /**
  4822. * Constructs a new column with a custom renderer.
  4823. *
  4824. * @param renderer
  4825. * The renderer to use for rendering the cells
  4826. *
  4827. * @throws IllegalArgumentException
  4828. * if given Renderer is null
  4829. */
  4830. public Column(Renderer<? super C> renderer)
  4831. throws IllegalArgumentException {
  4832. setRenderer(renderer);
  4833. }
  4834. /**
  4835. * Constructs a new column with a custom renderer.
  4836. *
  4837. * @param renderer
  4838. * The renderer to use for rendering the cells
  4839. * @param caption
  4840. * The header caption for this column
  4841. *
  4842. * @throws IllegalArgumentException
  4843. * if given Renderer or header caption is null
  4844. */
  4845. public Column(String caption, Renderer<? super C> renderer)
  4846. throws IllegalArgumentException {
  4847. this(renderer);
  4848. setHeaderCaption(caption);
  4849. }
  4850. /**
  4851. * Internally used by the grid to set itself
  4852. *
  4853. * @param grid
  4854. */
  4855. private void setGrid(Grid<T> grid) {
  4856. if (this.grid != null && grid != null) {
  4857. // Trying to replace grid
  4858. throw new IllegalStateException("Column already is attached "
  4859. + "to a grid. Remove the column first from the grid "
  4860. + "and then add it. (in: " + toString() + ")");
  4861. }
  4862. if (this.grid != null) {
  4863. this.grid.recalculateColumnWidths();
  4864. }
  4865. this.grid = grid;
  4866. if (this.grid != null) {
  4867. this.grid.recalculateColumnWidths();
  4868. }
  4869. }
  4870. /**
  4871. * Sets a header caption for this column.
  4872. *
  4873. * @param caption
  4874. * The header caption for this column
  4875. * @return the column itself
  4876. *
  4877. */
  4878. public Column<C, T> setHeaderCaption(String caption) {
  4879. if (caption == null) {
  4880. caption = "";
  4881. }
  4882. if (!this.headerCaption.equals(caption)) {
  4883. this.headerCaption = caption;
  4884. if (grid != null) {
  4885. updateHeader();
  4886. }
  4887. }
  4888. return this;
  4889. }
  4890. /**
  4891. * Returns the current header caption for this column.
  4892. *
  4893. * @since 7.6
  4894. * @return the header caption string
  4895. */
  4896. public String getHeaderCaption() {
  4897. return headerCaption;
  4898. }
  4899. /**
  4900. * Sets the header aria-label for this column.
  4901. *
  4902. * @param caption
  4903. * The header aria-label for this column
  4904. * @return the column itself
  4905. *
  4906. * @since 8.2
  4907. */
  4908. public Column<C, T> setAssistiveCaption(String caption) {
  4909. if (!Objects.equals(this.assistiveCaption, caption)) {
  4910. this.assistiveCaption = caption;
  4911. if (grid != null) {
  4912. grid.getHeader().requestSectionRefresh();
  4913. }
  4914. }
  4915. return this;
  4916. }
  4917. /**
  4918. * Returns the current header aria-label for this column.
  4919. *
  4920. * @return the header aria-label string
  4921. *
  4922. * @since 8.2
  4923. */
  4924. public String getAssistiveCaption() {
  4925. return assistiveCaption;
  4926. }
  4927. private void updateHeader() {
  4928. HeaderRow row = grid.getHeader().getDefaultRow();
  4929. if (row != null) {
  4930. setDefaultHeaderContent(row.getCell(this));
  4931. if (isHidable()) {
  4932. grid.columnHider.updateHidingToggle(this);
  4933. }
  4934. }
  4935. }
  4936. /**
  4937. * Returns the data that should be rendered into the cell. By default
  4938. * returning Strings and Widgets are supported. If the return type is a
  4939. * String then it will be treated as preformatted text.
  4940. * <p>
  4941. * To support other types you will need to pass a custom renderer to the
  4942. * column via the column constructor.
  4943. *
  4944. * @param row
  4945. * The row object that provides the cell content.
  4946. *
  4947. * @return The cell content
  4948. */
  4949. public abstract C getValue(T row);
  4950. /**
  4951. * The renderer to render the cell with. By default renders the data as
  4952. * a String or adds the widget into the cell if the column type is of
  4953. * widget type.
  4954. *
  4955. * @return The renderer to render the cell content with
  4956. */
  4957. public Renderer<? super C> getRenderer() {
  4958. return bodyRenderer;
  4959. }
  4960. /**
  4961. * Sets a custom {@link Renderer} for this column.
  4962. *
  4963. * @param renderer
  4964. * The renderer to use for rendering the cells
  4965. * @return the column itself
  4966. *
  4967. * @throws IllegalArgumentException
  4968. * if given Renderer is null
  4969. */
  4970. public Column<C, T> setRenderer(Renderer<? super C> renderer)
  4971. throws IllegalArgumentException {
  4972. if (renderer == null) {
  4973. throw new IllegalArgumentException("Renderer cannot be null.");
  4974. }
  4975. if (renderer != bodyRenderer) {
  4976. // Variables used to restore removed column.
  4977. boolean columnRemoved = false;
  4978. double widthInConfiguration = 0.0d;
  4979. ColumnConfiguration conf = null;
  4980. int index = 0;
  4981. if (!isHidden() && grid != null
  4982. && (bodyRenderer instanceof WidgetRenderer
  4983. || renderer instanceof WidgetRenderer)) {
  4984. // Column needs to be recreated.
  4985. index = grid.getVisibleColumns().indexOf(this);
  4986. conf = grid.escalator.getColumnConfiguration();
  4987. widthInConfiguration = conf.getColumnWidth(index);
  4988. conf.removeColumns(index, 1);
  4989. columnRemoved = true;
  4990. }
  4991. // Complex renderers need to be destroyed.
  4992. if (bodyRenderer instanceof ComplexRenderer) {
  4993. ((ComplexRenderer<? super C>) bodyRenderer).destroy();
  4994. }
  4995. bodyRenderer = renderer;
  4996. if (columnRemoved) {
  4997. // Restore the column.
  4998. conf.insertColumns(index, 1);
  4999. conf.setColumnWidth(index, widthInConfiguration);
  5000. }
  5001. if (!isHidden() && grid != null) {
  5002. grid.requestRefreshBody();
  5003. }
  5004. }
  5005. return this;
  5006. }
  5007. /**
  5008. * Sets the pixel width of the column. Use a negative value for the grid
  5009. * to autosize column based on content and available space.
  5010. * <p>
  5011. * This action is done "finally", once the current execution loop
  5012. * returns. This is done to reduce overhead of unintentionally always
  5013. * recalculate all columns, when modifying several columns at once.
  5014. * <p>
  5015. * If the column is currently {@link #isHidden() hidden}, then this set
  5016. * width has effect only once the column has been made visible again.
  5017. *
  5018. * @param pixels
  5019. * the width in pixels or negative for auto sizing
  5020. * @return this column
  5021. */
  5022. public Column<C, T> setWidth(double pixels) {
  5023. if (!WidgetUtil.pixelValuesEqual(widthUser, pixels)) {
  5024. widthUser = pixels;
  5025. if (!isHidden()) {
  5026. scheduleColumnWidthRecalculator();
  5027. }
  5028. }
  5029. return this;
  5030. }
  5031. void doSetWidth(double pixels) {
  5032. assert !isHidden() : "applying width for a hidden column";
  5033. if (grid != null) {
  5034. int index = grid.getVisibleColumns().indexOf(this);
  5035. ColumnConfiguration conf = grid.escalator
  5036. .getColumnConfiguration();
  5037. conf.setColumnWidth(index, pixels);
  5038. }
  5039. }
  5040. /**
  5041. * Returns the pixel width of the column as given by the user.
  5042. * <p>
  5043. * <em>Note:</em> If a negative value was given to
  5044. * {@link #setWidth(double)}, that same negative value is returned here.
  5045. * <p>
  5046. * <em>Note:</em> Returns the value, even if the column is currently
  5047. * {@link #isHidden() hidden}.
  5048. *
  5049. * @return pixel width of the column, or a negative number if the column
  5050. * width has been automatically calculated.
  5051. * @see #setWidth(double)
  5052. * @see #getWidthActual()
  5053. */
  5054. public double getWidth() {
  5055. return widthUser;
  5056. }
  5057. /**
  5058. * Returns the effective pixel width of the column.
  5059. * <p>
  5060. * This differs from {@link #getWidth()} only when the column has been
  5061. * automatically resized, or when the column is currently
  5062. * {@link #isHidden() hidden}, when the value is 0.
  5063. *
  5064. * @return pixel width of the column.
  5065. */
  5066. public double getWidthActual() {
  5067. if (isHidden()) {
  5068. return 0;
  5069. }
  5070. return grid.escalator.getColumnConfiguration().getColumnWidthActual(
  5071. grid.getVisibleColumns().indexOf(this));
  5072. }
  5073. void reapplyWidth() {
  5074. scheduleColumnWidthRecalculator();
  5075. }
  5076. /**
  5077. * Sets whether the column should be sortable by the user. The grid can
  5078. * be sorted by a sortable column by clicking or tapping the column's
  5079. * default header. Programmatic sorting using the Grid#sort methods is
  5080. * not affected by this setting.
  5081. *
  5082. * @param sortable
  5083. * {@code true} if the user should be able to sort the
  5084. * column, {@code false} otherwise
  5085. * @return the column itself
  5086. */
  5087. public Column<C, T> setSortable(boolean sortable) {
  5088. if (this.sortable != sortable) {
  5089. this.sortable = sortable;
  5090. if (grid != null) {
  5091. grid.getHeader().requestSectionRefresh();
  5092. }
  5093. }
  5094. return this;
  5095. }
  5096. /**
  5097. * Returns whether the user can sort the grid by this column.
  5098. * <p>
  5099. * <em>Note:</em> it is possible to sort by this column programmatically
  5100. * using the Grid#sort methods regardless of the returned value.
  5101. *
  5102. * @return {@code true} if the column is sortable by the user,
  5103. * {@code false} otherwise
  5104. */
  5105. public boolean isSortable() {
  5106. return sortable;
  5107. }
  5108. /**
  5109. * Sets whether this column can be resized by the user.
  5110. *
  5111. * @since 7.6
  5112. *
  5113. * @param resizable
  5114. * {@code true} if this column should be resizable,
  5115. * {@code false} otherwise
  5116. * @return this column
  5117. */
  5118. public Column<C, T> setResizable(boolean resizable) {
  5119. if (this.resizable != resizable) {
  5120. this.resizable = resizable;
  5121. if (grid != null) {
  5122. grid.getHeader().requestSectionRefresh();
  5123. }
  5124. }
  5125. return this;
  5126. }
  5127. /**
  5128. * Returns whether this column can be resized by the user. Default is
  5129. * {@code true}.
  5130. * <p>
  5131. * <em>Note:</em> the column can be programmatically resized using
  5132. * {@link #setWidth(double)} and {@link #setWidthUndefined()} regardless
  5133. * of the returned value.
  5134. *
  5135. * @since 7.6
  5136. *
  5137. * @return {@code true} if this column is resizable, {@code false}
  5138. * otherwise
  5139. */
  5140. public boolean isResizable() {
  5141. return grid.isEnabled() && resizable;
  5142. }
  5143. /**
  5144. * Hides or shows the column. By default columns are visible before
  5145. * explicitly hiding them.
  5146. *
  5147. * @since 7.5.0
  5148. * @param hidden
  5149. * <code>true</code> to hide the column, <code>false</code>
  5150. * to show
  5151. * @return this column
  5152. */
  5153. public Column<C, T> setHidden(boolean hidden) {
  5154. setHidden(hidden, false);
  5155. return this;
  5156. }
  5157. private void setHidden(boolean hidden, boolean userOriginated) {
  5158. if (this.hidden != hidden) {
  5159. if (grid == null) {
  5160. // Not yet attached so just update the flag so that a column
  5161. // can initially be hidden
  5162. this.hidden = hidden;
  5163. return;
  5164. }
  5165. if (hidden) {
  5166. grid.escalator.getColumnConfiguration().removeColumns(
  5167. grid.getVisibleColumns().indexOf(this), 1);
  5168. this.hidden = hidden;
  5169. } else {
  5170. this.hidden = hidden;
  5171. int columnIndex = grid.getVisibleColumns().indexOf(this);
  5172. grid.escalator.getColumnConfiguration()
  5173. .insertColumns(columnIndex, 1);
  5174. // make sure column is set to frozen if it needs to be,
  5175. // escalator doesn't handle situation where the added column
  5176. // would be the last frozen column
  5177. int gridFrozenColumns = grid.getFrozenColumnCount();
  5178. // Correct column index for multiselect mode
  5179. if (grid.getSelectionColumn().isPresent()) {
  5180. gridFrozenColumns++;
  5181. }
  5182. int escalatorFrozenColumns = grid.escalator
  5183. .getColumnConfiguration().getFrozenColumnCount();
  5184. if (gridFrozenColumns > escalatorFrozenColumns
  5185. && escalatorFrozenColumns == columnIndex
  5186. && grid.getColumns()
  5187. .indexOf(this) < gridFrozenColumns) {
  5188. grid.escalator.getColumnConfiguration()
  5189. .setFrozenColumnCount(++escalatorFrozenColumns);
  5190. }
  5191. }
  5192. grid.columnHider.updateHidingToggle(this);
  5193. grid.header.updateColSpans();
  5194. grid.footer.updateColSpans();
  5195. scheduleColumnWidthRecalculator();
  5196. this.grid.fireEvent(new ColumnVisibilityChangeEvent<>(this,
  5197. hidden, userOriginated));
  5198. }
  5199. }
  5200. /**
  5201. * Returns whether this column is hidden. Default is {@code false}.
  5202. *
  5203. * @since 7.5.0
  5204. * @return {@code true} if the column is currently hidden, {@code false}
  5205. * otherwise
  5206. */
  5207. public boolean isHidden() {
  5208. return hidden;
  5209. }
  5210. /**
  5211. * Set whether it is possible for the user to hide this column or not.
  5212. * Default is {@code false}.
  5213. * <p>
  5214. * <em>Note:</em> it is still possible to hide the column
  5215. * programmatically using {@link #setHidden(boolean)}.
  5216. *
  5217. * @since 7.5.0
  5218. * @param hidable
  5219. * {@code true} the user can hide this column, {@code false}
  5220. * otherwise
  5221. * @return this column
  5222. */
  5223. public Column<C, T> setHidable(boolean hidable) {
  5224. if (this.hidable != hidable) {
  5225. this.hidable = hidable;
  5226. grid.columnHider.updateColumnHidable(this);
  5227. }
  5228. return this;
  5229. }
  5230. /**
  5231. * Is it possible for the the user to hide this column. Default is
  5232. * {@code false}.
  5233. * <p>
  5234. * <em>Note:</em> the column can be programmatically hidden using
  5235. * {@link #setHidden(boolean)} regardless of the returned value.
  5236. *
  5237. * @since 7.5.0
  5238. * @return <code>true</code> if the user can hide the column,
  5239. * <code>false</code> if not
  5240. */
  5241. public boolean isHidable() {
  5242. return hidable;
  5243. }
  5244. /**
  5245. * Sets the hiding toggle's caption for this column. Shown in the toggle
  5246. * for this column in the grid's sidebar when the column is
  5247. * {@link #isHidable() hidable}.
  5248. * <p>
  5249. * The default value is <code>null</code>. In this case the header
  5250. * caption is used, see {@link #setHeaderCaption(String)}.
  5251. *
  5252. * @since 7.5.0
  5253. * @param hidingToggleCaption
  5254. * the caption for the hiding toggle for this column
  5255. * @return this column
  5256. */
  5257. public Column<C, T> setHidingToggleCaption(String hidingToggleCaption) {
  5258. this.hidingToggleCaption = hidingToggleCaption;
  5259. if (isHidable()) {
  5260. grid.columnHider.updateHidingToggle(this);
  5261. }
  5262. return this;
  5263. }
  5264. /**
  5265. * Gets the hiding toggle caption for this column.
  5266. *
  5267. * @since 7.5.0
  5268. * @see #setHidingToggleCaption(String)
  5269. * @return the hiding toggle's caption for this column
  5270. */
  5271. public String getHidingToggleCaption() {
  5272. return hidingToggleCaption;
  5273. }
  5274. @Override
  5275. public String toString() {
  5276. String details = "";
  5277. if (headerCaption != null && !headerCaption.isEmpty()) {
  5278. details += "header:\"" + headerCaption + "\" ";
  5279. } else {
  5280. details += "header:empty ";
  5281. }
  5282. if (grid != null) {
  5283. int index = grid.getColumns().indexOf(this);
  5284. if (index != -1) {
  5285. details += "attached:#" + index + " ";
  5286. } else {
  5287. details += "attached:unindexed ";
  5288. }
  5289. } else {
  5290. details += "detached ";
  5291. }
  5292. details += "sortable:" + sortable + " ";
  5293. return getClass().getSimpleName() + "[" + details.trim() + "]";
  5294. }
  5295. /**
  5296. * Sets the minimum width for this column.
  5297. * <p>
  5298. * This defines the minimum guaranteed pixel width of the column
  5299. * <em>when it is set to expand</em>.
  5300. * <p>
  5301. * This action is done "finally", once the current execution loop
  5302. * returns. This is done to reduce overhead of unintentionally always
  5303. * recalculate all columns, when modifying several columns at once.
  5304. *
  5305. * @param pixels
  5306. * the minimum width
  5307. * @return this column
  5308. */
  5309. public Column<C, T> setMinimumWidth(double pixels) {
  5310. final double maxwidth = getMaximumWidth();
  5311. if (pixels >= 0 && pixels > maxwidth && maxwidth >= 0) {
  5312. throw new IllegalArgumentException("New minimum width ("
  5313. + pixels + ") was greater than maximum width ("
  5314. + maxwidth + ")");
  5315. }
  5316. if (minimumWidthPx != pixels) {
  5317. minimumWidthPx = pixels;
  5318. scheduleColumnWidthRecalculator();
  5319. }
  5320. return this;
  5321. }
  5322. /**
  5323. * Sets whether the width of the contents in the column should be
  5324. * considered minimum width for this column.
  5325. * <p>
  5326. * If this is set to <code>true</code> (default for backwards
  5327. * compatibility), then a column will not shrink to smaller than the
  5328. * width required to show the contents available when calculating the
  5329. * widths (first N rows).
  5330. * <p>
  5331. * If this is set to <code>false</code>, then a column will shrink if
  5332. * necessary to the minimum width defined by
  5333. * {@link #setMinimumWidth(double)} <em>when it is set to expand</em>.
  5334. *
  5335. * @param minimumWidthFromContent
  5336. * <code>true</code> to reserve space for all contents,
  5337. * <code>false</code> to allow the column to shrink smaller
  5338. * than the contents
  5339. * @since 8.1
  5340. */
  5341. public void setMinimumWidthFromContent(
  5342. boolean minimumWidthFromContent) {
  5343. this.minimumWidthFromContent = minimumWidthFromContent;
  5344. }
  5345. /**
  5346. * Gets whether the width of the contents in the column should be
  5347. * considered minimum width for this column.
  5348. *
  5349. * @return <code>true</code> to reserve space for all contents,
  5350. * <code>false</code> to allow the column to shrink smaller than
  5351. * the contents
  5352. * @since 8.1
  5353. */
  5354. public boolean isMinimumWidthFromContent() {
  5355. return minimumWidthFromContent;
  5356. }
  5357. /**
  5358. * Sets the maximum width for this column.
  5359. * <p>
  5360. * This defines the maximum allowed pixel width of the column <em>when
  5361. * it is set to expand</em>.
  5362. * <p>
  5363. * This action is done "finally", once the current execution loop
  5364. * returns. This is done to reduce overhead of unintentionally always
  5365. * recalculate all columns, when modifying several columns at once.
  5366. *
  5367. * @param pixels
  5368. * the maximum width
  5369. * @return this column
  5370. */
  5371. public Column<C, T> setMaximumWidth(double pixels) {
  5372. final double minwidth = getMinimumWidth();
  5373. if (pixels >= 0 && pixels < minwidth && minwidth >= 0) {
  5374. throw new IllegalArgumentException("New maximum width ("
  5375. + pixels + ") was less than minimum width (" + minwidth
  5376. + ")");
  5377. }
  5378. if (maximumWidthPx != pixels) {
  5379. maximumWidthPx = pixels;
  5380. scheduleColumnWidthRecalculator();
  5381. }
  5382. return this;
  5383. }
  5384. /**
  5385. * Sets the ratio with which the column expands.
  5386. * <p>
  5387. * By default, all columns expand equally (treated as if all of them had
  5388. * an expand ratio of 1). Once at least one column gets a defined expand
  5389. * ratio, the implicit expand ratio is removed, and only the defined
  5390. * expand ratios are taken into account.
  5391. * <p>
  5392. * If a column has a defined width ({@link #setWidth(double)}), it
  5393. * overrides this method's effects.
  5394. * <p>
  5395. * <em>Example:</em> A grid with three columns, with expand ratios 0, 1
  5396. * and 2, respectively. The column with a <strong>ratio of 0 is exactly
  5397. * as wide as its contents requires</strong>. The column with a ratio of
  5398. * 1 is as wide as it needs, <strong>plus a third of any excess
  5399. * space</strong>, bceause we have 3 parts total, and this column
  5400. * reservs only one of those. The column with a ratio of 2, is as wide
  5401. * as it needs to be, <strong>plus two thirds</strong> of the excess
  5402. * width.
  5403. * <p>
  5404. * This action is done "finally", once the current execution loop
  5405. * returns. This is done to reduce overhead of unintentionally always
  5406. * recalculate all columns, when modifying several columns at once.
  5407. *
  5408. * @param ratio
  5409. * the expand ratio of this column. {@code 0} to not have it
  5410. * expand at all. A negative number to clear the expand
  5411. * value.
  5412. * @return this column
  5413. */
  5414. public Column<C, T> setExpandRatio(int ratio) {
  5415. if (expandRatio != ratio) {
  5416. expandRatio = ratio;
  5417. scheduleColumnWidthRecalculator();
  5418. }
  5419. return this;
  5420. }
  5421. /**
  5422. * Clears the column's expand ratio.
  5423. * <p>
  5424. * Same as calling {@link #setExpandRatio(int) setExpandRatio(-1)}
  5425. *
  5426. * @return this column
  5427. */
  5428. public Column<C, T> clearExpandRatio() {
  5429. return setExpandRatio(-1);
  5430. }
  5431. /**
  5432. * Gets the minimum width for this column.
  5433. *
  5434. * @return the minimum width for this column
  5435. * @see #setMinimumWidth(double)
  5436. */
  5437. public double getMinimumWidth() {
  5438. return minimumWidthPx;
  5439. }
  5440. /**
  5441. * Gets the maximum width for this column.
  5442. *
  5443. * @return the maximum width for this column
  5444. * @see #setMaximumWidth(double)
  5445. */
  5446. public double getMaximumWidth() {
  5447. return maximumWidthPx;
  5448. }
  5449. /**
  5450. * Gets the expand ratio for this column.
  5451. *
  5452. * @return the expand ratio for this column
  5453. * @see #setExpandRatio(int)
  5454. */
  5455. public int getExpandRatio() {
  5456. return expandRatio;
  5457. }
  5458. /**
  5459. * Sets whether the values in this column should be editable by the user
  5460. * when the row editor is active. By default columns are editable.
  5461. *
  5462. * @param editable
  5463. * {@code true} to set this column editable, {@code false}
  5464. * otherwise
  5465. * @return this column
  5466. *
  5467. * @throws IllegalStateException
  5468. * if the editor is currently active
  5469. *
  5470. * @see Grid#editRow(int)
  5471. * @see Grid#isEditorActive()
  5472. */
  5473. public Column<C, T> setEditable(boolean editable) {
  5474. if (editable != this.editable && grid != null
  5475. && grid.isEditorActive()) {
  5476. throw new IllegalStateException(
  5477. "Cannot change column editable status while the editor is active");
  5478. }
  5479. this.editable = editable;
  5480. return this;
  5481. }
  5482. /**
  5483. * Returns whether the values in this column are editable by the user
  5484. * when the row editor is active.
  5485. *
  5486. * @return {@code true} if this column is editable, {@code false}
  5487. * otherwise
  5488. *
  5489. * @see #setEditable(boolean)
  5490. */
  5491. public boolean isEditable() {
  5492. return editable;
  5493. }
  5494. private void scheduleColumnWidthRecalculator() {
  5495. if (grid != null) {
  5496. grid.recalculateColumnWidths();
  5497. } else {
  5498. /*
  5499. * NOOP
  5500. *
  5501. * Since setGrid() will call reapplyWidths as the colum is
  5502. * attached to a grid, it will call setWidth, which, in turn,
  5503. * will call this method again. Therefore, it's guaranteed that
  5504. * the recalculation is scheduled eventually, once the column is
  5505. * attached to a grid.
  5506. */
  5507. }
  5508. }
  5509. /**
  5510. * Resets the default header cell contents to column header captions.
  5511. *
  5512. * @since 7.5.1
  5513. * @param cell
  5514. * default header cell for this column
  5515. */
  5516. protected void setDefaultHeaderContent(HeaderCell cell) {
  5517. cell.setText(headerCaption);
  5518. }
  5519. /**
  5520. * Returns whether Grid should handle events from Widgets in this
  5521. * Column.
  5522. *
  5523. * @return {@code true} to handle events from widgets; {@code false} to
  5524. * not
  5525. * @since 8.3
  5526. */
  5527. public boolean isHandleWidgetEvents() {
  5528. return handleWidgetEvents;
  5529. }
  5530. /**
  5531. * Sets whether Grid should handle events from Widgets in this Column.
  5532. *
  5533. * @param handleWidgetEvents
  5534. * {@code true} to let grid handle events from widgets;
  5535. * {@code false} to not
  5536. *
  5537. * @since 8.3
  5538. */
  5539. public void setHandleWidgetEvents(boolean handleWidgetEvents) {
  5540. this.handleWidgetEvents = handleWidgetEvents;
  5541. }
  5542. }
  5543. /**
  5544. * EscalatorUpdater implementation for Grid's body section.
  5545. *
  5546. * @see EscalatorUpdater
  5547. *
  5548. */
  5549. protected class BodyUpdater implements EscalatorUpdater {
  5550. @Override
  5551. public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
  5552. int rowIndex = row.getRow();
  5553. rowReference.set(rowIndex, getDataSource().getRow(rowIndex),
  5554. row.getElement());
  5555. for (FlyweightCell cell : cellsToAttach) {
  5556. Renderer<?> renderer = findRenderer(cell);
  5557. if (renderer instanceof ComplexRenderer) {
  5558. try {
  5559. Column<?, T> column = getVisibleColumn(
  5560. cell.getColumn());
  5561. rendererCellReference.set(cell,
  5562. getColumns().indexOf(column), column);
  5563. ((ComplexRenderer<?>) renderer)
  5564. .init(rendererCellReference);
  5565. } catch (RuntimeException e) {
  5566. getLogger().log(Level.SEVERE,
  5567. "Error initing cell in column "
  5568. + cell.getColumn(),
  5569. e);
  5570. }
  5571. }
  5572. }
  5573. }
  5574. @Override
  5575. public void postAttach(Row row, Iterable<FlyweightCell> attachedCells) {
  5576. for (FlyweightCell cell : attachedCells) {
  5577. Renderer<?> renderer = findRenderer(cell);
  5578. if (renderer instanceof WidgetRenderer) {
  5579. try {
  5580. WidgetRenderer<?, ?> widgetRenderer = (WidgetRenderer<?, ?>) renderer;
  5581. Widget widget = widgetRenderer.createWidget();
  5582. assert widget != null : "WidgetRenderer.createWidget() returned null. It should return a widget.";
  5583. assert widget
  5584. .getParent() == null : "WidgetRenderer.createWidget() returned a widget which already is attached.";
  5585. assert cell.getElement()
  5586. .getChildCount() == 0 : "Cell content should be empty when adding Widget";
  5587. // Physical attach
  5588. cell.getElement().appendChild(widget.getElement());
  5589. // Logical attach
  5590. setParent(widget, Grid.this);
  5591. } catch (RuntimeException e) {
  5592. getLogger().log(Level.SEVERE,
  5593. "Error attaching child widget in column "
  5594. + cell.getColumn(),
  5595. e);
  5596. }
  5597. }
  5598. }
  5599. }
  5600. @Override
  5601. @SuppressWarnings("unchecked")
  5602. public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
  5603. int rowIndex = row.getRow();
  5604. TableRowElement rowElement = row.getElement();
  5605. T rowData = dataSource.getRow(rowIndex);
  5606. boolean hasData = rowData != null;
  5607. /*
  5608. * TODO could be more efficient to build a list of all styles that
  5609. * should be used and update the element only once instead of
  5610. * attempting to update only the ones that have changed.
  5611. */
  5612. // Assign stylename for rows with data
  5613. boolean usedToHaveData = rowElement
  5614. .hasClassName(rowHasDataStyleName);
  5615. if (usedToHaveData != hasData) {
  5616. setStyleName(rowElement, rowHasDataStyleName, hasData);
  5617. }
  5618. boolean isEvenIndex = row.getRow() % 2 == 0;
  5619. setStyleName(rowElement, rowStripeStyleName, !isEvenIndex);
  5620. rowReference.set(rowIndex, rowData, rowElement);
  5621. boolean isSelected = hasData && isSelected(rowData);
  5622. if (Grid.this.selectionModel.isSelectionAllowed()) {
  5623. rowElement.setAttribute("aria-selected",
  5624. String.valueOf(isSelected));
  5625. } else {
  5626. rowElement.removeAttribute("aria-selected");
  5627. }
  5628. if (hasData) {
  5629. setStyleName(rowElement, rowSelectedStyleName, isSelected);
  5630. if (rowStyleGenerator != null) {
  5631. try {
  5632. String rowStylename = rowStyleGenerator
  5633. .getStyle(rowReference);
  5634. setCustomStyleName(rowElement, rowStylename);
  5635. } catch (RuntimeException e) {
  5636. getLogger().log(Level.SEVERE,
  5637. "Error generating styles for row "
  5638. + row.getRow(),
  5639. e);
  5640. }
  5641. } else {
  5642. // Remove in case there was a generator previously
  5643. setCustomStyleName(rowElement, null);
  5644. }
  5645. } else if (usedToHaveData) {
  5646. setStyleName(rowElement, rowSelectedStyleName, false);
  5647. setCustomStyleName(rowElement, null);
  5648. }
  5649. cellFocusHandler.updateFocusedRowStyle(row);
  5650. for (FlyweightCell cell : cellsToUpdate) {
  5651. Column<?, T> column = getVisibleColumn(cell.getColumn());
  5652. final int columnIndex = getColumns().indexOf(column);
  5653. assert column != null : "Column was not found from cell ("
  5654. + cell.getColumn() + "," + cell.getRow() + ")";
  5655. cellFocusHandler.updateFocusedCellStyle(cell,
  5656. escalator.getBody());
  5657. if (hasData && cellStyleGenerator != null) {
  5658. try {
  5659. cellReference.set(cell.getColumn(), columnIndex,
  5660. column);
  5661. String generatedStyle = cellStyleGenerator
  5662. .getStyle(cellReference);
  5663. setCustomStyleName(cell.getElement(), generatedStyle);
  5664. } catch (RuntimeException e) {
  5665. getLogger().log(Level.SEVERE,
  5666. "Error generating style for cell in column "
  5667. + cell.getColumn(),
  5668. e);
  5669. }
  5670. } else if (hasData || usedToHaveData) {
  5671. setCustomStyleName(cell.getElement(), null);
  5672. }
  5673. @SuppressWarnings("rawtypes")
  5674. Renderer renderer = column.getRenderer();
  5675. try {
  5676. rendererCellReference.set(cell, columnIndex, column);
  5677. if (renderer instanceof ComplexRenderer) {
  5678. // Hide cell content if needed
  5679. @SuppressWarnings("rawtypes")
  5680. ComplexRenderer clxRenderer = (ComplexRenderer<?>) renderer;
  5681. if (hasData) {
  5682. if (!usedToHaveData) {
  5683. // Prepare cell for rendering
  5684. clxRenderer.setContentVisible(
  5685. rendererCellReference, true);
  5686. }
  5687. Object value = column.getValue(rowData);
  5688. clxRenderer.render(rendererCellReference, value);
  5689. } else {
  5690. // Prepare cell for no data
  5691. clxRenderer.setContentVisible(rendererCellReference,
  5692. false);
  5693. }
  5694. } else if (hasData) {
  5695. // Simple renderers just render
  5696. Object value = column.getValue(rowData);
  5697. renderer.render(rendererCellReference, value);
  5698. } else {
  5699. // Clear cell if there is no data
  5700. cell.getElement().removeAllChildren();
  5701. }
  5702. } catch (RuntimeException e) {
  5703. getLogger().log(Level.SEVERE,
  5704. "Error rendering cell in column "
  5705. + cell.getColumn(),
  5706. e);
  5707. }
  5708. }
  5709. }
  5710. @Override
  5711. public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
  5712. for (FlyweightCell cell : cellsToDetach) {
  5713. Renderer<?> renderer = findRenderer(cell);
  5714. if (renderer instanceof WidgetRenderer) {
  5715. try {
  5716. Widget w = WidgetUtil.findWidget(
  5717. cell.getElement().getFirstChildElement());
  5718. if (w != null) {
  5719. // Logical detach
  5720. setParent(w, null);
  5721. // Physical detach
  5722. cell.getElement().removeChild(w.getElement());
  5723. }
  5724. } catch (RuntimeException e) {
  5725. getLogger().log(Level.SEVERE,
  5726. "Error detaching widget in column "
  5727. + cell.getColumn(),
  5728. e);
  5729. }
  5730. }
  5731. }
  5732. }
  5733. @Override
  5734. public void postDetach(Row row, Iterable<FlyweightCell> detachedCells) {
  5735. int rowIndex = row.getRow();
  5736. // Passing null row data since it might not exist in the data source
  5737. // any more
  5738. rowReference.set(rowIndex, null, row.getElement());
  5739. for (FlyweightCell cell : detachedCells) {
  5740. Renderer<?> renderer = findRenderer(cell);
  5741. if (renderer instanceof ComplexRenderer) {
  5742. try {
  5743. Column<?, T> column = getVisibleColumn(
  5744. cell.getColumn());
  5745. rendererCellReference.set(cell,
  5746. getColumns().indexOf(column), column);
  5747. ((ComplexRenderer<?>) renderer)
  5748. .destroy(rendererCellReference);
  5749. } catch (RuntimeException e) {
  5750. getLogger().log(Level.SEVERE,
  5751. "Error destroying cell in column "
  5752. + cell.getColumn(),
  5753. e);
  5754. }
  5755. }
  5756. }
  5757. }
  5758. }
  5759. /**
  5760. * EscalatorUpdater implementation for Grid's static sections (header and
  5761. * footer).
  5762. *
  5763. * @see EscalatorUpdater
  5764. *
  5765. */
  5766. protected class StaticSectionUpdater implements EscalatorUpdater {
  5767. private StaticSection<?> section;
  5768. private RowContainer container;
  5769. /**
  5770. * Constructs an updater instance for the given section.
  5771. *
  5772. * @param section
  5773. * the section that needs an updater
  5774. * @param container
  5775. * the row container of the given section
  5776. */
  5777. public StaticSectionUpdater(StaticSection<?> section,
  5778. RowContainer container) {
  5779. super();
  5780. this.section = section;
  5781. this.container = container;
  5782. }
  5783. @Override
  5784. public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
  5785. StaticSection.StaticRow<?> staticRow = section.getRow(row.getRow());
  5786. final List<Column<?, T>> columns = getVisibleColumns();
  5787. setCustomStyleName(row.getElement(), staticRow.getStyleName());
  5788. for (FlyweightCell cell : cellsToUpdate) {
  5789. final StaticSection.StaticCell metadata = staticRow
  5790. .getCell(columns.get(cell.getColumn()));
  5791. // Decorate default row with sorting indicators
  5792. if (staticRow instanceof HeaderRow) {
  5793. addAriaLabelToHeaderRow(cell);
  5794. addSortingIndicatorsToHeaderRow((HeaderRow) staticRow,
  5795. cell);
  5796. }
  5797. // Assign colspan to cell before rendering
  5798. cell.setColSpan(metadata.getColspan());
  5799. Element td = cell.getElement();
  5800. td.removeAllChildren();
  5801. setCustomStyleName(td, metadata.getStyleName());
  5802. Element content;
  5803. // Wrap text or html content in default header to isolate
  5804. // the content from the possible column resize drag handle
  5805. // next to it
  5806. GridStaticCellType metaDataType = metadata.getType();
  5807. if (metaDataType != GridStaticCellType.WIDGET) {
  5808. content = DOM.createDiv();
  5809. if (staticRow instanceof HeaderRow) {
  5810. content.setClassName(getStylePrimaryName()
  5811. + "-column-header-content");
  5812. if (((HeaderRow) staticRow).isDefault()) {
  5813. content.setClassName(content.getClassName() + " "
  5814. + getStylePrimaryName()
  5815. + "-column-default-header-content");
  5816. }
  5817. } else if (staticRow instanceof FooterRow) {
  5818. content.setClassName(getStylePrimaryName()
  5819. + "-column-footer-content");
  5820. } else {
  5821. getLogger().severe("Unhandled static row type "
  5822. + staticRow.getClass().getCanonicalName());
  5823. }
  5824. td.appendChild(content);
  5825. } else {
  5826. content = td;
  5827. }
  5828. switch (metaDataType) {
  5829. case TEXT:
  5830. content.setInnerText(metadata.getText());
  5831. break;
  5832. case HTML:
  5833. content.setInnerHTML(metadata.getHtml());
  5834. break;
  5835. case WIDGET:
  5836. preDetach(row, Arrays.asList(cell));
  5837. content.setInnerHTML("");
  5838. postAttach(row, Arrays.asList(cell));
  5839. break;
  5840. default:
  5841. getLogger().severe("Unhandled metadata type: "
  5842. + (metaDataType == null ? "null"
  5843. : metaDataType.name()));
  5844. break;
  5845. }
  5846. // XXX: Should add only once in preAttach/postAttach or when
  5847. // resizable status changes
  5848. // Only add resize handles to default header row for now
  5849. if (columns.get(cell.getColumn()).isResizable()
  5850. && staticRow instanceof HeaderRow
  5851. && ((HeaderRow) staticRow).isDefault()) {
  5852. final DivElement resizeElement = Document.get()
  5853. .createDivElement();
  5854. resizeElement.addClassName(getStylePrimaryName()
  5855. + "-column-resize-simple-indicator");
  5856. final int column = cell.getColumn();
  5857. final DragHandle dragger = new DragHandle(
  5858. getStylePrimaryName() + "-column-resize-handle");
  5859. dragger.addTo(td);
  5860. // Save the newest resize handle's width with the assumption
  5861. // that all the resize handles are the same size. This is
  5862. // used in column's minimum width calculations, so the
  5863. // border of the cell is also included.
  5864. resizeHandleWidth = dragger.getElement().getOffsetWidth()
  5865. + WidgetUtil.getBorderLeftAndRightThickness(td);
  5866. final DragHandleCallback simpleResizeMode = createSimpleResizeModeCallback(
  5867. column, dragger, resizeElement);
  5868. final DragHandleCallback animatedResizeMode = createAnimatedResizeModeCallback(
  5869. column);
  5870. // DragHandle gets assigned a 'master callback' that
  5871. // delegates functionality to the correct case-specific
  5872. // implementation
  5873. dragger.setCallback(createResizeModeAwareDragHandleCallback(
  5874. simpleResizeMode, animatedResizeMode));
  5875. }
  5876. cellFocusHandler.updateFocusedCellStyle(cell, container);
  5877. }
  5878. }
  5879. // Common functionality for drag handle callback
  5880. // implementations
  5881. private abstract class AbstractDHCallback
  5882. implements DragHandleCallback {
  5883. protected Column<?, T> col;
  5884. protected double initialWidth = 0;
  5885. protected double minCellWidth;
  5886. protected double width;
  5887. AbstractDHCallback(int column) {
  5888. col = getVisibleColumn(column);
  5889. }
  5890. protected void dragStarted() {
  5891. initialWidth = col.getWidthActual();
  5892. width = initialWidth;
  5893. minCellWidth = escalator
  5894. .getMinCellWidth(getVisibleColumns().indexOf(col));
  5895. for (Column<?, T> c : getVisibleColumns()) {
  5896. if (selectionColumn == c) {
  5897. // Don't modify selection column.
  5898. continue;
  5899. }
  5900. if (c.getWidth() < 0) {
  5901. c.setWidth(c.getWidthActual());
  5902. fireEvent(new ColumnResizeEvent<>(c));
  5903. }
  5904. }
  5905. WidgetUtil.setTextSelectionEnabled(getElement(), false);
  5906. }
  5907. protected void dragEnded() {
  5908. WidgetUtil.setTextSelectionEnabled(getElement(), true);
  5909. }
  5910. }
  5911. private DragHandleCallback createSimpleResizeModeCallback(
  5912. final int column, final DragHandle dragger,
  5913. final DivElement resizeElement) {
  5914. return new AbstractDHCallback(column) {
  5915. @Override
  5916. protected void dragEnded() {
  5917. super.dragEnded();
  5918. dragger.getElement().removeChild(resizeElement);
  5919. }
  5920. @Override
  5921. public void onStart() {
  5922. dragStarted();
  5923. dragger.getElement().appendChild(resizeElement);
  5924. resizeElement.getStyle()
  5925. .setLeft((dragger.getElement().getOffsetWidth()
  5926. - resizeElement.getOffsetWidth()) * .5,
  5927. Unit.PX);
  5928. resizeElement.getStyle()
  5929. .setHeight(col.grid.getOffsetHeight(), Unit.PX);
  5930. }
  5931. @Override
  5932. public void onUpdate(double deltaX, double deltaY) {
  5933. width = Math.max(minCellWidth, initialWidth + deltaX);
  5934. resizeElement.getStyle()
  5935. .setLeft(
  5936. (dragger.getElement().getOffsetWidth()
  5937. - resizeElement.getOffsetWidth())
  5938. * .5 + (width - initialWidth),
  5939. Unit.PX);
  5940. }
  5941. @Override
  5942. public void onCancel() {
  5943. dragEnded();
  5944. }
  5945. @Override
  5946. public void onComplete() {
  5947. dragEnded();
  5948. col.setWidth(width);
  5949. // Need to wait for column width recalculation
  5950. // scheduled by setWidth() before firing the event
  5951. Scheduler.get().scheduleDeferred(
  5952. () -> fireEvent(new ColumnResizeEvent<>(col)));
  5953. }
  5954. };
  5955. }
  5956. private DragHandleCallback createAnimatedResizeModeCallback(
  5957. final int column) {
  5958. return new AbstractDHCallback(column) {
  5959. @Override
  5960. public void onStart() {
  5961. dragStarted();
  5962. }
  5963. @Override
  5964. public void onUpdate(double deltaX, double deltaY) {
  5965. width = Math.max(minCellWidth, initialWidth + deltaX);
  5966. col.setWidth(width);
  5967. }
  5968. @Override
  5969. public void onCancel() {
  5970. dragEnded();
  5971. col.setWidth(initialWidth);
  5972. }
  5973. @Override
  5974. public void onComplete() {
  5975. dragEnded();
  5976. col.setWidth(width);
  5977. fireEvent(new ColumnResizeEvent<>(col));
  5978. }
  5979. };
  5980. }
  5981. private DragHandleCallback createResizeModeAwareDragHandleCallback(
  5982. final DragHandleCallback simpleResizeMode,
  5983. final DragHandleCallback animatedResizeMode) {
  5984. return new DragHandleCallback() {
  5985. private DragHandleCallback currentCallback;
  5986. @Override
  5987. public void onStart() {
  5988. switch (getColumnResizeMode()) {
  5989. case SIMPLE:
  5990. currentCallback = simpleResizeMode;
  5991. break;
  5992. case ANIMATED:
  5993. currentCallback = animatedResizeMode;
  5994. break;
  5995. default:
  5996. throw new UnsupportedOperationException(
  5997. "Support for current column resize mode is not yet implemented");
  5998. }
  5999. currentCallback.onStart();
  6000. }
  6001. @Override
  6002. public void onUpdate(double deltaX, double deltaY) {
  6003. currentCallback.onUpdate(deltaX, deltaY);
  6004. }
  6005. @Override
  6006. public void onCancel() {
  6007. currentCallback.onCancel();
  6008. }
  6009. @Override
  6010. public void onComplete() {
  6011. currentCallback.onComplete();
  6012. }
  6013. };
  6014. }
  6015. private void addAriaLabelToHeaderRow(FlyweightCell cell) {
  6016. Element cellElement = cell.getElement();
  6017. final Column<?, T> column = getVisibleColumn(cell.getColumn());
  6018. if (column.getAssistiveCaption() != null) {
  6019. cellElement.setAttribute("aria-label",
  6020. column.getAssistiveCaption());
  6021. } else {
  6022. cellElement.removeAttribute("aria-label");
  6023. }
  6024. }
  6025. private void addSortingIndicatorsToHeaderRow(HeaderRow headerRow,
  6026. FlyweightCell cell) {
  6027. Element cellElement = cell.getElement();
  6028. boolean sortedBefore = cellElement.hasClassName("sort-asc")
  6029. || cellElement.hasClassName("sort-desc");
  6030. cleanup(cell);
  6031. if (!headerRow.isDefault()) {
  6032. // Nothing more to do if not in the default row
  6033. return;
  6034. }
  6035. final Column<?, T> column = getVisibleColumn(cell.getColumn());
  6036. SortOrder sortingOrder = getSortOrder(column);
  6037. boolean sortable = column.isSortable();
  6038. if (sortable) {
  6039. cellElement.addClassName("sortable");
  6040. cellElement.setAttribute("aria-sort", "none");
  6041. }
  6042. if (!sortable || sortingOrder == null) {
  6043. // Only apply sorting indicators to sortable header columns
  6044. return;
  6045. }
  6046. if (SortDirection.ASCENDING == sortingOrder.getDirection()) {
  6047. cellElement.addClassName("sort-asc");
  6048. cellElement.setAttribute("aria-sort", "ascending");
  6049. } else {
  6050. cellElement.addClassName("sort-desc");
  6051. cellElement.setAttribute("aria-sort", "descending");
  6052. }
  6053. int sortIndex = Grid.this.getSortOrder().indexOf(sortingOrder);
  6054. if (sortIndex > -1 && Grid.this.getSortOrder().size() > 1) {
  6055. // Show sort order indicator if column is
  6056. // sorted and other sorted columns also exists.
  6057. cellElement.setAttribute("sort-order",
  6058. String.valueOf(sortIndex + 1));
  6059. cellElement.setAttribute("aria-sort", "other");
  6060. }
  6061. if (!sortedBefore) {
  6062. verifyColumnWidth(column);
  6063. }
  6064. }
  6065. /**
  6066. * Sort indicator requires a bit more space from the cell than normally.
  6067. * This method check that the now sorted column has enough width.
  6068. *
  6069. * @param column
  6070. * sorted column
  6071. */
  6072. private void verifyColumnWidth(Column<?, T> column) {
  6073. int colIndex = getColumns().indexOf(column);
  6074. double minWidth = escalator.getMinCellWidth(colIndex);
  6075. if (column.getWidthActual() < minWidth) {
  6076. // Fix column size
  6077. escalator.getColumnConfiguration().setColumnWidth(colIndex,
  6078. minWidth);
  6079. fireEvent(new ColumnResizeEvent<>(column));
  6080. }
  6081. }
  6082. /**
  6083. * Finds the sort order for this column
  6084. */
  6085. private SortOrder getSortOrder(Column<?, ?> column) {
  6086. for (SortOrder order : Grid.this.getSortOrder()) {
  6087. if (order.getColumn() == column) {
  6088. return order;
  6089. }
  6090. }
  6091. return null;
  6092. }
  6093. private void cleanup(FlyweightCell cell) {
  6094. Element cellElement = cell.getElement();
  6095. cellElement.removeAttribute("sort-order");
  6096. cellElement.removeAttribute("aria-sort");
  6097. cellElement.removeClassName("sort-desc");
  6098. cellElement.removeClassName("sort-asc");
  6099. cellElement.removeClassName("sortable");
  6100. }
  6101. @Override
  6102. public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
  6103. }
  6104. @Override
  6105. public void postAttach(Row row, Iterable<FlyweightCell> attachedCells) {
  6106. StaticSection.StaticRow<?> gridRow = section.getRow(row.getRow());
  6107. List<Column<?, T>> columns = getVisibleColumns();
  6108. for (FlyweightCell cell : attachedCells) {
  6109. StaticSection.StaticCell metadata = gridRow
  6110. .getCell(columns.get(cell.getColumn()));
  6111. /*
  6112. * If the cell contains widgets that are not currently attached
  6113. * then attach them now.
  6114. */
  6115. if (GridStaticCellType.WIDGET.equals(metadata.getType())) {
  6116. final Widget widget = metadata.getWidget();
  6117. if (widget != null && !widget.isAttached()) {
  6118. getGrid().attachWidget(metadata.getWidget(),
  6119. cell.getElement());
  6120. }
  6121. }
  6122. }
  6123. }
  6124. @Override
  6125. public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
  6126. if (section.getRowCount() > row.getRow()) {
  6127. StaticSection.StaticRow<?> gridRow = section
  6128. .getRow(row.getRow());
  6129. List<Column<?, T>> columns = getVisibleColumns();
  6130. for (FlyweightCell cell : cellsToDetach) {
  6131. StaticSection.StaticCell metadata = gridRow
  6132. .getCell(columns.get(cell.getColumn()));
  6133. if (GridStaticCellType.WIDGET.equals(metadata.getType())
  6134. && metadata.getWidget() != null
  6135. && metadata.getWidget().isAttached()) {
  6136. getGrid().detachWidget(metadata.getWidget());
  6137. }
  6138. }
  6139. }
  6140. }
  6141. /**
  6142. * Returns the Grid instance for this updater.
  6143. *
  6144. * @return the grid that is being updated
  6145. */
  6146. @SuppressWarnings("rawtypes")
  6147. protected Grid getGrid() {
  6148. return section.grid;
  6149. }
  6150. @Override
  6151. public void postDetach(Row row, Iterable<FlyweightCell> detachedCells) {
  6152. }
  6153. };
  6154. /**
  6155. * Creates a new instance.
  6156. */
  6157. public Grid() {
  6158. initWidget(escalator);
  6159. getElement().setTabIndex(0);
  6160. cellFocusHandler = new CellFocusHandler();
  6161. setStylePrimaryName(STYLE_NAME);
  6162. setAriaRole("grid");
  6163. escalator.getHeader().setEscalatorUpdater(createHeaderUpdater());
  6164. escalator.getBody().setEscalatorUpdater(createBodyUpdater());
  6165. escalator.getFooter().setEscalatorUpdater(createFooterUpdater());
  6166. header.setGrid(this);
  6167. HeaderRow defaultRow = header.appendRow();
  6168. header.setDefaultRow(defaultRow);
  6169. footer.setGrid(this);
  6170. editor.setGrid(this);
  6171. setSelectionModel(new SelectionModel.NoSelectionModel<>());
  6172. escalator.getBody().setSpacerUpdater(gridSpacerUpdater);
  6173. escalator.addScrollHandler(event -> fireEvent(new ScrollEvent()));
  6174. escalator.addRowVisibilityChangeHandler(event -> {
  6175. if (dataSource != null && dataSource.size() != 0) {
  6176. dataSource.ensureAvailability(event.getFirstVisibleRow(),
  6177. event.getVisibleRowCount());
  6178. }
  6179. });
  6180. escalator.addVerticalScrollbarVisibilityChangeHandler(event -> {
  6181. if (!(currentDataAvailable.isEmpty()
  6182. && escalator.getBody().getRowCount() > 0)) {
  6183. recalculateColumnWidths();
  6184. } else {
  6185. recalculateColumnWidthsNeeded = true;
  6186. }
  6187. });
  6188. // Default action on SelectionEvents. Refresh the body so changed
  6189. // become visible.
  6190. addSelectionHandler(new SelectionHandler<T>() {
  6191. @Override
  6192. public void onSelect(SelectionEvent<T> event) {
  6193. refreshBody();
  6194. }
  6195. });
  6196. addSpacerIndexChangedHandler(new SpacerIndexChangedHandler() {
  6197. @Override
  6198. public void onSpacerIndexChanged(SpacerIndexChangedEvent event) {
  6199. // remove old index and add new index
  6200. visibleDetails.remove(event.getOldIndex());
  6201. visibleDetails.add(event.getNewIndex());
  6202. }
  6203. });
  6204. // Sink header events and key events
  6205. sinkEvents(getHeader().getConsumedEvents());
  6206. sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP,
  6207. BrowserEvents.KEYPRESS, BrowserEvents.DBLCLICK,
  6208. BrowserEvents.MOUSEDOWN, BrowserEvents.CLICK));
  6209. // Make ENTER and SHIFT+ENTER in the header perform sorting
  6210. addHeaderKeyUpHandler(event -> {
  6211. if (event.getNativeKeyCode() != KeyCodes.KEY_ENTER) {
  6212. return;
  6213. }
  6214. if (getHeader().getRow(event.getFocusedCell().getRowIndex())
  6215. .isDefault()) {
  6216. // Only sort for enter on the default header
  6217. sorter.sort(event.getFocusedCell().getColumn(),
  6218. event.isShiftKeyDown());
  6219. }
  6220. });
  6221. browserEventHandlers.addAll(Arrays.asList(
  6222. // Opening, closing and navigating in the editor
  6223. new EditorEventHandler(),
  6224. // Keyboard and click handlers, Escalator events
  6225. new SuperEventHandler(),
  6226. // Column reordering via header drag&drop
  6227. new HeaderCellDragStartHandler(),
  6228. // Column sorting via header click
  6229. new HeaderDefaultRowEventHandler(),
  6230. // Invoking event-aware renderers
  6231. new RendererEventHandler(),
  6232. // Moving cell focus by keyboard or mouse
  6233. new CellFocusEventHandler()));
  6234. }
  6235. @Override
  6236. public boolean isEnabled() {
  6237. return enabled;
  6238. }
  6239. @Override
  6240. public void setEnabled(boolean enabled) {
  6241. if (enabled == this.enabled) {
  6242. return;
  6243. }
  6244. this.enabled = enabled;
  6245. getElement().setTabIndex(enabled ? 0 : -1);
  6246. // Editor save and cancel buttons need to be disabled.
  6247. boolean editorOpen = editor.getState() != State.INACTIVE;
  6248. if (editorOpen) {
  6249. editor.setGridEnabled(enabled);
  6250. }
  6251. sidebar.setEnabled(enabled);
  6252. getEscalator().setScrollLocked(Direction.VERTICAL,
  6253. !enabled || editorOpen);
  6254. getEscalator().setScrollLocked(Direction.HORIZONTAL, !enabled);
  6255. getHeader().requestSectionRefresh();
  6256. fireEvent(new GridEnabledEvent(enabled));
  6257. }
  6258. /**
  6259. * Sets the column resize mode to use. The default mode is
  6260. * {@link ColumnResizeMode.ANIMATED}.
  6261. *
  6262. * @param mode
  6263. * a ColumnResizeMode value
  6264. *
  6265. * @since 7.7.5
  6266. */
  6267. public void setColumnResizeMode(ColumnResizeMode mode) {
  6268. columnResizeMode = mode;
  6269. }
  6270. /**
  6271. * Returns the current column resize mode. The default mode is
  6272. * {@link ColumnResizeMode.ANIMATED}.
  6273. *
  6274. * @return a ColumnResizeMode value
  6275. * @since 7.7.5
  6276. */
  6277. public ColumnResizeMode getColumnResizeMode() {
  6278. return columnResizeMode;
  6279. }
  6280. @Override
  6281. public void setStylePrimaryName(String style) {
  6282. super.setStylePrimaryName(style);
  6283. escalator.setStylePrimaryName(style);
  6284. editor.setStylePrimaryName(style);
  6285. sidebar.setStylePrimaryName(style + "-sidebar");
  6286. sidebar.addStyleName("v-contextmenu");
  6287. String rowStyle = getStylePrimaryName() + "-row";
  6288. rowHasDataStyleName = rowStyle + "-has-data";
  6289. rowSelectedStyleName = rowStyle + "-selected";
  6290. rowStripeStyleName = rowStyle + "-stripe";
  6291. cellFocusStyleName = getStylePrimaryName() + "-cell-focused";
  6292. rowFocusStyleName = getStylePrimaryName() + "-row-focused";
  6293. if (isAttached()) {
  6294. refreshHeader();
  6295. requestRefreshBody();
  6296. refreshFooter();
  6297. }
  6298. }
  6299. /**
  6300. * Adds the given role as 'role="$param"' to the <code>&lt;table&gt;</code>
  6301. * element of the grid.
  6302. *
  6303. * @param role
  6304. * the role param
  6305. * @since 8.2
  6306. */
  6307. protected void setAriaRole(String role) {
  6308. escalator.getTable().setAttribute("role", role);
  6309. }
  6310. /**
  6311. * Creates the escalator updater used to update the header rows in this
  6312. * grid. The updater is invoked when header rows or columns are added or
  6313. * removed, or the content of existing header cells is changed.
  6314. *
  6315. * @return the new header updater instance
  6316. *
  6317. * @see GridHeader
  6318. * @see Grid#getHeader()
  6319. */
  6320. protected EscalatorUpdater createHeaderUpdater() {
  6321. return new StaticSectionUpdater(header, escalator.getHeader());
  6322. }
  6323. /**
  6324. * Creates the escalator updater used to update the body rows in this grid.
  6325. * The updater is invoked when body rows or columns are added or removed,
  6326. * the content of body cells is changed, or the body is scrolled to expose
  6327. * previously hidden content.
  6328. *
  6329. * @return the new body updater instance
  6330. */
  6331. protected EscalatorUpdater createBodyUpdater() {
  6332. return new BodyUpdater();
  6333. }
  6334. /**
  6335. * Creates the escalator updater used to update the footer rows in this
  6336. * grid. The updater is invoked when header rows or columns are added or
  6337. * removed, or the content of existing header cells is changed.
  6338. *
  6339. * @return the new footer updater instance
  6340. *
  6341. * @see GridFooter
  6342. * @see #getFooter()
  6343. */
  6344. protected EscalatorUpdater createFooterUpdater() {
  6345. return new StaticSectionUpdater(footer, escalator.getFooter());
  6346. }
  6347. /**
  6348. * Refreshes header or footer rows on demand
  6349. *
  6350. * @param rows
  6351. * The row container
  6352. * @param firstRowIsVisible
  6353. * is the first row visible
  6354. * @param isHeader
  6355. * <code>true</code> if we refreshing the header, else assumed
  6356. * the footer
  6357. */
  6358. private void refreshRowContainer(RowContainer rows,
  6359. StaticSection<?> section) {
  6360. // Add or Remove rows on demand
  6361. int rowDiff = section.getVisibleRowCount() - rows.getRowCount();
  6362. if (rowDiff > 0) {
  6363. rows.insertRows(0, rowDiff);
  6364. } else if (rowDiff < 0) {
  6365. rows.removeRows(0, -rowDiff);
  6366. }
  6367. // Refresh all the rows
  6368. if (rows.getRowCount() > 0) {
  6369. rows.refreshRows(0, rows.getRowCount());
  6370. }
  6371. }
  6372. /**
  6373. * Focus a body cell by row and column index.
  6374. *
  6375. * @param rowIndex
  6376. * index of row to focus
  6377. * @param columnIndexDOM
  6378. * index (excluding hidden columns) of cell to focus
  6379. */
  6380. void focusCell(int rowIndex, int columnIndexDOM) {
  6381. final Range rowRange = Range.between(0, dataSource.size());
  6382. final Range columnRange = Range.between(0, getVisibleColumns().size());
  6383. assert rowRange.contains(
  6384. rowIndex) : "Illegal row index. Should be in range " + rowRange;
  6385. assert columnRange.contains(
  6386. columnIndexDOM) : "Illegal column index. Should be in range "
  6387. + columnRange;
  6388. if (rowRange.contains(rowIndex)
  6389. && columnRange.contains(columnIndexDOM)) {
  6390. cellFocusHandler.setCellFocus(rowIndex, columnIndexDOM,
  6391. escalator.getBody());
  6392. WidgetUtil.focus(getElement());
  6393. }
  6394. }
  6395. /**
  6396. * Refreshes all header rows
  6397. */
  6398. void refreshHeader() {
  6399. refreshRowContainer(escalator.getHeader(), header);
  6400. }
  6401. /**
  6402. * Refreshes all body rows
  6403. */
  6404. private void refreshBody() {
  6405. escalator.getBody().refreshRows(0, escalator.getBody().getRowCount());
  6406. }
  6407. /**
  6408. * Request delayed refresh of all body rows.
  6409. *
  6410. * @since 8.1
  6411. */
  6412. public void requestRefreshBody() {
  6413. if (!refreshBodyRequested) {
  6414. refreshBodyRequested = true;
  6415. Scheduler.get().scheduleFinally(() -> {
  6416. refreshBodyRequested = false;
  6417. refreshBody();
  6418. });
  6419. }
  6420. }
  6421. /**
  6422. * Refreshes all footer rows
  6423. */
  6424. void refreshFooter() {
  6425. refreshRowContainer(escalator.getFooter(), footer);
  6426. }
  6427. /**
  6428. * Adds columns as the last columns in the grid.
  6429. *
  6430. * @param columns
  6431. * the columns to add
  6432. */
  6433. @SuppressWarnings("unchecked")
  6434. public void addColumns(Column<?, T>... columns) {
  6435. if (columns.length == 0) {
  6436. // Nothing to add.
  6437. return;
  6438. }
  6439. addColumnsSkipSelectionColumnCheck(Arrays.asList(columns),
  6440. getVisibleColumns().size());
  6441. }
  6442. /**
  6443. * Adds a column as the last column in the grid.
  6444. *
  6445. * @param <C>
  6446. * class that extends Column
  6447. * @param column
  6448. * the column to add
  6449. * @return given column
  6450. */
  6451. public <C extends Column<?, T>> C addColumn(C column) {
  6452. addColumn(column, getColumnCount());
  6453. return column;
  6454. }
  6455. /**
  6456. * Inserts a column into a specific position in the grid.
  6457. *
  6458. * @param <C>
  6459. * class that extends Column
  6460. * @param column
  6461. * the column to add
  6462. * @param index
  6463. * the index where the column should be inserted into
  6464. * @return given column
  6465. *
  6466. * @throws IllegalStateException
  6467. * if Grid's current selection model renders a selection column,
  6468. * and {@code index} is 0.
  6469. */
  6470. public <C extends Column<?, T>> C addColumn(C column, int index) {
  6471. if (column == selectionColumn) {
  6472. throw new IllegalArgumentException(
  6473. "The selection column may not be added manually");
  6474. } else if (selectionColumn != null && index == 0) {
  6475. throw new IllegalStateException("A column cannot be inserted "
  6476. + "before the selection column");
  6477. }
  6478. addColumnsSkipSelectionColumnCheck(Collections.singleton(column),
  6479. index);
  6480. return column;
  6481. }
  6482. private void addColumnsSkipSelectionColumnCheck(
  6483. Collection<Column<?, T>> columnsToAdd, int startIndex) {
  6484. AtomicInteger index = new AtomicInteger(startIndex);
  6485. columnsToAdd.forEach(col -> {
  6486. // Register column with grid
  6487. columns.add(index.getAndIncrement(), col);
  6488. header.addColumn(col);
  6489. footer.addColumn(col);
  6490. // Register this grid instance with the column
  6491. col.setGrid(this);
  6492. });
  6493. escalator.getColumnConfiguration().insertColumns(startIndex,
  6494. (int) columnsToAdd.stream().filter(col -> !col.isHidden())
  6495. .count());
  6496. columnsToAdd.forEach(col -> {
  6497. // Reapply column width
  6498. col.reapplyWidth();
  6499. // Sink all renderer events
  6500. Set<String> events = new HashSet<>();
  6501. events.addAll(getConsumedEventsForRenderer(col.getRenderer()));
  6502. if (col.isHidable()) {
  6503. columnHider.updateColumnHidable(col);
  6504. }
  6505. sinkEvents(events);
  6506. });
  6507. }
  6508. private void sinkEvents(Collection<String> events) {
  6509. assert events != null;
  6510. int eventsToSink = 0;
  6511. for (String typeName : events) {
  6512. int typeInt = Event.getTypeInt(typeName);
  6513. if (typeInt < 0) {
  6514. // Type not recognized by typeInt
  6515. sinkBitlessEvent(typeName);
  6516. } else {
  6517. eventsToSink |= typeInt;
  6518. }
  6519. }
  6520. if (eventsToSink > 0) {
  6521. sinkEvents(eventsToSink);
  6522. }
  6523. }
  6524. private Renderer<?> findRenderer(FlyweightCell cell) {
  6525. Column<?, T> column = getVisibleColumn(cell.getColumn());
  6526. assert column != null : "Could not find column at index:"
  6527. + cell.getColumn();
  6528. return column.getRenderer();
  6529. }
  6530. /**
  6531. * Removes a column from the grid.
  6532. *
  6533. * @param column
  6534. * the column to remove
  6535. */
  6536. public void removeColumn(Column<?, T> column) {
  6537. if (column != null && column.equals(selectionColumn)) {
  6538. throw new IllegalArgumentException(
  6539. "The selection column may not be removed manually.");
  6540. }
  6541. removeColumnSkipSelectionColumnCheck(column);
  6542. }
  6543. private void removeColumnSkipSelectionColumnCheck(Column<?, T> column) {
  6544. int columnIndex = columns.indexOf(column);
  6545. // Remove from column configuration
  6546. int visibleColumnIndex = getVisibleColumns().indexOf(column);
  6547. if (visibleColumnIndex < 0) {
  6548. assert column.isHidden();
  6549. // Hidden columns are not included in Escalator
  6550. } else {
  6551. getEscalator().getColumnConfiguration()
  6552. .removeColumns(visibleColumnIndex, 1);
  6553. }
  6554. header.removeColumn(column);
  6555. footer.removeColumn(column);
  6556. // de-register column with grid
  6557. ((Column<?, T>) column).setGrid(null);
  6558. columns.remove(columnIndex);
  6559. if (column.isHidable()) {
  6560. columnHider.removeColumnHidingToggle(column);
  6561. }
  6562. updateFrozenColumns();
  6563. }
  6564. /**
  6565. * Returns the amount of columns in the grid.
  6566. * <p>
  6567. * <em>NOTE:</em> this includes the hidden columns in the count.
  6568. *
  6569. * @return The number of columns in the grid
  6570. */
  6571. public int getColumnCount() {
  6572. return columns.size();
  6573. }
  6574. /**
  6575. * Returns a list columns in the grid, including hidden columns.
  6576. * <p>
  6577. * For currently visible columns, use {@link #getVisibleColumns()}.
  6578. *
  6579. * @return A unmodifiable list of the columns in the grid
  6580. */
  6581. public List<Column<?, T>> getColumns() {
  6582. return Collections.unmodifiableList(new ArrayList<>(columns));
  6583. }
  6584. /**
  6585. * Returns a list of the currently visible columns in the grid.
  6586. * <p>
  6587. * No {@link Column#isHidden() hidden} columns included.
  6588. *
  6589. * @since 7.5.0
  6590. * @return A unmodifiable list of the currently visible columns in the grid
  6591. */
  6592. public List<Column<?, T>> getVisibleColumns() {
  6593. List<Column<?, T>> visible = new ArrayList<>();
  6594. for (Column<?, T> c : columns) {
  6595. if (!c.isHidden()) {
  6596. visible.add(c);
  6597. }
  6598. }
  6599. return Collections.unmodifiableList(visible);
  6600. }
  6601. /**
  6602. * Returns a column by its index in the grid.
  6603. * <p>
  6604. * <em>NOTE:</em> The indexing includes hidden columns.
  6605. *
  6606. * @param index
  6607. * the index of the column
  6608. * @return The column in the given index
  6609. * @throws IllegalArgumentException
  6610. * if the column index does not exist in the grid
  6611. */
  6612. public Column<?, T> getColumn(int index) throws IllegalArgumentException {
  6613. if (index < 0 || index >= columns.size()) {
  6614. throw new IllegalStateException("Column not found.");
  6615. }
  6616. return columns.get(index);
  6617. }
  6618. private Column<?, T> getVisibleColumn(int index)
  6619. throws IllegalArgumentException {
  6620. List<Column<?, T>> visibleColumns = getVisibleColumns();
  6621. if (index < 0 || index >= visibleColumns.size()) {
  6622. throw new IllegalStateException("Column not found.");
  6623. }
  6624. return visibleColumns.get(index);
  6625. }
  6626. /**
  6627. * Returns the header section of this grid. The default header contains a
  6628. * single row displaying the column captions.
  6629. *
  6630. * @return the header
  6631. */
  6632. protected Header getHeader() {
  6633. return header;
  6634. }
  6635. /**
  6636. * Gets the header row at given index.
  6637. *
  6638. * @param rowIndex
  6639. * 0 based index for row. Counted from top to bottom
  6640. * @return header row at given index
  6641. * @throws IllegalArgumentException
  6642. * if no row exists at given index
  6643. */
  6644. public HeaderRow getHeaderRow(int rowIndex) {
  6645. return header.getRow(rowIndex);
  6646. }
  6647. /**
  6648. * Inserts a new row at the given position to the header section. Shifts the
  6649. * row currently at that position and any subsequent rows down (adds one to
  6650. * their indices).
  6651. *
  6652. * @param index
  6653. * the position at which to insert the row
  6654. * @return the new row
  6655. *
  6656. * @throws IllegalArgumentException
  6657. * if the index is less than 0 or greater than row count
  6658. * @see #appendHeaderRow()
  6659. * @see #prependHeaderRow()
  6660. * @see #removeHeaderRow(HeaderRow)
  6661. * @see #removeHeaderRow(int)
  6662. */
  6663. public HeaderRow addHeaderRowAt(int index) {
  6664. return header.addRowAt(index);
  6665. }
  6666. /**
  6667. * Adds a new row at the bottom of the header section.
  6668. *
  6669. * @return the new row
  6670. * @see #prependHeaderRow()
  6671. * @see #addHeaderRowAt(int)
  6672. * @see #removeHeaderRow(HeaderRow)
  6673. * @see #removeHeaderRow(int)
  6674. */
  6675. public HeaderRow appendHeaderRow() {
  6676. return header.appendRow();
  6677. }
  6678. /**
  6679. * Returns the current default row of the header section. The default row is
  6680. * a special header row providing a user interface for sorting columns.
  6681. * Setting a header caption for column updates cells in the default header.
  6682. *
  6683. * @return the default row or null if no default row set
  6684. */
  6685. public HeaderRow getDefaultHeaderRow() {
  6686. return header.getDefaultRow();
  6687. }
  6688. /**
  6689. * Gets the row count for the header section.
  6690. *
  6691. * @return row count
  6692. */
  6693. public int getHeaderRowCount() {
  6694. return header.getRowCount();
  6695. }
  6696. /**
  6697. * Adds a new row at the top of the header section.
  6698. *
  6699. * @return the new row
  6700. * @see #appendHeaderRow()
  6701. * @see #addHeaderRowAt(int)
  6702. * @see #removeHeaderRow(HeaderRow)
  6703. * @see #removeHeaderRow(int)
  6704. */
  6705. public HeaderRow prependHeaderRow() {
  6706. return header.prependRow();
  6707. }
  6708. /**
  6709. * Removes the given row from the header section.
  6710. *
  6711. * @param row
  6712. * the row to be removed
  6713. *
  6714. * @throws IllegalArgumentException
  6715. * if the row does not exist in this section
  6716. * @see #removeHeaderRow(int)
  6717. * @see #addHeaderRowAt(int)
  6718. * @see #appendHeaderRow()
  6719. * @see #prependHeaderRow()
  6720. */
  6721. public void removeHeaderRow(HeaderRow row) {
  6722. header.removeRow(row);
  6723. }
  6724. /**
  6725. * Removes the row at the given position from the header section.
  6726. *
  6727. * @param rowIndex
  6728. * the position of the row
  6729. *
  6730. * @throws IllegalArgumentException
  6731. * if no row exists at given index
  6732. * @see #removeHeaderRow(HeaderRow)
  6733. * @see #addHeaderRowAt(int)
  6734. * @see #appendHeaderRow()
  6735. * @see #prependHeaderRow()
  6736. */
  6737. public void removeHeaderRow(int rowIndex) {
  6738. header.removeRow(rowIndex);
  6739. }
  6740. /**
  6741. * Sets the default row of the header. The default row is a special header
  6742. * row providing a user interface for sorting columns.
  6743. * <p>
  6744. * Note: Setting the default header row will reset all cell contents to
  6745. * Column defaults.
  6746. *
  6747. * @param row
  6748. * the new default row, or null for no default row
  6749. *
  6750. * @throws IllegalArgumentException
  6751. * header does not contain the row
  6752. */
  6753. public void setDefaultHeaderRow(HeaderRow row) {
  6754. header.setDefaultRow(row);
  6755. }
  6756. /**
  6757. * Sets the visibility of the header section.
  6758. *
  6759. * @param visible
  6760. * true to show header section, false to hide
  6761. */
  6762. public void setHeaderVisible(boolean visible) {
  6763. header.setVisible(visible);
  6764. }
  6765. /**
  6766. * Returns the visibility of the header section.
  6767. *
  6768. * @return true if visible, false otherwise.
  6769. */
  6770. public boolean isHeaderVisible() {
  6771. return header.isVisible();
  6772. }
  6773. /* Grid Footers */
  6774. /**
  6775. * Returns the footer section of this grid. The default footer is empty.
  6776. *
  6777. * @return the footer
  6778. */
  6779. protected Footer getFooter() {
  6780. return footer;
  6781. }
  6782. /**
  6783. * Gets the footer row at given index.
  6784. *
  6785. * @param rowIndex
  6786. * 0 based index for row. Counted from top to bottom
  6787. * @return footer row at given index
  6788. * @throws IllegalArgumentException
  6789. * if no row exists at given index
  6790. */
  6791. public FooterRow getFooterRow(int rowIndex) {
  6792. return footer.getRow(rowIndex);
  6793. }
  6794. /**
  6795. * Inserts a new row at the given position to the footer section. Shifts the
  6796. * row currently at that position and any subsequent rows down (adds one to
  6797. * their indices).
  6798. *
  6799. * @param index
  6800. * the position at which to insert the row
  6801. * @return the new row
  6802. *
  6803. * @throws IllegalArgumentException
  6804. * if the index is less than 0 or greater than row count
  6805. * @see #appendFooterRow()
  6806. * @see #prependFooterRow()
  6807. * @see #removeFooterRow(FooterRow)
  6808. * @see #removeFooterRow(int)
  6809. */
  6810. public FooterRow addFooterRowAt(int index) {
  6811. return footer.addRowAt(index);
  6812. }
  6813. /**
  6814. * Adds a new row at the bottom of the footer section.
  6815. *
  6816. * @return the new row
  6817. * @see #prependFooterRow()
  6818. * @see #addFooterRowAt(int)
  6819. * @see #removeFooterRow(FooterRow)
  6820. * @see #removeFooterRow(int)
  6821. */
  6822. public FooterRow appendFooterRow() {
  6823. return footer.appendRow();
  6824. }
  6825. /**
  6826. * Gets the row count for the footer.
  6827. *
  6828. * @return row count
  6829. */
  6830. public int getFooterRowCount() {
  6831. return footer.getRowCount();
  6832. }
  6833. /**
  6834. * Adds a new row at the top of the footer section.
  6835. *
  6836. * @return the new row
  6837. * @see #appendFooterRow()
  6838. * @see #addFooterRowAt(int)
  6839. * @see #removeFooterRow(FooterRow)
  6840. * @see #removeFooterRow(int)
  6841. */
  6842. public FooterRow prependFooterRow() {
  6843. return footer.prependRow();
  6844. }
  6845. /**
  6846. * Removes the given row from the footer section.
  6847. *
  6848. * @param row
  6849. * the row to be removed
  6850. *
  6851. * @throws IllegalArgumentException
  6852. * if the row does not exist in this section
  6853. * @see #removeFooterRow(int)
  6854. * @see #addFooterRowAt(int)
  6855. * @see #appendFooterRow()
  6856. * @see #prependFooterRow()
  6857. */
  6858. public void removeFooterRow(FooterRow row) {
  6859. footer.removeRow(row);
  6860. }
  6861. /**
  6862. * Removes the row at the given position from the footer section.
  6863. *
  6864. * @param rowIndex
  6865. * the position of the row
  6866. *
  6867. * @throws IllegalArgumentException
  6868. * if no row exists at given index
  6869. * @see #removeFooterRow(FooterRow)
  6870. * @see #addFooterRowAt(int)
  6871. * @see #appendFooterRow()
  6872. * @see #prependFooterRow()
  6873. */
  6874. public void removeFooterRow(int rowIndex) {
  6875. footer.removeRow(rowIndex);
  6876. }
  6877. /**
  6878. * Sets the visibility of the footer section.
  6879. *
  6880. * @param visible
  6881. * true to show footer section, false to hide
  6882. */
  6883. public void setFooterVisible(boolean visible) {
  6884. footer.setVisible(visible);
  6885. }
  6886. /**
  6887. * Returns the visibility of the footer section.
  6888. *
  6889. * @return true if visible, false otherwise.
  6890. */
  6891. public boolean isFooterVisible() {
  6892. return footer.isVisible();
  6893. }
  6894. /**
  6895. * Returns the {@link Editor} for this Grid.
  6896. *
  6897. * @return editor
  6898. */
  6899. public Editor<T> getEditor() {
  6900. return editor;
  6901. }
  6902. /**
  6903. * Gets the {@link Escalator} used by this Grid instance.
  6904. *
  6905. * @return the escalator instance, never <code>null</code>
  6906. */
  6907. public Escalator getEscalator() {
  6908. return escalator;
  6909. }
  6910. /**
  6911. * {@inheritDoc}
  6912. * <p>
  6913. * <em>Note:</em> This method will change the widget's size in the browser
  6914. * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}.
  6915. *
  6916. * @see #setHeightMode(HeightMode)
  6917. */
  6918. @Override
  6919. public void setHeight(String height) {
  6920. escalator.setHeight(height);
  6921. }
  6922. @Override
  6923. public void setWidth(String width) {
  6924. escalator.setWidth(width);
  6925. }
  6926. /**
  6927. * Sets the data source used by this grid.
  6928. *
  6929. * @param dataSource
  6930. * the data source to use, not null
  6931. * @throws IllegalArgumentException
  6932. * if <code>dataSource</code> is <code>null</code>
  6933. */
  6934. public void setDataSource(final DataSource<T> dataSource)
  6935. throws IllegalArgumentException {
  6936. if (dataSource == null) {
  6937. throw new IllegalArgumentException("dataSource can't be null.");
  6938. }
  6939. if (changeHandler != null) {
  6940. changeHandler.remove();
  6941. changeHandler = null;
  6942. }
  6943. this.dataSource = dataSource;
  6944. changeHandler = dataSource
  6945. .addDataChangeHandler(new DataChangeHandler() {
  6946. @Override
  6947. public void dataUpdated(int firstIndex, int numberOfItems) {
  6948. escalator.getBody().refreshRows(firstIndex,
  6949. numberOfItems);
  6950. }
  6951. @Override
  6952. public void dataRemoved(int firstIndex, int numberOfItems) {
  6953. for (int i = 0; i < numberOfItems; ++i) {
  6954. visibleDetails.remove(firstIndex + i);
  6955. }
  6956. escalator.getBody().removeRows(firstIndex,
  6957. numberOfItems);
  6958. Range removed = Range.withLength(firstIndex,
  6959. numberOfItems);
  6960. cellFocusHandler.rowsRemovedFromBody(removed);
  6961. }
  6962. @Override
  6963. public void dataAdded(int firstIndex, int numberOfItems) {
  6964. escalator.getBody().insertRows(firstIndex,
  6965. numberOfItems);
  6966. Range added = Range.withLength(firstIndex,
  6967. numberOfItems);
  6968. cellFocusHandler.rowsAddedToBody(added);
  6969. }
  6970. @Override
  6971. public void dataAvailable(int firstIndex,
  6972. int numberOfItems) {
  6973. currentDataAvailable = Range.withLength(firstIndex,
  6974. numberOfItems);
  6975. if (recalculateColumnWidthsNeeded) {
  6976. // Ensure that cache has actually been populated or
  6977. // all rows removed, otherwise wait for next call.
  6978. if (numberOfItems > 0
  6979. || getDataSource().size() == 0) {
  6980. recalculateColumnWidths();
  6981. recalculateColumnWidthsNeeded = false;
  6982. }
  6983. }
  6984. fireEvent(new DataAvailableEvent(currentDataAvailable));
  6985. }
  6986. @Override
  6987. public void resetDataAndSize(int newSize) {
  6988. // It might take a while for new data to arrive,
  6989. // clear the record of cached rows.
  6990. currentDataAvailable = Range.emptyRange();
  6991. RowContainer body = escalator.getBody();
  6992. int oldSize = body.getRowCount();
  6993. if (newSize > oldSize) {
  6994. if (oldSize == 0 && !isHeaderVisible()) {
  6995. // Fixes framework/issues/11607
  6996. // Need to recalculate column widths when the
  6997. // first row is added to a non-header grid,
  6998. // otherwise the checkbox will be aligned in a
  6999. // wrong place. Wait until the cache has been
  7000. // populated before making the call.
  7001. recalculateColumnWidthsNeeded = true;
  7002. }
  7003. body.insertRows(oldSize, newSize - oldSize);
  7004. cellFocusHandler.rowsAddedToBody(Range
  7005. .withLength(oldSize, newSize - oldSize));
  7006. } else if (newSize < oldSize) {
  7007. body.removeRows(newSize, oldSize - newSize);
  7008. cellFocusHandler.rowsRemovedFromBody(Range
  7009. .withLength(newSize, oldSize - newSize));
  7010. }
  7011. if (newSize > 0) {
  7012. Range visibleRowRange = escalator
  7013. .getVisibleRowRange();
  7014. dataSource.ensureAvailability(
  7015. visibleRowRange.getStart(),
  7016. visibleRowRange.length());
  7017. } else {
  7018. // We won't expect any data more data updates, so
  7019. // just make the bookkeeping happy.
  7020. dataAvailable(0, 0);
  7021. }
  7022. assert body.getRowCount() == newSize;
  7023. }
  7024. });
  7025. int previousRowCount = escalator.getBody().getRowCount();
  7026. if (previousRowCount != 0) {
  7027. escalator.getBody().removeRows(0, previousRowCount);
  7028. }
  7029. setEscalatorSizeFromDataSource();
  7030. }
  7031. private void setEscalatorSizeFromDataSource() {
  7032. assert escalator.getBody().getRowCount() == 0;
  7033. int size = dataSource.size();
  7034. if (size > 0) {
  7035. escalator.getBody().insertRows(0, size);
  7036. }
  7037. }
  7038. /**
  7039. * Gets the {@Link DataSource} for this Grid.
  7040. *
  7041. * @return the data source used by this grid
  7042. */
  7043. public DataSource<T> getDataSource() {
  7044. return dataSource;
  7045. }
  7046. /**
  7047. * Sets the number of frozen columns in this grid. Setting the count to 0
  7048. * means that no data columns will be frozen, but the built-in selection
  7049. * checkbox column will still be frozen if it's in use. Setting the count to
  7050. * -1 will also disable the selection column.
  7051. * <p>
  7052. * The default value is 0.
  7053. *
  7054. * @param numberOfColumns
  7055. * the number of columns that should be frozen
  7056. *
  7057. * @throws IllegalArgumentException
  7058. * if the column count is < -1 or > the number of visible
  7059. * columns
  7060. */
  7061. public void setFrozenColumnCount(int numberOfColumns) {
  7062. if (numberOfColumns < -1 || numberOfColumns > getColumnCount()) {
  7063. throw new IllegalArgumentException(
  7064. "count must be between -1 and the current number of columns ("
  7065. + getColumnCount() + ")");
  7066. }
  7067. frozenColumnCount = numberOfColumns;
  7068. updateFrozenColumns();
  7069. }
  7070. private void updateFrozenColumns() {
  7071. int visibleFrozenColumnCount = getVisibleFrozenColumnCount();
  7072. ColumnConfiguration columnConfiguration = escalator
  7073. .getColumnConfiguration();
  7074. if (columnConfiguration.getColumnCount() < visibleFrozenColumnCount) {
  7075. // new columns may not have got added yet, delay and check the
  7076. // correct count again
  7077. Scheduler.get().scheduleFinally(() -> columnConfiguration
  7078. .setFrozenColumnCount(getVisibleFrozenColumnCount()));
  7079. } else {
  7080. columnConfiguration.setFrozenColumnCount(visibleFrozenColumnCount);
  7081. }
  7082. }
  7083. private int getVisibleFrozenColumnCount() {
  7084. int numberOfColumns = getFrozenColumnCount();
  7085. // for the escalator the hidden columns are not in the frozen column
  7086. // count, but for grid they are. thus need to convert the index
  7087. int limit = getFrozenColumnCount();
  7088. if (getSelectionColumn().isPresent()) {
  7089. // If the grid is in MultiSelect mode, getColumn(0) in the following
  7090. // for loop returns the selection column. Accordingly, verifying
  7091. // which frozen columns are visible if the selection column is
  7092. // present should take this fact into account.
  7093. limit++;
  7094. }
  7095. for (int i = 0; i < limit; i++) {
  7096. if (i >= getColumnCount() || getColumn(i).isHidden()) {
  7097. numberOfColumns--;
  7098. }
  7099. }
  7100. if (numberOfColumns == -1) {
  7101. numberOfColumns = 0;
  7102. } else if (selectionColumn != null) {
  7103. numberOfColumns++;
  7104. }
  7105. return numberOfColumns;
  7106. }
  7107. /**
  7108. * Gets the number of frozen columns in this grid. 0 means that no data
  7109. * columns will be frozen, but the built-in selection checkbox column will
  7110. * still be frozen if it's in use. -1 means that not even the selection
  7111. * column is frozen.
  7112. * <p>
  7113. * <em>NOTE:</em> This includes {@link Column#isHidden() hidden columns} in
  7114. * the count.
  7115. *
  7116. * @return the number of frozen columns
  7117. */
  7118. public int getFrozenColumnCount() {
  7119. return frozenColumnCount;
  7120. }
  7121. /**
  7122. * Adds an event handler that gets notified when the range of visible rows
  7123. * changes e.g. because of scrolling, row resizing or spacers
  7124. * appearing/disappearing.
  7125. *
  7126. * @param handler
  7127. * the event handler
  7128. * @return a handler registration for the added handler
  7129. */
  7130. public HandlerRegistration addRowVisibilityChangeHandler(
  7131. RowVisibilityChangeHandler handler) {
  7132. /*
  7133. * Reusing Escalator's RowVisibilityChangeHandler, since a scroll
  7134. * concept is too abstract. e.g. the event needs to be re-sent when the
  7135. * widget is resized.
  7136. */
  7137. return escalator.addRowVisibilityChangeHandler(handler);
  7138. }
  7139. /**
  7140. * Scrolls to a certain row, using {@link ScrollDestination#ANY}.
  7141. * <p>
  7142. * If the details for that row are visible, those will be taken into account
  7143. * as well.
  7144. *
  7145. * @param rowIndex
  7146. * zero-based index of the row to scroll to.
  7147. * @throws IllegalArgumentException
  7148. * if rowIndex is below zero, or above the maximum value
  7149. * supported by the data source.
  7150. */
  7151. public void scrollToRow(int rowIndex) throws IllegalArgumentException {
  7152. scrollToRow(rowIndex, ScrollDestination.ANY,
  7153. GridConstants.DEFAULT_PADDING);
  7154. }
  7155. /**
  7156. * Scrolls to a certain row, using user-specified scroll destination.
  7157. * <p>
  7158. * If the details for that row are visible, those will be taken into account
  7159. * as well.
  7160. *
  7161. * @param rowIndex
  7162. * zero-based index of the row to scroll to.
  7163. * @param destination
  7164. * desired destination placement of scrolled-to-row. See
  7165. * {@link ScrollDestination} for more information.
  7166. * @throws IllegalArgumentException
  7167. * if rowIndex is below zero, or above the maximum value
  7168. * supported by the data source.
  7169. */
  7170. public void scrollToRow(int rowIndex, ScrollDestination destination)
  7171. throws IllegalArgumentException {
  7172. scrollToRow(rowIndex, destination,
  7173. destination == ScrollDestination.MIDDLE ? 0
  7174. : GridConstants.DEFAULT_PADDING);
  7175. }
  7176. /**
  7177. * Helper method for making sure desired row is visible and it is properly
  7178. * rendered.
  7179. *
  7180. * @param rowIndex
  7181. * the row to look for
  7182. * @param destination
  7183. * the desired scroll destination
  7184. * @param callback
  7185. * the callback command to execute when row is available
  7186. * @since 8.4
  7187. */
  7188. public void scrollToRow(int rowIndex, ScrollDestination destination,
  7189. Runnable callback) {
  7190. waitUntilVisible(rowIndex, destination, callback);
  7191. }
  7192. /**
  7193. * Helper method for making sure desired row is visible and it is properly
  7194. * rendered.
  7195. *
  7196. * @param rowIndex
  7197. * the row to look for
  7198. * @param whenRendered
  7199. * the callback command to execute when row is available
  7200. * @since 8.4
  7201. */
  7202. public void scrollToRow(int rowIndex, Runnable whenRendered) {
  7203. scrollToRow(rowIndex, ScrollDestination.ANY, whenRendered);
  7204. }
  7205. /**
  7206. * Scrolls to a certain row using only user-specified parameters.
  7207. * <p>
  7208. * If the details for that row are visible, those will be taken into account
  7209. * as well.
  7210. *
  7211. * @param rowIndex
  7212. * zero-based index of the row to scroll to.
  7213. * @param destination
  7214. * desired destination placement of scrolled-to-row. See
  7215. * {@link ScrollDestination} for more information.
  7216. * @param paddingPx
  7217. * number of pixels to overscroll. Behavior depends on
  7218. * destination.
  7219. * @throws IllegalArgumentException
  7220. * if {@code destination} is {@link ScrollDestination#MIDDLE}
  7221. * and padding is nonzero, because having a padding on a
  7222. * centered row is undefined behavior, or if rowIndex is below
  7223. * zero or above the row count of the data source.
  7224. */
  7225. private void scrollToRow(int rowIndex, ScrollDestination destination,
  7226. int paddingPx) throws IllegalArgumentException {
  7227. int maxsize = escalator.getBody().getRowCount() - 1;
  7228. if (rowIndex < 0) {
  7229. throw new IllegalArgumentException(
  7230. "Row index (" + rowIndex + ") is below zero!");
  7231. }
  7232. if (rowIndex > maxsize) {
  7233. throw new IllegalArgumentException("Row index (" + rowIndex
  7234. + ") is above maximum (" + maxsize + ")!");
  7235. }
  7236. escalator.scrollToRowAndSpacer(rowIndex, destination, paddingPx);
  7237. }
  7238. /**
  7239. * Helper method for scrolling and making sure row is visible.
  7240. *
  7241. * @param rowIndex
  7242. * the row index to make visible
  7243. * @param destination
  7244. * the desired scroll destination
  7245. * @param whenVisible
  7246. * the callback method to call when row is visible
  7247. */
  7248. private void waitUntilVisible(int rowIndex, ScrollDestination destination,
  7249. Runnable whenVisible) {
  7250. boolean waitForCache = false;
  7251. if (getDataSource().getRow(rowIndex) == null) {
  7252. // not yet in cache, wait for this to change
  7253. waitForCache = true;
  7254. Reference<Registration> registration = new Reference<>();
  7255. registration.set(getDataSource()
  7256. .addDataChangeHandler(new DataChangeHandler() {
  7257. @Override
  7258. public void resetDataAndSize(int estimatedNewDataSize) {
  7259. // data set changed, cancel the operation
  7260. registration.get().remove();
  7261. }
  7262. @Override
  7263. public void dataUpdated(int firstRowIndex,
  7264. int numberOfRows) {
  7265. // NOP
  7266. }
  7267. @Override
  7268. public void dataRemoved(int firstRowIndex,
  7269. int numberOfRows) {
  7270. // data set changed, cancel the operation
  7271. registration.get().remove();
  7272. }
  7273. @Override
  7274. public void dataAvailable(int firstRowIndex,
  7275. int numberOfRows) {
  7276. // if new available range contains the row,
  7277. // try again
  7278. if (Range.withLength(firstRowIndex, numberOfRows)
  7279. .contains(rowIndex)) {
  7280. registration.get().remove();
  7281. waitUntilVisible(rowIndex, destination,
  7282. whenVisible);
  7283. }
  7284. }
  7285. @Override
  7286. public void dataAdded(int firstRowIndex,
  7287. int numberOfRows) {
  7288. // data set changed, cancel the operation
  7289. registration.get().remove();
  7290. }
  7291. }));
  7292. }
  7293. scrollToRow(rowIndex, destination);
  7294. if (!waitForCache) {
  7295. // all necessary adjustments done, time to perform
  7296. whenVisible.run();
  7297. }
  7298. }
  7299. /**
  7300. * Scrolls to the beginning of the very first row.
  7301. */
  7302. public void scrollToStart() {
  7303. if (getEscalator().getBody().getRowCount() > 0) {
  7304. scrollToRow(0, ScrollDestination.START);
  7305. }
  7306. }
  7307. /**
  7308. * Scrolls to the end of the very last row.
  7309. */
  7310. public void scrollToEnd() {
  7311. if (getEscalator().getBody().getRowCount() > 0) {
  7312. scrollToRow(escalator.getBody().getRowCount() - 1,
  7313. ScrollDestination.END);
  7314. }
  7315. }
  7316. /**
  7317. * Sets the vertical scroll offset.
  7318. *
  7319. * @param px
  7320. * the number of pixels this grid should be scrolled down
  7321. */
  7322. public void setScrollTop(double px) {
  7323. escalator.setScrollTop(px);
  7324. }
  7325. /**
  7326. * Gets the vertical scroll offset.
  7327. *
  7328. * @return the number of pixels this grid is scrolled down
  7329. */
  7330. public double getScrollTop() {
  7331. return escalator.getScrollTop();
  7332. }
  7333. /**
  7334. * Sets the horizontal scroll offset.
  7335. *
  7336. * @since 7.5.0
  7337. * @param px
  7338. * the number of pixels this grid should be scrolled right
  7339. */
  7340. public void setScrollLeft(double px) {
  7341. escalator.setScrollLeft(px);
  7342. }
  7343. /**
  7344. * Gets the horizontal scroll offset.
  7345. *
  7346. * @return the number of pixels this grid is scrolled to the right
  7347. */
  7348. public double getScrollLeft() {
  7349. return escalator.getScrollLeft();
  7350. }
  7351. /**
  7352. * Returns the height of the scrollable area in pixels.
  7353. *
  7354. * @since 7.5.0
  7355. * @return the height of the scrollable area in pixels
  7356. */
  7357. public double getScrollHeight() {
  7358. return escalator.getScrollHeight();
  7359. }
  7360. /**
  7361. * Returns the width of the scrollable area in pixels.
  7362. *
  7363. * @since 7.5.0
  7364. * @return the width of the scrollable area in pixels.
  7365. */
  7366. public double getScrollWidth() {
  7367. return escalator.getScrollWidth();
  7368. }
  7369. private static final Logger getLogger() {
  7370. return Logger.getLogger(Grid.class.getName());
  7371. }
  7372. /**
  7373. * Sets the number of rows that should be visible in Grid's body, while
  7374. * {@link #getHeightMode()} is {@link HeightMode#ROW}.
  7375. * <p>
  7376. * If Grid is currently not in {@link HeightMode#ROW}, the given value is
  7377. * remembered, and applied once the mode is applied.
  7378. *
  7379. * @param rows
  7380. * The height in terms of number of rows displayed in Grid's
  7381. * body. If Grid doesn't contain enough rows, white space is
  7382. * displayed instead.
  7383. * @throws IllegalArgumentException
  7384. * if {@code rows} is zero or less
  7385. * @throws IllegalArgumentException
  7386. * if {@code rows} is {@link Double#isInifinite(double)
  7387. * infinite}
  7388. * @throws IllegalArgumentException
  7389. * if {@code rows} is {@link Double#isNaN(double) NaN}
  7390. *
  7391. * @see #setHeightMode(HeightMode)
  7392. */
  7393. public void setHeightByRows(double rows) throws IllegalArgumentException {
  7394. escalator.setHeightByRows(rows);
  7395. }
  7396. /**
  7397. * Gets the amount of rows in Grid's body that are shown, while
  7398. * {@link #getHeightMode()} is {@link HeightMode#ROW}.
  7399. * <p>
  7400. * By default, it is {@value Escalator#DEFAULT_HEIGHT_BY_ROWS}.
  7401. *
  7402. * @return the amount of rows that should be shown in Grid's body, while in
  7403. * {@link HeightMode#ROW}.
  7404. * @see #setHeightByRows(double)
  7405. */
  7406. public double getHeightByRows() {
  7407. return escalator.getHeightByRows();
  7408. }
  7409. /**
  7410. * Defines the mode in which the Grid widget's height is calculated.
  7411. * <p>
  7412. * If {@link HeightMode#CSS} is given, Grid will respect the values given
  7413. * via {@link #setHeight(String)}, and behave as a traditional Widget.
  7414. * <p>
  7415. * If {@link HeightMode#ROW} is given, Grid will make sure that the body
  7416. * will display as many rows as {@link #getHeightByRows()} defines.
  7417. * <em>Note:</em> If headers/footers are inserted or removed, the widget
  7418. * will resize itself to still display the required amount of rows in its
  7419. * body. It also takes the horizontal scrollbar into account.
  7420. *
  7421. * @param heightMode
  7422. * the mode in to which Grid should be set
  7423. */
  7424. public void setHeightMode(HeightMode heightMode) {
  7425. /*
  7426. * This method is a workaround for the fact that Vaadin re-applies
  7427. * widget dimensions (height/width) on each state change event. The
  7428. * original design was to have setHeight an setHeightByRow be equals,
  7429. * and whichever was called the latest was considered in effect.
  7430. *
  7431. * But, because of Vaadin always calling setHeight on the widget, this
  7432. * approach doesn't work.
  7433. */
  7434. escalator.setHeightMode(heightMode);
  7435. }
  7436. /**
  7437. * Returns the current {@link HeightMode} the Grid is in.
  7438. * <p>
  7439. * Defaults to {@link HeightMode#CSS}.
  7440. *
  7441. * @return the current HeightMode
  7442. */
  7443. public HeightMode getHeightMode() {
  7444. return escalator.getHeightMode();
  7445. }
  7446. private Set<String> getConsumedEventsForRenderer(Renderer<?> renderer) {
  7447. Set<String> events = new HashSet<>();
  7448. if (renderer instanceof ComplexRenderer) {
  7449. Collection<String> consumedEvents = ((ComplexRenderer<?>) renderer)
  7450. .getConsumedEvents();
  7451. if (consumedEvents != null) {
  7452. events.addAll(consumedEvents);
  7453. }
  7454. }
  7455. return events;
  7456. }
  7457. @Override
  7458. public void onBrowserEvent(Event event) {
  7459. if (!isEnabled()) {
  7460. return;
  7461. }
  7462. String eventType = event.getType();
  7463. if (eventType.equals(BrowserEvents.FOCUS)
  7464. || eventType.equals(BrowserEvents.BLUR)) {
  7465. super.onBrowserEvent(event);
  7466. return;
  7467. }
  7468. EventTarget target = event.getEventTarget();
  7469. if (!Element.is(target) || isOrContainsInSpacer(Element.as(target))) {
  7470. return;
  7471. }
  7472. Element element = Element.as(target);
  7473. RowContainer container = escalator.findRowContainer(element);
  7474. Cell cell;
  7475. if (container == null) {
  7476. if (eventType.equals(BrowserEvents.KEYDOWN)
  7477. || eventType.equals(BrowserEvents.KEYUP)
  7478. || eventType.equals(BrowserEvents.KEYPRESS)) {
  7479. cell = cellFocusHandler.getFocusedCell();
  7480. container = cellFocusHandler.containerWithFocus;
  7481. } else {
  7482. // Click might be in an editor cell, should still map.
  7483. if (editor.editorOverlay != null
  7484. && editor.editorOverlay.isOrHasChild(element)) {
  7485. container = escalator.getBody();
  7486. int rowIndex = editor.getRow();
  7487. int colIndex = editor.getElementColumn(element);
  7488. if (colIndex < 0) {
  7489. // Click in editor, but not for any column.
  7490. return;
  7491. }
  7492. try {
  7493. TableCellElement cellElement = container
  7494. .getRowElement(rowIndex).getCells()
  7495. .getItem(colIndex);
  7496. cell = new Cell(rowIndex, colIndex, cellElement);
  7497. } catch (IllegalStateException exception) {
  7498. // IllegalStateException may occur if user has scrolled
  7499. // Grid so that Escalator has updated, and row under
  7500. // Editor is no longer there
  7501. return;
  7502. }
  7503. } else {
  7504. if (escalator.getElement().isOrHasChild(element)) {
  7505. eventCell.set(new Cell(-1, -1, null), Section.BODY);
  7506. // Fire native events.
  7507. super.onBrowserEvent(event);
  7508. }
  7509. return;
  7510. }
  7511. }
  7512. } else {
  7513. cell = container.getCell(element);
  7514. if (eventType.equals(BrowserEvents.MOUSEDOWN)) {
  7515. cellOnPrevMouseDown = cell;
  7516. } else if (cell == null && eventType.equals(BrowserEvents.CLICK)) {
  7517. /*
  7518. * Chrome has an interesting idea on click targets (see
  7519. * cellOnPrevMouseDown javadoc). Firefox, on the other hand, has
  7520. * the mousedown target as the click target.
  7521. */
  7522. cell = cellOnPrevMouseDown;
  7523. }
  7524. }
  7525. if (cell == null) {
  7526. getLogger().log(Level.WARNING,
  7527. "received " + eventType + "-event with a null cell target");
  7528. return;
  7529. }
  7530. eventCell.set(cell, getSectionFromContainer(container));
  7531. GridEvent<T> gridEvent = new GridEvent<>(event, eventCell);
  7532. for (GridEventHandler<T> handler : browserEventHandlers) {
  7533. handler.onEvent(gridEvent);
  7534. }
  7535. }
  7536. private Section getSectionFromContainer(RowContainer container) {
  7537. assert container != null : "RowContainer should not be null";
  7538. if (container == escalator.getBody()) {
  7539. return Section.BODY;
  7540. } else if (container == escalator.getFooter()) {
  7541. return Section.FOOTER;
  7542. } else if (container == escalator.getHeader()) {
  7543. return Section.HEADER;
  7544. }
  7545. assert false : "RowContainer was not header, footer or body.";
  7546. return null;
  7547. }
  7548. private boolean isOrContainsInSpacer(Node node) {
  7549. Node n = node;
  7550. while (n != null && n != getElement()) {
  7551. boolean isElement = Element.is(n);
  7552. if (isElement) {
  7553. String className = Element.as(n).getClassName();
  7554. // Also check whether className is indeed a string. For
  7555. // SVGElement it may be of type SVGAnimatedString.
  7556. // https://developer.mozilla.org/en-US/docs/Web/API/Element/className#Notes
  7557. if (WidgetUtil.isString(className) && className
  7558. .contains(getStylePrimaryName() + "-spacer")) {
  7559. return true;
  7560. }
  7561. }
  7562. n = n.getParentNode();
  7563. }
  7564. return false;
  7565. }
  7566. private boolean isElementInChildWidget(Element e) {
  7567. Widget w = WidgetUtil.findWidget(e);
  7568. if (w == this) {
  7569. return false;
  7570. }
  7571. /*
  7572. * If e is directly inside this grid, but the grid is wrapped in a
  7573. * Composite, findWidget is not going to find this, only the wrapper.
  7574. * Thus we need to check its parents to see if we encounter this; if we
  7575. * don't, the found widget is actually a parent of this, so we should
  7576. * return false.
  7577. */
  7578. while (w != null && w != this) {
  7579. w = w.getParent();
  7580. }
  7581. return w != null;
  7582. }
  7583. private class EditorEventHandler implements GridEventHandler<T> {
  7584. @Override
  7585. public void onEvent(GridEvent<T> event) {
  7586. if (!isEditorEnabled()) {
  7587. return;
  7588. }
  7589. Widget widget;
  7590. if (editor.focusedColumnIndexDOM < 0) {
  7591. widget = null;
  7592. } else {
  7593. widget = editor.getWidget(
  7594. getVisibleColumn(editor.focusedColumnIndexDOM));
  7595. }
  7596. EditorDomEvent<T> editorEvent = new EditorDomEvent<>(
  7597. event.getDomEvent(), event.getCell(), widget);
  7598. event.setHandled(
  7599. getEditor().getEventHandler().handleEvent(editorEvent));
  7600. }
  7601. };
  7602. private class SuperEventHandler implements GridEventHandler<T> {
  7603. @Override
  7604. public void onEvent(GridEvent<T> event) {
  7605. if (event.isHandled()) {
  7606. return;
  7607. }
  7608. Grid.super.onBrowserEvent(event.getDomEvent());
  7609. }
  7610. };
  7611. private abstract class AbstractGridEventHandler
  7612. implements GridEventHandler<T> {
  7613. @Override
  7614. public void onEvent(GridEvent<T> event) {
  7615. if (event.isHandled()) {
  7616. return;
  7617. }
  7618. event.setHandled(isElementInChildWidget(
  7619. Element.as(event.getDomEvent().getEventTarget())));
  7620. }
  7621. };
  7622. private class RendererEventHandler extends AbstractGridEventHandler {
  7623. @Override
  7624. public void onEvent(GridEvent<T> event) {
  7625. super.onEvent(event);
  7626. if (event.isHandled()) {
  7627. return;
  7628. }
  7629. if (!event.getCell().isBody()) {
  7630. return;
  7631. }
  7632. Column<?, T> gridColumn = event.getCell().getColumn();
  7633. boolean enterKey = event.getDomEvent().getType()
  7634. .equals(BrowserEvents.KEYDOWN)
  7635. && event.getDomEvent().getKeyCode() == KeyCodes.KEY_ENTER;
  7636. boolean doubleClick = event.getDomEvent().getType()
  7637. .equals(BrowserEvents.DBLCLICK);
  7638. if (gridColumn.getRenderer() instanceof ComplexRenderer) {
  7639. ComplexRenderer<?> cplxRenderer = (ComplexRenderer<?>) gridColumn
  7640. .getRenderer();
  7641. if (cplxRenderer.getConsumedEvents()
  7642. .contains(event.getDomEvent().getType())) {
  7643. if (cplxRenderer.onBrowserEvent(event.getCell(),
  7644. event.getDomEvent())) {
  7645. event.setHandled(true);
  7646. }
  7647. }
  7648. // Calls onActivate if KeyDown and Enter or double click
  7649. if ((enterKey || doubleClick)
  7650. && cplxRenderer.onActivate(event.getCell())) {
  7651. event.setHandled(true);
  7652. }
  7653. }
  7654. }
  7655. };
  7656. private class CellFocusEventHandler extends AbstractGridEventHandler {
  7657. @Override
  7658. public void onEvent(GridEvent<T> event) {
  7659. super.onEvent(event);
  7660. if (event.isHandled()) {
  7661. return;
  7662. }
  7663. Collection<String> navigation = cellFocusHandler
  7664. .getNavigationEvents();
  7665. if (navigation.contains(event.getDomEvent().getType())) {
  7666. cellFocusHandler.handleNavigationEvent(event.getDomEvent(),
  7667. event.getCell());
  7668. }
  7669. }
  7670. };
  7671. private class HeaderCellDragStartHandler extends AbstractGridEventHandler {
  7672. @Override
  7673. public void onEvent(GridEvent<T> event) {
  7674. super.onEvent(event);
  7675. if (event.isHandled()) {
  7676. return;
  7677. }
  7678. if (!isColumnReorderingAllowed()) {
  7679. return;
  7680. }
  7681. if (!event.getCell().isHeader()) {
  7682. return;
  7683. }
  7684. int offset = 0; // apply offset depending on selection column, see
  7685. // #10546
  7686. if (getSelectionColumn().isPresent()) {
  7687. offset = -1;
  7688. }
  7689. if (event.getCell().getColumnIndex()
  7690. + offset < getFrozenColumnCount()) {
  7691. return;
  7692. }
  7693. if (event.getDomEvent().getTypeInt() == Event.ONMOUSEDOWN
  7694. && event.getDomEvent()
  7695. .getButton() == NativeEvent.BUTTON_LEFT
  7696. || event.getDomEvent().getTypeInt() == Event.ONTOUCHSTART) {
  7697. dndHandler.onDragStartOnDraggableElement(event.getDomEvent(),
  7698. headerCellDndCallback);
  7699. event.getDomEvent().preventDefault();
  7700. event.getDomEvent().stopPropagation();
  7701. // fixes https://github.com/vaadin/framework/issues/8632
  7702. // don't mark the event as handled, in order for the next
  7703. // handler in the handler chain (HeaderDefaultRowEventHandler)
  7704. // to be able to receive it. This should be safe since the next
  7705. // handlers in the chain (RendererEventHandler and
  7706. // CellFocusEventHandler) do not react to header touches/clicks.
  7707. // event.setHandled(true);
  7708. }
  7709. }
  7710. };
  7711. private class HeaderDefaultRowEventHandler
  7712. extends AbstractGridEventHandler {
  7713. private Point rowEventTouchStartingPoint;
  7714. @Override
  7715. public void onEvent(GridEvent<T> event) {
  7716. super.onEvent(event);
  7717. if (event.isHandled()) {
  7718. return;
  7719. }
  7720. if (!event.getCell().isHeader()) {
  7721. return;
  7722. }
  7723. if (!getHeader().getRow(event.getCell().getRowIndex())
  7724. .isDefault()) {
  7725. return;
  7726. }
  7727. if (!event.getCell().getColumn().isSortable()) {
  7728. // Only handle sorting events if the column is sortable
  7729. return;
  7730. }
  7731. if (BrowserEvents.MOUSEDOWN.equals(event.getDomEvent().getType())
  7732. && event.getDomEvent().getShiftKey()) {
  7733. // Don't select text when shift clicking on a header.
  7734. event.getDomEvent().preventDefault();
  7735. }
  7736. if (BrowserEvents.TOUCHSTART
  7737. .equals(event.getDomEvent().getType())) {
  7738. if (event.getDomEvent().getTouches().length() > 1) {
  7739. return;
  7740. }
  7741. event.getDomEvent().preventDefault();
  7742. Touch touch = event.getDomEvent().getChangedTouches().get(0);
  7743. rowEventTouchStartingPoint = new Point(touch.getClientX(),
  7744. touch.getClientY());
  7745. sorter.awaitForTouchEnd(GridConstants.LONG_TAP_DELAY);
  7746. event.setHandled(true);
  7747. } else if (BrowserEvents.TOUCHMOVE
  7748. .equals(event.getDomEvent().getType())) {
  7749. if (event.getDomEvent().getTouches().length() > 1) {
  7750. return;
  7751. }
  7752. if (rowEventTouchStartingPoint == null) {
  7753. return;
  7754. }
  7755. event.getDomEvent().preventDefault();
  7756. Touch touch = event.getDomEvent().getChangedTouches().get(0);
  7757. double diffX = Math.abs(
  7758. touch.getClientX() - rowEventTouchStartingPoint.getX());
  7759. double diffY = Math.abs(
  7760. touch.getClientY() - rowEventTouchStartingPoint.getY());
  7761. // Cancel long tap if finger strays too far from
  7762. // starting point
  7763. if (diffX > GridConstants.LONG_TAP_THRESHOLD
  7764. || diffY > GridConstants.LONG_TAP_THRESHOLD) {
  7765. sorter.cancelAwaitForTouchEnd();
  7766. }
  7767. event.setHandled(true);
  7768. } else if (BrowserEvents.TOUCHEND
  7769. .equals(event.getDomEvent().getType())) {
  7770. if (event.getDomEvent().getTouches().length() > 1) {
  7771. return;
  7772. }
  7773. if (rowEventTouchStartingPoint == null) {
  7774. return;
  7775. }
  7776. sorter.onTouchEnd();
  7777. event.setHandled(true);
  7778. } else if (BrowserEvents.TOUCHCANCEL
  7779. .equals(event.getDomEvent().getType())) {
  7780. if (event.getDomEvent().getTouches().length() > 1) {
  7781. return;
  7782. }
  7783. sorter.cancelAwaitForTouchEnd();
  7784. event.setHandled(true);
  7785. } else if (BrowserEvents.CLICK
  7786. .equals(event.getDomEvent().getType())) {
  7787. sorter.sort(event.getCell().getColumn(),
  7788. event.getDomEvent().getShiftKey());
  7789. }
  7790. }
  7791. };
  7792. @Override
  7793. public com.google.gwt.user.client.Element getSubPartElement(
  7794. String subPart) {
  7795. /*
  7796. * handles details[] (translated to spacer[] for Escalator), cell[],
  7797. * header[] and footer[]
  7798. */
  7799. // "#header[0][0]/DRAGhANDLE"
  7800. Element escalatorElement = escalator.getSubPartElement(
  7801. subPart.replaceFirst("^details\\[", "spacer["));
  7802. if (escalatorElement != null) {
  7803. int detailIdx = subPart.indexOf("/");
  7804. if (detailIdx > 0) {
  7805. String detail = subPart.substring(detailIdx + 1);
  7806. getLogger().severe("Looking up detail from index " + detailIdx
  7807. + " onward: \"" + detail + "\"");
  7808. if (detail.equalsIgnoreCase("content")) {
  7809. // XXX: Fix this to look up by class name!
  7810. return DOM.asOld(Element.as(escalatorElement.getChild(0)));
  7811. }
  7812. if (detail.equalsIgnoreCase("draghandle")) {
  7813. // XXX: Fix this to look up by class name!
  7814. return DOM.asOld(Element.as(escalatorElement.getChild(1)));
  7815. }
  7816. }
  7817. return DOM.asOld(escalatorElement);
  7818. }
  7819. SubPartArguments args = SubPartArguments.create(subPart);
  7820. Element editor = getSubPartElementEditor(args);
  7821. if (editor != null) {
  7822. return DOM.asOld(editor);
  7823. }
  7824. return null;
  7825. }
  7826. private Element getSubPartElementEditor(SubPartArguments args) {
  7827. if (!args.getType().equalsIgnoreCase("editor")
  7828. || editor.getState() != State.ACTIVE) {
  7829. return null;
  7830. }
  7831. if (args.getIndicesLength() == 0) {
  7832. return editor.editorOverlay;
  7833. } else if (args.getIndicesLength() == 1) {
  7834. int index = args.getIndex(0);
  7835. if (index >= columns.size()) {
  7836. return null;
  7837. }
  7838. escalator.scrollToColumn(index, ScrollDestination.ANY, 0);
  7839. Widget widget = editor.getWidget(columns.get(index));
  7840. if (widget != null) {
  7841. return widget.getElement();
  7842. }
  7843. // No widget for the column.
  7844. return null;
  7845. }
  7846. return null;
  7847. }
  7848. @Override
  7849. public String getSubPartName(
  7850. com.google.gwt.user.client.Element subElement) {
  7851. String escalatorStructureName = escalator.getSubPartName(subElement);
  7852. if (escalatorStructureName != null) {
  7853. return escalatorStructureName.replaceFirst("^spacer", "details");
  7854. }
  7855. String editorName = getSubPartNameEditor(subElement);
  7856. if (editorName != null) {
  7857. return editorName;
  7858. }
  7859. return null;
  7860. }
  7861. private String getSubPartNameEditor(Element subElement) {
  7862. if (editor.getState() != State.ACTIVE
  7863. || !editor.editorOverlay.isOrHasChild(subElement)) {
  7864. return null;
  7865. }
  7866. int i = 0;
  7867. for (Column<?, T> column : columns) {
  7868. if (editor.getWidget(column).getElement()
  7869. .isOrHasChild(subElement)) {
  7870. return "editor[" + i + "]";
  7871. }
  7872. ++i;
  7873. }
  7874. return "editor";
  7875. }
  7876. private void setSelectColumnRenderer(
  7877. final Renderer<Boolean> selectColumnRenderer) {
  7878. if (this.selectColumnRenderer == selectColumnRenderer) {
  7879. return;
  7880. }
  7881. if (this.selectColumnRenderer != null) {
  7882. if (this.selectColumnRenderer instanceof ComplexRenderer) {
  7883. // End of Life for the old selection column renderer.
  7884. ((ComplexRenderer<?>) this.selectColumnRenderer).destroy();
  7885. }
  7886. // Clear field so frozen column logic in the remove method knows
  7887. // what to do
  7888. Column<?, T> colToRemove = selectionColumn;
  7889. selectionColumn = null;
  7890. removeColumnSkipSelectionColumnCheck(colToRemove);
  7891. cellFocusHandler.offsetRangeBy(-1);
  7892. }
  7893. this.selectColumnRenderer = selectColumnRenderer;
  7894. if (selectColumnRenderer != null) {
  7895. cellFocusHandler.offsetRangeBy(1);
  7896. selectionColumn = new SelectionColumn(selectColumnRenderer);
  7897. addColumnsSkipSelectionColumnCheck(
  7898. Collections.singleton(selectionColumn), 0);
  7899. selectionColumn.initDone();
  7900. } else {
  7901. selectionColumn = null;
  7902. requestRefreshBody();
  7903. }
  7904. updateFrozenColumns();
  7905. }
  7906. /**
  7907. * Sets the current selection model.
  7908. *
  7909. * @param selectionModel
  7910. * a selection model implementation.
  7911. * @throws IllegalArgumentException
  7912. * if selection model argument is null
  7913. */
  7914. public void setSelectionModel(SelectionModel<T> selectionModel) {
  7915. if (selectionModel == null) {
  7916. throw new IllegalArgumentException("Selection model can't be null");
  7917. }
  7918. this.selectionModel = selectionModel;
  7919. if (selectionModel instanceof SelectionModelWithSelectionColumn) {
  7920. setSelectColumnRenderer(
  7921. ((SelectionModelWithSelectionColumn) selectionModel)
  7922. .getRenderer());
  7923. } else {
  7924. setSelectColumnRenderer(null);
  7925. }
  7926. if (this.selectionModel.isMultiSelectionAllowed()) {
  7927. escalator.getTable().setAttribute("aria-multiselectable", "true");
  7928. } else if (this.selectionModel.isSelectionAllowed()) {
  7929. escalator.getTable().setAttribute("aria-multiselectable", "false");
  7930. } else {
  7931. escalator.getTable().removeAttribute("aria-multiselectable");
  7932. }
  7933. // Refresh rendered rows to update selection, if it has changed
  7934. requestRefreshBody();
  7935. }
  7936. /**
  7937. * Gets a reference to the current selection model.
  7938. *
  7939. * @return the currently used SelectionModel instance.
  7940. */
  7941. public SelectionModel<T> getSelectionModel() {
  7942. return selectionModel;
  7943. }
  7944. /**
  7945. * Returns if a row is selected.
  7946. *
  7947. * @param row
  7948. * a row object
  7949. * @return {@code true}, if the current selection model considers the
  7950. * provided row object selected.
  7951. */
  7952. public boolean isSelected(T row) {
  7953. return selectionModel.isSelected(row);
  7954. }
  7955. /**
  7956. * Selects a row using the current selection model.
  7957. * <p>
  7958. * Only selection models implementing {@link SelectionModel.Single} and
  7959. * {@link SelectionModel.Multi} are supported; for anything else, an
  7960. * exception will be thrown.
  7961. *
  7962. * @param row
  7963. * a row object
  7964. * @throws IllegalStateException
  7965. * if the current selection model is not an instance of
  7966. * {@link SelectionModel.Single} or {@link SelectionModel.Multi}
  7967. */
  7968. public void select(T row) {
  7969. if (getSelectionModel().isSelectionAllowed()) {
  7970. getSelectionModel().select(row);
  7971. }
  7972. }
  7973. /**
  7974. * Deselects a row using the current selection model.
  7975. * <p>
  7976. * Only selection models implementing {@link SelectionModel.Single} and
  7977. * {@link SelectionModel.Multi} are supported; for anything else, an
  7978. * exception will be thrown.
  7979. *
  7980. * @param row
  7981. * a row object
  7982. * @throws IllegalStateException
  7983. * if the current selection model is not an instance of
  7984. * {@link SelectionModel.Single} or {@link SelectionModel.Multi}
  7985. */
  7986. public void deselect(T row) {
  7987. if (getSelectionModel().isSelectionAllowed()) {
  7988. getSelectionModel().deselect(row);
  7989. }
  7990. }
  7991. /**
  7992. * Deselects all rows using the current selection model.
  7993. *
  7994. * @throws IllegalStateException
  7995. * if the current selection model is not an instance of
  7996. * {@link SelectionModel.Single} or {@link SelectionModel.Multi}
  7997. */
  7998. public void deselectAll() {
  7999. getSelectionModel().deselectAll();
  8000. }
  8001. @Override
  8002. public HandlerRegistration addSelectionHandler(
  8003. final SelectionHandler<T> handler) {
  8004. return addHandler(handler, SelectionEvent.getType());
  8005. }
  8006. /**
  8007. * Sets the current sort order using the fluid Sort API. Read the
  8008. * documentation for {@link Sort} for more information.
  8009. *
  8010. * @param s
  8011. * a sort instance
  8012. */
  8013. public void sort(Sort s) {
  8014. setSortOrder(s.build());
  8015. }
  8016. /**
  8017. * Sorts the Grid data in ascending order along one column.
  8018. *
  8019. * @param <C>
  8020. * the column type
  8021. * @param column
  8022. * a grid column reference
  8023. */
  8024. public <C> void sort(Column<C, T> column) {
  8025. sort(column, SortDirection.ASCENDING);
  8026. }
  8027. /**
  8028. * Sorts the Grid data along one column.
  8029. *
  8030. * @param <C>
  8031. * the column type
  8032. * @param column
  8033. * a grid column reference
  8034. * @param direction
  8035. * a sort direction value
  8036. */
  8037. public <C> void sort(Column<C, T> column, SortDirection direction) {
  8038. sort(Sort.by(column, direction));
  8039. }
  8040. /**
  8041. * Sets the sort order to use. Setting this causes the Grid to re-sort
  8042. * itself.
  8043. *
  8044. * @param order
  8045. * a sort order list. If set to null, the sort order is cleared.
  8046. */
  8047. public void setSortOrder(List<SortOrder> order) {
  8048. setSortOrder(order, false);
  8049. }
  8050. /**
  8051. * Clears the sort order and indicators without re-sorting.
  8052. */
  8053. private void clearSortOrder() {
  8054. sortOrder.clear();
  8055. refreshHeader();
  8056. }
  8057. private void setSortOrder(List<SortOrder> order, boolean userOriginated) {
  8058. if (order != sortOrder) {
  8059. sortOrder.clear();
  8060. if (order != null) {
  8061. sortOrder.addAll(order);
  8062. }
  8063. }
  8064. sort(userOriginated);
  8065. }
  8066. /**
  8067. * Get a copy of the current sort order array.
  8068. *
  8069. * @return a copy of the current sort order array
  8070. */
  8071. public List<SortOrder> getSortOrder() {
  8072. return Collections.unmodifiableList(sortOrder);
  8073. }
  8074. /**
  8075. * Finds the sorting order for this column
  8076. */
  8077. private SortOrder getSortOrder(Column<?, ?> column) {
  8078. for (SortOrder order : getSortOrder()) {
  8079. if (order.getColumn() == column) {
  8080. return order;
  8081. }
  8082. }
  8083. return null;
  8084. }
  8085. /**
  8086. * Register a GWT event handler for a sorting event. This handler gets
  8087. * called whenever this Grid needs its data source to provide data sorted in
  8088. * a specific order.
  8089. *
  8090. * @param handler
  8091. * a sort event handler
  8092. * @return the registration for the handler
  8093. */
  8094. public HandlerRegistration addSortHandler(SortHandler<T> handler) {
  8095. return addHandler(handler, SortEvent.getType());
  8096. }
  8097. /**
  8098. * Register a GWT event handler for a select all event. This handler gets
  8099. * called whenever Grid needs all rows selected.
  8100. * <p>
  8101. * In case the select all checkbox is not visible in the
  8102. * {@link SelectionColumn}, it will be come visible after adding the
  8103. * handler.
  8104. *
  8105. * @param handler
  8106. * a select all event handler
  8107. * @return the registration for the handler
  8108. */
  8109. public HandlerRegistration addSelectAllHandler(
  8110. SelectAllHandler<T> handler) {
  8111. HandlerRegistration registration = addHandler(handler,
  8112. SelectAllEvent.getType());
  8113. return registration;
  8114. }
  8115. /**
  8116. * Register a GWT event handler for a data available event. This handler
  8117. * gets called whenever the {@link DataSource} for this Grid has new data
  8118. * available.
  8119. * <p>
  8120. * This handle will be fired with the current available data after
  8121. * registration is done.
  8122. *
  8123. * @param handler
  8124. * a data available event handler
  8125. * @return the registration for the handler
  8126. */
  8127. public HandlerRegistration addDataAvailableHandler(
  8128. final DataAvailableHandler handler) {
  8129. // Deferred call to handler with current row range
  8130. Scheduler.get().scheduleFinally(() -> {
  8131. if (!dataSource.isWaitingForData()) {
  8132. handler.onDataAvailable(
  8133. new DataAvailableEvent(currentDataAvailable));
  8134. }
  8135. });
  8136. return addHandler(handler, DataAvailableEvent.TYPE);
  8137. }
  8138. /**
  8139. * Register a BodyKeyDownHandler to this Grid. The event for this handler is
  8140. * fired when a KeyDown event occurs while cell focus is in the Body of this
  8141. * Grid.
  8142. *
  8143. * @param handler
  8144. * the key handler to register
  8145. * @return the registration for the handler
  8146. */
  8147. public HandlerRegistration addBodyKeyDownHandler(
  8148. BodyKeyDownHandler handler) {
  8149. return addHandler(handler, GridKeyDownEvent.TYPE);
  8150. }
  8151. /**
  8152. * Register a BodyKeyUpHandler to this Grid. The event for this handler is
  8153. * fired when a KeyUp event occurs while cell focus is in the Body of this
  8154. * Grid.
  8155. *
  8156. * @param handler
  8157. * the key handler to register
  8158. * @return the registration for the handler
  8159. */
  8160. public HandlerRegistration addBodyKeyUpHandler(BodyKeyUpHandler handler) {
  8161. return addHandler(handler, GridKeyUpEvent.TYPE);
  8162. }
  8163. /**
  8164. * Register a BodyKeyPressHandler to this Grid. The event for this handler
  8165. * is fired when a KeyPress event occurs while cell focus is in the Body of
  8166. * this Grid.
  8167. *
  8168. * @param handler
  8169. * the key handler to register
  8170. * @return the registration for the handler
  8171. */
  8172. public HandlerRegistration addBodyKeyPressHandler(
  8173. BodyKeyPressHandler handler) {
  8174. return addHandler(handler, GridKeyPressEvent.TYPE);
  8175. }
  8176. /**
  8177. * Register a HeaderKeyDownHandler to this Grid. The event for this handler
  8178. * is fired when a KeyDown event occurs while cell focus is in the Header of
  8179. * this Grid.
  8180. *
  8181. * @param handler
  8182. * the key handler to register
  8183. * @return the registration for the handler
  8184. */
  8185. public HandlerRegistration addHeaderKeyDownHandler(
  8186. HeaderKeyDownHandler handler) {
  8187. return addHandler(handler, GridKeyDownEvent.TYPE);
  8188. }
  8189. /**
  8190. * Register a HeaderKeyUpHandler to this Grid. The event for this handler is
  8191. * fired when a KeyUp event occurs while cell focus is in the Header of this
  8192. * Grid.
  8193. *
  8194. * @param handler
  8195. * the key handler to register
  8196. * @return the registration for the handler
  8197. */
  8198. public HandlerRegistration addHeaderKeyUpHandler(
  8199. HeaderKeyUpHandler handler) {
  8200. return addHandler(handler, GridKeyUpEvent.TYPE);
  8201. }
  8202. /**
  8203. * Register a HeaderKeyPressHandler to this Grid. The event for this handler
  8204. * is fired when a KeyPress event occurs while cell focus is in the Header
  8205. * of this Grid.
  8206. *
  8207. * @param handler
  8208. * the key handler to register
  8209. * @return the registration for the handler
  8210. */
  8211. public HandlerRegistration addHeaderKeyPressHandler(
  8212. HeaderKeyPressHandler handler) {
  8213. return addHandler(handler, GridKeyPressEvent.TYPE);
  8214. }
  8215. /**
  8216. * Register a FooterKeyDownHandler to this Grid. The event for this handler
  8217. * is fired when a KeyDown event occurs while cell focus is in the Footer of
  8218. * this Grid.
  8219. *
  8220. * @param handler
  8221. * the key handler to register
  8222. * @return the registration for the handler
  8223. */
  8224. public HandlerRegistration addFooterKeyDownHandler(
  8225. FooterKeyDownHandler handler) {
  8226. return addHandler(handler, GridKeyDownEvent.TYPE);
  8227. }
  8228. /**
  8229. * Register a FooterKeyUpHandler to this Grid. The event for this handler is
  8230. * fired when a KeyUp event occurs while cell focus is in the Footer of this
  8231. * Grid.
  8232. *
  8233. * @param handler
  8234. * the key handler to register
  8235. * @return the registration for the handler
  8236. */
  8237. public HandlerRegistration addFooterKeyUpHandler(
  8238. FooterKeyUpHandler handler) {
  8239. return addHandler(handler, GridKeyUpEvent.TYPE);
  8240. }
  8241. /**
  8242. * Register a FooterKeyPressHandler to this Grid. The event for this handler
  8243. * is fired when a KeyPress event occurs while cell focus is in the Footer
  8244. * of this Grid.
  8245. *
  8246. * @param handler
  8247. * the key handler to register
  8248. * @return the registration for the handler
  8249. */
  8250. public HandlerRegistration addFooterKeyPressHandler(
  8251. FooterKeyPressHandler handler) {
  8252. return addHandler(handler, GridKeyPressEvent.TYPE);
  8253. }
  8254. /**
  8255. * Register a BodyClickHandler to this Grid. The event for this handler is
  8256. * fired when a Click event occurs in the Body of this Grid.
  8257. *
  8258. * @param handler
  8259. * the click handler to register
  8260. * @return the registration for the handler
  8261. */
  8262. public HandlerRegistration addBodyClickHandler(BodyClickHandler handler) {
  8263. return addHandler(handler, GridClickEvent.TYPE);
  8264. }
  8265. /**
  8266. * Register a HeaderClickHandler to this Grid. The event for this handler is
  8267. * fired when a Click event occurs in the Header of this Grid.
  8268. *
  8269. * @param handler
  8270. * the click handler to register
  8271. * @return the registration for the handler
  8272. */
  8273. public HandlerRegistration addHeaderClickHandler(
  8274. HeaderClickHandler handler) {
  8275. return addHandler(handler, GridClickEvent.TYPE);
  8276. }
  8277. /**
  8278. * Register a FooterClickHandler to this Grid. The event for this handler is
  8279. * fired when a Click event occurs in the Footer of this Grid.
  8280. *
  8281. * @param handler
  8282. * the click handler to register
  8283. * @return the registration for the handler
  8284. */
  8285. public HandlerRegistration addFooterClickHandler(
  8286. FooterClickHandler handler) {
  8287. return addHandler(handler, GridClickEvent.TYPE);
  8288. }
  8289. /**
  8290. * Register a BodyDoubleClickHandler to this Grid. The event for this
  8291. * handler is fired when a double click event occurs in the Body of this
  8292. * Grid.
  8293. *
  8294. * @param handler
  8295. * the double click handler to register
  8296. * @return the registration for the handler
  8297. */
  8298. public HandlerRegistration addBodyDoubleClickHandler(
  8299. BodyDoubleClickHandler handler) {
  8300. return addHandler(handler, GridDoubleClickEvent.TYPE);
  8301. }
  8302. /**
  8303. * Register a HeaderDoubleClickHandler to this Grid. The event for this
  8304. * handler is fired when a double click event occurs in the Header of this
  8305. * Grid.
  8306. *
  8307. * @param handler
  8308. * the double click handler to register
  8309. * @return the registration for the handler
  8310. */
  8311. public HandlerRegistration addHeaderDoubleClickHandler(
  8312. HeaderDoubleClickHandler handler) {
  8313. return addHandler(handler, GridDoubleClickEvent.TYPE);
  8314. }
  8315. /**
  8316. * Register a FooterDoubleClickHandler to this Grid. The event for this
  8317. * handler is fired when a double click event occurs in the Footer of this
  8318. * Grid.
  8319. *
  8320. * @param handler
  8321. * the double click handler to register
  8322. * @return the registration for the handler
  8323. */
  8324. public HandlerRegistration addFooterDoubleClickHandler(
  8325. FooterDoubleClickHandler handler) {
  8326. return addHandler(handler, GridDoubleClickEvent.TYPE);
  8327. }
  8328. /**
  8329. * Register a column reorder handler to this Grid. The event for this
  8330. * handler is fired when the Grid's columns are reordered.
  8331. *
  8332. * @since 7.5.0
  8333. * @param handler
  8334. * the handler for the event
  8335. * @return the registration for the handler
  8336. */
  8337. public HandlerRegistration addColumnReorderHandler(
  8338. ColumnReorderHandler<T> handler) {
  8339. return addHandler(handler, ColumnReorderEvent.getType());
  8340. }
  8341. /**
  8342. * Register a column visibility change handler to this Grid. The event for
  8343. * this handler is fired when the Grid's columns change visibility.
  8344. *
  8345. * @since 7.5.0
  8346. * @param handler
  8347. * the handler for the event
  8348. * @return the registration for the handler
  8349. */
  8350. public HandlerRegistration addColumnVisibilityChangeHandler(
  8351. ColumnVisibilityChangeHandler<T> handler) {
  8352. return addHandler(handler, ColumnVisibilityChangeEvent.getType());
  8353. }
  8354. /**
  8355. * Register a column resize handler to this Grid. The event for this handler
  8356. * is fired when the Grid's columns are resized.
  8357. *
  8358. * @since 7.6
  8359. * @param handler
  8360. * the handler for the event
  8361. * @return the registration for the handler
  8362. */
  8363. public HandlerRegistration addColumnResizeHandler(
  8364. ColumnResizeHandler<T> handler) {
  8365. return addHandler(handler, ColumnResizeEvent.getType());
  8366. }
  8367. /**
  8368. * Register a enabled status change handler to this Grid. The event for this
  8369. * handler is fired when the Grid changes from disabled to enabled and
  8370. * vice-versa.
  8371. *
  8372. * @param handler
  8373. * the handler for the event
  8374. * @return the registration for the handler
  8375. */
  8376. public HandlerRegistration addEnabledHandler(GridEnabledHandler handler) {
  8377. return addHandler(handler, GridEnabledEvent.TYPE);
  8378. }
  8379. /**
  8380. * Register a selection allowed status change handler to this Grid. The
  8381. * event for this handler is fired when the Grid changes selection allowed
  8382. * state.
  8383. *
  8384. * @param handler
  8385. * the handler for the event
  8386. * @return the registration for the handler
  8387. */
  8388. public HandlerRegistration addSelectionAllowedHandler(
  8389. GridSelectionAllowedHandler handler) {
  8390. return addHandler(handler, GridSelectionAllowedEvent.TYPE);
  8391. }
  8392. /**
  8393. * Register a row height changed handler to this Grid. The event for this
  8394. * handler is fired when the row height is changed in the Grid's header,
  8395. * body or footer.
  8396. *
  8397. * @param handler
  8398. * the handler for the event
  8399. * @return the registration for the handler
  8400. */
  8401. public HandlerRegistration addRowHeightChangedHandler(
  8402. RowHeightChangedHandler handler) {
  8403. return escalator.addHandler(handler, RowHeightChangedEvent.TYPE);
  8404. }
  8405. /**
  8406. * Adds a spacer visibility changed handler to the underlying escalator.
  8407. *
  8408. * @param handler
  8409. * the handler to be called when a spacer's visibility changes
  8410. * @return the registration object with which the handler can be removed
  8411. * @since 8.3.2
  8412. */
  8413. public HandlerRegistration addSpacerVisibilityChangedHandler(
  8414. SpacerVisibilityChangedHandler handler) {
  8415. return escalator.addHandler(handler, SpacerVisibilityChangedEvent.TYPE);
  8416. }
  8417. /**
  8418. * Adds a spacer index changed handler to the underlying escalator.
  8419. *
  8420. * @param handler
  8421. * the handler to be called when a spacer's index changes
  8422. * @return the registration object with which the handler can be removed
  8423. * @since 8.9
  8424. */
  8425. public HandlerRegistration addSpacerIndexChangedHandler(
  8426. SpacerIndexChangedHandler handler) {
  8427. return escalator.addHandler(handler, SpacerIndexChangedEvent.TYPE);
  8428. }
  8429. /**
  8430. * Adds a low-level DOM event handler to this Grid. The handler is inserted
  8431. * into the given position in the list of handlers. The handlers are invoked
  8432. * in order. If the
  8433. * {@link GridEventHandler#onEvent(Event, EventCellReference) onEvent}
  8434. * method of a handler returns true, subsequent handlers are not invoked.
  8435. *
  8436. * @param index
  8437. * the index to insert the handler to
  8438. * @param handler
  8439. * the handler to add
  8440. */
  8441. public void addBrowserEventHandler(int index, GridEventHandler<T> handler) {
  8442. browserEventHandlers.add(index, handler);
  8443. }
  8444. /**
  8445. * Apply sorting to data source.
  8446. */
  8447. private void sort(boolean userOriginated) {
  8448. refreshHeader();
  8449. fireEvent(new SortEvent<>(this, Collections.unmodifiableList(sortOrder),
  8450. userOriginated));
  8451. }
  8452. private int getLastVisibleRowIndex() {
  8453. int lastRowIndex = escalator.getVisibleRowRange().getEnd();
  8454. int footerTop = escalator.getFooter().getElement().getAbsoluteTop();
  8455. Element lastRow;
  8456. do {
  8457. lastRow = escalator.getBody().getRowElement(--lastRowIndex);
  8458. } while (lastRow.getAbsoluteTop() > footerTop);
  8459. return lastRowIndex;
  8460. }
  8461. private int getFirstVisibleRowIndex() {
  8462. int firstRowIndex = escalator.getVisibleRowRange().getStart();
  8463. int headerBottom = escalator.getHeader().getElement()
  8464. .getAbsoluteBottom();
  8465. Element firstRow = escalator.getBody().getRowElement(firstRowIndex);
  8466. while (firstRow.getAbsoluteBottom() < headerBottom) {
  8467. firstRow = escalator.getBody().getRowElement(++firstRowIndex);
  8468. }
  8469. return firstRowIndex;
  8470. }
  8471. /**
  8472. * Adds a scroll handler to this grid.
  8473. *
  8474. * @param handler
  8475. * the scroll handler to add
  8476. * @return a handler registration for the registered scroll handler
  8477. */
  8478. public HandlerRegistration addScrollHandler(ScrollHandler handler) {
  8479. return addHandler(handler, ScrollEvent.TYPE);
  8480. }
  8481. @Override
  8482. public boolean isWorkPending() {
  8483. return escalator.isWorkPending() || dataSource.isWaitingForData()
  8484. || autoColumnWidthsRecalculator.isScheduled()
  8485. || editor.isWorkPending();
  8486. }
  8487. /**
  8488. * Returns whether columns can be reordered with drag and drop.
  8489. *
  8490. * @since 7.5.0
  8491. * @return <code>true</code> if columns can be reordered, false otherwise
  8492. */
  8493. public boolean isColumnReorderingAllowed() {
  8494. return columnReorderingAllowed;
  8495. }
  8496. /**
  8497. * Sets whether column reordering with drag and drop is allowed or not.
  8498. *
  8499. * @since 7.5.0
  8500. * @param columnReorderingAllowed
  8501. * specifies whether column reordering is allowed
  8502. */
  8503. public void setColumnReorderingAllowed(boolean columnReorderingAllowed) {
  8504. this.columnReorderingAllowed = columnReorderingAllowed;
  8505. }
  8506. /**
  8507. * Sets a new column order for the grid. All columns which are not ordered
  8508. * here will remain in the order they were before as the last columns of
  8509. * grid.
  8510. *
  8511. * @param orderedColumns
  8512. * array of columns in wanted order
  8513. */
  8514. @SuppressWarnings("unchecked")
  8515. public void setColumnOrder(Column<?, T>... orderedColumns) {
  8516. setColumnOrder(false, orderedColumns);
  8517. }
  8518. @SuppressWarnings("unchecked")
  8519. private void setColumnOrder(boolean isUserOriginated,
  8520. Column<?, T>... orderedColumns) {
  8521. List<Column<?, T>> newOrder = new ArrayList<>();
  8522. if (selectionColumn != null) {
  8523. newOrder.add(selectionColumn);
  8524. }
  8525. int i = 0;
  8526. for (Column<?, T> column : orderedColumns) {
  8527. if (columns.contains(column)) {
  8528. newOrder.add(column);
  8529. ++i;
  8530. } else {
  8531. throw new IllegalArgumentException("Given column at index " + i
  8532. + " does not exist in Grid");
  8533. }
  8534. }
  8535. if (columns.size() != newOrder.size()) {
  8536. columns.stream().filter(col -> !newOrder.contains(col))
  8537. .forEach(newOrder::add);
  8538. }
  8539. if (columns.equals(newOrder)) {
  8540. // No changes in order.
  8541. return;
  8542. }
  8543. // Prepare event for firing
  8544. ColumnReorderEvent<T> event = new ColumnReorderEvent<>(columns,
  8545. newOrder, isUserOriginated);
  8546. // Trigger ComplexRenderer.destroy for old content
  8547. ColumnConfiguration conf = getEscalator().getColumnConfiguration();
  8548. conf.removeColumns(0, conf.getColumnCount());
  8549. // Update the order
  8550. columns = newOrder;
  8551. // Do ComplexRenderer.init and render new content
  8552. conf.insertColumns(0, getVisibleColumns().size());
  8553. // Number of frozen columns should be kept same #16901
  8554. updateFrozenColumns();
  8555. // Update column widths.
  8556. for (Column<?, T> column : columns) {
  8557. column.reapplyWidth();
  8558. }
  8559. // Recalculate all the colspans
  8560. for (HeaderRow row : header.getRows()) {
  8561. row.calculateColspans();
  8562. }
  8563. for (FooterRow row : footer.getRows()) {
  8564. row.calculateColspans();
  8565. }
  8566. columnHider.updateTogglesOrder();
  8567. fireEvent(event);
  8568. }
  8569. /**
  8570. * Sets the style generator that is used for generating styles for cells.
  8571. *
  8572. * @param cellStyleGenerator
  8573. * the cell style generator to set, or <code>null</code> to
  8574. * remove a previously set generator
  8575. */
  8576. public void setCellStyleGenerator(
  8577. CellStyleGenerator<T> cellStyleGenerator) {
  8578. this.cellStyleGenerator = cellStyleGenerator;
  8579. requestRefreshBody();
  8580. }
  8581. /**
  8582. * Gets the style generator that is used for generating styles for cells.
  8583. *
  8584. * @return the cell style generator, or <code>null</code> if no generator is
  8585. * set
  8586. */
  8587. public CellStyleGenerator<T> getCellStyleGenerator() {
  8588. return cellStyleGenerator;
  8589. }
  8590. /**
  8591. * Sets the style generator that is used for generating styles for rows.
  8592. *
  8593. * @param rowStyleGenerator
  8594. * the row style generator to set, or <code>null</code> to remove
  8595. * a previously set generator
  8596. */
  8597. public void setRowStyleGenerator(RowStyleGenerator<T> rowStyleGenerator) {
  8598. this.rowStyleGenerator = rowStyleGenerator;
  8599. requestRefreshBody();
  8600. }
  8601. /**
  8602. * Gets the style generator that is used for generating styles for rows.
  8603. *
  8604. * @return the row style generator, or <code>null</code> if no generator is
  8605. * set
  8606. */
  8607. public RowStyleGenerator<T> getRowStyleGenerator() {
  8608. return rowStyleGenerator;
  8609. }
  8610. private static void setCustomStyleName(Element element, String styleName) {
  8611. assert element != null;
  8612. String oldStyleName = element
  8613. .getPropertyString(CUSTOM_STYLE_PROPERTY_NAME);
  8614. if (!SharedUtil.equals(oldStyleName, styleName)) {
  8615. if (oldStyleName != null && !oldStyleName.isEmpty()) {
  8616. element.removeClassName(oldStyleName);
  8617. }
  8618. if (styleName != null && !styleName.isEmpty()) {
  8619. element.addClassName(styleName);
  8620. }
  8621. element.setPropertyString(CUSTOM_STYLE_PROPERTY_NAME, styleName);
  8622. }
  8623. }
  8624. /**
  8625. * Opens the editor over the row with the given index.
  8626. *
  8627. * @param rowIndex
  8628. * the index of the row to be edited
  8629. *
  8630. * @throws IllegalStateException
  8631. * if the editor is not enabled
  8632. * @throws IllegalStateException
  8633. * if the editor is already in edit mode
  8634. */
  8635. public void editRow(int rowIndex) {
  8636. editor.editRow(rowIndex);
  8637. }
  8638. /**
  8639. * Returns whether the editor is currently open on some row.
  8640. *
  8641. * @return {@code true} if the editor is active, {@code false} otherwise.
  8642. */
  8643. public boolean isEditorActive() {
  8644. return editor.getState() != State.INACTIVE;
  8645. }
  8646. /**
  8647. * Saves any unsaved changes in the editor to the data source.
  8648. *
  8649. * @throws IllegalStateException
  8650. * if the editor is not enabled
  8651. * @throws IllegalStateException
  8652. * if the editor is not in edit mode
  8653. */
  8654. public void saveEditor() {
  8655. editor.save();
  8656. }
  8657. /**
  8658. * Cancels the currently active edit and hides the editor. Any changes that
  8659. * are not {@link #saveEditor() saved} are lost.
  8660. *
  8661. * @throws IllegalStateException
  8662. * if the editor is not enabled
  8663. * @throws IllegalStateException
  8664. * if the editor is not in edit mode
  8665. */
  8666. public void cancelEditor() {
  8667. editor.cancel();
  8668. }
  8669. /**
  8670. * Returns the handler responsible for binding data and editor widgets to
  8671. * the editor.
  8672. *
  8673. * @return the editor handler or null if not set
  8674. */
  8675. public EditorHandler<T> getEditorHandler() {
  8676. return editor.getHandler();
  8677. }
  8678. /**
  8679. * Sets the handler responsible for binding data and editor widgets to the
  8680. * editor.
  8681. *
  8682. * @param handler
  8683. * the new editor handler
  8684. *
  8685. * @throws IllegalStateException
  8686. * if the editor is currently in edit mode
  8687. */
  8688. public void setEditorHandler(EditorHandler<T> handler) {
  8689. editor.setHandler(handler);
  8690. }
  8691. /**
  8692. * Returns the enabled state of the editor.
  8693. *
  8694. * @return true if editing is enabled, false otherwise
  8695. */
  8696. public boolean isEditorEnabled() {
  8697. return editor.isEnabled();
  8698. }
  8699. /**
  8700. * Sets the enabled state of the editor.
  8701. *
  8702. * @param enabled
  8703. * true to enable editing, false to disable
  8704. *
  8705. * @throws IllegalStateException
  8706. * if in edit mode and trying to disable
  8707. * @throws IllegalStateException
  8708. * if the editor handler is not set
  8709. */
  8710. public void setEditorEnabled(boolean enabled) {
  8711. editor.setEnabled(enabled);
  8712. }
  8713. /**
  8714. * Returns the editor widget associated with the given column. If the editor
  8715. * is not active, returns null.
  8716. *
  8717. * @param column
  8718. * the column
  8719. * @return the widget if the editor is open, null otherwise
  8720. */
  8721. public Widget getEditorWidget(Column<?, T> column) {
  8722. return editor.getWidget(column);
  8723. }
  8724. /**
  8725. * Sets the caption on the save button in the Grid editor.
  8726. *
  8727. * @param saveCaption
  8728. * the caption to set
  8729. * @throws IllegalArgumentException
  8730. * if {@code saveCaption} is {@code null}
  8731. */
  8732. public void setEditorSaveCaption(String saveCaption)
  8733. throws IllegalArgumentException {
  8734. editor.setSaveCaption(saveCaption);
  8735. }
  8736. /**
  8737. * Gets the current caption on the save button in the Grid editor.
  8738. *
  8739. * @return the current caption on the save button
  8740. */
  8741. public String getEditorSaveCaption() {
  8742. return editor.getSaveCaption();
  8743. }
  8744. /**
  8745. * Sets the caption on the cancel button in the Grid editor.
  8746. *
  8747. * @param cancelCaption
  8748. * the caption to set
  8749. * @throws IllegalArgumentException
  8750. * if {@code cancelCaption} is {@code null}
  8751. */
  8752. public void setEditorCancelCaption(String cancelCaption)
  8753. throws IllegalArgumentException {
  8754. editor.setCancelCaption(cancelCaption);
  8755. }
  8756. /**
  8757. * Gets the caption on the cancel button in the Grid editor.
  8758. *
  8759. * @return the current caption on the cancel button
  8760. */
  8761. public String getEditorCancelCaption() {
  8762. return editor.getCancelCaption();
  8763. }
  8764. @Override
  8765. protected void onAttach() {
  8766. super.onAttach();
  8767. // Grid was just attached to DOM. Column widths should be
  8768. // calculated.
  8769. recalculateColumnWidths();
  8770. if (getEscalator().getBody().getRowCount() == 0 && dataSource != null) {
  8771. setEscalatorSizeFromDataSource();
  8772. }
  8773. for (int row : reattachVisibleDetails) {
  8774. setDetailsVisible(row, true);
  8775. }
  8776. reattachVisibleDetails.clear();
  8777. }
  8778. @Override
  8779. protected void onDetach() {
  8780. Set<Integer> details = new HashSet<>(visibleDetails);
  8781. reattachVisibleDetails.clear();
  8782. reattachVisibleDetails.addAll(details);
  8783. for (int row : details) {
  8784. setDetailsVisible(row, false);
  8785. }
  8786. super.onDetach();
  8787. }
  8788. @Override
  8789. public void onResize() {
  8790. super.onResize();
  8791. /*
  8792. * Delay calculation to be deferred so Escalator can do it's magic.
  8793. */
  8794. Scheduler.get().scheduleFinally(() -> {
  8795. if (escalator
  8796. .getInnerWidth() != autoColumnWidthsRecalculator.lastCalculatedInnerWidth) {
  8797. recalculateColumnWidths();
  8798. }
  8799. // Vertical resizing could make editor positioning invalid so it
  8800. // needs to be recalculated on resize
  8801. if (isEditorActive()) {
  8802. editor.updateVerticalScrollPosition();
  8803. }
  8804. // if there is a resize, we need to refresh the body to avoid an
  8805. // off-by-one error which occurs when the user scrolls all the
  8806. // way to the bottom.
  8807. refreshBody();
  8808. });
  8809. }
  8810. /**
  8811. * Grid does not support adding Widgets this way.
  8812. * <p>
  8813. * This method is implemented only because removing widgets from Grid (added
  8814. * via e.g. {@link Renderer}s) requires the {@link HasWidgets} interface.
  8815. *
  8816. * @param w
  8817. * irrelevant
  8818. * @throws UnsupportedOperationException
  8819. * always
  8820. */
  8821. @Override
  8822. @Deprecated
  8823. public void add(Widget w) {
  8824. throw new UnsupportedOperationException(
  8825. "Cannot add widgets to Grid with this method");
  8826. }
  8827. /**
  8828. * Grid does not support clearing Widgets this way.
  8829. * <p>
  8830. * This method is implemented only because removing widgets from Grid (added
  8831. * via e.g. {@link Renderer}s) requires the {@link HasWidgets} interface.
  8832. *
  8833. * @throws UnsupportedOperationException
  8834. * always
  8835. */
  8836. @Override
  8837. @Deprecated
  8838. public void clear() {
  8839. throw new UnsupportedOperationException(
  8840. "Cannot clear widgets from Grid this way");
  8841. }
  8842. /**
  8843. * Grid does not support iterating through Widgets this way.
  8844. * <p>
  8845. * This method is implemented only because removing widgets from Grid (added
  8846. * via e.g. {@link Renderer}s) requires the {@link HasWidgets} interface.
  8847. *
  8848. * @return never
  8849. * @throws UnsupportedOperationException
  8850. * always
  8851. */
  8852. @Override
  8853. @Deprecated
  8854. public Iterator<Widget> iterator() {
  8855. throw new UnsupportedOperationException(
  8856. "Cannot iterate through widgets in Grid this way");
  8857. }
  8858. /**
  8859. * Grid does not support removing Widgets this way.
  8860. * <p>
  8861. * This method is implemented only because removing widgets from Grid (added
  8862. * via e.g. {@link Renderer}s) requires the {@link HasWidgets} interface.
  8863. *
  8864. * @return always <code>false</code>
  8865. */
  8866. @Override
  8867. @Deprecated
  8868. public boolean remove(Widget w) {
  8869. /*
  8870. * This is the method that is the sole reason to have Grid implement
  8871. * HasWidget - when Vaadin removes a Component from the hierarchy, the
  8872. * corresponding Widget will call removeFromParent() on itself. GWT will
  8873. * check there that its parent (i.e. Grid) implements HasWidgets, and
  8874. * will call this remove(Widget) method.
  8875. *
  8876. * tl;dr: all this song and dance to make sure GWT's sanity checks
  8877. * aren't triggered, even though they effectively do nothing interesting
  8878. * from Grid's perspective.
  8879. */
  8880. return false;
  8881. }
  8882. /**
  8883. * Accesses the package private method Widget#setParent()
  8884. *
  8885. * @param widget
  8886. * The widget to access
  8887. * @param parent
  8888. * The parent to set
  8889. */
  8890. private static final native void setParent(Widget widget, Grid<?> parent)
  8891. /*-{
  8892. widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
  8893. }-*/;
  8894. private static final native void onAttach(Widget widget)
  8895. /*-{
  8896. widget.@Widget::onAttach()();
  8897. }-*/;
  8898. private static final native void onDetach(Widget widget)
  8899. /*-{
  8900. widget.@Widget::onDetach()();
  8901. }-*/;
  8902. @Override
  8903. protected void doAttachChildren() {
  8904. if (sidebar.getParent() == this) {
  8905. onAttach(sidebar);
  8906. }
  8907. }
  8908. @Override
  8909. protected void doDetachChildren() {
  8910. if (sidebar.getParent() == this) {
  8911. onDetach(sidebar);
  8912. }
  8913. }
  8914. private void attachWidget(Widget w, Element parent) {
  8915. assert w.getParent() == null;
  8916. parent.appendChild(w.getElement());
  8917. setParent(w, this);
  8918. }
  8919. private void detachWidget(Widget w) {
  8920. assert w.getParent() == this;
  8921. setParent(w, null);
  8922. w.getElement().removeFromParent();
  8923. }
  8924. /**
  8925. * Resets all cached pixel sizes and reads new values from the DOM. This
  8926. * methods should be used e.g. when styles affecting the dimensions of
  8927. * elements in this grid have been changed.
  8928. */
  8929. public void resetSizesFromDom() {
  8930. getEscalator().resetSizesFromDom();
  8931. }
  8932. /**
  8933. * Sets a new details generator for row details.
  8934. * <p>
  8935. * The currently opened row details will be re-rendered.
  8936. *
  8937. * @since 7.5.0
  8938. * @param detailsGenerator
  8939. * the details generator to set
  8940. * @throws IllegalArgumentException
  8941. * if detailsGenerator is <code>null</code>;
  8942. */
  8943. public void setDetailsGenerator(DetailsGenerator detailsGenerator)
  8944. throws IllegalArgumentException {
  8945. if (detailsGenerator == null) {
  8946. throw new IllegalArgumentException(
  8947. "Details generator may not be null");
  8948. }
  8949. for (Integer index : visibleDetails) {
  8950. setDetailsVisible(index, false);
  8951. }
  8952. this.detailsGenerator = detailsGenerator;
  8953. // this will refresh all visible spacers
  8954. escalator.getBody().setSpacerUpdater(gridSpacerUpdater);
  8955. }
  8956. /**
  8957. * Gets the current details generator for row details.
  8958. *
  8959. * @since 7.5.0
  8960. * @return the detailsGenerator the current details generator
  8961. */
  8962. public DetailsGenerator getDetailsGenerator() {
  8963. return detailsGenerator;
  8964. }
  8965. /**
  8966. * Shows or hides the details for a specific row.
  8967. * <p>
  8968. * This method does nothing if trying to set show already-visible details,
  8969. * or hide already-hidden details.
  8970. *
  8971. * @since 7.5.0
  8972. * @param rowIndex
  8973. * the index of the affected row
  8974. * @param visible
  8975. * <code>true</code> to show the details, or <code>false</code>
  8976. * to hide them
  8977. * @see #isDetailsVisible(int)
  8978. */
  8979. public void setDetailsVisible(int rowIndex, boolean visible) {
  8980. if (DetailsGenerator.NULL.equals(detailsGenerator)) {
  8981. return;
  8982. }
  8983. Integer rowIndexInteger = Integer.valueOf(rowIndex);
  8984. /*
  8985. * We want to prevent opening a details row twice, so any subsequent
  8986. * openings (or closings) of details is a NOOP.
  8987. *
  8988. * When a details row is opened, it is given an arbitrary height
  8989. * (because Escalator requires a height upon opening). Only when it's
  8990. * opened, Escalator will ask the generator to generate a widget, which
  8991. * we then can measure. When measured, we correct the initial height by
  8992. * the original height.
  8993. *
  8994. * Without this check, we would override the measured height, and revert
  8995. * back to the initial, arbitrary, height which would most probably be
  8996. * wrong.
  8997. *
  8998. * see GridSpacerUpdater.init for implementation details.
  8999. *
  9000. * The order of operations isn't entirely stable. Sometimes Escalator
  9001. * knows about the spacer visibility updates first and doesn't need
  9002. * updating again but Grid's visibleDetails set still does.
  9003. */
  9004. boolean isVisible = isDetailsVisible(rowIndex);
  9005. boolean isVisibleInEscalator = escalator.getBody()
  9006. .spacerExists(rowIndex);
  9007. if (visible) {
  9008. if (!isVisibleInEscalator) {
  9009. escalator.getBody().setSpacer(rowIndex,
  9010. DETAILS_ROW_INITIAL_HEIGHT);
  9011. }
  9012. if (!isVisible) {
  9013. visibleDetails.add(rowIndexInteger);
  9014. }
  9015. } else {
  9016. if (isVisibleInEscalator) {
  9017. escalator.getBody().setSpacer(rowIndex, -1);
  9018. }
  9019. if (isVisible) {
  9020. visibleDetails.remove(rowIndexInteger);
  9021. }
  9022. }
  9023. }
  9024. /**
  9025. * Check whether the details for a row is visible or not.
  9026. *
  9027. * @since 7.5.0
  9028. * @param rowIndex
  9029. * the index of the row for which to check details
  9030. * @return <code>true</code> if the details for the given row is visible
  9031. * @see #setDetailsVisible(int, boolean)
  9032. */
  9033. public boolean isDetailsVisible(int rowIndex) {
  9034. return visibleDetails.contains(Integer.valueOf(rowIndex));
  9035. }
  9036. /**
  9037. * Reset the details row with current contents.
  9038. *
  9039. * @since 8.13
  9040. * @param rowIndex
  9041. * the index of the row for which details should be reset
  9042. */
  9043. public void resetVisibleDetails(int rowIndex) {
  9044. escalator.getBody().resetSpacer(rowIndex);
  9045. }
  9046. /**
  9047. * Update details row height.
  9048. *
  9049. * @since 8.1.3
  9050. * @param rowIndex
  9051. * the index of the row for which to update details height
  9052. * @param height
  9053. * new height of the details row
  9054. */
  9055. public void setDetailsHeight(int rowIndex, double height) {
  9056. escalator.getBody().setSpacer(rowIndex, height);
  9057. }
  9058. /**
  9059. * Requests that the column widths should be recalculated.
  9060. * <p>
  9061. * The actual recalculation is not necessarily done immediately so you
  9062. * cannot rely on the columns being the correct width after the call
  9063. * returns.
  9064. *
  9065. * @since 7.4.1
  9066. */
  9067. public void recalculateColumnWidths() {
  9068. autoColumnWidthsRecalculator.schedule();
  9069. }
  9070. /**
  9071. * Gets the customizable menu bar that is by default used for toggling
  9072. * column hidability. The application developer is allowed to add their
  9073. * custom items to the end of the menu, but should try to avoid modifying
  9074. * the items in the beginning of the menu that control the column hiding if
  9075. * any columns are marked as hidable. A toggle for opening the menu will be
  9076. * displayed whenever the menu contains at least one item.
  9077. *
  9078. * @since 7.5.0
  9079. * @return the menu bar
  9080. */
  9081. public MenuBar getSidebarMenu() {
  9082. return sidebar.menuBar;
  9083. }
  9084. /**
  9085. * Tests whether the sidebar menu is currently open.
  9086. *
  9087. * @since 7.5.0
  9088. * @see #getSidebarMenu()
  9089. * @return <code>true</code> if the sidebar is open; <code>false</code> if
  9090. * it is closed
  9091. */
  9092. public boolean isSidebarOpen() {
  9093. return sidebar.isOpen();
  9094. }
  9095. /**
  9096. * Sets whether the sidebar menu is open.
  9097. *
  9098. *
  9099. * @since 7.5.0
  9100. * @see #getSidebarMenu()
  9101. * @see #isSidebarOpen()
  9102. * @param sidebarOpen
  9103. * <code>true</code> to open the sidebar; <code>false</code> to
  9104. * close it
  9105. */
  9106. public void setSidebarOpen(boolean sidebarOpen) {
  9107. if (sidebarOpen) {
  9108. sidebar.open();
  9109. } else {
  9110. sidebar.close();
  9111. }
  9112. }
  9113. @Override
  9114. public int getTabIndex() {
  9115. return FocusUtil.getTabIndex(this);
  9116. }
  9117. @Override
  9118. public void setAccessKey(char key) {
  9119. FocusUtil.setAccessKey(this, key);
  9120. }
  9121. @Override
  9122. public void setFocus(boolean focused) {
  9123. FocusUtil.setFocus(this, focused);
  9124. }
  9125. @Override
  9126. public void setTabIndex(int index) {
  9127. FocusUtil.setTabIndex(this, index);
  9128. }
  9129. @Override
  9130. public void focus() {
  9131. setFocus(true);
  9132. }
  9133. /**
  9134. * Sets the buffered editor mode.
  9135. *
  9136. * @since 7.6
  9137. * @param editorBuffered
  9138. * <code>true</code> to enable buffered editor,
  9139. * <code>false</code> to disable it
  9140. */
  9141. public void setEditorBuffered(boolean editorBuffered) {
  9142. editor.setBuffered(editorBuffered);
  9143. }
  9144. /**
  9145. * Gets the buffered editor mode.
  9146. *
  9147. * @since 7.6
  9148. * @return <code>true</code> if buffered editor is enabled,
  9149. * <code>false</code> otherwise
  9150. */
  9151. public boolean isEditorBuffered() {
  9152. return editor.isBuffered();
  9153. }
  9154. /**
  9155. * Returns the {@link EventCellReference} for the latest event fired from
  9156. * this Grid.
  9157. * <p>
  9158. * Note: This cell reference will be updated when firing the next event.
  9159. *
  9160. * @since 7.5
  9161. * @return event cell reference
  9162. */
  9163. public EventCellReference<T> getEventCell() {
  9164. return eventCell;
  9165. }
  9166. /**
  9167. * Returns a CellReference for the cell to which the given element belongs
  9168. * to.
  9169. *
  9170. * @since 7.6
  9171. * @param element
  9172. * Element to find from the cell's content.
  9173. * @return CellReference or <code>null</code> if cell was not found.
  9174. */
  9175. public CellReference<T> getCellReference(Element element) {
  9176. RowContainer container = getEscalator().findRowContainer(element);
  9177. if (container != null) {
  9178. Cell cell = container.getCell(element);
  9179. if (cell != null) {
  9180. EventCellReference<T> cellRef = new EventCellReference<>(this);
  9181. cellRef.set(cell, getSectionFromContainer(container));
  9182. return cellRef;
  9183. }
  9184. }
  9185. return null;
  9186. }
  9187. /**
  9188. * Returns the selection column for the grid if the selection model is of
  9189. * type {@link SelectionModelWithSelectionColumn}.
  9190. *
  9191. * @return the select all checkbox, or an empty optional if not in use
  9192. */
  9193. public Optional<SelectionColumn> getSelectionColumn() {
  9194. return Optional.ofNullable(selectionColumn);
  9195. }
  9196. }