]> source.dussan.org Git - vaadin-framework.git/commitdiff
New component: Accordion. Doesn't support sizing properly yet (only width).
authorJouni Koivuviita <jouni.koivuviita@itmill.com>
Fri, 14 Dec 2007 13:38:16 +0000 (13:38 +0000)
committerJouni Koivuviita <jouni.koivuviita@itmill.com>
Fri, 14 Dec 2007 13:38:16 +0000 (13:38 +0000)
-ITabsheet refactored: new superclass for different kinds of tabs, ITabsheetBase. Use this when you want to create some sort of tabbable component.

svn changeset:3242/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/DefaultWidgetSetNoEntry.gwt.xml
src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/public/default/accordion/accordion.css [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/collapsed-icon.png [new file with mode: 0755]
src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/expanded-icon.png [new file with mode: 0755]
src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/selected-bg.png [new file with mode: 0755]
src/com/itmill/toolkit/ui/Accordion.java [new file with mode: 0644]
src/com/itmill/toolkit/ui/OrderedLayout.java

index 29c26697706ea9eb015d65262c0a855b5f6a38f5..82b848b129ce7bddff35d67cfd0a6fc8133b9408 100644 (file)
@@ -41,5 +41,6 @@
        <stylesheet src="default/progressindicator/progressindicator.css"/>
        <stylesheet src="default/expandlayout/expandlayout.css"/>
        <stylesheet src="default/orderedlayout/orderedlayout.css"/>
+       <stylesheet src="default/accordion/accordion.css"/>
 
 </module>
index b846a50c17afd6462d5dde4ca9cf5a40bafdbeca..b3ee13f7a34e145cdbf9a392b9508ec92ec741ec 100644 (file)
@@ -6,6 +6,7 @@ package com.itmill.toolkit.terminal.gwt.client;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.IAccordion;
 import com.itmill.toolkit.terminal.gwt.client.ui.IButton;
 import com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox;
 import com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout;
@@ -166,6 +167,9 @@ public class DefaultWidgetSet implements WidgetSet {
         } else if ("com.itmill.toolkit.terminal.gwt.client.ui.richtextarea.IRichTextArea"
                 .equals(className)) {
             return new IRichTextArea();
+        } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IAccordion"
+                .equals(className)) {
+            return new IAccordion();
         }
 
         return new IUnknownComponent();
