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.

TableConnector.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.Iterator;
  6. import com.google.gwt.core.client.GWT;
  7. import com.google.gwt.core.client.Scheduler;
  8. import com.google.gwt.core.client.Scheduler.ScheduledCommand;
  9. import com.google.gwt.dom.client.Style.Position;
  10. import com.google.gwt.user.client.Command;
  11. import com.google.gwt.user.client.ui.Widget;
  12. import com.vaadin.terminal.gwt.client.AbstractFieldState;
  13. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  14. import com.vaadin.terminal.gwt.client.BrowserInfo;
  15. import com.vaadin.terminal.gwt.client.ComponentConnector;
  16. import com.vaadin.terminal.gwt.client.DirectionalManagedLayout;
  17. import com.vaadin.terminal.gwt.client.Paintable;
  18. import com.vaadin.terminal.gwt.client.UIDL;
  19. import com.vaadin.terminal.gwt.client.Util;
  20. import com.vaadin.terminal.gwt.client.ui.VScrollTable.ContextMenuDetails;
  21. import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
  22. @Component(com.vaadin.ui.Table.class)
  23. public class TableConnector extends AbstractComponentContainerConnector
  24. implements Paintable, DirectionalManagedLayout, PostLayoutListener {
  25. @Override
  26. protected void init() {
  27. super.init();
  28. getWidget().init(getConnection());
  29. }
  30. /*
  31. * (non-Javadoc)
  32. *
  33. * @see
  34. * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
  35. * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
  36. */
  37. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  38. getWidget().rendering = true;
  39. // If a row has an open context menu, it will be closed as the row is
  40. // detached. Retain a reference here so we can restore the menu if
  41. // required.
  42. ContextMenuDetails contextMenuBeforeUpdate = getWidget().contextMenu;
  43. if (uidl.hasAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST)) {
  44. getWidget().serverCacheFirst = uidl
  45. .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST);
  46. getWidget().serverCacheLast = uidl
  47. .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_LAST);
  48. } else {
  49. getWidget().serverCacheFirst = -1;
  50. getWidget().serverCacheLast = -1;
  51. }
  52. /*
  53. * We need to do this before updateComponent since updateComponent calls
  54. * this.setHeight() which will calculate a new body height depending on
  55. * the space available.
  56. */
  57. if (uidl.hasAttribute("colfooters")) {
  58. getWidget().showColFooters = uidl.getBooleanAttribute("colfooters");
  59. }
  60. getWidget().tFoot.setVisible(getWidget().showColFooters);
  61. if (!isRealUpdate(uidl)) {
  62. getWidget().rendering = false;
  63. return;
  64. }
  65. getWidget().enabled = isEnabled();
  66. if (BrowserInfo.get().isIE8() && !getWidget().enabled) {
  67. /*
  68. * The disabled shim will not cover the table body if it is relative
  69. * in IE8. See #7324
  70. */
  71. getWidget().scrollBodyPanel.getElement().getStyle()
  72. .setPosition(Position.STATIC);
  73. } else if (BrowserInfo.get().isIE8()) {
  74. getWidget().scrollBodyPanel.getElement().getStyle()
  75. .setPosition(Position.RELATIVE);
  76. }
  77. getWidget().paintableId = uidl.getStringAttribute("id");
  78. getWidget().immediate = getState().isImmediate();
  79. int previousTotalRows = getWidget().totalRows;
  80. getWidget().updateTotalRows(uidl);
  81. boolean totalRowsChanged = (getWidget().totalRows != previousTotalRows);
  82. getWidget().updateDragMode(uidl);
  83. getWidget().updateSelectionProperties(uidl, getState(), isReadOnly());
  84. if (uidl.hasAttribute("alb")) {
  85. getWidget().bodyActionKeys = uidl.getStringArrayAttribute("alb");
  86. } else {
  87. // Need to clear the actions if the action handlers have been
  88. // removed
  89. getWidget().bodyActionKeys = null;
  90. }
  91. getWidget().setCacheRateFromUIDL(uidl);
  92. getWidget().recalcWidths = uidl.hasAttribute("recalcWidths");
  93. if (getWidget().recalcWidths) {
  94. getWidget().tHead.clear();
  95. getWidget().tFoot.clear();
  96. }
  97. getWidget().updatePageLength(uidl);
  98. getWidget().updateFirstVisibleAndScrollIfNeeded(uidl);
  99. getWidget().showRowHeaders = uidl.getBooleanAttribute("rowheaders");
  100. getWidget().showColHeaders = uidl.getBooleanAttribute("colheaders");
  101. getWidget().updateSortingProperties(uidl);
  102. boolean keyboardSelectionOverRowFetchInProgress = getWidget()
  103. .selectSelectedRows(uidl);
  104. getWidget().updateActionMap(uidl);
  105. getWidget().updateColumnProperties(uidl);
  106. UIDL ac = uidl.getChildByTagName("-ac");
  107. if (ac == null) {
  108. if (getWidget().dropHandler != null) {
  109. // remove dropHandler if not present anymore
  110. getWidget().dropHandler = null;
  111. }
  112. } else {
  113. if (getWidget().dropHandler == null) {
  114. getWidget().dropHandler = getWidget().new VScrollTableDropHandler();
  115. }
  116. getWidget().dropHandler.updateAcceptRules(ac);
  117. }
  118. UIDL partialRowAdditions = uidl.getChildByTagName("prows");
  119. UIDL partialRowUpdates = uidl.getChildByTagName("urows");
  120. if (partialRowUpdates != null || partialRowAdditions != null) {
  121. // we may have pending cache row fetch, cancel it. See #2136
  122. getWidget().rowRequestHandler.cancel();
  123. getWidget().updateRowsInBody(partialRowUpdates);
  124. getWidget().addAndRemoveRows(partialRowAdditions);
  125. } else {
  126. UIDL rowData = uidl.getChildByTagName("rows");
  127. if (rowData != null) {
  128. // we may have pending cache row fetch, cancel it. See #2136
  129. getWidget().rowRequestHandler.cancel();
  130. if (!getWidget().recalcWidths
  131. && getWidget().initializedAndAttached) {
  132. getWidget().updateBody(rowData,
  133. uidl.getIntAttribute("firstrow"),
  134. uidl.getIntAttribute("rows"));
  135. if (getWidget().headerChangedDuringUpdate) {
  136. getWidget().triggerLazyColumnAdjustment(true);
  137. } else if (!getWidget().isScrollPositionVisible()
  138. || totalRowsChanged
  139. || getWidget().lastRenderedHeight != getWidget().scrollBody
  140. .getOffsetHeight()) {
  141. // webkits may still bug with their disturbing scrollbar
  142. // bug, see #3457
  143. // Run overflow fix for the scrollable area
  144. // #6698 - If there's a scroll going on, don't abort it
  145. // by changing overflows as the length of the contents
  146. // *shouldn't* have changed (unless the number of rows
  147. // or the height of the widget has also changed)
  148. Scheduler.get().scheduleDeferred(new Command() {
  149. public void execute() {
  150. Util.runWebkitOverflowAutoFix(getWidget().scrollBodyPanel
  151. .getElement());
  152. }
  153. });
  154. }
  155. } else {
  156. getWidget().initializeRows(uidl, rowData);
  157. }
  158. }
  159. }
  160. // If a row had an open context menu before the update, and after the
  161. // update there's a row with the same key as that row, restore the
  162. // context menu. See #8526.
  163. showSavedContextMenu(contextMenuBeforeUpdate);
  164. if (!getWidget().isSelectable()) {
  165. getWidget().scrollBody.addStyleName(VScrollTable.CLASSNAME
  166. + "-body-noselection");
  167. } else {
  168. getWidget().scrollBody.removeStyleName(VScrollTable.CLASSNAME
  169. + "-body-noselection");
  170. }
  171. getWidget().hideScrollPositionAnnotation();
  172. // selection is no in sync with server, avoid excessive server visits by
  173. // clearing to flag used during the normal operation
  174. if (!keyboardSelectionOverRowFetchInProgress) {
  175. getWidget().selectionChanged = false;
  176. }
  177. /*
  178. * This is called when the Home or page up button has been pressed in
  179. * selectable mode and the next selected row was not yet rendered in the
  180. * client
  181. */
  182. if (getWidget().selectFirstItemInNextRender
  183. || getWidget().focusFirstItemInNextRender) {
  184. getWidget().selectFirstRenderedRowInViewPort(
  185. getWidget().focusFirstItemInNextRender);
  186. getWidget().selectFirstItemInNextRender = getWidget().focusFirstItemInNextRender = false;
  187. }
  188. /*
  189. * This is called when the page down or end button has been pressed in
  190. * selectable mode and the next selected row was not yet rendered in the
  191. * client
  192. */
  193. if (getWidget().selectLastItemInNextRender
  194. || getWidget().focusLastItemInNextRender) {
  195. getWidget().selectLastRenderedRowInViewPort(
  196. getWidget().focusLastItemInNextRender);
  197. getWidget().selectLastItemInNextRender = getWidget().focusLastItemInNextRender = false;
  198. }
  199. getWidget().multiselectPending = false;
  200. if (getWidget().focusedRow != null) {
  201. if (!getWidget().focusedRow.isAttached()
  202. && !getWidget().rowRequestHandler.isRunning()) {
  203. // focused row has been orphaned, can't focus
  204. getWidget().focusRowFromBody();
  205. }
  206. }
  207. getWidget().tabIndex = uidl.hasAttribute("tabindex") ? uidl
  208. .getIntAttribute("tabindex") : 0;
  209. getWidget().setProperTabIndex();
  210. getWidget().resizeSortedColumnForSortIndicator();
  211. // Remember this to detect situations where overflow hack might be
  212. // needed during scrolling
  213. getWidget().lastRenderedHeight = getWidget().scrollBody
  214. .getOffsetHeight();
  215. getWidget().rendering = false;
  216. getWidget().headerChangedDuringUpdate = false;
  217. }
  218. @Override
  219. protected Widget createWidget() {
  220. return GWT.create(VScrollTable.class);
  221. }
  222. @Override
  223. public VScrollTable getWidget() {
  224. return (VScrollTable) super.getWidget();
  225. }
  226. public void updateCaption(ComponentConnector component) {
  227. // NOP, not rendered
  228. }
  229. public void layoutVertically() {
  230. getWidget().updateHeight();
  231. }
  232. public void layoutHorizontally() {
  233. getWidget().updateWidth();
  234. }
  235. public void postLayout() {
  236. VScrollTable table = getWidget();
  237. if (table.sizeNeedsInit) {
  238. table.sizeInit();
  239. Scheduler.get().scheduleFinally(new ScheduledCommand() {
  240. public void execute() {
  241. getLayoutManager().setNeedsUpdate(TableConnector.this);
  242. getLayoutManager().layoutNow();
  243. }
  244. });
  245. }
  246. }
  247. @Override
  248. public boolean isReadOnly() {
  249. return super.isReadOnly() || getState().isPropertyReadOnly();
  250. }
  251. @Override
  252. public AbstractFieldState getState() {
  253. return (AbstractFieldState) super.getState();
  254. }
  255. /**
  256. * Shows a saved row context menu if the row for the context menu is still
  257. * visible. Does nothing if a context menu has not been saved.
  258. *
  259. * @param savedContextMenu
  260. */
  261. public void showSavedContextMenu(ContextMenuDetails savedContextMenu) {
  262. if (isEnabled() && savedContextMenu != null) {
  263. Iterator<Widget> iterator = getWidget().scrollBody.iterator();
  264. while (iterator.hasNext()) {
  265. Widget w = iterator.next();
  266. VScrollTableRow row = (VScrollTableRow) w;
  267. if (row.getKey().equals(savedContextMenu.rowKey)) {
  268. getWidget().contextMenu = savedContextMenu;
  269. getConnection().getContextMenu().showAt(row,
  270. savedContextMenu.left, savedContextMenu.top);
  271. }
  272. }
  273. }
  274. }
  275. }