package edu.washington.cs.oneswarm.ui.gwt.client;
import com.google.gwt.core.client.GWT;
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.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseUpEvent;
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.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import edu.washington.cs.oneswarm.ui.gwt.client.i18n.OSMessages;
/**
* A form of popup that has a caption area at the top and can be dragged by the
* user.
* <p>
* <img class='gallery' src='DialogBox.png'/>
* </p>
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-DialogBox { the outside of the dialog }</li>
* <li>.gwt-DialogBox .Caption { the caption }</li>
* </ul>
* <p>
* <h3>Example</h3>
* {@example com.google.gwt.examples.DialogBoxExample}
* </p>
*/
public class OneSwarmDialogBox extends PopupPanel implements HasHTML, ClickHandler, MouseListener {
public static final String CSS_DIALOG_HEADER = "os-dialog_header";
public final static String CLOSE_IMAGE_URL = GWT.getModuleBaseURL() + "images/close.png";
protected static OSMessages msg = OneSwarmGWT.msg;
private Image closeImage = null;
private HTML caption = new HTML();
private Widget child;
private boolean dragging;
private int dragStartX, dragStartY;
private FlexTable panel = new FlexTable();
/**
* Creates an empty dialog box. It should not be shown until its child
* widget has been added using {@link #add(Widget)} This is the same as
* OneSwarmDialogBox(false,false,true) .
*/
public OneSwarmDialogBox() {
this(false, false, true);
}
/**
* Creates an empty dialog box specifying its "auto-hide" property. It
* should not be shown until its child widget has been added using
* {@link #add(Widget)}.
*
* @param autoHide
* <code>true</code> if the dialog should be automatically hidden
* when the user clicks outside of it
*/
public OneSwarmDialogBox(boolean autoHide) {
this(autoHide, false, true);
}
/**
* Creates an empty dialog box specifying its "auto-hide" property. It
* should not be shown until its child widget has been added using
* {@link #add(Widget)}.
*
* @param autoHide
* <code>true</code> if the dialog should be automatically hidden
* when the user clicks outside of it
* @param modal
* <code>true</code> if keyboard and mouse events for widgets not
* contained by the dialog should be ignored
* @param canClose
* <code>true</code> if this dialog box is close-able
*/
public OneSwarmDialogBox(boolean autoHide, boolean modal, boolean canClose) {
super(autoHide, modal);
// create a new panel, so we can fit the close sign
FlexTable captionPanel = new FlexTable();
captionPanel.setWidget(0, 0, caption);
captionPanel.setBorderWidth(0);
captionPanel.setCellSpacing(0);
captionPanel.setCellPadding(0);
captionPanel.setWidth("100%");
// captionPanel.setStyleName("Caption");
// add the close cross
if (canClose) {
closeImage = new Image(CLOSE_IMAGE_URL);
captionPanel.setWidget(0, 1, closeImage);
}
// panel.getCellFormatter().setHeight(0, 1, "10px");
captionPanel.getCellFormatter().setWidth(0, 1, "20px");
captionPanel.getCellFormatter().setAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER,
HasVerticalAlignment.ALIGN_MIDDLE);
if (canClose) {
closeImage.addClickHandler(this);
}
captionPanel.setStyleName("Top");
// super.setStyleName("os-image-panel");
panel.setWidget(0, 0, captionPanel);
panel.setHeight("100%");
panel.setBorderWidth(0);
panel.setCellPadding(0);
panel.setCellSpacing(0);
panel.getCellFormatter().setHeight(1, 0, "100%");
panel.getCellFormatter().setWidth(1, 0, "100%");
panel.getCellFormatter().setAlignment(1, 0, HasHorizontalAlignment.ALIGN_CENTER,
HasVerticalAlignment.ALIGN_MIDDLE);
super.setWidget(panel);
setStyleName("gwt-DialogBox");
caption.setStyleName("Caption");
caption.addMouseListener(this);
// caption.addMouseUpHandler(this);
// caption.addMouseMoveHandler(this);
}
public void onClick(ClickEvent event) {
hide();
}
public String getHTML() {
return caption.getHTML();
}
public String getText() {
return caption.getText();
}
public boolean onEventPreview(Event event) {
// We need to preventDefault() on mouseDown events (outside of the
// DialogBox content) to keep text from being selected when it
// is dragged.
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
if (DOM.isOrHasChild(caption.getElement(), DOM.eventGetTarget(event))) {
DOM.eventPreventDefault(event);
}
}
return super.onEventPreview(event);
}
public void onMouseDown(Widget sender, int x, int y) {
dragging = true;
DOM.setCapture(caption.getElement());
dragStartX = x;
dragStartY = y;
}
public void onMouseEnter(Widget sender) {
}
public void onMouseLeave(Widget sender) {
}
public void onMouseMove(Widget sender, int x, int y) {
if (dragging) {
int absX = x + getAbsoluteLeft();
int absY = y + getAbsoluteTop();
setPopupPosition(absX - dragStartX, absY - dragStartY);
}
}
public void onMouseUp(Widget sender, int x, int y) {
dragging = false;
DOM.releaseCapture(caption.getElement());
}
public boolean remove(Widget w) {
if (child != w) {
return false;
}
panel.remove(w);
return true;
}
public void setHTML(String html) {
caption.setHTML(html);
}
public void setText(String text) {
caption.setText(text);
}
public void setWidget(Widget w) {
// If there is already a widget, remove it.
if (child != null) {
panel.remove(child);
}
// Add the widget to the center of the cell.
if (w != null) {
panel.setWidget(1, 0, w);
}
child = w;
}
/**
* Override, so that interior panel reflows to match parent's new width.
*
* @Override
*/
public void setWidth(String width) {
super.setWidth(width);
// note that you CANNOT call panel.setWidth("100%") until parent's width
// has been explicitly set, b/c until then parent's width is
// unconstrained
// and setting panel's width to 100% will flow parent to 100% of browser
// (i.e. can't do this in constructor)
panel.setWidth("100%");
}
// public void onClick(Widget sender) {
// // Window.alert("clicked");
// this.hide();
//
// }
// /**
// * remove the location sanity checks, makes it possible for the popup to
// * more outside the iframe it is in
// *
// * @Override
// */
public void setPopupPosition(int left, int top) {
// Keep the popup within the browser's client area, so that they can't
// get
// 'lost' and become impossible to interact with. Note that we don't
// attempt
// to keep popups pegged to the bottom and right edges, as they will
// then
// cause scrollbars to appear, so the user can't lose them.
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
// Set the popup's position manually, allowing setPopupPosition() to be
// called before show() is called (so a popup can be positioned without
// it
// 'jumping' on the screen).
Element elem = getElement();
DOM.setStyleAttribute(elem, "left", left + "px");
DOM.setStyleAttribute(elem, "top", top + "px");
}
public void show() {
super.show();
DOM.setStyleAttribute(getElement(), "zIndex", "2000");
// DOM.setStyleAttribute(, "position", "absolute");
}
public void hide() {
super.hide();
}
public boolean onKeyUpPreview(char keyCode, int modifiers) {
if (keyCode == KeyboardListener.KEY_ESCAPE && closeImage != null) // a
// proxy
// for
// canClose
// bool
{
hide();
return false;
}
return true; // true means don't suppress, false means suppress (weird,
// but true)
}
}