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 11KB

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