summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/AbsoluteLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com/vaadin/ui/AbsoluteLayout.java')
-rw-r--r--server/src/com/vaadin/ui/AbsoluteLayout.java644
1 files changed, 644 insertions, 0 deletions
diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java
new file mode 100644
index 0000000000..9851a79bcd
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbsoluteLayout.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.vaadin.event.LayoutEvents.LayoutClickEvent;
+import com.vaadin.event.LayoutEvents.LayoutClickListener;
+import com.vaadin.event.LayoutEvents.LayoutClickNotifier;
+import com.vaadin.shared.Connector;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutServerRpc;
+import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutState;
+import com.vaadin.terminal.Sizeable;
+
+/**
+ * AbsoluteLayout is a layout implementation that mimics html absolute
+ * positioning.
+ *
+ */
+@SuppressWarnings("serial")
+public class AbsoluteLayout extends AbstractLayout implements
+ LayoutClickNotifier {
+
+ private AbsoluteLayoutServerRpc rpc = new AbsoluteLayoutServerRpc() {
+
+ @Override
+ public void layoutClick(MouseEventDetails mouseDetails,
+ Connector clickedConnector) {
+ fireEvent(LayoutClickEvent.createEvent(AbsoluteLayout.this,
+ mouseDetails, clickedConnector));
+ }
+ };
+ // Maps each component to a position
+ private LinkedHashMap<Component, ComponentPosition> componentToCoordinates = new LinkedHashMap<Component, ComponentPosition>();
+
+ /**
+ * Creates an AbsoluteLayout with full size.
+ */
+ public AbsoluteLayout() {
+ registerRpc(rpc);
+ setSizeFull();
+ }
+
+ @Override
+ public AbsoluteLayoutState getState() {
+ return (AbsoluteLayoutState) super.getState();
+ }
+
+ /**
+ * Gets an iterator for going through all components enclosed in the
+ * absolute layout.
+ */
+ @Override
+ public Iterator<Component> getComponentIterator() {
+ return componentToCoordinates.keySet().iterator();
+ }
+
+ /**
+ * Gets the number of contained components. Consistent with the iterator
+ * returned by {@link #getComponentIterator()}.
+ *
+ * @return the number of contained components
+ */
+ @Override
+ public int getComponentCount() {
+ return componentToCoordinates.size();
+ }
+
+ /**
+ * Replaces one component with another one. The new component inherits the
+ * old components position.
+ */
+ @Override
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+ ComponentPosition position = getPosition(oldComponent);
+ removeComponent(oldComponent);
+ addComponent(newComponent, position);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component
+ * )
+ */
+ @Override
+ public void addComponent(Component c) {
+ addComponent(c, new ComponentPosition());
+ }
+
+ /**
+ * Adds a component to the layout. The component can be positioned by
+ * providing a string formatted in CSS-format.
+ * <p>
+ * For example the string "top:10px;left:10px" will position the component
+ * 10 pixels from the left and 10 pixels from the top. The identifiers:
+ * "top","left","right" and "bottom" can be used to specify the position.
+ * </p>
+ *
+ * @param c
+ * The component to add to the layout
+ * @param cssPosition
+ * The css position string
+ */
+ public void addComponent(Component c, String cssPosition) {
+ ComponentPosition position = new ComponentPosition();
+ position.setCSSString(cssPosition);
+ addComponent(c, position);
+ }
+
+ /**
+ * Adds the component using the given position. Ensures the position is only
+ * set if the component is added correctly.
+ *
+ * @param c
+ * The component to add
+ * @param position
+ * The position info for the component. Must not be null.
+ * @throws IllegalArgumentException
+ * If adding the component failed
+ */
+ private void addComponent(Component c, ComponentPosition position)
+ throws IllegalArgumentException {
+ /*
+ * Create position instance and add it to componentToCoordinates map. We
+ * need to do this before we call addComponent so the attachListeners
+ * can access this position. #6368
+ */
+ internalSetPosition(c, position);
+ try {
+ super.addComponent(c);
+ } catch (IllegalArgumentException e) {
+ internalRemoveComponent(c);
+ throw e;
+ }
+ requestRepaint();
+ }
+
+ /**
+ * Removes the component from all internal data structures. Does not
+ * actually remove the component from the layout (this is assumed to have
+ * been done by the caller).
+ *
+ * @param c
+ * The component to remove
+ */
+ private void internalRemoveComponent(Component c) {
+ componentToCoordinates.remove(c);
+ }
+
+ @Override
+ public void updateState() {
+ super.updateState();
+
+ // This could be in internalRemoveComponent and internalSetComponent if
+ // Map<Connector,String> was supported. We cannot get the child
+ // connectorId unless the component is attached to the application so
+ // the String->String map cannot be populated in internal* either.
+ Map<String, String> connectorToPosition = new HashMap<String, String>();
+ for (Iterator<Component> ci = getComponentIterator(); ci.hasNext();) {
+ Component c = ci.next();
+ connectorToPosition.put(c.getConnectorId(), getPosition(c)
+ .getCSSString());
+ }
+ getState().setConnectorToCssPosition(connectorToPosition);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui
+ * .Component)
+ */
+ @Override
+ public void removeComponent(Component c) {
+ internalRemoveComponent(c);
+ super.removeComponent(c);
+ requestRepaint();
+ }
+
+ /**
+ * Gets the position of a component in the layout. Returns null if component
+ * is not attached to the layout.
+ * <p>
+ * Note that you cannot update the position by updating this object. Call
+ * {@link #setPosition(Component, ComponentPosition)} with the updated
+ * {@link ComponentPosition} object.
+ * </p>
+ *
+ * @param component
+ * The component which position is needed
+ * @return An instance of ComponentPosition containing the position of the
+ * component, or null if the component is not enclosed in the
+ * layout.
+ */
+ public ComponentPosition getPosition(Component component) {
+ return componentToCoordinates.get(component);
+ }
+
+ /**
+ * Sets the position of a component in the layout.
+ *
+ * @param component
+ * @param position
+ */
+ public void setPosition(Component component, ComponentPosition position) {
+ if (!componentToCoordinates.containsKey(component)) {
+ throw new IllegalArgumentException(
+ "Component must be a child of this layout");
+ }
+ internalSetPosition(component, position);
+ }
+
+ /**
+ * Updates the position for a component. Caller must ensure component is a
+ * child of this layout.
+ *
+ * @param component
+ * The component. Must be a child for this layout. Not enforced.
+ * @param position
+ * New position. Must not be null.
+ */
+ private void internalSetPosition(Component component,
+ ComponentPosition position) {
+ componentToCoordinates.put(component, position);
+ requestRepaint();
+ }
+
+ /**
+ * The CompontPosition class represents a components position within the
+ * absolute layout. It contains the attributes for left, right, top and
+ * bottom and the units used to specify them.
+ */
+ public class ComponentPosition implements Serializable {
+
+ private int zIndex = -1;
+ private Float topValue = null;
+ private Float rightValue = null;
+ private Float bottomValue = null;
+ private Float leftValue = null;
+
+ private Unit topUnits = Unit.PIXELS;
+ private Unit rightUnits = Unit.PIXELS;
+ private Unit bottomUnits = Unit.PIXELS;
+ private Unit leftUnits = Unit.PIXELS;
+
+ /**
+ * Sets the position attributes using CSS syntax. Attributes not
+ * included in the string are reset to their unset states.
+ *
+ * <code><pre>
+ * setCSSString("top:10px;left:20%;z-index:16;");
+ * </pre></code>
+ *
+ * @param css
+ */
+ public void setCSSString(String css) {
+ topValue = rightValue = bottomValue = leftValue = null;
+ topUnits = rightUnits = bottomUnits = leftUnits = Unit.PIXELS;
+ zIndex = -1;
+ if (css == null) {
+ return;
+ }
+
+ 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("")) {
+ continue;
+ }
+ if (key.equals("z-index")) {
+ zIndex = Integer.parseInt(keyValuePair[1].trim());
+ } else {
+ String value;
+ if (keyValuePair.length > 1) {
+ value = keyValuePair[1].trim();
+ } else {
+ value = "";
+ }
+ String symbol = value.replaceAll("[0-9\\.\\-]+", "");
+ if (!symbol.equals("")) {
+ value = value.substring(0, value.indexOf(symbol))
+ .trim();
+ }
+ float v = Float.parseFloat(value);
+ Unit unit = Unit.getUnitFromSymbol(symbol);
+ if (key.equals("top")) {
+ topValue = v;
+ topUnits = unit;
+ } else if (key.equals("right")) {
+ rightValue = v;
+ rightUnits = unit;
+ } else if (key.equals("bottom")) {
+ bottomValue = v;
+ bottomUnits = unit;
+ } else if (key.equals("left")) {
+ leftValue = v;
+ leftUnits = unit;
+ }
+ }
+ }
+ requestRepaint();
+ }
+
+ /**
+ * Converts the internal values into a valid CSS string.
+ *
+ * @return A valid CSS string
+ */
+ public String getCSSString() {
+ String s = "";
+ if (topValue != null) {
+ s += "top:" + topValue + topUnits.getSymbol() + ";";
+ }
+ if (rightValue != null) {
+ s += "right:" + rightValue + rightUnits.getSymbol() + ";";
+ }
+ if (bottomValue != null) {
+ s += "bottom:" + bottomValue + bottomUnits.getSymbol() + ";";
+ }
+ if (leftValue != null) {
+ s += "left:" + leftValue + leftUnits.getSymbol() + ";";
+ }
+ if (zIndex >= 0) {
+ s += "z-index:" + zIndex + ";";
+ }
+ return s;
+ }
+
+ /**
+ * Sets the 'top' attribute; distance from the top of the component to
+ * the top edge of the layout.
+ *
+ * @param topValue
+ * The value of the 'top' attribute
+ * @param topUnits
+ * The unit of the 'top' attribute. See UNIT_SYMBOLS for a
+ * description of the available units.
+ */
+ public void setTop(Float topValue, Unit topUnits) {
+ this.topValue = topValue;
+ this.topUnits = topUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Sets the 'right' attribute; distance from the right of the component
+ * to the right edge of the layout.
+ *
+ * @param rightValue
+ * The value of the 'right' attribute
+ * @param rightUnits
+ * The unit of the 'right' attribute. See UNIT_SYMBOLS for a
+ * description of the available units.
+ */
+ public void setRight(Float rightValue, Unit rightUnits) {
+ this.rightValue = rightValue;
+ this.rightUnits = rightUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Sets the 'bottom' attribute; distance from the bottom of the
+ * component to the bottom edge of the layout.
+ *
+ * @param bottomValue
+ * The value of the 'bottom' attribute
+ * @param units
+ * The unit of the 'bottom' attribute. See UNIT_SYMBOLS for a
+ * description of the available units.
+ */
+ public void setBottom(Float bottomValue, Unit bottomUnits) {
+ this.bottomValue = bottomValue;
+ this.bottomUnits = bottomUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Sets the 'left' attribute; distance from the left of the component to
+ * the left edge of the layout.
+ *
+ * @param leftValue
+ * The value of the 'left' attribute
+ * @param units
+ * The unit of the 'left' attribute. See UNIT_SYMBOLS for a
+ * description of the available units.
+ */
+ public void setLeft(Float leftValue, Unit leftUnits) {
+ this.leftValue = leftValue;
+ this.leftUnits = leftUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Sets the 'z-index' attribute; the visual stacking order
+ *
+ * @param zIndex
+ * The z-index for the component.
+ */
+ public void setZIndex(int zIndex) {
+ this.zIndex = zIndex;
+ requestRepaint();
+ }
+
+ /**
+ * Sets the value of the 'top' attribute; distance from the top of the
+ * component to the top edge of the layout.
+ *
+ * @param topValue
+ * The value of the 'left' attribute
+ */
+ public void setTopValue(Float topValue) {
+ this.topValue = topValue;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the 'top' attributes value in current units.
+ *
+ * @see #getTopUnits()
+ * @return The value of the 'top' attribute, null if not set
+ */
+ public Float getTopValue() {
+ return topValue;
+ }
+
+ /**
+ * Gets the 'right' attributes value in current units.
+ *
+ * @return The value of the 'right' attribute, null if not set
+ * @see #getRightUnits()
+ */
+ public Float getRightValue() {
+ return rightValue;
+ }
+
+ /**
+ * Sets the 'right' attribute value (distance from the right of the
+ * component to the right edge of the layout). Currently active units
+ * are maintained.
+ *
+ * @param rightValue
+ * The value of the 'right' attribute
+ * @see #setRightUnits(int)
+ */
+ public void setRightValue(Float rightValue) {
+ this.rightValue = rightValue;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the 'bottom' attributes value using current units.
+ *
+ * @return The value of the 'bottom' attribute, null if not set
+ * @see #getBottomUnits()
+ */
+ public Float getBottomValue() {
+ return bottomValue;
+ }
+
+ /**
+ * Sets the 'bottom' attribute value (distance from the bottom of the
+ * component to the bottom edge of the layout). Currently active units
+ * are maintained.
+ *
+ * @param bottomValue
+ * The value of the 'bottom' attribute
+ * @see #setBottomUnits(int)
+ */
+ public void setBottomValue(Float bottomValue) {
+ this.bottomValue = bottomValue;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the 'left' attributes value using current units.
+ *
+ * @return The value of the 'left' attribute, null if not set
+ * @see #getLeftUnits()
+ */
+ public Float getLeftValue() {
+ return leftValue;
+ }
+
+ /**
+ * Sets the 'left' attribute value (distance from the left of the
+ * component to the left edge of the layout). Currently active units are
+ * maintained.
+ *
+ * @param leftValue
+ * The value of the 'left' CSS-attribute
+ * @see #setLeftUnits(int)
+ */
+ public void setLeftValue(Float leftValue) {
+ this.leftValue = leftValue;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the unit for the 'top' attribute
+ *
+ * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public Unit getTopUnits() {
+ return topUnits;
+ }
+
+ /**
+ * Sets the unit for the 'top' attribute
+ *
+ * @param topUnits
+ * See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public void setTopUnits(Unit topUnits) {
+ this.topUnits = topUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the unit for the 'right' attribute
+ *
+ * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public Unit getRightUnits() {
+ return rightUnits;
+ }
+
+ /**
+ * Sets the unit for the 'right' attribute
+ *
+ * @param rightUnits
+ * See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public void setRightUnits(Unit rightUnits) {
+ this.rightUnits = rightUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the unit for the 'bottom' attribute
+ *
+ * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public Unit getBottomUnits() {
+ return bottomUnits;
+ }
+
+ /**
+ * Sets the unit for the 'bottom' attribute
+ *
+ * @param bottomUnits
+ * See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public void setBottomUnits(Unit bottomUnits) {
+ this.bottomUnits = bottomUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the unit for the 'left' attribute
+ *
+ * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public Unit getLeftUnits() {
+ return leftUnits;
+ }
+
+ /**
+ * Sets the unit for the 'left' attribute
+ *
+ * @param leftUnits
+ * See {@link Sizeable} UNIT_SYMBOLS for a description of the
+ * available units.
+ */
+ public void setLeftUnits(Unit leftUnits) {
+ this.leftUnits = leftUnits;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the 'z-index' attribute.
+ *
+ * @return the zIndex The z-index attribute
+ */
+ public int getZIndex() {
+ return zIndex;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getCSSString();
+ }
+
+ }
+
+ @Override
+ public void addListener(LayoutClickListener listener) {
+ addListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER,
+ LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ @Override
+ public void removeListener(LayoutClickListener listener) {
+ removeListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER,
+ LayoutClickEvent.class, listener);
+ }
+
+}