]> source.dussan.org Git - vaadin-framework.git/commitdiff
Merge commit '0ec349'
authorJohannes Dahlström <johannesd@vaadin.com>
Mon, 11 Jun 2012 11:06:49 +0000 (14:06 +0300)
committerJohannes Dahlström <johannesd@vaadin.com>
Mon, 11 Jun 2012 11:06:49 +0000 (14:06 +0300)
1  2 
src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java

index 8e78696f1bd6e16f07aec97828264653d2194b41,0000000000000000000000000000000000000000..444909c1b1bfaae268741e395e993dcc1accefd2
mode 100644,000000..100644
--- /dev/null
@@@ -1,517 -1,0 +1,517 @@@
-             sinkEvents(Event.TOUCHEVENTS | Event.MOUSEEVENTS);
 +/*
 +@VaadinApache2LicenseForJavaFiles@
 + */
 +package com.vaadin.terminal.gwt.client.ui.accordion;
 +
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Iterator;
 +import java.util.Set;
 +
 +import com.google.gwt.event.dom.client.ClickEvent;
 +import com.google.gwt.event.dom.client.ClickHandler;
 +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.ComplexPanel;
 +import com.google.gwt.user.client.ui.Widget;
 +import com.vaadin.terminal.gwt.client.ComponentConnector;
 +import com.vaadin.terminal.gwt.client.ConnectorMap;
 +import com.vaadin.terminal.gwt.client.UIDL;
 +import com.vaadin.terminal.gwt.client.Util;
 +import com.vaadin.terminal.gwt.client.VCaption;
 +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
 +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
 +import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector;
 +import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetBase;
 +
 +public class VAccordion extends VTabsheetBase {
 +
 +    public static final String CLASSNAME = "v-accordion";
 +
 +    private Set<Widget> widgets = new HashSet<Widget>();
 +
 +    HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>();
 +
 +    StackItem openTab = null;
 +
 +    int selectedUIDLItemIndex = -1;
 +
 +    private final TouchScrollHandler touchScrollHandler;
 +
 +    public VAccordion() {
 +        super(CLASSNAME);
 +        touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
 +    }
 +
 +    @Override
 +    protected void renderTab(UIDL tabUidl, int index, boolean selected,
 +            boolean hidden) {
 +        StackItem item;
 +        int itemIndex;
 +        if (getWidgetCount() <= index) {
 +            // Create stackItem and render caption
 +            item = new StackItem(tabUidl);
 +            if (getWidgetCount() == 0) {
 +                item.addStyleDependentName("first");
 +            }
 +            itemIndex = getWidgetCount();
 +            add(item, getElement());
 +        } else {
 +            item = getStackItem(index);
 +            item = moveStackItemIfNeeded(item, index, tabUidl);
 +            itemIndex = index;
 +        }
 +        item.updateCaption(tabUidl);
 +
 +        item.setVisible(!hidden);
 +
 +        if (selected) {
 +            selectedUIDLItemIndex = itemIndex;
 +        }
 +
 +        if (tabUidl.getChildCount() > 0) {
 +            lazyUpdateMap.put(item, tabUidl.getChildUIDL(0));
 +        }
 +    }
 +
 +    /**
 +     * This method tries to find out if a tab has been rendered with a different
 +     * index previously. If this is the case it re-orders the children so the
 +     * same StackItem is used for rendering this time. E.g. if the first tab has
 +     * been removed all tabs which contain cached content must be moved 1 step
 +     * up to preserve the cached content.
 +     * 
 +     * @param item
 +     * @param newIndex
 +     * @param tabUidl
 +     * @return
 +     */
 +    private StackItem moveStackItemIfNeeded(StackItem item, int newIndex,
 +            UIDL tabUidl) {
 +        UIDL tabContentUIDL = null;
 +        ComponentConnector tabContent = null;
 +        if (tabUidl.getChildCount() > 0) {
 +            tabContentUIDL = tabUidl.getChildUIDL(0);
 +            tabContent = client.getPaintable(tabContentUIDL);
 +        }
 +
 +        Widget itemWidget = item.getComponent();
 +        if (tabContent != null) {
 +            if (tabContent != itemWidget) {
 +                /*
 +                 * This is not the same widget as before, find out if it has
 +                 * been moved
 +                 */
 +                int oldIndex = -1;
 +                StackItem oldItem = null;
 +                for (int i = 0; i < getWidgetCount(); i++) {
 +                    Widget w = getWidget(i);
 +                    oldItem = (StackItem) w;
 +                    if (tabContent == oldItem.getComponent()) {
 +                        oldIndex = i;
 +                        break;
 +                    }
 +                }
 +
 +                if (oldIndex != -1 && oldIndex > newIndex) {
 +                    /*
 +                     * The tab has previously been rendered in another position
 +                     * so we must move the cached content to correct position.
 +                     * We move only items with oldIndex > newIndex to prevent
 +                     * moving items already rendered in this update. If for
 +                     * instance tabs 1,2,3 are removed and added as 3,2,1 we
 +                     * cannot re-use "1" when we get to the third tab.
 +                     */
 +                    insert(oldItem, getElement(), newIndex, true);
 +                    return oldItem;
 +                }
 +            }
 +        } else {
 +            // Tab which has never been loaded. Must assure we use an empty
 +            // StackItem
 +            Widget oldWidget = item.getComponent();
 +            if (oldWidget != null) {
 +                oldWidget.removeFromParent();
 +            }
 +        }
 +        return item;
 +    }
 +
 +    void open(int itemIndex) {
 +        StackItem item = (StackItem) getWidget(itemIndex);
 +        boolean alreadyOpen = false;
 +        if (openTab != null) {
 +            if (openTab.isOpen()) {
 +                if (openTab == item) {
 +                    alreadyOpen = true;
 +                } else {
 +                    openTab.close();
 +                }
 +            }
 +        }
 +        if (!alreadyOpen) {
 +            item.open();
 +            activeTabIndex = itemIndex;
 +            openTab = item;
 +        }
 +
 +        // Update the size for the open tab
 +        updateOpenTabSize();
 +    }
 +
 +    void close(StackItem item) {
 +        if (!item.isOpen()) {
 +            return;
 +        }
 +
 +        item.close();
 +        activeTabIndex = -1;
 +        openTab = null;
 +
 +    }
 +
 +    @Override
 +    protected void selectTab(final int index, final UIDL contentUidl) {
 +        StackItem item = getStackItem(index);
 +        if (index != activeTabIndex) {
 +            open(index);
 +            iLayout();
 +            // TODO Check if this is needed
 +            client.runDescendentsLayout(this);
 +
 +        }
 +        item.setContent(contentUidl);
 +    }
 +
 +    public void onSelectTab(StackItem item) {
 +        final int index = getWidgetIndex(item);
 +        if (index != activeTabIndex && !disabled && !readonly
 +                && !disabledTabKeys.contains(tabKeys.get(index))) {
 +            addStyleDependentName("loading");
 +            client.updateVariable(id, "selected", "" + tabKeys.get(index), true);
 +        }
 +    }
 +
 +    /**
 +     * Sets the size of the open tab
 +     */
 +    void updateOpenTabSize() {
 +        if (openTab == null) {
 +            return;
 +        }
 +
 +        // WIDTH
 +        if (!isDynamicWidth()) {
 +            openTab.setWidth("100%");
 +        } else {
 +            openTab.setWidth(null);
 +        }
 +
 +        // HEIGHT
 +        if (!isDynamicHeight()) {
 +            int usedPixels = 0;
 +            for (Widget w : getChildren()) {
 +                StackItem item = (StackItem) w;
 +                if (item == openTab) {
 +                    usedPixels += item.getCaptionHeight();
 +                } else {
 +                    // This includes the captionNode borders
 +                    usedPixels += item.getHeight();
 +                }
 +            }
 +
 +            int offsetHeight = getOffsetHeight();
 +
 +            int spaceForOpenItem = offsetHeight - usedPixels;
 +
 +            if (spaceForOpenItem < 0) {
 +                spaceForOpenItem = 0;
 +            }
 +
 +            openTab.setHeight(spaceForOpenItem);
 +        } else {
 +            openTab.setHeightFromWidget();
 +
 +        }
 +
 +    }
 +
 +    public void iLayout() {
 +        if (openTab == null) {
 +            return;
 +        }
 +
 +        if (isDynamicWidth()) {
 +            int maxWidth = 40;
 +            for (Widget w : getChildren()) {
 +                StackItem si = (StackItem) w;
 +                int captionWidth = si.getCaptionWidth();
 +                if (captionWidth > maxWidth) {
 +                    maxWidth = captionWidth;
 +                }
 +            }
 +            int widgetWidth = openTab.getWidgetWidth();
 +            if (widgetWidth > maxWidth) {
 +                maxWidth = widgetWidth;
 +            }
 +            super.setWidth(maxWidth + "px");
 +            openTab.setWidth(maxWidth);
 +        }
 +    }
 +
 +    /**
 +     * A StackItem has always two children, Child 0 is a VCaption, Child 1 is
 +     * the actual child widget.
 +     */
 +    protected class StackItem extends ComplexPanel implements ClickHandler {
 +
 +        public void setHeight(int height) {
 +            if (height == -1) {
 +                super.setHeight("");
 +                DOM.setStyleAttribute(content, "height", "0px");
 +            } else {
 +                super.setHeight((height + getCaptionHeight()) + "px");
 +                DOM.setStyleAttribute(content, "height", height + "px");
 +                DOM.setStyleAttribute(content, "top", getCaptionHeight() + "px");
 +
 +            }
 +        }
 +
 +        public Widget getComponent() {
 +            if (getWidgetCount() < 2) {
 +                return null;
 +            }
 +            return getWidget(1);
 +        }
 +
 +        @Override
 +        public void setVisible(boolean visible) {
 +            super.setVisible(visible);
 +        }
 +
 +        public void setHeightFromWidget() {
 +            Widget widget = getChildWidget();
 +            if (widget == null) {
 +                return;
 +            }
 +
 +            int paintableHeight = widget.getElement().getOffsetHeight();
 +            setHeight(paintableHeight);
 +
 +        }
 +
 +        /**
 +         * Returns caption width including padding
 +         * 
 +         * @return
 +         */
 +        public int getCaptionWidth() {
 +            if (caption == null) {
 +                return 0;
 +            }
 +
 +            int captionWidth = caption.getRequiredWidth();
 +            int padding = Util.measureHorizontalPaddingAndBorder(
 +                    caption.getElement(), 18);
 +            return captionWidth + padding;
 +        }
 +
 +        public void setWidth(int width) {
 +            if (width == -1) {
 +                super.setWidth("");
 +            } else {
 +                super.setWidth(width + "px");
 +            }
 +        }
 +
 +        public int getHeight() {
 +            return getOffsetHeight();
 +        }
 +
 +        public int getCaptionHeight() {
 +            return captionNode.getOffsetHeight();
 +        }
 +
 +        private VCaption caption;
 +        private boolean open = false;
 +        private Element content = DOM.createDiv();
 +        private Element captionNode = DOM.createDiv();
 +
 +        public StackItem(UIDL tabUidl) {
 +            setElement(DOM.createDiv());
 +            caption = new VCaption(client);
 +            caption.addClickHandler(this);
 +            super.add(caption, captionNode);
 +            DOM.appendChild(captionNode, caption.getElement());
 +            DOM.appendChild(getElement(), captionNode);
 +            DOM.appendChild(getElement(), content);
 +
 +            getElement().addClassName(CLASSNAME + "-item");
 +            captionNode.addClassName(CLASSNAME + "-item-caption");
 +            content.addClassName(CLASSNAME + "-item-content");
 +
 +            touchScrollHandler.addElement(getContainerElement());
 +
++            sinkEvents(Event.MOUSEEVENTS);
 +
 +            close();
 +        }
 +
 +        @Override
 +        public void onBrowserEvent(Event event) {
 +            onSelectTab(this);
 +        }
 +
 +        public Element getContainerElement() {
 +            return content;
 +        }
 +
 +        public Widget getChildWidget() {
 +            if (getWidgetCount() > 1) {
 +                return getWidget(1);
 +            } else {
 +                return null;
 +            }
 +        }
 +
 +        public void replaceWidget(Widget newWidget) {
 +            if (getWidgetCount() > 1) {
 +                Widget oldWidget = getWidget(1);
 +                ComponentConnector oldPaintable = ConnectorMap.get(client)
 +                        .getConnector(oldWidget);
 +                ConnectorMap.get(client).unregisterConnector(oldPaintable);
 +                widgets.remove(oldWidget);
 +                remove(1);
 +            }
 +            add(newWidget, content);
 +            widgets.add(newWidget);
 +        }
 +
 +        public void open() {
 +            open = true;
 +            DOM.setStyleAttribute(content, "top", getCaptionHeight() + "px");
 +            DOM.setStyleAttribute(content, "left", "0px");
 +            DOM.setStyleAttribute(content, "visibility", "");
 +            addStyleDependentName("open");
 +        }
 +
 +        public void hide() {
 +            DOM.setStyleAttribute(content, "visibility", "hidden");
 +        }
 +
 +        public void close() {
 +            DOM.setStyleAttribute(content, "visibility", "hidden");
 +            DOM.setStyleAttribute(content, "top", "-100000px");
 +            DOM.setStyleAttribute(content, "left", "-100000px");
 +            removeStyleDependentName("open");
 +            setHeight(-1);
 +            setWidth("");
 +            open = false;
 +        }
 +
 +        public boolean isOpen() {
 +            return open;
 +        }
 +
 +        public void setContent(UIDL contentUidl) {
 +            final ComponentConnector newPntbl = client
 +                    .getPaintable(contentUidl);
 +            Widget newWidget = newPntbl.getWidget();
 +            if (getChildWidget() == null) {
 +                add(newWidget, content);
 +                widgets.add(newWidget);
 +            } else if (getChildWidget() != newWidget) {
 +                replaceWidget(newWidget);
 +            }
 +            if (contentUidl.getBooleanAttribute("cached")) {
 +                /*
 +                 * The size of a cached, relative sized component must be
 +                 * updated to report correct size.
 +                 */
 +                client.handleComponentRelativeSize(newPntbl.getWidget());
 +            }
 +            if (isOpen() && isDynamicHeight()) {
 +                setHeightFromWidget();
 +            }
 +        }
 +
 +        @Override
 +        public void onClick(ClickEvent event) {
 +            onSelectTab(this);
 +        }
 +
 +        public void updateCaption(UIDL uidl) {
 +            // TODO need to call this because the caption does not have an owner
 +            caption.updateCaptionWithoutOwner(
 +                    uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION),
 +                    uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED),
 +                    uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION),
 +                    uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE),
 +                    uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON));
 +        }
 +
 +        public int getWidgetWidth() {
 +            return DOM.getFirstChild(content).getOffsetWidth();
 +        }
 +
 +        public boolean contains(ComponentConnector p) {
 +            return (getChildWidget() == p.getWidget());
 +        }
 +
 +        public boolean isCaptionVisible() {
 +            return caption.isVisible();
 +        }
 +
 +    }
 +
 +    @Override
 +    protected void clearPaintables() {
 +        clear();
 +    }
 +
 +    boolean isDynamicWidth() {
 +        ComponentConnector paintable = ConnectorMap.get(client).getConnector(
 +                this);
 +        return paintable.isUndefinedWidth();
 +    }
 +
 +    boolean isDynamicHeight() {
 +        ComponentConnector paintable = ConnectorMap.get(client).getConnector(
 +                this);
 +        return paintable.isUndefinedHeight();
 +    }
 +
 +    @Override
 +    @SuppressWarnings("unchecked")
 +    protected Iterator<Widget> getWidgetIterator() {
 +        return widgets.iterator();
 +    }
 +
 +    @Override
 +    protected int getTabCount() {
 +        return getWidgetCount();
 +    }
 +
 +    @Override
 +    protected void removeTab(int index) {
 +        StackItem item = getStackItem(index);
 +        remove(item);
 +        touchScrollHandler.removeElement(item.getContainerElement());
 +    }
 +
 +    @Override
 +    protected ComponentConnector getTab(int index) {
 +        if (index < getWidgetCount()) {
 +            Widget w = getStackItem(index);
 +            return ConnectorMap.get(client).getConnector(w);
 +        }
 +
 +        return null;
 +    }
 +
 +    StackItem getStackItem(int index) {
 +        return (StackItem) getWidget(index);
 +    }
 +
 +}