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.

VAccordion.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * Copyright 2000-2016 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 java.util.HashSet;
  18. import java.util.Iterator;
  19. import java.util.Set;
  20. import com.google.gwt.dom.client.Element;
  21. import com.google.gwt.dom.client.Style.Unit;
  22. import com.google.gwt.dom.client.Style.Visibility;
  23. import com.google.gwt.event.dom.client.ClickEvent;
  24. import com.google.gwt.event.dom.client.ClickHandler;
  25. import com.google.gwt.user.client.DOM;
  26. import com.google.gwt.user.client.Event;
  27. import com.google.gwt.user.client.ui.ComplexPanel;
  28. import com.google.gwt.user.client.ui.Widget;
  29. import com.vaadin.client.ComponentConnector;
  30. import com.vaadin.client.VCaption;
  31. import com.vaadin.client.WidgetUtil;
  32. import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
  33. import com.vaadin.shared.ComponentConstants;
  34. import com.vaadin.shared.ui.accordion.AccordionState;
  35. import com.vaadin.shared.ui.tabsheet.TabState;
  36. import com.vaadin.shared.ui.tabsheet.TabsheetServerRpc;
  37. import com.vaadin.shared.util.SharedUtil;
  38. public class VAccordion extends VTabsheetBase {
  39. public static final String CLASSNAME = AccordionState.PRIMARY_STYLE_NAME;
  40. private Set<Widget> widgets = new HashSet<>();
  41. private StackItem openTab;
  42. /** For internal use only. May be removed or replaced in the future. */
  43. public int selectedItemIndex = -1;
  44. private final TouchScrollHandler touchScrollHandler;
  45. public VAccordion() {
  46. super(CLASSNAME);
  47. touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
  48. }
  49. @Override
  50. public void renderTab(TabState tabState, int index) {
  51. StackItem item;
  52. int itemIndex;
  53. if (getWidgetCount() <= index) {
  54. // Create stackItem and render caption
  55. item = new StackItem();
  56. if (getWidgetCount() == 0) {
  57. item.addStyleDependentName("first");
  58. }
  59. itemIndex = getWidgetCount();
  60. add(item, getElement());
  61. } else {
  62. item = getStackItem(index);
  63. itemIndex = index;
  64. }
  65. item.updateCaption(tabState);
  66. item.updateTabStyleName(tabState.styleName);
  67. item.setVisible(tabState.visible);
  68. item.setId(tabState.id);
  69. }
  70. @Override
  71. public void selectTab(int index) {
  72. selectedItemIndex = index;
  73. }
  74. @Override
  75. public void setStylePrimaryName(String style) {
  76. super.setStylePrimaryName(style);
  77. updateStyleNames(style);
  78. }
  79. @Override
  80. public void setStyleName(String style) {
  81. super.setStyleName(style);
  82. updateStyleNames(style);
  83. }
  84. protected void updateStyleNames(String primaryStyleName) {
  85. for (Widget w : getChildren()) {
  86. if (w instanceof StackItem) {
  87. StackItem item = (StackItem) w;
  88. item.updateStyleNames(primaryStyleName);
  89. }
  90. }
  91. }
  92. /** For internal use only. May be removed or replaced in the future. */
  93. public void open(int itemIndex) {
  94. StackItem item = (StackItem) getWidget(itemIndex);
  95. boolean alreadyOpen = false;
  96. if (openTab != null) {
  97. if (openTab.isOpen()) {
  98. if (openTab == item) {
  99. alreadyOpen = true;
  100. } else {
  101. openTab.close();
  102. }
  103. }
  104. }
  105. if (!alreadyOpen) {
  106. item.open();
  107. activeTabIndex = itemIndex;
  108. openTab = item;
  109. }
  110. }
  111. /** For internal use only. May be removed or replaced in the future. */
  112. public void close(StackItem item) {
  113. if (!item.isOpen()) {
  114. return;
  115. }
  116. item.close();
  117. activeTabIndex = -1;
  118. openTab = null;
  119. }
  120. public void onSelectTab(StackItem item) {
  121. final int index = getWidgetIndex(item);
  122. if (index != activeTabIndex && !disabled && !readonly
  123. && !disabledTabKeys.contains(tabKeys.get(index))) {
  124. addStyleDependentName("loading");
  125. connector.getRpcProxy(TabsheetServerRpc.class)
  126. .setSelected(tabKeys.get(index).toString());
  127. }
  128. }
  129. /**
  130. * A StackItem has always two children, Child 0 is a VCaption, Child 1 is
  131. * the actual child widget.
  132. */
  133. public class StackItem extends ComplexPanel implements ClickHandler {
  134. private Widget widget;
  135. private String id;
  136. public void setHeight(int height) {
  137. if (height == -1) {
  138. super.setHeight("");
  139. content.getStyle().setHeight(0, Unit.PX);
  140. } else {
  141. super.setHeight((height + getCaptionHeight()) + "px");
  142. content.getStyle().setHeight(height, Unit.PX);
  143. content.getStyle().setTop(getCaptionHeight(), Unit.PX);
  144. }
  145. }
  146. public void setId(String newId) {
  147. if (!SharedUtil.equals(newId, id)) {
  148. if (id != null) {
  149. getElement().removeAttribute("id");
  150. }
  151. id = newId;
  152. if (id != null && !id.isEmpty()) {
  153. getElement().setId(id);
  154. }
  155. }
  156. }
  157. public Widget getComponent() {
  158. return widget;
  159. }
  160. @Override
  161. public void setVisible(boolean visible) {
  162. super.setVisible(visible);
  163. }
  164. public void setHeightFromWidget() {
  165. Widget widget = getChildWidget();
  166. if (widget == null) {
  167. return;
  168. }
  169. int paintableHeight = widget.getElement().getOffsetHeight();
  170. setHeight(paintableHeight);
  171. }
  172. /**
  173. * Returns caption width including padding
  174. *
  175. * @return
  176. */
  177. public int getCaptionWidth() {
  178. if (caption == null) {
  179. return 0;
  180. }
  181. int captionWidth = caption.getRequiredWidth();
  182. int padding = WidgetUtil.measureHorizontalPaddingAndBorder(
  183. caption.getElement(), 18);
  184. return captionWidth + padding;
  185. }
  186. public void setWidth(int width) {
  187. if (width == -1) {
  188. super.setWidth("");
  189. } else {
  190. super.setWidth(width + "px");
  191. }
  192. }
  193. public int getHeight() {
  194. return getOffsetHeight();
  195. }
  196. public int getCaptionHeight() {
  197. return captionNode.getOffsetHeight();
  198. }
  199. private VCaption caption;
  200. private boolean open = false;
  201. private Element content = DOM.createDiv();
  202. private Element captionNode = DOM.createDiv();
  203. private String styleName;
  204. public StackItem() {
  205. setElement(DOM.createDiv());
  206. caption = new VCaption(client);
  207. caption.addClickHandler(this);
  208. super.add(caption, captionNode);
  209. DOM.appendChild(captionNode, caption.getElement());
  210. DOM.appendChild(getElement(), captionNode);
  211. DOM.appendChild(getElement(), content);
  212. updateStyleNames(VAccordion.this.getStylePrimaryName());
  213. touchScrollHandler.addElement(getContainerElement());
  214. close();
  215. }
  216. private void updateStyleNames(String primaryStyleName) {
  217. content.removeClassName(getStylePrimaryName() + "-content");
  218. captionNode.removeClassName(getStylePrimaryName() + "-caption");
  219. setStylePrimaryName(primaryStyleName + "-item");
  220. updateTabStyleName(getStylePrimaryName());
  221. captionNode.addClassName(getStylePrimaryName() + "-caption");
  222. content.addClassName(getStylePrimaryName() + "-content");
  223. }
  224. @Override
  225. public void onBrowserEvent(Event event) {
  226. onSelectTab(this);
  227. }
  228. public com.google.gwt.user.client.Element getContainerElement() {
  229. return DOM.asOld(content);
  230. }
  231. public Widget getChildWidget() {
  232. return widget;
  233. }
  234. public void replaceWidget(Widget newWidget) {
  235. if (widget != null) {
  236. widgets.remove(widget);
  237. if (open) {
  238. remove(widget);
  239. }
  240. }
  241. widget = newWidget;
  242. widgets.add(newWidget);
  243. if (open) {
  244. add(widget, content);
  245. }
  246. }
  247. public void open() {
  248. add(widget, content);
  249. open = true;
  250. content.getStyle().setTop(getCaptionHeight(), Unit.PX);
  251. content.getStyle().setLeft(0, Unit.PX);
  252. content.getStyle().clearVisibility();
  253. addStyleDependentName("open");
  254. }
  255. public void hide() {
  256. content.getStyle().setVisibility(Visibility.HIDDEN);
  257. }
  258. public void close() {
  259. if (widget != null) {
  260. remove(widget);
  261. }
  262. content.getStyle().setVisibility(Visibility.HIDDEN);
  263. content.getStyle().setTop(-100000, Unit.PX);
  264. content.getStyle().setLeft(-100000, Unit.PX);
  265. removeStyleDependentName("open");
  266. setHeight(-1);
  267. setWidth("");
  268. open = false;
  269. }
  270. public boolean isOpen() {
  271. return open;
  272. }
  273. /**
  274. * Updates the content of the open tab of the accordion.
  275. *
  276. * This method is mostly for internal use and may change in future
  277. * versions.
  278. *
  279. * @since 7.2
  280. * @param newWidget
  281. * new content
  282. */
  283. public void setContent(Widget newWidget) {
  284. if (widget == null) {
  285. widget = newWidget;
  286. widgets.add(newWidget);
  287. } else if (widget != newWidget) {
  288. replaceWidget(newWidget);
  289. }
  290. if (isOpen() && isDynamicHeight()) {
  291. setHeightFromWidget();
  292. }
  293. }
  294. @Override
  295. public void onClick(ClickEvent event) {
  296. onSelectTab(this);
  297. }
  298. public void updateCaption(TabState tabState) {
  299. // TODO need to call this because the caption does not have an owner
  300. caption.setCaptionAsHtml(isTabCaptionsAsHtml());
  301. caption.updateCaptionWithoutOwner(tabState.caption,
  302. !tabState.enabled, hasAttribute(tabState.description),
  303. hasAttribute(tabState.componentError),
  304. connector.getResourceUrl(
  305. ComponentConstants.ICON_RESOURCE + tabState.key));
  306. }
  307. private boolean hasAttribute(String string) {
  308. return string != null && !string.trim().isEmpty();
  309. }
  310. /**
  311. * Updates a tabs stylename from the child UIDL
  312. *
  313. * @param uidl
  314. * The child UIDL of the tab
  315. */
  316. private void updateTabStyleName(String newStyleName) {
  317. if (newStyleName != null && !newStyleName.isEmpty()) {
  318. if (!newStyleName.equals(styleName)) {
  319. // If we have a new style name
  320. if (styleName != null && !styleName.isEmpty()) {
  321. // Remove old style name if present
  322. removeStyleDependentName(styleName);
  323. }
  324. // Set new style name
  325. addStyleDependentName(newStyleName);
  326. styleName = newStyleName;
  327. }
  328. } else if (styleName != null) {
  329. // Remove the set stylename if no stylename is present in the
  330. // uidl
  331. removeStyleDependentName(styleName);
  332. styleName = null;
  333. }
  334. }
  335. public int getWidgetWidth() {
  336. return DOM.getFirstChild(content).getOffsetWidth();
  337. }
  338. public boolean contains(ComponentConnector p) {
  339. return (getChildWidget() == p.getWidget());
  340. }
  341. public boolean isCaptionVisible() {
  342. return caption.isVisible();
  343. }
  344. }
  345. @Override
  346. protected void clearPaintables() {
  347. clear();
  348. }
  349. @Override
  350. public Iterator<Widget> getWidgetIterator() {
  351. return widgets.iterator();
  352. }
  353. @Override
  354. public int getTabCount() {
  355. return getWidgetCount();
  356. }
  357. @Override
  358. public void removeTab(int index) {
  359. StackItem item = getStackItem(index);
  360. remove(item);
  361. if (selectedItemIndex == index) {
  362. selectedItemIndex = -1;
  363. }
  364. touchScrollHandler.removeElement(item.getContainerElement());
  365. }
  366. @Override
  367. public ComponentConnector getTab(int index) {
  368. if (index < getWidgetCount()) {
  369. StackItem stackItem = getStackItem(index);
  370. if (stackItem == null) {
  371. return null;
  372. }
  373. Widget w = stackItem.getChildWidget();
  374. if (w != null) {
  375. return getConnectorForWidget(w);
  376. }
  377. }
  378. return null;
  379. }
  380. /** For internal use only. May be removed or replaced in the future. */
  381. public StackItem getStackItem(int index) {
  382. return (StackItem) getWidget(index);
  383. }
  384. public Iterable<StackItem> getStackItems() {
  385. return (Iterable) getChildren();
  386. }
  387. public StackItem getOpenStackItem() {
  388. return openTab;
  389. }
  390. }