您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

IOrderedLayout.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.itmill.toolkit.terminal.gwt.client.ui;
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import java.util.Iterator;
  8. import com.google.gwt.user.client.DOM;
  9. import com.google.gwt.user.client.Element;
  10. import com.google.gwt.user.client.ui.ComplexPanel;
  11. import com.google.gwt.user.client.ui.UIObject;
  12. import com.google.gwt.user.client.ui.Widget;
  13. import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
  14. import com.itmill.toolkit.terminal.gwt.client.Caption;
  15. import com.itmill.toolkit.terminal.gwt.client.Container;
  16. import com.itmill.toolkit.terminal.gwt.client.Paintable;
  17. import com.itmill.toolkit.terminal.gwt.client.StyleConstants;
  18. import com.itmill.toolkit.terminal.gwt.client.UIDL;
  19. import com.itmill.toolkit.terminal.gwt.client.Util;
  20. /**
  21. * Abstract base class for ordered layouts. Use either vertical or horizontal
  22. * subclass.
  23. *
  24. * @author IT Mill Ltd
  25. */
  26. public abstract class IOrderedLayout extends ComplexPanel implements Container {
  27. public static final String CLASSNAME = "i-orderedlayout";
  28. public static final int ORIENTATION_VERTICAL = 0;
  29. public static final int ORIENTATION_HORIZONTAL = 1;
  30. int orientationMode = ORIENTATION_VERTICAL;
  31. protected HashMap componentToCaption = new HashMap();
  32. protected ApplicationConnection client;
  33. /**
  34. * Contains reference to Element where Paintables are wrapped. Normally a TR
  35. * or a TBODY element.
  36. */
  37. protected Element childContainer;
  38. /*
  39. * Elements that provides the Layout interface implementation.
  40. */
  41. protected Element root;
  42. protected Element margin;
  43. public IOrderedLayout(int orientation) {
  44. orientationMode = orientation;
  45. constructDOM();
  46. setStyleName(CLASSNAME);
  47. }
  48. protected void constructDOM() {
  49. root = DOM.createDiv();
  50. margin = DOM.createDiv();
  51. DOM.appendChild(root, margin);
  52. if (orientationMode == ORIENTATION_HORIZONTAL) {
  53. final String structure = "<table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr></tr></tbody></table>";
  54. DOM.setInnerHTML(margin, structure);
  55. childContainer = DOM.getFirstChild(DOM.getFirstChild(DOM.getFirstChild(margin)));
  56. } else {
  57. childContainer = margin;
  58. }
  59. setElement(root);
  60. }
  61. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  62. this.client = client;
  63. // Ensure correct implementation
  64. if (client.updateComponent(this, uidl, false)) {
  65. return;
  66. }
  67. // Update contained components
  68. final ArrayList uidlWidgets = new ArrayList();
  69. for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
  70. final UIDL uidlForChild = (UIDL) it.next();
  71. final Paintable child = client.getPaintable(uidlForChild);
  72. uidlWidgets.add(child);
  73. }
  74. final ArrayList oldWidgets = getPaintables();
  75. final Iterator oldIt = oldWidgets.iterator();
  76. final Iterator newIt = uidlWidgets.iterator();
  77. final Iterator newUidl = uidl.getChildIterator();
  78. Widget oldChild = null;
  79. while (newIt.hasNext()) {
  80. final Widget child = (Widget) newIt.next();
  81. final UIDL childUidl = (UIDL) newUidl.next();
  82. if (oldChild == null && oldIt.hasNext()) {
  83. // search for next old Paintable which still exists in layout
  84. // and delete others
  85. while (oldIt.hasNext()) {
  86. oldChild = (Widget) oldIt.next();
  87. // now oldChild is an instance of Paintable
  88. if (uidlWidgets.contains(oldChild)) {
  89. break;
  90. } else {
  91. removePaintable((Paintable) oldChild);
  92. oldChild = null;
  93. }
  94. }
  95. }
  96. if (oldChild == null) {
  97. // we are adding components to layout
  98. add(child);
  99. } else if (child == oldChild) {
  100. // child already attached and updated
  101. oldChild = null;
  102. } else if (hasChildComponent(child)) {
  103. // current child has been moved, re-insert before current
  104. // oldChild
  105. // TODO this might be optimized by moving only container element
  106. // to correct position
  107. removeCaption(child);
  108. int index = getWidgetIndex(oldChild);
  109. if (componentToCaption.containsKey(oldChild)) {
  110. index--;
  111. }
  112. remove(child);
  113. this.insert(child, index);
  114. } else {
  115. // insert new child before old one
  116. final int index = getWidgetIndex(oldChild);
  117. insert(child, index);
  118. }
  119. ((Paintable) child).updateFromUIDL(childUidl, client);
  120. }
  121. // remove possibly remaining old Paintable object which were not updated
  122. while (oldIt.hasNext()) {
  123. oldChild = (Widget) oldIt.next();
  124. final Paintable p = (Paintable) oldChild;
  125. if (!uidlWidgets.contains(p)) {
  126. removePaintable(p);
  127. }
  128. }
  129. // Handle component alignments
  130. handleAlignments(uidl);
  131. // Handle layout margins
  132. handleMargins(uidl);
  133. }
  134. /**
  135. * Retuns a list of Paintables currently rendered in layout
  136. *
  137. * @return list of Paintable objects
  138. */
  139. protected ArrayList getPaintables() {
  140. final ArrayList al = new ArrayList();
  141. final Iterator it = iterator();
  142. while (it.hasNext()) {
  143. final Widget w = (Widget) it.next();
  144. if (w instanceof Paintable) {
  145. al.add(w);
  146. }
  147. }
  148. return al;
  149. }
  150. /**
  151. * Removes Paintable from DOM and its reference from ApplicationConnection.
  152. *
  153. * Also removes Paintable's Caption if one exists
  154. *
  155. * @param p
  156. * Paintable to be removed
  157. */
  158. public boolean removePaintable(Paintable p) {
  159. final Caption c = (Caption) componentToCaption.get(p);
  160. if (c != null) {
  161. componentToCaption.remove(c);
  162. remove(c);
  163. }
  164. client.unregisterPaintable(p);
  165. return remove((Widget) p);
  166. }
  167. /*
  168. * (non-Javadoc)
  169. *
  170. * @see com.itmill.toolkit.terminal.gwt.client.Layout#replaceChildComponent(com.google.gwt.user.client.ui.Widget,
  171. * com.google.gwt.user.client.ui.Widget)
  172. */
  173. public void replaceChildComponent(Widget from, Widget to) {
  174. client.unregisterPaintable((Paintable) from);
  175. final Caption c = (Caption) componentToCaption.get(from);
  176. if (c != null) {
  177. remove(c);
  178. componentToCaption.remove(c);
  179. }
  180. final int index = getWidgetIndex(from);
  181. if (index >= 0) {
  182. remove(index);
  183. insert(to, index);
  184. }
  185. }
  186. protected void insert(Widget w, int beforeIndex) {
  187. if (w instanceof Caption) {
  188. final Caption c = (Caption) w;
  189. // captions go into same container element as their
  190. // owners
  191. final Element container = DOM.getParent(((UIObject) c.getOwner())
  192. .getElement());
  193. final Element captionContainer = DOM.createDiv();
  194. DOM.insertChild(container, captionContainer, 0);
  195. insert(w, captionContainer, beforeIndex, false);
  196. } else {
  197. final Element wrapper = createWidgetWrappper();
  198. DOM.insertChild(childContainer, wrapper, beforeIndex);
  199. insert(w, wrapper, beforeIndex, false);
  200. }
  201. }
  202. /**
  203. * creates an Element which will contain child widget
  204. */
  205. protected Element createWidgetWrappper() {
  206. switch (orientationMode) {
  207. case ORIENTATION_HORIZONTAL:
  208. final Element td = DOM.createTD();
  209. return td;
  210. default:
  211. final Element div = DOM.createDiv();
  212. return div;
  213. }
  214. }
  215. public boolean hasChildComponent(Widget component) {
  216. return getWidgetIndex(component) >= 0;
  217. }
  218. public void updateCaption(Paintable component, UIDL uidl) {
  219. Caption c = (Caption) componentToCaption.get(component);
  220. if (Caption.isNeeded(uidl)) {
  221. if (c == null) {
  222. final int index = getWidgetIndex((Widget) component);
  223. c = new Caption(component, client);
  224. insert(c, index);
  225. componentToCaption.put(component, c);
  226. }
  227. c.updateCaption(uidl);
  228. } else {
  229. if (c != null) {
  230. remove(c);
  231. componentToCaption.remove(component);
  232. }
  233. }
  234. }
  235. public void removeCaption(Widget w) {
  236. final Caption c = (Caption) componentToCaption.get(w);
  237. if (c != null) {
  238. this.remove(c);
  239. componentToCaption.remove(w);
  240. }
  241. }
  242. public void add(Widget w) {
  243. final Element wrapper = createWidgetWrappper();
  244. DOM.appendChild(childContainer, wrapper);
  245. super.add(w, wrapper);
  246. }
  247. public boolean remove(int index) {
  248. return remove(getWidget(index));
  249. }
  250. public boolean remove(Widget w) {
  251. final Element wrapper = DOM.getParent(w.getElement());
  252. final boolean removed = super.remove(w);
  253. if (removed) {
  254. if (!(w instanceof Caption)) {
  255. DOM.removeChild(childContainer, wrapper);
  256. }
  257. return true;
  258. }
  259. return false;
  260. }
  261. public Widget getWidget(int index) {
  262. return getChildren().get(index);
  263. }
  264. public int getWidgetCount() {
  265. return getChildren().size();
  266. }
  267. public int getWidgetIndex(Widget child) {
  268. return getChildren().indexOf(child);
  269. }
  270. protected void handleMargins(UIDL uidl) {
  271. final MarginInfo margins = new MarginInfo(uidl
  272. .getIntAttribute("margins"));
  273. setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP, margins
  274. .hasTop());
  275. setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT, margins
  276. .hasRight());
  277. setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM,
  278. margins.hasBottom());
  279. setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT, margins
  280. .hasLeft());
  281. }
  282. protected void handleAlignments(UIDL uidl) {
  283. // Component alignments as a comma separated list.
  284. // See com.itmill.toolkit.terminal.gwt.client.ui.AlignmentInfo.java for
  285. // possible values.
  286. final int[] alignments = uidl.getIntArrayAttribute("alignments");
  287. int alignmentIndex = 0;
  288. // Insert alignment attributes
  289. final Iterator it = getPaintables().iterator();
  290. while (it.hasNext()) {
  291. // Calculate alignment info
  292. final AlignmentInfo ai = new AlignmentInfo(
  293. alignments[alignmentIndex++]);
  294. final Element td = DOM.getParent(((Widget) it.next()).getElement());
  295. if (Util.isIE()) {
  296. DOM
  297. .setElementAttribute(td, "vAlign", ai
  298. .getVerticalAlignment());
  299. } else {
  300. DOM.setStyleAttribute(td, "verticalAlign", ai
  301. .getVerticalAlignment());
  302. }
  303. // TODO use one-cell table to implement horizontal alignments
  304. if (Util.isIE()) {
  305. DOM.setElementAttribute(td, "align", ai
  306. .getHorizontalAlignment());
  307. } else {
  308. DOM.setStyleAttribute(td, "textAlign", ai
  309. .getHorizontalAlignment());
  310. }
  311. }
  312. }
  313. }