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.

AbstractSplitPanelConnector.java 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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.splitpanel;
  17. import java.util.LinkedList;
  18. import java.util.List;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.NativeEvent;
  21. import com.google.gwt.event.dom.client.DomEvent;
  22. import com.google.gwt.event.dom.client.DomEvent.Type;
  23. import com.google.gwt.event.shared.EventHandler;
  24. import com.google.gwt.event.shared.HandlerRegistration;
  25. import com.google.gwt.user.client.DOM;
  26. import com.google.gwt.user.client.Event;
  27. import com.google.gwt.user.client.ui.Widget;
  28. import com.vaadin.client.ComponentConnector;
  29. import com.vaadin.client.ConnectorHierarchyChangeEvent;
  30. import com.vaadin.client.LayoutManager;
  31. import com.vaadin.client.communication.StateChangeEvent;
  32. import com.vaadin.client.ui.AbstractComponentContainerConnector;
  33. import com.vaadin.client.ui.ClickEventHandler;
  34. import com.vaadin.client.ui.SimpleManagedLayout;
  35. import com.vaadin.client.ui.VAbstractSplitPanel;
  36. import com.vaadin.client.ui.VAbstractSplitPanel.SplitterMoveHandler;
  37. import com.vaadin.client.ui.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent;
  38. import com.vaadin.shared.MouseEventDetails;
  39. import com.vaadin.shared.ui.ComponentStateUtil;
  40. import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelRpc;
  41. import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState;
  42. import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState.SplitterState;
  43. public abstract class AbstractSplitPanelConnector extends
  44. AbstractComponentContainerConnector implements SimpleManagedLayout {
  45. @Override
  46. protected void init() {
  47. super.init();
  48. // TODO Remove
  49. getWidget().client = getConnection();
  50. getWidget().addHandler(new SplitterMoveHandler() {
  51. @Override
  52. public void splitterMoved(SplitterMoveEvent event) {
  53. String position = getWidget().getSplitterPosition();
  54. float pos = 0;
  55. if (position.indexOf("%") > 0) {
  56. // Send % values as a fraction to avoid that the splitter
  57. // "jumps" when server responds with the integer pct value
  58. // (e.g. dragged 16.6% -> should not jump to 17%)
  59. pos = Float.valueOf(
  60. position.substring(0, position.length() - 1));
  61. } else {
  62. pos = Integer.parseInt(
  63. position.substring(0, position.length() - 2));
  64. }
  65. getRpcProxy(AbstractSplitPanelRpc.class)
  66. .setSplitterPosition(pos);
  67. }
  68. }, SplitterMoveEvent.TYPE);
  69. }
  70. @Override
  71. public void updateCaption(ComponentConnector component) {
  72. // TODO Implement caption handling
  73. }
  74. ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
  75. @Override
  76. protected <H extends EventHandler> HandlerRegistration registerHandler(
  77. H handler, Type<H> type) {
  78. if ((Event.getEventsSunk(getWidget().splitter)
  79. & Event.getTypeInt(type.getName())) != 0) {
  80. // If we are already sinking the event for the splitter we do
  81. // not want to additionally sink it for the root element
  82. return getWidget().addHandler(handler, type);
  83. } else {
  84. return getWidget().addDomHandler(handler, type);
  85. }
  86. }
  87. @Override
  88. protected boolean shouldFireEvent(DomEvent<?> event) {
  89. Element target = event.getNativeEvent().getEventTarget().cast();
  90. if (!getWidget().splitter.isOrHasChild(target)) {
  91. return false;
  92. }
  93. return super.shouldFireEvent(event);
  94. }
  95. @Override
  96. protected com.google.gwt.user.client.Element getRelativeToElement() {
  97. return DOM.asOld(getWidget().splitter);
  98. }
  99. @Override
  100. protected void fireClick(NativeEvent event,
  101. MouseEventDetails mouseDetails) {
  102. getRpcProxy(AbstractSplitPanelRpc.class)
  103. .splitterClick(mouseDetails);
  104. }
  105. };
  106. @Override
  107. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  108. super.onStateChanged(stateChangeEvent);
  109. getWidget().immediate = getState().immediate;
  110. getWidget().setEnabled(isEnabled());
  111. clickEventHandler.handleEventHandlerRegistration();
  112. if (ComponentStateUtil.hasStyles(getState())) {
  113. getWidget().componentStyleNames = getState().styles;
  114. } else {
  115. getWidget().componentStyleNames = new LinkedList<>();
  116. }
  117. // Splitter updates
  118. SplitterState splitterState = getState().splitterState;
  119. getWidget().setStylenames();
  120. getWidget().minimumPosition = splitterState.minPosition
  121. + splitterState.minPositionUnit;
  122. getWidget().maximumPosition = splitterState.maxPosition
  123. + splitterState.maxPositionUnit;
  124. getWidget().position = splitterState.position
  125. + splitterState.positionUnit;
  126. getWidget().setPositionReversed(splitterState.positionReversed);
  127. getWidget().setLocked(splitterState.locked);
  128. // This is needed at least for cases like #3458 to take
  129. // appearing/disappearing scrollbars into account.
  130. getConnection().runDescendentsLayout(getWidget());
  131. getLayoutManager().setNeedsLayout(this);
  132. getWidget().makeScrollable();
  133. handleSingleComponentMove();
  134. }
  135. /**
  136. * Handles the case when there is only one child component and that
  137. * component is moved between first <-> second. This does not trigger a
  138. * hierarchy change event as the list of children contains the same
  139. * component in both cases.
  140. */
  141. private void handleSingleComponentMove() {
  142. if (getChildComponents().size() == 1) {
  143. Widget stateFirstChild = null;
  144. Widget stateSecondChild = null;
  145. if (getState().firstChild != null) {
  146. stateFirstChild = ((ComponentConnector) getState().firstChild)
  147. .getWidget();
  148. }
  149. if (getState().secondChild != null) {
  150. stateSecondChild = ((ComponentConnector) getState().secondChild)
  151. .getWidget();
  152. }
  153. if (stateFirstChild == getWidget().getSecondWidget()
  154. || stateSecondChild == getWidget().getFirstWidget()) {
  155. handleHierarchyChange();
  156. }
  157. }
  158. }
  159. @Override
  160. public void layout() {
  161. VAbstractSplitPanel splitPanel = getWidget();
  162. splitPanel.setSplitPosition(splitPanel.position);
  163. splitPanel.updateSizes();
  164. // Report relative sizes in other direction for quicker propagation
  165. List<ComponentConnector> children = getChildComponents();
  166. for (ComponentConnector child : children) {
  167. reportOtherDimension(child);
  168. }
  169. }
  170. private void reportOtherDimension(ComponentConnector child) {
  171. LayoutManager layoutManager = getLayoutManager();
  172. if (this instanceof HorizontalSplitPanelConnector) {
  173. if (child.isRelativeHeight()) {
  174. int height = layoutManager
  175. .getInnerHeight(getWidget().getElement());
  176. layoutManager.reportHeightAssignedToRelative(child, height);
  177. }
  178. } else {
  179. if (child.isRelativeWidth()) {
  180. int width = layoutManager
  181. .getInnerWidth(getWidget().getElement());
  182. layoutManager.reportWidthAssignedToRelative(child, width);
  183. }
  184. }
  185. }
  186. @Override
  187. public VAbstractSplitPanel getWidget() {
  188. return (VAbstractSplitPanel) super.getWidget();
  189. }
  190. @Override
  191. public AbstractSplitPanelState getState() {
  192. return (AbstractSplitPanelState) super.getState();
  193. }
  194. private ComponentConnector getFirstChild() {
  195. return (ComponentConnector) getState().firstChild;
  196. }
  197. private ComponentConnector getSecondChild() {
  198. return (ComponentConnector) getState().secondChild;
  199. }
  200. @Override
  201. public void onConnectorHierarchyChange(
  202. ConnectorHierarchyChangeEvent event) {
  203. handleHierarchyChange();
  204. }
  205. private void handleHierarchyChange() {
  206. /*
  207. * When the connector gets detached, the state isn't updated but there's
  208. * still a hierarchy change -> verify that the child from the state is
  209. * still our child before attaching the widget. See #10150.
  210. */
  211. Widget newFirstChildWidget = null;
  212. ComponentConnector firstChild = getFirstChild();
  213. if (firstChild != null && firstChild.getParent() == this) {
  214. newFirstChildWidget = firstChild.getWidget();
  215. }
  216. getWidget().setFirstWidget(newFirstChildWidget);
  217. Widget newSecondChildWidget = null;
  218. ComponentConnector secondChild = getSecondChild();
  219. if (secondChild != null && secondChild.getParent() == this) {
  220. newSecondChildWidget = secondChild.getWidget();
  221. }
  222. getWidget().setSecondWidget(newSecondChildWidget);
  223. }
  224. }