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.

VSplitPanel.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.Set;
  6. import com.google.gwt.dom.client.NativeEvent;
  7. import com.google.gwt.dom.client.Node;
  8. import com.google.gwt.event.dom.client.DomEvent.Type;
  9. import com.google.gwt.event.dom.client.TouchCancelEvent;
  10. import com.google.gwt.event.dom.client.TouchCancelHandler;
  11. import com.google.gwt.event.dom.client.TouchEndEvent;
  12. import com.google.gwt.event.dom.client.TouchEndHandler;
  13. import com.google.gwt.event.dom.client.TouchMoveEvent;
  14. import com.google.gwt.event.dom.client.TouchMoveHandler;
  15. import com.google.gwt.event.dom.client.TouchStartEvent;
  16. import com.google.gwt.event.dom.client.TouchStartHandler;
  17. import com.google.gwt.event.shared.EventHandler;
  18. import com.google.gwt.event.shared.HandlerRegistration;
  19. import com.google.gwt.user.client.DOM;
  20. import com.google.gwt.user.client.Element;
  21. import com.google.gwt.user.client.Event;
  22. import com.google.gwt.user.client.ui.ComplexPanel;
  23. import com.google.gwt.user.client.ui.Widget;
  24. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  25. import com.vaadin.terminal.gwt.client.BrowserInfo;
  26. import com.vaadin.terminal.gwt.client.Container;
  27. import com.vaadin.terminal.gwt.client.ContainerResizedListener;
  28. import com.vaadin.terminal.gwt.client.RenderInformation;
  29. import com.vaadin.terminal.gwt.client.RenderSpace;
  30. import com.vaadin.terminal.gwt.client.UIDL;
  31. import com.vaadin.terminal.gwt.client.Util;
  32. import com.vaadin.terminal.gwt.client.VConsole;
  33. import com.vaadin.terminal.gwt.client.VPaintableMap;
  34. import com.vaadin.terminal.gwt.client.VPaintableWidget;
  35. public class VSplitPanel extends ComplexPanel implements Container,
  36. ContainerResizedListener {
  37. private boolean enabled = false;
  38. public static final String CLASSNAME = "v-splitpanel";
  39. public static final String SPLITTER_CLICK_EVENT_IDENTIFIER = "sp_click";
  40. private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
  41. SPLITTER_CLICK_EVENT_IDENTIFIER) {
  42. @Override
  43. protected <H extends EventHandler> HandlerRegistration registerHandler(
  44. H handler, Type<H> type) {
  45. if ((Event.getEventsSunk(splitter) & Event.getTypeInt(type
  46. .getName())) != 0) {
  47. // If we are already sinking the event for the splitter we do
  48. // not want to additionally sink it for the root element
  49. return addHandler(handler, type);
  50. } else {
  51. return addDomHandler(handler, type);
  52. }
  53. }
  54. @Override
  55. public void onContextMenu(
  56. com.google.gwt.event.dom.client.ContextMenuEvent event) {
  57. Element target = event.getNativeEvent().getEventTarget().cast();
  58. if (splitter.isOrHasChild(target)) {
  59. super.onContextMenu(event);
  60. }
  61. };
  62. @Override
  63. protected void fireClick(NativeEvent event) {
  64. Element target = event.getEventTarget().cast();
  65. if (splitter.isOrHasChild(target)) {
  66. super.fireClick(event);
  67. }
  68. }
  69. @Override
  70. protected Element getRelativeToElement() {
  71. return null;
  72. }
  73. };
  74. public static final int ORIENTATION_HORIZONTAL = 0;
  75. public static final int ORIENTATION_VERTICAL = 1;
  76. private static final int MIN_SIZE = 30;
  77. private int orientation = ORIENTATION_HORIZONTAL;
  78. private Widget firstChild;
  79. private Widget secondChild;
  80. private final Element wrapper = DOM.createDiv();
  81. private final Element firstContainer = DOM.createDiv();
  82. private final Element secondContainer = DOM.createDiv();
  83. private final Element splitter = DOM.createDiv();
  84. private boolean resizing;
  85. private boolean resized = false;
  86. private int origX;
  87. private int origY;
  88. private int origMouseX;
  89. private int origMouseY;
  90. private boolean locked = false;
  91. private boolean positionReversed = false;
  92. private String[] componentStyleNames;
  93. private Element draggingCurtain;
  94. private ApplicationConnection client;
  95. private String width = "";
  96. private String height = "";
  97. private RenderSpace firstRenderSpace = new RenderSpace(0, 0, true);
  98. private RenderSpace secondRenderSpace = new RenderSpace(0, 0, true);
  99. RenderInformation renderInformation = new RenderInformation();
  100. private String id;
  101. private boolean immediate;
  102. private boolean rendering = false;
  103. /* The current position of the split handle in either percentages or pixels */
  104. private String position;
  105. protected Element scrolledContainer;
  106. protected int origScrollTop;
  107. private TouchScrollDelegate touchScrollDelegate;
  108. public VSplitPanel() {
  109. this(ORIENTATION_HORIZONTAL);
  110. }
  111. public VSplitPanel(int orientation) {
  112. setElement(DOM.createDiv());
  113. switch (orientation) {
  114. case ORIENTATION_HORIZONTAL:
  115. setStyleName(CLASSNAME + "-horizontal");
  116. break;
  117. case ORIENTATION_VERTICAL:
  118. default:
  119. setStyleName(CLASSNAME + "-vertical");
  120. break;
  121. }
  122. // size below will be overridden in update from uidl, initial size
  123. // needed to keep IE alive
  124. setWidth(MIN_SIZE + "px");
  125. setHeight(MIN_SIZE + "px");
  126. constructDom();
  127. setOrientation(orientation);
  128. sinkEvents(Event.MOUSEEVENTS);
  129. addDomHandler(new TouchCancelHandler() {
  130. public void onTouchCancel(TouchCancelEvent event) {
  131. // TODO When does this actually happen??
  132. VConsole.log("TOUCH CANCEL");
  133. }
  134. }, TouchCancelEvent.getType());
  135. addDomHandler(new TouchStartHandler() {
  136. public void onTouchStart(TouchStartEvent event) {
  137. Node target = event.getTouches().get(0).getTarget().cast();
  138. if (splitter.isOrHasChild(target)) {
  139. onMouseDown(Event.as(event.getNativeEvent()));
  140. } else {
  141. getTouchScrollDelegate().onTouchStart(event);
  142. }
  143. }
  144. }, TouchStartEvent.getType());
  145. addDomHandler(new TouchMoveHandler() {
  146. public void onTouchMove(TouchMoveEvent event) {
  147. if (resizing) {
  148. onMouseMove(Event.as(event.getNativeEvent()));
  149. }
  150. }
  151. }, TouchMoveEvent.getType());
  152. addDomHandler(new TouchEndHandler() {
  153. public void onTouchEnd(TouchEndEvent event) {
  154. if (resizing) {
  155. onMouseUp(Event.as(event.getNativeEvent()));
  156. }
  157. }
  158. }, TouchEndEvent.getType());
  159. }
  160. private TouchScrollDelegate getTouchScrollDelegate() {
  161. if (touchScrollDelegate == null) {
  162. touchScrollDelegate = new TouchScrollDelegate(firstContainer,
  163. secondContainer);
  164. }
  165. return touchScrollDelegate;
  166. }
  167. protected void constructDom() {
  168. DOM.appendChild(splitter, DOM.createDiv()); // for styling
  169. DOM.appendChild(getElement(), wrapper);
  170. DOM.setStyleAttribute(wrapper, "position", "relative");
  171. DOM.setStyleAttribute(wrapper, "width", "100%");
  172. DOM.setStyleAttribute(wrapper, "height", "100%");
  173. DOM.appendChild(wrapper, secondContainer);
  174. DOM.appendChild(wrapper, firstContainer);
  175. DOM.appendChild(wrapper, splitter);
  176. DOM.setStyleAttribute(splitter, "position", "absolute");
  177. DOM.setStyleAttribute(secondContainer, "position", "absolute");
  178. DOM.setStyleAttribute(firstContainer, "overflow", "auto");
  179. DOM.setStyleAttribute(secondContainer, "overflow", "auto");
  180. }
  181. private void setOrientation(int orientation) {
  182. this.orientation = orientation;
  183. if (orientation == ORIENTATION_HORIZONTAL) {
  184. DOM.setStyleAttribute(splitter, "height", "100%");
  185. DOM.setStyleAttribute(splitter, "top", "0");
  186. DOM.setStyleAttribute(firstContainer, "height", "100%");
  187. DOM.setStyleAttribute(secondContainer, "height", "100%");
  188. } else {
  189. DOM.setStyleAttribute(splitter, "width", "100%");
  190. DOM.setStyleAttribute(splitter, "left", "0");
  191. DOM.setStyleAttribute(firstContainer, "width", "100%");
  192. DOM.setStyleAttribute(secondContainer, "width", "100%");
  193. }
  194. DOM.setElementProperty(firstContainer, "className", CLASSNAME
  195. + "-first-container");
  196. DOM.setElementProperty(secondContainer, "className", CLASSNAME
  197. + "-second-container");
  198. }
  199. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  200. this.client = client;
  201. id = uidl.getId();
  202. rendering = true;
  203. immediate = uidl.hasAttribute("immediate");
  204. if (client.updateComponent(this, uidl, true)) {
  205. rendering = false;
  206. return;
  207. }
  208. setEnabled(!uidl.getBooleanAttribute("disabled"));
  209. clickEventHandler.handleEventHandlerRegistration(client);
  210. if (uidl.hasAttribute("style")) {
  211. componentStyleNames = uidl.getStringAttribute("style").split(" ");
  212. } else {
  213. componentStyleNames = new String[0];
  214. }
  215. setLocked(uidl.getBooleanAttribute("locked"));
  216. setPositionReversed(uidl.getBooleanAttribute("reversed"));
  217. setStylenames();
  218. position = uidl.getStringAttribute("position");
  219. setSplitPosition(position);
  220. final VPaintableWidget newFirstChildPaintable = client
  221. .getPaintable(uidl.getChildUIDL(0));
  222. final VPaintableWidget newSecondChildPaintable = client
  223. .getPaintable(uidl.getChildUIDL(1));
  224. Widget newFirstChild = newFirstChildPaintable.getWidgetForPaintable();
  225. Widget newSecondChild = newSecondChildPaintable.getWidgetForPaintable();
  226. if (firstChild != newFirstChild) {
  227. if (firstChild != null) {
  228. client.unregisterPaintable(VPaintableMap.get(client)
  229. .getPaintable(firstChild));
  230. }
  231. setFirstWidget(newFirstChild);
  232. }
  233. if (secondChild != newSecondChild) {
  234. if (secondChild != null) {
  235. client.unregisterPaintable(VPaintableMap.get(client)
  236. .getPaintable(secondChild));
  237. }
  238. setSecondWidget(newSecondChild);
  239. }
  240. newFirstChildPaintable.updateFromUIDL(uidl.getChildUIDL(0), client);
  241. newSecondChildPaintable.updateFromUIDL(uidl.getChildUIDL(1), client);
  242. renderInformation.updateSize(getElement());
  243. // This is needed at least for cases like #3458 to take
  244. // appearing/disappearing scrollbars into account.
  245. client.runDescendentsLayout(this);
  246. rendering = false;
  247. }
  248. @Override
  249. public boolean remove(Widget w) {
  250. boolean removed = super.remove(w);
  251. if (removed) {
  252. if (firstChild == w) {
  253. firstChild = null;
  254. } else {
  255. secondChild = null;
  256. }
  257. }
  258. return removed;
  259. }
  260. private void setLocked(boolean newValue) {
  261. if (locked != newValue) {
  262. locked = newValue;
  263. splitterSize = -1;
  264. setStylenames();
  265. }
  266. }
  267. private void setPositionReversed(boolean reversed) {
  268. if (positionReversed != reversed) {
  269. if (orientation == ORIENTATION_HORIZONTAL) {
  270. DOM.setStyleAttribute(splitter, "right", "");
  271. DOM.setStyleAttribute(splitter, "left", "");
  272. } else if (orientation == ORIENTATION_VERTICAL) {
  273. DOM.setStyleAttribute(splitter, "top", "");
  274. DOM.setStyleAttribute(splitter, "bottom", "");
  275. }
  276. positionReversed = reversed;
  277. }
  278. }
  279. private void setSplitPosition(String pos) {
  280. if (pos == null) {
  281. return;
  282. }
  283. // Convert percentage values to pixels
  284. if (pos.indexOf("%") > 0) {
  285. pos = Float.parseFloat(pos.substring(0, pos.length() - 1))
  286. / 100
  287. * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
  288. : getOffsetHeight()) + "px";
  289. }
  290. if (orientation == ORIENTATION_HORIZONTAL) {
  291. if (positionReversed) {
  292. DOM.setStyleAttribute(splitter, "right", pos);
  293. } else {
  294. DOM.setStyleAttribute(splitter, "left", pos);
  295. }
  296. } else {
  297. if (positionReversed) {
  298. DOM.setStyleAttribute(splitter, "bottom", pos);
  299. } else {
  300. DOM.setStyleAttribute(splitter, "top", pos);
  301. }
  302. }
  303. iLayout();
  304. client.runDescendentsLayout(this);
  305. }
  306. /*
  307. * Calculates absolutely positioned container places/sizes (non-Javadoc)
  308. *
  309. * @see com.vaadin.terminal.gwt.client.NeedsLayout#layout()
  310. */
  311. public void iLayout() {
  312. if (!isAttached()) {
  313. return;
  314. }
  315. renderInformation.updateSize(getElement());
  316. int wholeSize;
  317. int pixelPosition;
  318. switch (orientation) {
  319. case ORIENTATION_HORIZONTAL:
  320. wholeSize = DOM.getElementPropertyInt(wrapper, "clientWidth");
  321. pixelPosition = DOM.getElementPropertyInt(splitter, "offsetLeft");
  322. // reposition splitter in case it is out of box
  323. if ((pixelPosition > 0 && pixelPosition + getSplitterSize() > wholeSize)
  324. || (positionReversed && pixelPosition < 0)) {
  325. pixelPosition = wholeSize - getSplitterSize();
  326. if (pixelPosition < 0) {
  327. pixelPosition = 0;
  328. }
  329. setSplitPosition(pixelPosition + "px");
  330. return;
  331. }
  332. DOM.setStyleAttribute(firstContainer, "width", pixelPosition + "px");
  333. int secondContainerWidth = (wholeSize - pixelPosition - getSplitterSize());
  334. if (secondContainerWidth < 0) {
  335. secondContainerWidth = 0;
  336. }
  337. DOM.setStyleAttribute(secondContainer, "width",
  338. secondContainerWidth + "px");
  339. DOM.setStyleAttribute(secondContainer, "left",
  340. (pixelPosition + getSplitterSize()) + "px");
  341. int contentHeight = renderInformation.getRenderedSize().getHeight();
  342. firstRenderSpace.setHeight(contentHeight);
  343. firstRenderSpace.setWidth(pixelPosition);
  344. secondRenderSpace.setHeight(contentHeight);
  345. secondRenderSpace.setWidth(secondContainerWidth);
  346. break;
  347. case ORIENTATION_VERTICAL:
  348. wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight");
  349. pixelPosition = DOM.getElementPropertyInt(splitter, "offsetTop");
  350. // reposition splitter in case it is out of box
  351. if ((pixelPosition > 0 && pixelPosition + getSplitterSize() > wholeSize)
  352. || (positionReversed && pixelPosition < 0)) {
  353. pixelPosition = wholeSize - getSplitterSize();
  354. if (pixelPosition < 0) {
  355. pixelPosition = 0;
  356. }
  357. setSplitPosition(pixelPosition + "px");
  358. return;
  359. }
  360. DOM.setStyleAttribute(firstContainer, "height", pixelPosition
  361. + "px");
  362. int secondContainerHeight = (wholeSize - pixelPosition - getSplitterSize());
  363. if (secondContainerHeight < 0) {
  364. secondContainerHeight = 0;
  365. }
  366. DOM.setStyleAttribute(secondContainer, "height",
  367. secondContainerHeight + "px");
  368. DOM.setStyleAttribute(secondContainer, "top",
  369. (pixelPosition + getSplitterSize()) + "px");
  370. int contentWidth = renderInformation.getRenderedSize().getWidth();
  371. firstRenderSpace.setHeight(pixelPosition);
  372. firstRenderSpace.setWidth(contentWidth);
  373. secondRenderSpace.setHeight(secondContainerHeight);
  374. secondRenderSpace.setWidth(contentWidth);
  375. break;
  376. }
  377. // fixes scrollbars issues on webkit based browsers
  378. Util.runWebkitOverflowAutoFix(secondContainer);
  379. Util.runWebkitOverflowAutoFix(firstContainer);
  380. }
  381. private void setFirstWidget(Widget w) {
  382. if (firstChild != null) {
  383. firstChild.removeFromParent();
  384. }
  385. super.add(w, firstContainer);
  386. firstChild = w;
  387. }
  388. private void setSecondWidget(Widget w) {
  389. if (secondChild != null) {
  390. secondChild.removeFromParent();
  391. }
  392. super.add(w, secondContainer);
  393. secondChild = w;
  394. }
  395. @Override
  396. public void onBrowserEvent(Event event) {
  397. switch (DOM.eventGetType(event)) {
  398. case Event.ONMOUSEMOVE:
  399. // case Event.ONTOUCHMOVE:
  400. if (resizing) {
  401. onMouseMove(event);
  402. }
  403. break;
  404. case Event.ONMOUSEDOWN:
  405. // case Event.ONTOUCHSTART:
  406. onMouseDown(event);
  407. break;
  408. case Event.ONMOUSEOUT:
  409. // Dragging curtain interferes with click events if added in
  410. // mousedown so we add it only when needed i.e., if the mouse moves
  411. // outside the splitter.
  412. if (resizing) {
  413. showDraggingCurtain();
  414. }
  415. break;
  416. case Event.ONMOUSEUP:
  417. // case Event.ONTOUCHEND:
  418. if (resizing) {
  419. onMouseUp(event);
  420. }
  421. break;
  422. case Event.ONCLICK:
  423. resizing = false;
  424. break;
  425. }
  426. // Only fire click event listeners if the splitter isn't moved
  427. if (Util.isTouchEvent(event) || !resized) {
  428. super.onBrowserEvent(event);
  429. } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
  430. // Reset the resized flag after a mouseup has occured so the next
  431. // mousedown/mouseup can be interpreted as a click.
  432. resized = false;
  433. }
  434. }
  435. public void onMouseDown(Event event) {
  436. if (locked || !isEnabled()) {
  437. return;
  438. }
  439. final Element trg = event.getEventTarget().cast();
  440. if (trg == splitter || trg == DOM.getChild(splitter, 0)) {
  441. resizing = true;
  442. DOM.setCapture(getElement());
  443. origX = DOM.getElementPropertyInt(splitter, "offsetLeft");
  444. origY = DOM.getElementPropertyInt(splitter, "offsetTop");
  445. origMouseX = Util.getTouchOrMouseClientX(event);
  446. origMouseY = Util.getTouchOrMouseClientY(event);
  447. event.stopPropagation();
  448. event.preventDefault();
  449. }
  450. }
  451. public void onMouseMove(Event event) {
  452. switch (orientation) {
  453. case ORIENTATION_HORIZONTAL:
  454. final int x = Util.getTouchOrMouseClientX(event);
  455. onHorizontalMouseMove(x);
  456. break;
  457. case ORIENTATION_VERTICAL:
  458. default:
  459. final int y = Util.getTouchOrMouseClientY(event);
  460. onVerticalMouseMove(y);
  461. break;
  462. }
  463. }
  464. private void onHorizontalMouseMove(int x) {
  465. int newX = origX + x - origMouseX;
  466. if (newX < 0) {
  467. newX = 0;
  468. }
  469. if (newX + getSplitterSize() > getOffsetWidth()) {
  470. newX = getOffsetWidth() - getSplitterSize();
  471. }
  472. if (position.indexOf("%") > 0) {
  473. float pos = newX;
  474. // 100% needs special handling
  475. if (newX + getSplitterSize() >= getOffsetWidth()) {
  476. pos = getOffsetWidth();
  477. }
  478. // Reversed position
  479. if (positionReversed) {
  480. pos = getOffsetWidth() - pos;
  481. }
  482. position = (pos / getOffsetWidth() * 100) + "%";
  483. } else {
  484. // Reversed position
  485. if (positionReversed) {
  486. position = (getOffsetWidth() - newX - getSplitterSize()) + "px";
  487. } else {
  488. position = newX + "px";
  489. }
  490. }
  491. if (origX != newX) {
  492. resized = true;
  493. }
  494. // Reversed position
  495. if (positionReversed) {
  496. newX = getOffsetWidth() - newX - getSplitterSize();
  497. }
  498. setSplitPosition(newX + "px");
  499. }
  500. private void onVerticalMouseMove(int y) {
  501. int newY = origY + y - origMouseY;
  502. if (newY < 0) {
  503. newY = 0;
  504. }
  505. if (newY + getSplitterSize() > getOffsetHeight()) {
  506. newY = getOffsetHeight() - getSplitterSize();
  507. }
  508. if (position.indexOf("%") > 0) {
  509. float pos = newY;
  510. // 100% needs special handling
  511. if (newY + getSplitterSize() >= getOffsetHeight()) {
  512. pos = getOffsetHeight();
  513. }
  514. // Reversed position
  515. if (positionReversed) {
  516. pos = getOffsetHeight() - pos - getSplitterSize();
  517. }
  518. position = pos / getOffsetHeight() * 100 + "%";
  519. } else {
  520. // Reversed position
  521. if (positionReversed) {
  522. position = (getOffsetHeight() - newY - getSplitterSize())
  523. + "px";
  524. } else {
  525. position = newY + "px";
  526. }
  527. }
  528. if (origY != newY) {
  529. resized = true;
  530. }
  531. // Reversed position
  532. if (positionReversed) {
  533. newY = getOffsetHeight() - newY - getSplitterSize();
  534. }
  535. setSplitPosition(newY + "px");
  536. }
  537. public void onMouseUp(Event event) {
  538. DOM.releaseCapture(getElement());
  539. hideDraggingCurtain();
  540. resizing = false;
  541. if (!Util.isTouchEvent(event)) {
  542. onMouseMove(event);
  543. }
  544. updateSplitPositionToServer();
  545. }
  546. /**
  547. * Used in FF to avoid losing mouse capture when pointer is moved on an
  548. * iframe.
  549. */
  550. private void showDraggingCurtain() {
  551. if (!isDraggingCurtainRequired()) {
  552. return;
  553. }
  554. if (draggingCurtain == null) {
  555. draggingCurtain = DOM.createDiv();
  556. DOM.setStyleAttribute(draggingCurtain, "position", "absolute");
  557. DOM.setStyleAttribute(draggingCurtain, "top", "0px");
  558. DOM.setStyleAttribute(draggingCurtain, "left", "0px");
  559. DOM.setStyleAttribute(draggingCurtain, "width", "100%");
  560. DOM.setStyleAttribute(draggingCurtain, "height", "100%");
  561. DOM.setStyleAttribute(draggingCurtain, "zIndex", ""
  562. + VOverlay.Z_INDEX);
  563. DOM.appendChild(wrapper, draggingCurtain);
  564. }
  565. }
  566. /**
  567. * A dragging curtain is required in Gecko and Webkit.
  568. *
  569. * @return true if the browser requires a dragging curtain
  570. */
  571. private boolean isDraggingCurtainRequired() {
  572. return (BrowserInfo.get().isGecko() || BrowserInfo.get().isWebkit());
  573. }
  574. /**
  575. * Hides dragging curtain
  576. */
  577. private void hideDraggingCurtain() {
  578. if (draggingCurtain != null) {
  579. DOM.removeChild(wrapper, draggingCurtain);
  580. draggingCurtain = null;
  581. }
  582. }
  583. private int splitterSize = -1;
  584. private int getSplitterSize() {
  585. if (splitterSize < 0) {
  586. if (isAttached()) {
  587. switch (orientation) {
  588. case ORIENTATION_HORIZONTAL:
  589. splitterSize = DOM.getElementPropertyInt(splitter,
  590. "offsetWidth");
  591. break;
  592. default:
  593. splitterSize = DOM.getElementPropertyInt(splitter,
  594. "offsetHeight");
  595. break;
  596. }
  597. }
  598. }
  599. return splitterSize;
  600. }
  601. @Override
  602. public void setHeight(String height) {
  603. if (this.height.equals(height)) {
  604. return;
  605. }
  606. this.height = height;
  607. super.setHeight(height);
  608. if (!rendering && client != null) {
  609. setSplitPosition(position);
  610. }
  611. }
  612. @Override
  613. public void setWidth(String width) {
  614. if (this.width.equals(width)) {
  615. return;
  616. }
  617. this.width = width;
  618. super.setWidth(width);
  619. if (!rendering && client != null) {
  620. setSplitPosition(position);
  621. }
  622. }
  623. public RenderSpace getAllocatedSpace(Widget child) {
  624. if (child == firstChild) {
  625. return firstRenderSpace;
  626. } else if (child == secondChild) {
  627. return secondRenderSpace;
  628. }
  629. return null;
  630. }
  631. public boolean hasChildComponent(Widget component) {
  632. return (component != null && (component == firstChild || component == secondChild));
  633. }
  634. public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
  635. if (oldComponent == firstChild) {
  636. setFirstWidget(newComponent);
  637. } else if (oldComponent == secondChild) {
  638. setSecondWidget(newComponent);
  639. }
  640. }
  641. public boolean requestLayout(Set<Widget> children) {
  642. // content size change might cause change to its available space
  643. // (scrollbars)
  644. for (Widget widget : children) {
  645. client.handleComponentRelativeSize(widget);
  646. }
  647. if (height != null && width != null) {
  648. /*
  649. * If the height and width has been specified the child components
  650. * cannot make the size of the layout change
  651. */
  652. return true;
  653. }
  654. if (renderInformation.updateSize(getElement())) {
  655. return false;
  656. } else {
  657. return true;
  658. }
  659. }
  660. public void updateCaption(VPaintableWidget component, UIDL uidl) {
  661. // TODO Implement caption handling
  662. }
  663. /**
  664. * Updates the new split position back to server.
  665. */
  666. private void updateSplitPositionToServer() {
  667. int pos = 0;
  668. if (position.indexOf("%") > 0) {
  669. pos = Math.round(Float.valueOf(position.substring(0,
  670. position.length() - 1)));
  671. } else {
  672. pos = Integer
  673. .parseInt(position.substring(0, position.length() - 2));
  674. }
  675. client.updateVariable(id, "position", pos, immediate);
  676. }
  677. private void setStylenames() {
  678. final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
  679. : "-vsplitter");
  680. final String firstContainerSuffix = "-first-container";
  681. final String secondContainerSuffix = "-second-container";
  682. String lockedSuffix = "";
  683. String splitterStyle = CLASSNAME + splitterSuffix;
  684. String firstStyle = CLASSNAME + firstContainerSuffix;
  685. String secondStyle = CLASSNAME + secondContainerSuffix;
  686. if (locked) {
  687. splitterStyle = CLASSNAME + splitterSuffix + "-locked";
  688. lockedSuffix = "-locked";
  689. }
  690. for (int i = 0; i < componentStyleNames.length; i++) {
  691. splitterStyle += " " + CLASSNAME + splitterSuffix + "-"
  692. + componentStyleNames[i] + lockedSuffix;
  693. firstStyle += " " + CLASSNAME + firstContainerSuffix + "-"
  694. + componentStyleNames[i];
  695. secondStyle += " " + CLASSNAME + secondContainerSuffix + "-"
  696. + componentStyleNames[i];
  697. }
  698. DOM.setElementProperty(splitter, "className", splitterStyle);
  699. DOM.setElementProperty(firstContainer, "className", firstStyle);
  700. DOM.setElementProperty(secondContainer, "className", secondStyle);
  701. }
  702. public void setEnabled(boolean enabled) {
  703. this.enabled = enabled;
  704. }
  705. public boolean isEnabled() {
  706. return enabled;
  707. }
  708. public Widget getWidgetForPaintable() {
  709. return this;
  710. }
  711. }