summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/AbstractOrderedLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com/vaadin/ui/AbstractOrderedLayout.java')
-rw-r--r--server/src/com/vaadin/ui/AbstractOrderedLayout.java383
1 files changed, 383 insertions, 0 deletions
diff --git a/server/src/com/vaadin/ui/AbstractOrderedLayout.java b/server/src/com/vaadin/ui/AbstractOrderedLayout.java
new file mode 100644
index 0000000000..0581d0a279
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbstractOrderedLayout.java
@@ -0,0 +1,383 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+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.MouseEventDetails;
+import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
+import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState;
+import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState.ChildComponentData;
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
+
+@SuppressWarnings("serial")
+public abstract class AbstractOrderedLayout extends AbstractLayout implements
+ Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier {
+
+ private AbstractOrderedLayoutServerRpc rpc = new AbstractOrderedLayoutServerRpc() {
+
+ @Override
+ public void layoutClick(MouseEventDetails mouseDetails,
+ Connector clickedConnector) {
+ fireEvent(LayoutClickEvent.createEvent(AbstractOrderedLayout.this,
+ mouseDetails, clickedConnector));
+ }
+ };
+
+ public static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT;
+
+ /**
+ * Custom layout slots containing the components.
+ */
+ protected LinkedList<Component> components = new LinkedList<Component>();
+
+ /* Child component alignments */
+
+ /**
+ * Mapping from components to alignments (horizontal + vertical).
+ */
+ public AbstractOrderedLayout() {
+ registerRpc(rpc);
+ }
+
+ @Override
+ public AbstractOrderedLayoutState getState() {
+ return (AbstractOrderedLayoutState) super.getState();
+ }
+
+ /**
+ * 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) {
+ // Add to components before calling super.addComponent
+ // so that it is available to AttachListeners
+ components.add(c);
+ try {
+ super.addComponent(c);
+ } catch (IllegalArgumentException e) {
+ components.remove(c);
+ throw e;
+ }
+ componentAdded(c);
+ }
+
+ /**
+ * 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) {
+ // If c is already in this, we must remove it before proceeding
+ // see ticket #7668
+ if (c.getParent() == this) {
+ removeComponent(c);
+ }
+ components.addFirst(c);
+ try {
+ super.addComponent(c);
+ } catch (IllegalArgumentException e) {
+ components.remove(c);
+ throw e;
+ }
+ componentAdded(c);
+
+ }
+
+ /**
+ * 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) {
+ // If c is already in this, we must remove it before proceeding
+ // see ticket #7668
+ if (c.getParent() == this) {
+ // When c is removed, all components after it are shifted down
+ if (index > getComponentIndex(c)) {
+ index--;
+ }
+ removeComponent(c);
+ }
+ components.add(index, c);
+ try {
+ super.addComponent(c);
+ } catch (IllegalArgumentException e) {
+ components.remove(c);
+ throw e;
+ }
+
+ componentAdded(c);
+ }
+
+ private void componentRemoved(Component c) {
+ getState().getChildData().remove(c);
+ requestRepaint();
+ }
+
+ private void componentAdded(Component c) {
+ getState().getChildData().put(c, new ChildComponentData());
+ requestRepaint();
+
+ }
+
+ /**
+ * Removes the component from this container.
+ *
+ * @param c
+ * the component to be removed.
+ */
+ @Override
+ public void removeComponent(Component c) {
+ components.remove(c);
+ super.removeComponent(c);
+ componentRemoved(c);
+ }
+
+ /**
+ * Gets the component container iterator for going trough all the components
+ * in the container.
+ *
+ * @return the Iterator of the components inside the container.
+ */
+ @Override
+ public Iterator<Component> getComponentIterator() {
+ return components.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 components.size();
+ }
+
+ /* Documented in superclass */
+ @Override
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+
+ // Gets the locations
+ int oldLocation = -1;
+ int newLocation = -1;
+ int location = 0;
+ for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
+ final 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 {
+ // Both old and new are in the layout
+ 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();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.AlignmentHandler#setComponentAlignment(com
+ * .vaadin.ui.Component, int, int)
+ */
+ @Override
+ public void setComponentAlignment(Component childComponent,
+ int horizontalAlignment, int verticalAlignment) {
+ Alignment a = new Alignment(horizontalAlignment + verticalAlignment);
+ setComponentAlignment(childComponent, a);
+ }
+
+ @Override
+ public void setComponentAlignment(Component childComponent,
+ Alignment alignment) {
+ ChildComponentData childData = getState().getChildData().get(
+ childComponent);
+ if (childData != null) {
+ // Alignments are bit masks
+ childData.setAlignmentBitmask(alignment.getBitMask());
+ requestRepaint();
+ } else {
+ throw new IllegalArgumentException(
+ "Component must be added to layout before using setComponentAlignment()");
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.AlignmentHandler#getComponentAlignment(com
+ * .vaadin.ui.Component)
+ */
+ @Override
+ public Alignment getComponentAlignment(Component childComponent) {
+ ChildComponentData childData = getState().getChildData().get(
+ childComponent);
+ if (childData == null) {
+ throw new IllegalArgumentException(
+ "The given component is not a child of this layout");
+ }
+
+ return new Alignment(childData.getAlignmentBitmask());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean)
+ */
+ @Override
+ public void setSpacing(boolean spacing) {
+ getState().setSpacing(spacing);
+ requestRepaint();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing()
+ */
+ @Override
+ public boolean isSpacing() {
+ return getState().isSpacing();
+ }
+
+ /**
+ * <p>
+ * This method is used to control how excess space in layout is distributed
+ * among components. Excess space may exist if layout is sized and contained
+ * non relatively sized components don't consume all available space.
+ *
+ * <p>
+ * Example how to distribute 1:3 (33%) for component1 and 2:3 (67%) for
+ * component2 :
+ *
+ * <code>
+ * layout.setExpandRatio(component1, 1);<br>
+ * layout.setExpandRatio(component2, 2);
+ * </code>
+ *
+ * <p>
+ * If no ratios have been set, the excess space is distributed evenly among
+ * all components.
+ *
+ * <p>
+ * Note, that width or height (depending on orientation) needs to be defined
+ * for this method to have any effect.
+ *
+ * @see Sizeable
+ *
+ * @param component
+ * the component in this layout which expand ratio is to be set
+ * @param ratio
+ */
+ public void setExpandRatio(Component component, float ratio) {
+ ChildComponentData childData = getState().getChildData().get(component);
+ if (childData == null) {
+ throw new IllegalArgumentException(
+ "The given component is not a child of this layout");
+ }
+
+ childData.setExpandRatio(ratio);
+ requestRepaint();
+ };
+
+ /**
+ * Returns the expand ratio of given component.
+ *
+ * @param component
+ * which expand ratios is requested
+ * @return expand ratio of given component, 0.0f by default.
+ */
+ public float getExpandRatio(Component component) {
+ ChildComponentData childData = getState().getChildData().get(component);
+ if (childData == null) {
+ throw new IllegalArgumentException(
+ "The given component is not a child of this layout");
+ }
+
+ return childData.getExpandRatio();
+ }
+
+ @Override
+ public void addListener(LayoutClickListener listener) {
+ addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER,
+ LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ @Override
+ public void removeListener(LayoutClickListener listener) {
+ removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER,
+ LayoutClickEvent.class, listener);
+ }
+
+ /**
+ * Returns the index of the given component.
+ *
+ * @param component
+ * The component to look up.
+ * @return The index of the component or -1 if the component is not a child.
+ */
+ public int getComponentIndex(Component component) {
+ return components.indexOf(component);
+ }
+
+ /**
+ * Returns the component at the given position.
+ *
+ * @param index
+ * The position of the component.
+ * @return The component at the given index.
+ * @throws IndexOutOfBoundsException
+ * If the index is out of range.
+ */
+ public Component getComponent(int index) throws IndexOutOfBoundsException {
+ return components.get(index);
+ }
+
+}