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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.Set;
  6. import com.google.gwt.event.dom.client.KeyDownEvent;
  7. import com.google.gwt.event.dom.client.KeyDownHandler;
  8. import com.google.gwt.event.shared.HandlerRegistration;
  9. import com.google.gwt.user.client.DOM;
  10. import com.google.gwt.user.client.Element;
  11. import com.google.gwt.user.client.Event;
  12. import com.google.gwt.user.client.ui.ComplexPanel;
  13. import com.google.gwt.user.client.ui.Widget;
  14. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  15. import com.vaadin.terminal.gwt.client.BrowserInfo;
  16. import com.vaadin.terminal.gwt.client.Container;
  17. import com.vaadin.terminal.gwt.client.Paintable;
  18. import com.vaadin.terminal.gwt.client.RenderInformation;
  19. import com.vaadin.terminal.gwt.client.RenderSpace;
  20. import com.vaadin.terminal.gwt.client.UIDL;
  21. import com.vaadin.terminal.gwt.client.Util;
  22. import com.vaadin.terminal.gwt.client.VErrorMessage;
  23. public class VForm extends ComplexPanel implements Container, KeyDownHandler {
  24. protected String id;
  25. private String height = "";
  26. private String width = "";
  27. public static final String CLASSNAME = "v-form";
  28. private Container lo;
  29. private Element legend = DOM.createLegend();
  30. private Element caption = DOM.createSpan();
  31. private Element errorIndicatorElement = DOM.createDiv();
  32. private Element desc = DOM.createDiv();
  33. private Icon icon;
  34. private VErrorMessage errorMessage = new VErrorMessage();
  35. private Element fieldContainer = DOM.createDiv();
  36. private Element footerContainer = DOM.createDiv();
  37. private Element fieldSet = DOM.createFieldSet();
  38. private Container footer;
  39. private ApplicationConnection client;
  40. private RenderInformation renderInformation = new RenderInformation();
  41. private int borderPaddingHorizontal = -1;
  42. private boolean rendering = false;
  43. ShortcutActionHandler shortcutHandler;
  44. private HandlerRegistration keyDownRegistration;
  45. public VForm() {
  46. setElement(DOM.createDiv());
  47. DOM.appendChild(getElement(), fieldSet);
  48. setStyleName(CLASSNAME);
  49. DOM.appendChild(fieldSet, legend);
  50. DOM.appendChild(legend, caption);
  51. DOM.setElementProperty(errorIndicatorElement, "className",
  52. "v-errorindicator");
  53. DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
  54. DOM.setInnerText(errorIndicatorElement, " "); // needed for IE
  55. DOM.setElementProperty(desc, "className", "v-form-description");
  56. DOM.appendChild(fieldSet, desc);
  57. DOM.appendChild(fieldSet, fieldContainer);
  58. errorMessage.setVisible(false);
  59. errorMessage.setStyleName(CLASSNAME + "-errormessage");
  60. DOM.appendChild(fieldSet, errorMessage.getElement());
  61. DOM.appendChild(fieldSet, footerContainer);
  62. }
  63. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  64. rendering = true;
  65. this.client = client;
  66. id = uidl.getId();
  67. if (client.updateComponent(this, uidl, false)) {
  68. rendering = false;
  69. return;
  70. }
  71. boolean legendEmpty = true;
  72. if (uidl.hasAttribute("caption")) {
  73. DOM.setInnerText(caption, uidl.getStringAttribute("caption"));
  74. legendEmpty = false;
  75. } else {
  76. DOM.setInnerText(caption, "");
  77. }
  78. if (uidl.hasAttribute("icon")) {
  79. if (icon == null) {
  80. icon = new Icon(client);
  81. DOM.insertChild(legend, icon.getElement(), 0);
  82. }
  83. icon.setUri(uidl.getStringAttribute("icon"));
  84. legendEmpty = false;
  85. } else {
  86. if (icon != null) {
  87. DOM.removeChild(legend, icon.getElement());
  88. }
  89. }
  90. if (legendEmpty) {
  91. addStyleDependentName("nocaption");
  92. } else {
  93. removeStyleDependentName("nocaption");
  94. }
  95. if (uidl.hasAttribute("error")) {
  96. final UIDL errorUidl = uidl.getErrors();
  97. errorMessage.updateFromUIDL(errorUidl);
  98. errorMessage.setVisible(true);
  99. } else {
  100. errorMessage.setVisible(false);
  101. }
  102. if (uidl.hasAttribute("description")) {
  103. DOM.setInnerHTML(desc, uidl.getStringAttribute("description"));
  104. } else {
  105. DOM.setInnerHTML(desc, "");
  106. }
  107. updateSize();
  108. // TODO Check if this is needed
  109. client.runDescendentsLayout(this);
  110. // first render footer so it will be easier to handle relative height of
  111. // main layout
  112. if (uidl.getChildCount() > 1
  113. && !uidl.getChildUIDL(1).getTag().equals("actions")) {
  114. // render footer
  115. Container newFooter = (Container) client.getPaintable(uidl
  116. .getChildUIDL(1));
  117. if (footer == null) {
  118. add((Widget) newFooter, footerContainer);
  119. footer = newFooter;
  120. } else if (newFooter != footer) {
  121. remove((Widget) footer);
  122. client.unregisterPaintable(footer);
  123. add((Widget) newFooter, footerContainer);
  124. }
  125. footer = newFooter;
  126. footer.updateFromUIDL(uidl.getChildUIDL(1), client);
  127. updateSize();
  128. } else {
  129. if (footer != null) {
  130. remove((Widget) footer);
  131. client.unregisterPaintable(footer);
  132. updateSize();
  133. }
  134. }
  135. final UIDL layoutUidl = uidl.getChildUIDL(0);
  136. Container newLo = (Container) client.getPaintable(layoutUidl);
  137. if (lo == null) {
  138. lo = newLo;
  139. add((Widget) lo, fieldContainer);
  140. } else if (lo != newLo) {
  141. client.unregisterPaintable(lo);
  142. remove((Widget) lo);
  143. lo = newLo;
  144. add((Widget) lo, fieldContainer);
  145. }
  146. lo.updateFromUIDL(layoutUidl, client);
  147. // We may have actions attached
  148. if (uidl.getChildCount() > 1) {
  149. UIDL childUidl = uidl.getChildByTagName("actions");
  150. if (childUidl != null) {
  151. if (shortcutHandler == null) {
  152. shortcutHandler = new ShortcutActionHandler(id, client);
  153. keyDownRegistration = addDomHandler(this,
  154. KeyDownEvent.getType());
  155. }
  156. shortcutHandler.updateActionMap(childUidl);
  157. }
  158. } else if (shortcutHandler != null) {
  159. keyDownRegistration.removeHandler();
  160. shortcutHandler = null;
  161. keyDownRegistration = null;
  162. }
  163. rendering = false;
  164. }
  165. public void updateSize() {
  166. renderInformation.updateSize(getElement());
  167. renderInformation.setContentAreaHeight(renderInformation
  168. .getRenderedSize().getHeight() - getSpaceConsumedVertically());
  169. if (BrowserInfo.get().isIE6()) {
  170. getElement().getStyle().setProperty("overflow", "hidden");
  171. }
  172. renderInformation.setContentAreaWidth(renderInformation
  173. .getRenderedSize().getWidth() - borderPaddingHorizontal);
  174. }
  175. public RenderSpace getAllocatedSpace(Widget child) {
  176. if (child == lo) {
  177. return renderInformation.getContentAreaSize();
  178. } else if (child == footer) {
  179. return new RenderSpace(renderInformation.getContentAreaSize()
  180. .getWidth(), 0);
  181. } else {
  182. ApplicationConnection.getConsole().error(
  183. "Invalid child requested RenderSpace information");
  184. return null;
  185. }
  186. }
  187. public boolean hasChildComponent(Widget component) {
  188. return component != null && (component == lo || component == footer);
  189. }
  190. public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
  191. if (!hasChildComponent(oldComponent)) {
  192. throw new IllegalArgumentException(
  193. "Old component is not inside this Container");
  194. }
  195. remove(oldComponent);
  196. if (oldComponent == lo) {
  197. lo = (Container) newComponent;
  198. add((Widget) lo, fieldContainer);
  199. } else {
  200. footer = (Container) newComponent;
  201. add((Widget) footer, footerContainer);
  202. }
  203. }
  204. public boolean requestLayout(Set<Paintable> child) {
  205. if (height != null && !"".equals(height) && width != null
  206. && !"".equals(width)) {
  207. /*
  208. * If the height and width has been specified the child components
  209. * cannot make the size of the layout change
  210. */
  211. return true;
  212. }
  213. if (renderInformation.updateSize(getElement())) {
  214. return false;
  215. } else {
  216. return true;
  217. }
  218. }
  219. public void updateCaption(Paintable component, UIDL uidl) {
  220. // NOP form don't render caption for neither field layout nor footer
  221. // layout
  222. }
  223. @Override
  224. public void setHeight(String height) {
  225. if (this.height.equals(height)) {
  226. return;
  227. }
  228. this.height = height;
  229. super.setHeight(height);
  230. updateSize();
  231. }
  232. /**
  233. * @return pixels consumed by decoration, captions, descrioptiosn etc.. In
  234. * other words space, not used by the actual layout in form.
  235. */
  236. private int getSpaceConsumedVertically() {
  237. int offsetHeight2 = fieldSet.getOffsetHeight();
  238. int offsetHeight3 = fieldContainer.getOffsetHeight();
  239. int borderPadding = offsetHeight2 - offsetHeight3;
  240. return borderPadding;
  241. }
  242. @Override
  243. public void setWidth(String width) {
  244. if (borderPaddingHorizontal < 0) {
  245. // measure excess size lazyly after stylename setting, but before
  246. // setting width
  247. int ow = getOffsetWidth();
  248. int dow = desc.getOffsetWidth();
  249. borderPaddingHorizontal = ow - dow;
  250. }
  251. if (Util.equals(this.width, width)) {
  252. return;
  253. }
  254. this.width = width;
  255. super.setWidth(width);
  256. updateSize();
  257. if (!rendering && height.equals("")) {
  258. // Width might affect height
  259. Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
  260. }
  261. }
  262. public void onKeyDown(KeyDownEvent event) {
  263. shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent()));
  264. }
  265. }