/* * Copyright 2014-2015 CyberVision, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaaproject.avro.ui.gwt.client.widget; import org.kaaproject.avro.ui.gwt.client.util.Utils; import com.google.gwt.animation.client.Animation; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; public class BusyPopup extends SimplePanel { private static BusyPopup instance; public static void showPopup() { if (instance == null) { instance = new BusyPopup(); } instance.rollDown(); } public static void hidePopup() { if (instance != null) { instance.hide(); } } private static final int ANIMATION_DURATION = 300; private static final int GLASS_Z_INDEX = 32766; private static final int POPUP_Z_INDEX = 32767; private ResizeHandler glassResizer = new ResizeHandler() { public void onResize(ResizeEvent event) { Style style = glass.getStyle(); int winWidth = Window.getClientWidth(); int winHeight = Window.getClientHeight(); style.setDisplay(Display.NONE); style.setWidth(0, Unit.PX); style.setHeight(0, Unit.PX); int width = Document.get().getScrollWidth(); int height = Document.get().getScrollHeight(); style.setWidth(Math.max(width, winWidth), Unit.PX); style.setHeight(Math.max(height, winHeight), Unit.PX); style.setDisplay(Display.BLOCK); } }; private boolean showing; private boolean isAnimationEnabled = true; private Element glass; private HandlerRegistration nativePreviewHandlerRegistration; private int leftPosition = -1; private int topPosition = -1; private RollAnimation rollAnimation = new RollAnimation(this); public BusyPopup() { glass = Document.get().createDivElement(); glass.setClassName(Utils.avroUiStyle.busyGlass()); glass.getStyle().setPosition(Position.ABSOLUTE); glass.getStyle().setLeft(0, Unit.PX); glass.getStyle().setTop(0, Unit.PX); glass.getStyle().setZIndex(GLASS_Z_INDEX); getElement().getStyle().setZIndex(POPUP_Z_INDEX); HorizontalPanel panel = new HorizontalPanel(); panel.setSize("320px", "70px"); panel.addStyleName(Utils.avroUiStyle.busyPopup()); Image image = new Image(); image.setResource(Utils.resources.busyIndicator()); panel.add(image); panel.setCellWidth(image, "60px"); panel.setCellHorizontalAlignment(image, HasHorizontalAlignment.ALIGN_CENTER); panel.setCellVerticalAlignment(image, HasVerticalAlignment.ALIGN_MIDDLE); Label label = new Label(); label.setText(Utils.constants.busyPopupText()); label.getElement().getStyle().setPaddingRight(15, Unit.PX); panel.add(label); panel.setCellHorizontalAlignment(label, HasHorizontalAlignment.ALIGN_CENTER); panel.setCellVerticalAlignment(label, HasVerticalAlignment.ALIGN_MIDDLE); setWidget(panel); } public void setAnimationEnabled(boolean enable) { isAnimationEnabled = enable; } public void setPopupPosition(int left, int top) { leftPosition = left; topPosition = top; left -= Document.get().getBodyOffsetLeft(); top -= Document.get().getBodyOffsetTop(); Element elem = getElement(); elem.getStyle().setPropertyPx("left", left); elem.getStyle().setPropertyPx("top", top); } public void rollDown() { boolean initiallyShowing = showing; boolean initiallyAnimated = isAnimationEnabled; if (!initiallyShowing) { setVisible(false); setAnimationEnabled(false); show(); } Element elem = getElement(); elem.getStyle().setPropertyPx("left", 0); elem.getStyle().setPropertyPx("top", 0); int left = (Window.getClientWidth() - getOffsetWidth()) >> 1; int top = -getOffsetHeight(); setPopupPosition(Math.max(Window.getScrollLeft() + left, 0), Math.max( Window.getScrollTop() + top, -getOffsetHeight())); if (!initiallyShowing) { setAnimationEnabled(initiallyAnimated); if (initiallyAnimated) { setVisible(true); rollAnimation.run(ANIMATION_DURATION); } else { setVisible(true); } } } @Override public void setVisible(boolean visible) { getElement().getStyle().setProperty("visibility", visible ? "visible" : "hidden"); if (glass != null) { glass.getStyle().setProperty("visibility", visible ? "visible" : "hidden"); } } public boolean isShowing() { return showing; } public void show() { if (showing) { return; } else if (isAttached()) { this.removeFromParent(); } rollAnimation.setState(true, false); } public void hide() { if (!isShowing()) { return; } rollAnimation.setState(false, false); } private void previewNativeEvent(NativePreviewEvent event) { event.cancel(); return; } private void updateHandlers() { if (nativePreviewHandlerRegistration != null) { nativePreviewHandlerRegistration.removeHandler(); nativePreviewHandlerRegistration = null; } if (showing) { nativePreviewHandlerRegistration = Event.addNativePreviewHandler(new NativePreviewHandler() { public void onPreviewNativeEvent(NativePreviewEvent event) { previewNativeEvent(event); } }); } } static class RollAnimation extends Animation { private BusyPopup curPanel = null; private boolean isUnloading; private boolean showing; private Timer showTimer; private boolean glassShowing; private HandlerRegistration resizeRegistration; private int offsetHeight = -1; public RollAnimation(BusyPopup panel) { this.curPanel = panel; } public void setState(boolean showing, boolean isUnloading) { this.isUnloading = isUnloading; cancel(); if (showTimer != null) { showTimer.cancel(); showTimer = null; onComplete(); } curPanel.showing = showing; curPanel.updateHandlers(); boolean animate = !isUnloading && curPanel.isAnimationEnabled; this.showing = showing; if (animate) { if (showing) { maybeShowGlass(); curPanel.getElement().getStyle().setProperty("position", "absolute"); if (curPanel.topPosition != -1) { curPanel.setPopupPosition(curPanel.leftPosition, curPanel.topPosition); } RootPanel.get().add(curPanel); showTimer = new Timer() { @Override public void run() { showTimer = null; RollAnimation.this.run(ANIMATION_DURATION); } }; showTimer.schedule(1); } else { run(ANIMATION_DURATION); } } else { onInstantaneousRun(); } } @Override protected void onComplete() { if (!showing) { maybeShowGlass(); if (!isUnloading) { RootPanel.get().remove(curPanel); } } curPanel.getElement().getStyle().setProperty("overflow", "visible"); } @Override protected void onStart() { offsetHeight = curPanel.getOffsetHeight(); super.onStart(); } @Override protected void onUpdate(double progress) { if (!showing) { progress = 1.0 - progress; } int topPosition = (int) (progress * offsetHeight) - offsetHeight; curPanel.setPopupPosition(curPanel.leftPosition, Math.max( Window.getScrollTop() + topPosition, -offsetHeight)); } private void maybeShowGlass() { if (showing) { Document.get().getBody().appendChild(curPanel.glass); resizeRegistration = Window.addResizeHandler(curPanel.glassResizer); curPanel.glassResizer.onResize(null); glassShowing = true; } else if (glassShowing) { Document.get().getBody().removeChild(curPanel.glass); resizeRegistration.removeHandler(); resizeRegistration = null; glassShowing = false; } } private void onInstantaneousRun() { maybeShowGlass(); if (showing) { curPanel.getElement().getStyle().setProperty("position", "absolute"); if (curPanel.topPosition != -1) { curPanel.setPopupPosition(curPanel.leftPosition, curPanel.topPosition); } RootPanel.get().add(curPanel); } else { if (!isUnloading) { RootPanel.get().remove(curPanel); } } curPanel.getElement().getStyle().setProperty("overflow", "visible"); } } }