From 84301d07dac96f817c984c955130ccaebe9fa967 Mon Sep 17 00:00:00 2001 From: Jouni Koivuviita Date: Fri, 14 Dec 2007 13:38:16 +0000 Subject: [PATCH] New component: Accordion. Doesn't support sizing properly yet (only width). -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 --- .../gwt/DefaultWidgetSetNoEntry.gwt.xml | 1 + .../terminal/gwt/client/DefaultWidgetSet.java | 6 + .../terminal/gwt/client/ui/IAccordion.java | 222 ++++++++++++++++++ .../terminal/gwt/client/ui/ITabsheet.java | 117 ++------- .../terminal/gwt/client/ui/ITabsheetBase.java | 118 ++++++++++ .../public/default/accordion/accordion.css | 35 +++ .../default/accordion/img/collapsed-icon.png | Bin 0 -> 240 bytes .../default/accordion/img/expanded-icon.png | Bin 0 -> 253 bytes .../default/accordion/img/selected-bg.png | Bin 0 -> 265 bytes src/com/itmill/toolkit/ui/Accordion.java | 9 + src/com/itmill/toolkit/ui/OrderedLayout.java | 2 +- 11 files changed, 418 insertions(+), 92 deletions(-) create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java create mode 100644 src/com/itmill/toolkit/terminal/gwt/public/default/accordion/accordion.css create mode 100755 src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/collapsed-icon.png create mode 100755 src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/expanded-icon.png create mode 100755 src/com/itmill/toolkit/terminal/gwt/public/default/accordion/img/selected-bg.png create mode 100644 src/com/itmill/toolkit/ui/Accordion.java diff --git a/src/com/itmill/toolkit/terminal/gwt/DefaultWidgetSetNoEntry.gwt.xml b/src/com/itmill/toolkit/terminal/gwt/DefaultWidgetSetNoEntry.gwt.xml index 29c2669770..82b848b129 100644 --- a/src/com/itmill/toolkit/terminal/gwt/DefaultWidgetSetNoEntry.gwt.xml +++ b/src/com/itmill/toolkit/terminal/gwt/DefaultWidgetSetNoEntry.gwt.xml @@ -41,5 +41,6 @@ + diff --git a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java index b846a50c17..b3ee13f7a3 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java @@ -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 index 0000000000..c47ac52be9 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java @@ -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); + } + + } + +} diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java index 771082a15c..847980e1d6 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java @@ -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 = " "; - } - - captions.add(caption); - tabKeys.add(key); - - // Add new tab (additional SPAN-element for loading indication) - tb.insertTab("" + caption + "", 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 index 0000000000..c3cf0e6a56 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java @@ -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 = " "; + } + + 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 index 0000000000..fd5f752f02 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/public/default/accordion/accordion.css @@ -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 index 0000000000000000000000000000000000000000..1443459eb4c5bdee1b97c24154727b20df435dd3 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>3?#4ne^UZdEa{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i=)2l#}zepuS_>D=Dew=capzWr^L z=Z7WDpC8?Nvt{<%Dv!4d8{RIce-|wH|NsB@57y2FYT+#j@(TuX;ef&Rg;E<(!pzgf zF{I*F(u0Q&6O&nlY_E)M!3-oVE|jgj?r&v#yXe)`_4Stp-r&AfNx$?Lj(k9}7>xclst>AZXHOCKmsz5DMc3fv z?DF>5;pW%i+a|7^4jC(O%-s0Qi=jZS8+~w)s=j!+O_~PpB*5BhSU`==c001>fL_t(|+6=;l z5r9Ad03hu4?RNh)^}wwV337*7FOynL9<9cxbE%vLyG1ER;{DaOPk;dcHnsuLhutb) P00000NkvXXu0mjfgffT4 literal 0 HcmV?d00001 diff --git a/src/com/itmill/toolkit/ui/Accordion.java b/src/com/itmill/toolkit/ui/Accordion.java new file mode 100644 index 0000000000..4973303bfd --- /dev/null +++ b/src/com/itmill/toolkit/ui/Accordion.java @@ -0,0 +1,9 @@ +package com.itmill.toolkit.ui; + +public class Accordion extends TabSheet { + + public String getTag() { + return "accordion"; + } + +} diff --git a/src/com/itmill/toolkit/ui/OrderedLayout.java b/src/com/itmill/toolkit/ui/OrderedLayout.java index 7b2f116300..55eac04fce 100644 --- a/src/com/itmill/toolkit/ui/OrderedLayout.java +++ b/src/com/itmill/toolkit/ui/OrderedLayout.java @@ -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; -- 2.39.5