/**
* GwtFancyCssLayout.java (FancyLayouts)
*
* Copyright 2012 Vaadin Ltd, Sami Viitanen <alump@vaadin.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.vaadin.alump.fancylayouts.gwt.client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.vaadin.alump.fancylayouts.gwt.client.model.BrowserMode;
import org.vaadin.alump.fancylayouts.gwt.client.model.FancyRemover;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
public class GwtFancyCssLayout extends SimplePanel {
public final static String CLASS_NAME = "fancy-csslayout";
private static BrowserMode browserMode;
protected boolean transitionsEnabled = false;
protected String width = "";
protected String height = "";
protected FlowPanel flowPanel = new FlowPanel();
protected List<Widget> children = new ArrayList<Widget>();
protected Map<Element, Widget> widgetMap = new HashMap<Element, Widget>();
protected Set<Widget> removingMap = new HashSet<Widget>();
protected boolean horizontalMarginTransitionEnabled = true;
protected boolean verticalMarginTransitionEnabled = true;
protected FancyRemover fancyRemover = null;
public GwtFancyCssLayout() {
addStyleName(CLASS_NAME);
flowPanel.addStyleName(CLASS_NAME + "-content");
super.add(flowPanel);
if (browserMode == null) {
browserMode = BrowserMode.resolve();
}
transitionsEnabled = !(browserMode == BrowserMode.DEFAULT);
}
public void addOrMove(Widget widget, int index) {
if (hasChild(widget)) {
if (children.indexOf(widget) != index) {
remove(widget);
add(widget, index);
}
} else {
add(widget, index);
}
}
/**
* Add widget to given position
*
* @param widget
* Widget added
* @param index
* Index for widget
*/
public void add(Widget widget, int index) {
if (hasChild(widget)) {
return;
}
SimplePanel wrapper = new SimplePanel();
wrapper.setStyleName(CLASS_NAME + "-item");
if (index < 0 || index >= flowPanel.getWidgetCount()) {
flowPanel.add(wrapper);
} else {
flowPanel.insert(wrapper, index);
}
wrapper.add(widget);
final Element wrapperElement = wrapper.getElement();
widgetMap.put(wrapperElement, widget);
children.add(index, widget);
if (this.isVisible()) {
wrapperElement.getStyle().setOpacity(0.0);
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
@Override
public boolean execute() {
wrapperElement.getStyle().setOpacity(1.0);
return false;
}
}, 50);
}
}
@Override
public void add(Widget widget) {
add(widget, -1);
}
public boolean hasChild(Widget widget) {
return children.contains(widget);
}
private void addTransitionEndListener(Element element) {
if (element.hasAttribute("hasTransitionEndListener")
&& element.getAttribute("hasTransitionEndListener").equals("1")) {
return;
}
String eventName = browserMode.getTransitionEnd();
if (eventName != null) {
addTransitionEndListener(eventName, element);
}
}
private native void addTransitionEndListener(String eventName,
Element element)
/*-{
var that = this;
element.addEventListener(eventName, function(event){
that.@org.vaadin.alump.fancylayouts.gwt.client.GwtFancyCssLayout::onTransitionEnd(Ljava/lang/Object;)(element);
},false);
element.hasTransitionEndListener = true;
}-*/;
private void onTransitionEnd(Object object) {
if (!(object instanceof Element)) {
return;
}
final Element element = (Element) object;
Widget widget = widgetMap.get(element);
if (widget == null) {
return;
}
try {
float value = new Float(element.getStyle().getOpacity());
if (value < 0.01f) {
removingMap.remove(widget);
performFancyRemove(widget);
}
} catch (Exception e) {
}
}
private void removeWidgetWithTransition(Widget child) {
Element wrapperElement = child.getParent().getElement();
if (!child.isVisible()) {
performFancyRemove(child);
} else if (!removingMap.contains(child)) {
removingMap.add(child);
addTransitionEndListener(wrapperElement);
wrapperElement.getStyle().setOpacity(0.0);
if (verticalMarginTransitionEnabled) {
wrapperElement.getStyle().setMarginTop(
-wrapperElement.getOffsetHeight() / 2.0, Unit.PX);
wrapperElement.getStyle().setMarginBottom(
-wrapperElement.getOffsetHeight() / 2.0, Unit.PX);
}
if (horizontalMarginTransitionEnabled) {
wrapperElement.getStyle().setMarginLeft(
-wrapperElement.getOffsetWidth() / 2.0, Unit.PX);
wrapperElement.getStyle().setMarginRight(
-wrapperElement.getOffsetWidth() / 2.0, Unit.PX);
}
}
}
public void setVerticalMarginTransitionEnabled(boolean enabled) {
verticalMarginTransitionEnabled = enabled;
}
public void setHorizontalMarginTransitionEnabled(boolean enabled) {
horizontalMarginTransitionEnabled = enabled;
}
/**
* Do fancy remove of widget
*
* @param widget
* Widget removed
* @return true if remove started/done
*/
public boolean fancyRemove(Widget widget) {
if (!children.contains(widget)) {
return false;
}
if (transitionsEnabled && this.isVisible()) {
removeWidgetWithTransition(widget);
} else {
performFancyRemove(widget);
}
return true;
}
/**
* Remove fancy remover (called when remove should be done)
*
* @param remover
* Handler of removing
*/
public void setFancyRemover(FancyRemover remover) {
fancyRemover = remover;
}
/**
* To be overwritten if additional actions has to be performed. For example
* do the deletion via server.
*
* @param widget
* Child widget removed
*/
protected void performFancyRemove(Widget widget) {
if (fancyRemover == null) {
remove(widget);
} else {
fancyRemover.remove(widget);
}
}
@Override
public boolean remove(Widget widget) {
if (children.contains(widget)) {
Widget wrapper = widget.getParent();
widgetMap.remove(wrapper.getElement());
removingMap.remove(widget);
flowPanel.remove(wrapper);
children.remove(widget);
return true;
} else {
return false;
}
}
@Override
public void setWidth(String width) {
if (this.width.endsWith(width)) {
return;
}
this.width = width;
super.setWidth(width);
}
@Override
public void setHeight(String height) {
this.height = height;
super.setHeight(height);
}
public Iterator<Widget> childIterator() {
return children.iterator();
}
}