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.

GridConnector.java 27KB

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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. * Copyright 2000-2018 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.connectors.grid;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.HashSet;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Objects;
  25. import java.util.Set;
  26. import java.util.stream.Collectors;
  27. import com.google.gwt.core.client.Scheduler;
  28. import com.google.gwt.dom.client.Element;
  29. import com.google.gwt.dom.client.EventTarget;
  30. import com.google.gwt.dom.client.NativeEvent;
  31. import com.google.gwt.event.shared.HandlerRegistration;
  32. import com.vaadin.client.ComponentConnector;
  33. import com.vaadin.client.ConnectorHierarchyChangeEvent;
  34. import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
  35. import com.vaadin.client.DeferredWorker;
  36. import com.vaadin.client.HasComponentsConnector;
  37. import com.vaadin.client.MouseEventDetailsBuilder;
  38. import com.vaadin.client.TooltipInfo;
  39. import com.vaadin.client.WidgetUtil;
  40. import com.vaadin.client.annotations.OnStateChange;
  41. import com.vaadin.client.communication.StateChangeEvent;
  42. import com.vaadin.client.connectors.AbstractListingConnector;
  43. import com.vaadin.client.connectors.grid.ColumnConnector.CustomColumn;
  44. import com.vaadin.client.data.DataSource;
  45. import com.vaadin.client.ui.SimpleManagedLayout;
  46. import com.vaadin.client.widget.escalator.RowContainer;
  47. import com.vaadin.client.widget.grid.CellReference;
  48. import com.vaadin.client.widget.grid.EventCellReference;
  49. import com.vaadin.client.widget.grid.events.BodyClickHandler;
  50. import com.vaadin.client.widget.grid.events.BodyDoubleClickHandler;
  51. import com.vaadin.client.widget.grid.events.GridClickEvent;
  52. import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
  53. import com.vaadin.client.widget.grid.sort.SortEvent;
  54. import com.vaadin.client.widget.grid.sort.SortOrder;
  55. import com.vaadin.client.widgets.Grid;
  56. import com.vaadin.client.widgets.Grid.Column;
  57. import com.vaadin.client.widgets.Grid.FooterRow;
  58. import com.vaadin.client.widgets.Grid.HeaderRow;
  59. import com.vaadin.client.widgets.Grid.SelectionColumn;
  60. import com.vaadin.client.widgets.Grid.StaticSection.StaticCell;
  61. import com.vaadin.shared.MouseEventDetails;
  62. import com.vaadin.shared.data.sort.SortDirection;
  63. import com.vaadin.shared.ui.Connect;
  64. import com.vaadin.shared.ui.grid.GridClientRpc;
  65. import com.vaadin.shared.ui.grid.GridConstants;
  66. import com.vaadin.shared.ui.grid.GridConstants.Section;
  67. import com.vaadin.shared.ui.grid.GridServerRpc;
  68. import com.vaadin.shared.ui.grid.GridState;
  69. import com.vaadin.shared.ui.grid.ScrollDestination;
  70. import com.vaadin.shared.ui.grid.SectionState;
  71. import com.vaadin.shared.ui.grid.SectionState.CellState;
  72. import com.vaadin.shared.ui.grid.SectionState.RowState;
  73. import elemental.json.JsonObject;
  74. /**
  75. * A connector class for the typed Grid component.
  76. *
  77. * @author Vaadin Ltd
  78. * @since 8.0
  79. */
  80. @Connect(com.vaadin.ui.Grid.class)
  81. public class GridConnector extends AbstractListingConnector
  82. implements HasComponentsConnector, SimpleManagedLayout, DeferredWorker {
  83. private Set<Runnable> refreshDetailsCallbacks = new HashSet<>();
  84. /**
  85. * Server-to-client RPC implementation for GridConnector.
  86. * <p>
  87. * The scrolling methods must trigger the scrolling only after any potential
  88. * resizing or other similar action triggered from the server side within
  89. * the same round trip has had a chance to happen, so there needs to be a
  90. * delay. The delay is done with <code>scheduleDeferred</code> rather than
  91. * <code>scheduleFinally</code> because otherwise the order of the
  92. * operations isn't guaranteed.
  93. *
  94. */
  95. private class GridConnectorClientRpc implements GridClientRpc {
  96. private final Grid<JsonObject> grid;
  97. private GridConnectorClientRpc(Grid<JsonObject> grid) {
  98. this.grid = grid;
  99. }
  100. @Override
  101. public void scrollToRow(int row, ScrollDestination destination) {
  102. Scheduler.get().scheduleDeferred(() -> {
  103. grid.scrollToRow(row, destination);
  104. // Add details refresh listener and handle possible detail
  105. // for scrolled row.
  106. addDetailsRefreshCallback(() -> {
  107. if (rowHasDetails(row)) {
  108. grid.scrollToRow(row, destination);
  109. }
  110. });
  111. });
  112. }
  113. @Override
  114. public void scrollToStart() {
  115. Scheduler.get().scheduleDeferred(() -> grid.scrollToStart());
  116. }
  117. @Override
  118. public void scrollToEnd() {
  119. Scheduler.get().scheduleDeferred(() -> {
  120. grid.scrollToEnd();
  121. addDetailsRefreshCallback(() -> {
  122. if (rowHasDetails(grid.getDataSource().size() - 1)) {
  123. grid.scrollToEnd();
  124. }
  125. });
  126. });
  127. }
  128. @Override
  129. public void recalculateColumnWidths() {
  130. grid.recalculateColumnWidths();
  131. }
  132. }
  133. private class ItemClickHandler
  134. implements BodyClickHandler, BodyDoubleClickHandler {
  135. @Override
  136. public void onClick(GridClickEvent event) {
  137. if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
  138. fireItemClick(event.getTargetCell(), event.getNativeEvent());
  139. }
  140. }
  141. @Override
  142. public void onDoubleClick(GridDoubleClickEvent event) {
  143. if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
  144. fireItemClick(event.getTargetCell(), event.getNativeEvent());
  145. }
  146. }
  147. private void fireItemClick(CellReference<?> cell,
  148. NativeEvent mouseEvent) {
  149. String rowKey = getRowKey((JsonObject) cell.getRow());
  150. String columnId = columnToIdMap.get(cell.getColumn());
  151. int rowIndex = cell.getRowIndex();
  152. getRpcProxy(GridServerRpc.class).itemClick(rowKey, columnId,
  153. MouseEventDetailsBuilder.buildMouseEventDetails(mouseEvent),
  154. rowIndex);
  155. }
  156. }
  157. /* Map to keep track of all added columns */
  158. private Map<CustomColumn, String> columnToIdMap = new HashMap<>();
  159. private Map<String, CustomColumn> idToColumn = new HashMap<>();
  160. /* Child component list for HasComponentsConnector */
  161. private List<ComponentConnector> childComponents;
  162. private ItemClickHandler itemClickHandler = new ItemClickHandler();
  163. private boolean rowHeightScheduled = false;
  164. /**
  165. * Gets the string identifier of the given column in this grid.
  166. *
  167. * @param column
  168. * the column whose id to get
  169. * @return the string id of the column
  170. */
  171. public String getColumnId(Column<?, ?> column) {
  172. return columnToIdMap.get(column);
  173. }
  174. /**
  175. * Gets the column corresponding to the given string identifier.
  176. *
  177. * @param columnId
  178. * the id of the column to get
  179. * @return the column with the given id
  180. */
  181. public CustomColumn getColumn(String columnId) {
  182. return idToColumn.get(columnId);
  183. }
  184. @Override
  185. @SuppressWarnings("unchecked")
  186. public Grid<JsonObject> getWidget() {
  187. return (Grid<JsonObject>) super.getWidget();
  188. }
  189. /**
  190. * Method called for a row details refresh. Runs all callbacks if any
  191. * details were shown and clears the callbacks.
  192. *
  193. * @param detailsShown
  194. * True if any details were set visible
  195. */
  196. protected void detailsRefreshed(boolean detailsShown) {
  197. if (detailsShown) {
  198. refreshDetailsCallbacks.forEach(Runnable::run);
  199. }
  200. refreshDetailsCallbacks.clear();
  201. }
  202. /**
  203. * Method target for when one single details has been updated and we might
  204. * need to scroll it into view.
  205. *
  206. * @param rowIndex
  207. * index of updated row
  208. */
  209. protected void singleDetailsOpened(int rowIndex) {
  210. addDetailsRefreshCallback(() -> {
  211. if (rowHasDetails(rowIndex)) {
  212. getWidget().scrollToRow(rowIndex);
  213. }
  214. });
  215. }
  216. /**
  217. * Add a single use details runnable callback for when we get a call to
  218. * {@link #detailsRefreshed(boolean)}.
  219. *
  220. * @param refreshCallback
  221. * Details refreshed callback
  222. */
  223. private void addDetailsRefreshCallback(Runnable refreshCallback) {
  224. refreshDetailsCallbacks.add(refreshCallback);
  225. }
  226. /**
  227. * Check if we have details for given row.
  228. *
  229. * @param rowIndex
  230. * @return
  231. */
  232. private boolean rowHasDetails(int rowIndex) {
  233. JsonObject row = getWidget().getDataSource().getRow(rowIndex);
  234. return row != null && row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)
  235. && !row.getString(GridState.JSONKEY_DETAILS_VISIBLE).isEmpty();
  236. }
  237. @Override
  238. protected void init() {
  239. super.init();
  240. updateWidgetStyleNames();
  241. Grid<JsonObject> grid = getWidget();
  242. // Trigger early redraw of both grid static sections.
  243. grid.setHeaderVisible(!grid.isHeaderVisible());
  244. grid.setFooterVisible(!grid.isFooterVisible());
  245. registerRpc(GridClientRpc.class, new GridConnectorClientRpc(grid));
  246. grid.addSortHandler(this::handleSortEvent);
  247. grid.setRowStyleGenerator(rowRef -> {
  248. JsonObject json = rowRef.getRow();
  249. return json.hasKey(GridState.JSONKEY_ROWSTYLE)
  250. ? json.getString(GridState.JSONKEY_ROWSTYLE)
  251. : null;
  252. });
  253. grid.setCellStyleGenerator(cellRef -> {
  254. JsonObject row = cellRef.getRow();
  255. if (!row.hasKey(GridState.JSONKEY_CELLSTYLES)) {
  256. return null;
  257. }
  258. Column<?, JsonObject> column = cellRef.getColumn();
  259. if (column instanceof CustomColumn) {
  260. String id = ((CustomColumn) column).getConnectorId();
  261. JsonObject cellStyles = row
  262. .getObject(GridState.JSONKEY_CELLSTYLES);
  263. if (cellStyles.hasKey(id)) {
  264. return cellStyles.getString(id);
  265. }
  266. }
  267. return null;
  268. });
  269. grid.addColumnVisibilityChangeHandler(event -> {
  270. if (event.isUserOriginated()) {
  271. getRpcProxy(GridServerRpc.class).columnVisibilityChanged(
  272. getColumnId(event.getColumn()), event.isHidden());
  273. }
  274. });
  275. grid.addColumnReorderHandler(event -> {
  276. if (event.isUserOriginated()) {
  277. List<String> newColumnOrder = mapColumnsToIds(
  278. event.getNewColumnOrder());
  279. List<String> oldColumnOrder = mapColumnsToIds(
  280. event.getOldColumnOrder());
  281. getRpcProxy(GridServerRpc.class)
  282. .columnsReordered(newColumnOrder, oldColumnOrder);
  283. }
  284. });
  285. grid.addColumnResizeHandler(event -> {
  286. Column<?, JsonObject> column = event.getColumn();
  287. getRpcProxy(GridServerRpc.class).columnResized(getColumnId(column),
  288. column.getWidthActual());
  289. });
  290. // Handling row height changes
  291. grid.addRowHeightChangedHandler(event -> {
  292. getLayoutManager().setNeedsMeasureRecursively(GridConnector.this);
  293. getLayoutManager().layoutNow();
  294. });
  295. /* Item click events */
  296. grid.addBodyClickHandler(itemClickHandler);
  297. grid.addBodyDoubleClickHandler(itemClickHandler);
  298. layout();
  299. }
  300. @Override
  301. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  302. super.onStateChanged(stateChangeEvent);
  303. if (!getState().columnOrder.containsAll(idToColumn.keySet())) {
  304. updateColumns();
  305. } else if (stateChangeEvent.hasPropertyChanged("columnOrder")) {
  306. updateColumnOrder();
  307. }
  308. if (stateChangeEvent.hasPropertyChanged("header")) {
  309. updateHeader();
  310. }
  311. if (stateChangeEvent.hasPropertyChanged("footer")) {
  312. updateFooter();
  313. }
  314. }
  315. void updateColumnOrder() {
  316. getWidget().setColumnOrder(getState().columnOrder.stream()
  317. .map(this::getColumn).toArray(size -> new CustomColumn[size]));
  318. }
  319. @OnStateChange("columnResizeMode")
  320. void updateColumnResizeMode() {
  321. getWidget().setColumnResizeMode(getState().columnResizeMode);
  322. }
  323. /**
  324. * Updates the grid header section on state change.
  325. */
  326. void updateHeader() {
  327. final Grid<JsonObject> grid = getWidget();
  328. final SectionState state = getState().header;
  329. while (grid.getHeaderRowCount() > 0) {
  330. grid.removeHeaderRow(0);
  331. }
  332. for (RowState rowState : state.rows) {
  333. HeaderRow row = grid.appendHeaderRow();
  334. if (rowState.defaultHeader) {
  335. grid.setDefaultHeaderRow(row);
  336. }
  337. updateStaticRow(rowState, row);
  338. }
  339. grid.setHeaderVisible(state.visible);
  340. }
  341. @OnStateChange({ "bodyRowHeight", "headerRowHeight", "footerRowHeight" })
  342. void updateRowHeight() {
  343. if (rowHeightScheduled) {
  344. return;
  345. }
  346. Scheduler.get().scheduleFinally(() -> {
  347. GridState state = getState();
  348. Grid<JsonObject> grid = getWidget();
  349. if (grid.isAttached() && rowHeightNeedsReset()) {
  350. grid.resetSizesFromDom();
  351. }
  352. updateContainerRowHeigth(grid.getEscalator().getBody(),
  353. state.bodyRowHeight);
  354. updateContainerRowHeigth(grid.getEscalator().getHeader(),
  355. state.headerRowHeight);
  356. updateContainerRowHeigth(grid.getEscalator().getFooter(),
  357. state.footerRowHeight);
  358. rowHeightScheduled = false;
  359. });
  360. rowHeightScheduled = true;
  361. }
  362. private boolean rowHeightNeedsReset() {
  363. GridState state = getState();
  364. // Body
  365. boolean bodyAutoCalc = state.bodyRowHeight < 0;
  366. // Header
  367. boolean headerAutoCalc = state.headerRowHeight < 0;
  368. boolean headerReset = headerAutoCalc && hasVisibleContent(state.header);
  369. // Footer
  370. boolean footerAutoCalc = state.footerRowHeight < 0;
  371. boolean footerReset = footerAutoCalc && hasVisibleContent(state.footer);
  372. return bodyAutoCalc || headerReset || footerReset;
  373. }
  374. private boolean hasVisibleContent(SectionState state) {
  375. return state.visible && !state.rows.isEmpty();
  376. }
  377. private void updateContainerRowHeigth(RowContainer container,
  378. double height) {
  379. if (height >= 0) {
  380. container.setDefaultRowHeight(height);
  381. }
  382. }
  383. private void updateStaticRow(RowState rowState,
  384. Grid.StaticSection.StaticRow row) {
  385. rowState.cells
  386. .forEach((columnId, cellState) -> updateStaticCellFromState(
  387. row.getCell(getColumn(columnId)), cellState));
  388. for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups
  389. .entrySet()) {
  390. Set<String> group = cellGroupEntry.getValue();
  391. Grid.Column<?, ?>[] columns = group.stream().map(idToColumn::get)
  392. .toArray(size -> new Grid.Column<?, ?>[size]);
  393. // Set state to be the same as first in group.
  394. updateStaticCellFromState(row.join(columns),
  395. cellGroupEntry.getKey());
  396. }
  397. row.setStyleName(rowState.styleName);
  398. }
  399. private void updateStaticCellFromState(Grid.StaticSection.StaticCell cell,
  400. CellState cellState) {
  401. switch (cellState.type) {
  402. case TEXT:
  403. cell.setText(cellState.text);
  404. break;
  405. case HTML:
  406. cell.setHtml(cellState.html);
  407. break;
  408. case WIDGET:
  409. ComponentConnector connector = (ComponentConnector) cellState.connector;
  410. if (connector != null) {
  411. cell.setWidget(connector.getWidget());
  412. } else {
  413. // This happens if you do setVisible(false) on the component on
  414. // the server side
  415. cell.setWidget(null);
  416. }
  417. break;
  418. default:
  419. throw new IllegalStateException(
  420. "unexpected cell type: " + cellState.type);
  421. }
  422. cell.setStyleName(cellState.styleName);
  423. cell.setDescription(cellState.description);
  424. cell.setDescriptionContentMode(cellState.descriptionContentMode);
  425. }
  426. /**
  427. * Updates the grid footer section on state change.
  428. */
  429. void updateFooter() {
  430. final Grid<JsonObject> grid = getWidget();
  431. final SectionState state = getState().footer;
  432. while (grid.getFooterRowCount() > 0) {
  433. grid.removeFooterRow(0);
  434. }
  435. for (RowState rowState : state.rows) {
  436. FooterRow row = grid.appendFooterRow();
  437. updateStaticRow(rowState, row);
  438. }
  439. grid.setFooterVisible(state.visible);
  440. }
  441. @OnStateChange({ "sortColumns", "sortDirs" })
  442. void updateSortOrder() {
  443. List<SortOrder> sortOrder = new ArrayList<SortOrder>();
  444. String[] sortColumns = getState().sortColumns;
  445. SortDirection[] sortDirs = getState().sortDirs;
  446. for (int i = 0; i < sortColumns.length; i++) {
  447. sortOrder
  448. .add(new SortOrder(getColumn(sortColumns[i]), sortDirs[i]));
  449. }
  450. getWidget().setSortOrder(sortOrder);
  451. }
  452. @Override
  453. public void setDataSource(DataSource<JsonObject> dataSource) {
  454. super.setDataSource(dataSource);
  455. getWidget().setDataSource(dataSource);
  456. }
  457. /**
  458. * Adds a column to the Grid widget. For each column a communication id
  459. * stored for client to server communication.
  460. *
  461. * @param column
  462. * column to add
  463. * @param id
  464. * communication id
  465. */
  466. public void addColumn(CustomColumn column, String id) {
  467. assert !columnToIdMap.containsKey(column) && !columnToIdMap
  468. .containsValue(id) : "Column with given id already exists.";
  469. columnToIdMap.put(column, id);
  470. idToColumn.put(id, column);
  471. if (idToColumn.keySet().containsAll(getState().columnOrder)) {
  472. // All columns are available.
  473. updateColumns();
  474. }
  475. }
  476. /**
  477. * Updates the widgets columns to match the map in this connector.
  478. */
  479. protected void updateColumns() {
  480. List<Column<?, JsonObject>> currentColumns = getWidget().getColumns();
  481. List<CustomColumn> columnOrder = getState().columnOrder.stream()
  482. .map(this::getColumn).collect(Collectors.toList());
  483. if (isColumnOrderCorrect(currentColumns, columnOrder)) {
  484. // All up to date
  485. return;
  486. }
  487. Grid<JsonObject> grid = getWidget();
  488. // Remove old column
  489. currentColumns.stream()
  490. .filter(col -> !(columnOrder.contains(col)
  491. || col instanceof SelectionColumn))
  492. .forEach(grid::removeColumn);
  493. // Add new columns
  494. grid.addColumns(columnOrder.stream()
  495. .filter(col -> !currentColumns.contains(col))
  496. .toArray(CustomColumn[]::new));
  497. // Make sure order is correct.
  498. grid.setColumnOrder(
  499. columnOrder.toArray(new CustomColumn[columnOrder.size()]));
  500. }
  501. private boolean isColumnOrderCorrect(List<Column<?, JsonObject>> current,
  502. List<CustomColumn> order) {
  503. List<Column<?, JsonObject>> columnsToCompare = current;
  504. if (current.size() > 0 && current.get(0) instanceof SelectionColumn) {
  505. // Remove selection column.
  506. columnsToCompare = current.subList(1, current.size());
  507. }
  508. return columnsToCompare.equals(order);
  509. }
  510. /**
  511. * Removes the given column from mappings in this Connector.
  512. *
  513. * @param column
  514. * column to remove from the mapping
  515. */
  516. public void removeColumnMapping(CustomColumn column) {
  517. assert columnToIdMap
  518. .containsKey(column) : "Given Column does not exist.";
  519. // Remove mapping. Columns are removed from Grid when state changes.
  520. String id = columnToIdMap.remove(column);
  521. idToColumn.remove(id);
  522. }
  523. /**
  524. * Method called by {@code CustomColumn} when its renderer changes. This
  525. * method is used to maintain hierarchical renderer wrap in
  526. * {@code TreeGrid}.
  527. *
  528. * @param column
  529. * the column which now has a new renderer
  530. *
  531. * @since 8.1
  532. */
  533. public void onColumnRendererChanged(CustomColumn column) {
  534. // NO-OP
  535. }
  536. @Override
  537. public void onUnregister() {
  538. super.onUnregister();
  539. }
  540. @Override
  541. public boolean isWorkPending() {
  542. return getWidget().isWorkPending();
  543. }
  544. @Override
  545. public void layout() {
  546. getWidget().onResize();
  547. }
  548. /**
  549. * Sends sort information from an event to the server-side of the Grid.
  550. *
  551. * @param event
  552. * the sort event
  553. */
  554. private void handleSortEvent(SortEvent<JsonObject> event) {
  555. List<String> columnIds = new ArrayList<>();
  556. List<SortDirection> sortDirections = new ArrayList<>();
  557. for (SortOrder so : event.getOrder()) {
  558. if (columnToIdMap.containsKey(so.getColumn())) {
  559. columnIds.add(columnToIdMap.get(so.getColumn()));
  560. sortDirections.add(so.getDirection());
  561. }
  562. }
  563. String[] colArray = columnIds.toArray(new String[0]);
  564. SortDirection[] dirArray = sortDirections.toArray(new SortDirection[0]);
  565. if (!Arrays.equals(colArray, getState().sortColumns)
  566. || !Arrays.equals(dirArray, getState().sortDirs)) {
  567. // State has actually changed, send to server
  568. getRpcProxy(GridServerRpc.class).sort(colArray, dirArray,
  569. event.isUserOriginated());
  570. }
  571. }
  572. /* HasComponentsConnector */
  573. @Override
  574. public void updateCaption(ComponentConnector connector) {
  575. // Details components don't support captions.
  576. }
  577. @Override
  578. public List<ComponentConnector> getChildComponents() {
  579. if (childComponents == null) {
  580. return Collections.emptyList();
  581. }
  582. return childComponents;
  583. }
  584. @Override
  585. public void setChildComponents(List<ComponentConnector> children) {
  586. childComponents = children;
  587. }
  588. @Override
  589. public HandlerRegistration addConnectorHierarchyChangeHandler(
  590. ConnectorHierarchyChangeHandler handler) {
  591. return ensureHandlerManager()
  592. .addHandler(ConnectorHierarchyChangeEvent.TYPE, handler);
  593. }
  594. @Override
  595. public GridState getState() {
  596. return (GridState) super.getState();
  597. }
  598. @Override
  599. public boolean hasTooltip() {
  600. // Always check for generated descriptions.
  601. return true;
  602. }
  603. @Override
  604. public TooltipInfo getTooltipInfo(Element element) {
  605. CellReference<JsonObject> cell = getWidget().getCellReference(element);
  606. if (cell != null) {
  607. JsonObject row = cell.getRow();
  608. TooltipInfo tooltip = getHeaderFooterTooltip(cell);
  609. if (tooltip != null) {
  610. return tooltip;
  611. }
  612. if (row != null && (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)
  613. || row.hasKey(GridState.JSONKEY_CELLDESCRIPTION))) {
  614. Column<?, JsonObject> column = cell.getColumn();
  615. if (column instanceof CustomColumn) {
  616. JsonObject cellDescriptions = row
  617. .getObject(GridState.JSONKEY_CELLDESCRIPTION);
  618. String id = ((CustomColumn) column).getConnectorId();
  619. if (cellDescriptions != null
  620. && cellDescriptions.hasKey(id)) {
  621. return new TooltipInfo(cellDescriptions.getString(id),
  622. ((CustomColumn) column)
  623. .getTooltipContentMode());
  624. } else if (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)) {
  625. return new TooltipInfo(
  626. row.getString(GridState.JSONKEY_ROWDESCRIPTION),
  627. getState().rowDescriptionContentMode);
  628. }
  629. }
  630. }
  631. }
  632. if (super.hasTooltip()) {
  633. return super.getTooltipInfo(element);
  634. }
  635. return null;
  636. }
  637. private TooltipInfo getHeaderFooterTooltip(CellReference cell) {
  638. Section section = Section.BODY;
  639. if (cell instanceof EventCellReference) {
  640. // Header or footer
  641. section = ((EventCellReference) cell).getSection();
  642. }
  643. StaticCell staticCell = null;
  644. if (section == Section.HEADER) {
  645. staticCell = getWidget().getHeaderRow(cell.getRowIndex())
  646. .getCell(cell.getColumn());
  647. } else if (section == Section.FOOTER) {
  648. staticCell = getWidget().getFooterRow(cell.getRowIndex())
  649. .getCell(cell.getColumn());
  650. }
  651. if (staticCell != null && staticCell.getDescription() != null) {
  652. return new TooltipInfo(staticCell.getDescription(),
  653. staticCell.getDescriptionContentMode());
  654. }
  655. return null;
  656. }
  657. @Override
  658. protected void sendContextClickEvent(MouseEventDetails details,
  659. EventTarget eventTarget) {
  660. // if element is the resize indicator, ignore the event
  661. if (isResizeHandle(eventTarget)) {
  662. WidgetUtil.clearTextSelection();
  663. return;
  664. }
  665. EventCellReference<JsonObject> eventCell = getWidget().getEventCell();
  666. Section section = eventCell.getSection();
  667. String rowKey = null;
  668. if (eventCell.isBody() && eventCell.getRow() != null) {
  669. rowKey = getRowKey(eventCell.getRow());
  670. }
  671. String columnId = getColumnId(eventCell.getColumn());
  672. getRpcProxy(GridServerRpc.class).contextClick(eventCell.getRowIndex(),
  673. rowKey, columnId, section, details);
  674. WidgetUtil.clearTextSelection();
  675. }
  676. private boolean isResizeHandle(EventTarget eventTarget) {
  677. if (Element.is(eventTarget)) {
  678. Element e = Element.as(eventTarget);
  679. if (e.getClassName().contains("-column-resize-handle")) {
  680. return true;
  681. }
  682. }
  683. return false;
  684. }
  685. private List<String> mapColumnsToIds(List<Column<?, JsonObject>> columns) {
  686. return columns.stream().map(this::getColumnId).filter(Objects::nonNull)
  687. .collect(Collectors.toList());
  688. }
  689. }