]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Basic framework for table layout with Knuth elements as documented on the Wiki. The...
authorJeremias Maerki <jeremias@apache.org>
Tue, 5 Apr 2005 15:42:45 +0000 (15:42 +0000)
committerJeremias Maerki <jeremias@apache.org>
Tue, 5 Apr 2005 15:42:45 +0000 (15:42 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_KnuthStylePageBreaking@198563 13f79535-47bb-0310-9956-ffa450edef68

21 files changed:
src/java/org/apache/fop/fo/FObj.java
src/java/org/apache/fop/fo/flow/Table.java
src/java/org/apache/fop/fo/flow/TableBody.java
src/java/org/apache/fop/fo/flow/TableCell.java
src/java/org/apache/fop/fo/flow/TableColumn.java
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
src/java/org/apache/fop/layoutmgr/table/Body.java
src/java/org/apache/fop/layoutmgr/table/Cell.java
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java
src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/GridUnit.java
src/java/org/apache/fop/layoutmgr/table/OldGridUnit.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/PrimaryGridUnit.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/Row.java
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java [new file with mode: 0644]

index b3982bfa5069a9a9ad55399965920ec6e1a75280..b2b79eceb26d9b972debde553ca2bdbf12fc2e53 100644 (file)
@@ -18,9 +18,8 @@
 
 package org.apache.fop.fo;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
@@ -39,7 +38,7 @@ public abstract class FObj extends FONode implements Constants {
     public static PropertyMaker[] propertyListTable = null;
     
     /** The immediate child nodes of this node. */
-    public ArrayList childNodes = null;
+    public List childNodes = null;
 
     /** Used to indicate if this FO is either an Out Of Line FO (see rec)
         or a descendant of one.  Used during validateChildNode() FO 
@@ -164,7 +163,7 @@ public abstract class FObj extends FONode implements Constants {
                 addMarker((Marker) child);
         } else {
             if (childNodes == null) {
-                childNodes = new ArrayList();
+                childNodes = new java.util.ArrayList();
             }
             childNodes.add(child);
         }
@@ -198,7 +197,7 @@ public abstract class FObj extends FONode implements Constants {
      */
     public void setLayoutDimension(PercentBase.LayoutDimension key, int dimension) {
         if (layoutDimension == null) {
-            layoutDimension = new HashMap();
+            layoutDimension = new java.util.HashMap();
         }
         layoutDimension.put(key, new Integer(dimension));
     }
@@ -210,7 +209,7 @@ public abstract class FObj extends FONode implements Constants {
      */
     public void setLayoutDimension(PercentBase.LayoutDimension key, float dimension) {
         if (layoutDimension == null) {
-            layoutDimension = new HashMap();
+            layoutDimension = new java.util.HashMap();
         }
         layoutDimension.put(key, new Float(dimension));
     }
@@ -307,7 +306,7 @@ public abstract class FObj extends FONode implements Constants {
             }
         }
         if (markers == null) {
-            markers = new HashMap();
+            markers = new java.util.HashMap();
         }
         if (!markers.containsKey(mcname)) {
             markers.put(mcname, marker);
index 97cba06f156ac6d47dee6ed1830871d9c6401134..a6534e3d119fe1b3d3696565639c77d4f07d0908 100644 (file)
@@ -238,6 +238,14 @@ public class Table extends FObj {
     public List getColumns() {
         return columns;
     }
+    
+    /**
+     * @param index index of the table-body element.
+     * @return the requested table-body element
+     */
+    public TableBody getBody(int index) {
+        return (TableBody)childNodes.get(index);
+    }
 
     public TableBody getTableHeader() {
         return tableHeader;
index da1dc92f9b64f718e60d36614f536c97d75305d7..cae2fd2ce759844aa79cdca7029f63a30d7c1de5 100644 (file)
@@ -102,9 +102,10 @@ public class TableBody extends FObj {
                 getParent().removeChild(this);
             }
         }
+        /*
         if (tableCellsFound) {
             convertCellsToRows();
-        }
+        }*/
         savedPropertyList = null; //Release reference
     }
 
@@ -148,7 +149,7 @@ public class TableBody extends FObj {
      */
     private void convertCellsToRows() throws FOPException {
         //getLogger().debug("Converting cells to rows...");
-        List cells = (List)childNodes.clone();
+        List cells = new java.util.ArrayList(childNodes);
         childNodes.clear();
         Iterator i = cells.iterator();
         TableRow row = null;
index 6466da45393f5f0f8bf35e2283e88f174ed385ae..dcc7a0a4c0c4599a27cc81479841075a80c7abbf 100644 (file)
@@ -156,6 +156,7 @@ public class TableCell extends FObj {
         if (!blockItemFound) {
             missingChildElementError("marker* (%block;)+");
         }
+        //TODO Complain about startsRow|endsRow=true if parent is a table-row
         getFOEventHandler().endCell(this);
     }
 
index 4a0b7d037e9d3366c77e3cc5579ae045431f25bc..2f8bf5ada31a2005e49bd83ac48a90ea5406526a 100644 (file)
@@ -137,13 +137,16 @@ public class TableColumn extends FObj {
         return columnNumber.getValue();
     }
 
-    /**
-     * @return value for number of columns repeated
-     */
+    /** @return value for number-columns-repeated. */
     public int getNumberColumnsRepeated() {
         return numberColumnsRepeated.getValue();
     }
     
+    /** @return value for number-columns-spanned. */
+    public int getNumberColumnsSpanned() {
+        return numberColumnsSpanned.getValue();
+    }
+    
     /** @see org.apache.fop.fo.FONode#getName() */
     public String getName() {
         return "fo:table-column";
@@ -153,5 +156,21 @@ public class TableColumn extends FObj {
     public int getNameId() {
         return FO_TABLE_COLUMN;
     }
+    
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("fo:table-column");
+        if (hasColumnNumber()) {
+            sb.append(" column-number=").append(getColumnNumber());
+        }
+        if (getNumberColumnsRepeated() > 1) {
+            sb.append(" number-columns-repeated=").append(getNumberColumnsRepeated());
+        }
+        if (getNumberColumnsSpanned() > 1) {
+            sb.append(" number-columns-spanned=").append(getNumberColumnsSpanned());
+        }
+        sb.append(" column-width=").append(getColumnWidth());
+        return sb.toString();
+    }
 }
 
index 858bad1858ebf63c2a03798cc9ffe975d4dc41bd..fbf5cc4aed941dc8bbbbe6e1d158765f922a8857 100644 (file)
@@ -245,7 +245,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
         
         addKnuthElementForBorderPaddingBefore(returnList, returnPosition, 
                 fobj.getCommonBorderPaddingBackground());
-
+        
         while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
             LayoutContext childLC = new LayoutContext(0);
             if (curLM instanceof LineLayoutManager) {
@@ -314,11 +314,11 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
                         // a penalty
                     }
                 }
-                contentList.addAll(returnedList);
                 if (returnedList.size() == 0) {
                     //Avoid NoSuchElementException below (happens with empty blocks)
                     continue;
                 }
+                contentList.addAll(returnedList);
                 if (((KnuthElement) returnedList.getLast()).isPenalty()
                         && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
                     // a descendant of this block has break-after
@@ -340,6 +340,11 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
 
                     return returnList;
                 }
+                /*
+                if (allocatedSpace.min > context.getStackLimit().max) {
+                    log.debug("Allocated space exceeds stack limit, returning early.");
+                    return returnList;
+                }*/
             }
             prevLM = curLM;
         }
@@ -1169,8 +1174,12 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
         boolean bSpaceAfter = false;
         while (parentIter.hasNext()) {
             pos = (Position) parentIter.next();
-            /* LF *///System.out.println("pos = " + pos.getClass().getName());
-            Position innerPosition = ((NonLeafPosition) pos).getPosition();
+            //log.trace("pos = " + pos.getClass().getName() + "; " + pos);
+            Position innerPosition = pos;
+            if (pos instanceof NonLeafPosition) {
+                //Not all elements are wrapped
+                innerPosition = ((NonLeafPosition) pos).getPosition();
+            }
             if (innerPosition == null) {
                 // pos was created by this BlockLM and was inside an element
                 // representing space before or after
@@ -1178,24 +1187,23 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
                 if (positionList.size() == 0) {
                     // pos was in the element representing space-before
                     bSpaceBefore = true;
-                    /* LF *///System.out.println(" spazio prima");
+                    //log.trace(" space before");
                 } else {
                     // pos was in the element representing space-after
                     bSpaceAfter = true;
-                    /* LF *///System.out.println(" spazio dopo");
+                    //log.trace(" space-after");
                 }
             } else if (innerPosition.getLM() == this
                     && !(innerPosition instanceof MappingPosition)) {
                 // pos was created by this BlockLM and was inside a penalty
                 // allowing or forbidding a page break
                 // nothing to do
-                /* LF *///System.out.println(" penalty");
+                //log.trace(" penalty");
             } else {
                 // innerPosition was created by another LM
                 positionList.add(innerPosition);
                 lastLM = innerPosition.getLM();
-                /* LF *///System.out.println(" " +
-                      // innerPosition.getClass().getName());
+                //log.trace(" " + innerPosition.getClass().getName());
             }
         }
 
index a08c7bf55eb06241c21432a1a29d5a800654fdea..af13de9d2763755d5d3649a4a25748818e7d7aa0 100644 (file)
@@ -367,10 +367,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
         while (listIter.hasNext()) {
             KnuthElement tempElement;
             tempElement = (KnuthElement) listIter.next();
-            //if (tempElement.getLayoutManager() != this) {
-            tempElement.setPosition(new NonLeafPosition(this,
-                    tempElement.getPosition()));
-            //}
+            if (tempElement.getLayoutManager() != this) {
+                tempElement.setPosition(new NonLeafPosition(this,
+                        tempElement.getPosition()));
+            }
             targetList.add(tempElement);
         }
     }
index a608b70072fb9f7d731da4d1ea09c26b9e128d38..db5ce5a2afbbf28093eba1e76abc710bc44341e5 100644 (file)
@@ -18,7 +18,6 @@
 
 package org.apache.fop.layoutmgr;
 
-import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.flow.Marker;
 import org.apache.fop.fo.pagination.Flow;
 import org.apache.fop.area.Area;
@@ -152,13 +151,33 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
     }*/
 
 
+    /**
+     * "wrap" the Position inside each element moving the elements from 
+     * SourceList to targetList
+     * @param sourceList source list
+     * @param targetList target list receiving the wrapped position elements
+     */
+    protected void wrapPositionElements(List sourceList, List targetList) {
+        ListIterator listIter = sourceList.listIterator();
+        while (listIter.hasNext()) {
+            KnuthElement tempElement;
+            tempElement = (KnuthElement) listIter.next();
+            //if (tempElement.getLayoutManager() != this) {
+            tempElement.setPosition(new NonLeafPosition(this,
+                    tempElement.getPosition()));
+            //}
+            targetList.add(tempElement);
+        }
+    }
+
+    
 //TODO Reintroduce emergency counter (generate error to avoid endless loop)
 //TODO Reintroduce layout dimensions
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         // currently active LM
         BlockLevelLayoutManager curLM;
         BlockLevelLayoutManager prevLM = null;
-        MinOptMax stackSize = new MinOptMax();
+        //MinOptMax stackSize = new MinOptMax();
         LinkedList returnedList;
         LinkedList returnList = new LinkedList();
 
@@ -170,29 +189,20 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
             }
 
             // Set up a LayoutContext
-            MinOptMax bpd = context.getStackLimit();
-            BreakPoss bp;
-            bp = null;
+            //MinOptMax bpd = context.getStackLimit();
 
             LayoutContext childLC = new LayoutContext(0);
-            boolean breakPage = false;
-            childLC.setStackLimit(MinOptMax.subtract(bpd, stackSize));
+            childLC.setStackLimit(context.getStackLimit());
             childLC.setRefIPD(context.getRefIPD());
 
             // get elements from curLM
             returnedList = curLM.getNextKnuthElements(childLC, alignment);
-/*LF*/      //System.out.println("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
+            //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
 
             // "wrap" the Position inside each element
             LinkedList tempList = returnedList;
-            KnuthElement tempElement;
             returnedList = new LinkedList();
