package org.gwtoolbox.widget.client.popup.dialog;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import org.gwtoolbox.commons.ui.client.event.CompoundHandlerRegistration;
import org.gwtoolbox.commons.ui.client.event.HoverHandler;
import org.gwtoolbox.commons.ui.client.event.EventUtils;
import org.gwtoolbox.commons.ui.client.event.Handler;
import org.gwtoolbox.widget.client.panel.LayoutUtils;
import org.gwtoolbox.widget.client.popup.Popup;
import org.gwtoolbox.widget.client.support.CssFloat;
import org.gwtoolbox.widget.client.support.setter.ValueSetter;
/**
* @author Uri Boness
*/
public class Dialog extends Popup {
private Element table;
private Element header;
private Element headerLeft;
private Element headerCenter;
private Element headerRight;
private Element middle;
private Element middleLeft;
private Element middleCenter;
private Element middleRight;
private Element footer;
private Element footerLeft;
private Element footerCenter;
private Element footerRight;
private Element title;
private Element toolbar;
private Element content;
private ValueSetter<Boolean> closableSetter;
private boolean closable;
private ValueSetter<Boolean> resizableSetter;
private boolean resizable;
private CompoundHandlerRegistration dragHandlerRegistration;
private boolean draggable = true;
private Impl impl = GWT.create(Impl.class);
public Dialog() {
this(true);
}
public Dialog(boolean autoHide) {
this(autoHide, false);
}
public Dialog(boolean autoHide, boolean modal) {
super(DOM.createTable(), autoHide, modal);
setAnimationType(AnimationType.CENTER);
setAnimationEnabled(true);
table = getContentElement().cast();
DOM.setElementPropertyInt(table, "cellSpacing", 0);
DOM.setElementPropertyInt(table, "cellPadding", 0);
header = DOM.createTR();
table.appendChild(header);
header.setClassName("DialogHead");
middle = DOM.createTR();
table.appendChild(middle);
footer = DOM.createTR();
table.appendChild(footer);
headerLeft = DOM.createTD();
headerLeft.setClassName("DialogHead-left");
header.appendChild(headerLeft);
headerCenter = DOM.createTD();
headerCenter.setClassName("DialogHead-center");
header.appendChild(headerCenter);
headerRight = DOM.createTD();
headerRight.setClassName("DialogHead-right");
header.appendChild(headerRight);
toolbar = DOM.createDiv();
LayoutUtils.setCssFloat(toolbar, CssFloat.RIGHT);
Element closeButton = buildCloseButton();
toolbar.appendChild(closeButton);
setClosable(false);
title = DOM.createDiv();
title.setClassName("DialogCaption");
headerCenter.appendChild(toolbar);
headerCenter.appendChild(title);
header.getStyle().setHeight(25, Style.Unit.PX);
headerLeft.getStyle().setWidth(5, Style.Unit.PX);
headerLeft.getStyle().setHeight(25, Style.Unit.PX);
headerLeft.getStyle().setProperty("lineHeight", "25px");
headerCenter.getStyle().setHeight(25, Style.Unit.PX);
headerCenter.getStyle().setProperty("lineHeight", "25px");
headerCenter.getStyle().setVerticalAlign(Style.VerticalAlign.MIDDLE);
headerRight.getStyle().setWidth(5, Style.Unit.PX);
headerRight.getStyle().setHeight(25, Style.Unit.PX);
headerRight.getStyle().setProperty("lineHeight", "25px");
middleLeft = DOM.createTD();
middleLeft.setClassName("DialogContent-left");
middle.appendChild(middleLeft);
middleCenter = DOM.createTD();
middleCenter.setClassName("DialogContent-center");
middle.appendChild(middleCenter);
middleRight = DOM.createTD();
middleRight.setClassName("DialogContent-right");
middle.appendChild(middleRight);
footerLeft = DOM.createTD();
footerLeft.setClassName("DialogFooter-left");
footer.appendChild(footerLeft);
footerCenter = DOM.createTD();
footerCenter.setClassName("DialogFooter-center");
footer.appendChild(footerCenter);
footerRight = DOM.createTD();
footerRight.setClassName("DialogFooter-right");
footer.appendChild(footerRight);
footer.getStyle().setHeight(8, Style.Unit.PX);
footerLeft.getStyle().setHeight(8, Style.Unit.PX);
footerLeft.getStyle().setProperty("lineHeight", "8px");
footerLeft.getStyle().setWidth(5, Style.Unit.PX);
footerCenter.getStyle().setHeight(8, Style.Unit.PX);
footerCenter.getStyle().setProperty("lineHeight", "8px");
footerRight.getStyle().setHeight(8, Style.Unit.PX);
footerRight.getStyle().setProperty("lineHeight", "8px");
footerRight.getStyle().setWidth(5, Style.Unit.PX);
final Element resizeHandle = createResizeHandle();
resizableSetter = new ValueSetter<Boolean>() {
public void set(Boolean resiable) {
setVisible(resizeHandle, resiable);
}
};
footerRight.appendChild(resizeHandle);
setResizable(false);
content = DOM.createDiv();
content.setClassName("DialogContent");
middleCenter.appendChild(content);
addStyleName("Dialog");
}
@Override
protected com.google.gwt.dom.client.Element getContentContainer() {
return content;
}
public void setCaption(String caption) {
title.setInnerHTML(caption);
}
public void setClosable(boolean closable) {
this.closable = closable;
closableSetter.set(closable);
}
public boolean isClosable() {
return closable;
}
public void setResizable(boolean resizable) {
this.resizable = resizable;
resizableSetter.set(resizable);
}
public boolean isResizable() {
return resizable;
}
public void setDraggable(boolean draggable) {
this.draggable = draggable;
if (draggable) {
title.removeClassName("DialogCaption-nodrag");
} else {
title.addClassName("DialogCaption-nodrag");
}
}
public boolean isDraggable() {
return draggable;
}
public void setSize(String width, String height) {
throw new UnsupportedOperationException("Use setPixelSize or instead");
}
@Override
public void setPixelSize(int width, int height) {
setWidthPx(width);
setHeightPx(height);
}
public void setWidthPx(int width) {
content.getStyle().setWidth(width, Style.Unit.PX);
}
public void setHeightPx(int height) {
content.getStyle().setHeight(height, Style.Unit.PX);
}
@Override
public void setWidth(String width) {
throw new UnsupportedOperationException("Use setWidthPx instead");
}
@Override
public void setHeight(String height) {
throw new UnsupportedOperationException("Use setHeightPx instead");
}
//================================================ Helper Methods ==================================================
private Element buildCloseButton() {
final Element closeButton = DOM.createDiv();
closeButton.setClassName("DialogTool-close");
closeButton.getStyle().setWidth(11, Style.Unit.PX);
closeButton.getStyle().setHeight(11, Style.Unit.PX);
LayoutUtils.setCssFloat(closeButton, CssFloat.LEFT);
EventUtils.addMouseHoverHandler(closeButton, new HoverHandler() {
public void onMouseOver(Event event) {
setStyleName(closeButton, "DialogTool-close-hover", true);
}
public void onMouseOut(Event event) {
setStyleName(closeButton, "DialogTool-close-hover", false);
}
});
EventUtils.addOnClickHandler(closeButton, new Handler<Event>() {
public void handle(Event event) {
hide();
}
});
closableSetter = new ValueSetter<Boolean>() {
public void set(Boolean closable) {
setVisible(closeButton, closable);
}
};
return closeButton;
}
private Element createResizeHandle() {
Element element = DOM.createDiv();
element.setClassName("DialogResizeHandle");
ResizeHandler handler = new ResizeHandler(element);
addDomHandler(handler, MouseDownEvent.getType());
addDomHandler(handler, MouseUpEvent.getType());
addDomHandler(handler, MouseMoveEvent.getType());
return element;
}
@Override
protected void onLoad() {
super.onLoad();
DragHandler handler = new DragHandler();
dragHandlerRegistration = new CompoundHandlerRegistration();
dragHandlerRegistration.addRegistration(addDomHandler(handler, MouseDownEvent.getType()));
dragHandlerRegistration.addRegistration(addDomHandler(handler, MouseUpEvent.getType()));
dragHandlerRegistration.addRegistration(addDomHandler(handler, MouseMoveEvent.getType()));
}
@Override
protected void onUnload() {
super.onUnload();
if (dragHandlerRegistration != null) {
dragHandlerRegistration.removeHandler();
}
dragHandlerRegistration = null;
}
//================================================= Inner Classes ==================================================
private class DragHandler implements MouseDownHandler, MouseUpHandler, MouseMoveHandler {
private boolean dragging;
private int initialX;
private int initialY;
private int lastX;
private int lastY;
public void onMouseDown(MouseDownEvent event) {
if (!draggable) {
return;
}
Element target = event.getNativeEvent().getEventTarget().cast();
if (!header.isOrHasChild(target)) {
return;
}
initialX = event.getClientX() + Document.get().getScrollLeft();
initialY = event.getClientY() + Document.get().getScrollTop();
lastX = initialX;
lastY = initialY;
dragging = true;
if (getWidget() != null) {
getWidget().getElement().getStyle().setVisibility(Style.Visibility.HIDDEN);
}
addStyleName("transparent-75");
DOM.setCapture(getElement());
event.preventDefault();
}
public void onMouseMove(MouseMoveEvent event) {
if (!dragging) {
return;
}
int currentX = event.getClientX() + Document.get().getScrollLeft();
int currentY = event.getClientY() + Document.get().getScrollTop();
if (currentX < 0 || currentY < 0) {
return;
}
event.preventDefault();
int deltaX = currentX - lastX;
int deltaY = currentY - lastY;
lastX = currentX;
lastY = currentY;
setPopupPosition(getPopupLeft() + deltaX, getPopupTop() + deltaY);
}
public void onMouseUp(MouseUpEvent event) {
if (!dragging) {
return;
}
dragging = false;
if (getWidget() != null) {
getWidget().getElement().getStyle().clearVisibility();
}
removeStyleName("transparent-75");
DOM.releaseCapture(getElement());
}
}
private class ResizeHandler implements MouseUpHandler, MouseDownHandler, MouseMoveHandler {
private final Element handle;
private int initialX;
private int initialY;
private int lastX;
private int lastY;
private boolean dragging;
private ResizeHandler(Element handle) {
this.handle = handle;
}
public void onMouseDown(MouseDownEvent event) {
Element target = event.getNativeEvent().getEventTarget().cast();
if (!handle.isOrHasChild(target)) {
return;
}
initialX = event.getClientX() + Document.get().getScrollLeft();
initialY = event.getClientY() + Document.get().getScrollTop();
lastX = initialX;
lastY = initialY;
dragging = true;
DOM.setCapture(getElement());
event.preventDefault();
}
public void onMouseMove(MouseMoveEvent event) {
if (!dragging) {
return;
}
int currentX = event.getClientX() + Document.get().getScrollLeft();
int currentY = event.getClientY() + Document.get().getScrollTop();
if (currentX < 0 || currentY < 0) {
return;
}
event.preventDefault();
int deltaX = currentX - lastX;
int deltaY = currentY - lastY;
lastX = currentX;
lastY = currentY;
int newWidth = content.getOffsetWidth() + deltaX;
int newHeight = content.getOffsetHeight() + deltaY;
setPixelSize(newWidth, newHeight);
LayoutUtils.notifyResize(getWidget());
}
public void onMouseUp(MouseUpEvent event) {
if (!dragging) {
return;
}
dragging = false;
DOM.releaseCapture(getElement());
}
}
private static class Impl {
public void setContentRowStyle(Element element) {
element.getStyle().setPaddingBottom(9, Style.Unit.PX);
element.getStyle().setPaddingRight(1, Style.Unit.PX);
}
public void setContentStyle(Element element) {
element.getStyle().setPosition(Style.Position.RELATIVE);
element.getStyle().setWidth(100, Style.Unit.PCT);
element.getStyle().setHeight(100, Style.Unit.PCT);
}
}
private static class ImplIE extends Impl {
@Override
public void setContentStyle(Element element) {
DOM.setStyleAttribute(element, "margin", "0");
DOM.setStyleAttribute(element, "overflow", "hidden");
DOM.setStyleAttribute(element, "width", "100%");
DOM.setStyleAttribute(element, "height", "100%");
}
}
}