diff options
author | Jouni Koivuviita <jouni.koivuviita@itmill.com> | 2009-04-09 10:37:39 +0000 |
---|---|---|
committer | Jouni Koivuviita <jouni.koivuviita@itmill.com> | 2009-04-09 10:37:39 +0000 |
commit | 7e676a5e38016e70021b3a48e5e6e263783a5383 (patch) | |
tree | e0fbb10d845a52b05197b173107b8697a72ee84d | |
parent | 9e5e8f677bd01d53167c4587b5e29f0a8438e7b4 (diff) | |
download | vaadin-framework-7e676a5e38016e70021b3a48e5e6e263783a5383.tar.gz vaadin-framework-7e676a5e38016e70021b3a48e5e6e263783a5383.zip |
Merges from 6.0 branch.
svn changeset:7375/svn branch:theme_2009_03
9 files changed, 618 insertions, 12 deletions
diff --git a/WebContent/ITMILL/themes/default/absolutelayout/absolutelayout.css b/WebContent/ITMILL/themes/default/absolutelayout/absolutelayout.css new file mode 100644 index 0000000000..e77e380688 --- /dev/null +++ b/WebContent/ITMILL/themes/default/absolutelayout/absolutelayout.css @@ -0,0 +1,4 @@ +.i-absolutelayout-wrapper { + position: absolute; + overflow:hidden; +} diff --git a/WebContent/ITMILL/themes/tests-tickets/styles.css b/WebContent/ITMILL/themes/tests-tickets/styles.css index 225bbd6d1d..2c2b359ed9 100644 --- a/WebContent/ITMILL/themes/tests-tickets/styles.css +++ b/WebContent/ITMILL/themes/tests-tickets/styles.css @@ -1276,4 +1276,16 @@ padding:2px; .i-button-nowraplink span { white-space: normal; } + +.cyan { + background:cyan; +} +.yellow { + background:yellow; +} + +.green { + background:green; +} +
\ No newline at end of file diff --git a/src/com/itmill/toolkit/data/Validator.java b/src/com/itmill/toolkit/data/Validator.java index 0e09e3de6b..d0094914ed 100644 --- a/src/com/itmill/toolkit/data/Validator.java +++ b/src/com/itmill/toolkit/data/Validator.java @@ -17,6 +17,9 @@ import com.itmill.toolkit.terminal.PaintTarget; * {@link Validator.InvalidValueException} if the given value is not valid by * its standards. * + * Validators should not have side effects on other objects as they can be + * called from Paintable.paint(). + * * @author IT Mill Ltd. * @version * @VERSION@ diff --git a/src/com/itmill/toolkit/demo/sampler/features/commons/ValidationExample.java b/src/com/itmill/toolkit/demo/sampler/features/commons/ValidationExample.java index 75bacd5b10..19444045a9 100644 --- a/src/com/itmill/toolkit/demo/sampler/features/commons/ValidationExample.java +++ b/src/com/itmill/toolkit/demo/sampler/features/commons/ValidationExample.java @@ -46,17 +46,15 @@ public class ValidationExample extends VerticalLayout { throw new Validator.InvalidValueException("Username " + value + " already in use"); } - usernames.add(value); } }); username.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { TextField tf = (TextField) event.getProperty(); tf.validate(); - if (tf.isValid()) { - addComponent(new Label("Added " + tf.getValue() - + " to usernames")); - } + usernames.add(tf.getValue()); + addComponent(new Label("Added " + tf.getValue() + + " to usernames")); } }); diff --git a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java index e81f5fff47..0bc849affa 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java @@ -5,6 +5,7 @@ package com.itmill.toolkit.terminal.gwt.client; import com.google.gwt.user.client.ui.Widget; +import com.itmill.toolkit.terminal.gwt.client.ui.IAbsoluteLayout; 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; @@ -139,6 +140,8 @@ public class DefaultWidgetSet implements WidgetSet { return new IPopupView(); } else if (IUriFragmentUtility.class == classType) { return new IUriFragmentUtility(); + } else if (IAbsoluteLayout.class == classType) { + return new IAbsoluteLayout(); } return new IUnknownComponent(); @@ -249,6 +252,8 @@ public class DefaultWidgetSet implements WidgetSet { return IPopupView.class; } else if ("urifragment".equals(tag)) { return IUriFragmentUtility.class; + } else if (IAbsoluteLayout.TAGNAME.equals(tag)) { + return IAbsoluteLayout.class; } return IUnknownComponent.class; diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IAbsoluteLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAbsoluteLayout.java new file mode 100644 index 0000000000..fc1f14cb83 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAbsoluteLayout.java @@ -0,0 +1,320 @@ +package com.itmill.toolkit.terminal.gwt.client.ui; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +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.ComplexPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; +import com.itmill.toolkit.terminal.gwt.client.BrowserInfo; +import com.itmill.toolkit.terminal.gwt.client.Container; +import com.itmill.toolkit.terminal.gwt.client.Paintable; +import com.itmill.toolkit.terminal.gwt.client.RenderSpace; +import com.itmill.toolkit.terminal.gwt.client.UIDL; + +public class IAbsoluteLayout extends ComplexPanel implements Container { + + /** Tag name for widget creation */ + public static final String TAGNAME = "absolutelayout"; + + /** Class name, prefix in styling */ + public static final String CLASSNAME = "i-absolutelayout"; + + private DivElement marginElement; + + private Element canvas; + + private int excessPixelsHorizontal; + + private int excessPixelsVertical; + + private Object previousStyleName; + + private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>(); + + private ApplicationConnection client; + + private boolean rendering; + + public IAbsoluteLayout() { + setElement(Document.get().createDivElement()); + setStyleName(CLASSNAME); + marginElement = Document.get().createDivElement(); + canvas = DOM.createDiv(); + canvas.getStyle().setProperty("position", "relative"); + marginElement.appendChild(canvas); + getElement().appendChild(marginElement); + } + + public RenderSpace getAllocatedSpace(Widget child) { + // TODO needs some special handling for components with only on edge + // horizontally or vertically defined + AbsoluteWrapper wrapper = (AbsoluteWrapper) child.getParent(); + int w; + if (wrapper.left != null && wrapper.right != null) { + w = wrapper.getOffsetWidth(); + } else if (wrapper.right != null) { + // left == null + // available width == right edge == offsetleft + width + w = wrapper.getOffsetWidth() + wrapper.getElement().getOffsetLeft(); + } else { + // left != null && right == null || left == null && + // right == null + // available width == canvas width - offset left + w = canvas.getOffsetWidth() - wrapper.getElement().getOffsetLeft(); + } + int h; + if (wrapper.top != null && wrapper.bottom != null) { + h = wrapper.getOffsetHeight(); + } else if (wrapper.bottom != null) { + // top not defined, available space 0... bottom of wrapper + h = wrapper.getElement().getOffsetTop() + wrapper.getOffsetHeight(); + } else { + // top defined or both undefined, available space == canvas - top + h = canvas.getOffsetHeight() - wrapper.getElement().getOffsetTop(); + } + + return new RenderSpace(w, h); + } + + public boolean hasChildComponent(Widget component) { + for (Iterator<Entry<String, AbsoluteWrapper>> iterator = pidToComponentWrappper + .entrySet().iterator(); iterator.hasNext();) { + if (iterator.next().getValue().paintable == component) { + return true; + } + } + return false; + } + + public void replaceChildComponent(Widget oldComponent, Widget newComponent) { + for (Widget wrapper : getChildren()) { + AbsoluteWrapper w = (AbsoluteWrapper) wrapper; + if (w.getWidget() == oldComponent) { + w.setWidget(newComponent); + return; + } + } + } + + public boolean requestLayout(Set<Paintable> children) { + // component inside an absolute panel never affects parent nor the + // layout + return true; + } + + public void updateCaption(Paintable component, UIDL uidl) { + // TODO Auto-generated method stub + + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + rendering = true; + this.client = client; + // TODO margin handling + if (client.updateComponent(this, uidl, true)) { + rendering = false; + return; + } + + HashSet<String> unrenderedPids = new HashSet<String>( + pidToComponentWrappper.keySet()); + + for (Iterator<UIDL> childIterator = uidl.getChildIterator(); childIterator + .hasNext();) { + UIDL cc = childIterator.next(); + UIDL componentUIDL = cc.getChildUIDL(0); + unrenderedPids.remove(componentUIDL.getId()); + getWrapper(client, componentUIDL).updateFromUIDL(cc); + } + + for (String pid : unrenderedPids) { + AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid); + pidToComponentWrappper.remove(pid); + absoluteWrapper.destroy(); + } + rendering = false; + } + + private AbsoluteWrapper getWrapper(ApplicationConnection client, + UIDL componentUIDL) { + AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL + .getId()); + if (wrapper == null) { + wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL)); + pidToComponentWrappper.put(componentUIDL.getId(), wrapper); + add(wrapper); + } + return wrapper; + + } + + @Override + public void add(Widget child) { + super.add(child, canvas); + } + + @Override + public void setStyleName(String style) { + super.setStyleName(style); + if (previousStyleName == null || !previousStyleName.equals(style)) { + excessPixelsHorizontal = -1; + excessPixelsVertical = -1; + } + } + + @Override + public void setWidth(String width) { + super.setWidth(width); + // TODO do this so that canvas gets the sized properly (the area + // inside marginals) + canvas.getStyle().setProperty("width", width); + + if (!rendering && BrowserInfo.get().isIE6()) { + relayoutWrappersForIe6(); + } + } + + @Override + public void setHeight(String height) { + super.setHeight(height); + // TODO do this so that canvas gets the sized properly (the area + // inside marginals) + canvas.getStyle().setProperty("height", height); + + if (!rendering && BrowserInfo.get().isIE6()) { + relayoutWrappersForIe6(); + } + } + + private void relayoutWrappersForIe6() { + for (Widget wrapper : getChildren()) { + ((AbsoluteWrapper) wrapper).ie6Layout(); + } + } + + public class AbsoluteWrapper extends SimplePanel { + private String css; + private String left; + private String top; + private String right; + private String bottom; + private String zIndex; + + private Paintable paintable; + + public AbsoluteWrapper(Paintable paintable) { + this.paintable = paintable; + setStyleName(CLASSNAME + "-wrapper"); + } + + public void destroy() { + client.unregisterPaintable(paintable); + removeFromParent(); + } + + public void updateFromUIDL(UIDL componentUIDL) { + setPosition(componentUIDL.getStringAttribute("css")); + if (getWidget() != paintable) { + setWidget((Widget) paintable); + } + paintable.updateFromUIDL(componentUIDL.getChildUIDL(0), client); + } + + public void setPosition(String stringAttribute) { + if (css == null || !css.equals(stringAttribute)) { + css = stringAttribute; + top = right = bottom = left = zIndex = null; + if (!css.equals("")) { + String[] properties = css.split(";"); + for (int i = 0; i < properties.length; i++) { + String[] keyValue = properties[i].split(":"); + if (keyValue[0].equals("left")) { + left = keyValue[1]; + } else if (keyValue[0].equals("top")) { + top = keyValue[1]; + } else if (keyValue[0].equals("right")) { + right = keyValue[1]; + } else if (keyValue[0].equals("bottom")) { + bottom = keyValue[1]; + } else if (keyValue[0].equals("z-index")) { + zIndex = keyValue[1]; + } + } + } + // ensure ne values + Style style = getElement().getStyle(); + style.setProperty("zIndex", zIndex); + style.setProperty("top", top); + style.setProperty("left", left); + style.setProperty("right", right); + style.setProperty("bottom", bottom); + + if (BrowserInfo.get().isIE6()) { + ie6Layout(); + } + } + + } + + private void ie6Layout() { + // special handling for IE6 is needed, it does not support + // setting both left/right or top/bottom + Style style = getElement().getStyle(); + if (bottom != null && top != null) { + // define height for wrapper to simulate bottom property + int bottompixels = measureForIE6(bottom); + ApplicationConnection.getConsole().log("ALB" + bottompixels); + int height = canvas.getOffsetHeight() - bottompixels + - getElement().getOffsetTop(); + ApplicationConnection.getConsole().log("ALB" + height); + if (height < 0) { + height = 0; + } + style.setPropertyPx("height", height); + } else { + // reset possibly existing value + style.setProperty("height", ""); + } + if (left != null && right != null) { + // define width for wrapper to simulate right property + int rightPixels = measureForIE6(right); + ApplicationConnection.getConsole().log("ALR" + rightPixels); + int width = canvas.getOffsetWidth() - rightPixels + - getElement().getOffsetWidth(); + ApplicationConnection.getConsole().log("ALR" + width); + if (width < 0) { + width = 0; + } + style.setPropertyPx("width", width); + } else { + // reset possibly existing value + style.setProperty("width", ""); + } + } + + } + + private Element measureElement; + + private int measureForIE6(String cssLength) { + if (measureElement == null) { + measureElement = DOM.createDiv(); + measureElement.getStyle().setProperty("position", "absolute"); + canvas.appendChild(measureElement); + } + measureElement.getStyle().setProperty("width", cssLength); + return measureElement.getOffsetWidth(); + } + +} diff --git a/src/com/itmill/toolkit/tests/layouts/TestAbsoluteLayout.java b/src/com/itmill/toolkit/tests/layouts/TestAbsoluteLayout.java new file mode 100644 index 0000000000..6631df2963 --- /dev/null +++ b/src/com/itmill/toolkit/tests/layouts/TestAbsoluteLayout.java @@ -0,0 +1,54 @@ +package com.itmill.toolkit.tests.layouts;
+
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.AbsoluteLayout;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.Label;
+
+public class TestAbsoluteLayout extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "This is absolute layout tester.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+ @Override
+ protected void setup() {
+ AbsoluteLayout layout = new AbsoluteLayout();
+ setTheme("tests-tickets");
+ layout.setStyleName("cyan");
+
+ layout.addComponent(new Label("Hello World"));
+
+ Button button = new Button("Centered button,z-index:10;");
+ button.setSizeFull();
+ layout.addComponent(button,
+ "top:40%;bottom:40%;right:20%;left:20%;z-index:10;");
+
+ Label label = new Label(
+ "Exotic positioned label. Fullsize, top:100px; left:2cm; right: 3.5in; bottom:12.12mm ");
+ label.setStyleName("yellow");
+ label.setSizeFull();
+ layout.addComponent(label,
+ "top:100px; left:2cm; right: 3.5in; bottom:12.12mm");
+
+ label = new Label("fullize, bottom:80%;left:80%;");
+ label.setStyleName("green");
+ label.setSizeFull();
+ layout.addComponent(label, "bottom:80%;left:80%;");
+
+ label = new Label("bottomright");
+ label.setSizeUndefined();
+ label.setStyleName("green");
+ layout.addComponent(label, "bottom:0px; right:0px;");
+
+ getLayout().setSizeFull();
+ getLayout().addComponent(layout);
+
+ }
+}
diff --git a/src/com/itmill/toolkit/ui/AbsoluteLayout.java b/src/com/itmill/toolkit/ui/AbsoluteLayout.java new file mode 100644 index 0000000000..61a12bb76f --- /dev/null +++ b/src/com/itmill/toolkit/ui/AbsoluteLayout.java @@ -0,0 +1,210 @@ +package com.itmill.toolkit.ui; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import com.itmill.toolkit.terminal.PaintException; +import com.itmill.toolkit.terminal.PaintTarget; +import com.itmill.toolkit.terminal.gwt.client.ui.IAbsoluteLayout; + +/** + * AbsoluteLayout is a layout implementation that mimics html absolute + * positioning. + * + */ +public class AbsoluteLayout extends AbstractLayout { + + private Collection<Component> components = new HashSet<Component>(); + private Map<Component, ComponentPosition> componentToCoordinates = new HashMap<Component, ComponentPosition>(); + + public AbsoluteLayout() { + setSizeFull(); + } + + @Override + public String getTag() { + return IAbsoluteLayout.TAGNAME; + } + + public Iterator<Component> getComponentIterator() { + return components.iterator(); + } + + public void replaceComponent(Component oldComponent, Component newComponent) { + ComponentPosition position = getPosition(oldComponent); + removeComponent(oldComponent); + addComponent(newComponent); + componentToCoordinates.put(newComponent, position); + } + + @Override + public void addComponent(Component c) { + components.add(c); + super.addComponent(c); + } + + @Override + public void removeComponent(Component c) { + components.remove(c); + super.removeComponent(c); + } + + public void addComponent(Component c, String cssPosition) { + addComponent(c); + getPosition(c).setCSSString(cssPosition); + } + + public ComponentPosition getPosition(Component component) { + if (componentToCoordinates.containsKey(component)) { + return componentToCoordinates.get(component); + } else { + ComponentPosition coords = new ComponentPosition(); + componentToCoordinates.put(component, coords); + return coords; + } + } + + /** + * TODO symmetric getters and setters for fields to make this simpler to use + * in generic java tools + * + */ + public class ComponentPosition { + + private int zIndex = -1; + private float top = -1; + private float right = -1; + private float bottom = -1; + private float left = -1; + + private int topUnits; + private int rightUnits; + private int bottomUnits; + private int leftUnits; + + /** + * Sets the position attributes using CSS syntax. Example usage: + * + * <code><pre> + * setCSSString("top:10px;left:20%;z-index:16;"); + * </pre></code> + * + * @param css + */ + public void setCSSString(String css) { + String[] cssProperties = css.split(";"); + for (int i = 0; i < cssProperties.length; i++) { + String[] keyValuePair = cssProperties[i].split(":"); + String key = keyValuePair[0].trim(); + if (key.equals("z-index")) { + zIndex = Integer.parseInt(keyValuePair[1]); + } else { + String value = keyValuePair[1].trim(); + String unit = value.replaceAll("[0-9\\.]+", ""); + if (!unit.equals("")) { + value = value.substring(0, value.indexOf(unit)).trim(); + } + float v = Float.parseFloat(value); + int unitInt = parseCssUnit(unit); + if (key.equals("top")) { + top = v; + topUnits = unitInt; + } else if (key.equals("right")) { + right = v; + rightUnits = unitInt; + } else if (key.equals("bottom")) { + bottom = v; + bottomUnits = unitInt; + } else if (key.equals("left")) { + left = v; + leftUnits = unitInt; + } + } + } + requestRepaint(); + } + + private int parseCssUnit(String string) { + for (int i = 0; i < UNIT_SYMBOLS.length; i++) { + if (UNIT_SYMBOLS[i].equals(string)) { + return i; + } + } + return 0; // defaults to px (eg. top:0;) + } + + public String getCSSString() { + String s = ""; + if (top >= 0) { + s += "top:" + top + UNIT_SYMBOLS[topUnits] + ";"; + } + if (right >= 0) { + s += "right:" + right + UNIT_SYMBOLS[rightUnits] + ";"; + } + if (bottom >= 0) { + s += "bottom:" + bottom + UNIT_SYMBOLS[bottomUnits] + ";"; + } + if (left >= 0) { + s += "left:" + left + UNIT_SYMBOLS[leftUnits] + ";"; + } + if (zIndex >= 0) { + s += "z-index:" + zIndex + ";"; + } + return s; + } + + public void setTop(float topValue, int topUnits) { + validateLength(topValue, topUnits); + top = topValue; + this.topUnits = topUnits; + requestRepaint(); + } + + public void setRight(float rightValue, int rightUnits) { + validateLength(rightValue, rightUnits); + right = rightValue; + this.rightUnits = rightUnits; + requestRepaint(); + } + + public void setBottom(float bottomValue, int units) { + validateLength(bottomValue, units); + bottom = bottomValue; + bottomUnits = units; + requestRepaint(); + } + + public void setLeft(float leftValue, int units) { + validateLength(leftValue, units); + left = leftValue; + leftUnits = units; + requestRepaint(); + } + + public void setZIndex(int zIndex) { + this.zIndex = zIndex; + requestRepaint(); + } + + } + + @Override + public void paintContent(PaintTarget target) throws PaintException { + super.paintContent(target); + for (Component component : components) { + target.startTag("cc"); + target.addAttribute("css", getPosition(component).getCSSString()); + component.paint(target); + target.endTag("cc"); + } + } + + private static void validateLength(float topValue, int topUnits2) { + // TODO throw on invalid value + + } + +} diff --git a/src/com/itmill/toolkit/ui/AbstractField.java b/src/com/itmill/toolkit/ui/AbstractField.java index c998236f32..4d717826e6 100644 --- a/src/com/itmill/toolkit/ui/AbstractField.java +++ b/src/com/itmill/toolkit/ui/AbstractField.java @@ -639,12 +639,10 @@ public abstract class AbstractField extends AbstractComponent implements Field, */ public boolean isValid() { - if (isRequired()) { - if (isEmpty()) { + if (isEmpty()) { + if (isRequired()) { return false; - } - } else { - if (isEmpty()) { + } else { return true; } } @@ -675,9 +673,11 @@ public abstract class AbstractField extends AbstractComponent implements Field, */ public void validate() throws Validator.InvalidValueException { - if (isRequired()) { - if (isEmpty()) { + if (isEmpty()) { + if (isRequired()) { throw new Validator.EmptyValueException(requiredError); + } else { + return; } } |