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.

IPopupView.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. package com.itmill.toolkit.terminal.gwt.client.ui;
  2. import java.util.HashSet;
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import com.google.gwt.user.client.DOM;
  6. import com.google.gwt.user.client.Element;
  7. import com.google.gwt.user.client.Event;
  8. import com.google.gwt.user.client.ui.ClickListener;
  9. import com.google.gwt.user.client.ui.HTML;
  10. import com.google.gwt.user.client.ui.HasFocus;
  11. import com.google.gwt.user.client.ui.Label;
  12. import com.google.gwt.user.client.ui.PopupListener;
  13. import com.google.gwt.user.client.ui.PopupPanel;
  14. import com.google.gwt.user.client.ui.RootPanel;
  15. import com.google.gwt.user.client.ui.Widget;
  16. import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
  17. import com.itmill.toolkit.terminal.gwt.client.ICaption;
  18. import com.itmill.toolkit.terminal.gwt.client.ICaptionWrapper;
  19. import com.itmill.toolkit.terminal.gwt.client.Container;
  20. import com.itmill.toolkit.terminal.gwt.client.Paintable;
  21. import com.itmill.toolkit.terminal.gwt.client.UIDL;
  22. public class IPopupView extends HTML implements Paintable, Container {
  23. public static final String CLASSNAME = "i-popupview";
  24. /** For server-client communication */
  25. private String uidlId;
  26. private ApplicationConnection client;
  27. /** For inner classes */
  28. private final IPopupView hostReference = this;
  29. /** This variable helps to communicate popup visibility to the server */
  30. private boolean hostPopupVisible;
  31. private CustomPopup popup;
  32. private final Label loading = new Label("Loading...");
  33. // Browser window sizes
  34. int windowTop;
  35. int windowLeft;
  36. int windowRight;
  37. int windowBottom;
  38. /**
  39. * loading constructor
  40. */
  41. public IPopupView() {
  42. super();
  43. popup = new CustomPopup();
  44. setStyleName(CLASSNAME);
  45. popup.setStylePrimaryName(CLASSNAME + "-popup");
  46. setHTML("PopupPanel");
  47. popup.setWidget(loading);
  48. // When we click to open the popup...
  49. addClickListener(new ClickListener() {
  50. public void onClick(Widget sender) {
  51. updateState(true);
  52. }
  53. });
  54. // ..and when we close it
  55. popup.addPopupListener(new PopupListener() {
  56. public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
  57. updateState(false);
  58. }
  59. });
  60. }
  61. /**
  62. *
  63. *
  64. * @see com.itmill.toolkit.terminal.gwt.client.Paintable#updateFromUIDL(com.itmill.toolkit.terminal.gwt.client.UIDL,
  65. * com.itmill.toolkit.terminal.gwt.client.ApplicationConnection)
  66. */
  67. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  68. // This call should be made first. Ensure correct implementation,
  69. // and don't let the containing layout manage caption.
  70. if (client.updateComponent(this, uidl, false)) {
  71. return;
  72. }
  73. // These are for future server connections
  74. this.client = client;
  75. uidlId = uidl.getId();
  76. updateWindowSize();
  77. hostPopupVisible = uidl.getBooleanAttribute("popupVisible");
  78. setHTML(uidl.getStringAttribute("html"));
  79. if (uidl.hasAttribute("description")) {
  80. setTitle(uidl.getStringAttribute("description"));
  81. }
  82. // Render the popup if visible and show it. The component inside can
  83. // change dynamically.
  84. if (hostPopupVisible) {
  85. UIDL popupUIDL = uidl.getChildUIDL(0);
  86. popup.updateFromUIDL(popupUIDL, client);
  87. showPopupOnTop(popup, hostReference);
  88. } else { // The popup isn't visible so we should remove its child
  89. popup.setWidget(null);
  90. }
  91. }// updateFromUIDL
  92. /**
  93. *
  94. * @param visibility
  95. */
  96. private void updateState(boolean visibility) {
  97. // If we know the server connection
  98. // then update the current situation
  99. if (uidlId != null && client != null) {
  100. client.updateVariable(uidlId, "popupVisibility", visibility, true);
  101. }
  102. }
  103. /**
  104. * This shows the popup on top of the widget below. This function allows us
  105. * to position the popup before making it visible.
  106. *
  107. * @param popup
  108. * the popup to show
  109. * @param host
  110. * the widget to draw the popup on
  111. */
  112. private void showPopupOnTop(final CustomPopup popup, final Widget host) {
  113. popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
  114. public void setPosition(int offsetWidth, int offsetHeight) {
  115. int hostHorizontalCenter = host.getAbsoluteLeft()
  116. + host.getOffsetWidth() / 2;
  117. int hostVerticalCenter = host.getAbsoluteTop()
  118. + host.getOffsetHeight() / 2;
  119. int left = hostHorizontalCenter - offsetWidth / 2;
  120. int top = hostVerticalCenter - offsetHeight / 2;
  121. // Superclass takes care of top and left
  122. if ((left + offsetWidth) > windowRight) {
  123. left -= (left + offsetWidth) - windowRight;
  124. }
  125. if ((top + offsetHeight) > windowBottom) {
  126. top -= (top + offsetHeight) - windowBottom;
  127. }
  128. popup.setPopupPosition(left, top);
  129. }
  130. });
  131. }
  132. public void updateWindowSize() {
  133. windowTop = RootPanel.get().getAbsoluteTop();
  134. windowLeft = RootPanel.get().getAbsoluteLeft();
  135. windowRight = windowLeft + RootPanel.get().getOffsetWidth();
  136. windowBottom = windowTop + RootPanel.get().getOffsetHeight();
  137. }
  138. public boolean hasChildComponent(Widget component) {
  139. return popup.equals(component);
  140. }
  141. public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
  142. if (newComponent == null || newComponent instanceof CustomPopup) {
  143. popup.hide();
  144. if (popup != null) {
  145. client.unregisterPaintable(popup);
  146. }
  147. popup = (CustomPopup) newComponent;
  148. } else {
  149. throw new IllegalArgumentException(
  150. "PopupPanel only supports components of type CustomPopup");
  151. }
  152. }
  153. public void updateCaption(Paintable component, UIDL uidl) {
  154. }
  155. public static native void nativeBlur(Element e) /*-{
  156. if(e.focus) {
  157. e.blur();
  158. }
  159. }-*/;
  160. private class CustomPopup extends IToolkitOverlay implements Container {
  161. private Paintable popupComponentPaintable = null;
  162. private Widget popupComponentWidget = null;
  163. private ICaptionWrapper captionWrapper = null;
  164. private boolean hasHadMouseOver = false;
  165. private Set activeChildren;
  166. public CustomPopup() {
  167. super(true, false, true); // autoHide, not modal, dropshadow
  168. activeChildren = new HashSet();
  169. }
  170. // For some reason ONMOUSEOUT events are not always recieved, so we have
  171. // to use ONMOUSEMOVE that doesn't target the popup
  172. public boolean onEventPreview(Event event) {
  173. Element target = DOM.eventGetTarget(event);
  174. boolean eventTargetsPopup = DOM.isOrHasChild(getElement(), target);
  175. int type = DOM.eventGetType(event);
  176. // Catch children that use keyboard, so we can unfocus them when
  177. // hiding
  178. if (type == Event.ONKEYPRESS) {
  179. activeChildren.add(target);
  180. }
  181. if (eventTargetsPopup & type == Event.ONMOUSEMOVE) {
  182. hasHadMouseOver = true;
  183. }
  184. if (!eventTargetsPopup & type == Event.ONMOUSEMOVE) {
  185. if (hasHadMouseOver) {
  186. hide();
  187. hasHadMouseOver = false;
  188. return true;
  189. }
  190. }
  191. return super.onEventPreview(event);
  192. }
  193. public void hide() {
  194. // Notify children with focus
  195. if ((popupComponentWidget instanceof HasFocus)) {
  196. ((HasFocus) popupComponentWidget).setFocus(false);
  197. }
  198. for (Iterator iterator = activeChildren.iterator(); iterator
  199. .hasNext();) {
  200. nativeBlur((Element) iterator.next());
  201. }
  202. activeChildren.clear();
  203. super.hide();
  204. }
  205. public void setWidget(Widget w) {
  206. super.setWidget(w);
  207. if (w == null) {
  208. unregisterPaintables();
  209. popupComponentPaintable = null;
  210. popupComponentWidget = null;
  211. captionWrapper = null;
  212. }
  213. }
  214. public boolean hasChildComponent(Widget component) {
  215. if (popupComponentWidget != null) {
  216. return popupComponentWidget.equals(component);
  217. } else {
  218. return false;
  219. }
  220. }
  221. public void replaceChildComponent(Widget oldComponent,
  222. Widget newComponent) {
  223. // System.out.println("CustomPopup replacechildcomponent");
  224. if (oldComponent != null) {
  225. client.unregisterPaintable((Paintable) oldComponent);
  226. }
  227. popupComponentWidget = newComponent;
  228. setWidget(popupComponentWidget);
  229. }
  230. public void updateCaption(Paintable component, UIDL uidl) {
  231. if (ICaption.isNeeded(uidl)) {
  232. if (captionWrapper != null) {
  233. captionWrapper.updateCaption(uidl);
  234. } else {
  235. captionWrapper = new ICaptionWrapper(component, client);
  236. setWidget(captionWrapper);
  237. captionWrapper.updateCaption(uidl);
  238. }
  239. } else {
  240. if (captionWrapper != null) {
  241. setWidget(popupComponentWidget);
  242. }
  243. }
  244. }
  245. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  246. if (client.updateComponent(this, uidl, false)) {
  247. return;
  248. }
  249. Paintable newPopupComponent = client.getPaintable(uidl
  250. .getChildUIDL(0));
  251. if (newPopupComponent != popupComponentPaintable) {
  252. unregisterPaintables();
  253. popupComponentWidget = (Widget) newPopupComponent;
  254. popup.setWidget(popupComponentWidget);
  255. popupComponentPaintable = newPopupComponent;
  256. popupComponentPaintable.updateFromUIDL(uidl.getChildUIDL(0),
  257. client);
  258. }
  259. }
  260. private void unregisterPaintables() {
  261. if (popupComponentPaintable != null) {
  262. client.unregisterPaintable(popupComponentPaintable);
  263. }
  264. }
  265. }// class CustomPopup
  266. }// class IPopupView