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.

AbstractComponentConnector.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.Set;
  6. import com.google.gwt.user.client.ui.Focusable;
  7. import com.google.gwt.user.client.ui.HasEnabled;
  8. import com.google.gwt.user.client.ui.Widget;
  9. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  10. import com.vaadin.terminal.gwt.client.ComponentConnector;
  11. import com.vaadin.terminal.gwt.client.ComponentContainerConnector;
  12. import com.vaadin.terminal.gwt.client.ComponentState;
  13. import com.vaadin.terminal.gwt.client.ConnectorMap;
  14. import com.vaadin.terminal.gwt.client.LayoutManager;
  15. import com.vaadin.terminal.gwt.client.TooltipInfo;
  16. import com.vaadin.terminal.gwt.client.UIDL;
  17. import com.vaadin.terminal.gwt.client.Util;
  18. import com.vaadin.terminal.gwt.client.VConsole;
  19. import com.vaadin.terminal.gwt.client.communication.SharedState;
  20. import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
  21. import com.vaadin.terminal.gwt.client.ui.root.RootConnector;
  22. public abstract class AbstractComponentConnector extends AbstractConnector
  23. implements ComponentConnector {
  24. private ComponentContainerConnector parent;
  25. private Widget widget;
  26. // shared state from the server to the client
  27. private ComponentState state;
  28. private String lastKnownWidth = "";
  29. private String lastKnownHeight = "";
  30. /**
  31. * Default constructor
  32. */
  33. public AbstractComponentConnector() {
  34. }
  35. /**
  36. * Creates and returns the widget for this VPaintableWidget. This method
  37. * should only be called once when initializing the paintable.
  38. *
  39. * @return
  40. */
  41. protected abstract Widget createWidget();
  42. /**
  43. * Returns the widget associated with this paintable. The widget returned by
  44. * this method must not changed during the life time of the paintable.
  45. *
  46. * @return The widget associated with this paintable
  47. */
  48. public Widget getWidget() {
  49. if (widget == null) {
  50. widget = createWidget();
  51. }
  52. return widget;
  53. }
  54. /**
  55. * Returns the shared state object for this connector.
  56. *
  57. * If overriding this method to return a more specific type, also
  58. * {@link #createState()} must be overridden.
  59. *
  60. * @return current shared state (not null)
  61. */
  62. public ComponentState getState() {
  63. return state;
  64. }
  65. @Deprecated
  66. public static boolean isRealUpdate(UIDL uidl) {
  67. return !uidl.hasAttribute("cached");
  68. }
  69. @Override
  70. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  71. super.onStateChanged(stateChangeEvent);
  72. ConnectorMap paintableMap = ConnectorMap.get(getConnection());
  73. if (getState().getDebugId() != null) {
  74. getWidget().getElement().setId(getState().getDebugId());
  75. } else {
  76. getWidget().getElement().removeAttribute("id");
  77. }
  78. setWidgetEnabled(isEnabled());
  79. /*
  80. * Disabled state may affect (override) tabindex so the order must be
  81. * first setting tabindex, then enabled state.
  82. */
  83. if (state instanceof TabIndexState && getWidget() instanceof Focusable) {
  84. ((Focusable) getWidget()).setTabIndex(((TabIndexState) state)
  85. .getTabIndex());
  86. }
  87. // Style names
  88. String styleName = getStyleNames(getWidget().getStylePrimaryName());
  89. getWidget().setStyleName(styleName);
  90. // Update tooltip
  91. TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(this, null);
  92. if (getState().hasDescription()) {
  93. tooltipInfo.setTitle(getState().getDescription());
  94. } else {
  95. tooltipInfo.setTitle(null);
  96. }
  97. // add error info to tooltip if present
  98. tooltipInfo.setErrorMessage(getState().getErrorMessage());
  99. // Set captions
  100. if (delegateCaptionHandling()) {
  101. ComponentContainerConnector parent = getParent();
  102. if (parent != null) {
  103. parent.updateCaption(this);
  104. } else if (!(this instanceof RootConnector)) {
  105. VConsole.error("Parent of connector "
  106. + Util.getConnectorString(this)
  107. + " is null. This is typically an indication of a broken component hierarchy");
  108. }
  109. }
  110. /*
  111. * updateComponentSize need to be after caption update so caption can be
  112. * taken into account
  113. */
  114. updateComponentSize();
  115. }
  116. public void setWidgetEnabled(boolean widgetEnabled) {
  117. if (getWidget() instanceof HasEnabled) {
  118. HasEnabled hasEnabled = (HasEnabled) getWidget();
  119. if (hasEnabled.isEnabled() != widgetEnabled) {
  120. hasEnabled.setEnabled(widgetEnabled);
  121. }
  122. }
  123. }
  124. private void updateComponentSize() {
  125. String newWidth = getState().getWidth();
  126. String newHeight = getState().getHeight();
  127. // Parent should be updated if either dimension changed between relative
  128. // and non-relative
  129. if (newWidth.endsWith("%") != lastKnownWidth.endsWith("%")) {
  130. ComponentContainerConnector parent = getParent();
  131. if (parent instanceof ManagedLayout) {
  132. getLayoutManager().setNeedsHorizontalLayout(
  133. (ManagedLayout) parent);
  134. }
  135. }
  136. if (newHeight.endsWith("%") != lastKnownHeight.endsWith("%")) {
  137. ComponentContainerConnector parent = getParent();
  138. if (parent instanceof ManagedLayout) {
  139. getLayoutManager().setNeedsVerticalLayout(
  140. (ManagedLayout) parent);
  141. }
  142. }
  143. lastKnownWidth = newWidth;
  144. lastKnownHeight = newHeight;
  145. // Set defined sizes
  146. Widget widget = getWidget();
  147. widget.setStyleName("v-has-width", !isUndefinedWidth());
  148. widget.setStyleName("v-has-height", !isUndefinedHeight());
  149. widget.setHeight(newHeight);
  150. widget.setWidth(newWidth);
  151. }
  152. public boolean isRelativeHeight() {
  153. return getState().getHeight().endsWith("%");
  154. }
  155. public boolean isRelativeWidth() {
  156. return getState().getWidth().endsWith("%");
  157. }
  158. public boolean isUndefinedHeight() {
  159. return getState().getHeight().length() == 0;
  160. }
  161. public boolean isUndefinedWidth() {
  162. return getState().getWidth().length() == 0;
  163. }
  164. /*
  165. * (non-Javadoc)
  166. *
  167. * @see com.vaadin.terminal.gwt.client.Connector#isEnabled()
  168. */
  169. public boolean isEnabled() {
  170. if (!getState().isEnabled()) {
  171. return false;
  172. }
  173. if (getParent() == null) {
  174. return true;
  175. } else {
  176. return getParent().isEnabled();
  177. }
  178. }
  179. /*
  180. * (non-Javadoc)
  181. *
  182. * @see
  183. * com.vaadin.terminal.gwt.client.ComponentConnector#delegateCaptionHandling
  184. * ()
  185. */
  186. public boolean delegateCaptionHandling() {
  187. return true;
  188. }
  189. /**
  190. * Generates the style name for the widget based on the given primary style
  191. * name and the shared state.
  192. * <p>
  193. * This method can be overridden to provide additional style names for the
  194. * component
  195. * </p>
  196. *
  197. * @param primaryStyleName
  198. * The primary style name to use when generating the final style
  199. * names
  200. * @return The style names, settable using
  201. * {@link Widget#setStyleName(String)}
  202. */
  203. protected String getStyleNames(String primaryStyleName) {
  204. ComponentState state = getState();
  205. StringBuilder styleBuf = new StringBuilder();
  206. styleBuf.append(primaryStyleName);
  207. styleBuf.append(" v-connector");
  208. // Uses connector methods to enable connectors to take hierarchy or
  209. // multiple state variables into account
  210. if (!isEnabled()) {
  211. styleBuf.append(" ");
  212. styleBuf.append(ApplicationConnection.DISABLED_CLASSNAME);
  213. }
  214. if (isReadOnly()) {
  215. styleBuf.append(" ");
  216. styleBuf.append("v-readonly");
  217. }
  218. // add additional styles as css classes, prefixed with component default
  219. // stylename
  220. if (state.hasStyles()) {
  221. for (String style : state.getStyles()) {
  222. styleBuf.append(" ");
  223. styleBuf.append(primaryStyleName);
  224. styleBuf.append("-");
  225. styleBuf.append(style);
  226. styleBuf.append(" ");
  227. styleBuf.append(style);
  228. }
  229. }
  230. // add error classname to components w/ error
  231. if (null != state.getErrorMessage()) {
  232. styleBuf.append(" ");
  233. styleBuf.append(primaryStyleName);
  234. styleBuf.append(ApplicationConnection.ERROR_CLASSNAME_EXT);
  235. }
  236. return styleBuf.toString();
  237. }
  238. /*
  239. * (non-Javadoc)
  240. *
  241. * @see com.vaadin.terminal.gwt.client.ComponentConnector#isReadOnly()
  242. */
  243. @Deprecated
  244. public boolean isReadOnly() {
  245. return getState().isReadOnly();
  246. }
  247. /**
  248. * Sets the shared state for the paintable widget.
  249. *
  250. * @param new shared state (must be compatible with the return value of
  251. * {@link #getState()} - {@link ComponentState} if
  252. * {@link #getState()} is not overridden
  253. */
  254. public final void setState(SharedState state) {
  255. this.state = (ComponentState) state;
  256. }
  257. public LayoutManager getLayoutManager() {
  258. return LayoutManager.get(getConnection());
  259. }
  260. /*
  261. * (non-Javadoc)
  262. *
  263. * @see com.vaadin.terminal.gwt.client.Connector#getParent()
  264. */
  265. public ComponentContainerConnector getParent() {
  266. return parent;
  267. }
  268. /*
  269. * (non-Javadoc)
  270. *
  271. * @see
  272. * com.vaadin.terminal.gwt.client.Connector#setParent(com.vaadin.terminal
  273. * .gwt.client.ComponentContainerConnector)
  274. */
  275. public void setParent(ComponentContainerConnector parent) {
  276. this.parent = parent;
  277. }
  278. /**
  279. * Checks if there is a registered server side listener for the given event
  280. * identifier.
  281. *
  282. * @param eventIdentifier
  283. * The identifier to check for
  284. * @return true if an event listener has been registered with the given
  285. * event identifier on the server side, false otherwise
  286. */
  287. public boolean hasEventListener(String eventIdentifier) {
  288. Set<String> reg = getState().getRegisteredEventListeners();
  289. return (reg != null && reg.contains(eventIdentifier));
  290. }
  291. @Override
  292. public void onUnregister() {
  293. super.onUnregister();
  294. // Show an error if widget is still attached to DOM. It should never be
  295. // at this point.
  296. if (getWidget() != null && getWidget().isAttached()) {
  297. getWidget().removeFromParent();
  298. VConsole.error("Widget is still attached to the DOM after the connector ("
  299. + Util.getConnectorString(this)
  300. + ") has been unregistered. Widget was removed.");
  301. }
  302. }
  303. }