@@ -229,6 +233,8 @@ public class DefaultWidgetSet implements WidgetSet {
             return "com.itmill.toolkit.terminal.gwt.client.ui.IPanel";
         } else if ("tabsheet".equals(tag)) {
             return "com.itmill.toolkit.terminal.gwt.client.ui.ITabsheet";
+        } else if ("accordion".equals(tag)) {
+            return "com.itmill.toolkit.terminal.gwt.client.ui.IAccordion";
         } else if ("embedded".equals(tag)) {
             return "com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded";
         } else if ("customlayout".equals(tag)) {
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java
new file mode 100644 (file)
index 0000000..c47ac52
--- /dev/null
@@ -0,0 +1,222 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+import com.itmill.toolkit.terminal.gwt.client.Util;
+
+public class IAccordion extends ITabsheetBase implements
+        ContainerResizedListener {
+
+    public static final String CLASSNAME = "i-accordion";
+
+    private ArrayList stack;
+
+    private String height;
+
+    public IAccordion() {
+        super(CLASSNAME);
+        stack = new ArrayList();
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        super.updateFromUIDL(uidl, client);
+
+        iLayout();
+    }
+
+    public void clear() {
+        super.clear();
+        stack.clear();
+    }
+
+    private StackItem getSelectedStack() {
+        return (StackItem) stack.get(activeTabIndex);
+    }
+
+    protected void renderTab(UIDL contentUidl, String caption, int index,
+            boolean selected) {
+        // TODO check indexes, now new tabs get placed last (changing tab order
+        // is not supported from server-side)
+        StackItem item = new StackItem(caption);
+        if (selected) {
+            item.setContent(new StackContent(contentUidl));
+            item.open();
+        } else {
+            item.setContent(new StackContent());
+        }
+
+        if (stack.size() == 0) {
+            item.addStyleDependentName("first");
+        }
+
+        stack.add(item);
+        add(item);
+    }
+
+    protected void selectTab(final int index, final UIDL contentUidl) {
+        if (index != activeTabIndex) {
+            activeTabIndex = index;
+            StackItem item = (StackItem) stack.get(index);
+            item.setContent(new StackContent(contentUidl));
+            item.open();
+        }
+    }
+
+    public void onSelectTab(StackItem item) {
+        final int index = stack.indexOf(item);
+        if (index != activeTabIndex && !disabled && !readonly) {
+            getSelectedStack().close();
+            addStyleDependentName("loading");
+            // run updating variables in deferred command to bypass some FF
+            // optimization issues
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    client.updateVariable(id, "selected", ""
+                            + tabKeys.get(index), true);
+                }
+            });
+        }
+    }
+
+    public void setWidth(String width) {
+        if (width.equals("100%")) {
+            super.setWidth("");
+        } else {
+            super.setWidth(width);
+        }
+    }
+
+    public void setHeight(String height) {
+        this.height = height;
+    }
+
+    public void iLayout() {
+        if (height != null && height != "") {
+            // TODO
+        } else {
+            // getVisibleContent().getContent().setHeight("");
+        }
+        Util.runDescendentsLayout(this);
+    }
+
+    protected class StackItem extends Widget {
+
+        private String caption;
+        private Element captionNode;
+        private boolean open = false;
+        private StackContent content;
+
+        protected StackItem() {
+            setElement(DOM.createDiv());
+            captionNode = DOM.createDiv();
+            // Additional SPAN element for styling
+            DOM.appendChild(captionNode, DOM.createSpan());
+            DOM.appendChild(getElement(), captionNode);
+            setStylePrimaryName(CLASSNAME + "-item");
+            DOM.setElementProperty(captionNode, "className", CLASSNAME
+                    + "-item-caption");
+            sinkEvents(Event.ONCLICK);
+        }
+
+        public StackItem(String caption) {
+            this();
+            setCaption(caption);
+        }
+
+        public StackItem(String caption, UIDL contentUidl) {
+            this();
+            setCaption(caption);
+            setContent(new StackContent(contentUidl));
+        }
+
+        public void setCaption(String caption) {
+            this.caption = caption;
+            DOM.setInnerText(DOM.getFirstChild(captionNode), caption);
+        }
+
+        public String getCaption() {
+            return caption;
+        }
+
+        public void open() {
+            open = true;
+            content.show();
+            addStyleDependentName("open");
+        }
+
+        public void close() {
+            open = false;
+            content.hide();
+            removeStyleDependentName("open");
+        }
+
+        public boolean isOpen() {
+            return open;
+        }
+
+        public StackContent getContent() {
+            return content;
+        }
+
+        public void setContent(StackContent content) {
+            if (this.content != null) {
+                // Remove old content
+                DOM.removeChild(getElement(), getContent().getElement());
+            }
+            this.content = content;
+            DOM.appendChild(getElement(), getContent().getElement());
+        }
+
+        public void onBrowserEvent(Event evt) {
+            if (DOM.eventGetType(evt) == Event.ONCLICK) {
+                Element target = DOM.eventGetTarget(evt);
+                if (DOM.compare(target, captionNode)
+                        || DOM.compare(target, DOM.getFirstChild(captionNode))) {
+                    ((IAccordion) getParent()).onSelectTab(this);
+                }
+            }
+        }
+
+    }
+
+    protected class StackContent extends UIObject {
+
+        protected StackContent() {
+            setElement(DOM.createDiv());
+            setVisible(false);
+            setStyleName(CLASSNAME + "-item-content");
+        }
+
+        protected StackContent(UIDL contentUidl) {
+            this();
+            renderContent(contentUidl);
+        }
+
+        public void show() {
+            setVisible(true);
+        }
+
+        public void hide() {
+            setVisible(false);
+        }
+
+        private void renderContent(UIDL contentUidl) {
+            final Paintable content = client.getPaintable(contentUidl);
+            DOM.appendChild(getElement(), ((Widget) content).getElement());
+            (content).updateFromUIDL(contentUidl, client);
+        }
+
+    }
+
+}
index 771082a15c04ae495d8e053aac4cdf1a702e74f9..847980e1d6224effa1183f8a11bee45eedf19a54 100644 (file)
@@ -4,14 +4,11 @@
 
 package com.itmill.toolkit.terminal.gwt.client.ui;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.SourcesTabEvents;
 import com.google.gwt.user.client.ui.TabBar;
 import com.google.gwt.user.client.ui.TabListener;
