You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by we...@apache.org on 2005/08/03 15:41:08 UTC

svn commit: r227220 - in /portals/jetspeed-2/trunk: layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ layout-portlets/src/test/ layout-portlets/src/test/org/ layout-portlets/src/test/org/apache/ layout-portlets/src/test/org/apache/jetspeed/...

Author: weaver
Date: Wed Aug  3 06:41:01 2005
New Revision: 227220

URL: http://svn.apache.org/viewcvs?rev=227220&view=rev
Log:
http://issues.apache.org/jira/browse/JS2-321

- Created a ColumnLayout model object that handles the layout and movement.
- Created an extensive test case for the ColumnLayout
- Created a formal exception hierarchy for the layout api.
- Created an event system for the ColumnLayout.
- Created a PageManagerLayoutEventListener that gets fired when fragments are moved around to save the new fragment positions.

Added:
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java   (with props)
    portals/jetspeed-2/trunk/layout-portlets/src/test/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/
    portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java   (with props)
    portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/apps/
Modified:
    portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/MultiColumnPortlet.java
    portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/templates/layout/html/columns/layout.vm

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,567 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.jetspeed.om.page.Fragment;
+
+/**
+ * <p>
+ * <code>ColumnLayout</code> is the model used to support any 1 to <i>n</i>
+ * column-based layout. <code>ColumnLayout</code> is constrained by a number
+ * columns that will not be exceeded, even if a fragment specifies a column
+ * outside of this constraint. Any fragment exceeded the specified column
+ * constraint will be deposited into the right-most column.
+ * </p>
+ * Columns always start at 0.
+ * 
+ * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
+ * 
+ */
+public class ColumnLayout implements Serializable
+{
+    private static final String COLUMN = "column";
+
+    private static final String ROW = "row";
+
+    private final int numberOfColumns;
+
+    private final SortedMap columns;
+
+    private final String layoutType;
+
+    /** Efficent way to always be aware of the next available row in a column */
+    private final int[] nextRowNumber;
+    
+    /** maps Fragments (key) to it's current LayoutCoordinate (value) in this layout */
+    private final Map coordinates;
+    
+    private final List eventListeners;
+
+    /**
+     * 
+     * @param numberOfColumns
+     *            the maximum number of columns this layout will have.
+     * @param layoutType
+     *            this value corresponds to the property settings of the
+     *            fragments within your psml. Layout type allows segration of
+     *            property settings based on the type of layout in use. This
+     *            effectively allows for the interchange of multiple layout
+     *            formats without one format effecting the settings of another.
+     */
+    public ColumnLayout(int numberOfColumns, String layoutType)
+    {
+        this.numberOfColumns = numberOfColumns;
+        this.layoutType = layoutType;
+        eventListeners = new ArrayList();
+
+        columns = new TreeMap();
+        coordinates = new HashMap();
+
+        for (int i = 0; i < numberOfColumns; i++)
+        {
+            columns.put(new Integer(i), new TreeMap());
+        }
+
+        nextRowNumber = new int[numberOfColumns];
+
+        for (int i = 0; i < numberOfColumns; i++)
+        {
+            nextRowNumber[i] = 0;
+        }
+    }
+
+    public ColumnLayout(int numberOfColumns, String layoutType, Collection fragments) throws LayoutEventException
+    {
+        this(numberOfColumns, layoutType);
+        Iterator fragmentsItr = fragments.iterator();
+        try
+        {
+            while (fragmentsItr.hasNext())
+            {
+                Fragment fragment = (Fragment) fragmentsItr.next();
+                doAdd(getColumn(fragment), getRow(getColumn(fragment), fragment), fragment);
+            }
+        }
+        catch (InvalidLayoutLocationException e)
+        {
+            // This should NEVER happen as getColumn() should
+            // automatically constrain any fragments who's column
+            // setting would cause this exception.
+            throw new LayoutError("A malformed fragment could not be adjusted.", e);
+        }
+    }
+
+    /**
+     * <p>
+     * Adds a fragment to the layout using fragment properties of
+     * <code> row  </code> and <code> column  </code> as hints on where to put
+     * this fragment. The following rules apply to malformed fragment
+     * definitions:
+     * </p>
+     * <ul>
+     * <li>Fragments without a row defined are placed at the bottom of their
+     * respective column </li>
+     * <li>Fragments without a column are placed in the right-most column.
+     * </li>
+     * <li> Fragments with overlapping row numbers. The last fragment has
+     * priority pushing the fragment in that row down one row. </li>
+     * </ul>
+     * 
+     * @param fragment
+     *            Fragment to add to this layout.
+     * @throws LayoutEventException 
+     * 
+     */
+    public void addFragment(Fragment fragment) throws LayoutEventException
+    {
+        try
+        {
+            doAdd(getColumn(fragment), getRow(getColumn(fragment), fragment), fragment);
+            LayoutCoordinate coordinate = getCoordinate(fragment);
+            processEvent(new LayoutEvent(LayoutEvent.ADDED, fragment, coordinate, coordinate));
+        }
+        catch (InvalidLayoutLocationException e)
+        {
+            // This should NEVER happen as getColumn() should
+            // automatically constrain any fragments who's column
+            // setting would cause this exception.
+            throw new LayoutError("A malformed fragment could not be adjusted.", e);
+        }
+        catch (FragmentNotInLayoutException e)
+        {        
+            throw new LayoutError("Failed to add coordinate to this ColumnLayout.", e);
+        }
+    }
+    
+    public void addLayoutEventListener(LayoutEventListener eventListener)
+    {
+        eventListeners.add(eventListener);
+    }
+
+    /**
+     * 
+     * 
+     * @param columnNumber
+     *            Number of column to retreive
+     * @return requested column (as a immutable Collection). Never returns
+     *         <code>null.</code>
+     * @throws InvalidLayoutLocationException
+     *             if the column is outisde of the constraintes of this layout
+     */
+    public Collection getColumn(int columnNumber) throws InvalidLayoutLocationException
+    {
+        return Collections.unmodifiableCollection(getColumnMap(columnNumber).values());
+    }
+
+    /**
+     * @return <code>java.util.Collection</code> all of columns (also
+     *         Collection objects) in order within this layout. All Collections
+     *         are immutable.
+     */
+    public Collection getColumns()
+    {
+        ArrayList columnList = new ArrayList(getNumberOfColumns());
+        Iterator itr = columns.values().iterator();
+        while (itr.hasNext())
+        {
+            columnList.add(Collections.unmodifiableCollection(((Map) itr.next()).values()));
+        }
+
+        return Collections.unmodifiableCollection(columnList);
+    }
+    
+    /**
+     * Returns an immutable Collection of all the Fragments contained within
+     * this ColumnLayout in no sepcific order.
+     * @return Immutable Collection of Fragments.
+     */
+    public Collection getFragments()
+    {
+        return Collections.unmodifiableCollection(coordinates.keySet());
+    }
+
+    /**
+     * 
+     * @param columnNumber
+     * @param rowNumber
+     * @return
+     * @throws EmptyLayoutLocationException
+     * @throws InvalidLayoutLocationException
+     */
+    public Fragment getFragmentAt(int columnNumber, int rowNumber) throws EmptyLayoutLocationException,
+            InvalidLayoutLocationException
+    {
+        SortedMap column = getColumnMap(columnNumber);
+        Integer rowInteger = new Integer(rowNumber);
+        if (column.containsKey(rowInteger))
+        {
+            return (Fragment) column.get(rowInteger);
+        }
+        else
+        {
+            throw new EmptyLayoutLocationException(columnNumber, rowNumber);
+        }
+    }
+
+    public Fragment getFragmentAt(LayoutCoordinate coodinate) throws EmptyLayoutLocationException,
+            InvalidLayoutLocationException
+    {
+        return getFragmentAt(coodinate.getX(), coodinate.getY());
+    }
+
+    /**
+     * 
+     * @return
+     */
+    public int getNumberOfColumns()
+    {
+        return numberOfColumns;
+    }
+
+    /**
+     * 
+     * @return
+     * @throws InvalidLayoutLocationException
+     */
+    public Collection getLastColumn() throws InvalidLayoutLocationException
+    {
+        return Collections.unmodifiableCollection((Collection) getColumnMap(numberOfColumns - 1).values());
+    }
+
+    /**
+     * 
+     * @return
+     * @throws InvalidLayoutLocationException
+     */
+    public Collection getFirstColumn() throws InvalidLayoutLocationException
+    {
+        return Collections.unmodifiableCollection((Collection) getColumnMap(1).values());
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @throws FragmentNotInLayoutException
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    public void moveRight(Fragment fragment) throws FragmentNotInLayoutException, InvalidLayoutLocationException, LayoutEventException
+    {
+        LayoutCoordinate coordinate = getCoordinate(fragment);
+        LayoutCoordinate newCoordinate = new LayoutCoordinate(coordinate.getX() + 1, coordinate.getY());
+
+        if (newCoordinate.getX() < numberOfColumns)
+        {
+
+            doMove(fragment, coordinate, newCoordinate);
+            processEvent(new LayoutEvent(LayoutEvent.MOVED_RIGHT, fragment, coordinate, newCoordinate));
+            // now move the fragment below up one level.
+            try
+            {
+                Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(coordinate.getX(), coordinate.getY() + 1));
+                moveUp(fragmentBelow);
+            }
+            catch (EmptyLayoutLocationException e)
+            {
+                // indicates no fragment below
+            }
+        }
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @throws FragmentNotInLayoutException
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    public void moveLeft(Fragment fragment) throws FragmentNotInLayoutException, InvalidLayoutLocationException, LayoutEventException
+    {
+        LayoutCoordinate coordinate = getCoordinate(fragment);
+        LayoutCoordinate newCoordinate = new LayoutCoordinate(coordinate.getX() - 1, coordinate.getY());
+
+        if (newCoordinate.getX() >= 0)
+        {
+            doMove(fragment, coordinate, newCoordinate);
+            processEvent(new LayoutEvent(LayoutEvent.MOVED_LEFT, fragment, coordinate, newCoordinate));
+            // now move the fragment below up one level.
+            try
+            {
+                Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(coordinate.getX(), coordinate.getY() + 1));
+                moveUp(fragmentBelow);
+            }
+            catch (EmptyLayoutLocationException e)
+            {
+                // indicates no fragment below
+            }
+        }
+
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @throws FragmentNotInLayoutException
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    public void moveUp(Fragment fragment) throws FragmentNotInLayoutException, InvalidLayoutLocationException, LayoutEventException
+    {
+        LayoutCoordinate coordinate = getCoordinate(fragment);
+        LayoutCoordinate aboveLayoutCoordinate = new LayoutCoordinate(coordinate.getX(), coordinate.getY() - 1);
+        LayoutCoordinate newCoordinate = aboveLayoutCoordinate;
+
+        // never go "above" 0.
+        if (newCoordinate.getY() >= 0)
+        {
+            try
+            {
+                // now move the fragment above down one level.
+                Fragment fragmentAbove = getFragmentAt(aboveLayoutCoordinate);
+                doMove(fragment, coordinate, newCoordinate);
+                processEvent(new LayoutEvent(LayoutEvent.MOVED_UP, fragment, coordinate, newCoordinate));                
+            }
+            catch (EmptyLayoutLocationException e)
+            {
+                // Nothing above??? Then scoot all elements below up one level.
+                doMove(fragment, coordinate, newCoordinate);
+                processEvent(new LayoutEvent(LayoutEvent.MOVED_UP, fragment, coordinate, newCoordinate));
+                
+                // If this the last row, make sure to update the next row pointer accordingly.
+                if(coordinate.getY() == (nextRowNumber[coordinate.getX()] - 1))
+                {
+                    nextRowNumber[coordinate.getX()] = coordinate.getX();
+                }
+                
+                try
+                {
+                    Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(coordinate.getX(),
+                            coordinate.getY() + 1));
+                    moveUp(fragmentBelow);
+                }
+                catch (EmptyLayoutLocationException e1)
+                {
+
+                }
+            }
+
+        }
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @throws FragmentNotInLayoutException
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    public void moveDown(Fragment fragment) throws FragmentNotInLayoutException, InvalidLayoutLocationException, LayoutEventException
+    {
+        LayoutCoordinate coordinate = getCoordinate(fragment);
+        LayoutCoordinate newCoordinate = new LayoutCoordinate(coordinate.getX(), coordinate.getY() + 1);
+
+        // never move past the current bottom row
+        if (newCoordinate.getY() < nextRowNumber[coordinate.getX()])
+        {
+            try
+            {
+                // the best approach to move a fragment down is to actually move
+                // its neighbor underneath up
+                LayoutCoordinate aboveCoord = new LayoutCoordinate(coordinate.getX(), coordinate.getY() + 1);
+                Fragment fragmentBelow = getFragmentAt(aboveCoord);
+                doMove(fragmentBelow, aboveCoord, coordinate);
+                processEvent(new LayoutEvent(LayoutEvent.MOVED_UP, fragmentBelow, aboveCoord, coordinate));
+                // Since this logic path is a somewhat special case, the processing of the  MOVED_DOWN
+                // event happens within the doAdd() method.
+            }
+            catch (EmptyLayoutLocationException e)
+            {
+                doMove(fragment, coordinate, newCoordinate);
+                processEvent(new LayoutEvent(LayoutEvent.MOVED_DOWN, fragment, coordinate, newCoordinate));
+            }
+        }
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @param oldCoordinate
+     * @param newCoordinate
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    protected void doMove(Fragment fragment, LayoutCoordinate oldCoordinate, LayoutCoordinate newCoordinate)
+            throws InvalidLayoutLocationException, LayoutEventException
+    {
+        SortedMap oldColumn = getColumnMap(oldCoordinate.getX());
+        oldColumn.remove(new Integer(oldCoordinate.getY()));
+        coordinates.remove(fragment);
+
+        doAdd(newCoordinate.getX(), newCoordinate.getY(), fragment);
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @return
+     * @throws FragmentNotInLayoutException
+     */
+    public LayoutCoordinate getCoordinate(Fragment fragment) throws FragmentNotInLayoutException
+    {
+        if (coordinates.containsKey(fragment))
+        {
+            return (LayoutCoordinate) coordinates.get(fragment);
+        }
+        else
+        {
+            throw new FragmentNotInLayoutException(fragment);
+        }
+    }
+
+    /**
+     * 
+     * @param columnNumber
+     * @param rowNumber
+     * @param fragment
+     * @throws InvalidLayoutLocationException
+     * @throws LayoutEventException 
+     */
+    protected void doAdd(int columnNumber, int rowNumber, Fragment fragment) throws InvalidLayoutLocationException, LayoutEventException
+    {
+        SortedMap column = getColumnMap(columnNumber);
+    
+        Integer rowInteger = new Integer(rowNumber);
+        LayoutCoordinate targetCoordinate = new LayoutCoordinate(columnNumber, rowNumber);
+        if (column.containsKey(rowInteger))
+        {
+            // If the row has something in it, push everythin down 1
+            Fragment existingFragment = (Fragment) column.get(rowInteger);
+            column.put(rowInteger, fragment);
+            coordinates.put(fragment, targetCoordinate);
+            doAdd(columnNumber, ++rowNumber, existingFragment);
+            
+            LayoutCoordinate oneDownCoordinate = new LayoutCoordinate(targetCoordinate.getX(), targetCoordinate.getY() + 1);
+            processEvent(new LayoutEvent(LayoutEvent.MOVED_DOWN, existingFragment, targetCoordinate, oneDownCoordinate));
+        }
+        else
+        {
+            column.put(rowInteger, fragment);
+            coordinates.put(fragment, targetCoordinate);
+            rowNumber++;
+            if(rowNumber > nextRowNumber[columnNumber])
+            {
+                nextRowNumber[columnNumber] = rowNumber;
+            }
+        }
+    
+    }
+
+    /**
+     * 
+     * @param columnNumber
+     * @return
+     * @throws InvalidLayoutLocationException
+     */
+    protected final SortedMap getColumnMap(int columnNumber) throws InvalidLayoutLocationException
+    {
+        Integer columnNumberIneteger = new Integer(columnNumber);
+
+        if (columns.containsKey(columnNumberIneteger))
+        {
+            return ((SortedMap) columns.get(columnNumberIneteger));
+        }
+        else
+        {
+            throw new InvalidLayoutLocationException(columnNumber);
+        }
+
+    }
+
+    /**
+     * 
+     * @param currentColumn
+     * @param fragment
+     * @return
+     */
+    protected final int getRow(int currentColumn, Fragment fragment)
+    {
+        String propertyValue = fragment.getPropertyValue(layoutType, ROW);
+
+        if (propertyValue != null)
+        {
+            return Integer.parseInt(propertyValue);
+        }
+        else
+        {
+            return nextRowNumber[currentColumn];
+        }
+
+    }
+
+    /**
+     * 
+     * @param fragment
+     * @return
+     */
+    protected final int getColumn(Fragment fragment)
+    {
+        String propertyValue = fragment.getPropertyValue(layoutType, COLUMN);
+        if (propertyValue != null)
+        {
+            int columnNumber = Integer.parseInt(propertyValue);
+
+            // Exceeded columns get put into the last column
+            if (columnNumber >= numberOfColumns)
+            {
+                columnNumber = (numberOfColumns - 1);
+            }
+            // Columns less than 1 go in the first column
+            else if (columnNumber < 0)
+            {
+                columnNumber = 0;
+            }
+
+            return columnNumber;
+        }
+        else
+        {
+            return (numberOfColumns - 1);
+        }
+    }
+    
+    protected final void processEvent(LayoutEvent event) throws LayoutEventException
+    {
+        Iterator itr = eventListeners.iterator();
+        while(itr.hasNext())
+        {
+            LayoutEventListener eventListener = (LayoutEventListener) itr.next();
+            eventListener.handleEvent(event);
+        }
+        
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/ColumnLayout.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+
+public class EmptyLayoutLocationException extends LayoutException
+{
+    public EmptyLayoutLocationException(int column, int row)
+    {
+        super("No fragment is located in this layout at column:"+column+" row:"+row);
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/EmptyLayoutLocationException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import org.apache.jetspeed.om.page.Fragment;
+
+public class FragmentNotInLayoutException extends LayoutException
+{
+    public FragmentNotInLayoutException(Fragment fragment)
+    {
+        super("The fragment "+fragment.getId()+" could not be located in this layout.");
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/FragmentNotInLayoutException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+
+public class InvalidLayoutLocationException extends LayoutException
+{
+    public InvalidLayoutLocationException(LayoutCoordinate coordinate)
+    {
+        super("Invalid layout coordinate "+coordinate.toString());
+    }    
+    
+    public InvalidLayoutLocationException(int column)
+    {
+        super("Column number "+column+" is not a valid column for this layout.");
+    }
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/InvalidLayoutLocationException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import java.io.Serializable;
+
+public final class LayoutCoordinate implements Comparable, Serializable
+{
+    private final int x;
+    private final int y;
+    
+    public LayoutCoordinate(int x, int y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX()
+    {
+        return x;
+    }
+    
+
+    public int getY()
+    {
+        return y;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if(obj instanceof LayoutCoordinate)
+        {
+            LayoutCoordinate coordinate = (LayoutCoordinate) obj;
+            return x == coordinate.x && y == coordinate.y;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public int hashCode()
+    {        
+        return toString().hashCode();
+    }
+
+    public String toString()
+    {      
+        return x+","+y;
+    }
+
+    public int compareTo(Object obj)
+    {
+        LayoutCoordinate coordinate = (LayoutCoordinate) obj;
+        if(!coordinate.equals(this))
+        {
+           if(y == coordinate.y)
+           {
+               return x > coordinate.x ? 1 : -1;
+           }
+           else
+           {
+               return y > coordinate.y ? 1 : -1;
+           }
+           
+        }
+        else
+        {
+            return 0;
+        }
+    }
+    
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutCoordinate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+/**
+ * 
+ * Should only be thrown when something truely unexpected happens
+ * when processing a layout.  Basically used in the case where something
+ * that "should never happen" happens.
+ * 
+ * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
+ *
+ */
+public class LayoutError extends Error
+{
+    private static final String BUG_MESSAGE = "Congratulations!!! You have found a bug! Please log this issue at http://issues.apache.org/jira.";
+
+    public LayoutError()
+    {
+        super(BUG_MESSAGE);
+    }
+
+    public LayoutError(String message)
+    {
+        super(BUG_MESSAGE+"\n"+message);
+    }
+
+    public LayoutError(Throwable cause)
+    {
+        super(cause);
+    }
+
+    public LayoutError(String message, Throwable cause)
+    {
+        super(BUG_MESSAGE+"\n"+message, cause);
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutError.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import org.apache.jetspeed.om.page.Fragment;
+
+public class LayoutEvent
+{
+    public static final int ADDED =0;
+    public static final int MOVED_UP = 1;
+    public static final int MOVED_DOWN = 2;
+    public static final int MOVED_LEFT = 3;
+    public static final int MOVED_RIGHT = 4;
+    
+    private final int eventType;
+    private final Fragment fragment;
+    private final LayoutCoordinate originalCoordinate;
+    private final LayoutCoordinate newCoordinate;    
+
+    public LayoutEvent(int eventType, Fragment fragment, LayoutCoordinate originalCoordinate, LayoutCoordinate newCoordinate)
+    {
+        super();       
+        this.eventType = eventType;
+        this.fragment = fragment;
+        this.originalCoordinate = originalCoordinate;
+        this.newCoordinate = newCoordinate;
+    }
+   
+   
+    public int getEventType()
+    {
+        return eventType;
+    }
+    
+
+    public Fragment getFragment()
+    {
+        return fragment;
+    }
+    
+
+    public LayoutCoordinate getNewCoordinate()
+    {
+        return newCoordinate;
+    }
+    
+
+    public LayoutCoordinate getOriginalCoordinate()
+    {
+        return originalCoordinate;
+    }
+
+
+    public boolean equals(Object obj)
+    {
+        if(obj instanceof LayoutEvent)
+        {
+            LayoutEvent event = (LayoutEvent) obj;
+            return event.fragment.equals(fragment) 
+              && event.eventType == eventType
+              && event.originalCoordinate.equals(originalCoordinate)
+              && event.newCoordinate.equals(newCoordinate);
+            
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    public String toString()
+    {
+        
+        return "event_target="+fragment.getId()+",event_type_code="+ eventType + ",orginial_coordinate="+ originalCoordinate+
+               ",new_coordinate="+newCoordinate;
+    }
+    
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEvent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import org.apache.jetspeed.i18n.KeyedMessage;
+
+public class LayoutEventException extends LayoutException
+{
+
+    public LayoutEventException()
+    {
+        super();
+    }
+
+    public LayoutEventException(String message)
+    {
+        super(message);
+    }
+
+    public LayoutEventException(KeyedMessage typedMessage)
+    {
+        super(typedMessage);
+    }
+
+    public LayoutEventException(Throwable nested)
+    {
+        super(nested);
+    }
+
+    public LayoutEventException(String msg, Throwable nested)
+    {
+        super(msg, nested);
+    }
+
+    public LayoutEventException(KeyedMessage keyedMessage, Throwable nested)
+    {
+        super(keyedMessage, nested);
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+public interface LayoutEventListener
+{
+    void handleEvent(LayoutEvent event) throws LayoutEventException;
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutEventListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import org.apache.jetspeed.exception.JetspeedException;
+import org.apache.jetspeed.i18n.KeyedMessage;
+
+public class LayoutException extends JetspeedException
+{
+
+    public LayoutException()
+    {
+        super();
+    }
+
+    public LayoutException(String message)
+    {
+        super(message);
+    }
+
+    public LayoutException(KeyedMessage typedMessage)
+    {
+        super(typedMessage);       
+    }
+
+    public LayoutException(Throwable nested)
+    {
+        super(nested);
+    }
+
+    public LayoutException(String msg, Throwable nested)
+    {
+        super(msg, nested);
+    }
+
+    public LayoutException(KeyedMessage keyedMessage, Throwable nested)
+    {
+        super(keyedMessage, nested);
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/LayoutException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/MultiColumnPortlet.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/MultiColumnPortlet.java?rev=227220&r1=227219&r2=227220&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/MultiColumnPortlet.java (original)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/MultiColumnPortlet.java Wed Aug  3 06:41:01 2005
@@ -18,8 +18,10 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -55,10 +57,12 @@
     private String layoutType;
     private List columnSizes = null;
     protected PageManager pm;
+    private Map layouts ;
 
     public void init( PortletConfig config ) throws PortletException
     {
         super.init(config);
+        layouts = new HashMap();
         this.numColumns = Integer.parseInt(config.getInitParameter(PARAM_NUM_COLUMN));
         if (0 == numColumns)
             numColumns = 1;
@@ -76,18 +80,45 @@
     {
         RequestContext context = getRequestContext(request);
         PortletWindow window = context.getPortalURL().getNavigationalState().getMaximizedWindow();
-
-        if (request.getParameter("moveBy") != null && request.getParameter("fragmentId") != null)
+        Page page = getRequestContext(request).getPage();
+        Fragment f = getFragment(request, false);
+        ColumnLayout layout;
+        try
+        {
+            layout = new ColumnLayout(numColumns, layoutType, f.getFragments());
+            layout.addLayoutEventListener(new PageManagerLayoutEventListener(pm, page, layoutType));
+        }
+        catch (LayoutEventException e1)
         {
-            Page page = getRequestContext(request).getPage();
-            Fragment f = getFragment(request, false);
-            ArrayList tempFrags = new ArrayList(f.getFragments());
-            doMoveFragment(page.getFragmentById(request.getParameter("fragmentId")), request.getParameter("moveBy"),
-                           request, tempFrags);
+            throw new PortletException("Failed to build ColumnLayout "+e1.getMessage(), e1);
+        }
+
+        if (request.getParameter("move") != null && request.getParameter("fragmentId") != null)
+        {            
+            Fragment fragmentToMove = page.getFragmentById(request.getParameter("fragmentId"));
+           
+            int moveCode = Integer.parseInt(request.getParameter("move"));           
 
             try
-            {
-                pm.updatePage(page);
+            {                
+                switch (moveCode)
+                {
+                case LayoutEvent.MOVED_UP:
+                    layout.moveUp(fragmentToMove);
+                    break;
+                case LayoutEvent.MOVED_DOWN:
+                    layout.moveDown(fragmentToMove);
+                    break;
+                case LayoutEvent.MOVED_RIGHT:
+                    layout.moveRight(fragmentToMove);
+                    break;
+                case LayoutEvent.MOVED_LEFT:
+                    layout.moveLeft(fragmentToMove);
+                    break;
+                default:
+                    throw new PortletException("Invalid movement code " + moveCode);
+                }
+               
             }
             catch (SecurityException se)
             {
@@ -98,7 +129,14 @@
             }
             catch (Exception e)
             {
-                log.error("Unable to update page " + page.getId() + " layout: "+e.toString(), e);
+                if (e instanceof PortletException)
+                {
+                    throw (PortletException)e;
+                }
+                else
+                {
+                    throw new PortletException("Unable to process layout for page " + page.getId() + " layout: " + e.toString(), e);
+                }
             }
         }
 
@@ -109,10 +147,7 @@
             return;
         }
 
-        Fragment f = getFragment(request, false);
-        List[] columns = buildColumns(f, this.numColumns, request);
-
-        request.setAttribute("columns", columns);
+        request.setAttribute("columnLayout", layout);
         request.setAttribute("numberOfColumns", new Integer(numColumns));
         
         List columnSizes = this.columnSizes;
@@ -129,156 +164,11 @@
         // now invoke the JSP associated with this portlet
         super.doView(request, response);
         
-        request.removeAttribute("columns");
+        request.removeAttribute("columnLayout");
         request.removeAttribute("numberOfColumns");
         request.removeAttribute("columnSizes");
     }
 
-    protected List[] buildColumns( Fragment f, int colNum, RenderRequest request ) throws PortletException
-    {
-        // normalize the constraints and calculate max num of rows needed
-        Iterator iterator = f.getFragments().iterator();
-        int row = 0;
-        int col = 0;
-        int rowNum = 0;
-        int[] lastRowForColumn = new int[numColumns];
-
-        while (iterator.hasNext())
-        {
-            Fragment fChild = (Fragment) iterator.next();
-
-            try
-            {
-
-                row = Integer.parseInt(fChild.getPropertyValue(this.layoutType, "row"));
-                if (row > rowNum)
-                {
-                    rowNum = row;
-                }
-
-                if (colNum > 1)
-                {
-                    col = Integer.parseInt(fChild.getPropertyValue(this.layoutType, "column"));
-                    if (col > colNum)
-                    {
-                        fChild.setPropertyValue(this.layoutType, "column", String.valueOf(col % colNum));
-                    }
-                }
-                else
-                {
-                    col = 0;
-                    fChild.setPropertyValue(this.layoutType, "column", String.valueOf(col));
-                }
-
-                if (row > lastRowForColumn[col])
-                {
-                    lastRowForColumn[col] = row;
-                }
-
-            }
-            catch (Exception e)
-            {
-                //ignore any malformed layout properties
-            }
-
-        }
-
-        int sCount = f.getFragments().size();
-        row = (sCount / colNum) + 1;
-        if (row > rowNum)
-        {
-            rowNum = row;
-        }
-
-        // initialize the result position table and the work list
-        List[] table = new List[colNum];
-        List filler = Collections.nCopies(rowNum + 1, null);
-        for (int i = 0; i < colNum; i++)
-        {
-            table[i] = new ArrayList();
-            table[i].addAll(filler);
-        }
-
-        List work = new ArrayList();
-
-        //position the constrained elements and keep a reference to the
-        //others
-        for (int i = 0; i < sCount; i++)
-        {
-            addElement((Fragment) f.getFragments().get(i), table, work, colNum);
-        }
-
-        //insert the unconstrained elements in the table
-        Iterator i = work.iterator();
-        boolean unconstrainedFound = false;
-        for (row = 0; row < rowNum; row++)
-        {
-            for (col = 0; i.hasNext() && (col < colNum); col++)
-            {
-                if (table[col].get(row) == null)
-                {
-                    Fragment ucf = (Fragment) i.next();
-                    table[col].set(row, ucf);
-
-                    ucf.setPropertyValue(layoutType, "row", String.valueOf(row));
-                    ucf.setPropertyValue(layoutType, "column", String.valueOf(col));
-                    unconstrainedFound = true;
-                    if (row > lastRowForColumn[col])
-                    {
-                        lastRowForColumn[col] = row;
-                    }
-
-                }
-            }
-        }
-
-        if (unconstrainedFound)
-        {
-            Page page = getRequestContext(request).getPage();
-            try
-            {
-                pm.updatePage(page);
-            }
-            catch (SecurityException se)
-            {
-                // ignore page security constraint violations, only
-                // permitted users can edit managed pages; page
-                // update will remain transient
-                log.info("Unable to update page " + page.getId() + " layout due to security permission/constraint.");
-            }
-            catch (Exception e)
-            {
-                log.error("Unable to update page " + page.getId() + " layout: "+e.toString(), e);
-            }           
-        }
-
-        // now cleanup any remaining null elements
-        for (int j = 0; j < table.length; j++)
-        {
-            i = table[j].iterator();
-            while (i.hasNext())
-            {
-                Object obj = i.next();
-
-                if (obj == null)
-                {
-                    i.remove();
-                }
-
-            }
-        }
-        
-        ArrayList lastRowForColList = new ArrayList(lastRowForColumn.length);
-        for(int j=0; j < lastRowForColumn.length; j++)
-        {
-            lastRowForColList.add(new Integer(lastRowForColumn[j]));
-        }
-        
-        request.setAttribute("lastRowForColumn", lastRowForColList);
-
-        return table;
-    }
-
     /**
      * Parses the size config info and returns a list of size values for the
      * current set
@@ -317,150 +207,5 @@
         }
 
         return list;
-    }
-
-    /**
-     * Add an element to the "table" or "work" objects. If the element is
-     * unconstrained, and the position is within the number of columns, then the
-     * element is added to "table". Othewise the element is added to "work"
-     * 
-     * @param f
-     *            fragment to add
-     * @param table
-     *            of positioned elements
-     * @param work
-     *            list of un-positioned elements
-     * @param columnCount
-     *            Number of colum
-     */
-    protected void addElement( Fragment f, List[] table, List work, int columnCount )
-    {
-        int row = -1;
-        int col = -1;
-
-        try
-        {
-            row = Integer.parseInt(f.getPropertyValue(this.layoutType, "row"));
-            col = Integer.parseInt(f.getPropertyValue(this.layoutType, "column"));
-        }
-        catch (Exception e)
-        {
-            //ignore any malformed layout properties
-        }
-
-        if ((row >= 0) && (col >= 0) && (col < columnCount))
-        {
-            table[col].set(row, f);
-        }
-        else
-        {
-            work.add(f);
-        }
-    }
-
-    protected void doMoveFragment( Fragment fToMove, String coordinates, RenderRequest request, List fragments )
-    {
-
-        StringTokenizer coorTk = new StringTokenizer(coordinates, ",");
-        int x = Integer.parseInt(coorTk.nextToken());
-        int y = Integer.parseInt(coorTk.nextToken());
-        if (x == 0 && y == 0)
-        {
-            return;
-        }
-
-        String rowValue = fToMove.getPropertyValue(layoutType, "row");
-        int row = Integer.parseInt(rowValue);
-        int column = Integer.parseInt(fToMove.getPropertyValue(layoutType, "column"));
-
-        int newRow = row + y;
-        int newColumn = column + x;
-        doMoveFragmentTo(fToMove, newColumn, newRow, request, fragments, true);
-
-    }
-
-    protected void doMoveFragmentTo( Fragment fToMove, int column, int row, RenderRequest request, List fragments,
-            boolean firstCall )
-    {
-        //Wrapping logic
-        if (column >= numColumns)
-        {
-            column = 0;
-            row += 1;
-            doMoveFragmentTo(fToMove, column, row, request, fragments, false);
-            return;
-
-        }
-        else if (column < 0)
-        {
-            row -= 1;
-            column = (numColumns - 1);
-            doMoveFragmentTo(fToMove, column, row, request, fragments, false);
-            return;
-        }
-        else if (row < 0)
-        {
-            row = getLastRowInColumn(column, fragments, fToMove) + 1;
-            doMoveFragmentTo(fToMove, column, row, request, fragments, false);
-            return;
-        }
-        else
-        {
-
-            int currentRow = Integer.parseInt(fToMove.getPropertyValue(layoutType, "row"));
-            int currentColumn = Integer.parseInt(fToMove.getPropertyValue(layoutType, "column"));
-
-            int lastRow = getLastRowInColumn(column, fragments, fToMove);
-
-            // Prevent wacky row 999 if there are only 2 rows in the column
-            if (row > (lastRow + 1))
-            {
-                row = lastRow + 1;
-            }
-
-            fToMove.setPropertyValue(layoutType, "row", String.valueOf(row));
-            fToMove.setPropertyValue(layoutType, "column", String.valueOf(column));
-
-            for (int i = 0; i < fragments.size(); i++)
-            {
-                Fragment aFragment = (Fragment) fragments.get(i);
-                if (!aFragment.equals(fToMove))
-                {
-                    int aRow = Integer.parseInt(aFragment.getPropertyValue(layoutType, "row"));
-                    int aColumn = Integer.parseInt(aFragment.getPropertyValue(layoutType, "column"));
-                    if (aColumn == column && aRow == row)
-                    {
-                        if (currentColumn == column && currentRow < row && firstCall)
-                        {
-                            doMoveFragmentTo(aFragment, column, (row - 1), request, fragments, false);
-                        }
-                        else
-                        {
-                            doMoveFragmentTo(aFragment, column, (row + 1), request, fragments, false);
-                        }
-                    }
-                }
-
-            }
-            return;
-        }
-
-    }
-
-    protected int getLastRowInColumn( int column, List fragments, Fragment f )
-    {
-        int row = 0;
-        Iterator allFrags = fragments.iterator();
-        while (allFrags.hasNext())
-        {
-            Fragment aFrag = (Fragment) allFrags.next();
-            int currentRow = Integer.parseInt(aFrag.getPropertyValue(layoutType, "row"));
-            int currentColumn = Integer.parseInt(aFrag.getPropertyValue(layoutType, "column"));
-            if (currentRow > row && currentColumn == column && (f == null || !f.equals(aFrag)))
-            {
-                row = currentRow;
-            }
-        }
-        return row;
     }
 }

Added: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,46 @@
+package org.apache.jetspeed.portlets.layout;
+
+import org.apache.jetspeed.exception.JetspeedException;
+import org.apache.jetspeed.om.page.Fragment;
+import org.apache.jetspeed.om.page.Page;
+import org.apache.jetspeed.page.PageManager;
+import org.apache.jetspeed.page.PageNotUpdatedException;
+
+public class PageManagerLayoutEventListener implements LayoutEventListener
+{
+    private final PageManager pageManager;
+    private final Page page;
+    private final String layoutType;
+    
+    public PageManagerLayoutEventListener(PageManager pageManager, Page page, String layoutType)
+    {
+        this.pageManager = pageManager;
+        this.page = page;
+        this.layoutType = layoutType;
+    }
+
+    public void handleEvent(LayoutEvent event) throws LayoutEventException
+    {
+        try
+        {
+            if(event.getEventType() == LayoutEvent.ADDED)
+            {
+                page.getRootFragment().getFragments().add(event.getFragment());
+                pageManager.updatePage(page);
+            }
+            else
+            {
+                Fragment fragment = event.getFragment();
+                LayoutCoordinate coordinate = event.getNewCoordinate();
+                fragment.setPropertyValue(layoutType, "column", String.valueOf(coordinate.getX()));
+                fragment.setPropertyValue(layoutType, "row", String.valueOf(coordinate.getY()));
+                pageManager.updatePage(page);
+            }
+        }
+        catch (Exception e)
+        {
+            throw new LayoutEventException("Unable to update page.", e);
+        }
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/java/org/apache/jetspeed/portlets/layout/PageManagerLayoutEventListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java?rev=227220&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java (added)
+++ portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java Wed Aug  3 06:41:01 2005
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2000-2001,2004 The Apache Software Foundation.
+ * 
+ * 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 org.apache.jetspeed.portlets.layout;
+
+import java.util.Iterator;
+
+import org.apache.jetspeed.om.page.Fragment;
+import org.apache.jetspeed.om.page.psml.FragmentImpl;
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+
+public class TestColumnLayout extends MockObjectTestCase
+{
+
+    private ColumnLayout layout;
+
+    private FragmentImpl f1;
+
+    private FragmentImpl f2;
+
+    private FragmentImpl f3;
+
+    private FragmentImpl f4;
+
+    private FragmentImpl f5;
+
+    private FragmentImpl f6;
+
+    public void testBasics() throws Exception
+    {
+
+        assertEquals(3, layout.getNumberOfColumns());
+        Iterator column0 = layout.getColumn(0).iterator();
+        assertNotNull(column0);
+        Iterator column1 = layout.getColumn(1).iterator();
+        assertNotNull(column1);
+        assertNotNull(layout.getColumn(2));
+
+        int idx = 0;
+        while (column0.hasNext())
+        {
+            idx++;
+            Fragment fragment = (Fragment) column0.next();
+            assertEquals("f" + idx, fragment.getId());
+        }
+
+        assertEquals(3, idx);
+
+        assertEquals(f4, column1.next());
+        assertEquals(f5, column1.next());
+        assertEquals(f6, column1.next());
+
+        Fragment testFragment = layout.getFragmentAt(new LayoutCoordinate(0, 0));
+        assertNotNull(testFragment);
+        assertEquals(f1, testFragment);
+
+        testFragment = layout.getFragmentAt(new LayoutCoordinate(0, 1));
+        assertNotNull(testFragment);
+        assertEquals(f2, testFragment);
+
+        testFragment = layout.getFragmentAt(1, 0);
+        assertNotNull(testFragment);
+        assertEquals(f4, testFragment);
+        
+        assertEquals(3, layout.getColumns().size());
+    }
+
+    public void testSameRowSameColumn() throws Exception
+    {
+        FragmentImpl f1 = new FragmentImpl();
+        f1.setId("f1");
+        f1.setPropertyValue("test", "row", "0");
+        f1.setPropertyValue("test", "column", "0");
+
+        FragmentImpl f2 = new FragmentImpl();
+        f2.setId("f2");
+        f2.setPropertyValue("test", "row", "0");
+        f2.setPropertyValue("test", "column", "0");
+
+        ColumnLayout layout = new ColumnLayout(3, "test");
+        layout.addFragment(f1);
+        layout.addFragment(f2);
+
+        Iterator column0 = layout.getColumn(0).iterator();
+        // all subsequent fragments that go into the same row will push
+        // the existing fragment down.
+        assertEquals(f2, column0.next());
+        assertEquals(f1, column0.next());
+
+        Fragment testFragment = layout.getFragmentAt(0, 1);
+        assertNotNull(testFragment);
+        assertEquals(f1, testFragment);
+
+        testFragment = layout.getFragmentAt(0, 0);
+        assertNotNull(testFragment);
+        assertEquals(f2, testFragment);
+
+    }
+
+    public void testColumnNotSet() throws Exception
+    {
+        FragmentImpl f1 = new FragmentImpl();
+        f1.setId("f1");
+        f1.setPropertyValue("test", "row", "0");
+        f1.setPropertyValue("test", "column", "0");
+
+        FragmentImpl f2 = new FragmentImpl();
+        f2.setId("f2");
+        f2.setPropertyValue("test", "row", "0");
+
+        ColumnLayout layout = new ColumnLayout(3, "test");
+        layout.addFragment(f1);
+        layout.addFragment(f2);
+
+        Fragment testFragment = layout.getFragmentAt(0, 0);
+        assertNotNull(testFragment);
+        assertEquals(f1, testFragment);
+
+        testFragment = layout.getFragmentAt(2, 0);
+        assertNotNull(testFragment);
+        assertEquals(f2, testFragment);
+
+        assertNotNull(layout.getFirstColumn());
+        assertNotNull(layout.getLastColumn());
+
+    }
+
+    public void testRowNotSet() throws Exception
+    {
+        FragmentImpl f1 = new FragmentImpl();
+        f1.setId("f1");
+        f1.setPropertyValue("test", "row", "0");
+        f1.setPropertyValue("test", "column", "0");
+
+        FragmentImpl f2 = new FragmentImpl();
+        f2.setId("f2");
+        f2.setPropertyValue("test", "column", "0");
+
+        ColumnLayout layout = new ColumnLayout(3, "test");
+        layout.addFragment(f1);
+        layout.addFragment(f2);
+
+        Fragment testFragment = layout.getFragmentAt(0, 0);
+        assertNotNull(testFragment);
+        assertEquals(f1, testFragment);
+
+        testFragment = layout.getFragmentAt(0, 1);
+        assertNotNull(testFragment);
+        assertEquals(f2, testFragment);
+    }
+
+    public void testColumnLimitExceeded() throws Exception
+    {
+        FragmentImpl f1 = new FragmentImpl();
+        f1.setId("f1");
+        f1.setPropertyValue("test", "row", "0");
+        f1.setPropertyValue("test", "column", "5");
+
+        ColumnLayout layout = new ColumnLayout(3, "test");
+        layout.addFragment(f1);
+
+        // Exceeded columns just get dumped into the last column
+        Fragment testFragment = layout.getFragmentAt(2, 0);
+        assertNotNull(testFragment);
+        assertEquals(f1, testFragment);
+    }
+
+    public void testMovingRight() throws Exception
+    {
+
+        Fragment movingFragment = layout.getFragmentAt(new LayoutCoordinate(0, 0));
+        assertEquals(f1, movingFragment);
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+
+        Mock listenerMock = mock(LayoutEventListener.class);
+        layout.addLayoutEventListener((LayoutEventListener) listenerMock.proxy());
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_RIGHT)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_UP)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_UP)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f4, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f5, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f6, layout, LayoutEvent.MOVED_DOWN)));
+        
+        
+        // moving right
+        layout.moveRight(movingFragment);
+        
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 3)));
+    }
+
+    public void testMovingLeft() throws Exception
+    {
+        Fragment movingFragment = layout.getFragmentAt(new LayoutCoordinate(1, 0));
+        assertEquals(f4, movingFragment);
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        
+        Mock listenerMock = mock(LayoutEventListener.class);
+        layout.addLayoutEventListener((LayoutEventListener) listenerMock.proxy());
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f4, layout, LayoutEvent.MOVED_LEFT)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f5, layout, LayoutEvent.MOVED_UP)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f6, layout, LayoutEvent.MOVED_UP)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_DOWN)));
+        
+        layout.moveLeft(f4);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 3)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        
+        listenerMock.reset();       
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f6, layout, LayoutEvent.MOVED_LEFT)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_DOWN)));
+
+        layout.moveLeft(f6);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 3)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 4)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+
+        
+        listenerMock.reset();
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f5, layout, LayoutEvent.MOVED_LEFT)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f4, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f6, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_DOWN)));
+        
+        
+        layout.moveLeft(f5);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 3)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 4)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 5)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+
+        // This is a test to make sure the next row pointer is being decremented
+        // correctly
+        Fragment f7 = new FragmentImpl();
+        f7.setId("f7");
+        f7.setPropertyValue("test", "row", "0");
+        f7.setPropertyValue("test", "column", "1");
+
+        listenerMock.reset();
+        LayoutCoordinate coordinate = new LayoutCoordinate(1, 0);
+        LayoutEvent event = new LayoutEvent(LayoutEvent.ADDED, f7, coordinate, coordinate);
+        listenerMock.expects(once()).method("handleEvent").with(eq(event));
+        
+        layout.addFragment(f7);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 3)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 4)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 5)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f7, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+
+        // test that column consistency is maitained
+        Iterator itr1 = layout.getColumn(1).iterator();
+
+        itr1.next().equals(f7);
+
+        Iterator itr0 = layout.getColumn(0).iterator();
+
+        itr0.next().equals(f5);
+        itr0.next().equals(f4);
+        itr0.next().equals(f6);
+        itr0.next().equals(f1);
+        itr0.next().equals(f2);
+        itr0.next().equals(f3);
+    }
+
+    public void testInvalidOperations() throws Exception
+    {
+        layout.moveUp(f1); // Nothing at all should happen, not even exceptions
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+
+        layout.moveDown(f3); // Nothing at all should happen, not even
+                                // exceptions
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+
+        layout.moveLeft(f1); // Nothing at all should happen, not even
+        // exceptions
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+    }
+
+    public void testMoveDown() throws Exception
+    {
+        Mock listenerMock = mock(LayoutEventListener.class);
+        layout.addLayoutEventListener((LayoutEventListener) listenerMock.proxy());
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_UP)));
+
+        layout.moveDown(f1);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+        
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f1, layout, LayoutEvent.MOVED_DOWN)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_UP)));
+
+        layout.moveDown(f1);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+
+    }
+
+    public void testMoveUp() throws Exception
+    {
+
+        Mock listenerMock = mock(LayoutEventListener.class);
+        layout.addLayoutEventListener((LayoutEventListener) listenerMock.proxy());
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f3, layout, LayoutEvent.MOVED_UP)));
+        listenerMock.expects(once()).method("handleEvent").with(eq(createEvent(f2, layout, LayoutEvent.MOVED_DOWN)));
+        layout.moveUp(f3);
+
+        assertEquals(f1, layout.getFragmentAt(new LayoutCoordinate(0, 0)));
+        assertEquals(f2, layout.getFragmentAt(new LayoutCoordinate(0, 2)));
+        assertEquals(f3, layout.getFragmentAt(new LayoutCoordinate(0, 1)));
+        assertEquals(f4, layout.getFragmentAt(new LayoutCoordinate(1, 0)));
+        assertEquals(f5, layout.getFragmentAt(new LayoutCoordinate(1, 1)));
+        assertEquals(f6, layout.getFragmentAt(new LayoutCoordinate(1, 2)));
+    }
+
+    protected void setUp() throws Exception
+    {
+        f1 = new FragmentImpl();
+        f1.setId("f1");
+        f1.setPropertyValue("test", "row", "0");
+        f1.setPropertyValue("test", "column", "0");
+
+        f2 = new FragmentImpl();
+        f2.setId("f2");
+        f2.setPropertyValue("test", "row", "1");
+        f2.setPropertyValue("test", "column", "0");
+
+        f3 = new FragmentImpl();
+        f3.setId("f3");
+        f3.setPropertyValue("test", "row", "2");
+        f3.setPropertyValue("test", "column", "0");
+
+        f4 = new FragmentImpl();
+        f4.setId("f4");
+        f4.setPropertyValue("test", "row", "0");
+        f4.setPropertyValue("test", "column", "1");
+
+        f5 = new FragmentImpl();
+        f5.setId("f5");
+        f5.setPropertyValue("test", "row", "1");
+        f5.setPropertyValue("test", "column", "1");
+
+        f6 = new FragmentImpl();
+        f6.setId("f6");
+        f6.setPropertyValue("test", "row", "2");
+        f6.setPropertyValue("test", "column", "1");
+
+        layout = new ColumnLayout(3, "test");
+        layout.addFragment(f1);
+        layout.addFragment(f2);
+        layout.addFragment(f3);
+        layout.addFragment(f4);
+        layout.addFragment(f5);
+        layout.addFragment(f6);
+    }
+
+    protected LayoutEvent createEvent(Fragment fragment, ColumnLayout layout, int eventType) throws Exception
+    {
+        LayoutCoordinate fragmentOriginal = layout.getCoordinate(fragment);
+        LayoutCoordinate fragmentNew;
+
+        switch (eventType)
+        {
+        case LayoutEvent.MOVED_UP:
+            fragmentNew = new LayoutCoordinate(fragmentOriginal.getX(), fragmentOriginal.getY() - 1);
+            break;
+        case LayoutEvent.MOVED_DOWN:
+            fragmentNew = new LayoutCoordinate(fragmentOriginal.getX(), fragmentOriginal.getY() + 1);
+            break;
+        case LayoutEvent.MOVED_LEFT:
+            fragmentNew = new LayoutCoordinate(fragmentOriginal.getX() - 1, fragmentOriginal.getY());
+            break;
+        case LayoutEvent.MOVED_RIGHT:
+            fragmentNew = new LayoutCoordinate(fragmentOriginal.getX() + 1, fragmentOriginal.getY());
+            break;
+        default:
+            fragmentNew = new LayoutCoordinate(fragmentOriginal.getX(), fragmentOriginal.getY());
+            break;
+        }
+
+        return new LayoutEvent(eventType, fragment, fragmentOriginal, fragmentNew);
+
+    }
+
+}

