/*******************************************************************************
* Copyright (c) 2012 Rushan R. Gilmullin and others.
* 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:
* Rushan R. Gilmullin - initial API and implementation
*******************************************************************************/
package org.semanticsoft.vaaclipse.widgets.client.ui.stackwidget;
import java.util.Map;
import org.semanticsoft.commons.geom.GeomUtils.Side;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.VConsole;
import fi.jasoft.dragdroplayouts.client.ui.tabsheet.VDDTabSheet;
/**
* Client side widget which communicates with the server. Messages from the
* server are shown as HTML and mouse clicks are sent to the server.
*/
public class VStackWidget extends VDDTabSheet
//,DragHandlerFinder
{
/** Set the CSS class name to allow styling. */
public static final String CLASSNAME = "v-stackwidget";
public static final String CLICK_EVENT_IDENTIFIER = "click";
ApplicationConnection client;
String id;
//Minmax button support
private Element tabs;
private Element scroller;
private Element buttonPanel;
//Docking support
private Element dockZone1;
private Element dockZone2;
private Element dockZone3;
private Element dockZone4;
private Element dockZoneContainer;
final String E4_ELEMENT_TYPE = "e4ElementType";
Side dockSide;
Element maximizeButton;
Element minimizeButton;
int state;
private static final int MINIMIZED = -1;
private static final int NORMAL = 0;
private static final int MAXIMIZED = 1;
boolean maximizeEnabled = true;
boolean minimizeEnabled = true;
private String baseURL;
//Relocate of part toolbar support
private boolean toolbarRelocated = false;
private Element toolbarElement;
private Integer toolbarElementHeight;
private Map<Element, String> overflowRewritedElements;
private Integer oldTabbarOffsetHeight;
/**
* The constructor should first call super() to initialize the component and
* then handle any initialization relevant to Vaadin.
*/
public VStackWidget() {
super();
this.baseURL = GWT.getHostPageBaseURL();
tabs = (Element) getElement().getChild(0);
scroller = DOM.getChild(tabs, 1);
DOM.setStyleAttribute(scroller, "marginRight", "45px");
//scroller.setAttribute("style", "width:90px;");
for (int i = 0; i < DOM.getChildCount(scroller); i++)
{
Element child = DOM.getChild(scroller, i);
DOM.setStyleAttribute(child, "float", "left");
}
buttonPanel = DOM.createDiv();
setStyleName(buttonPanel, "vaadock-tabsheet-button-panel");
DOM.appendChild(tabs, buttonPanel);
maximizeButton = DOM.createButton();
setStyleName(maximizeButton, "v-vaadock-tabsheet-maximize-button");
DOM.sinkEvents(maximizeButton, Event.ONCLICK);
DOM.appendChild(buttonPanel, maximizeButton);
minimizeButton = DOM.createButton();
DOM.sinkEvents(minimizeButton, Event.ONCLICK);
setStyleName(minimizeButton, "v-vaadock-tabsheet-minimize-button");
DOM.appendChild(buttonPanel, minimizeButton);
// if (VDragAndDropManager.get().getDragHandlerFinder() == null)
// {
// VDragAndDropManager.get().setDragHandlerFinder(this);
// VConsole.log("DragHandlerFinder is installed");
// }
}
@Override
public void iLayout()
{
super.iLayout();
updateLocationOfButtonPanel();
// updateLocationOfPartToolbar();
}
private void updateLocationOfButtonPanel()
{
int buttonPanelHeight = tabs.getOffsetHeight();
int buttonPanelMarginTop = -buttonPanelHeight;
DOM.setStyleAttribute(buttonPanel, "height", buttonPanelHeight + "px");
DOM.setStyleAttribute(buttonPanel, "marginTop", buttonPanelMarginTop + "px");
}
public int getState()
{
return state;
}
public void setState(int state)
{
if (state != MINIMIZED && state != NORMAL && state != MAXIMIZED)
return;
this.state = state;
VConsole.log("VStackWidget: state = " + this.state);
if (this.state == NORMAL)
{
this.state = NORMAL;
setStyleName(maximizeButton, "v-vaadock-tabsheet-maximize-button");
setStyleName(minimizeButton, "v-vaadock-tabsheet-minimize-button");
maximizeButton.setAttribute("style", "");
minimizeButton.setAttribute("style", "");
}
else if (this.state == MAXIMIZED)
{
this.state = MAXIMIZED;
setStyleName(maximizeButton, "v-vaadock-tabsheet-restore-button");
setStyleName(minimizeButton, "v-vaadock-tabsheet-minimize-button");
maximizeButton.setAttribute("style", "");
minimizeButton.setAttribute("style", "");
}
else if (this.state == MINIMIZED)
{
this.state = MINIMIZED;
setStyleName(maximizeButton, "v-vaadock-tabsheet-maximize-button");
setStyleName(minimizeButton, "v-vaadock-tabsheet-restore-button");
maximizeButton.setAttribute("style", "display: none;");
minimizeButton.setAttribute("style", "");
}
}
@Override
public void onBrowserEvent(Event event)
{
if (event.getTypeInt() == Event.ONCLICK)
{
if (DOM.eventGetTarget(event) == maximizeButton)
{
//VConsole.log(event.getType());
synchronized (this)
{
event.stopPropagation();
if (this.state == MAXIMIZED)
{
setState(NORMAL);
}
else if (this.state == NORMAL)
{
setState(MAXIMIZED);
}
client.updateVariable(this.id, "vaadock_tabsheet_state", new Integer(this.state), true);
}
}
else if (DOM.eventGetTarget(event) == minimizeButton)
{
//VConsole.log(event.getType());
synchronized (this)
{
event.stopPropagation();
if (this.state == NORMAL)
{
setState(MINIMIZED);
}
else if (this.state == MINIMIZED)
{
setState(NORMAL);
}
else if (this.state == MAXIMIZED)
{
setState(MINIMIZED);
}
client.updateVariable(this.id, "vaadock_tabsheet_state", new Integer(this.state), true);
}
}
}
super.onBrowserEvent(event);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Drag-and-drop support
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// public VDropHandler findDragTarget(com.google.gwt.dom.client.Element element) {
//
// try {
// Widget w = Util.findWidget(
// (com.google.gwt.user.client.Element) element, null);
// if (w == null) {
// return null;
// }
//
// VDragEvent event = VDragAndDropManager.get().getDragEvent();
// Widget sourceWidget = (Widget) event.getTransferable().getDragSource();
// if (sourceWidget != null && sourceWidget instanceof VDDTabSheet)
// {
// while (!(w instanceof VDDTabSheet) ) {
// w = w.getParent();
// if (w == null) {
// break;
// }
// }
// }
// else
// {
// while (!(w instanceof VHasDropHandler) ) {
// w = w.getParent();
// if (w == null) {
// break;
// }
// }
// }
//
// if (w == null) {
// return null;
// } else {
// VDropHandler dh = ((VHasDropHandler) w).getDropHandler();
// return dh;
// }
// } catch (Exception e) {
// return null;
// }
//
// }
//
// @Override
// protected void updateDropHandler(UIDL childUidl) {
// if (dropHandler == null) {
// dropHandler = new VAbstractDropHandler() {
//
// /*
// * (non-Javadoc)
// *
// * @see com.vaadin.terminal.gwt.client.ui.dd.VDropHandler#
// * getApplicationConnection()
// */
// public ApplicationConnection getApplicationConnection() {
// return client;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see
// * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
// * #getPaintable()
// */
// @Override
// public Paintable getPaintable() {
// return VStackWidget.this;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see
// * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
// * #dragAccepted
// * (com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
// */
// @Override
// protected void dragAccepted(VDragEvent drag) {
// dragOver(drag);
//
// //prepare inner drophandler owners
//// if (!innerDropProcessed)
//// {
//// processInnerHandlerOwners(VDDTabSheet.this, innerDropOwners);
//// innerDropProcessed = true;
//// }
// }
//
// /*
// * (non-Javadoc)
// *
// * @see
// * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
// * #drop(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
// */
// @Override
// public boolean drop(VDragEvent drag) {
//
// deEmphasis();
//
// // Update the details
// updateDropDetails(drag);
//
// if (dockZone1 != null && dockZoneContainer != null)
// {
// removeDockZone();
// }
//
// return postDropHook(drag) && super.drop(drag);
// };
//
// /*
// * (non-Javadoc)
// *
// * @see
// * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
// * #dragOver(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
// */
// @Override
// public void dragOver(VDragEvent drag) {
//
// //VConsole.log("drag over");
//
// if (drag.getElementOver() == newTab) {
// return;
// }
//
// deEmphasis();
//
// updateDropDetails(drag);
//
// postOverHook(drag);
//
// // Check if we are dropping on our self
// if (VStackWidget.this.equals(drag.getTransferable().getData(
// Constants.TRANSFERABLE_DETAIL_COMPONENT))) {
// return;
// }
//
// // Validate the drop
// validate(new VAcceptCallback() {
// public void accepted(VDragEvent event) {
// emphasis(event.getElementOver(), event);
// }
// }, drag);
// };
//
// /*
// * (non-Javadoc)
// *
// * @see
// * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
// * #dragLeave(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
// */
// @Override
// public void dragLeave(VDragEvent drag) {
// deEmphasis();
// updateDropDetails(drag);
// postLeaveHook(drag);
//
// if (dockZone1 != null && dockZoneContainer != null)
// {
// removeDockZone();
// }
// };
// };
// }
//
// // Update the rules
// dropHandler.updateAcceptRules(childUidl);
// }
//
// protected boolean isDockZoneExists()
// {
// return dockZone1 != null && dockZoneContainer != null;
// }
//
// protected void removeDockZone()
// {
// if (isDockZoneExists())
// {
// dockSide = null;
// DOM.removeChild(dockZoneContainer, dockZone1);
// DOM.removeChild(dockZoneContainer, dockZone2);
// DOM.removeChild(dockZoneContainer, dockZone3);
// DOM.removeChild(dockZoneContainer, dockZone4);
// dockZone1 = null;
// dockZone2 = null;
// dockZone3 = null;
// dockZone4 = null;
// dockZoneContainer = null;
// }
// }
//
// /**
// * Updates the drop details while dragging. This is needed to ensure client
// * side criterias can validate the drop location.
// *
// * @param widget
// * The container which we are hovering over
// * @param event
// * The drag event
// */
// @Override
// protected void updateDropDetails(VDragEvent event)
// {
// Element element = event.getElementOver();
// Widget targetWidget = Util.findWidget(element, null);
//
// if (targetWidget == null)
// {
// return;
// }
//
// if (targetWidget != this)
// {
// Widget parent = targetWidget.getParent();
// while (parent != null && parent != this)
// {
// parent = parent.getParent();
// }
//
// if (parent == null)
// {
// return;
// }
// targetWidget = parent;
// }
//
// MouseEventDetails details1 = new MouseEventDetails(
// event.getCurrentGwtEvent(), getElement());
//
// int mouseX = details1.getClientX();
// int mouseY = details1.getClientY();
//
//
// int barLeft = tabBar.getAbsoluteLeft();
// int barTop = tabBar.getAbsoluteTop();
// int barWidth = tabBar.getOffsetWidth();
// int barHeight = tabBar.getOffsetHeight();
//
// boolean overBar = mouseX > barLeft && mouseX < barLeft + barWidth && mouseY > barTop && mouseY < barTop + barHeight;
//
// if (overBar)
// {
// removeDockZone();
//
// event.getDropDetails().put("targetWidgetClassName", targetWidget.getClass().getName());
// event.getDropDetails().put("dropType", "DropToTabsheetBar");
// event.getDropDetails().put("targetWidgetAbsoluteLeft", targetWidget.getAbsoluteLeft());
// event.getDropDetails().put("targetWidgetAbsoluteTop", targetWidget.getAbsoluteTop());
// event.getDropDetails().put("targetWidgetOffsetWidth", targetWidget.getOffsetWidth());
// event.getDropDetails().put("targetWidgetOffsetHeight", targetWidget.getOffsetHeight());
// }
// else
// {
// Widget sourceWidget = (Widget) event.getTransferable().getDragSource();
// if (!(sourceWidget instanceof VDDTabSheet))
// return;
// VDDTabSheet sourceTabSheet = (VDDTabSheet) sourceWidget;
// VDDTabSheet targetTabSheet = this;
//
// VBoundsinfoVerticalLayout outerArea = findOuterArea(targetTabSheet);
//
// Widget boundingWidget = null;
//
// if (outerArea != null)
// {
// if ("area".equals(outerArea.getVariableValue(E4_ELEMENT_TYPE)))
// boundingWidget = outerArea;
// }
// else
// boundingWidget = targetTabSheet;
//
// if (boundingWidget == null)
// return;
//
// event.getDropDetails().put("targetWidgetClassName", boundingWidget.getClass().getName());
// event.getDropDetails().put("dropType", "DropToTabsheetBody");
// event.getDropDetails().put("targetWidgetAbsoluteLeft", boundingWidget.getAbsoluteLeft());
// event.getDropDetails().put("targetWidgetAbsoluteTop", boundingWidget.getAbsoluteTop());
// event.getDropDetails().put("targetWidgetOffsetWidth", boundingWidget.getOffsetWidth());
// event.getDropDetails().put("targetWidgetOffsetHeight", boundingWidget.getOffsetHeight());
//
//
// int x0 = boundingWidget.getAbsoluteLeft();
// int y0 = boundingWidget.getAbsoluteTop();
// int dx = boundingWidget.getOffsetWidth();
// int dy = boundingWidget.getOffsetHeight();
//
// int docPrcnt = 30;
// double docX = dx * docPrcnt / 100;
// double docY = dy * docPrcnt / 100;
// double d = 1;
//
// Vector mousePos = Vector.valueOf(mouseX, mouseY);
//
// Side side = GeomUtils.findDockSide(x0, y0, dx, dy, docX, docY, mousePos);
// //VConsole.log("dock side: " + side);
// if (side != null)
// {
// double _x = 0, _y = 0, _w = 0, _h = 0;
//
// if (side == Side.LEFT)
// {
// _x = d;
// _y = d;
// _w = docX - d;
// _h = dy - 2*d;
// }
// else if (side == Side.TOP)
// {
// _x = d;
// _y = d;
// _w = dx - 2*d;
// _h = docY - d;
// }
// else if (side == Side.RIGHT)
// {
// _x = dx - docX;
// _y = d;
// _w = docX - d;
// _h = dy - 2*d;
// }
// else if (side == Side.BOTTOM)
// {
// _x = d;
// _y = dy - docY;
// _w = dx - 2*d;
// _h = docY - d;
// }
// else if (side == Side.CENTER)
// {
// _x = d;
// _y = d;
// _w = dx - 2*d;
// _h = dy - 2*d;
// }
// else
// return;
//
// _x = x0 + _x;
// _y = y0 + _y;
//
// if (dockZone1 == null)
// {
// dockZone1 = DOM.createDiv();
// dockZone2 = DOM.createDiv();
// dockZone3 = DOM.createDiv();
// dockZone4 = DOM.createDiv();
// }
//
// //VConsole.log("x=" + _x + "; y=" + _y + "; w=" + _w + "; h=" + _h);
//
// if (side != dockSide)
// {
// int l = 3;
// String style1 = "position: absolute; left: " + _x + "px; top: " + _y +
// "px; width: " + _w + "px; height: " + l + "px; background-image: url(" + baseURL + "VAADIN/themes/dragdrop/vaadock/img/dockzone.png); z-index: 20000;";
// dockZone1.setAttribute("style", style1);
//
// String style2 = "position: absolute; left: " + _x + "px; top: " + (_y + _h - l) +
// "px; width: " + _w + "px; height: " + l + "px; background-image: url(" + baseURL + "VAADIN/themes/dragdrop/vaadock/img/dockzone.png); z-index: 20000;";
// dockZone2.setAttribute("style", style2);
//
// String style3 = "position: absolute; left: " + _x + "px; top: " + _y +
// "px; width: " + l + "px; height: " + _h + "px; background-image: url(" + baseURL + "VAADIN/themes/dragdrop/vaadock/img/dockzone.png); z-index: 20000;";
// dockZone3.setAttribute("style", style3);
//
// String style4 = "position: absolute; left: " + (_x + _w - l) + "px; top: " + _y +
// "px; width: " + l + "px; height: " + _h + "px; background-image: url(" + baseURL + "VAADIN/themes/dragdrop/vaadock/img/dockzone.png); z-index: 20000;";
// dockZone4.setAttribute("style", style4);
//
// //setStyleName(dockZone, "v-etot-sukin-syn");
// //dockZoneContainer = boundingWidget.getElement();
// dockZoneContainer = RootPanel.get().getElement();
// DOM.appendChild(dockZoneContainer, dockZone1);
// DOM.appendChild(dockZoneContainer, dockZone2);
// DOM.appendChild(dockZoneContainer, dockZone3);
// DOM.appendChild(dockZoneContainer, dockZone4);
//
// dockSide = side;
// }
// }
// }
//
// //--
//
// if (tabBar.getElement().isOrHasChild(element)) {
//
// if (targetWidget == tabBar) {
// // Ove3r the spacer
//
// // Add index
// event.getDropDetails().put(Constants.DROP_DETAIL_TO,
// tabBar.getWidgetCount() - 1);
//
// // Add drop location
// event.getDropDetails().put(
// Constants.DROP_DETAIL_HORIZONTAL_DROP_LOCATION,
// HorizontalDropLocation.RIGHT);
//
// } else {
//
// // Add index
// event.getDropDetails().put(Constants.DROP_DETAIL_TO,
// getTabPosition(targetWidget));
//
// // Add drop location
// HorizontalDropLocation location = VDragDropUtil
// .getHorizontalDropLocation(element, Util
// .getTouchOrMouseClientX(event
// .getCurrentGwtEvent()),
// tabLeftRightDropRatio);
// event.getDropDetails().put(
// Constants.DROP_DETAIL_HORIZONTAL_DROP_LOCATION,
// location);
// }
// }
//
// // Add mouse event details
// MouseEventDetails details = new MouseEventDetails(
// event.getCurrentGwtEvent(), getElement());
// event.getDropDetails().put(Constants.DROP_DETAIL_MOUSE_EVENT,
// details.serialize());
// }
//
// private VBoundsinfoVerticalLayout findOuterArea(Widget w)
// {
// if (w instanceof VBoundsinfoVerticalLayout)
// {
// VBoundsinfoVerticalLayout bl = (VBoundsinfoVerticalLayout) w;
// final String type = bl.getVariableValue(E4_ELEMENT_TYPE);
// if (type != null && ("area".equals(type) || "perspective".equals(type) || "window".equals(type)))
// return bl;
// }
//
// if (w.getParent() != null)
// return findOuterArea(w.getParent());
// else
// return null;
// }
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Part toolbar relocate support
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// private void updateLocationOfPartToolbar()
// {
// if (toolbarRelocated)
// {
// if (!hasSpace(toolbarElement))
// {
// restoreLocationOfPartToolbar();
// }
// }
// else
// {
// Paintable selectedTab = getTab(activeTabIndex);
// if (selectedTab == null || !(selectedTab instanceof Widget))
// return;
//
// Widget selectedWidget = (Widget) selectedTab;
//
// Element _toolbarElement = findToolbarElement(selectedWidget.getElement());
// if (_toolbarElement == null)
// return;
//
// if (hasSpace(_toolbarElement))
// {
// changeLocationOfPartToolbar(selectedWidget, _toolbarElement);
// }
// }
// }
//
// private boolean hasSpace(Element toolbarElement)
// {
// Element tb = (Element) tabs.getChild(0);
// Element spacertd = (Element) tb.getChild(0).getChild(0).getLastChild();
//
// return tb.getOffsetWidth() - DOM.getElementPropertyInt((Element) spacertd.cast(), "offsetWidth") < getOffsetWidth()
// - buttonPanel.getOffsetWidth() - toolbarElement.getOffsetWidth() - 10;
// }
//
// private void changeLocationOfPartToolbar(Widget selectedWidget, Element _toolbarElement)
// {
// if (toolbarRelocated || activeTabIndex < 0 || this.getParent() == null)
// return;
//
// toolbarElement = _toolbarElement;
// overflowRewritedElements = new HashMap<Element, String>();
//
// List<Node> pathToParent = findPathToParent(toolbarElement, selectedWidget.getParent().getElement());
//
// for (Node node: pathToParent)
// {
// if (node instanceof Element)
// {
// Element element = (Element) node;
// String overflow = DOM.getElementProperty((Element) element, "overflow");
// if (!"".equals(overflow) && !"visible".equals(overflow) && !"".equals("inherit"))
// {
// DOM.setStyleAttribute(element, "overflow", "visible");
// overflowRewritedElements.put(element, overflow);
// }
// }
// }
//
// toolbarRelocated = true;
//
// updateGeometry();
// }
//
// private void updateGeometry()
// {
// int marginRight = buttonPanel.getOffsetWidth() + 5;
// int marginTop = tabs.getAbsoluteTop() - toolbarElement.getAbsoluteTop();
//
// DOM.setStyleAttribute(toolbarElement, "marginRight", marginRight + "px");
// DOM.setStyleAttribute(toolbarElement, "marginTop", marginTop + "px");
// }
//
// private void restoreLocationOfPartToolbar()
// {
// if (!toolbarRelocated)
// return;
//
// DOM.setStyleAttribute(toolbarElement, "marginRight", "");
// DOM.setStyleAttribute(toolbarElement, "marginTop", "");
//
// toolbarElement = null;
// overflowRewritedElements = null;
// oldTabbarOffsetHeight = null;
// toolbarElementHeight = null;
// toolbarRelocated = false;
// }
//
// private Element findToolbarElement(Element parent)
// {
// for (int i = 0; i < parent.getChildCount(); i++)
// {
// Node node = parent.getChild(i);
// if (node instanceof Element)
// {
// Element childElement = (Element) node;
// String className = childElement.getClassName();
// if (className != null && !className.contains("mparttoolbararea") && className.contains("mparttoolbar"))
// {
// return childElement;
// }
// else
// {
// Element toolbarElement = findToolbarElement(childElement);
// if (toolbarElement != null)
// return toolbarElement;
// }
// }
// }
// return null;
// }
//
// private List<Node> findPathToParent(Element element, Element parentElement)
// {
// List<Node> pathToParent = new ArrayList<Node>();
// Node parent = element.getParentElement();
// while (parent != null && parent != parentElement)
// {
// pathToParent.add(parent);
// parent = parent.getParentElement();
// }
// if (parent != null)
// pathToParent.add(parent);
// else
// pathToParent.clear();
// return pathToParent;
// }
}