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

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