Propchange: portals/jetspeed-2/trunk/layout-portlets/src/test/org/apache/jetspeed/portlets/layout/TestColumnLayout.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/templates/layout/html/columns/layout.vm
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/templates/layout/html/columns/layout.vm?rev=227220&r1=227219&r2=227220&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/templates/layout/html/columns/layout.vm (original)
+++ portals/jetspeed-2/trunk/portal-webapp/src/webapp/WEB-INF/templates/layout/html/columns/layout.vm Wed Aug  3 06:41:01 2005
@@ -55,6 +55,7 @@
   #end
 
 #set($layoutType =$portletConfig.getInitParameter("layoutType"))
+#set($columnLayout = $renderRequest.getAttribute("columnLayout"))
 
 #if ($actions.size()>0)
 <table  width="100%" cellspacing="0" cellpadding="0" >
@@ -97,7 +98,7 @@
   <tr>
      #set ($sizeIndex = 0)
      #set ($layoutImageBase = "${jetspeed.pageBasePath}/content/images")
-     #foreach($entry in $table)
+     #foreach($column in $columnLayout.columns)
         #if ($sizes)
           #if ($sizeIndex < $sizes.size())
              <td valign='top' width='$sizes.get($sizeIndex)'/>
@@ -109,14 +110,13 @@
        #end
        #set ($sizeIndex = $sizeIndex + 1)     
        <table width="100%" class="portal-layout-column">