@@ -22,21 +19,16 @@ import com.itmill.toolkit.terminal.gwt.client.Paintable;
 import com.itmill.toolkit.terminal.gwt.client.UIDL;
 import com.itmill.toolkit.terminal.gwt.client.Util;
 
-public class ITabsheet extends FlowPanel implements Paintable,
+public class ITabsheet extends ITabsheetBase implements
         ContainerResizedListener {
 
     public static final String CLASSNAME = "i-tabsheet";
 
-    String id;
-    ApplicationConnection client;
-
-    private final ArrayList tabKeys = new ArrayList();
-    private final ArrayList captions = new ArrayList();
-    int activeTabIndex = 0;
     private final TabBar tb;
     private final ITabsheetPanel tp;
     private final Element contentNode, deco;
-    private boolean disabled;
+
+    private String height;
 
     private final TabListener tl = new TabListener() {
 
@@ -63,10 +55,8 @@ public class ITabsheet extends FlowPanel implements Paintable,
 
     };
 
-    private String height;
-
     public ITabsheet() {
-        setStyleName(CLASSNAME);
+        super(CLASSNAME);
 
         tb = new TabBar();
         tp = new ITabsheetPanel();
@@ -87,7 +77,7 @@ public class ITabsheet extends FlowPanel implements Paintable,
 
         tb.addTabListener(tl);
 
-        clearTabs();
+        clear();
 
         // TODO Use for Safari only. Fix annoying 1px first cell in TabBar.
         DOM.setStyleAttribute(DOM.getFirstChild(DOM.getFirstChild(DOM
@@ -95,16 +85,10 @@ public class ITabsheet extends FlowPanel implements Paintable,
     }
 
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        id = uidl.getId();
+        super.updateFromUIDL(uidl, client);
 
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        disabled = uidl.hasAttribute("disabled");
-
-        // Add proper stylenames for all elements
+        // Add proper stylenames for all elements (easier to prevent unwanted
+        // style inheritance)
         if (uidl.hasAttribute("style")) {
             final String[] styles = uidl.getStringAttribute("style").split(" ");
             final String contentBaseClass = "CLASSNAME" + "-content";
@@ -125,74 +109,26 @@ public class ITabsheet extends FlowPanel implements Paintable,
             DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
         }
 
-        // Adjust width and height
-        if (uidl.hasAttribute("height")) {
-            setHeight(uidl.getStringAttribute("height"));
-        } else {
-            setHeight("");
-        }
-        if (uidl.hasAttribute("width")) {
-            setWidth(uidl.getStringAttribute("width"));
-        } else {
-            setWidth("");
-        }
+    }
 
-        // Render content
-        final UIDL tabs = uidl.getChildUIDL(0);
-        boolean keepCurrentTabs = tabKeys.size() == tabs.getNumberOfChildren();
-        for (int i = 0; keepCurrentTabs && i < tabKeys.size(); i++) {
-            keepCurrentTabs = tabKeys.get(i).equals(
-                    tabs.getChildUIDL(i).getStringAttribute("key"))
-                    && captions.get(i).equals(
-                            tabs.getChildUIDL(i).getStringAttribute("caption"));
-        }
-        if (keepCurrentTabs) {
-            int index = 0;
-            for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
-                final UIDL tab = (UIDL) it.next();
-                if (tab.getBooleanAttribute("selected")) {
-                    activeTabIndex = index;
-                    renderContent(tab.getChildUIDL(0));
-                }
-                index++;
-            }
-        } else {
-            tabKeys.clear();
-            captions.clear();
-            clearTabs();
-
-            int index = 0;
-            for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
-                final UIDL tab = (UIDL) it.next();
-                final String key = tab.getStringAttribute("key");
-                String caption = tab.getStringAttribute("caption");
-                if (caption == null) {
-                    caption = "&nbsp;";
-                }
-
-                captions.add(caption);
-                tabKeys.add(key);
-
-                // Add new tab (additional SPAN-element for loading indication)
-                tb.insertTab("<span>" + caption + "</span>", true, tb
-                        .getTabCount());
-
-                // Add placeholder content
-                tp.add(new ILabel(""));
-
-                if (tab.getBooleanAttribute("selected")) {
-                    activeTabIndex = index;
-                    renderContent(tab.getChildUIDL(0));
-                }
-                index++;
-            }
+    protected void renderTab(final UIDL contentUidl, String caption, int index,
+            boolean selected) {
+        // TODO check indexes, now new tabs get placed last (changing tab order
+        // is not supported from server-side)
+        tb.addTab(caption);
+        if (selected) {
+            renderContent(contentUidl);
+            tb.selectTab(index);
         }
+        // Add place-holder content
+        tp.add(new Label(""));
+    }
 
-        // Open selected tab, if there's something to show
-        if (tabKeys.size() > 0) {
-            tb.selectTab(activeTabIndex);
+    protected void selectTab(int index, final UIDL contentUidl) {
+        if (index != activeTabIndex) {
+            activeTabIndex = index;
+            renderContent(contentUidl);
         }
-
     }
 
     private void renderContent(final UIDL contentUIDL) {
@@ -207,10 +143,9 @@ public class ITabsheet extends FlowPanel implements Paintable,
                 ITabsheet.this.iLayout();
             }
         });
-
     }
 
