/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ui.window;
import elemental.js.dom.JsElement;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import org.vectomatic.dom.svg.ui.SVGImage;
import javax.annotation.Nullable;
/**
* A popup that automatically centers its content, even if the dimensions of the content change. The
* centering is done in CSS, so performance is very good. A semi-transparent "glass" panel appears
* behind the popup. The glass is not optional due to the way {@link Window} is implemented.
* <p/>
* <p>
* {@link Window} animates into and out of view using the shrink in/expand out animation.
* </p>
*/
public abstract class Window implements IsWidget {
protected static final Resources resources = GWT.create(Resources.class);
static {
resources.centerPanelCss().ensureInjected();
}
private boolean hideOnEscapeEnabled = true;
private boolean isShowing;
private View view;
protected Window() {
this(true);
}
protected Window(boolean showBottomPanel) {
view = new View(resources, showBottomPanel);
}
public void setWidget(Widget widget) {
view.setContent(widget);
handleViewEvents();
}
/**
* ensureDebugId on the current window container. ensureDebugId id + "-headerLabel" on the window control bar title
*
* @see UIObject#ensureDebugId(String)
*/
public void ensureDebugId(String id) {
view.contentContainer.ensureDebugId(id);
view.headerLabel.ensureDebugId(id + "-headerLabel");
}
/**
* Hides the {@link Window} popup. The popup will animate out of view.
*/
public void hide() {
if (!isShowing) {
return;
}
isShowing = false;
// Animate the popup out of existence.
view.setShowing(false);
// Remove the popup when the animation completes.
new Timer() {
@Override
public void run() {
// The popup may have been shown before this timer executes.
if (!isShowing) {
view.removeFromParent();
Style style = view.contentContainer.getElement().getStyle();
style.clearPosition();
style.clearLeft();
style.clearTop();
}
}
}.schedule(view.getAnimationDuration());
}
/**
* Checks if the {@link Window} is showing or animating into view.
*
* @return true if showing, false if hidden
*/
public boolean isShowing() {
return isShowing;
}
/**
* Sets whether or not the popup should hide when escape is pressed. The
* default behavior is to ignore the escape key.
*
* @param isEnabled
* true to close on escape, false not to
*/
public void setHideOnEscapeEnabled(boolean isEnabled) {
this.hideOnEscapeEnabled = isEnabled;
}
protected Button createButton(String title, String debugId, ClickHandler clickHandler) {
Button button = new Button();
button.setText(title);
button.ensureDebugId(debugId);
button.getElement().setId(debugId);
button.addStyleName(resources.centerPanelCss().alignBtn());
button.addStyleName(resources.centerPanelCss().button());
button.addClickHandler(clickHandler);
return button;
}
protected Button createButton(String tooltip, SVGImage image, String debugId, ClickHandler clickHandler) {
Button button = new Button();
button.setTitle(tooltip);
button.ensureDebugId(debugId);
button.getElement().setId(debugId);
if (image != null) {
button.getElement().appendChild(image.getElement());
}
button.addStyleName(resources.centerPanelCss().iconButton());
button.addStyleName(resources.centerPanelCss().button());
button.addClickHandler(clickHandler);
return button;
}
protected void onEnterClicked() {
}
/**
* See {@link #show(com.google.gwt.dom.client.InputElement)}.
*/
public void show() {
show(null);
}
/**
* Displays the {@link Window} popup. The popup will animate into view.
*
* @param selectAndFocusElement
* an {@link com.google.gwt.dom.client.InputElement} to select and focus on when the panel is
* shown. If null, no element will be given focus
*/
public void show(@Nullable final InputElement selectAndFocusElement) {
if (isShowing) {
return;
}
isShowing = true;
// Attach the popup to the body.
final JsElement popup = view.popup.getElement().cast();
if (popup.getParentElement() == null) {
// Hide the popup so it can enter its initial state without flickering.
popup.getStyle().setVisibility("hidden");
RootLayoutPanel.get().add(view);
}
// Start the animation after the element is attached.
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
// The popup may have been hidden before this timer executes.
if (isShowing) {
popup.getStyle().removeProperty("visibility");
view.setShowing(true);
if (selectAndFocusElement != null) {
selectAndFocusElement.select();
selectAndFocusElement.focus();
}
}
}
});
}
private void handleViewEvents() {
view.setDelegate(new ViewEvents() {
@Override
public void onEscapeKey() {
if (hideOnEscapeEnabled) {
hide();
Window.this.onClose();
}
}
@Override
public void onClose() {
hide();
Window.this.onClose();
}
@Override
public void onEnterKey() {
onEnterClicked();
}
});
}
/**
* this method called when user close Window
*/
protected abstract void onClose();
@Override
public Widget asWidget() {
return com.google.gwt.user.client.ui.HTML.wrap(view.getElement());
}
public void setTitle(String title) {
view.headerLabel.setText(title);
}
public HTMLPanel getFooter() {
return view.footer;
}
/**
* The resources used by this UI component.
*/
public interface Resources extends ClientBundle {
@Source({"org/eclipse/che/ide/common/constants.css", "Window.css", "org/eclipse/che/ide/api/ui/style.css"})
Css centerPanelCss();
@Source("close-dark-normal.png")
ImageResource closeDark();
@Source("close-dark-hover.png")
ImageResource closeDarkHover();
@Source("close-white-hover.png")
ImageResource closeWhiteHover();
@Source("close-white-normal.png")
ImageResource closeWhite();
}
/**
* The Css Style names used by this panel.
*/
public interface Css extends CssResource {
/**
* Returns duration of the popup animation in milliseconds.
*/
int animationDuration();
String content();
String contentVisible();
String glass();
String glassVisible();
String popup();
String positioner();
String header();
String headerTitleWrapper();
String headerTitleLabel();
String footer();
String separator();
String alignBtn();
String crossButton();
String blueButton();
String button();
String label();
String image();
String iconButton();
}
/**
* The events sources by the View.
*/
public interface ViewEvents {
void onEscapeKey();
void onClose();
void onEnterKey();
}
}