Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

VAbsoluteLayout.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /*
  2. * Copyright 2000-2013 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.Style;
  20. import com.google.gwt.dom.client.Style.Unit;
  21. import com.google.gwt.user.client.DOM;
  22. import com.google.gwt.user.client.Element;
  23. import com.google.gwt.user.client.ui.ComplexPanel;
  24. import com.google.gwt.user.client.ui.SimplePanel;
  25. import com.google.gwt.user.client.ui.Widget;
  26. import com.vaadin.client.StyleConstants;
  27. import com.vaadin.client.VCaption;
  28. public class VAbsoluteLayout extends ComplexPanel {
  29. /** Tag name for widget creation */
  30. public static final String TAGNAME = "absolutelayout";
  31. /** Class name, prefix in styling */
  32. public static final String CLASSNAME = "v-absolutelayout";
  33. private DivElement marginElement;
  34. protected final Element canvas = DOM.createDiv();
  35. /**
  36. * Default constructor
  37. */
  38. public VAbsoluteLayout() {
  39. setElement(Document.get().createDivElement());
  40. marginElement = Document.get().createDivElement();
  41. canvas.getStyle().setProperty("position", "relative");
  42. canvas.getStyle().setProperty("overflow", "hidden");
  43. marginElement.appendChild(canvas);
  44. getElement().appendChild(marginElement);
  45. setStyleName(CLASSNAME);
  46. }
  47. /*
  48. * (non-Javadoc)
  49. *
  50. * @see
  51. * com.google.gwt.user.client.ui.Panel#add(com.google.gwt.user.client.ui
  52. * .Widget)
  53. */
  54. @Override
  55. public void add(Widget child) {
  56. AbsoluteWrapper wrapper = new AbsoluteWrapper(child);
  57. wrapper.updateStyleNames();
  58. super.add(wrapper, canvas);
  59. }
  60. /*
  61. * (non-Javadoc)
  62. *
  63. * @see
  64. * com.google.gwt.user.client.ui.ComplexPanel#remove(com.google.gwt.user
  65. * .client.ui.Widget)
  66. */
  67. @Override
  68. public boolean remove(Widget w) {
  69. AbsoluteWrapper wrapper = getChildWrapper(w);
  70. if (wrapper != null) {
  71. wrapper.destroy();
  72. return super.remove(wrapper);
  73. }
  74. return super.remove(w);
  75. }
  76. /**
  77. * Does this layout contain a widget
  78. *
  79. * @param widget
  80. * The widget to check
  81. * @return Returns true if the widget is in this layout, false if not
  82. */
  83. public boolean contains(Widget widget) {
  84. return getChildWrapper(widget) != null;
  85. }
  86. /*
  87. * (non-Javadoc)
  88. *
  89. * @see com.google.gwt.user.client.ui.ComplexPanel#getWidget(int)
  90. */
  91. @Override
  92. public Widget getWidget(int index) {
  93. for (int i = 0, j = 0; i < super.getWidgetCount(); i++) {
  94. Widget w = super.getWidget(i);
  95. if (w instanceof AbsoluteWrapper) {
  96. if (j == index) {
  97. return w;
  98. } else {
  99. j++;
  100. }
  101. }
  102. }
  103. return null;
  104. }
  105. /*
  106. * (non-Javadoc)
  107. *
  108. * @see com.google.gwt.user.client.ui.ComplexPanel#getWidgetCount()
  109. */
  110. @Override
  111. public int getWidgetCount() {
  112. int counter = 0;
  113. for (int i = 0; i < super.getWidgetCount(); i++) {
  114. if (super.getWidget(i) instanceof AbsoluteWrapper) {
  115. counter++;
  116. }
  117. }
  118. return counter;
  119. }
  120. /*
  121. * (non-Javadoc)
  122. *
  123. * @see
  124. * com.google.gwt.user.client.ui.ComplexPanel#getWidgetIndex(com.google.
  125. * gwt.user.client.ui.Widget)
  126. */
  127. @Override
  128. public int getWidgetIndex(Widget child) {
  129. for (int i = 0, j = 0; i < super.getWidgetCount(); i++) {
  130. Widget w = super.getWidget(i);
  131. if (w instanceof AbsoluteWrapper) {
  132. if (child == w) {
  133. return j;
  134. } else {
  135. j++;
  136. }
  137. }
  138. }
  139. return -1;
  140. }
  141. /**
  142. * Sets a caption for a contained widget
  143. *
  144. * @param child
  145. * The child widget to set the caption for
  146. * @param caption
  147. * The caption of the widget
  148. */
  149. public void setWidgetCaption(Widget child, VCaption caption) {
  150. AbsoluteWrapper wrapper = getChildWrapper(child);
  151. if (wrapper != null) {
  152. if (caption != null) {
  153. if (!getChildren().contains(caption)) {
  154. super.add(caption, canvas);
  155. }
  156. wrapper.setCaption(caption);
  157. caption.updateCaption();
  158. wrapper.updateCaptionPosition();
  159. } else if (wrapper.getCaption() != null) {
  160. wrapper.setCaption(null);
  161. }
  162. }
  163. }
  164. /**
  165. * Set the position of the widget in the layout. The position is a CSS
  166. * property string using properties such as top,left,right,top
  167. *
  168. * @param child
  169. * The child widget to set the position for
  170. * @param position
  171. * The position string
  172. */
  173. public void setWidgetPosition(Widget child, String position) {
  174. AbsoluteWrapper wrapper = getChildWrapper(child);
  175. if (wrapper != null) {
  176. wrapper.setPosition(position);
  177. }
  178. }
  179. /**
  180. * Get the caption for a widget
  181. *
  182. * @param child
  183. * The child widget to get the caption of
  184. */
  185. public VCaption getWidgetCaption(Widget child) {
  186. AbsoluteWrapper wrapper = getChildWrapper(child);
  187. if (wrapper != null) {
  188. return wrapper.getCaption();
  189. }
  190. return null;
  191. }
  192. /**
  193. * Get the pixel width of an slot in the layout
  194. *
  195. * @param child
  196. * The widget in the layout.
  197. * @return Returns the size in pixels, or 0 if child is not in the layout
  198. */
  199. public int getWidgetSlotWidth(Widget child) {
  200. AbsoluteWrapper wrapper = getChildWrapper(child);
  201. if (wrapper != null) {
  202. return wrapper.getOffsetWidth();
  203. }
  204. return 0;
  205. }
  206. /**
  207. * Get the pixel height of an slot in the layout
  208. *
  209. * @param child
  210. * The widget in the layout
  211. * @return Returns the size in pixels, or 0 if the child is not in the
  212. * layout
  213. */
  214. public int getWidgetSlotHeight(Widget child) {
  215. AbsoluteWrapper wrapper = getChildWrapper(child);
  216. if (wrapper != null) {
  217. return wrapper.getOffsetHeight();
  218. }
  219. return 0;
  220. }
  221. /**
  222. * Get the wrapper for a widget
  223. *
  224. * @param child
  225. * The child to get the wrapper for
  226. * @return
  227. */
  228. protected AbsoluteWrapper getChildWrapper(Widget child) {
  229. for (Widget w : getChildren()) {
  230. if (w instanceof AbsoluteWrapper) {
  231. AbsoluteWrapper wrapper = (AbsoluteWrapper) w;
  232. if (wrapper.getWidget() == child) {
  233. return wrapper;
  234. }
  235. }
  236. }
  237. return null;
  238. }
  239. /*
  240. * (non-Javadoc)
  241. *
  242. * @see
  243. * com.google.gwt.user.client.ui.UIObject#setStylePrimaryName(java.lang.
  244. * String)
  245. */
  246. @Override
  247. public void setStylePrimaryName(String style) {
  248. updateStylenames(style);
  249. }
  250. /*
  251. * (non-Javadoc)
  252. *
  253. * @see
  254. * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)
  255. */
  256. @Override
  257. public void setStyleName(String style) {
  258. super.setStyleName(style);
  259. updateStylenames(style);
  260. addStyleName(StyleConstants.UI_LAYOUT);
  261. }
  262. /**
  263. * Updates all style names contained in the layout
  264. *
  265. * @param primaryStyleName
  266. * The style name to use as primary
  267. */
  268. protected void updateStylenames(String primaryStyleName) {
  269. super.setStylePrimaryName(primaryStyleName);
  270. canvas.setClassName(getStylePrimaryName() + "-canvas");
  271. canvas.setClassName(getStylePrimaryName() + "-margin");
  272. for (Widget w : getChildren()) {
  273. if (w instanceof AbsoluteWrapper) {
  274. AbsoluteWrapper wrapper = (AbsoluteWrapper) w;
  275. wrapper.updateStyleNames();
  276. }
  277. }
  278. }
  279. /**
  280. * Performs a vertical layout of the layout. Should be called when a widget
  281. * is added or removed
  282. */
  283. public void layoutVertically() {
  284. for (Widget widget : getChildren()) {
  285. if (widget instanceof AbsoluteWrapper) {
  286. AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
  287. /*
  288. * Cleanup old wrappers which have been left empty by other
  289. * inner layouts moving the widget from the wrapper into their
  290. * own hierarchy. This usually happens when a call to
  291. * setWidget(widget) is done in an inner layout which
  292. * automatically detaches the widget from the parent, in this
  293. * case the wrapper, and re-attaches it somewhere else. This has
  294. * to be done in the layout phase since the order of the
  295. * hierarchy events are not defined.
  296. */
  297. if (wrapper.getWidget() == null) {
  298. wrapper.destroy();
  299. super.remove(wrapper);
  300. continue;
  301. }
  302. Style wrapperStyle = wrapper.getElement().getStyle();
  303. Style widgetStyle = wrapper.getWidget().getElement().getStyle();
  304. // Ensure previous heights do not affect the measures
  305. wrapperStyle.clearHeight();
  306. if (widgetStyle.getHeight() != null
  307. && widgetStyle.getHeight().endsWith("%")) {
  308. int h;
  309. if (wrapper.top != null && wrapper.bottom != null) {
  310. h = wrapper.getOffsetHeight();
  311. } else if (wrapper.bottom != null) {
  312. // top not defined, available space 0... bottom of
  313. // wrapper
  314. h = wrapper.getElement().getOffsetTop()
  315. + wrapper.getOffsetHeight();
  316. } else {
  317. // top defined or both undefined, available space ==
  318. // canvas - top
  319. h = canvas.getOffsetHeight()
  320. - wrapper.getElement().getOffsetTop();
  321. }
  322. wrapperStyle.setHeight(h, Unit.PX);
  323. }
  324. wrapper.updateCaptionPosition();
  325. }
  326. }
  327. }
  328. /**
  329. * Performs an horizontal layout. Should be called when a widget is add or
  330. * removed
  331. */
  332. public void layoutHorizontally() {
  333. for (Widget widget : getChildren()) {
  334. if (widget instanceof AbsoluteWrapper) {
  335. AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
  336. /*
  337. * Cleanup old wrappers which have been left empty by other
  338. * inner layouts moving the widget from the wrapper into their
  339. * own hierarchy. This usually happens when a call to
  340. * setWidget(widget) is done in an inner layout which
  341. * automatically detaches the widget from the parent, in this
  342. * case the wrapper, and re-attaches it somewhere else. This has
  343. * to be done in the layout phase since the order of the
  344. * hierarchy events are not defined.
  345. */
  346. if (wrapper.getWidget() == null) {
  347. wrapper.destroy();
  348. super.remove(wrapper);
  349. continue;
  350. }
  351. Style wrapperStyle = wrapper.getElement().getStyle();
  352. Style widgetStyle = wrapper.getWidget().getElement().getStyle();
  353. // Ensure previous heights do not affect the measures
  354. wrapperStyle.clearWidth();
  355. if (widgetStyle.getWidth() != null
  356. && widgetStyle.getWidth().endsWith("%")) {
  357. int w;
  358. if (wrapper.left != null && wrapper.right != null) {
  359. w = wrapper.getOffsetWidth();
  360. } else if (wrapper.right != null) {
  361. // left == null
  362. // available width == right edge == offsetleft + width
  363. w = wrapper.getOffsetWidth()
  364. + wrapper.getElement().getOffsetLeft();
  365. } else {
  366. // left != null && right == null || left == null &&
  367. // right == null
  368. // available width == canvas width - offset left
  369. w = canvas.getOffsetWidth()
  370. - wrapper.getElement().getOffsetLeft();
  371. }
  372. wrapperStyle.setWidth(w, Unit.PX);
  373. }
  374. wrapper.updateCaptionPosition();
  375. }
  376. }
  377. }
  378. /**
  379. * Sets style names for the wrapper wrapping the widget in the layout. The
  380. * style names will be prefixed with v-absolutelayout-wrapper.
  381. *
  382. * @param widget
  383. * The widget which wrapper we want to add the stylenames to
  384. * @param stylenames
  385. * The style names that should be added to the wrapper
  386. */
  387. public void setWidgetWrapperStyleNames(Widget widget, String... stylenames) {
  388. AbsoluteWrapper wrapper = getChildWrapper(widget);
  389. if (wrapper == null) {
  390. throw new IllegalArgumentException(
  391. "No wrapper for widget found, has the widget been added to the layout?");
  392. }
  393. wrapper.setWrapperStyleNames(stylenames);
  394. }
  395. /**
  396. * Internal wrapper for wrapping widgets in the Absolute layout
  397. */
  398. protected class AbsoluteWrapper extends SimplePanel {
  399. private String css;
  400. private String left;
  401. private String top;
  402. private String right;
  403. private String bottom;
  404. private String zIndex;
  405. private VCaption caption;
  406. private String[] extraStyleNames;
  407. /**
  408. * Constructor
  409. *
  410. * @param child
  411. * The child to wrap
  412. */
  413. public AbsoluteWrapper(Widget child) {
  414. setWidget(child);
  415. }
  416. /**
  417. * Get the caption of the wrapper
  418. */
  419. public VCaption getCaption() {
  420. return caption;
  421. }
  422. /**
  423. * Set the caption for the wrapper
  424. *
  425. * @param caption
  426. * The caption for the wrapper
  427. */
  428. public void setCaption(VCaption caption) {
  429. if (caption != null) {
  430. this.caption = caption;
  431. } else if (this.caption != null) {
  432. this.caption.removeFromParent();
  433. this.caption = caption;
  434. }
  435. }
  436. /**
  437. * Removes the wrapper caption and itself from the layout
  438. */
  439. public void destroy() {
  440. if (caption != null) {
  441. caption.removeFromParent();
  442. }
  443. removeFromParent();
  444. }
  445. /**
  446. * Set the position for the wrapper in the layout
  447. *
  448. * @param position
  449. * The position string
  450. */
  451. public void setPosition(String position) {
  452. if (css == null || !css.equals(position)) {
  453. css = position;
  454. top = right = bottom = left = zIndex = null;
  455. if (!css.equals("")) {
  456. String[] properties = css.split(";");
  457. for (int i = 0; i < properties.length; i++) {
  458. String[] keyValue = properties[i].split(":");
  459. if (keyValue[0].equals("left")) {
  460. left = keyValue[1];
  461. } else if (keyValue[0].equals("top")) {
  462. top = keyValue[1];
  463. } else if (keyValue[0].equals("right")) {
  464. right = keyValue[1];
  465. } else if (keyValue[0].equals("bottom")) {
  466. bottom = keyValue[1];
  467. } else if (keyValue[0].equals("z-index")) {
  468. zIndex = keyValue[1];
  469. }
  470. }
  471. }
  472. // ensure ne values
  473. Style style = getElement().getStyle();
  474. /*
  475. * IE8 dies when nulling zIndex, even in IE7 mode. All other css
  476. * properties (and even in older IE's) accept null values just
  477. * fine. Assign empty string instead of null.
  478. */
  479. if (zIndex != null) {
  480. style.setProperty("zIndex", zIndex);
  481. } else {
  482. style.setProperty("zIndex", "");
  483. }
  484. style.setProperty("top", top);
  485. style.setProperty("left", left);
  486. style.setProperty("right", right);
  487. style.setProperty("bottom", bottom);
  488. }
  489. updateCaptionPosition();
  490. }
  491. /**
  492. * Updates the caption position by using element offset left and top
  493. */
  494. private void updateCaptionPosition() {
  495. if (caption != null) {
  496. Style style = caption.getElement().getStyle();
  497. style.setProperty("position", "absolute");
  498. style.setPropertyPx("left", getElement().getOffsetLeft());
  499. style.setPropertyPx("top", getElement().getOffsetTop()
  500. - caption.getHeight());
  501. }
  502. }
  503. /**
  504. * Sets the style names of the wrapper. Will be prefixed with the
  505. * v-absolutelayout-wrapper prefix
  506. *
  507. * @param stylenames
  508. * The wrapper style names
  509. */
  510. public void setWrapperStyleNames(String... stylenames) {
  511. extraStyleNames = stylenames;
  512. updateStyleNames();
  513. }
  514. /**
  515. * Updates the style names using the primary style name as prefix
  516. */
  517. protected void updateStyleNames() {
  518. setStyleName(VAbsoluteLayout.this.getStylePrimaryName()
  519. + "-wrapper");
  520. if (extraStyleNames != null) {
  521. for (String stylename : extraStyleNames) {
  522. addStyleDependentName(stylename);
  523. }
  524. }
  525. }
  526. }
  527. }