/*
* 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 java.util.Iterator;
import org.kaaproject.avro.ui.gwt.client.util.Utils;
import org.kaaproject.avro.ui.gwt.client.widget.dialog.AvroUiDialog;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.logical.shared.AttachEvent;
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.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
@SuppressWarnings("deprecation")
public class FormPopup extends PopupPanel implements MouseListener {
public static class CloseWidget extends InlineLabel {
public CloseWidget() {
super();
setStyleName(Utils.avroUiStyle.closeAction());
}
public void doAttach() {
super.onAttach();
}
public void doDetach() {
super.onDetach();
}
}
private static class BottomPanel extends HorizontalPanel {
public BottomPanel() {
setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
setWidth("100%");
}
public void doAttach() {
super.onAttach();
}
public void doDetach() {
super.onDetach();
}
}
public static class DecoratorPanelImpl extends DecoratorPanel {
public DecoratorPanelImpl() {
super();
}
public void doAttach() {
super.onAttach();
}
public void doDetach() {
super.onDetach();
}
protected Element getCellElement(int row, int cell) {
return super.getCellElement(row, cell);
}
}
private class MouseHandler implements MouseDownHandler, MouseUpHandler,
MouseOutHandler, MouseOverHandler, MouseMoveHandler {
public void onMouseDown(MouseDownEvent event) {
beginDragging(event);
}
public void onMouseMove(MouseMoveEvent event) {
continueDragging(event);
}
public void onMouseOut(MouseOutEvent event) {
FormPopup.this.onMouseLeave(decPanel.asWidget());
}
public void onMouseOver(MouseOverEvent event) {
FormPopup.this.onMouseEnter(decPanel.asWidget());
}
public void onMouseUp(MouseUpEvent event) {
endDragging(event);
}
}
private DecoratorPanelImpl decPanel;
private CloseWidget closeWidget;
private boolean dragging;
private int dragStartX, dragStartY;
private int windowWidth;
private int clientLeft;
private int clientTop;
private String desiredHeight;
private String desiredWidth;
private HandlerRegistration resizeHandlerRegistration;
private BottomPanel bottomPanel;
private HorizontalPanel buttonsPanel;
public FormPopup() {
this(false);
}
public FormPopup(boolean autoHide) {
this(autoHide, true, true, false);
}
public FormPopup(boolean autoHide, boolean modal, boolean showCloseButton,
boolean autoHideOnHistoryEvents) {
super(autoHide, modal);
this.setAutoHideOnHistoryEventsEnabled(autoHideOnHistoryEvents);
setGlassEnabled(true);
setAnimationEnabled(true);
if (showCloseButton) {
closeWidget = new CloseWidget();
}
decPanel = new DecoratorPanelImpl();
decPanel.setStyleName("");
decPanel.setSize("100%", "100%");
setStylePrimaryName(Utils.avroUiStyle.formPopup());
super.setWidget(decPanel);
setStyleName(getContainerElement(), "popupContent", false);
if (showCloseButton) {
Element td = getCellElement(1, 2);
DOM.appendChild(td, closeWidget.asWidget().getElement());
adopt(closeWidget.asWidget());
}
windowWidth = Window.getClientWidth();
clientLeft = Document.get().getBodyOffsetLeft();
clientTop = Document.get().getBodyOffsetTop();
MouseHandler mouseHandler = new MouseHandler();
addDomHandler(mouseHandler, MouseDownEvent.getType());
addDomHandler(mouseHandler, MouseUpEvent.getType());
addDomHandler(mouseHandler, MouseMoveEvent.getType());
addDomHandler(mouseHandler, MouseOverEvent.getType());
addDomHandler(mouseHandler, MouseOutEvent.getType());
if (showCloseButton) {
closeWidget.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
hide();
}
});
}
addAttachHandler(new AttachEvent.Handler() {
@Override
public void onAttachOrDetach(AttachEvent event) {
if (event.isAttached()) {
int popupWidth = getOffsetWidth();
int popupHeight = getOffsetHeight();
int deltaWidth = (Window.getClientWidth() - popupWidth);
int deltaHeight = (Window.getClientHeight() - popupHeight);
if (deltaWidth < 0 || deltaHeight < 0) {
if (deltaWidth < 0) {
popupWidth += deltaWidth;
} else {
deltaWidth = 0;
}
if (deltaHeight < 0) {
popupHeight += deltaHeight;
} else {
deltaHeight = 0;
}
getElement().getStyle().setWidth(popupWidth, Unit.PX);
getElement().getStyle().setHeight(popupHeight, Unit.PX);
onSizeOverflow(deltaWidth, deltaHeight);
}
}
}
});
getGlassElement().getStyle().setZIndex(AvroUiDialog.GLASS_Z_INDEX);
getElement().getStyle().setZIndex(AvroUiDialog.DIALOG_Z_INDEX);
}
public void onSizeOverflow(int deltaWidth, int deltaHeight) {
}
private void initButtonsPanel() {
buttonsPanel = new HorizontalPanel();
buttonsPanel.setSpacing(5);
buttonsPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
bottomPanel = new BottomPanel();
bottomPanel.add(buttonsPanel);
Element td = getCellElement(2, 1);
DOM.insertChild(td, bottomPanel.getElement(), 0);
adopt(bottomPanel);
}
public void addButton(com.google.gwt.user.client.ui.Button button) {
if (buttonsPanel == null)
initButtonsPanel();
button.getElement().getStyle().setMarginLeft(20, Unit.PX);
buttonsPanel.add(button);
}
@Override
public void hide() {
if (resizeHandlerRegistration != null) {
resizeHandlerRegistration.removeHandler();
resizeHandlerRegistration = null;
}
super.hide();
}
@Override
public void show() {
if (resizeHandlerRegistration == null) {
resizeHandlerRegistration = Window
.addResizeHandler(new ResizeHandler() {
public void onResize(ResizeEvent event) {
windowWidth = event.getWidth();
}
});
}
Timer timer = new Timer() {
public void run() {
getElement().getStyle().setProperty("clip", "auto");
}
};
timer.schedule(300);
super.show();
}
@Override
public void onBrowserEvent(Event event) {
switch (event.getTypeInt()) {
case Event.ONMOUSEDOWN:
case Event.ONMOUSEUP:
case Event.ONMOUSEMOVE:
case Event.ONMOUSEOVER:
case Event.ONMOUSEOUT:
if (!dragging && !isCaptionEvent(event)) {
return;
}
}
super.onBrowserEvent(event);
}
@Override
public void clear() {
decPanel.clear();
}
@Override
public Widget getWidget() {
return decPanel.getWidget();
}
@Override
public Iterator<Widget> iterator() {
return decPanel.iterator();
}
@Override
public boolean remove(Widget w) {
return decPanel.remove(w);
}
@Override
public void setWidget(Widget w) {
decPanel.setWidget(w);
maybeUpdateSizeInternal();
}
void maybeUpdateSizeInternal() {
Widget w = super.getWidget();
if (w != null) {
if (desiredHeight != null) {
w.setHeight(desiredHeight);
}
if (desiredWidth != null) {
w.setWidth(desiredWidth);
}
}
}
@Override
public void setHeight(String height) {
super.setHeight(height);
desiredHeight = height;
// If the user cleared the size, revert to not trying to control
// children.
if (height.length() == 0) {
desiredHeight = null;
}
}
@Override
public void setWidth(String width) {
super.setWidth(width);
desiredWidth = width;
// If the user cleared the size, revert to not trying to control
// children.
if (width.length() == 0) {
desiredWidth = null;
}
}
@Override
protected void doAttachChildren() {
try {
decPanel.doAttach();
} finally {
if (closeWidget != null)
closeWidget.doAttach();
if (bottomPanel != null)
bottomPanel.doAttach();
}
}
@Override
protected void doDetachChildren() {
try {
decPanel.doDetach();
} finally {
if (closeWidget != null)
closeWidget.doDetach();
if (bottomPanel != null)
bottomPanel.doDetach();
}
}
@Override
public void onMouseDown(Widget sender, int x, int y) {
if (DOM.getCaptureElement() == null) {
/*
* Need to check to make sure that we aren't already capturing an
* element otherwise events will not fire as expected. If this check
* isn't here, any class which extends custom button will not fire
* its click event for example.
*/
dragging = true;
DOM.setCapture(getElement());
dragStartX = x;
dragStartY = y;
}
}
@Override
public void onMouseEnter(Widget sender) {
}
@Override
public void onMouseLeave(Widget sender) {
}
@Override
public void onMouseMove(Widget sender, int x, int y) {
if (dragging) {
int absX = x + getAbsoluteLeft();
int absY = y + getAbsoluteTop();
if (absX < clientLeft || absX >= windowWidth || absY < clientTop) {
return;
}
setPopupPosition(absX - dragStartX, absY - dragStartY);
}
}
@Override
public void onMouseUp(Widget sender, int x, int y) {
dragging = false;
DOM.releaseCapture(getElement());
}
protected void beginDragging(MouseDownEvent event) {
onMouseDown(decPanel.asWidget(), event.getX(), event.getY());
}
protected void continueDragging(MouseMoveEvent event) {
onMouseMove(decPanel.asWidget(), event.getX(), event.getY());
}
protected void endDragging(MouseUpEvent event) {
onMouseUp(decPanel.asWidget(), event.getX(), event.getY());
}
@Override
protected void onPreviewNativeEvent(NativePreviewEvent event) {
NativeEvent nativeEvent = event.getNativeEvent();
if (!event.isCanceled() && (event.getTypeInt() == Event.ONMOUSEDOWN)
&& isCaptionEvent(nativeEvent)) {
nativeEvent.preventDefault();
}
super.onPreviewNativeEvent(event);
}
private boolean isCaptionEvent(NativeEvent event) {
EventTarget target = event.getEventTarget();
if (Element.is(target)) {
com.google.gwt.dom.client.Element element = Element.as(target);
if (decPanel.getElement().isOrHasChild(element)) {
String tag = element.getTagName();
String className = element.getClassName();
if (tag.equalsIgnoreCase("tr")) {
if ("top".equalsIgnoreCase(className)) {
return true;
}
} else if (tag.equalsIgnoreCase("td")) {
if ("topLeft".equalsIgnoreCase(className)
|| "topCenter".equalsIgnoreCase(className)
|| "topRight".equalsIgnoreCase(className)) {
return true;
}
} else if (tag.equalsIgnoreCase("div")) {
if ("topLeftInner".equalsIgnoreCase(className)
|| "topCenterInner".equalsIgnoreCase(className)
|| "topRightInner".equalsIgnoreCase(className)) {
return true;
}
}
}
}
return false;
}
public void setTitle(String title) {
getCellElement(0, 1).setInnerText(title);
}
protected Element getCellElement(int row, int cell) {
return decPanel.getCellElement(row, cell);
}
@Override
protected void onEnsureDebugId(String baseID) {
super.onEnsureDebugId(baseID);
ensureDebugId(getCellElement(1, 1), baseID, "content");
}
}