import com.vaadin.demo.sampler.features.dates.DateResolution;
import com.vaadin.demo.sampler.features.form.FormBasic;
import com.vaadin.demo.sampler.features.layouts.ApplicationLayout;
+import com.vaadin.demo.sampler.features.layouts.CssLayouts;
import com.vaadin.demo.sampler.features.layouts.CustomLayouts;
import com.vaadin.demo.sampler.features.layouts.ExpandingComponent;
import com.vaadin.demo.sampler.features.layouts.GridLayoutBasic;
new ApplicationLayout(), //
new WebLayout(), //
new CustomLayouts(), //
+ new CssLayouts(),//
});
}
}
--- /dev/null
+package com.vaadin.demo.sampler.features.layouts;\r
+\r
+import com.vaadin.demo.sampler.APIResource;\r
+import com.vaadin.demo.sampler.Feature;\r
+import com.vaadin.demo.sampler.NamedExternalResource;\r
+import com.vaadin.ui.HorizontalLayout;\r
+import com.vaadin.ui.VerticalLayout;\r
+\r
+@SuppressWarnings("serial")\r
+public class CssLayouts extends Feature {\r
+\r
+ @Override\r
+ public String getName() {\r
+ return "Css layout";\r
+ }\r
+\r
+ @Override\r
+ public String getDescription() {\r
+ // TODO\r
+ return "Most commonly developers usign Vaadin don't want to think "\r
+ + "of the browser environment at all. With the flexible "\r
+ + "layout API found from grid, horizontal and vertical "\r
+ + "layout developers can build almost anything with plain "\r
+ + "Java. But sometimes experienced web developers miss "\r
+ + "flexibility of CSS and HTML. CssLayout is a simple "\r
+ + "layout that puts contained componets into div element. "\r
+ + "It has a simple DOM structure and it leaves all the power "\r
+ + "to CSS designer hands. Having a very narrow feature set"\r
+ + ", CssLayout is also the fastest layout to render in "\r
+ + "Vaadin.";\r
+ }\r
+\r
+ @Override\r
+ public APIResource[] getRelatedAPI() {\r
+ return new APIResource[] { new APIResource(HorizontalLayout.class),\r
+ new APIResource(VerticalLayout.class) };\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public Class<? extends Feature>[] getRelatedFeatures() {\r
+ return new Class[] { ApplicationLayout.class, CustomLayouts.class };\r
+ }\r
+\r
+ @Override\r
+ public NamedExternalResource[] getRelatedResources() {\r
+ return null;\r
+ }\r
+}\r
--- /dev/null
+package com.vaadin.demo.sampler.features.layouts;\r
+\r
+import com.vaadin.ui.Component;\r
+import com.vaadin.ui.CssLayout;\r
+import com.vaadin.ui.Label;\r
+import com.vaadin.ui.Panel;\r
+import com.vaadin.ui.VerticalLayout;\r
+\r
+@SuppressWarnings("serial")\r
+public class CssLayoutsExample extends VerticalLayout {\r
+\r
+ public CssLayoutsExample() {\r
+ setMargin(true);\r
+\r
+ /*\r
+ * Note that adding inline style like this is a very bad programming\r
+ * habit in common. The correct place for css is in theme. We do it here\r
+ * to keep css in java code for demonstration purposes.\r
+ */\r
+ Label demostyle = new Label(\r
+ "<style>"\r
+ + ".floatedpanel {float:right;} "\r
+ + ".footer {width: 3in; padding: 3px;margin-left:auto;margin-right:auto;"\r
+ + "clear:both; height:40px; background-color: grey; white-space:normal;} "\r
+ + ".brick {text-align:center;width: 100px; height: 100px; margin: 10px;padding:10px;"\r
+ + "background-color:#1E2123; color:white;float:left; border: 3px solid black;} "\r
+ + "</style>", Label.CONTENT_XHTML);\r
+\r
+ addComponent(demostyle);\r
+\r
+ final Panel panel = new Panel("Panel");\r
+ panel.setStyleName("floatedpanel");\r
+ panel.setWidth("30%");\r
+ panel.setHeight("370px");\r
+ panel.addComponent(new Label("This panel is 30% width "\r
+ + "and 370px height(defined on server side) "\r
+ + "and floated right (with custom css). "\r
+ + "Try resizesing browser window to see "\r
+ + "how black boxes (floated to left) "\r
+ + "behave. Every third of them has red "\r
+ + "color to demonstrate dynamic css injection. "));\r
+\r
+ final Label bottomCenter = new Label(\r
+ "I'm 3 inches wide footer at the bottom "\r
+ + "of the layout (and centered unless I'm in IE6)");\r
+ bottomCenter.setSizeUndefined(); // disable 100% default width\r
+ bottomCenter.setStyleName("footer");\r
+ // bottomCenter.setWidth("50px");\r
+\r
+ CssLayout cssLayout = new CssLayout() {\r
+ int brickCounter = 0;\r
+\r
+ @Override\r
+ protected String getCss(Component c) {\r
+ // colorize every third rendered brick\r
+ if (c instanceof Brick) {\r
+ brickCounter++;\r
+ if (brickCounter % 3 == 0) {\r
+ // make every third brick red and bold\r
+ return "color: #ff6611; font-weight:bold;";\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ };\r
+\r
+ cssLayout.setWidth("100%");\r
+\r
+ cssLayout.addComponent(panel);\r
+ for (int i = 0; i < 15; i++) {\r
+ // add black labels that float left\r
+ cssLayout.addComponent(new Brick());\r
+ }\r
+ cssLayout.addComponent(bottomCenter);\r
+\r
+ addComponent(cssLayout);\r
+ }\r
+\r
+ /**\r
+ * A simple label containing text "Brick" and themed black square.\r
+ */\r
+ static class Brick extends Label {\r
+ public Brick() {\r
+ super("Brick");\r
+ // disable 100% that label has by default\r
+ setSizeUndefined();\r
+ setStyleName("brick");\r
+ }\r
+ }\r
+\r
+}
\ No newline at end of file
import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
import com.vaadin.terminal.gwt.client.ui.VEmbedded;
import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
+import com.vaadin.terminal.gwt.client.ui.VCssLayout;
import com.vaadin.terminal.gwt.client.ui.VForm;
import com.vaadin.terminal.gwt.client.ui.VFormLayout;
import com.vaadin.terminal.gwt.client.ui.VGridLayout;
return new VUriFragmentUtility();
} else if (VAbsoluteLayout.class == classType) {
return new VAbsoluteLayout();
+ } else if (VCssLayout.class == classType) {
+ return new VCssLayout();
}
return new VUnknownComponent();
return VUriFragmentUtility.class;
} else if (VAbsoluteLayout.TAGNAME.equals(tag)) {
return VAbsoluteLayout.class;
+ } else if (VCssLayout.TAGNAME.equals(tag)) {
+ return VCssLayout.class;
}
return VUnknownComponent.class;
--- /dev/null
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.StyleConstants;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.ValueMap;
+
+public class VCssLayout extends SimplePanel implements Paintable, Container {
+ public static final String TAGNAME = "csslayout";
+ public static final String CLASSNAME = "v-" + TAGNAME;
+
+ private FlowPane panel = new FlowPane();
+
+ private Element margin = DOM.createDiv();
+
+ private boolean hasHeight;
+ private boolean hasWidth;
+
+ public VCssLayout() {
+ super();
+ DOM.appendChild(getElement(), margin);
+ DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+ setStyleName(CLASSNAME);
+ setWidget(panel);
+ }
+
+ @Override
+ protected Element getContainerElement() {
+ return margin;
+ }
+
+ @Override
+ public void setWidth(String width) {
+ super.setWidth(width);
+ panel.setWidth(width);
+ hasWidth = width != null && !width.equals("");
+ }
+
+ @Override
+ public void setHeight(String height) {
+ super.setHeight(height);
+ panel.setHeight(height);
+ hasHeight = height != null && !height.equals("");
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ final VMarginInfo margins = new VMarginInfo(uidl
+ .getIntAttribute("margins"));
+
+ setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
+ margins.hasTop());
+ setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
+ margins.hasRight());
+ setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM,
+ margins.hasBottom());
+ setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
+ margins.hasLeft());
+
+ setStyleName(margin, CLASSNAME + "-" + "spacing", uidl
+ .hasAttribute("spacing"));
+ panel.updateFromUIDL(uidl, client);
+ }
+
+ public boolean hasChildComponent(Widget component) {
+ return panel.hasChildComponent(component);
+ }
+
+ public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+ panel.replaceChildComponent(oldComponent, newComponent);
+ }
+
+ public void updateCaption(Paintable component, UIDL uidl) {
+ panel.updateCaption(component, uidl);
+ }
+
+ public class FlowPane extends FlowPanel {
+
+ private final HashMap<Widget, VCaption> widgetToCaption = new HashMap<Widget, VCaption>();
+ private ApplicationConnection client;
+
+ public FlowPane() {
+ super();
+ setStyleName(CLASSNAME + "-grid");
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ // for later requests
+ this.client = client;
+
+ final ArrayList<Widget> oldWidgets = new ArrayList<Widget>();
+ for (final Iterator<Widget> iterator = iterator(); iterator
+ .hasNext();) {
+ oldWidgets.add(iterator.next());
+ }
+ clear();
+
+ ValueMap mapAttribute = null;
+ if (uidl.hasAttribute("css")) {
+ mapAttribute = uidl.getMapAttribute("css");
+ }
+
+ for (final Iterator<Object> i = uidl.getChildIterator(); i
+ .hasNext();) {
+ final UIDL r = (UIDL) i.next();
+ final Paintable child = client.getPaintable(r);
+ if (oldWidgets.contains(child)) {
+ oldWidgets.remove(child);
+ }
+
+ add((Widget) child);
+ if (mapAttribute != null && mapAttribute.containsKey(r.getId())) {
+ String css = null;
+ try {
+ Style style = ((Widget) child).getElement().getStyle();
+ css = mapAttribute.getString(r.getId());
+ String[] cssRules = css.split(";");
+ for (int j = 0; j < cssRules.length; j++) {
+ String[] rule = cssRules[j].split(":");
+ if (rule.length == 0) {
+ continue;
+ } else {
+ style.setProperty(
+ makeCamelCase(rule[0].trim()), rule[1]
+ .trim());
+ }
+ }
+ } catch (Exception e) {
+ ApplicationConnection.getConsole().log(
+ "CssLayout encounterd invalid css string: "
+ + css);
+ }
+ }
+
+ if (!r.getBooleanAttribute("cached")) {
+ child.updateFromUIDL(r, client);
+ }
+ }
+
+ // loop oldWidgetWrappers that where not re-attached and unregister
+ // them
+ for (final Iterator<Widget> it = oldWidgets.iterator(); it
+ .hasNext();) {
+ final Paintable w = (Paintable) it.next();
+ client.unregisterPaintable(w);
+ widgetToCaption.remove(w);
+ }
+ }
+
+ public boolean hasChildComponent(Widget component) {
+ return component.getParent() == this;
+ }
+
+ public void replaceChildComponent(Widget oldComponent,
+ Widget newComponent) {
+ VCaption caption = widgetToCaption.get(oldComponent);
+ if (caption != null) {
+ remove(caption);
+ widgetToCaption.remove(oldComponent);
+ }
+ int index = getWidgetIndex(oldComponent);
+ if (index >= 0) {
+ remove(oldComponent);
+ insert(newComponent, index);
+ }
+ }
+
+ public void updateCaption(Paintable component, UIDL uidl) {
+ VCaption caption = widgetToCaption.get(component);
+ if (VCaption.isNeeded(uidl)) {
+ Widget widget = (Widget) component;
+ if (caption == null) {
+ caption = new VCaption(component, client);
+ widgetToCaption.put(widget, caption);
+ insert(caption, getWidgetIndex(widget));
+ } else if (!caption.isAttached()) {
+ insert(caption, getWidgetIndex(widget));
+ }
+ caption.updateCaption(uidl);
+ } else if (caption != null) {
+ remove(caption);
+ widgetToCaption.remove(component);
+ }
+ }
+ }
+
+ public RenderSpace getAllocatedSpace(Widget child) {
+ com.google.gwt.dom.client.Element div = child.getElement()
+ .getParentElement();
+ return new RenderSpace(div.getOffsetWidth(), div.getOffsetHeight());
+ }
+
+ public boolean requestLayout(Set<Paintable> children) {
+ if (hasSize()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private boolean hasSize() {
+ return hasWidth || hasHeight;
+ }
+
+ private static final String makeCamelCase(String cssProperty) {
+ // TODO this might be cleaner to implement with regexp
+ while (cssProperty.contains("-")) {
+ int indexOf = cssProperty.indexOf("-");
+ cssProperty = cssProperty.substring(0, indexOf)
+ + String.valueOf(cssProperty.charAt(indexOf + 1))
+ .toUpperCase() + cssProperty.substring(indexOf + 2);
+ }
+ return cssProperty;
+ }
+}
--- /dev/null
+package com.vaadin.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Paintable;
+import com.vaadin.terminal.gwt.client.ui.VCssLayout;
+
+/**
+ * CssLayout is a layout component that can be used in browser environment only.
+ * It simply renders components and their captions into a same div element.
+ * Component layout can then be adjusted with css.
+ * <p>
+ * In comparison to {@link HorizontalLayout} and {@link VerticalLayout}
+ * <ul>
+ * <li>rather similar server side api
+ * <li>no spacing, alignment or expand ratios
+ * <li>much simpler DOM that can be styled by skilled web developer
+ * <li>no abstraction of browser differences (developer must ensure that the
+ * result works properly on each browser)
+ * <li>different kind of handling for relative sizes (that are set from server
+ * side) (*)
+ * <li>noticeable faster rendering time in some situations as we rely more on
+ * browsers rendering engine.
+ * </ul>
+ *<p>
+ * With {@link CustomLayout} one can often achieve similar results (good looking
+ * layouts with web technologies), but with CustomLayout developer needs to work
+ * with fixed templates.
+ * <p>
+ * By extending CssLayout one can also inject some css rules straight to child
+ * components using {@link #getCss(Component)}.
+ *
+ * <p>
+ * (*) Relative sizes (set from server side) are treated bit differently than in
+ * other layouts in Vaadin. In cssLayout the size is calculated relatively to
+ * CSS layouts content area which is pretty much as in html and css. In other
+ * layouts the size of component is calculated relatively to the "slot" given by
+ * layout.
+ * <p>
+ * Also note that client side framework in Vaadin modifies inline style
+ * properties width and height. This happens on each update to component. If one
+ * wants to set component sizes with CSS, component must have undefined size on
+ * server side (which is not the default for all components) and the size must
+ * be defined with class styles - not by directly injecting width and height.
+ *
+ * @since 6.1 brought in from "FastLayouts" incubator project
+ *
+ */
+public class CssLayout extends AbstractLayout {
+
+ private static final long serialVersionUID = -6408703812053460073L;
+
+ @Override
+ public String getTag() {
+ return VCssLayout.TAGNAME;
+ }
+
+ /**
+ * Custom layout slots containing the components.
+ */
+ protected LinkedList<Component> components = new LinkedList<Component>();
+
+ /**
+ * Add a component into this container. The component is added to the right
+ * or under the previous component.
+ *
+ * @param c
+ * the component to be added.
+ */
+ @Override
+ public void addComponent(Component c) {
+ super.addComponent(c);
+ components.add(c);
+ requestRepaint();
+ }
+
+ /**
+ * Adds a component into this container. The component is added to the left
+ * or on top of the other components.
+ *
+ * @param c
+ * the component to be added.
+ */
+ public void addComponentAsFirst(Component c) {
+ super.addComponent(c);
+ components.addFirst(c);
+ requestRepaint();
+ }
+
+ /**
+ * Adds a component into indexed position in this container.
+ *
+ * @param c
+ * the component to be added.
+ * @param index
+ * the Index of the component position. The components currently
+ * in and after the position are shifted forwards.
+ */
+ public void addComponent(Component c, int index) {
+ super.addComponent(c);
+ components.add(index, c);
+ requestRepaint();
+ }
+
+ /**
+ * Removes the component from this container.
+ *
+ * @param c
+ * the component to be removed.
+ */
+ @Override
+ public void removeComponent(Component c) {
+ super.removeComponent(c);
+ components.remove(c);
+ requestRepaint();
+ }
+
+ /**
+ * Gets the component container iterator for going trough all the components
+ * in the container.
+ *
+ * @return the Iterator of the components inside the container.
+ */
+ public Iterator getComponentIterator() {
+ return components.iterator();
+ }
+
+ /**
+ * Paints the content of this component.
+ *
+ * @param target
+ * the Paint Event.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ HashMap<Paintable, String> componentCss = null;
+ // Adds all items in all the locations
+ for (Component c : components) {
+ // Paint child component UIDL
+ c.paint(target);
+ String componentCssString = getCss(c);
+ if (componentCssString != null) {
+ if (componentCss == null) {
+ componentCss = new HashMap<Paintable, String>();
+ }
+ componentCss.put(c, componentCssString);
+ }
+ }
+ if (componentCss != null) {
+ target.addAttribute("css", componentCss);
+ }
+ }
+
+ /**
+ * Returns styles to be applied to given component. Override this method to
+ * inject custom style rules to components.
+ *
+ * <p>
+ * Note that styles are injected over previous styles before actual child
+ * rendering. Previous styles are not cleared, but overridden.
+ *
+ * <p>
+ * Note that one most often achieves better code style, by separating
+ * styling to theme (with custom theme and {@link #addStyleName(String)}.
+ * With own custom styles it is also very easy to break browser
+ * compatibility.
+ *
+ * @param c
+ * the component
+ * @return css rules to be applied to component
+ */
+ protected String getCss(Component c) {
+ return null;
+ }
+
+ /* Documented in superclass */
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+
+ // Gets the locations
+ int oldLocation = -1;
+ int newLocation = -1;
+ int location = 0;
+ for (final Iterator i = components.iterator(); i.hasNext();) {
+ final Component component = (Component) i.next();
+
+ if (component == oldComponent) {
+ oldLocation = location;
+ }
+ if (component == newComponent) {
+ newLocation = location;
+ }
+
+ location++;
+ }
+
+ if (oldLocation == -1) {
+ addComponent(newComponent);
+ } else if (newLocation == -1) {
+ removeComponent(oldComponent);
+ addComponent(newComponent, oldLocation);
+ } else {
+ if (oldLocation > newLocation) {
+ components.remove(oldComponent);
+ components.add(newLocation, oldComponent);
+ components.remove(newComponent);
+ components.add(oldLocation, newComponent);
+ } else {
+ components.remove(newComponent);
+ components.add(oldLocation, newComponent);
+ components.remove(oldComponent);
+ components.add(newLocation, oldComponent);
+ }
+
+ requestRepaint();
+ }
+ }
+
+}