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.3KB

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