Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.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.connectors.AbstractListingConnector;
  42. import com.vaadin.client.connectors.grid.ColumnConnector.CustomColumn;
  43. import com.vaadin.client.data.DataSource;
  44. import com.vaadin.client.ui.SimpleManagedLayout;
  45. import com.vaadin.client.widget.escalator.RowContainer;
  46. import com.vaadin.client.widget.grid.CellReference;
  47. import com.vaadin.client.widget.grid.EventCellReference;
  48. import com.vaadin.client.widget.grid.events.BodyClickHandler;
  49. import com.vaadin.client.widget.grid.events.BodyDoubleClickHandler;
  50. import com.vaadin.client.widget.grid.events.GridClickEvent;
  51. import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
  52. import com.vaadin.client.widget.grid.sort.SortEvent;
  53. import com.vaadin.client.widget.grid.sort.SortOrder;
  54. import com.vaadin.client.widgets.Grid;
  55. import com.vaadin.client.widgets.Grid.Column;
  56. import com.vaadin.client.widgets.Grid.FooterRow;
  57. import com.vaadin.client.widgets.Grid.HeaderRow;
  58. import com.vaadin.shared.MouseEventDetails;
  59. import com.vaadin.shared.data.sort.SortDirection;
  60. import com.vaadin.shared.ui.Connect;
  61. import com.vaadin.shared.ui.grid.GridClientRpc;
  62. import com.vaadin.shared.ui.grid.GridConstants;
  63. import com.vaadin.shared.ui.grid.GridConstants.Section;
  64. import com.vaadin.shared.ui.grid.GridServerRpc;
  65. import com.vaadin.shared.ui.grid.GridState;
  66. import com.vaadin.shared.ui.grid.ScrollDestination;
  67. import com.vaadin.shared.ui.grid.SectionState;
  68. import com.vaadin.shared.ui.grid.SectionState.CellState;
  69. import com.vaadin.shared.ui.grid.SectionState.RowState;
  70. import elemental.json.JsonObject;
  71. /**
  72. * A connector class for the typed Grid component.
  73. *
  74. * @author Vaadin Ltd
  75. * @since 8.0
  76. */
  77. @Connect(com.vaadin.ui.Grid.class)
  78. public class GridConnector extends AbstractListingConnector
  79. implements HasComponentsConnector, SimpleManagedLayout, DeferredWorker {
  80. private Set<Runnable> refreshDetailsCallbacks = new HashSet<>();
  81. private class ItemClickHandler
  82. implements BodyClickHandler, BodyDoubleClickHandler {
  83. @Override
  84. public void onClick(GridClickEvent event) {
  85. if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
  86. fireItemClick(event.getTargetCell(), event.getNativeEvent());
  87. }
  88. }
  89. @Override
  90. public void onDoubleClick(GridDoubleClickEvent event) {
  91. if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
  92. fireItemClick(event.getTargetCell(), event.getNativeEvent());
  93. }
  94. }
  95. private void fireItemClick(CellReference<?> cell,
  96. NativeEvent mouseEvent) {
  97. String rowKey = getRowKey((JsonObject) cell.getRow());
  98. String columnId = columnToIdMap.get(cell.getColumn());
  99. getRpcProxy(GridServerRpc.class).itemClick(rowKey, columnId,
  100. MouseEventDetailsBuilder
  101. .buildMouseEventDetails(mouseEvent));
  102. }
  103. }
  104. /* Map to keep track of all added columns */
  105. private Map<CustomColumn, String> columnToIdMap = new HashMap<>();
  106. private Map<String, CustomColumn> idToColumn = new HashMap<>();
  107. /* Child component list for HasComponentsConnector */
  108. private List<ComponentConnector> childComponents;
  109. private ItemClickHandler itemClickHandler = new ItemClickHandler();
  110. private boolean rowHeightScheduled = false;
  111. /**
  112. * Gets the string identifier of the given column in this grid.
  113. *
  114. * @param column
  115. * the column whose id to get
  116. * @return the string id of the column
  117. */
  118. public String getColumnId(Column<?, ?> column) {
  119. return columnToIdMap.get(column);
  120. }
  121. /**
  122. * Gets the column corresponding to the given string identifier.
  123. *
  124. * @param columnId
  125. * the id of the column to get
  126. * @return the column with the given id
  127. */
  128. public CustomColumn getColumn(String columnId) {
  129. return idToColumn.get(columnId);
  130. }
  131. @Override
  132. @SuppressWarnings("unchecked")
  133. public Grid<JsonObject> getWidget() {
  134. return (Grid<JsonObject>) super.getWidget();
  135. }
  136. /**
  137. * Method called for a row details refresh. Runs all callbacks if any
  138. * details were shown and clears the callbacks.
  139. *
  140. * @param detailsShown
  141. * True if any details were set visible
  142. */
  143. protected void detailsRefreshed(boolean detailsShown) {
  144. if (detailsShown) {
  145. refreshDetailsCallbacks.forEach(Runnable::run);
  146. }
  147. refreshDetailsCallbacks.clear();
  148. }
  149. /**
  150. * Method target for when one single details has been updated and we might
  151. * need to scroll it into view.
  152. *
  153. * @param rowIndex
  154. * index of updated row
  155. */
  156. protected void singleDetailsOpened(int rowIndex) {
  157. addDetailsRefreshCallback(() -> {
  158. if (rowHasDetails(rowIndex)) {
  159. getWidget().scrollToRow(rowIndex);
  160. }
  161. });
  162. }
  163. /**
  164. * Add a single use details runnable callback for when we get a call to
  165. * {@link #detailsRefreshed(boolean)}.
  166. *
  167. * @param refreshCallback
  168. * Details refreshed callback
  169. */
  170. private void addDetailsRefreshCallback(Runnable refreshCallback) {
  171. refreshDetailsCallbacks.add(refreshCallback);
  172. }
  173. /**
  174. * Check if we have details for given row.
  175. *
  176. * @param rowIndex
  177. * @return
  178. */
  179. private boolean rowHasDetails(int rowIndex) {
  180. JsonObject row = getWidget().getDataSource().getRow(rowIndex);
  181. return row != null && row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)
  182. && !row.getString(GridState.JSONKEY_DETAILS_VISIBLE).isEmpty();
  183. }
  184. @Override
  185. protected void init() {
  186. super.init();
  187. updateWidgetStyleNames();
  188. // Remove default headers when initializing Grid widget
  189. while (getWidget().getHeaderRowCount() > 0) {
  190. getWidget().removeHeaderRow(0);
  191. }
  192. registerRpc(GridClientRpc.class, new GridClientRpc() {
  193. @Override
  194. public void scrollToRow(int row, ScrollDestination destination) {
  195. Scheduler.get().scheduleFinally(
  196. () -> getWidget().scrollToRow(row, destination));
  197. // Add details refresh listener and handle possible detail for
  198. // scrolled row.
  199. addDetailsRefreshCallback(() -> {
  200. if (rowHasDetails(row)) {
  201. getWidget().scrollToRow(row, destination);
  202. }
  203. });
  204. }
  205. @Override
  206. public void scrollToStart() {
  207. Scheduler.get()
  208. .scheduleFinally(() -> getWidget().scrollToStart());
  209. }
  210. @Override
  211. public void scrollToEnd() {
  212. Scheduler.get()
  213. .scheduleFinally(() -> getWidget().scrollToEnd());
  214. addDetailsRefreshCallback(() -> {
  215. if (rowHasDetails(getWidget().getDataSource().size() - 1)) {
  216. getWidget().scrollToEnd();
  217. }
  218. });
  219. }
  220. @Override
  221. public void recalculateColumnWidths() {
  222. getWidget().recalculateColumnWidths();
  223. }
  224. });
  225. getWidget().addSortHandler(this::handleSortEvent);
  226. getWidget().setRowStyleGenerator(rowRef -> {
  227. JsonObject json = rowRef.getRow();
  228. return json.hasKey(GridState.JSONKEY_ROWSTYLE)
  229. ? json.getString(GridState.JSONKEY_ROWSTYLE)
  230. : null;
  231. });
  232. getWidget().setCellStyleGenerator(cellRef -> {
  233. JsonObject row = cellRef.getRow();
  234. if (!row.hasKey(GridState.JSONKEY_CELLSTYLES)) {
  235. return null;
  236. }
  237. Column<?, JsonObject> column = cellRef.getColumn();
  238. if (column instanceof CustomColumn) {
  239. String id = ((CustomColumn) column).getConnectorId();
  240. JsonObject cellStyles = row
  241. .getObject(GridState.JSONKEY_CELLSTYLES);
  242. if (cellStyles.hasKey(id)) {
  243. return cellStyles.getString(id);
  244. }
  245. }
  246. return null;
  247. });
  248. getWidget().addColumnVisibilityChangeHandler(event -> {
  249. if (event.isUserOriginated()) {
  250. getRpcProxy(GridServerRpc.class).columnVisibilityChanged(
  251. getColumnId(event.getColumn()), event.isHidden());
  252. }
  253. });
  254. getWidget().addColumnReorderHandler(event -> {
  255. if (event.isUserOriginated()) {
  256. List<String> newColumnOrder = mapColumnsToIds(
  257. event.getNewColumnOrder());
  258. List<String> oldColumnOrder = mapColumnsToIds(
  259. event.getOldColumnOrder());
  260. getRpcProxy(GridServerRpc.class)
  261. .columnsReordered(newColumnOrder, oldColumnOrder);
  262. }
  263. });
  264. getWidget().addColumnResizeHandler(event -> {
  265. Column<?, JsonObject> column = event.getColumn();
  266. getRpcProxy(GridServerRpc.class).columnResized(getColumnId(column),
  267. column.getWidthActual());
  268. });
  269. // Handling row height changes
  270. getWidget().addRowHeightChangedHandler(event -> {
  271. getLayoutManager().setNeedsMeasureRecursively(GridConnector.this);
  272. getLayoutManager().layoutNow();
  273. });
  274. /* Item click events */
  275. getWidget().addBodyClickHandler(itemClickHandler);
  276. getWidget().addBodyDoubleClickHandler(itemClickHandler);
  277. layout();
  278. }
  279. @SuppressWarnings("unchecked")
  280. @OnStateChange("columnOrder")
  281. void updateColumnOrder() {
  282. Scheduler.get()
  283. .scheduleFinally(() -> getWidget().setColumnOrder(
  284. getState().columnOrder.stream().map(this::getColumn)
  285. .toArray(size -> new Column[size])));
  286. }
  287. @OnStateChange("columnResizeMode")
  288. void updateColumnResizeMode() {
  289. getWidget().setColumnResizeMode(getState().columnResizeMode);
  290. }
  291. /**
  292. * Updates the grid header section on state change.
  293. */
  294. @OnStateChange("header")
  295. void updateHeader() {
  296. final Grid<JsonObject> grid = getWidget();
  297. final SectionState state = getState().header;
  298. while (grid.getHeaderRowCount() > 0) {
  299. grid.removeHeaderRow(0);
  300. }
  301. for (RowState rowState : state.rows) {
  302. HeaderRow row = grid.appendHeaderRow();
  303. if (rowState.defaultHeader) {
  304. grid.setDefaultHeaderRow(row);
  305. }
  306. updateStaticRow(rowState, row);
  307. }
  308. grid.setHeaderVisible(state.visible);
  309. }
  310. @OnStateChange({ "bodyRowHeight", "headerRowHeight", "footerRowHeight" })
  311. void updateRowHeight() {
  312. if (rowHeightScheduled) {
  313. return;
  314. }
  315. Scheduler.get().scheduleFinally(() -> {
  316. GridState state = getState();
  317. if (getWidget().isAttached() && rowHeightNeedsReset()) {
  318. getWidget().resetSizesFromDom();
  319. }
  320. updateContainerRowHeigth(getWidget().getEscalator().getBody(),
  321. state.bodyRowHeight);
  322. updateContainerRowHeigth(getWidget().getEscalator().getHeader(),
  323. state.headerRowHeight);
  324. updateContainerRowHeigth(getWidget().getEscalator().getFooter(),
  325. state.footerRowHeight);
  326. rowHeightScheduled = false;
  327. });
  328. rowHeightScheduled = true;
  329. }
  330. private boolean rowHeightNeedsReset() {
  331. GridState state = getState();
  332. // Body
  333. boolean bodyAutoCalc = state.bodyRowHeight < 0;
  334. // Header
  335. boolean headerAutoCalc = state.headerRowHeight < 0;
  336. boolean headerReset = headerAutoCalc && hasVisibleContent(state.header);
  337. // Footer
  338. boolean footerAutoCalc = state.footerRowHeight < 0;
  339. boolean footerReset = footerAutoCalc && hasVisibleContent(state.footer);
  340. return bodyAutoCalc || headerReset || footerReset;
  341. }
  342. private boolean hasVisibleContent(SectionState state) {
  343. return state.visible && !state.rows.isEmpty();
  344. }
  345. private void updateContainerRowHeigth(RowContainer container,
  346. double height) {
  347. if (height >= 0) {
  348. container.setDefaultRowHeight(height);
  349. }
  350. }
  351. private void updateStaticRow(RowState rowState,
  352. Grid.StaticSection.StaticRow row) {
  353. rowState.cells
  354. .forEach((columnId, cellState) -> updateStaticCellFromState(
  355. row.getCell(getColumn(columnId)), cellState));
  356. for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups
  357. .entrySet()) {
  358. Set<String> group = cellGroupEntry.getValue();
  359. Grid.Column<?, ?>[] columns = group.stream().map(idToColumn::get)
  360. .toArray(size -> new Grid.Column<?, ?>[size]);
  361. // Set state to be the same as first in group.
  362. updateStaticCellFromState(row.join(columns),
  363. cellGroupEntry.getKey());
  364. }
  365. row.setStyleName(rowState.styleName);
  366. }
  367. private void updateStaticCellFromState(Grid.StaticSection.StaticCell cell,
  368. CellState cellState) {
  369. switch (cellState.type) {
  370. case TEXT:
  371. cell.setText(cellState.text);
  372. break;
  373. case HTML:
  374. cell.setHtml(cellState.html);
  375. break;
  376. case WIDGET:
  377. ComponentConnector connector = (ComponentConnector) cellState.connector;
  378. if (connector != null) {
  379. cell.setWidget(connector.getWidget());
  380. } else {
  381. // This happens if you do setVisible(false) on the component on
  382. // the server side
  383. cell.setWidget(null);
  384. }
  385. break;
  386. default:
  387. throw new IllegalStateException(
  388. "unexpected cell type: " + cellState.type);
  389. }
  390. cell.setStyleName(cellState.styleName);
  391. }
  392. /**
  393. * Updates the grid footer section on state change.
  394. */
  395. @OnStateChange("footer")
  396. void updateFooter() {
  397. final Grid<JsonObject> grid = getWidget();
  398. final SectionState state = getState().footer;
  399. while (grid.getFooterRowCount() > 0) {
  400. grid.removeFooterRow(0);
  401. }
  402. for (RowState rowState : state.rows) {
  403. FooterRow row = grid.appendFooterRow();
  404. updateStaticRow(rowState, row);
  405. }
  406. grid.setFooterVisible(state.visible);
  407. }
  408. @OnStateChange({ "sortColumns", "sortDirs" })
  409. void updateSortOrder() {
  410. List<SortOrder> sortOrder = new ArrayList<SortOrder>();
  411. String[] sortColumns = getState().sortColumns;
  412. SortDirection[] sortDirs = getState().sortDirs;
  413. for (int i = 0; i < sortColumns.length; i++) {
  414. sortOrder
  415. .add(new SortOrder(getColumn(sortColumns[i]), sortDirs[i]));
  416. }
  417. getWidget().setSortOrder(sortOrder);
  418. }
  419. @Override
  420. public void setDataSource(DataSource<JsonObject> dataSource) {
  421. super.setDataSource(dataSource);
  422. getWidget().setDataSource(dataSource);
  423. }
  424. /**
  425. * Adds a column to the Grid widget. For each column a communication id
  426. * stored for client to server communication.
  427. *
  428. * @param column
  429. * column to add
  430. * @param id
  431. * communication id
  432. */
  433. public void addColumn(CustomColumn column, String id) {
  434. assert !columnToIdMap.containsKey(column) && !columnToIdMap
  435. .containsValue(id) : "Column with given id already exists.";
  436. getWidget().addColumn(column);
  437. columnToIdMap.put(column, id);
  438. idToColumn.put(id, column);
  439. }
  440. /**
  441. * Removes a column from Grid widget. This method also removes communication
  442. * id mapping for the column.
  443. *
  444. * @param column
  445. * column to remove
  446. */
  447. public void removeColumn(CustomColumn column) {
  448. assert columnToIdMap
  449. .containsKey(column) : "Given Column does not exist.";
  450. getWidget().removeColumn(column);
  451. String id = columnToIdMap.remove(column);
  452. idToColumn.remove(id);
  453. }
  454. /**
  455. * Method called by {@code CustomColumn} when its renderer changes. This
  456. * method is used to maintain hierarchical renderer wrap in
  457. * {@code TreeGrid}.
  458. *
  459. * @param column
  460. * the column which now has a new renderer
  461. *
  462. * @since 8.1
  463. */
  464. public void onColumnRendererChanged(CustomColumn column) {
  465. // NO-OP
  466. }
  467. @Override
  468. public void onUnregister() {
  469. super.onUnregister();
  470. }
  471. @Override
  472. public boolean isWorkPending() {
  473. return getWidget().isWorkPending();
  474. }
  475. @Override
  476. public void layout() {
  477. getWidget().onResize();
  478. }
  479. /**
  480. * Sends sort information from an event to the server-side of the Grid.
  481. *
  482. * @param event
  483. * the sort event
  484. */
  485. private void handleSortEvent(SortEvent<JsonObject> event) {
  486. List<String> columnIds = new ArrayList<>();
  487. List<SortDirection> sortDirections = new ArrayList<>();
  488. for (SortOrder so : event.getOrder()) {
  489. if (columnToIdMap.containsKey(so.getColumn())) {
  490. columnIds.add(columnToIdMap.get(so.getColumn()));
  491. sortDirections.add(so.getDirection());
  492. }
  493. }
  494. String[] colArray = columnIds.toArray(new String[0]);
  495. SortDirection[] dirArray = sortDirections.toArray(new SortDirection[0]);
  496. if (!Arrays.equals(colArray, getState().sortColumns)
  497. || !Arrays.equals(dirArray, getState().sortDirs)) {
  498. // State has actually changed, send to server
  499. getRpcProxy(GridServerRpc.class).sort(colArray, dirArray,
  500. event.isUserOriginated());
  501. }
  502. }
  503. /* HasComponentsConnector */
  504. @Override
  505. public void updateCaption(ComponentConnector connector) {
  506. // Details components don't support captions.
  507. }
  508. @Override
  509. public List<ComponentConnector> getChildComponents() {
  510. if (childComponents == null) {
  511. return Collections.emptyList();
  512. }
  513. return childComponents;
  514. }
  515. @Override
  516. public void setChildComponents(List<ComponentConnector> children) {
  517. childComponents = children;
  518. }
  519. @Override
  520. public HandlerRegistration addConnectorHierarchyChangeHandler(
  521. ConnectorHierarchyChangeHandler handler) {
  522. return ensureHandlerManager()
  523. .addHandler(ConnectorHierarchyChangeEvent.TYPE, handler);
  524. }
  525. @Override
  526. public GridState getState() {
  527. return (GridState) super.getState();
  528. }
  529. @Override
  530. public boolean hasTooltip() {
  531. // Always check for generated descriptions.
  532. return true;
  533. }
  534. @Override
  535. public TooltipInfo getTooltipInfo(Element element) {
  536. CellReference<JsonObject> cell = getWidget().getCellReference(element);
  537. if (cell != null) {
  538. JsonObject row = cell.getRow();
  539. if (row != null && (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)
  540. || row.hasKey(GridState.JSONKEY_CELLDESCRIPTION))) {
  541. Column<?, JsonObject> column = cell.getColumn();
  542. if (column instanceof CustomColumn) {
  543. JsonObject cellDescriptions = row
  544. .getObject(GridState.JSONKEY_CELLDESCRIPTION);
  545. String id = ((CustomColumn) column).getConnectorId();
  546. if (cellDescriptions != null
  547. && cellDescriptions.hasKey(id)) {
  548. return new TooltipInfo(cellDescriptions.getString(id));
  549. } else if (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)) {
  550. return new TooltipInfo(row
  551. .getString(GridState.JSONKEY_ROWDESCRIPTION));
  552. }
  553. }
  554. }
  555. }
  556. if (super.hasTooltip()) {
  557. return super.getTooltipInfo(element);
  558. } else {
  559. return null;
  560. }
  561. }
  562. @Override
  563. protected void sendContextClickEvent(MouseEventDetails details,
  564. EventTarget eventTarget) {
  565. // if element is the resize indicator, ignore the event
  566. if (isResizeHandle(eventTarget)) {
  567. WidgetUtil.clearTextSelection();
  568. return;
  569. }
  570. EventCellReference<JsonObject> eventCell = getWidget().getEventCell();
  571. Section section = eventCell.getSection();
  572. String rowKey = null;
  573. if (eventCell.isBody() && eventCell.getRow() != null) {
  574. rowKey = getRowKey(eventCell.getRow());
  575. }
  576. String columnId = getColumnId(eventCell.getColumn());
  577. getRpcProxy(GridServerRpc.class).contextClick(eventCell.getRowIndex(),
  578. rowKey, columnId, section, details);
  579. WidgetUtil.clearTextSelection();
  580. }
  581. private boolean isResizeHandle(EventTarget eventTarget) {
  582. if (Element.is(eventTarget)) {
  583. Element e = Element.as(eventTarget);
  584. if (e.getClassName().contains("-column-resize-handle")) {
  585. return true;
  586. }
  587. }
  588. return false;
  589. }
  590. private List<String> mapColumnsToIds(List<Column<?, JsonObject>> columns) {
  591. return columns.stream().map(this::getColumnId).filter(Objects::nonNull)
  592. .collect(Collectors.toList());
  593. }
  594. }