/*******************************************************************************
* Copyright (c) 2012-2017 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.api.parts.base;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import org.eclipse.che.ide.FontAwesome;
import org.eclipse.che.ide.api.mvp.View;
import org.eclipse.che.ide.api.parts.Focusable;
import org.eclipse.che.ide.api.parts.PartStackUIResources;
import org.eclipse.che.ide.ui.Tooltip;
import org.eclipse.che.ide.ui.menu.PositionController;
import org.eclipse.che.ide.util.UIUtil;
import org.vectomatic.dom.svg.ui.SVGImage;
import javax.validation.constraints.NotNull;
/**
* Base view for part. By default the view has toolbar containing part description and minimize button.
* Toolbar is represented as dock panel and can be simply expanded.
*
* @author Codenvy crowd
*/
public abstract class BaseView<T extends BaseActionDelegate> extends Composite implements View<T>, Focusable {
private final PartStackUIResources resources;
/** Root widget */
private DockLayoutPanel container;
protected DockLayoutPanel toolBar;
protected DockLayoutPanel toolbarHeader;
protected T delegate;
protected ToolButton minimizeButton;
protected Label titleLabel;
protected FocusWidget lastFocused;
/** Indicates whether this view is focused */
private boolean focused = false;
private BlurHandler blurHandler = new BlurHandler() {
@Override
public void onBlur(BlurEvent event) {
if (event.getSource() instanceof FocusWidget) {
lastFocused = (FocusWidget)event.getSource();
}
}
};
public BaseView(PartStackUIResources resources) {
this.resources = resources;
container = new DockLayoutPanel(Style.Unit.PX);
container.getElement().setAttribute("role", "part");
container.setSize("100%", "100%");
container.getElement().getStyle().setOutlineStyle(Style.OutlineStyle.NONE);
initWidget(container);
toolBar = new DockLayoutPanel(Style.Unit.PX);
toolBar.addStyleName(resources.partStackCss().ideBasePartToolbar());
toolBar.getElement().setAttribute("role", "toolbar");
toolBar.addDomHandler(new MouseUpHandler() {
@Override
public void onMouseUp(MouseUpEvent event) {
//activate last focused element if user clicked on part header
if (lastFocused != null) {
lastFocused.setFocus(true);
}
}
}, MouseUpEvent.getType());
container.addNorth(toolBar, 23);
//this hack used for adding box shadow effect to toolbar
toolBar.getElement().getParentElement().getStyle().setOverflow(Style.Overflow.VISIBLE);
toolbarHeader = new DockLayoutPanel(Style.Unit.PX);
toolbarHeader.getElement().setAttribute("role", "toolbar-header");
toolBar.addNorth(toolbarHeader, 22);
// padding 2 pixels from the right
toolbarHeader.addEast(new FlowPanel(), 2);
titleLabel = new Label();
titleLabel.setStyleName(resources.partStackCss().ideBasePartTitleLabel());
toolbarHeader.addWest(titleLabel, 200);
addMaximizeButton();
addMinimizeButton();
addMenuButton();
/**
* Handle double clicking on the toolbar header
*/
toolbarHeader.addDomHandler(new DoubleClickHandler() {
@Override
public void onDoubleClick(DoubleClickEvent event) {
onToggleMaximize();
}
}, DoubleClickEvent.getType());
}
/**
* Adds minimize part button.
*/
private void addMinimizeButton() {
SVGImage minimize = new SVGImage(resources.collapseExpandIcon());
minimize.getElement().setAttribute("name", "workBenchIconMinimize");
minimizeButton = new ToolButton(minimize);
minimizeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
onMinimize();
}
});
addToolButton(minimizeButton);
if (minimizeButton.getElement() instanceof elemental.dom.Element) {
Tooltip.create((elemental.dom.Element) minimizeButton.getElement(),
PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Hide");
}
}
/**
* Adds maximize part button.
*/
private void addMaximizeButton() {
SVGImage maximize = new SVGImage(resources.maximizePart());
maximize.getElement().setAttribute("name", "workBenchIconMaximize");
ToolButton maximizeButton = new ToolButton(maximize);
maximizeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
onToggleMaximize();
}
});
addToolButton(maximizeButton);
if (maximizeButton.getElement() instanceof elemental.dom.Element) {
Tooltip.create((elemental.dom.Element) maximizeButton.getElement(),
PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Maximize panel");
}
}
/**
* Adds part menu button.
*/
private void addMenuButton() {
final ToolButton menuButton = new ToolButton(FontAwesome.COG + " " + FontAwesome.CARET_DOWN);
menuButton.getElement().setAttribute("name", "workBenchIconMenu");
menuButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
int left = getAbsoluteLeft(menuButton.getElement());
int top = getAbsoluteTop(menuButton.getElement());
delegate.onPartMenu(left, top + 21);
}
});
toolbarHeader.addEast(menuButton, 25);
if (menuButton.getElement() instanceof elemental.dom.Element) {
Tooltip.create((elemental.dom.Element) menuButton.getElement(),
PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Panel options");
}
}
/**
* Returns absolute left position of the element.
*
* @param element
* element
* @return
* element left position
*/
private native int getAbsoluteLeft(JavaScriptObject element) /*-{
return element.getBoundingClientRect().left;
}-*/;
/**
* Returns absolute top position of the element.
*
* @param element
* element
* @return
* element top position
*/
private native int getAbsoluteTop(JavaScriptObject element) /*-{
return element.getBoundingClientRect().top;
}-*/;
/**
* Add a button on part toolbar,
*
* @param button button
*/
public final void addToolButton(@NotNull IsWidget button) {
if (button != null) {
toolbarHeader.addEast(button, 18);
}
}
/**
* Removes button from part toolbar.
*
* @param button button
*/
public void removeToolButton(@NotNull IsWidget button) {
if (button != null) {
toolbarHeader.remove(button);
}
}
/**
* Sets button visible on part toolbar.
*
* @param button button
*/
public final void showToolButton(@NotNull IsWidget button) {
if (button != null) {
toolbarHeader.setWidgetHidden(button.asWidget(), false);
}
}
/**
* Hides button on part toolbar.
*
* @param button button
*/
public final void hideToolButton(@NotNull IsWidget button) {
if (button != null) {
toolbarHeader.setWidgetHidden(button.asWidget(), true);
}
}
/** {@inheritDoc} */
@Override
public final void setDelegate(T delegate) {
this.delegate = delegate;
}
/**
* Toggles maximized state of the view.
*/
public void onToggleMaximize() {
if (delegate != null) {
delegate.onToggleMaximize();
}
}
/**
* Minimizes the view.
*/
public void onMinimize() {
if (delegate != null) {
delegate.onMinimize();
}
}
/**
* Sets content widget.
*
* @param widget
* content widget
*/
public final void setContentWidget(Widget widget) {
container.add(widget);
for (FocusWidget focusWidget : UIUtil.getFocusableChildren(widget)) {
focusWidget.addBlurHandler(blurHandler);
}
focusView();
}
/**
* Sets new value of part title.
*
* @param title
* part title
*/
@Override
public void setTitle(@NotNull String title) {
titleLabel.setText(title);
}
/**
* Sets new height of the toolbar.
*
* @param height
* new toolbar height
*/
@Deprecated
public final void setToolbarHeight(int height) {
container.setWidgetSize(toolBar, height);
}
/** {@inheritDoc} */
@Override
public final void setFocus(boolean focused) {
this.focused = focused;
if (focused) {
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
focusView();
}
});
}
}
/** {@inheritDoc} */
@Override
public final boolean isFocused() {
return focused;
}
/**
* Override this method to set focus to necessary element inside the view.
* Method is called when focusing the part view.
*/
protected void focusView() {
getElement().focus();
}
}