-       #foreach($f in $entry)       
+       #foreach($f in $column)       
         <tr>
-         <td width="100%">			
-            #set($row = $f.getPropertyValue($layoutType, "row"))
-            #set($col = $f.getPropertyValue($layoutType, "column"))
-            #set($temp = 0) ##create temp Integer to parse strings
-	        #set($row = $temp.parseInt($row))
-            #set($col = $temp.parseInt($col))
+         <td width="100%">		
+			#set($coords = $columnLayout.getCoordinate($f))
+			#set($col = $coords.x)
+			#set($row = $coords.y)
+
             #if($editing)<div id="_$f.id">        
             <div style="position:relative; top:10px; left:0; width:100%; height:100%;">
               <div id="_$f.id_toolBox"  >
@@ -126,7 +126,7 @@
                    <td align="center" onMouseover="this.style.backgroundColor='red'" onMouseout="this.style.backgroundColor=''">
                         #if($row > 0)
                          #set($upUrl = $renderResponse.createRenderURL())    
-                         $!upUrl.setParameter("moveBy","0,-1")
+                         $!upUrl.setParameter("move","1")
                          $!upUrl.setParameter("fragmentId","$f.id")
                          #set ($imgsrc="$layoutImageBase/movePortletUp.gif")
                          <a href="$upUrl"><img src="$jetspeed.getAbsoluteUrl($imgsrc)" border="0" title="Move Portlet Up"/></a>
