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.

VAbsoluteLayout.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui;
  17. import com.google.gwt.dom.client.DivElement;
  18. import com.google.gwt.dom.client.Document;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.Style;
  21. import com.google.gwt.user.client.DOM;
  22. import com.google.gwt.user.client.ui.ComplexPanel;
  23. import com.google.gwt.user.client.ui.SimplePanel;
  24. import com.google.gwt.user.client.ui.Widget;
  25. import com.vaadin.client.StyleConstants;
  26. import com.vaadin.client.VCaption;
  27. public class VAbsoluteLayout extends ComplexPanel {
  28. /** Tag name for widget creation. */
  29. public static final String TAGNAME = "absolutelayout";
  30. /** Class name, prefix in styling. */
  31. public static final String CLASSNAME = "v-absolutelayout";
  32. private DivElement marginElement;
  33. protected final Element canvas = DOM.createDiv();
  34. /**
  35. * Default constructor.
  36. */
  37. public VAbsoluteLayout() {
  38. setElement(Document.get().createDivElement());
  39. marginElement = Document.get().createDivElement();
  40. canvas.getStyle().setProperty("position", "relative");
  41. canvas.getStyle().setProperty("overflow", "hidden");
  42. marginElement.appendChild(canvas);
  43. getElement().appendChild(marginElement);
  44. setStyleName(CLASSNAME);
  45. }
  46. /*
  47. * (non-Javadoc)
  48. *
  49. * @see
  50. * com.google.gwt.user.client.ui.Panel#add(com.google.gwt.user.client.ui
  51. * .Widget)
  52. */
  53. @Override
  54. public void add(Widget child) {
  55. AbsoluteWrapper wrapper = new AbsoluteWrapper(child);
  56. wrapper.updateStyleNames();
  57. super.add(wrapper, canvas);
  58. }
  59. /*
  60. * (non-Javadoc)
  61. *
  62. * @see
  63. * com.google.gwt.user.client.ui.ComplexPanel#remove(com.google.gwt.user
  64. * .client.ui.Widget)
  65. */
  66. @Override
  67. public boolean remove(Widget w) {
  68. AbsoluteWrapper wrapper = getChildWrapper(w);
  69. if (wrapper != null) {
  70. wrapper.destroy();
  71. return super.remove(wrapper);
  72. }
  73. return super.remove(w);
  74. }
  75. /**
  76. * Does this layout contain a widget.
  77. *
  78. * @param widget
  79. * The widget to check
  80. * @return Returns true if the widget is in this layout, false if not
  81. */
  82. public boolean contains(Widget widget) {
  83. return getChildWrapper(widget) != null;
  84. }
  85. /*
  86. * (non-Javadoc)
  87. *
  88. * @see com.google.gwt.user.client.ui.ComplexPanel#getWidget(int)
  89. */
  90. @Override
  91. public Widget getWidget(int index) {
  92. for (int i = 0, j = 0; i < super.getWidgetCount(); i++) {
  93. Widget w = super.getWidget(i);
  94. if (w instanceof AbsoluteWrapper) {
  95. if (j == index) {
  96. return w;
  97. } else {
  98. j++;
  99. }
  100. }
  101. }
  102. return null;
  103. }
  104. /*
  105. * (non-Javadoc)
  106. *
  107. * @see com.google.gwt.user.client.ui.ComplexPanel#getWidgetCount()
  108. */
  109. @Override
  110. public int getWidgetCount() {
  111. int counter = 0;
  112. for (int i = 0; i < super.getWidgetCount(); i++) {
  113. if (super.getWidget(i) instanceof AbsoluteWrapper) {
  114. counter++;
  115. }
  116. }
  117. return counter;
  118. }
  119. /*
  120. * (non-Javadoc)
  121. *
  122. * @see
  123. * com.google.gwt.user.client.ui.ComplexPanel#getWidgetIndex(com.google.
  124. * gwt.user.client.ui.Widget)
  125. */
  126. @Override
  127. public int getWidgetIndex(Widget child) {
  128. for (int i = 0, j = 0; i < super.getWidgetCount(); i++) {
  129. Widget w = super.getWidget(i);
  130. if (w instanceof AbsoluteWrapper) {
  131. if (child == w) {
  132. return j;
  133. } else {
  134. j++;
  135. }
  136. }
  137. }
  138. return -1;
  139. }
  140. /**
  141. * Sets a caption for a contained widget.
  142. *
  143. * @param child
  144. * The child widget to set the caption for
  145. * @param caption
  146. * The caption of the widget
  147. */
  148. public void setWidgetCaption(Widget child, VCaption caption) {
  149. AbsoluteWrapper wrapper = getChildWrapper(child);
  150. if (wrapper != null) {
  151. if (caption != null) {
  152. if (!getChildren().contains(caption)) {
  153. super.add(caption, canvas);
  154. }
  155. wrapper.setCaption(caption);
  156. caption.updateCaption();
  157. wrapper.updateCaptionPosition();
  158. } else if (wrapper.getCaption() != null) {
  159. wrapper.setCaption(null);
  160. }
  161. }
  162. }
  163. /**
  164. * Set the position of the widget in the layout. The position is a CSS
  165. * property string using properties such as top,left,right,top
  166. *
  167. * @param child
  168. * The child widget to set the position for
  169. * @param position
  170. * The position string
  171. */
  172. public void setWidgetPosition(Widget child, String position) {
  173. AbsoluteWrapper wrapper = getChildWrapper(child);
  174. if (wrapper != null) {
  175. wrapper.setPosition(position);
  176. }
  177. }
  178. /**
  179. * Get the caption for a widget.
  180. *
  181. * @param child
  182. * The child widget to get the caption of
  183. */
  184. public VCaption getWidgetCaption(Widget child) {
  185. AbsoluteWrapper wrapper = getChildWrapper(child);
  186. if (wrapper != null) {
  187. return wrapper.getCaption();
  188. }
  189. return null;
  190. }
  191. /**
  192. * Get the pixel width of an slot in the layout.
  193. *
  194. * @param child
  195. * The widget in the layout.
  196. * @return Returns the size in pixels, or 0 if child is not in the layout
  197. */
  198. public int getWidgetSlotWidth(Widget child) {
  199. AbsoluteWrapper wrapper = getChildWrapper(child);
  200. if (wrapper != null) {
  201. return wrapper.getOffsetWidth();
  202. }
  203. return 0;
  204. }
  205. /**
  206. * Get the pixel height of an slot in the layout.
  207. *
  208. * @param child
  209. * The widget in the layout
  210. * @return Returns the size in pixels, or 0 if the child is not in the
  211. * layout
  212. */
  213. public int getWidgetSlotHeight(Widget child) {
  214. AbsoluteWrapper wrapper = getChildWrapper(child);
  215. if (wrapper != null) {
  216. return wrapper.getOffsetHeight();
  217. }
  218. return 0;
  219. }
  220. /**
  221. * Get the wrapper for a widget.
  222. *
  223. * @param child
  224. * The child to get the wrapper for
  225. * @return
  226. */
  227. protected AbsoluteWrapper getChildWrapper(Widget child) {
  228. for (Widget w : getChildren()) {
  229. if (w instanceof AbsoluteWrapper) {
  230. AbsoluteWrapper wrapper = (AbsoluteWrapper) w;
  231. if (wrapper.getWidget() == child) {
  232. return wrapper;
  233. }
  234. }
  235. }
  236. return null;
  237. }
  238. /*
  239. * (non-Javadoc)
  240. *
  241. * @see
  242. * com.google.gwt.user.client.ui.UIObject#setStylePrimaryName(java.lang.
  243. * String)
  244. */
  245. @Override
  246. public void setStylePrimaryName(String style) {
  247. updateStylenames(style);
  248. }
  249. /*
  250. * (non-Javadoc)
  251. *
  252. * @see
  253. * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)
  254. */
  255. @Override
  256. public void setStyleName(String style) {
  257. super.setStyleName(style);
  258. updateStylenames(style);
  259. addStyleName(StyleConstants.UI_LAYOUT);
  260. }
  261. /**
  262. * Updates all style names contained in the layout.
  263. *
  264. * @param primaryStyleName
  265. * The style name to use as primary
  266. */
  267. protected void updateStylenames(String primaryStyleName) {
  268. super.setStylePrimaryName(primaryStyleName);
  269. canvas.setClassName(getStylePrimaryName() + "-canvas");
  270. canvas.setClassName(getStylePrimaryName() + "-margin");
  271. for (Widget w : getChildren()) {
  272. if (w instanceof AbsoluteWrapper) {
  273. AbsoluteWrapper wrapper = (AbsoluteWrapper) w;
  274. wrapper.updateStyleNames();
  275. }
  276. }
  277. }
  278. /**
  279. * Performs a vertical layout of the layout. Should be called when a widget
  280. * is added or removed
  281. */
  282. public void layoutVertically() {
  283. layout();
  284. }
  285. /**
  286. * Performs an horizontal layout. Should be called when a widget is add or
  287. * removed
  288. */
  289. public void layoutHorizontally() {
  290. layout();
  291. }
  292. private void layout() {
  293. for (Widget widget : getChildren()) {
  294. if (widget instanceof AbsoluteWrapper) {
  295. AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
  296. wrapper.updateCaptionPosition();
  297. }
  298. }
  299. }
  300. /**
  301. * Cleanup old wrappers which have been left empty by other inner layouts
  302. * moving the widget from the wrapper into their own hierarchy. This usually
  303. * happens when a call to setWidget(widget) is done in an inner layout which
  304. * automatically detaches the widget from the parent, in this case the
  305. * wrapper, and re-attaches it somewhere else. This has to be done in the
  306. * layout phase since the order of the hierarchy events are not defined.
  307. */
  308. public void cleanupWrappers() {
  309. for (Widget widget : getChildren()) {
  310. if (widget instanceof AbsoluteWrapper) {
  311. AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
  312. if (wrapper.getWidget() == null) {
  313. wrapper.destroy();
  314. super.remove(wrapper);
  315. continue;
  316. }
  317. }
  318. }
  319. }
  320. /**
  321. * Sets style names for the wrapper wrapping the widget in the layout. The
  322. * style names will be prefixed with v-absolutelayout-wrapper.
  323. *
  324. * @param widget
  325. * The widget which wrapper we want to add the stylenames to
  326. * @param stylenames
  327. * The style names that should be added to the wrapper
  328. */
  329. public void setWidgetWrapperStyleNames(Widget widget,
  330. String... stylenames) {
  331. AbsoluteWrapper wrapper = getChildWrapper(widget);
  332. if (wrapper == null) {
  333. throw new IllegalArgumentException(
  334. "No wrapper for widget found, has the widget been added to the layout?");
  335. }
  336. wrapper.setWrapperStyleNames(stylenames);
  337. }
  338. /**
  339. * Internal wrapper for wrapping widgets in the Absolute layout.
  340. */
  341. protected class AbsoluteWrapper extends SimplePanel {
  342. private String css;
  343. private String left;
  344. private String top;
  345. private String right;
  346. private String bottom;
  347. private String zIndex;
  348. private VCaption caption;
  349. private String[] extraStyleNames;
  350. /**
  351. * Constructor.
  352. *
  353. * @param child
  354. * The child to wrap
  355. */
  356. public AbsoluteWrapper(Widget child) {
  357. setWidget(child);
  358. }
  359. /**
  360. * Get the caption of the wrapper.
  361. */
  362. public VCaption getCaption() {
  363. return caption;
  364. }
  365. /**
  366. * Set the caption for the wrapper.
  367. *
  368. * @param caption
  369. * The caption for the wrapper
  370. */
  371. public void setCaption(VCaption caption) {
  372. if (caption != null) {
  373. this.caption = caption;
  374. } else if (this.caption != null) {
  375. this.caption.removeFromParent();
  376. this.caption = caption;
  377. }
  378. }
  379. /**
  380. * Removes the wrapper caption and itself from the layout.
  381. */
  382. public void destroy() {
  383. if (caption != null) {
  384. caption.removeFromParent();
  385. }
  386. removeFromParent();
  387. }
  388. /**
  389. * Set the position for the wrapper in the layout.
  390. *
  391. * @param position
  392. * The position string
  393. */
  394. public void setPosition(String position) {
  395. if (css == null || !css.equals(position)) {
  396. css = position;
  397. top = right = bottom = left = zIndex = null;
  398. if (!css.isEmpty()) {
  399. for (String property : css.split(";")) {
  400. String[] keyValue = property.split(":");
  401. if (keyValue[0].equals("left")) {
  402. left = keyValue[1];
  403. } else if (keyValue[0].equals("top")) {
  404. top = keyValue[1];
  405. } else if (keyValue[0].equals("right")) {
  406. right = keyValue[1];
  407. } else if (keyValue[0].equals("bottom")) {
  408. bottom = keyValue[1];
  409. } else if (keyValue[0].equals("z-index")) {
  410. zIndex = keyValue[1];
  411. }
  412. }
  413. }
  414. // ensure ne values
  415. Style style = getElement().getStyle();
  416. style.setProperty("zIndex", zIndex);
  417. style.setProperty("top", top);
  418. style.setProperty("left", left);
  419. style.setProperty("right", right);
  420. style.setProperty("bottom", bottom);
  421. }
  422. updateCaptionPosition();
  423. }
  424. /**
  425. * Updates the caption position by using element offset left and top
  426. */
  427. private void updateCaptionPosition() {
  428. if (caption != null) {
  429. Style style = caption.getElement().getStyle();
  430. style.setProperty("position", "absolute");
  431. style.setPropertyPx("left", getElement().getOffsetLeft());
  432. style.setPropertyPx("top",
  433. getElement().getOffsetTop() - caption.getHeight());
  434. }
  435. }
  436. /**
  437. * Sets the style names of the wrapper. Will be prefixed with the
  438. * v-absolutelayout-wrapper prefix
  439. *
  440. * @param stylenames
  441. * The wrapper style names
  442. */
  443. public void setWrapperStyleNames(String... stylenames) {
  444. extraStyleNames = stylenames;
  445. updateStyleNames();
  446. }
  447. /**
  448. * Updates the style names using the primary style name as prefix.
  449. */
  450. protected void updateStyleNames() {
  451. setStyleName(
  452. VAbsoluteLayout.this.getStylePrimaryName() + "-wrapper");
  453. if (extraStyleNames != null) {
  454. for (String stylename : extraStyleNames) {
  455. addStyleDependentName(stylename);
  456. }
  457. }
  458. }
  459. }
  460. }