-    private void clearTabs() {
+    public void clear() {
         int i = tb.getTabCount();
         while (i > 0) {
             tb.removeTab(--i);
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java
new file mode 100644 (file)
index 0000000..c3cf0e6
--- /dev/null
@@ -0,0 +1,118 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+
+abstract class ITabsheetBase extends FlowPanel implements Paintable {
+
+    String id;
+    ApplicationConnection client;
+
+    protected final ArrayList tabKeys = new ArrayList();
+    protected final ArrayList captions = new ArrayList();
+    protected int activeTabIndex = 0;
+    protected boolean disabled;
+    protected boolean readonly;
+
+    public ITabsheetBase(String classname) {
+        setStylePrimaryName(classname);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        // Ensure correct implementation and let ApplicationConnection handle
+        // component caption
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        // Update member references
+        this.client = client;
+        id = uidl.getId();
+        disabled = uidl.hasAttribute("disabled");
+
+        // Adjust width and height
+        if (uidl.hasAttribute("height")) {
+            setHeight(uidl.getStringAttribute("height"));
+        } else {
+            setHeight("");
+        }
+        if (uidl.hasAttribute("width")) {
+            setWidth(uidl.getStringAttribute("width"));
+        } else {
+            setWidth("");
+        }
+
+        // Render content
+        final UIDL tabs = uidl.getChildUIDL(0);
+        if (keepCurrentTabs(uidl)) {
+            int index = 0;
+            for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
+                final UIDL tab = (UIDL) it.next();
+                final boolean selected = tab.getBooleanAttribute("selected");
+                if (selected) {
+                    selectTab(index, tab.getChildUIDL(0));
+                }
+                index++;
+            }
+        } else {
+            // Clear previous values
+            tabKeys.clear();
+            captions.clear();
+            clear();
+
+            int index = 0;
+            for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
+                final UIDL tab = (UIDL) it.next();
+                final String key = tab.getStringAttribute("key");
+                final boolean selected = tab.getBooleanAttribute("selected");
+                String caption = tab.getStringAttribute("caption");
+                if (caption == null) {
+                    caption = "&nbsp;";
+                }
+
+                captions.add(caption);
+                tabKeys.add(key);
+
+                if (selected) {
+                    activeTabIndex = index;
+                }
+                renderTab(tab.getChildUIDL(0), caption, index, selected);
+                index++;
+            }
+        }
+
+    }
+
+    protected boolean keepCurrentTabs(UIDL uidl) {
+        final UIDL tabs = uidl.getChildUIDL(0);
+        boolean retval = tabKeys.size() == tabs.getNumberOfChildren();
+        for (int i = 0; retval && i < tabKeys.size(); i++) {
+            retval = tabKeys.get(i).equals(
+                    tabs.getChildUIDL(i).getStringAttribute("key"))
+                    && captions.get(i).equals(
+                            tabs.getChildUIDL(i).getStringAttribute("caption"));
+        }
+        return retval;
+    }
+
+    /*
+     * Implement in extending classes. This method should render needed elements
+     * and set the visibility of the tab according to the 'selected' parameter.
+     */
+    protected abstract void renderTab(final UIDL contentUidl, String caption,
+            int index, boolean selected);
+
+    /*
+     * Implement in extending classes. This method should render any previously
+     * non-cached content and set the activeTabIndex property to the specified
+     * index.
+     */
+    protected abstract void selectTab(int index, final UIDL contentUidl);
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/accordion.css b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/accordion.css
new file mode 100644 (file)
index 0000000..fd5f752
--- /dev/null
@@ -0,0 +1,35 @@
+.i-accordion {
+       outline: none;
+       border-bottom: 1px solid #c8cccd;
+}
+
+.i-accordion-item-caption {
+       height: 25px;
+       padding: 6px 0 0 18px;
+       overflow: hidden;
+       white-space: nowrap;
+       background: #edf0f0 url(../tabsheet/img/tab-bg.png);
+       font-size: 15px;
+       color: #656d73;
+       border-top: 1px solid #c8cccd;
+}
+
+.i-accordion-item-caption span {
+       padding-left: 16px;
+       background: transparent url(img/collapsed-icon.png) no-repeat 0 50%;
+}
+
+.i-accordion-item-open .i-accordion-item-caption {
+       color: #3b4b57;
+       background: #d5dee2 url(img/selected-bg.png);
+       border-top-color: #cbd7de;
+       border-bottom-color: #bfc9d4;
+}
+
+.i-accordion-item-open .i-accordion-item-caption span {
+       background: transparent url(img/expanded-icon.png) no-repeat 0 55%;
+}
+
+.i-accordion-item-content {
+       border-top: 1px solid #c8cccd;
+}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/collapsed-icon.png b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/collapsed-icon.png
new file mode 100755 (executable)
index 0000000..1443459
Binary files /dev/null and b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/collapsed-icon.png differ
diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/expanded-icon.png b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/expanded-icon.png
new file mode 100755 (executable)
index 0000000..8a28fb8
Binary files /dev/null and b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/expanded-icon.png differ
diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/selected-bg.png b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/selected-bg.png
new file mode 100755 (executable)
index 0000000..99dca1c
Binary files /dev/null and b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/selected-bg.png differ
diff --git a/src/com/itmill/toolkit/ui/Accordion.java b/src/com/itmill/toolkit/ui/Accordion.java
new file mode 100644 (file)
index 0000000..4973303
--- /dev/null
@@ -0,0 +1,9 @@
+package com.itmill.toolkit.ui;
+
+public class Accordion extends TabSheet {
+    
+    public String getTag() {
+        return "accordion";
+    }
+
+}
index 7b2f1163001613814148b38b19ea4adfd3bfe3e1..55eac04fcef772aba7559dd9ec8649516d422f4f 100644 (file)
@@ -351,7 +351,7 @@ public class OrderedLayout extends AbstractLayout {
 
     /**
      * 
-     * @return true if spacing layout leaves space between components
+     * @return true if spacing, layout leaves space between components
      */
     public boolean isSpacingEnabled() {
         return spacing;