-            ListIterator listIter = tempList.listIterator();
-            while (listIter.hasNext()) {
-                tempElement = (KnuthElement)listIter.next();
-                tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
-                returnedList.add(tempElement);
-            }
+            wrapPositionElements(tempList, returnedList);
 
             if (returnedList.size() == 1
                 && ((KnuthElement)returnedList.getFirst()).isPenalty()
@@ -235,31 +245,31 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
     }
 
     public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
-/*LF*/  System.out.println(" FLM.negotiateBPDAdjustment> " + adj);
+        log.debug(" FLM.negotiateBPDAdjustment> " + adj);
 
-/*LF*/  if (lastElement.getPosition() instanceof NonLeafPosition) {
+        if (lastElement.getPosition() instanceof NonLeafPosition) {
             // this element was not created by this FlowLM
             NonLeafPosition savedPos = (NonLeafPosition)lastElement.getPosition();
             lastElement.setPosition(savedPos.getPosition());
             int returnValue = ((BlockLevelLayoutManager) lastElement.getLayoutManager()).negotiateBPDAdjustment(adj, lastElement);
             lastElement.setPosition(savedPos);
-/*LF*/      System.out.println(" FLM.negotiateBPDAdjustment> gestito " + returnValue);
+            log.debug(" FLM.negotiateBPDAdjustment> result " + returnValue);
             return returnValue;
-/*LF*/  } else {
-/*LF*/      return 0;
-/*LF*/  }
+        } else {
+            return 0;
+        }
     }
 
     public void discardSpace(KnuthGlue spaceGlue) {
-/*LF*/  System.out.println(" FLM.discardSpace> ");
+        log.debug(" FLM.discardSpace> ");
 
-/*LF*/  if (spaceGlue.getPosition() instanceof NonLeafPosition) {
+        if (spaceGlue.getPosition() instanceof NonLeafPosition) {
             // this element was not created by this FlowLM
             NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
             spaceGlue.setPosition(savedPos.getPosition());
             ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
             spaceGlue.setPosition(savedPos);
-/*LF*/  }
+        }
     }
 
     public boolean mustKeepTogether() {
index 85bc59c9646999a5d1ddc5b59d7dd9ba49d9cae9..ae7be8cba7dcb6560f5b4803b2d00cefe532cbb7 100644 (file)
@@ -114,12 +114,12 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
                    new PageNumberCitationLayoutManagerMaker());
         makers.put(PageSequence.class, new PageSequenceLayoutManagerMaker());
         makers.put(Table.class, new TableLayoutManagerMaker());
-        makers.put(TableBody.class, new TableBodyLayoutManagerMaker());
-        makers.put(TableColumn.class, new TableColumnLayoutManagerMaker());
-        makers.put(TableRow.class, new TableRowLayoutManagerMaker());
-        makers.put(TableCell.class, new TableCellLayoutManagerMaker());
-        makers.put(TableFooter.class, new TableBodyLayoutManagerMaker());
-        makers.put(TableHeader.class, new TableBodyLayoutManagerMaker());
+        makers.put(TableBody.class, new /*TableBodyLayoutManager*/Maker());
+        makers.put(TableColumn.class, new /*TableColumnLayoutManager*/Maker());
+        makers.put(TableRow.class, new /*TableRowLayoutManager*/Maker());
+        makers.put(TableCell.class, new /*TableCellLayoutManager*/Maker());
+        makers.put(TableFooter.class, new /*TableBodyLayoutManager*/Maker());
+        makers.put(TableHeader.class, new /*TableBodyLayoutManager*/Maker());
         makers.put(Flow.class, new FlowLayoutManagerMaker());
         makers.put(StaticContent.class, new StaticContentLayoutManagerMaker());
         makers.put(Wrapper.class, new WrapperLayoutManagerMaker());
@@ -313,6 +313,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
 
     public static class TableLayoutManagerMaker extends Maker {
         
+        /*
         private List getColumnLayoutManagerList(Table table, TableLayoutManager tlm) {
             List columnLMs = null;
             List columns = table.getColumns();
@@ -347,19 +348,21 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
                 }
             }
             return columnLMs;
-        }
+        }*/
         
         public void make(FONode node, List lms) {
             Table table = (Table) node;
             TableLayoutManager tlm = new TableLayoutManager(table);
+            /*
             List columnLMs = getColumnLayoutManagerList(table, tlm);
             if (columnLMs != null) {
                 tlm.setColumns(columnLMs);
-            }
+            }*/
             lms.add(tlm);
         }
     }