@@ -139,7 +139,7 @@
                    <td align="right" onMouseover="this.style.backgroundColor='red'" onMouseout="this.style.backgroundColor=''">
                         #if($lastColumn > 0 && $col > 0)            
                          #set($leftUrl = $renderResponse.createRenderURL())    
-                         $!leftUrl.setParameter("moveBy","-1,0")
+                         $!leftUrl.setParameter("move","3")
                          $!leftUrl.setParameter("fragmentId","$f.id")    
                          #set ($imgsrc="$layoutImageBase/movePortletLeft.gif")
                          <a href="$leftUrl"><img src="$jetspeed.getAbsoluteUrl($imgsrc)" border="0" title="Move Portlet Left"/></a>
@@ -151,7 +151,7 @@
                    <td align="left" onMouseover="this.style.backgroundColor='red'" onMouseout="this.style.backgroundColor=''">
                         #if($lastColumn > 0 && $col < $lastColumn)
                          #set($rightUrl = $renderResponse.createRenderURL())    
-                         $!rightUrl.setParameter("moveBy","1,0")
+                         $!rightUrl.setParameter("move","4")
                          $!rightUrl.setParameter("fragmentId","$f.id")
                          #set ($imgsrc="$layoutImageBase/movePortletRight.gif")
                          <a href="$rightUrl"><img src="$jetspeed.getAbsoluteUrl($imgsrc)" border="0" title="Move Portlet Right"/></a>
@@ -171,9 +171,9 @@
 					  #set($lastRow = $renderRequest.getAttribute("lastRowForColumn").get($col))
 					  #if($row < $lastRow)						
 					    #set($downUrl = $renderResponse.createRenderURL())	
-			            $!downUrl.setParameter("moveBy","0,1")
+			            $!downUrl.setParameter("move","2")
 			            $!downUrl.setParameter("fragmentId","$f.id")
-              #set ($imgsrc="$layoutImageBase/movePortletDown.gif")
+                        #set ($imgsrc="$layoutImageBase/movePortletDown.gif")
 					    <a href="$downUrl"><img src="$jetspeed.getAbsoluteUrl($imgsrc)" border="0" title="Move Portlet Down"/></a>
 					  #end
 					</td>



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org