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.

VAbstractPaintableWidget.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import com.google.gwt.core.client.GWT;
  6. import com.google.gwt.user.client.DOM;
  7. import com.google.gwt.user.client.ui.FocusWidget;
  8. import com.google.gwt.user.client.ui.Focusable;
  9. import com.google.gwt.user.client.ui.Widget;
  10. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  11. import com.vaadin.terminal.gwt.client.ComponentState;
  12. import com.vaadin.terminal.gwt.client.TooltipInfo;
  13. import com.vaadin.terminal.gwt.client.UIDL;
  14. import com.vaadin.terminal.gwt.client.VPaintableMap;
  15. import com.vaadin.terminal.gwt.client.VPaintableWidget;
  16. import com.vaadin.terminal.gwt.client.VPaintableWidgetContainer;
  17. import com.vaadin.terminal.gwt.client.communication.SharedState;
  18. public abstract class VAbstractPaintableWidget implements VPaintableWidget {
  19. // Generic UIDL parameter names, to be moved to shared state.
  20. // Attributes are here mainly if they apply to all paintable widgets or
  21. // affect captions - otherwise, they are in the relevant subclasses.
  22. // For e.g. item or context specific attributes, subclasses may use separate
  23. // constants, which may refer to these.
  24. // Not all references to the string literals have been converted to use
  25. // these!
  26. public static final String ATTRIBUTE_ICON = "icon";
  27. public static final String ATTRIBUTE_CAPTION = "caption";
  28. public static final String ATTRIBUTE_DESCRIPTION = "description";
  29. public static final String ATTRIBUTE_REQUIRED = "required";
  30. public static final String ATTRIBUTE_ERROR = "error";
  31. public static final String ATTRIBUTE_HIDEERRORS = "hideErrors";
  32. public static final String ATTRIBUTE_READONLY = "readonly";
  33. public static final String ATTRIBUTE_IMMEDIATE = "immediate";
  34. public static final String ATTRIBUTE_DISABLED = "disabled";
  35. public static final String ATTRIBUTE_STYLE = "style";
  36. private Widget widget;
  37. private ApplicationConnection connection;
  38. private String id;
  39. /* State variables */
  40. private boolean enabled = true;
  41. private boolean visible = true;
  42. // shared state from the server to the client
  43. private ComponentState state;
  44. /**
  45. * Default constructor
  46. */
  47. public VAbstractPaintableWidget() {
  48. }
  49. /**
  50. * Called after the application connection reference has been set up
  51. */
  52. public void init() {
  53. }
  54. /**
  55. * Creates and returns the widget for this VPaintableWidget. This method
  56. * should only be called once when initializing the paintable.
  57. *
  58. * @return
  59. */
  60. protected abstract Widget createWidget();
  61. /**
  62. * Returns the widget associated with this paintable. The widget returned by
  63. * this method must not changed during the life time of the paintable.
  64. *
  65. * @return The widget associated with this paintable
  66. */
  67. public Widget getWidgetForPaintable() {
  68. if (widget == null) {
  69. widget = createWidget();
  70. }
  71. return widget;
  72. }
  73. /*
  74. * (non-Javadoc)
  75. *
  76. * @see com.vaadin.terminal.gwt.client.VPaintable#getConnection()
  77. */
  78. public final ApplicationConnection getConnection() {
  79. return connection;
  80. }
  81. /*
  82. * (non-Javadoc)
  83. *
  84. * @see
  85. * com.vaadin.terminal.gwt.client.VPaintable#setConnection(com.vaadin.terminal
  86. * .gwt.client.ApplicationConnection)
  87. */
  88. public final void setConnection(ApplicationConnection connection) {
  89. this.connection = connection;
  90. }
  91. public String getId() {
  92. return id;
  93. }
  94. public void setId(String id) {
  95. this.id = id;
  96. }
  97. /**
  98. * Returns the shared state object for a paintable widget.
  99. *
  100. * A new state instance is created using {@link #createState()} if none has
  101. * been set by the server.
  102. *
  103. * If overriding this method to return a more specific type, also
  104. * {@link #createState()} must be overridden.
  105. *
  106. * @return current shared state (not null)
  107. */
  108. public ComponentState getState() {
  109. if (state == null) {
  110. state = createState();
  111. }
  112. return state;
  113. }
  114. /**
  115. * Creates a new instance of a shared state object for the widget. Normally,
  116. * the state instance is created by the server and sent to the client before
  117. * being used - this method is used if no shared state has been sent by the
  118. * server.
  119. *
  120. * When overriding {@link #getState()}, also {@link #createState()} should
  121. * be overridden to match it.
  122. *
  123. * @return newly created component shared state instance
  124. */
  125. protected ComponentState createState() {
  126. return GWT.create(ComponentState.class);
  127. }
  128. public VPaintableWidgetContainer getParent() {
  129. // FIXME: Hierarchy should be set by framework instead of looked up here
  130. VPaintableMap paintableMap = VPaintableMap.get(getConnection());
  131. Widget w = getWidgetForPaintable();
  132. while (true) {
  133. w = w.getParent();
  134. if (w == null) {
  135. return null;
  136. }
  137. if (paintableMap.isPaintable(w)) {
  138. return (VPaintableWidgetContainer) paintableMap.getPaintable(w);
  139. }
  140. }
  141. }
  142. protected static boolean isRealUpdate(UIDL uidl) {
  143. return !isCachedUpdate(uidl) && !uidl.getBooleanAttribute("invisible")
  144. && !uidl.hasAttribute("deferred");
  145. }
  146. protected static boolean isCachedUpdate(UIDL uidl) {
  147. return uidl.getBooleanAttribute("cached");
  148. }
  149. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  150. if (isCachedUpdate(uidl)) {
  151. return;
  152. }
  153. VPaintableMap paintableMap = VPaintableMap.get(getConnection());
  154. // register the listened events by the server-side to the event-handler
  155. // of the component
  156. paintableMap.registerEventListenersFromUIDL(getId(), uidl);
  157. // Visibility
  158. setVisible(!uidl.getBooleanAttribute("invisible"), uidl);
  159. if (uidl.getId().startsWith("PID_S")) {
  160. DOM.setElementProperty(getWidgetForPaintable().getElement(), "id",
  161. uidl.getId().substring(5));
  162. }
  163. if (!isVisible()) {
  164. // component is invisible, delete old size to notify parent, if
  165. // later made visible
  166. paintableMap.setOffsetSize(this, null);
  167. return;
  168. }
  169. if (!isRealUpdate(uidl)) {
  170. return;
  171. }
  172. /*
  173. * Disabled state may affect (override) tabindex so the order must be
  174. * first setting tabindex, then enabled state.
  175. */
  176. if (uidl.hasAttribute("tabindex")
  177. && getWidgetForPaintable() instanceof Focusable) {
  178. ((Focusable) getWidgetForPaintable()).setTabIndex(uidl
  179. .getIntAttribute("tabindex"));
  180. }
  181. setEnabled(!uidl.getBooleanAttribute(ATTRIBUTE_DISABLED));
  182. // Style names
  183. String styleName = getStyleNameFromUIDL(getWidgetForPaintable()
  184. .getStylePrimaryName(), uidl,
  185. getWidgetForPaintable() instanceof Field);
  186. getWidgetForPaintable().setStyleName(styleName);
  187. // Update tooltip
  188. TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(this, null);
  189. if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) {
  190. tooltipInfo
  191. .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION));
  192. } else {
  193. tooltipInfo.setTitle(null);
  194. }
  195. // add error info to tooltip if present
  196. if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
  197. tooltipInfo.setErrorUidl(uidl.getErrors());
  198. } else {
  199. tooltipInfo.setErrorUidl(null);
  200. }
  201. // Set captions
  202. if (delegateCaptionHandling()) {
  203. getParent().updateCaption(this, uidl);
  204. }
  205. /*
  206. * updateComponentSize need to be after caption update so caption can be
  207. * taken into account
  208. */
  209. getConnection().updateComponentSize(this);
  210. }
  211. /**
  212. * Sets the enabled state of this paintable
  213. *
  214. * @param enabled
  215. * true if the paintable is enabled, false otherwise
  216. */
  217. protected void setEnabled(boolean enabled) {
  218. this.enabled = enabled;
  219. if (getWidgetForPaintable() instanceof FocusWidget) {
  220. FocusWidget fw = (FocusWidget) getWidgetForPaintable();
  221. fw.setEnabled(enabled);
  222. }
  223. }
  224. public boolean isEnabled() {
  225. return enabled;
  226. }
  227. /**
  228. * Return true if parent handles caption, false if the paintable handles the
  229. * caption itself.
  230. *
  231. *
  232. * @deprecated This should always return true and all components should let
  233. * the parent handle the caption and use other attributes for
  234. * internal texts in the component
  235. * @return
  236. */
  237. @Deprecated
  238. protected boolean delegateCaptionHandling() {
  239. return true;
  240. }
  241. /**
  242. * Sets the visible state for this paintable.
  243. *
  244. * @param visible
  245. * true if the paintable should be made visible, false otherwise
  246. * @param captionUidl
  247. * The UIDL that is passed to the parent and onwards to VCaption
  248. * if the caption needs to be updated as a result of the
  249. * visibility change.
  250. */
  251. protected void setVisible(boolean visible, UIDL captionUidl) {
  252. boolean wasVisible = this.visible;
  253. this.visible = visible;
  254. getWidgetForPaintable().setVisible(visible);
  255. if (wasVisible != visible) {
  256. // Changed invisibile <-> visible
  257. if (wasVisible && delegateCaptionHandling()) {
  258. // Must hide caption when component is hidden
  259. getParent().updateCaption(this, captionUidl);
  260. }
  261. }
  262. }
  263. protected boolean isVisible() {
  264. return visible;
  265. }
  266. /**
  267. * Generates the style name for the widget based on the given primary style
  268. * name (typically returned by Widget.getPrimaryStyleName()) and the UIDL.
  269. * An additional "modified" style name can be added if the field parameter
  270. * is set to true.
  271. *
  272. * @param primaryStyleName
  273. * @param uidl
  274. * @param isField
  275. * @return
  276. */
  277. protected static String getStyleNameFromUIDL(String primaryStyleName,
  278. UIDL uidl, boolean field) {
  279. boolean enabled = !uidl.getBooleanAttribute(ATTRIBUTE_DISABLED);
  280. StringBuffer styleBuf = new StringBuffer();
  281. styleBuf.append(primaryStyleName);
  282. // first disabling and read-only status
  283. if (!enabled) {
  284. styleBuf.append(" ");
  285. styleBuf.append(ApplicationConnection.DISABLED_CLASSNAME);
  286. }
  287. if (uidl.getBooleanAttribute(ATTRIBUTE_READONLY)) {
  288. styleBuf.append(" ");
  289. styleBuf.append("v-readonly");
  290. }
  291. // add additional styles as css classes, prefixed with component default
  292. // stylename
  293. if (uidl.hasAttribute(ATTRIBUTE_STYLE)) {
  294. final String[] styles = uidl.getStringAttribute(ATTRIBUTE_STYLE)
  295. .split(" ");
  296. for (int i = 0; i < styles.length; i++) {
  297. styleBuf.append(" ");
  298. styleBuf.append(primaryStyleName);
  299. styleBuf.append("-");
  300. styleBuf.append(styles[i]);
  301. styleBuf.append(" ");
  302. styleBuf.append(styles[i]);
  303. }
  304. }
  305. // add modified classname to Fields
  306. if (field && uidl.hasAttribute("modified")) {
  307. styleBuf.append(" ");
  308. styleBuf.append(ApplicationConnection.MODIFIED_CLASSNAME);
  309. }
  310. // add error classname to components w/ error
  311. if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
  312. styleBuf.append(" ");
  313. styleBuf.append(primaryStyleName);
  314. styleBuf.append(ApplicationConnection.ERROR_CLASSNAME_EXT);
  315. }
  316. // add required style to required components
  317. if (uidl.hasAttribute(ATTRIBUTE_REQUIRED)) {
  318. styleBuf.append(" ");
  319. styleBuf.append(primaryStyleName);
  320. styleBuf.append(ApplicationConnection.REQUIRED_CLASSNAME_EXT);
  321. }
  322. return styleBuf.toString();
  323. }
  324. /**
  325. * Sets the shared state for the paintable widget.
  326. *
  327. * @param new shared state (must be compatible with the return value of
  328. * {@link #getState()} - {@link ComponentState} if
  329. * {@link #getState()} is not overridden
  330. */
  331. public final void setState(SharedState state) {
  332. this.state = (ComponentState) state;
  333. }
  334. }