-        
+     
+    /*
     public static class TableBodyLayoutManagerMaker extends Maker {
          public void make(FONode node, List lms) {
              lms.add(new Body((TableBody) node));
@@ -383,7 +386,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
         public void make(FONode node, List lms) {
             lms.add(new Cell((TableCell) node));
         }
-    }
+    }*/
 
     public static class FlowLayoutManagerMaker extends Maker {
          public void make(FONode node, List lms) {
index dbdf10b0af72acb4fbd5599b3abafce307b8b959..29af1f69c4e08d34cb38e56bd3ad778d46b5333a 100644 (file)
  
 package org.apache.fop.layoutmgr.table;
 
+import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.fop.fo.flow.TableBody;
+import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
 import org.apache.fop.layoutmgr.LeafPosition;
 import org.apache.fop.layoutmgr.BreakPoss;
 import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.BreakPossPosIter;
 import org.apache.fop.layoutmgr.Position;
@@ -39,7 +45,7 @@ import org.apache.fop.traits.MinOptMax;
  * These fo objects have either rows or cells underneath.
  * Cells are organised into rows.
  */
-public class Body extends BlockStackingLayoutManager {
+public class Body extends BlockStackingLayoutManager implements BlockLevelLayoutManager {
     private TableBody fobj;
     
     private List columns;
@@ -75,6 +81,99 @@ public class Body extends BlockStackingLayoutManager {
         columns = cols;
     }
 
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
+     */
+    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+        LayoutContext childLC = new LayoutContext(0);
+        childLC.setStackLimit(context.getStackLimit());
+        childLC.setRefIPD(context.getRefIPD());
+
+        LinkedList returnedList = null;
+        LinkedList contentList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        Position returnPosition = new NonLeafPosition(this, null);
+        
+        Row curLM; // currently active LM
+        Row prevLM = null; // previously active LM
+        while ((curLM = (Row)getChildLM()) != null) {
+
+            // get elements from curLM
+            returnedList = curLM.getNextKnuthElements(childLC, alignment);
+            /*
+            if (returnedList.size() == 1
+                    && ((KnuthElement) returnedList.getFirst()).isPenalty()
+                    && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+                // a descendant of this block has break-before
+                if (returnList.size() == 0) {
+                    // the first child (or its first child ...) has
+                    // break-before;
+                    // all this block, including space before, will be put in
+                    // the
+                    // following page
+                    bSpaceBeforeServed = false;
+                }
+                contentList.addAll(returnedList);
+
+                // "wrap" the Position inside each element
+                // moving the elements from contentList to returnList
+                returnedList = new LinkedList();
+                wrapPositionElements(contentList, returnList);
+
+                return returnList;
+            } else*/ {
+                if (prevLM != null) {
+                    // there is a block handled by prevLM
+                    // before the one handled by curLM
+                    if (mustKeepTogether() 
+                            || prevLM.mustKeepWithNext()
+                            || curLM.mustKeepWithPrevious()) {
+                        // add an infinite penalty to forbid a break between
+                        // blocks
+                        contentList.add(new KnuthPenalty(0,
+                                KnuthElement.INFINITE, false,
+                                new Position(this), false));
+                    } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+                        // add a null penalty to allow a break between blocks
+                        contentList.add(new KnuthPenalty(0, 0, false,
+                                new Position(this), false));
+                    } else {
+                        // the last element in contentList is a glue;
+                        // it is a feasible breakpoint, there is no need to add
+                        // a penalty
+                    }
+                }
+                contentList.addAll(returnedList);
+                if (returnedList.size() == 0) {
+                    //Avoid NoSuchElementException below (happens with empty blocks)
+                    continue;
+                }
+                if (((KnuthElement) returnedList.getLast()).isPenalty()
+                        && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+                    // a descendant of this block has break-after
+                    if (curLM.isFinished()) {
+                        // there is no other content in this block;
+                        // it's useless to add space after before a page break
+                        setFinished(true);
+                    }
+
+                    returnedList = new LinkedList();
+                    wrapPositionElements(contentList, returnList);
+
+                    return returnList;
+                }
+            }
+            prevLM = curLM;
+        }
+
+        setFinished(true);
+        if (returnList.size() > 0) {
+            return returnList;
+        } else {
+            return null;
+        }
+    }
+    
     /**
      * Breaks for this layout manager are of the form of before
      * or after a row and inside a row.
@@ -82,7 +181,7 @@ public class Body extends BlockStackingLayoutManager {
      * @param context the layout context for finding the breaks
      * @return the next break possibility
      */
-    public BreakPoss getNextBreakPoss(LayoutContext context) {
+    public BreakPoss getNextBreakPossOLDOLDOLD(LayoutContext context) {
         Row curLM; // currently active LM
 
         MinOptMax stackSize = new MinOptMax();
@@ -266,5 +365,41 @@ public class Body extends BlockStackingLayoutManager {
         return curBlockArea;
     }
 
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
+     */
+    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(org.apache.fop.layoutmgr.KnuthGlue)
+     */
+    public void discardSpace(KnuthGlue spaceGlue) {
+        // TODO Auto-generated method stub
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+     */
+    public boolean mustKeepTogether() {
+        return ((BlockLevelLayoutManager)getParent()).mustKeepTogether();
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+     */
+    public boolean mustKeepWithPrevious() {
+        return false;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+     */
+    public boolean mustKeepWithNext() {
+        return false;
+    }
+
 }
 
index 5a68aeb663999ffafd721da4ed150c048a12cb65..07e07f7cb0e55432bec5ec4dc8d3b927e8eca2fe 100644 (file)
@@ -23,12 +23,18 @@ import org.apache.fop.fo.flow.Table;
 import org.apache.fop.fo.flow.TableCell;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.layoutmgr.AreaAdditionUtil;
+import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.LeafPosition;
 import org.apache.fop.layoutmgr.BreakPoss;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.MinOptMaxUtil;
+import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.BreakPossPosIter;
 import org.apache.fop.layoutmgr.Position;
@@ -39,14 +45,17 @@ import org.apache.fop.area.Trait;
 import org.apache.fop.traits.MinOptMax;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
  * LayoutManager for a table-cell FO.
  * A cell contains blocks. These blocks fill the cell.
  */
-public class Cell extends BlockStackingLayoutManager {
+public class Cell extends BlockStackingLayoutManager implements BlockLevelLayoutManager {
+    
     private TableCell fobj;
+    private PrimaryGridUnit gridUnit;
     
     private Block curBlockArea;
 
@@ -65,16 +74,17 @@ public class Cell extends BlockStackingLayoutManager {
     private int borderAndPaddingBPD;
     private boolean emptyCell = true;
 
-    /** List of Lists containing GridUnit instances, one List per row. */
+    /** List of Lists containing OldGridUnit instances, one List per row. */
     private List rows = new java.util.ArrayList(); 
     
     /**
      * Create a new Cell layout manager.
      * @node table-cell FO for which to create the LM
      */
-    public Cell(TableCell node) {
+    public Cell(TableCell node, PrimaryGridUnit pgu) {
         super(node);
         fobj = node;
+        this.gridUnit = pgu;
     }
 
     /** @return the table-cell FO */
@@ -126,10 +136,10 @@ public class Cell extends BlockStackingLayoutManager {
         for (int i = 0; i < rows.size(); i++) {
             List gridUnits = (List)rows.get(i);
             startBorderWidth = Math.max(startBorderWidth, 
-                    ((GridUnit)gridUnits.get(0)).
+                    ((OldGridUnit)gridUnits.get(0)).
                         effBorders.getBorderStartWidth(false));
             endBorderWidth = Math.max(endBorderWidth, 
-                    ((GridUnit)gridUnits.get(gridUnits.size() - 1)).
+                    ((OldGridUnit)gridUnits.get(gridUnits.size() - 1)).
                         effBorders.getBorderEndWidth(false));
         }
         //iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
@@ -144,6 +154,111 @@ public class Cell extends BlockStackingLayoutManager {
         return iIndents;
     }
     
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
+     */
+    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+        MinOptMax stackSize = new MinOptMax();
+        MinOptMax stackLimit = new MinOptMax(context.getStackLimit());
+
+        BreakPoss lastPos = null;
+
+        referenceIPD = context.getRefIPD(); 
+        cellIPD = referenceIPD;
+        cellIPD -= getIPIndents();
+        if (fobj.isSeparateBorderModel()) {
+            int borderSep = fobj.getBorderSeparation().getLengthPair()
+                    .getIPD().getLength().getValue();
+            cellIPD -= borderSep;
+        }
+
+        LinkedList returnedList = null;
+        LinkedList contentList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        Position returnPosition = new NonLeafPosition(this, null);
+
+        BlockLevelLayoutManager curLM; // currently active LM
+        BlockLevelLayoutManager prevLM = null; // previously active LM
+        while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
+            LayoutContext childLC = new LayoutContext(0);
+            // curLM is a ?
+            childLC.setStackLimit(MinOptMax.subtract(context
+                    .getStackLimit(), stackLimit));
+            childLC.setRefIPD(cellIPD);
+
+            // get elements from curLM
+            returnedList = curLM.getNextKnuthElements(childLC, alignment);
+            if (returnedList.size() == 1
+                    && ((KnuthElement) returnedList.getFirst()).isPenalty()
+                    && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+                // a descendant of this block has break-before
+                if (returnList.size() == 0) {
+                    // the first child (or its first child ...) has
+                    // break-before;
+                    // all this block, including space before, will be put in
+                    // the
+                    // following page
+                }
+                contentList.addAll(returnedList);
+
+                // "wrap" the Position inside each element
+                // moving the elements from contentList to returnList
+                returnedList = new LinkedList();
+                wrapPositionElements(contentList, returnList);
+
+                return returnList;
+            } else {
+                if (prevLM != null) {
+                    // there is a block handled by prevLM
+                    // before the one handled by curLM
+                    if (mustKeepTogether() 
+                            || prevLM.mustKeepWithNext()
+                            || curLM.mustKeepWithPrevious()) {
+                        // add an infinite penalty to forbid a break between
+                        // blocks
+                        contentList.add(new KnuthPenalty(0,
+                                KnuthElement.INFINITE, false,
+                                new Position(this), false));
+                    } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+                        // add a null penalty to allow a break between blocks
+                        contentList.add(new KnuthPenalty(0, 0, false,
+                                new Position(this), false));
+                    } else {
+                        // the last element in contentList is a glue;
+                        // it is a feasible breakpoint, there is no need to add
+                        // a penalty
+                    }
+                }
+                contentList.addAll(returnedList);
+                if (returnedList.size() == 0) {
+                    //Avoid NoSuchElementException below (happens with empty blocks)
+                    continue;
+                }
+                if (((KnuthElement) returnedList.getLast()).isPenalty()
+                        && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+                    // a descendant of this block has break-after
+                    if (curLM.isFinished()) {
+                        // there is no other content in this block;
+                        // it's useless to add space after before a page break
+                        setFinished(true);
+                    }
+
+                    returnedList = new LinkedList();
+                    wrapPositionElements(contentList, returnList);
+
+                    return returnList;
+                }
+            }
+            prevLM = curLM;
+        }
+
+        returnedList = new LinkedList();
+        wrapPositionElements(contentList, returnList);
+        
+        setFinished(true);
+        return returnList;
+    }
+    
     /**
      * Get the next break possibility for this cell.
      * A cell contains blocks so there are breaks around the blocks
@@ -152,7 +267,7 @@ public class Cell extends BlockStackingLayoutManager {
      * @param context the layout context
      * @return the next break possibility
      */
-    public BreakPoss getNextBreakPoss(LayoutContext context) {
+    public BreakPoss getNextBreakPossOLDOLDOLD(LayoutContext context) {
         LayoutManager curLM; // currently active LM
 
         MinOptMax stackSize = new MinOptMax();
@@ -291,8 +406,8 @@ public class Cell extends BlockStackingLayoutManager {
     public void addAreas(PositionIterator parentIter,
                          LayoutContext layoutContext) {
         getParentArea(null);
-        BreakPoss bp1 = (BreakPoss)parentIter.peekNext();
-        bBogus = !bp1.generatesAreas(); 
+        //BreakPoss bp1 = (BreakPoss)parentIter.peekNext();
+        bBogus = false;//!bp1.generatesAreas(); 
 
         if (!isBogus()) {
             addID(fobj.getId());
@@ -310,7 +425,7 @@ public class Cell extends BlockStackingLayoutManager {
             if (rows.size() == 1 && ((List)rows.get(0)).size() == 1) {
                 //Can set the borders directly if there's no span
                 CommonBorderPaddingBackground effBorders =
-                    ((GridUnit)((List)rows.get(0)).get(0)).effBorders;
+                    ((OldGridUnit)((List)rows.get(0)).get(0)).effBorders;
                 //TODO Next line is a temporary hack!
                 TraitSetter.addCollapsingBorders(curBlockArea, 
                         fobj.getCommonBorderPaddingBackground(), outer);
@@ -323,7 +438,7 @@ public class Cell extends BlockStackingLayoutManager {
                     int dx = xoffset;
                     int lastRowHeight = 0;
                     for (int x = 0; x < gridUnits.size(); x++) {
-                        GridUnit gu = (GridUnit)gridUnits.get(x);
+                        OldGridUnit gu = (OldGridUnit)gridUnits.get(x);
                         if (!gu.effBorders.hasBorder()) {
                             continue;
                         }
@@ -364,9 +479,21 @@ public class Cell extends BlockStackingLayoutManager {
             }
         }
 
+        AreaAdditionUtil.addAreas(parentIter, layoutContext);
+        /*
         LayoutManager childLM;
         int iStartPos = 0;
         LayoutContext lc = new LayoutContext(0);
+        PositionIterator childPosIter;
+        childPosIter = new StackingIter(positionList.listIterator());
+        while ((childLM = childPosIter.getNextChildLM()) != null) {
+            // set last area flag
+            lc.setFlags(LayoutContext.LAST_AREA,
+                    (layoutContext.isLastArea() && childLM == lastLM));
+            lc.setStackLimit(layoutContext.getStackLimit());
+            // Add the line areas to Area
+            childLM.addAreas(childPosIter, lc);
+        }
         while (parentIter.hasNext()) {
             LeafPosition lfp = (LeafPosition) parentIter.next();
             // Add the block areas to Area
@@ -377,7 +504,7 @@ public class Cell extends BlockStackingLayoutManager {
             while ((childLM = breakPosIter.getNextChildLM()) != null) {
                 childLM.addAreas(breakPosIter, lc);
             }
-        }
+        }*/
 
         
         int contentBPD = rowHeight;
@@ -461,5 +588,52 @@ public class Cell extends BlockStackingLayoutManager {
         }
     }
 
+    /* (non-Javadoc)
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
+     */
+    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(org.apache.fop.layoutmgr.KnuthGlue)
+     */
+    public void discardSpace(KnuthGlue spaceGlue) {
+        // TODO Auto-generated method stub
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+     */
+    public boolean mustKeepTogether() {
+        //TODO Keeps will have to be more sophisticated sooner or later
+        return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()/* 
+                || !fobj.getKeepTogether().getWithinPage().isAuto()
+                || !fobj.getKeepTogether().getWithinColumn().isAuto()*/;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+     */
+    public boolean mustKeepWithPrevious() {
+        return false; //TODO FIX ME
+        /*
+        return !fobj.getKeepWithPrevious().getWithinPage().isAuto()
+            || !fobj.getKeepWithPrevious().getWithinColumn().isAuto();
+            */
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+     */
+    public boolean mustKeepWithNext() {
+        return false; //TODO FIX ME
+        /*
+        return !fobj.getKeepWithNext().getWithinPage().isAuto()
+            || !fobj.getKeepWithNext().getWithinColumn().isAuto();
+            */
+    }
+
 }
 
index 18999f0553d4826b56db91375c1138ca4a04f655..44ab65510415e09450b86fb93acab18d311f3b57 100644 (file)
@@ -116,6 +116,6 @@ public abstract class CollapsingBorderModel {
      * @return the winning BorderInfo
      */
     public abstract BorderInfo determineWinner(
-            GridUnit current, GridUnit neighbour, int side, int flags);
+            OldGridUnit current, OldGridUnit neighbour, int side, int flags);
     
 }
index e3e61033a8fd8b6daf722eb6b78c3b0de2d56e69..ea54d153c5e8c1f9598f7f071be26b401a2fecf9 100644 (file)
@@ -34,8 +34,8 @@ public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel {
     private static final int START = CommonBorderPaddingBackground.START;
     private static final int END = CommonBorderPaddingBackground.END;
     
-    public BorderInfo determineWinner(GridUnit currentGridUnit, 
-            GridUnit otherGridUnit, int side, int flags) {
+    public BorderInfo determineWinner(OldGridUnit currentGridUnit, 
+            OldGridUnit otherGridUnit, int side, int flags) {
         final boolean vertical = isVerticalRelation(side);
         final int otherSide = getOtherSide(side);
         
diff --git a/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java b/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
new file mode 100644 (file)
index 0000000..1d436d0
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.flow.TableColumn;
+
+/**
+ * Class holding a number of columns making up the column setup of a row.
+ */
+public class ColumnSetup {
+
+    /** Logger **/
+    private static Log log = LogFactory.getLog(ColumnSetup.class);
+
+    private Table table;
+    private List columns = new java.util.ArrayList();
+    private int maxColIndexReferenced = 0;
+    
+    public ColumnSetup(Table table) {
+        this.table = table;
+        prepareExplicitColumns();
+        if (getColumnCount() == 0) {
+            createColumnsFromFirstRow();
+        }
+    }
+    
+    private void prepareExplicitColumns() {
+        List rawCols = table.getColumns();
+        if (rawCols != null) {
+            int colnum = 1;
+            ListIterator iter = rawCols.listIterator();
+            while (iter.hasNext()) {
+                TableColumn col = (TableColumn)iter.next();
+                if (col.hasColumnNumber()) {
+                    colnum = col.getColumnNumber();
+                }
+                for (int i = 0; i < col.getNumberColumnsRepeated(); i++) {
+                    while (colnum > columns.size()) {
+                        columns.add(null);
+                    }
+                    columns.set(colnum - 1, col);
+                    colnum++;
+                }
+            }
+            //Post-processing the list (looking for gaps)
+            int pos = 1;
+            ListIterator ppIter = columns.listIterator();
+            while (ppIter.hasNext()) {
+                TableColumn col = (TableColumn)ppIter.next();
+                if (col == null) {
+                    log.error("Found a gap in the table-columns at position " + pos);
+                }
+                pos++;
+            }
+        }
+    }
+
+    public TableColumn getColumn(int index) {
+        int size = columns.size();
+        if (index > size - 1) {
+            maxColIndexReferenced = index;
+            return (TableColumn)columns.get(size - 1);
+        } else {
+            return (TableColumn)columns.get(index - 1);
+        }
+    }
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        return columns.toString();
+    }
+
+    /** @return the number of columns in the setup. */
+    public int getColumnCount() {
+        if (maxColIndexReferenced > columns.size()) {
+            return maxColIndexReferenced;
+        } else {
+            return columns.size();
+        }
+   }
+    
+    /** @return an Iterator over all columns */
+    public Iterator iterator() {
+        return this.columns.iterator();
+    }
+    
+    private void createColumnsFromFirstRow() {
+        //TODO Create oldColumns from first row here 
+        //--> rule 2 in "fixed table layout", see CSS2, 17.5.2
+        //Alternative: extend oldColumns on-the-fly, but in this case we need the
+        //new property evaluation context so proportional-column-width() works
+        //correctly.
+        if (columns.size() == 0) {
+            this.columns.add(table.getDefaultColumn());
+        }
+    }
+
+    /**
+     * @param col column index (1 is first column)
+     * @return the X offset of the requested column
+     */
+    public int getXOffset(int col) {
+        int xoffset = 0;
+        for (int i = 1; i < col; i++) {
+            xoffset += getColumn(i).getColumnWidth().getValue();
+        }
+        return xoffset;
+    }
+
+}
index e89f9d8ec03e306e7e1419c4078db3d4f7a520d8..7f7b738cb10fc4f3533440c330c6c00b2ad33bac 100644 (file)
 
 package org.apache.fop.layoutmgr.table;
 
+import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.flow.Table;
-import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
-import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
-
+import org.apache.fop.fo.flow.TableBody;
+import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.flow.TableColumn;
+import org.apache.fop.fo.flow.TableRow;
 
+/**
+ * This class represents one grid unit inside a table.
+ */
 public class GridUnit {
+
+    /** Table cell which occupies this grid unit */
+    private TableCell cell;
+    /** Table column that this grid unit belongs to */
+    private TableColumn column;
     
-    /** layout manager for the cell occupying this grid unit, may be null */
-    public Cell layoutManager;
-    /** layout manager for the column that this grid unit belongs to */
-    public Column column;
-    /** layout manager for the row that this grid unit belongs to */
-    public Row row;
+    /** start index of grid unit within row in column direction */
+    private int startCol;
     /** index of grid unit within cell in column direction */
-    public int colSpanIndex;
+    private int colSpanIndex;
     /** index of grid unit within cell in row direction */
-    public int rowSpanIndex;
-    /** effective borders for a cell slot (used for collapsing border model) */
-    public CommonBorderPaddingBackground effBorders;
+    private int rowSpanIndex;
     
-    public GridUnit(Cell layoutManager, int colSpanIndex) {
-        this.layoutManager = layoutManager;
+    
+    public GridUnit(TableCell cell, TableColumn column, int startCol, int colSpanIndex) {
+        this.cell = cell;
+        this.column = column;
+        this.startCol = startCol;
         this.colSpanIndex = colSpanIndex;
-        this.rowSpanIndex = 0;
     }
     
-    public GridUnit(Cell layoutManager) {
-        this(layoutManager, 0);
+    public TableCell getCell() {
+        return this.cell;
     }
-
-    /** @return true if the grid unit is the primary of a cell */
-    public boolean isPrimaryGridUnit() {
-        return (colSpanIndex == 0) && (rowSpanIndex == 0);
+    
+    public TableColumn getColumn() {
+        return this.column;
     }
     
-    /** @return true if the grid unit is the last in column spanning direction */
-    public boolean isLastGridUnitColSpan() {
-        if (layoutManager != null) {
-            return (colSpanIndex == layoutManager.getFObj().getNumberColumnsSpanned() - 1);
+    public TableRow getRow() {
+        if (getCell().getParent() instanceof TableRow) {
+            return (TableRow)getCell().getParent();
         } else {
-            return true;
+            return null;
         }
     }
     
-    /** @return true if the grid unit is the last in column spanning direction */
-    public boolean isLastGridUnitRowSpan() {
-        if (layoutManager != null) {
-            return (rowSpanIndex == layoutManager.getFObj().getNumberRowsSpanned() - 1);
-        } else {
-            return true;
+    public TableBody getBody() {
+        FONode node = getCell();
+        while (!(node instanceof TableBody)) {
+            node = node.getParent();
         }
+        return (TableBody)node;
     }
     
-    /** @return true if the cell is part of a span in column direction */
-    public boolean isColSpan() {
-        return (colSpanIndex > 0);
-    }
-
-    public BorderInfo getOriginalBorderInfoForCell(int side) {
-        if (layoutManager != null) {
-            return layoutManager.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
-        } else {
-            return null;
+    public Table getTable() {
+        FONode node = getCell();
+        while (!(node instanceof Table)) {
+            node = node.getParent();
         }
+        return (Table)node;
     }
     
-    /**
-     * Assign the borders from the given cell to this cell info. Used in
-     * case of separate border model.
-     * @param current cell to take the borders from
-     */
-    public void assignBorder(Cell current) {
-        if (current != null) {
-            this.effBorders = current.getFObj().getCommonBorderPaddingBackground();
-        }
+    public boolean isPrimary() {
+        return false;
     }
     
-    /**
-     * Assign the borders directly.
-     * @param borders the borders to use
-     */
-    public void assignBorder(CommonBorderPaddingBackground borders) {
-        if (borders != null) {
-            this.effBorders = borders;
-        }
+    public boolean isEmpty() {
+        return this.cell == null;
     }
     
-    /**
-     * Resolve collapsing borders for the given cell and store the resulting
-     * borders in this cell info. Use in case of the collapsing border model.
-     * @param current cell to resolve borders for
-     * @param before cell before the current cell, if any
-     * @param after cell after the current cell, if any
-     * @param start cell preceeding the current cell, if any
-     * @param end cell succeeding of the current cell, if any
-     */
-    public static void resolveBorder(Table table,
-            CommonBorderPaddingBackground target,
-            GridUnit current, GridUnit other, int side) {
-        if (current == null) {
-            return;
+    public int getStartCol() {
+        return this.startCol;
+    }
+    
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        if (isEmpty()) {
+            sb.append("EMPTY");
+        } else if (isPrimary()) {
+            sb.append("Primary");
+        }
+        sb.append("GridUnit:");
+        if (colSpanIndex > 0) {
+            sb.append(" colSpan=").append(colSpanIndex);
+        }
+        if (rowSpanIndex > 0) {
+            sb.append(" rowSpan=").append(rowSpanIndex);
         }
-        
-        CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
-                table.getBorderCollapse());
-        target.setBorderInfo(
-                borderModel.determineWinner(current, other, 
-                        side, 0), side);
+        sb.append(" startCol=").append(startCol);
+        return sb.toString();
     }
     
-}
\ No newline at end of file
+}
diff --git a/src/java/org/apache/fop/layoutmgr/table/OldGridUnit.java b/src/java/org/apache/fop/layoutmgr/table/OldGridUnit.java
new file mode 100644 (file)
index 0000000..4a7021a
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+
+public class OldGridUnit {
+    
+    /** layout manager for the cell occupying this grid unit, may be null */
+    public Cell layoutManager;
+    /** layout manager for the column that this grid unit belongs to */
+    public Column column;
+    /** layout manager for the row that this grid unit belongs to */
+    public Row row;
+    /** index of grid unit within cell in column direction */
+    public int colSpanIndex;
+    /** index of grid unit within cell in row direction */
+    public int rowSpanIndex;
+    /** effective borders for a cell slot (used for collapsing border model) */
+    public CommonBorderPaddingBackground effBorders;
+    
+    public OldGridUnit(Cell layoutManager, int colSpanIndex) {
+        this.layoutManager = layoutManager;
+        this.colSpanIndex = colSpanIndex;
+        this.rowSpanIndex = 0;
+    }
+    
+    public OldGridUnit(Cell layoutManager) {
+        this(layoutManager, 0);
+    }
+
+    /** @return true if the grid unit is the primary of a cell */
+    public boolean isPrimaryGridUnit() {
+        return (colSpanIndex == 0) && (rowSpanIndex == 0);
+    }
+    
+    /** @return true if the grid unit is the last in column spanning direction */
+    public boolean isLastGridUnitColSpan() {
+        if (layoutManager != null) {
+            return (colSpanIndex == layoutManager.getFObj().getNumberColumnsSpanned() - 1);
+        } else {
+            return true;
+        }
+    }
+    
+    /** @return true if the grid unit is the last in column spanning direction */
+    public boolean isLastGridUnitRowSpan() {
+        if (layoutManager != null) {
+            return (rowSpanIndex == layoutManager.getFObj().getNumberRowsSpanned() - 1);
+        } else {
+            return true;
+        }
+    }
+    
+    /** @return true if the cell is part of a span in column direction */
+    public boolean isColSpan() {
+        return (colSpanIndex > 0);
+    }
+
+    public BorderInfo getOriginalBorderInfoForCell(int side) {
+        if (layoutManager != null) {
+            return layoutManager.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Assign the borders from the given cell to this cell info. Used in
+     * case of separate border model.
+     * @param current cell to take the borders from
+     */
+    public void assignBorder(Cell current) {
+        if (current != null) {
+            this.effBorders = current.getFObj().getCommonBorderPaddingBackground();
+        }
+    }
+    
+    /**
+     * Assign the borders directly.
+     * @param borders the borders to use
+     */
+    public void assignBorder(CommonBorderPaddingBackground borders) {
+        if (borders != null) {
+            this.effBorders = borders;
+        }
+    }
+    
+    /**
+     * Resolve collapsing borders for the given cell and store the resulting
+     * borders in this cell info. Use in case of the collapsing border model.
+     * @param current cell to resolve borders for
+     * @param before cell before the current cell, if any
+     * @param after cell after the current cell, if any
+     * @param start cell preceeding the current cell, if any
+     * @param end cell succeeding of the current cell, if any
+     */
+    public static void resolveBorder(Table table,
+            CommonBorderPaddingBackground target,
+            OldGridUnit current, OldGridUnit other, int side) {
+        if (current == null) {
+            return;
+        }
+        
+        CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
+                table.getBorderCollapse());
+        target.setBorderInfo(
+                borderModel.determineWinner(current, other, 
+                        side, 0), side);
+    }
+    
+}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/table/PrimaryGridUnit.java b/src/java/org/apache/fop/layoutmgr/table/PrimaryGridUnit.java
new file mode 100644 (file)
index 0000000..eb9dd38
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import java.util.LinkedList;
+
+import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.flow.TableColumn;
+
+/**
+ * This class represents a primary grid unit of a spanned cell.
+ */
+public class PrimaryGridUnit extends GridUnit {
+
+    private Cell cellLM;
+    private LinkedList elements;
+    /** index of row where this cell starts */
+    private int startRow;
+
+    
+    public PrimaryGridUnit(TableCell cell, TableColumn column, int startCol, int startRow) {
+        super(cell, column, startCol, 0);
+        this.startRow = startRow;
+        if (cell != null) {
+            cellLM = new Cell(cell, this);
+        }
+    }
+    
+    public Cell getCellLM() {
+        return cellLM;
+    }
+    
+    public boolean isPrimary() {
+        return true;
+    }
+    
+    public void setElements(LinkedList elements) {
+        this.elements = elements;
+    }
+    
+    public LinkedList getElements() {
+        return this.elements;
+    }
+    
+    public int getStartRow() {
+        return this.startRow;
+    }
+
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        sb.append(" startRow=").append(startRow);
+        return sb.toString();
+    }
+    
+}
index c3d06d435bc13fae80269cd817546bc66b6fe091..fb615c194ff791e59c177b7a4c24621093980d9a 100644 (file)
@@ -25,7 +25,10 @@ import org.apache.fop.fo.flow.TableCell;
 import org.apache.fop.fo.flow.TableRow;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.LeafPosition;
 import org.apache.fop.layoutmgr.BreakPoss;
@@ -52,7 +55,7 @@ import java.util.ListIterator;
  * If there are row spanning cells then these cells belong to this row
  * but effect the occupied columns of future rows.
  */
-public class Row extends BlockStackingLayoutManager {
+public class Row extends BlockStackingLayoutManager implements BlockLevelLayoutManager {
     
     private TableRow fobj;
     
@@ -156,7 +159,7 @@ public class Row extends BlockStackingLayoutManager {
                 log.error("Overlapping cell at position " + colnum);
             }
             //Add cell info for primary slot
-            GridUnit info = new GridUnit(cellLM);
+            OldGridUnit info = new OldGridUnit(cellLM);
             info.row = this;
             gridUnits.set(colnum - 1, info);
             info.column = getColumn(colnum);
@@ -164,7 +167,7 @@ public class Row extends BlockStackingLayoutManager {
             //Add cell infos on spanned slots if any
             for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
                 colnum++;
-                GridUnit infoSpan = new GridUnit(cellLM, j);
+                OldGridUnit infoSpan = new OldGridUnit(cellLM, j);
                 infoSpan.row = this;
                 infoSpan.column = getColumn(colnum);
                 if (colnum > gridUnits.size()) {
@@ -186,12 +189,12 @@ public class Row extends BlockStackingLayoutManager {
 
     private void postProcessGridUnits() {
         for (int pos = 1; pos <= gridUnits.size(); pos++) {
-            GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
+            OldGridUnit gu = (OldGridUnit)gridUnits.get(pos - 1);
             
             //Empty grid units
             if (gu == null) {
                 //Add grid unit
-                gu = new GridUnit(null);
+                gu = new OldGridUnit(null);
                 gu.row = this;
                 gu.column = getColumn(pos);
                 gridUnits.set(pos - 1, gu);
@@ -200,17 +203,17 @@ public class Row extends BlockStackingLayoutManager {
             
         //Border resolution now that the empty grid units are filled
         for (int pos = 1; pos <= gridUnits.size(); pos++) {
-            GridUnit starting = (GridUnit)gridUnits.get(pos - 1);
+            OldGridUnit starting = (OldGridUnit)gridUnits.get(pos - 1);
          
             //Border resolution
             if (getTable().isSeparateBorderModel()) {
                 starting.assignBorder(starting.layoutManager);
             } else {
                 //Neighbouring grid unit at start edge 
-                GridUnit start = null;
+                OldGridUnit start = null;
                 int find = pos - 1;
                 while (find >= 1) {
-                    GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+                    OldGridUnit candidate = (OldGridUnit)gridUnits.get(find - 1);
                     if (candidate.isLastGridUnitColSpan()) {
                         start = candidate;
                         break;
@@ -219,17 +222,17 @@ public class Row extends BlockStackingLayoutManager {
                 }
                 
                 //Ending grid unit for current cell
-                GridUnit ending = null;
+                OldGridUnit ending = null;
                 if (starting.layoutManager != null) {
                     pos += starting.layoutManager.getFObj().getNumberColumnsSpanned() - 1;
                 }
-                ending = (GridUnit)gridUnits.get(pos - 1);
+                ending = (OldGridUnit)gridUnits.get(pos - 1);
                 
                 //Neighbouring grid unit at end edge 
-                GridUnit end = null;
+                OldGridUnit end = null;
                 find = pos + 1;
                 while (find <= gridUnits.size()) {
-                    GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+                    OldGridUnit candidate = (OldGridUnit)gridUnits.get(find - 1);
                     if (candidate.isPrimaryGridUnit()) {
                         end = candidate;
                         break;
@@ -237,14 +240,14 @@ public class Row extends BlockStackingLayoutManager {
                     find++;
                 }
                 CommonBorderPaddingBackground borders = new CommonBorderPaddingBackground();
-                GridUnit.resolveBorder(getTable(), borders, starting, 
+                OldGridUnit.resolveBorder(getTable(), borders, starting, 
                         (start != null ? start : null), 
                         CommonBorderPaddingBackground.START);
                 starting.effBorders = borders;
                 if (starting != ending) {
                     borders = new CommonBorderPaddingBackground();
                 }
-                GridUnit.resolveBorder(getTable(), borders, ending, 
+                OldGridUnit.resolveBorder(getTable(), borders, ending, 
                         (end != null ? end : null), 
                         CommonBorderPaddingBackground.END);
                 ending.effBorders = borders;
@@ -260,12 +263,12 @@ public class Row extends BlockStackingLayoutManager {
      * @param pos the position of the cell (must be >= 1)
      * @return the cell info object
      */
-    protected GridUnit getCellInfo(int pos) {
+    protected OldGridUnit getCellInfo(int pos) {
         if (gridUnits == null) {
             prepareGridUnits();
         }
         if (pos <= gridUnits.size()) {
-            return (GridUnit)gridUnits.get(pos - 1);
+            return (OldGridUnit)gridUnits.get(pos - 1);
         } else {
             return null;
         }
@@ -281,7 +284,7 @@ public class Row extends BlockStackingLayoutManager {
      */
     public BreakPoss getNextBreakPoss(LayoutContext context) {
         //LayoutManager curLM; // currently active LM
-        GridUnit curGridUnit; //currently active grid unit
+        OldGridUnit curGridUnit; //currently active grid unit
 
         BreakPoss lastPos = null;
         List breakList = new java.util.ArrayList();
@@ -322,7 +325,7 @@ public class Row extends BlockStackingLayoutManager {
             getGridUnitsForCell(cellLM, startColumn, spannedGridUnits);
             int childRefIPD = 0;
             for (int i = 0; i < spannedGridUnits.size(); i++) {
-                Column col = ((GridUnit)spannedGridUnits.get(i)).column;
+                Column col = ((OldGridUnit)spannedGridUnits.get(i)).column;
                 childRefIPD += col.getWidth().getValue();
             }
             childLC.setRefIPD(childRefIPD);
@@ -455,7 +458,7 @@ public class Row extends BlockStackingLayoutManager {
      */
     protected void reset(Position pos) {
         //LayoutManager curLM; // currently active LM
-        GridUnit curGridUnit;
+        OldGridUnit curGridUnit;
         int cellIndex = 1;
 
         if (pos == null) {
@@ -619,5 +622,47 @@ public class Row extends BlockStackingLayoutManager {
         }
     }
 
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
+     */
+    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(org.apache.fop.layoutmgr.KnuthGlue)
+     */
+    public void discardSpace(KnuthGlue spaceGlue) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+     */
+    public boolean mustKeepTogether() {
+        //TODO Keeps will have to be more sophisticated sooner or later
+        return ((BlockLevelLayoutManager)getParent()).mustKeepTogether() 
+                || !fobj.getKeepTogether().getWithinPage().isAuto()
+                || !fobj.getKeepTogether().getWithinColumn().isAuto();
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+     */
+    public boolean mustKeepWithPrevious() {
+        return !fobj.getKeepWithPrevious().getWithinPage().isAuto()
+                || !fobj.getKeepWithPrevious().getWithinColumn().isAuto();
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+     */
+    public boolean mustKeepWithNext() {
+        return !fobj.getKeepWithNext().getWithinPage().isAuto()
+                || !fobj.getKeepWithNext().getWithinColumn().isAuto();
+    }
+
 }
 
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
new file mode 100644 (file)
index 0000000..b2a949b
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.flow.TableRow;
+import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.layoutmgr.KnuthBox;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.KnuthPossPosIter;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.NonLeafPosition;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * Layout manager for table contents, particularly managing the creation of combined element lists.
+ */
+public class TableContentLayoutManager {
+
+    /** Logger **/
+    private static Log log = LogFactory.getLog(TableContentLayoutManager.class);
+
+    private TableLayoutManager tableLM;
+    private TableRowIterator trIter;
+
+    
+    public TableContentLayoutManager(TableLayoutManager parent) {
+        this.tableLM = parent;
+        this.trIter = new TableRowIterator(getTableLM().getTable(), getTableLM().getColumns());
+    }
+    
+    public TableLayoutManager getTableLM() {
+        return this.tableLM;
+    }
+    
+    public ColumnSetup getColumns() {
+        return getTableLM().getColumns();
+    }
+    
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
+     */
+    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+        System.out.println(getTableLM().getColumns());
+        LinkedList returnList = new LinkedList();
+        TableRowIterator.EffRow row = null;
+        while ((row = trIter.getNextRow()) != null) {
+            List pgus = new java.util.ArrayList();
+            TableRow tableRow = null;
+            int maxCellHeight = 0;
+            for (int j = 0; j < row.getGridUnits().size(); j++) {
+                GridUnit gu = (GridUnit)row.getGridUnits().get(j);
+                if (gu.isPrimary() && !gu.isEmpty()) {
+                    PrimaryGridUnit primary = (PrimaryGridUnit)gu;
+                    primary.getCellLM().setParent(tableLM);
+
+                    //Calculate width of cell
+                    int spanWidth = 0;
+                    for (int i = primary.getStartRow(); 
+                            i < primary.getStartRow() + primary.getCell().getNumberColumnsSpanned();
+                            i++) {
+                        spanWidth += getTableLM().getColumns().getColumn(i + 1)
+                            .getColumnWidth().getValue();
+                    }
+                    log.info("spanWidth=" + spanWidth);
+                    LayoutContext childLC = new LayoutContext(0);
+                    childLC.setStackLimit(context.getStackLimit()); //necessary?
+                    childLC.setRefIPD(spanWidth);
+                    
+                    LinkedList elems = primary.getCellLM().getNextKnuthElements(childLC, alignment);
+                    primary.setElements(elems);
+                    log.debug("Elements: " + elems);
+                    int len = calcCellHeightFromContents(elems);
+                    pgus.add(primary);
+                    maxCellHeight = Math.max(maxCellHeight, len);
+                    if (len > row.getHeight().opt) {
+                        row.setHeight(new MinOptMax(len));
+                    }
+                    LengthRangeProperty bpd = primary.getCell().getBlockProgressionDimension();
+                    if (!bpd.getOptimum().isAuto()) {
+                        if (bpd.getOptimum().getLength().getValue() > row.getHeight().opt) {
+                            row.setHeight(new MinOptMax(bpd.getOptimum().getLength().getValue()));
+                        }
+                    }
+                    if (tableRow == null) {
+                        tableRow = primary.getRow();
+                    }
+                }
+            }
+            
+            if (tableRow != null) {
+                LengthRangeProperty bpd = tableRow.getBlockProgressionDimension();
+                if (!bpd.getOptimum().isAuto()) {
+                    if (bpd.getOptimum().getLength().getValue() > row.getHeight().opt) {
+                        row.setHeight(new MinOptMax(bpd.getOptimum().getLength().getValue()));
+                    }
+                }
+            }
+            log.debug(row);
+            
+            PrimaryGridUnit[] pguArray = new PrimaryGridUnit[pgus.size()];
+            pguArray = (PrimaryGridUnit[])pgus.toArray(pguArray);
+            LinkedList returnedList = getCombinedKnuthElementsForRow(pguArray, row);
+            if (returnedList != null) {
+                returnList.addAll(returnedList);
+            }
+
+            if (row.getHeight().opt > maxCellHeight) {
+                //TODO Fix me (additional spaces)
+                log.warn("Knuth elements for additional space coming from height/bpd propertes NYI");
+                int space = row.getHeight().opt - maxCellHeight;
+                returnList.add(new KnuthGlue(space, 0, 0, new Position(null), false));
+            }
+        }
+        return returnList;
+    }
+    
+    private LinkedList getCombinedKnuthElementsForRow(PrimaryGridUnit[] pguArray, 
+            TableRowIterator.EffRow row) {
+        List[] elementLists = new List[pguArray.length];
+        for (int i = 0; i < pguArray.length; i++) {
+            //Copy elements to array lists to improve element access performance
+            elementLists[i] = new java.util.ArrayList(pguArray[i].getElements());
+        }
+        int[] index = new int[pguArray.length];
+        int[] start = new int[pguArray.length];
+        int[] end = new int[pguArray.length];
+        int[] widths = new int[pguArray.length];
+        int[] fullWidths = new int[pguArray.length];
+        Arrays.fill(end, -1);
+        
+        int totalHeight = 0;
+        for (int i = 0; i < pguArray.length; i++) {
+            fullWidths[i] = calcCellHeightFromContents(pguArray[i].getElements());
+            totalHeight = Math.max(totalHeight, fullWidths[i]);
+        }
+        int laststep = 0;
+        int step;
+        int addedBoxLen = 0;
+        LinkedList returnList = new LinkedList();
+        while ((step = getNextStep(laststep, elementLists, index, start, end, 
+                widths, fullWidths)) > 0) {
+            int increase = step - laststep;
+            int penaltyLen = step + getMaxRemainingHeight(fullWidths, widths) - totalHeight;
+            int boxLen = step - addedBoxLen - penaltyLen;
+            addedBoxLen += boxLen;
+            
+            log.debug(step + " " + increase + " box=" + boxLen + " penalty=" + penaltyLen);
+            
+            //Put all involved grid units into a list
+            List gridUnitParts = new java.util.ArrayList(pguArray.length);
+            for (int i = 0; i < pguArray.length; i++) {
+                if (end[i] >= start[i]) {
+                    gridUnitParts.add(new GridUnitPart(pguArray[i], start[i], end[i]));
+                }
+            }
+            
+            //Create elements for step
+            TableContentPosition tcpos = new TableContentPosition(getTableLM(), 
+                    gridUnitParts, row);
+            returnList.add(new KnuthBox(boxLen, tcpos, false));
+            returnList.add(new KnuthPenalty(penaltyLen, 0, false, null, false));
+            laststep = step;
+        }
+        return returnList;
+    }
+
+    private int getMaxRemainingHeight(int[] fullWidths, int[] widths) {
+        int maxW = 0;
+        for (int i = 0; i < fullWidths.length; i++) {
+            maxW = Math.max(maxW, fullWidths[i] - widths[i]);
+        }
+        return maxW;
+    }
+    
+    private int getNextStep(int laststep, List[] elementLists, int[] index, 
+            int[] start, int[] end, int[] widths, int[] fullWidths) {
+        int backupWidths[] = new int[start.length];
+        System.arraycopy(widths, 0, backupWidths, 0, backupWidths.length);
+        //set starting points
+        for (int i = 0; i < start.length; i++) {
+            if (end[i] < elementLists[i].size()) {
+                start[i] = end[i] + 1;
+            } else {
+                start[i] = -1; //end of list reached
+                end[i] = -1;
+            }
+        }
+        //Arrays.fill(widths, laststep);
+        
+        //Get next possible sequence for each cell
+        int seqCount = 0;
+        for (int i = 0; i < start.length; i++) {
+            while (end[i] + 1 < elementLists[i].size()) {
+                end[i]++;
+                KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
+                if (el.isPenalty()) {
+                    if (el.getP() < KnuthElement.INFINITE) {
+                        //First legal break point
+                        break;
+                    }
+                } else if (el.isGlue()) {
+                    KnuthElement prev = (KnuthElement)elementLists[i].get(end[i] - 1);
+                    if (prev.isBox()) {
+                        //Second legal break point
+                        break;
+                    }
+                    widths[i] += el.getW();
+                } else {
+                    widths[i] += el.getW();
+                }
+            }
+            if (end[i] < start[i]) {
+                widths[i] = backupWidths[i];
+            } else {
+                seqCount++;
+            }
+            //System.out.println("part " + start[i] + "-" + end[i] + " " + widths[i]);
+        }
+        if (seqCount == 0) {
+            return 0;
+        }
+        
+        //Determine smallest possible step
+        int minStep = Integer.MAX_VALUE;
+        for (int i = 0; i < widths.length; i++) {
+            if (end[i] >= start[i]) {
+                minStep = Math.min(widths[i], minStep);
+            }
+        }
+
+        //Reset bigger-than-minimum sequences
+        for (int i = 0; i < widths.length; i++) {
+            if (widths[i] > minStep) {
+                widths[i] = backupWidths[i];
+                end[i] = start[i] - 1;
+            }
+        }
+        if (log.isDebugEnabled()) {
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < widths.length; i++) {
+                if (end[i] >= start[i]) {
+                    sb.append(i + ": " + start[i] + "-" + end[i] + "(" + widths[i] + "), ");
+                } else {
+                    sb.append(i + ": skip, ");
+                }
+            }
+            log.debug(sb.toString());
+        }
+        return minStep;
+    }
+
+    private int calcCellHeightFromContents(List elems, int start, int end) {
+        ListIterator iter = elems.listIterator(start);
+        int count = end - start + 1;
+        int len = 0;
+        while (iter.hasNext()) {
+            KnuthElement el = (KnuthElement)iter.next();
+            if (el.isBox()) {
+                len += el.getW();
+            } else if (el.isGlue()) {
+                len += el.getW();
+            } else {
+                log.debug("Ignoring penalty: " + el);
+                //ignore penalties
+            }
+            count--;
+            if (count == 0) {
+                break;
+            }
+        }
+        return len;
+    }
+    
+    private int calcCellHeightFromContents(List elems) {
+        return calcCellHeightFromContents(elems, 0, elems.size() - 1);
+    }
+    
+    protected int getXOffsetOfGridUnit(GridUnit gu) {
+        int col = gu.getStartCol();
+        return getTableLM().getColumns().getXOffset(col + 1);
+    }
+    
+    public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
+        int colCount = getColumns().getColumnCount();
+        TableRowIterator.EffRow lastRow = null;
+        int lastRowHeight = 0;
+        int yoffset = 0;
+        
+        //These three variables are our buffer to recombine the individual steps into cells
+        PrimaryGridUnit[] gridUnits = new PrimaryGridUnit[colCount];
+        int[] start = new int[colCount];
+        int[] end = new int[colCount];
+        
+        //Iterate over all steps
+        while (parentIter.hasNext()) {
+            Position pos = (Position)parentIter.next();
+            //NonLeafPosition nlfp = (NonLeafPosition)pos;
+            //if (nlfp.getPosition() instanceof TableContentPosition) {
+            //    TableContentPosition pos = (TableContentPosition)nlfp.getPosition();
+            if (pos instanceof TableContentPosition) {
+                TableContentPosition tcpos = (TableContentPosition)pos;
+                if (lastRow != tcpos.row && lastRow != null) {
+                    //yoffset += lastRow.getHeight().opt;
+                    yoffset += lastRowHeight;
+                }
+                lastRow = tcpos.row;
+                Iterator iter = tcpos.gridUnitParts.iterator();
+                //Iterate over all grid units in the current step
+                while (iter.hasNext()) {
+                    GridUnitPart gup = (GridUnitPart)iter.next();
+                    log.debug(">" + gup);
+                    int colIndex = gup.pgu.getStartCol();
+                    if (gridUnits[colIndex] != gup.pgu) {
+                        gridUnits[colIndex] = gup.pgu;
+                        start[colIndex] = gup.start;
+                        end[colIndex] = gup.end;
+                    } else {
+                        end[colIndex] = gup.end;
+                    }
+                }
+                int maxLen = 0;
+                for (int i = 0; i < gridUnits.length; i++) {
+                    if ((gridUnits[i] != null) 
+                            && (end[i] == gridUnits[i].getElements().size() - 1)) {
+                        log.debug("getting len for " + i + " " 
+                                + start[i] + "-" + end[i]);
+                        int len = calcCellHeightFromContents(
+                                gridUnits[i].getElements(), start[i], end[i]);
+                        log.debug("len of part: " + len);
+                        maxLen = Math.max(maxLen, len);
+                        maxLen = Math.max(maxLen, getExplicitCellHeight(gridUnits[i]));
+                    }
+                }
+                lastRowHeight = maxLen;
+                for (int i = 0; i < gridUnits.length; i++) {
+                    if ((gridUnits[i] != null) 
+                            && (end[i] == gridUnits[i].getElements().size() - 1)) {
+                        log.debug("flushing..." + i + " " 
+                                + start[i] + "-" + end[i]);
+                        addAreasForCell(gridUnits[i], start[i], end[i], 
+                                layoutContext, lastRow, yoffset, maxLen);
+                        gridUnits[i] = null;
+                        start[i] = 0;
+                        end[i] = 0;
+                    }
+                }
+            }
+        }
+        
+        int maxLen = 0;
+        for (int i = 0; i < gridUnits.length; i++) {
+            if (gridUnits[i] != null) {
+                int len = calcCellHeightFromContents(
+                        gridUnits[i].getElements(), start[i], end[i]);
+                log.debug("len of part: " + len);
+                maxLen = Math.max(maxLen, len);
+                maxLen = Math.max(maxLen, getExplicitCellHeight(gridUnits[i]));
+            }
+        }
+        for (int i = 0; i < gridUnits.length; i++) {
+            if (gridUnits[i] != null) {
+                log.debug("final flushing " + i + " " + start[i] + "-" + end[i]);
+                addAreasForCell(gridUnits[i], start[i], end[i], 
+                        layoutContext, lastRow, yoffset, maxLen);
+            }
+        }
+        
+    }
+    
+    private int getExplicitCellHeight(PrimaryGridUnit pgu) {
+        int len = 0;
+        if (!pgu.getCell().getBlockProgressionDimension().getOptimum().isAuto()) {
+            len = pgu.getCell().getBlockProgressionDimension()
+                    .getOptimum().getLength().getValue();
+        }
+        if (pgu.getRow() != null 
+                && !pgu.getRow().getBlockProgressionDimension().getOptimum().isAuto()) {
+            len = Math.max(len, pgu.getRow().getBlockProgressionDimension()
+                    .getOptimum().getLength().getValue());
+        }
+        return len;
+    }
+    
+    private void addAreasForCell(PrimaryGridUnit gu, int start, int end, 
+            LayoutContext layoutContext, TableRowIterator.EffRow row, 
+            int yoffset, int rowHeight) {
+        Cell cellLM = gu.getCellLM();
+        cellLM.setXOffset(getXOffsetOfGridUnit(gu));
+        cellLM.setYOffset(yoffset);
+        cellLM.setRowHeight(rowHeight);
+        //cellLM.setRowHeight(row.getHeight().opt);
+        cellLM.addAreas(new KnuthPossPosIter(gu.getElements(), 
+                start, end + 1), layoutContext);
+    }
+    
+    private class GridUnitPart {
+        
+        protected PrimaryGridUnit pgu;
+        protected int start;
+        protected int end;
+        
+        protected GridUnitPart(PrimaryGridUnit pgu, int start, int end) {
+            this.pgu = pgu;
+            this.start = start;
+            this.end = end;
+        }
+        
+        /** @see java.lang.Object#toString() */
+        public String toString() {
+            StringBuffer sb = new StringBuffer("Part: ");
+            sb.append(start).append("-").append(end);
+            sb.append(" ").append(pgu);
+            return sb.toString();
+        }
+        
+    }
+    
+    public class TableContentPosition extends Position {
+
+        protected List gridUnitParts;
+        protected TableRowIterator.EffRow row;
+        
+        protected TableContentPosition(LayoutManager lm, List gridUnitParts, 
+                TableRowIterator.EffRow row) {
+            super(lm);
+            this.gridUnitParts = gridUnitParts;
+            this.row = row;
+        }
+        
+        /** @see java.lang.Object#toString() */
+        public String toString() {
+            StringBuffer sb = new StringBuffer("TableContentPosition {");
+            sb.append(gridUnitParts);
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+}
index 653c953c258a8d1909a67067925f7b82a8b889ef..0a6d0c19ebe7b39efc663fe8f28cd13af53aac5e 100644 (file)
@@ -21,12 +21,18 @@ package org.apache.fop.layoutmgr.table;
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.flow.TableColumn;
 import org.apache.fop.fo.properties.TableColLength;
+import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.LeafPosition;
 import org.apache.fop.layoutmgr.BreakPoss;
 import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.BreakPossPosIter;
 import org.apache.fop.layoutmgr.Position;
@@ -37,20 +43,24 @@ import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.traits.SpaceVal;
 
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
  * LayoutManager for a table FO.
- * A table consists of columns, table header, table footer and multiple
+ * A table consists of oldColumns, table header, table footer and multiple
  * table bodies.
  * The header, footer and body add the areas created from the table cells.
- * The table then creates areas for the columns, bodies and rows
+ * The table then creates areas for the oldColumns, bodies and rows
  * the render background.
  */
-public class TableLayoutManager extends BlockStackingLayoutManager {
+public class TableLayoutManager extends BlockStackingLayoutManager 
+                implements BlockLevelLayoutManager {
     private Table fobj;
     
-    private List columns = null;
+    private TableContentLayoutManager contentLM; 
+    private List oldColumns = null;
+    private ColumnSetup columns = null;
 
     private Block curBlockArea;
 
@@ -82,6 +92,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
     public TableLayoutManager(Table node) {
         super(node);
         fobj = node;
+        this.columns = new ColumnSetup(node);
     }
 
     /** @return the table FO */
@@ -90,14 +101,18 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
     }
     
     /**
-     * Set the columns for this table.
+     * Set the oldColumns for this table.
      *
      * @param cols the list of column layout managers
      */
     public void setColumns(List cols) {
-        columns = cols;
+        oldColumns = cols;
     }
 
+    public ColumnSetup getColumns() {
+        return this.columns;
+    }
+    
     /** @see org.apache.fop.layoutmgr.AbstractLayoutManager#initProperties() */
     protected void initProperties() {
         super.initProperties();
@@ -117,6 +132,165 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         return iIndents;
     }
     
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
+     */
+    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+        
+        Body curLM; // currently active LM
+
+        referenceIPD = context.getRefIPD();
+        if (fobj.getInlineProgressionDimension().getOptimum().getEnum() != EN_AUTO) {
+            referenceIPD = fobj.getInlineProgressionDimension().getOptimum().getLength().getValue();
+        }
+        if (referenceIPD > context.getRefIPD()) {
+            log.warn("Allocated IPD exceeds available reference IPD");
+        }
+        int contentIPD = referenceIPD - getIPIndents();
+
+        MinOptMax stackSize = new MinOptMax();
+        //Add spacing
+        if (spaceAfter != null) {
+            stackSize.add(spaceAfter);
+        }
+        if (spaceBefore != null) {
+            stackSize.add(spaceBefore);
+        }
+
+        BreakPoss lastPos = null;
+
+        fobj.setLayoutDimension(PercentBase.BLOCK_IPD, referenceIPD);
+        fobj.setLayoutDimension(PercentBase.BLOCK_BPD, context.getStackLimit().opt);
+        fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_IPD, referenceIPD);
+        fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_BPD, context.getStackLimit().opt);
+
+        /*
+        if (oldColumns == null) {
+            createColumnsFromFirstRow();
+        }*/
+        
+        // either works out table of column widths or if proportional-column-width function
+        // is used works out total factor, so that value of single unit can be computed.
+        int sumCols = 0;
+        float factors = 0;
+        for (Iterator i = columns.iterator(); i.hasNext(); ) {
+            TableColumn column = (TableColumn) i.next();
+            Length width = column.getColumnWidth();
+            sumCols += width.getValue();
+            if (width instanceof TableColLength) {
+                factors += ((TableColLength) width).getTableUnits();
+            }
+        }
+        // sets TABLE_UNITS in case where one or more oldColumns is defined using 
+        // proportional-column-width
+        if (sumCols < contentIPD) {
+            if (fobj.getLayoutDimension(PercentBase.TABLE_UNITS).floatValue() == 0.0) {
+                fobj.setLayoutDimension(PercentBase.TABLE_UNITS,
+                                      (contentIPD - sumCols) / factors);
+            }
+        }
+        
+        LinkedList headerElements = null;
+        LinkedList footerElements = null;
+        if (getTable().getTableHeader() != null) {
+            Body tableHeader = new Body(getTable().getTableHeader());
+            tableHeader.setParent(this);
+            headerElements = getKnuthElementsForHeaderFooter(
+                    tableHeader, context, alignment);
+        }
+        if (getTable().getTableFooter() != null) {
+            Body tableFooter = new Body(getTable().getTableFooter());
+            tableFooter.setParent(this);
+            footerElements = getKnuthElementsForHeaderFooter(
+                    tableFooter, context, alignment);
+        }
+
+        LinkedList returnedList = null;
+        LinkedList contentList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        Position returnPosition = new NonLeafPosition(this, null);
+        Body prevLM = null;
+
+        LayoutContext childLC = new LayoutContext(0);
+        childLC.setStackLimit(
+              MinOptMax.subtract(context.getStackLimit(),
+                                 stackSize));
+        childLC.setRefIPD(context.getRefIPD());
+
+        contentLM = new TableContentLayoutManager(this);
+        returnedList = contentLM.getNextKnuthElements(childLC, alignment);
+        log.debug(returnedList);
+        
+            if (returnedList.size() == 1
+                    && ((KnuthElement) returnedList.getFirst()).isPenalty()
+                    && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+                // a descendant of this block has break-before
+                if (returnList.size() == 0) {
+                    // the first child (or its first child ...) has
+                    // break-before;
+                    // all this block, including space before, will be put in
+                    // the
+                    // following page
+                    //FIX ME
+                    //bSpaceBeforeServed = false;
+                }
+                contentList.addAll(returnedList);
+
+                // "wrap" the Position inside each element
+                // moving the elements from contentList to returnList
+                returnedList = new LinkedList();
+                wrapPositionElements(contentList, returnList);
+
+                return returnList;
+            } else {
+                if (prevLM != null) {
+                    // there is a block handled by prevLM
+                    // before the one handled by curLM
+                    if (mustKeepTogether() 
+                            /*|| prevLM.mustKeepWithNext()
+                            || curLM.mustKeepWithPrevious()*/) {
+                        // add an infinite penalty to forbid a break between
+                        // blocks
+                        contentList.add(new KnuthPenalty(0,
+                                KnuthElement.INFINITE, false,
+                                new Position(this), false));
+                    } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+                        // add a null penalty to allow a break between blocks
+                        contentList.add(new KnuthPenalty(0, 0, false,
+                                new Position(this), false));
+                    } else {
+                        // the last element in contentList is a glue;
+                        // it is a feasible breakpoint, there is no need to add
+                        // a penalty
+                    }
+                }
+                contentList.addAll(returnedList);
+                /*
+                if (returnedList.size() == 0) {
+                    //Avoid NoSuchElementException below (happens with empty blocks)
+                    continue;
+                }*/
+                if (((KnuthElement) returnedList.getLast()).isPenalty()
+                        && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+                    // a descendant of this block has break-after
+                    if (false /*curLM.isFinished()*/) {
+                        // there is no other content in this block;
+                        // it's useless to add space after before a page break
+                        setFinished(true);
+                    }
+
+                    returnedList = new LinkedList();
+                    wrapPositionElements(contentList, returnList);
+
+                    return returnList;
+                }
+            
+        }
+        wrapPositionElements(contentList, returnList);
+        setFinished(true);
+        return returnList;
+    }
+    
     /**
      * Get the next break possibility.
      * The break possibility depends on the height of the header and footer
@@ -124,8 +298,8 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
      *
      * @param context the layout context for finding breaks
      * @return the next break possibility
-     */
-    public BreakPoss getNextBreakPoss(LayoutContext context) {
+     *//*
+    public BreakPoss getNextBreakPossOLDOLDOLD(LayoutContext context) {
         Body curLM; // currently active LM
 
         referenceIPD = context.getRefIPD();
@@ -153,7 +327,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_IPD, referenceIPD);
         fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_BPD, context.getStackLimit().opt);
 
-        if (columns == null) {
+        if (columns.getColumnCount() == 0) {
             createColumnsFromFirstRow();
         }
         
@@ -161,8 +335,8 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         // is used works out total factor, so that value of single unit can be computed.
         int sumCols = 0;
         float factors = 0;
-        if (columns != null) {
-            for (Iterator i = columns.iterator(); i.hasNext(); ) {
+        if (oldColumns != null) {
+            for (Iterator i = oldColumns.iterator(); i.hasNext(); ) {
                 Column column = (Column) i.next();
                 Length width = column.getWidth();
                 sumCols += width.getValue();
@@ -171,7 +345,8 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
                 }
             }
         }
-        // sets TABLE_UNITS in case where one or more columns is defined using proportional-column-width
+        // sets TABLE_UNITS in case where one or more oldColumns is defined using 
+        // proportional-column-width
         if (sumCols < contentIPD) {
             if (fobj.getLayoutDimension(PercentBase.TABLE_UNITS).floatValue() == 0.0) {
                 fobj.setLayoutDimension(PercentBase.TABLE_UNITS,
@@ -189,7 +364,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
                     if (!getTable().omitHeaderAtBreak() || !firstRowHandled) {
                         Body tableHeader = new Body(getTable().getTableHeader());
                         tableHeader.setParent(this);
-                        headerBreak = getHeight(tableHeader, context);
+                        headerBreak = getHeightOLDOLDOLD(tableHeader, context);
                         headerSize = headerBreak.getStackingSize();
                         stackSize.add(headerSize);
                     }
@@ -201,7 +376,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
                 if (getTable().getTableFooter() != null) {
                     Body tableFooter = new Body(getTable().getTableFooter());
                     tableFooter.setParent(this);
-                    footerBreak = getHeight(tableFooter, context);
+                    footerBreak = getHeightOLDOLDOLD(tableFooter, context);
                     footerSize = footerBreak.getStackingSize();
                     stackSize.add(footerSize);
                 }
@@ -227,7 +402,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
                                      stackSize));
             childLC.setRefIPD(ipd);
 
-            curLM.setColumns(columns);
+            curLM.setColumns(oldColumns);
 
             boolean over = false;
             while (!curLM.isFinished()) {
@@ -270,28 +445,29 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         }
         setFinished(true);
         return null;
-    }
+    }*/
 
+    /*
     private void createColumnsFromFirstRow() {
-        this.columns = new java.util.ArrayList();
-        //TODO Create columns from first row here 
+        this.oldColumns = new java.util.ArrayList();
+        //TODO Create oldColumns from first row here 
         //--> rule 2 in "fixed table layout", see CSS2, 17.5.2
-        //Alternative: extend columns on-the-fly, but in this case we need the
+        //Alternative: extend oldColumns on-the-fly, but in this case we need the
         //new property evaluation context so proportional-column-width() works
         //correctly.
-        if (columns.size() == 0) {
+        if (oldColumns.size() == 0) {
             Column col = new Column(getTable().getDefaultColumn());
             col.setParent(this);
-            this.columns.add(col);
+            this.oldColumns.add(col);
         }
-    }
+    }*/
     
     /**
      * @param column the column to check
      * @return true if the column is the first column
      */
     public boolean isFirst(Column column) {
-        return (this.columns.size() == 0 || this.columns.get(0) == column);
+        return (this.oldColumns.size() == 0 || this.oldColumns.get(0) == column);
     }
     
     /**
@@ -299,7 +475,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
      * @return true if the column is the last column
      */
     public boolean isLast(Column column) {
-        return (this.columns.size() == 0 || this.columns.get(columns.size() - 1) == column);
+        return (this.oldColumns.size() == 0 || this.oldColumns.get(oldColumns.size() - 1) == column);
     }
     
     /**
@@ -309,7 +485,8 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
      * @param context the parent layout context
      * @return the break possibility containing the stacking size
      */
-    protected BreakPoss getHeight(Body lm, LayoutContext context) {
+    protected LinkedList getKnuthElementsForHeaderFooter(Body lm, LayoutContext context, 
+                int alignment) {
         int referenceIPD = context.getRefIPD();
         int contentIPD = referenceIPD - getIPIndents();
         BreakPoss bp;
@@ -320,7 +497,127 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         childLC.setStackLimit(context.getStackLimit());
         childLC.setRefIPD(contentIPD);
 
-        lm.setColumns(columns);
+        lm.setColumns(oldColumns);
+
+        LinkedList returnedList = null;
+        LinkedList contentList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        Position returnPosition = new NonLeafPosition(this, null);
+        
+        Row curLM; // currently active LM
+        Row prevLM = null; // previously active LM
+        while ((curLM = (Row)getChildLM()) != null) {
+
+            // get elements from curLM
+            returnedList = curLM.getNextKnuthElements(childLC, alignment);
+            /*
+            if (returnedList.size() == 1
+                    && ((KnuthElement) returnedList.getFirst()).isPenalty()
+                    && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+                // a descendant of this block has break-before
+                if (returnList.size() == 0) {
+                    // the first child (or its first child ...) has
+                    // break-before;
+                    // all this block, including space before, will be put in
+                    // the
+                    // following page
+                    bSpaceBeforeServed = false;
+                }
+                contentList.addAll(returnedList);
+
+                // "wrap" the Position inside each element
+                // moving the elements from contentList to returnList
+                returnedList = new LinkedList();
+                wrapPositionElements(contentList, returnList);
+
+                return returnList;
+            } else*/ {
+                if (prevLM != null) {
+                    // there is a block handled by prevLM
+                    // before the one handled by curLM
+                    if (mustKeepTogether() 
+                            || prevLM.mustKeepWithNext()
+                            || curLM.mustKeepWithPrevious()) {
+                        // add an infinite penalty to forbid a break between
+                        // blocks
+                        contentList.add(new KnuthPenalty(0,
+                                KnuthElement.INFINITE, false,
+                                new Position(this), false));
+                    } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+                        // add a null penalty to allow a break between blocks
+                        contentList.add(new KnuthPenalty(0, 0, false,
+                                new Position(this), false));
+                    } else {
+                        // the last element in contentList is a glue;
+                        // it is a feasible breakpoint, there is no need to add
+                        // a penalty
+                    }
+                }
+                contentList.addAll(returnedList);
+                if (returnedList.size() == 0) {
+                    //Avoid NoSuchElementException below (happens with empty blocks)
+                    continue;
+                }
+                if (((KnuthElement) returnedList.getLast()).isPenalty()
+                        && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+                    // a descendant of this block has break-after
+                    if (curLM.isFinished()) {
+                        // there is no other content in this block;
+                        // it's useless to add space after before a page break
+                        setFinished(true);
+                    }
+
+                    returnedList = new LinkedList();
+                    wrapPositionElements(contentList, returnList);
+
+                    return returnList;
+                }
+            }
+            prevLM = curLM;
+        }
+
+        /*
+        List breaks = new java.util.ArrayList();
+        while (!lm.isFinished()) {
+            if ((bp = lm.getNextBreakPoss(childLC)) != null) {
+                stackSize.add(bp.getStackingSize());
+                breaks.add(bp);
+                childLC.setStackLimit(MinOptMax.subtract(
+                                         context.getStackLimit(), stackSize));
+            }
+        }
+        BreakPoss breakPoss = new BreakPoss(
+                               new SectionPosition(this, breaks.size() - 1, breaks));
+        breakPoss.setStackingSize(stackSize);
+        return breakPoss;*/
+
+        if (returnList.size() > 0) {
+            return returnList;
+        } else {
+            return null;
+        }
+        
+    }
+
+    /**
+     * Get the break possibility and height of the table header or footer.
+     *
+     * @param lm the header or footer layout manager
+     * @param context the parent layout context
+     * @return the break possibility containing the stacking size
+     */
+    protected BreakPoss getHeightOLDOLDOLD(Body lm, LayoutContext context) {
+        int referenceIPD = context.getRefIPD();
+        int contentIPD = referenceIPD - getIPIndents();
+        BreakPoss bp;
+
+        MinOptMax stackSize = new MinOptMax();
+
+        LayoutContext childLC = new LayoutContext(0);
+        childLC.setStackLimit(context.getStackLimit());
+        childLC.setRefIPD(contentIPD);
+
+        lm.setColumns(oldColumns);
 
         List breaks = new java.util.ArrayList();
         while (!lm.isFinished()) {
@@ -339,7 +636,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
 
     /**
      * The table area is a reference area that contains areas for
-     * columns, bodies, rows and the contents are in cells.
+     * oldColumns, bodies, rows and the contents are in cells.
      *
      * @param parentIter the position iterator
      * @param layoutContext the layout context for adding areas
@@ -374,21 +671,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
             }
         }
 
-        int iStartPos = 0;
-        while (parentIter.hasNext()) {
-            LeafPosition lfp = (LeafPosition) parentIter.next();
-            // Add the block areas to Area
-            PositionIterator breakPosIter =
-              new BreakPossPosIter(bodyBreaks, iStartPos,
-                                   lfp.getLeafPos() + 1);
-            iStartPos = lfp.getLeafPos() + 1;
-            while ((childLM = (Body)breakPosIter.getNextChildLM()) != null) {
-                childLM.setXOffset(startXOffset);
-                childLM.setYOffset(tableHeight);
-                childLM.addAreas(breakPosIter, lc);
-                tableHeight += childLM.getBodyHeight();
-            }
-        }
+        contentLM.addAreas(parentIter, layoutContext);
 
         // add footer areas
         if (footerBreak != null) {
@@ -474,5 +757,47 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         }
     }
 
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
+     */
+    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(org.apache.fop.layoutmgr.KnuthGlue)
+     */
+    public void discardSpace(KnuthGlue spaceGlue) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+     */
+    public boolean mustKeepTogether() {
+        //TODO Keeps will have to be more sophisticated sooner or later
+        return ((BlockLevelLayoutManager)getParent()).mustKeepTogether() 
+                || !fobj.getKeepTogether().getWithinPage().isAuto()
+                || !fobj.getKeepTogether().getWithinColumn().isAuto();
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+     */
+    public boolean mustKeepWithPrevious() {
+        return !fobj.getKeepWithPrevious().getWithinPage().isAuto()
+                || !fobj.getKeepWithPrevious().getWithinColumn().isAuto();
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+     */
+    public boolean mustKeepWithNext() {
+        return !fobj.getKeepWithNext().getWithinPage().isAuto()
+                || !fobj.getKeepWithNext().getWithinColumn().isAuto();
+    }
+
 }
 
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
new file mode 100644 (file)
index 0000000..ed42858
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.flow.TableBody;
+import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.flow.TableColumn;
+import org.apache.fop.fo.flow.TableRow;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * Iterator that lets the table layout manager step over all rows of a table.
+ */
+public class TableRowIterator {
+
+    /** Logger **/
+    private static Log log = LogFactory.getLog(TableRowIterator.class);
+
+    private Table table;
+    private ColumnSetup columns;
+    
+    private List currentRow = new java.util.ArrayList();
+    private int currentRowIndex = -1;
+    //TODO rows should later be a Jakarta Commons LinkedList so concurrent modifications while 
+    //using a ListIterator are possible
+    private List rows = new java.util.ArrayList();
+    private int indexOfFirstRowInList;
+    private int currentIndex = -1;
+    
+    //prefetch state
+    private ListIterator bodyIterator = null;
+    private ListIterator childInBodyIterator = null;
+    
+    public TableRowIterator(Table table, ColumnSetup columns) {
+        this.table = table;
+        this.columns = columns;
+        this.bodyIterator = table.getChildNodes();
+    }
+    
+    public void prefetchAll() {
+        while (prefetchNext()) {
+            System.out.println("found row...");
+        }
+    }
+    
+    public EffRow getNextRow() {
+        currentIndex++;
+        boolean moreRows = true;
+        while (moreRows && rows.size() < currentIndex + 1) {
+            moreRows = prefetchNext();
+        }
+        if (currentIndex < rows.size()) {
+            return getCachedRow(currentIndex);
+        } else {
+            return null;
+        }
+    }
+    
+    public EffRow getCachedRow(int index) {
+        return (EffRow)rows.get(index);
+    }
+    
+    private boolean prefetchNext() {
+        if (childInBodyIterator != null) {
+            if (!childInBodyIterator.hasNext()) {
+                //force skip on to next body
+                childInBodyIterator = null;
+            }
+        }
+        if (childInBodyIterator == null) {
+            if (bodyIterator.hasNext()) {
+                childInBodyIterator = ((TableBody)bodyIterator.next()).getChildNodes();
+            } else {
+                //no more rows
+                return false;
+            }
+        }
+        Object node = childInBodyIterator.next();
+        this.currentRow.clear();
+        this.currentRowIndex++;
+        if (node instanceof TableRow) {
+            TableRow row = (TableRow)node;
+            ListIterator cellIterator = row.getChildNodes();
+            while (cellIterator.hasNext()) {
+                this.currentRow.add(cellIterator.next());
+            }
+        } else if (node instanceof TableCell) {
+            this.currentRow.add(node);
+            if (!((TableCell)node).endsRow()) {
+                while (childInBodyIterator.hasNext()) {
+                    TableCell cell = (TableCell)childInBodyIterator.next();
+                    if (cell.startsRow()) {
+                        //next row already starts here, one step back
+                        childInBodyIterator.previous();
+                        break;
+                    }
+                    this.currentRow.add(cell);
+                    if (cell.endsRow()) {
+                        break;
+                    }
+                }
+            }
+        } else {
+            throw new IllegalStateException("Illegal class found: " + node.getClass().getName());
+        }
+        EffRow gridUnits = buildGridRow(this.currentRow);
+        log.debug(gridUnits);
+        rows.add(gridUnits);
+        return true;
+    }
+
+    private EffRow buildGridRow(List cells) {
+        EffRow row = new EffRow(this.currentRowIndex);
+        List gridUnits = row.getGridUnits();
+        
+        //Transfer available cells to their slots
+        int colnum = 1;
+        ListIterator iter = cells.listIterator();
+        while (iter.hasNext()) {
+            TableCell cell = (TableCell)iter.next();
+            if (cell.hasColumnNumber()) {
+                colnum = cell.getColumnNumber();
+            }
+            while (colnum > gridUnits.size()) {
+                gridUnits.add(null);
+            }
+            if (gridUnits.get(colnum - 1) != null) {
+                log.error("Overlapping cell at position " + colnum);
+                //TODO throw layout exception
+            }
+            TableColumn col = columns.getColumn(colnum);
+
+            //Add grid unit for primary grid unit
+            PrimaryGridUnit gu = new PrimaryGridUnit(cell, col, colnum - 1, this.currentRowIndex);
+            gridUnits.set(colnum - 1, gu);
+            
+            //Add cell infos on spanned slots if any
+            for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
+                colnum++;
+                GridUnit guSpan = new GridUnit(cell, columns.getColumn(colnum), colnum - 1, j);
+                if (colnum > gridUnits.size()) {
+                    gridUnits.add(guSpan);
+                } else {
+                    if (gridUnits.get(colnum - 1) != null) {
+                        log.error("Overlapping cell at position " + colnum);
+                        //TODO throw layout exception
+                    }
+                    gridUnits.set(colnum - 1, guSpan);
+                }
+            }
+            colnum++;
+        }
+        
+        //Post-processing the list (looking for gaps and resolve start and end borders)
+        postProcessGridUnits(gridUnits);
+        
+        return row;
+    }
+    
+    private void fillEmptyGridUnits(List gridUnits) {
+        for (int pos = 1; pos <= gridUnits.size(); pos++) {
+            GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
+            
+            //Empty grid units
+            if (gu == null) {
+                //Add grid unit
+                gu = new PrimaryGridUnit(null, columns.getColumn(pos), 
+                        pos - 1, this.currentRowIndex);
+                gridUnits.set(pos - 1, gu);
+            }
+        }
+    }
+    
+    private void postProcessGridUnits(List gridUnits) {
+        fillEmptyGridUnits(gridUnits);
+            
+        /*
+        //Border resolution now that the empty grid units are filled
+        for (int pos = 1; pos <= gridUnits.size(); pos++) {
+            GridUnit starting = (GridUnit)gridUnits.get(pos - 1);
+         
+            //Border resolution
+            if (table.isSeparateBorderModel()) {
+                starting.assignBorder(starting.layoutManager);
+            } else {
+                //Neighbouring grid unit at start edge 
+                OldGridUnit start = null;
+                int find = pos - 1;
+                while (find >= 1) {
+                    OldGridUnit candidate = (OldGridUnit)gridUnits.get(find - 1);
+                    if (candidate.isLastGridUnitColSpan()) {
+                        start = candidate;
+                        break;
+                    }
+                    find--;
+                }
+                
+                //Ending grid unit for current cell
+                OldGridUnit ending = null;
+                if (starting.layoutManager != null) {
+                    pos += starting.layoutManager.getFObj().getNumberColumnsSpanned() - 1;
+                }
+                ending = (OldGridUnit)gridUnits.get(pos - 1);
+                
+                //Neighbouring grid unit at end edge 
+                OldGridUnit end = null;
+                find = pos + 1;
+                while (find <= gridUnits.size()) {
+                    OldGridUnit candidate = (OldGridUnit)gridUnits.get(find - 1);
+                    if (candidate.isPrimaryGridUnit()) {
+                        end = candidate;
+                        break;
+                    }
+                    find++;
+                }
+                CommonBorderPaddingBackground borders = new CommonBorderPaddingBackground();
+                OldGridUnit.resolveBorder(table, borders, starting, 
+                        (start != null ? start : null), 
+                        CommonBorderPaddingBackground.START);
+                starting.effBorders = borders;
+                if (starting != ending) {
+                    borders = new CommonBorderPaddingBackground();
+                }
+                OldGridUnit.resolveBorder(table, borders, ending, 
+                        (end != null ? end : null), 
+                        CommonBorderPaddingBackground.END);
+                ending.effBorders = borders;
+                //Only start and end borders here, before and after during layout
+                //TODO resolve before and after borders during layout
+            }
+        }*/
+    }
+    
+    public class EffRow {
+        
+        private List gridUnits = new java.util.ArrayList();
+        private int index;
+        private MinOptMax height = new MinOptMax(0);
+        
+        public EffRow(int index) {
+            this.index = index;
+            this.height = height;
+        }
+        
+        public int getIndex() {
+            return this.index;
+        }
+        
+        public MinOptMax getHeight() {
+            return this.height;
+        }
+        
+        public void setHeight(MinOptMax height) {
+            this.height = height;
+        }
+        
+        public List getGridUnits() {
+            return gridUnits;
+        }
+        
+        /** @see java.lang.Object#toString() */
+        public String toString() {
+            StringBuffer sb = new StringBuffer("EffRow {");
+            sb.append(index);
+            sb.append(", ").append(height);
+            sb.append(", ").append(gridUnits.size()).append(" gu");
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+    
+}