Back to index

lightning-sunbird  0.9+nobinonly
nsGrid.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // Eric Vaughan
00040 // Netscape Communications
00041 //
00042 // See documentation in associated header file
00043 //
00044 
00045 #include "nsGrid.h"
00046 #include "nsGridRowGroupLayout.h"
00047 #include "nsBox.h"
00048 #include "nsIScrollableFrame.h"
00049 #include "nsSprocketLayout.h"
00050 #include "nsGridRow.h"
00051 #include "nsGridCell.h"
00052 
00053 /*
00054 The grid control expands the idea of boxes from 1 dimension to 2 dimensions. 
00055 It works by allowing the XUL to define a collection of rows and columns and then 
00056 stacking them on top of each other. Here is and example.
00057 
00058 Example 1:
00059 
00060 <grid>
00061    <columns>
00062       <column/>
00063       <column/>
00064    </columns>
00065 
00066    <rows>
00067       <row/>
00068       <row/>
00069    </rows>
00070 </grid>
00071 
00072 example 2:
00073 
00074 <grid>
00075    <columns>
00076       <column flex="1"/>
00077       <column flex="1"/>
00078    </columns>
00079 
00080    <rows>
00081       <row>
00082          <text value="hello"/>
00083          <text value="there"/>
00084       </row>
00085    </rows>
00086 </grid>
00087 
00088 example 3:
00089 
00090 <grid>
00091 
00092 <rows>
00093       <row>
00094          <text value="hello"/>
00095          <text value="there"/>
00096       </row>
00097    </rows>
00098 
00099    <columns>
00100       <column>
00101          <text value="Hey I'm in the column and I'm on top!"/>
00102       </column>
00103       <column/>
00104    </columns>
00105 
00106 </grid>
00107 
00108 Usually the columns are first and the rows are second, so the rows will be drawn on top of the columns. 
00109 You can reverse this by defining the rows first.
00110 Other tags are then placed in the <row> or <column> tags causing the grid to accommodate everyone.  
00111 It does this by creating 3 things: A cellmap, a row list, and a column list. The cellmap is a 2 
00112 dimensional array of nsGridCells. Each cell contains 2 boxes.  One cell from the column list 
00113 and one from the row list. When a cell is asked for its size it returns that smallest size it can 
00114 be to accommodate the 2 cells. Row lists and Column lists use the same data structure: nsGridRow. 
00115 Essentially a row and column are the same except a row goes alone the x axis and a column the y. 
00116 To make things easier and save code everything is written in terms of the x dimension. A flag is 
00117 passed in called "isHorizontal" that can flip the calculations to the y axis.
00118 
00119 Usually the number of cells in a row match the number of columns, but not always. 
00120 It is possible to define 5 columns for a grid but have 10 cells in one of the rows. 
00121 In this case 5 extra columns will be added to the column list to handle the situation. 
00122 These are called extraColumns/Rows.
00123 */
00124 
00125 nsGrid::nsGrid():mBox(nsnull),
00126                  mRows(nsnull),
00127                  mColumns(nsnull), 
00128                  mRowBox(nsnull),
00129                  mColumnBox(nsnull),
00130                  mNeedsRebuild(PR_TRUE),
00131                  mRowCount(0),
00132                  mColumnCount(0),
00133                  mExtraRowCount(0),
00134                  mExtraColumnCount(0),
00135                  mCellMap(nsnull),
00136                  mMarkingDirty(PR_FALSE)
00137 {
00138     MOZ_COUNT_CTOR(nsGrid);
00139 }
00140 
00141 nsGrid::~nsGrid()
00142 {
00143     FreeMap();
00144     MOZ_COUNT_DTOR(nsGrid);
00145 }
00146 
00147 /*
00148  * This is called whenever something major happens in the grid. And example 
00149  * might be when many cells or row are added. It sets a flag signaling that 
00150  * all the grids caches information should be recalculated.
00151  */
00152 void
00153 nsGrid::NeedsRebuild(nsBoxLayoutState& aState)
00154 {
00155   if (mNeedsRebuild)
00156     return;
00157 
00158   // iterate through columns and rows and dirty them
00159   mNeedsRebuild = PR_TRUE;
00160 
00161   // find the new row and column box. They could have 
00162   // been changed.
00163   mRowBox = nsnull;
00164   mColumnBox = nsnull;
00165   FindRowsAndColumns(&mRowBox, &mColumnBox);
00166 
00167   // tell all the rows and columns they are dirty
00168   DirtyRows(mRowBox, aState);
00169   DirtyRows(mColumnBox, aState);
00170 }
00171 
00172 
00173 
00177 void
00178 nsGrid::RebuildIfNeeded()
00179 {
00180   if (!mNeedsRebuild)
00181     return;
00182 
00183   mNeedsRebuild = PR_FALSE;
00184 
00185   // find the row and columns frames
00186   FindRowsAndColumns(&mRowBox, &mColumnBox);
00187 
00188   // count the rows and columns
00189   PRInt32 computedRowCount = 0;
00190   PRInt32 computedColumnCount = 0;
00191   PRInt32 rowCount = 0;
00192   PRInt32 columnCount = 0;
00193 
00194   CountRowsColumns(mRowBox, rowCount, computedColumnCount);
00195   CountRowsColumns(mColumnBox, columnCount, computedRowCount);
00196 
00197   // computedRowCount are the actual number of rows as determined by the 
00198   // columns children.
00199   // computedColumnCount are the number of columns as determined by the number
00200   // of rows children.
00201   // We can use this information to see how many extra columns or rows we need.
00202   // This can happen if there are are more children in a row that number of columns
00203   // defined. Example:
00204   //
00205   // <columns>
00206   //   <column/>
00207   // </columns>
00208   //
00209   // <rows>
00210   //   <row>
00211   //     <button/><button/>
00212   //   </row>
00213   // </rows>
00214   //
00215   // computedColumnCount = 2 // for the 2 buttons in the the row tag
00216   // computedRowCount = 0 // there is nothing in the  column tag
00217   // mColumnCount = 1 // one column defined
00218   // mRowCount = 1 // one row defined
00219   // 
00220   // So in this case we need to make 1 extra column.
00221   //
00222 
00223   // Make sure to update mExtraColumnCount no matter what, since it might
00224   // happen that we now have as many columns as are defined, and we wouldn't
00225   // want to have a positive mExtraColumnCount hanging about in that case!
00226   mExtraColumnCount = computedColumnCount - columnCount;
00227   if (computedColumnCount > columnCount) {
00228      columnCount = computedColumnCount;
00229   }
00230 
00231   // Same for rows.
00232   mExtraRowCount = computedRowCount - rowCount;
00233   if (computedRowCount > rowCount) {
00234      rowCount = computedRowCount;
00235   }
00236 
00237   // build and poplulate row and columns arrays
00238   BuildRows(mRowBox, rowCount, &mRows, PR_TRUE);
00239   BuildRows(mColumnBox, columnCount, &mColumns, PR_FALSE);
00240 
00241   // build and populate the cell map
00242   BuildCellMap(rowCount, columnCount, &mCellMap);
00243 
00244   mRowCount = rowCount;
00245   mColumnCount = columnCount;
00246 
00247   // populate the cell map from column and row children
00248   PopulateCellMap(mRows, mColumns, mRowCount, mColumnCount, PR_TRUE);
00249   PopulateCellMap(mColumns, mRows, mColumnCount, mRowCount, PR_FALSE);
00250 }
00251 
00252 void
00253 nsGrid::FreeMap()
00254 {
00255   if (mRows) 
00256     delete[] mRows;
00257 
00258   if (mColumns)
00259     delete[] mColumns;
00260 
00261   if (mCellMap)
00262     delete[] mCellMap;
00263 
00264   mRows = nsnull;
00265   mColumns = nsnull;
00266   mCellMap = nsnull;
00267   mColumnCount = 0;
00268   mRowCount = 0;
00269   mExtraColumnCount = 0;
00270   mExtraRowCount = 0;
00271   mRowBox = nsnull;
00272   mColumnBox = nsnull;
00273 }
00274 
00278 void
00279 nsGrid::FindRowsAndColumns(nsIBox** aRows, nsIBox** aColumns)
00280 {
00281   *aRows = nsnull;
00282   *aColumns = nsnull;
00283 
00284   // find the boxes that contain our rows and columns
00285   nsIBox* child = nsnull;
00286   // if we have <grid></grid> then mBox will be null (bug 125689)
00287   if (mBox)
00288     mBox->GetChildBox(&child);
00289 
00290   while(child)
00291   {
00292     nsIBox* oldBox = child;
00293     nsresult rv = NS_OK;
00294     nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(child, &rv);
00295     if (scrollFrame) {
00296        nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
00297        NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
00298        if (NS_FAILED(CallQueryInterface(scrolledFrame, &child)))
00299          child = nsnull;
00300     }
00301 
00302     nsCOMPtr<nsIBoxLayout> layout;
00303     child->GetLayoutManager(getter_AddRefs(layout));
00304 
00305      nsCOMPtr<nsIGridPart> monument( do_QueryInterface(layout) );
00306      if (monument)
00307      {
00308        nsGridRowGroupLayout* rowGroup = nsnull;
00309        monument->CastToRowGroupLayout(&rowGroup);
00310        if (rowGroup) {
00311           PRBool isHorizontal = !nsSprocketLayout::IsHorizontal(child);
00312           if (isHorizontal)
00313             *aRows = child;
00314           else
00315             *aColumns = child;
00316          
00317           if (*aRows && *aColumns)
00318             return;
00319        }
00320      }
00321 
00322     if (scrollFrame) {
00323       child = oldBox;
00324     }
00325 
00326     child->GetNextBox(&child);
00327   }
00328 }
00329 
00335 void
00336 nsGrid::CountRowsColumns(nsIBox* aRowBox, PRInt32& aRowCount, PRInt32& aComputedColumnCount)
00337 {
00338   // get the rowboxes layout manager. Then ask it to do the work for us
00339   if (aRowBox) {
00340     nsCOMPtr<nsIBoxLayout> layout;
00341     aRowBox->GetLayoutManager(getter_AddRefs(layout));
00342     if (layout) {
00343        nsCOMPtr<nsIGridPart> monument( do_QueryInterface(layout) );
00344        if (monument) 
00345           monument->CountRowsColumns(aRowBox, aRowCount, aComputedColumnCount);
00346     }
00347   }
00348 }
00349 
00350 
00354 void
00355 nsGrid::BuildRows(nsIBox* aBox, PRBool aRowCount, nsGridRow** aRows, PRBool aIsHorizontal)
00356 {
00357   // if no rows then return null
00358   if (aRowCount == 0) {
00359 
00360     // make sure we free up the memory.
00361     if (*aRows)
00362       delete[] (*aRows);
00363 
00364     *aRows = nsnull;
00365     return;
00366   }
00367 
00368   // create the array
00369   nsGridRow* row;
00370   
00371   // only create new rows if we have to. Reuse old rows.
00372   if (aIsHorizontal)
00373   { 
00374     if (aRowCount > mRowCount) {
00375        delete[] mRows;
00376        row = new nsGridRow[aRowCount];
00377     } else {
00378       for (PRInt32 i=0; i < mRowCount; i++)
00379         mRows[i].Init(nsnull, PR_FALSE);
00380 
00381       row = mRows;
00382     }
00383   } else {
00384     if (aRowCount > mColumnCount) {
00385        delete[] mColumns;
00386        row = new nsGridRow[aRowCount];
00387     } else {
00388        for (PRInt32 i=0; i < mColumnCount; i++)
00389          mColumns[i].Init(nsnull, PR_FALSE);
00390 
00391        row = mColumns;
00392     }
00393   }
00394 
00395   // populate it if we can. If not it will contain only dynamic columns
00396   if (aBox)
00397   {
00398     nsCOMPtr<nsIBoxLayout> layout;
00399     aBox->GetLayoutManager(getter_AddRefs(layout));
00400     if (layout) {
00401       nsCOMPtr<nsIGridPart> monument( do_QueryInterface(layout) );
00402       if (monument) {
00403          PRInt32 count;
00404          monument->BuildRows(aBox, row, &count);
00405       }
00406     }
00407   }
00408 
00409   *aRows = row;
00410 }
00411 
00412 
00416 void
00417 nsGrid::BuildCellMap(PRInt32 aRows, PRInt32 aColumns, nsGridCell** aCells)
00418 {
00419   PRInt32 size = aRows*aColumns;
00420   PRInt32 oldsize = mRowCount*mColumnCount;
00421   if (size == 0) {
00422     delete[] mCellMap;
00423     (*aCells) = nsnull;
00424   }
00425   else {
00426     if (size > oldsize) {
00427       delete[] mCellMap;
00428       (*aCells) = new nsGridCell[size];
00429     } else {
00430       // clear out cellmap
00431       for (PRInt32 i=0; i < oldsize; i++)
00432       {
00433         mCellMap[i].SetBoxInRow(nsnull);
00434         mCellMap[i].SetBoxInColumn(nsnull);
00435       }
00436 
00437       (*aCells) = mCellMap;
00438     }
00439   }
00440 }
00441 
00446 void
00447 nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, PRInt32 aRowCount, PRInt32 aColumnCount, PRBool aIsHorizontal)
00448 {
00449   if (!aRows)
00450     return;
00451 
00452    // look through the columns
00453   nscoord j = 0;
00454 
00455   for(PRInt32 i=0; i < aRowCount; i++) 
00456   {
00457      nsIBox* child = nsnull;
00458      nsGridRow* row = &aRows[i];
00459 
00460      // skip bogus rows. They have no cells
00461      if (row->mIsBogus) 
00462        continue;
00463 
00464      child = row->mBox;
00465      if (child) {
00466        child->GetChildBox(&child);
00467 
00468        j = 0;
00469 
00470        while(child && j < aColumnCount)
00471        {
00472          // skip bogus column. They have no cells
00473          nsGridRow* column = &aColumns[j];
00474          if (column->mIsBogus) 
00475          {
00476            j++;
00477            continue;
00478          }
00479 
00480          if (aIsHorizontal)
00481            GetCellAt(j,i)->SetBoxInRow(child);
00482          else
00483            GetCellAt(i,j)->SetBoxInColumn(child);
00484 
00485          child->GetNextBox(&child);
00486 
00487          j++;
00488        }
00489      }
00490   }
00491 }
00492 
00497 void 
00498 nsGrid::DirtyRows(nsIBox* aRowBox, nsBoxLayoutState& aState)
00499 {
00500   // make sure we prevent others from dirtying things.
00501   mMarkingDirty = PR_TRUE;
00502 
00503   // if the box is a grid part have it recursively hand it.
00504   if (aRowBox) {
00505     nsCOMPtr<nsIBoxLayout> layout;
00506     aRowBox->GetLayoutManager(getter_AddRefs(layout));
00507     if (layout) {
00508        nsCOMPtr<nsIGridPart> part( do_QueryInterface(layout) );
00509        if (part) 
00510           part->DirtyRows(aRowBox, aState);
00511     }
00512   }
00513 
00514   mMarkingDirty = PR_FALSE;
00515 }
00516 
00517 nsGridRow* nsGrid::GetColumns()
00518 {
00519   RebuildIfNeeded();
00520 
00521   return mColumns;
00522 }
00523 
00524 nsGridRow* nsGrid::GetRows()
00525 {
00526   RebuildIfNeeded();
00527 
00528   return mRows;
00529 }
00530 
00531 nsGridRow*
00532 nsGrid::GetColumnAt(PRInt32 aIndex, PRBool aIsHorizontal)
00533 {
00534   return GetRowAt(aIndex, !aIsHorizontal);
00535 }
00536 
00537 nsGridRow*
00538 nsGrid::GetRowAt(PRInt32 aIndex, PRBool aIsHorizontal)
00539 {
00540   RebuildIfNeeded();
00541 
00542   if (aIsHorizontal) {
00543     NS_ASSERTION(aIndex < mRowCount && aIndex >= 0, "Index out of range");
00544     return &mRows[aIndex];
00545   } else {
00546     NS_ASSERTION(aIndex < mColumnCount && aIndex >= 0, "Index out of range");
00547     return &mColumns[aIndex];
00548   }
00549 }
00550 
00551 nsGridCell*
00552 nsGrid::GetCellAt(PRInt32 aX, PRInt32 aY)
00553 {
00554   RebuildIfNeeded();
00555 
00556   NS_ASSERTION(aY < mRowCount && aY >= 0, "Index out of range");
00557   NS_ASSERTION(aX < mColumnCount && aX >= 0, "Index out of range");
00558   return &mCellMap[aY*mColumnCount+aX];
00559 }
00560 
00561 PRInt32
00562 nsGrid::GetExtraColumnCount(PRBool aIsHorizontal)
00563 {
00564   return GetExtraRowCount(!aIsHorizontal);
00565 }
00566 
00567 PRInt32
00568 nsGrid::GetExtraRowCount(PRBool aIsHorizontal)
00569 {
00570   RebuildIfNeeded();
00571 
00572   if (aIsHorizontal)
00573     return mExtraRowCount;
00574   else
00575     return mExtraColumnCount;
00576 }
00577 
00578 
00584 nsresult
00585 nsGrid::GetPrefRowSize(nsBoxLayoutState& aState, PRInt32 aRowIndex, nsSize& aSize, PRBool aIsHorizontal)
00586 { 
00587   NS_ASSERTION(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal), "Row index out of range!");
00588   if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
00589     return NS_OK;
00590 
00591   nscoord height = 0;
00592   GetPrefRowHeight(aState, aRowIndex, height, aIsHorizontal);
00593   SetLargestSize(aSize, height, aIsHorizontal);
00594 
00595   return NS_OK;
00596 }
00597 
00598 nsresult
00599 nsGrid::GetMinRowSize(nsBoxLayoutState& aState, PRInt32 aRowIndex, nsSize& aSize, PRBool aIsHorizontal)
00600 { 
00601   NS_ASSERTION(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal), "Row index out of range!");
00602 
00603   if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
00604     return NS_OK;
00605 
00606   nscoord height = 0;
00607   GetMinRowHeight(aState, aRowIndex, height, aIsHorizontal);
00608   SetLargestSize(aSize, height, aIsHorizontal);
00609 
00610   return NS_OK;
00611 }
00612 
00613 nsresult
00614 nsGrid::GetMaxRowSize(nsBoxLayoutState& aState, PRInt32 aRowIndex, nsSize& aSize, PRBool aIsHorizontal)
00615 { 
00616   NS_ASSERTION(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal), "Row index out of range!");
00617 
00618   if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
00619     return NS_OK;
00620 
00621   nscoord height = 0;
00622   GetMaxRowHeight(aState, aRowIndex, height, aIsHorizontal);
00623   SetSmallestSize(aSize, height, aIsHorizontal);
00624 
00625   return NS_OK;
00626 }
00627 
00628 void 
00629 nsGrid::GetPartFromBox(nsIBox* aBox, nsIGridPart** aPart)
00630 {
00631   *aPart = nsnull;
00632 
00633   if (aBox) {
00634     nsCOMPtr<nsIBoxLayout> layout;
00635     aBox->GetLayoutManager(getter_AddRefs(layout));
00636     if (layout) {
00637        nsCOMPtr<nsIGridPart> part( do_QueryInterface(layout) );
00638        if (part) { 
00639           *aPart = part.get();
00640           NS_IF_ADDREF(*aPart);
00641        }
00642     }
00643   }
00644 }
00645 
00646 void
00647 nsGrid::GetBoxTotalMargin(nsIBox* aBox, nsMargin& aMargin, PRBool aIsHorizontal)
00648 {
00649   // walk the boxes parent chain getting the border/padding/margin of our parent rows
00650   
00651   // first get the layour manager
00652   nsCOMPtr<nsIGridPart> part;
00653   nsCOMPtr<nsIGridPart> parent;
00654   GetPartFromBox(aBox, getter_AddRefs(part));
00655   if (part)
00656     part->GetTotalMargin(aBox, aMargin, aIsHorizontal);
00657 }
00658 
00668 void
00669 nsGrid::GetFirstAndLastRow(nsBoxLayoutState& aState, 
00670                           PRInt32& aFirstIndex, 
00671                           PRInt32& aLastIndex, 
00672                           nsGridRow*& aFirstRow,
00673                           nsGridRow*& aLastRow,
00674                           PRBool aIsHorizontal)
00675 {
00676   aFirstRow = nsnull;
00677   aLastRow = nsnull;
00678   aFirstIndex = -1;
00679   aLastIndex = -1;
00680 
00681   PRInt32 count = GetRowCount(aIsHorizontal);
00682 
00683   if (count == 0)
00684     return;
00685 
00686 
00687   // We could have collapsed columns either before or after our index.
00688   // they should not count. So if we are the 5th row and the first 4 are
00689   // collaped we become the first row. Or if we are the 9th row and
00690   // 10 up to the last row are collapsed we then become the last.
00691 
00692   // see if we are first
00693   PRInt32 i;
00694   for (i=0; i < count; i++)
00695   {
00696      nsGridRow* row = GetRowAt(i,aIsHorizontal);
00697      if (!row->IsCollapsed(aState)) {
00698        aFirstIndex = i;
00699        aFirstRow = row;
00700        break;
00701      }
00702   }
00703 
00704   // see if we are last
00705   for (i=count-1; i >= 0; i--)
00706   {
00707      nsGridRow* row = GetRowAt(i,aIsHorizontal);
00708      if (!row->IsCollapsed(aState)) {
00709        aLastIndex = i;
00710        aLastRow = row;
00711        break;
00712      }
00713 
00714   }
00715 }
00716 
00722 void
00723 nsGrid::GetRowOffsets(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aTop, nscoord& aBottom, PRBool aIsHorizontal)
00724 {
00725 
00726   RebuildIfNeeded();
00727 
00728   nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
00729 
00730   if (row->IsOffsetSet()) 
00731   {
00732     aTop    = row->mTop;
00733     aBottom = row->mBottom;
00734     return;
00735   }
00736 
00737   // first get the rows top and bottom border and padding
00738   nsIBox* box = row->GetBox();
00739 
00740   // add up all the padding
00741   nsMargin margin(0,0,0,0);
00742   nsMargin inset(0,0,0,0);
00743   nsMargin border(0,0,0,0);
00744   nsMargin padding(0,0,0,0);
00745   nsMargin totalBorderPadding(0,0,0,0);
00746   nsMargin totalMargin(0,0,0,0);
00747 
00748   // if there is a box and its not bogus take its
00749   // borders padding and insets into account
00750   if (box && !row->mIsBogus)
00751   {
00752      PRBool isCollapsed = PR_FALSE;
00753      box->IsCollapsed(aState, isCollapsed);
00754 
00755      if (!isCollapsed) 
00756      {
00757 
00758        box->GetInset(inset);
00759 
00760        // get real border and padding. GetBorderAndPadding
00761        // is redefined on nsGridRowLeafFrame. If we called it here
00762        // we would be in finite recurson.
00763        box->GetBorder(border);
00764        box->GetPadding(padding);
00765 
00766        totalBorderPadding += inset; 
00767        totalBorderPadding += border;
00768        totalBorderPadding += padding;
00769 
00770        box->GetMargin(margin);
00771      }
00772 
00773      // if we are the first or last row
00774      // take into account <rows> tags around us
00775      // that could have borders or margins.
00776      // fortunately they only affect the first
00777      // and last row inside the <rows> tag
00778 
00779      GetBoxTotalMargin(box, margin, aIsHorizontal);
00780 
00781      totalMargin = margin;
00782   }
00783 
00784   if (aIsHorizontal) {
00785     row->mTop = totalBorderPadding.top;
00786     row->mBottom = totalBorderPadding.bottom;
00787     row->mTopMargin = totalMargin.top;
00788     row->mBottomMargin = totalMargin.bottom;
00789   } else {
00790     row->mTop = totalBorderPadding.left;
00791     row->mBottom = totalBorderPadding.right;
00792     row->mTopMargin = totalMargin.left;
00793     row->mBottomMargin = totalMargin.right;
00794   }
00795 
00796   // if we are the first or last row take into account the top and bottom borders
00797   // of each columns. 
00798 
00799   // If we are the first row then get the largest top border/padding in 
00800   // our columns. If thats larger than the rows top border/padding use it.
00801 
00802   // If we are the last row then get the largest bottom border/padding in 
00803   // our columns. If thats larger than the rows bottom border/padding use it.
00804   PRInt32 firstIndex = 0;
00805   PRInt32 lastIndex = 0;
00806   nsGridRow* firstRow = nsnull;
00807   nsGridRow* lastRow = nsnull;
00808   GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, aIsHorizontal);
00809 
00810   if (aIndex == firstIndex || aIndex == lastIndex) {
00811     nscoord maxTop = 0;
00812     nscoord maxBottom = 0;
00813 
00814     // run through the columns. Look at each column
00815     // pick the largest top border or bottom border
00816     PRInt32 count = GetColumnCount(aIsHorizontal); 
00817 
00818     PRBool isCollapsed = PR_FALSE;
00819 
00820     for (PRInt32 i=0; i < count; i++)
00821     {  
00822       nsMargin totalChildBorderPadding(0,0,0,0);
00823 
00824       nsGridRow* column = GetColumnAt(i,aIsHorizontal);
00825       nsIBox* box = column->GetBox();
00826 
00827       if (box) 
00828       {
00829         // ignore collapsed children
00830         box->IsCollapsed(aState, isCollapsed);
00831 
00832         if (!isCollapsed)
00833         {
00834            // include the margin of the columns. To the row
00835            // at this point border/padding and margins all added
00836            // up to more needed space.
00837            GetBoxTotalMargin(box, margin, !aIsHorizontal);
00838            box->GetInset(inset);
00839            // get real border and padding. GetBorderAndPadding
00840            // is redefined on nsGridRowLeafFrame. If we called it here
00841            // we would be in finite recurson.
00842            box->GetBorder(border);
00843            box->GetPadding(padding);
00844            totalChildBorderPadding += inset; 
00845            totalChildBorderPadding += border;
00846            totalChildBorderPadding += padding;
00847            totalChildBorderPadding += margin;
00848         }
00849 
00850         nscoord top;
00851         nscoord bottom;
00852 
00853         // pick the largest top margin
00854         if (aIndex == firstIndex) {
00855           if (aIsHorizontal) {
00856             top = totalChildBorderPadding.top;
00857           } else {
00858             top = totalChildBorderPadding.left;
00859           }
00860           if (top > maxTop)
00861             maxTop = top;
00862         } 
00863 
00864         // pick the largest bottom margin
00865         if (aIndex == lastIndex) {
00866           if (aIsHorizontal) {
00867             bottom = totalChildBorderPadding.bottom;
00868           } else {
00869             bottom = totalChildBorderPadding.right;
00870           }
00871           if (bottom > maxBottom)
00872              maxBottom = bottom;
00873         }
00874 
00875       }
00876     
00877       // If the biggest top border/padding the columns is larger than this rows top border/padding
00878       // the use it.
00879       if (aIndex == firstIndex) {
00880         if (maxTop > (row->mTop + row->mTopMargin))
00881           row->mTop = maxTop - row->mTopMargin;
00882       }
00883 
00884       // If the biggest bottom border/padding the columns is larger than this rows bottom border/padding
00885       // the use it.
00886       if (aIndex == lastIndex) {
00887         if (maxBottom > (row->mBottom + row->mBottomMargin))
00888           row->mBottom = maxBottom - row->mBottomMargin;
00889       }
00890     }
00891   }
00892   
00893   aTop    = row->mTop;
00894   aBottom = row->mBottom;
00895 }
00896 
00902 nsresult
00903 nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aSize, PRBool aIsHorizontal)
00904 {
00905   RebuildIfNeeded();
00906 
00907   nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
00908 
00909   if (row->IsCollapsed(aState))
00910   {
00911     aSize = 0;
00912     return NS_OK;
00913   }
00914 
00915   if (row->IsPrefSet()) 
00916   {
00917     aSize = row->mPref;
00918     return NS_OK;
00919   }
00920 
00921   nsIBox* box = row->mBox;
00922 
00923   // set in CSS?
00924   if (box) 
00925   {
00926     nsSize cssSize;
00927     cssSize.width = -1;
00928     cssSize.height = -1;
00929     nsIBox::AddCSSPrefSize(aState, box, cssSize);
00930 
00931     row->mPref = GET_HEIGHT(cssSize, aIsHorizontal);
00932 
00933     // yep do nothing.
00934     if (row->mPref != -1)
00935     {
00936       aSize = row->mPref;
00937       return NS_OK;
00938     }
00939   }
00940 
00941   // get the offsets so they are cached.
00942   nscoord top;
00943   nscoord bottom;
00944   GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
00945 
00946 
00947   // is the row bogus? If so then just ask it for its size
00948   // it should not be affected by cells in the grid. 
00949   if (row->mIsBogus)
00950   {
00951      nsSize size(0,0);
00952      nsIBox* box = row->GetBox();
00953      if (box) 
00954      {
00955        box->GetPrefSize(aState, size);
00956        nsBox::AddMargin(box, size);
00957        nsStackLayout::AddOffset(aState, box, size);
00958      }
00959 
00960      row->mPref = GET_HEIGHT(size, aIsHorizontal);
00961      aSize = row->mPref;
00962 
00963      return NS_OK;
00964   }
00965 
00966   nsSize size(0,0);
00967 
00968   nsGridCell* child;
00969 
00970   PRInt32 count = GetColumnCount(aIsHorizontal); 
00971 
00972   PRBool isCollapsed = PR_FALSE;
00973 
00974   for (PRInt32 i=0; i < count; i++)
00975   {  
00976     if (aIsHorizontal)
00977      child = GetCellAt(i,aIndex);
00978     else
00979      child = GetCellAt(aIndex,i);
00980 
00981     // ignore collapsed children
00982     child->IsCollapsed(aState, isCollapsed);
00983 
00984     if (!isCollapsed)
00985     {
00986       nsSize childSize(0,0);
00987 
00988       child->GetPrefSize(aState, childSize);
00989 
00990       nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
00991     }
00992   }
00993 
00994   row->mPref = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
00995 
00996 
00997   aSize = row->mPref;
00998 
00999   return NS_OK;
01000 }
01001 
01002 nsresult
01003 nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aSize, PRBool aIsHorizontal)
01004 {
01005   RebuildIfNeeded();
01006 
01007   nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
01008 
01009   if (row->IsCollapsed(aState))
01010   {
01011     aSize = 0;
01012     return NS_OK;
01013   } 
01014 
01015   if (row->IsMinSet()) 
01016   {
01017     aSize = row->mMin;
01018     return NS_OK;
01019   }
01020 
01021   nsIBox* box = row->mBox;
01022 
01023   // set in CSS?
01024   if (box) {
01025     nsSize cssSize;
01026     cssSize.width = -1;
01027     cssSize.height = -1;
01028     nsIBox::AddCSSMinSize(aState, box, cssSize);
01029 
01030     row->mMin = GET_HEIGHT(cssSize, aIsHorizontal);
01031 
01032     // yep do nothing.
01033     if (row->mMin != -1)
01034     {
01035       aSize = row->mMin;
01036       return NS_OK;
01037     }
01038   }
01039 
01040   // get the offsets so they are cached.
01041   nscoord top;
01042   nscoord bottom;
01043   GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
01044 
01045     // is the row bogus? If so then just ask it for its size
01046   // it should not be affected by cells in the grid. 
01047   if (row->mIsBogus)
01048   {
01049      nsSize size(0,0);
01050      nsIBox* box = row->GetBox();
01051      if (box) {
01052        box->GetPrefSize(aState, size);
01053        nsBox::AddMargin(box, size);
01054        nsStackLayout::AddOffset(aState, box, size);
01055      }
01056 
01057      row->mMin = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
01058      aSize = row->mMin;
01059 
01060      return NS_OK;
01061   }
01062 
01063   nsSize size(0,0);
01064 
01065   nsGridCell* child;
01066 
01067   PRInt32 count = GetColumnCount(aIsHorizontal); 
01068 
01069   PRBool isCollapsed = PR_FALSE;
01070 
01071   for (PRInt32 i=0; i < count; i++)
01072   {  
01073     if (aIsHorizontal)
01074      child = GetCellAt(i,aIndex);
01075     else
01076      child = GetCellAt(aIndex,i);
01077 
01078     // ignore collapsed children
01079     child->IsCollapsed(aState, isCollapsed);
01080 
01081     if (!isCollapsed)
01082     {
01083       nsSize childSize(0,0);
01084 
01085       child->GetMinSize(aState, childSize);
01086 
01087       nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
01088     }
01089   }
01090 
01091   row->mMin = GET_HEIGHT(size, aIsHorizontal);
01092 
01093   aSize = row->mMin;
01094 
01095   return NS_OK;
01096 }
01097 
01098 nsresult
01099 nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aSize, PRBool aIsHorizontal)
01100 {
01101   RebuildIfNeeded();
01102 
01103   nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
01104 
01105   if (row->IsCollapsed(aState))
01106   {
01107     aSize = 0;
01108     return NS_OK;
01109   }
01110 
01111   if (row->IsMaxSet()) 
01112   {
01113     aSize = row->mMax;
01114     return NS_OK;
01115   }
01116 
01117   nsIBox* box = row->mBox;
01118 
01119   // set in CSS?
01120   if (box) {
01121     nsSize cssSize;
01122     cssSize.width = -1;
01123     cssSize.height = -1;
01124     nsIBox::AddCSSMaxSize(aState, box, cssSize);
01125     
01126     row->mMax = GET_HEIGHT(cssSize, aIsHorizontal);
01127 
01128     // yep do nothing.
01129     if (row->mMax != -1)
01130     {
01131       aSize = row->mMax;
01132       return NS_OK;
01133     }
01134   }
01135 
01136   // get the offsets so they are cached.
01137   nscoord top;
01138   nscoord bottom;
01139   GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
01140 
01141   // is the row bogus? If so then just ask it for its size
01142   // it should not be affected by cells in the grid. 
01143   if (row->mIsBogus)
01144   {
01145      nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
01146      nsIBox* box = row->GetBox();
01147      if (box) {
01148        box->GetPrefSize(aState, size);
01149        nsBox::AddMargin(box, size);
01150        nsStackLayout::AddOffset(aState, box, size);
01151      }
01152 
01153      row->mMax = GET_HEIGHT(size, aIsHorizontal);
01154      aSize = row->mMax;
01155 
01156      return NS_OK;
01157   }
01158 
01159   nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
01160 
01161   nsGridCell* child;
01162 
01163   PRInt32 count = GetColumnCount(aIsHorizontal); 
01164 
01165   PRBool isCollapsed = PR_FALSE;
01166 
01167   for (PRInt32 i=0; i < count; i++)
01168   {  
01169     if (aIsHorizontal)
01170      child = GetCellAt(i,aIndex);
01171     else
01172      child = GetCellAt(aIndex,i);
01173 
01174     // ignore collapsed children
01175     child->IsCollapsed(aState, isCollapsed);
01176 
01177     if (!isCollapsed)
01178     {
01179       nsSize childSize(0,0);
01180       child->GetMaxSize(aState, childSize);
01181       nsSize min(0,0);
01182       child->GetMinSize(aState, min);
01183       nsBox::BoundsCheckMinMax(min, childSize);
01184 
01185       nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
01186     }
01187   }
01188 
01189   row->mMax = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
01190 
01191   aSize = row->mMax;
01192 
01193   return NS_OK;
01194 }
01195 
01196 PRBool
01197 nsGrid::IsGrid(nsIBox* aBox)
01198 {
01199   if (!aBox)
01200     return PR_FALSE;
01201 
01202   nsCOMPtr<nsIGridPart> part;
01203   GetPartFromBox(aBox, getter_AddRefs(part));
01204   if (!part)
01205     return PR_FALSE;
01206 
01207   nsGridLayout2* grid = nsnull; 
01208   part->CastToGridLayout(&grid);
01209 
01210   if (grid)
01211     return PR_TRUE;
01212 
01213   return PR_FALSE;
01214 }
01215 
01221 nsresult
01222 nsGrid::GetRowFlex(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aFlex, PRBool aIsHorizontal)
01223 {
01224   RebuildIfNeeded();
01225 
01226   nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
01227 
01228   if (row->IsFlexSet()) 
01229   {
01230     aFlex = row->mFlex;
01231     return NS_OK;
01232   }
01233 
01234   nsIBox* box = row->mBox;
01235   row->mFlex = 0;
01236 
01237   if (box) {
01238 
01239     // We need our flex but a inflexible row could be around us. If so
01240     // neither are we. However if its the row tag just inside the grid it won't 
01241     // affect us. We need to do this for this case:
01242     // <grid> 
01243     //   <rows> 
01244     //     <rows> // this is not flexible. So our children should not be flexible
01245     //        <row flex="1"/>
01246     //        <row flex="1"/>
01247     //     </rows>
01248     //        <row/>
01249     //   </rows>
01250     // </grid>
01251     //
01252     // or..
01253     //
01254     // <grid> 
01255     //  <rows>
01256     //   <rows> // this is not flexible. So our children should not be flexible
01257     //     <rows flex="1"> 
01258     //        <row flex="1"/>
01259     //        <row flex="1"/>
01260     //     </rows>
01261     //        <row/>
01262     //   </rows>
01263     //  </row>
01264     // </grid>
01265 
01266 
01267     // So here is how it looks
01268     //
01269     // <grid>     
01270     //   <rows>   // parentsParent
01271     //     <rows> // parent
01272     //        <row flex="1"/> 
01273     //        <row flex="1"/>
01274     //     </rows>
01275     //        <row/>
01276     //   </rows>
01277     // </grid>
01278 
01279     // so the answer is simple: 1) Walk our parent chain. 2) If we find
01280     // someone who is not flexible and they aren't the rows immediately in
01281     // the grid. 3) Then we are not flexible
01282 
01283     nsIBox* parent=nsnull;
01284     nsIBox* parentsParent=nsnull;
01285 
01286     box = GetScrollBox(box);
01287     box->GetParentBox(&parent);
01288     
01289     while(parent)
01290     {
01291       parent = GetScrollBox(parent);
01292       parent->GetParentBox(&parentsParent);
01293 
01294       // if our parents parent is not a grid
01295       // the get its flex. If its 0 then we are
01296       // not flexible.
01297       if (parentsParent) {
01298         if (!IsGrid(parentsParent)) {
01299           PRInt32 flex = 0;
01300           parent->GetFlex(aState, flex);
01301           nsIBox::AddCSSFlex(aState, parent, flex);
01302           if (flex == 0) {
01303             row->mFlex = 0;
01304             aFlex = 0;
01305             return NS_OK;
01306           }
01307         } else 
01308           break;
01309       }
01310 
01311       parent = parentsParent;
01312     }
01313     
01314     // get the row flex.
01315     box->GetFlex(aState, row->mFlex);
01316     nsIBox::AddCSSFlex(aState, box, row->mFlex);
01317 
01318   }
01319 
01320   aFlex = row->mFlex;
01321 
01322   return NS_OK;
01323 }
01324 
01325 void
01326 nsGrid::SetLargestSize(nsSize& aSize, nscoord aHeight, PRBool aIsHorizontal)
01327 {
01328   if (aIsHorizontal) {
01329     if (aSize.height < aHeight)
01330       aSize.height = aHeight;
01331   } else {
01332     if (aSize.width < aHeight)
01333       aSize.width = aHeight;
01334   }
01335 }
01336 
01337 void
01338 nsGrid::SetSmallestSize(nsSize& aSize, nscoord aHeight, PRBool aIsHorizontal)
01339 {
01340   if (aIsHorizontal) {
01341     if (aSize.height > aHeight)
01342       aSize.height = aHeight;
01343   } else {
01344     if (aSize.width < aHeight)
01345       aSize.width = aHeight;
01346   }
01347 }
01348 
01349 PRInt32 
01350 nsGrid::GetRowCount(PRInt32 aIsHorizontal)
01351 {
01352   RebuildIfNeeded();
01353 
01354   if (aIsHorizontal)
01355     return mRowCount;
01356   else
01357     return mColumnCount;
01358 }
01359 
01360 PRInt32 
01361 nsGrid::GetColumnCount(PRInt32 aIsHorizontal)
01362 {
01363   return GetRowCount(!aIsHorizontal);
01364 }
01365 
01370 void 
01371 nsGrid::RowChildIsDirty(nsBoxLayoutState& aState, PRInt32 aRowIndex, PRInt32 aColumnIndex, PRBool aIsHorizontal)
01372 { 
01373   // if we are already dirty do nothing.
01374   if (mNeedsRebuild || mMarkingDirty)
01375     return;
01376 
01377   NeedsRebuild(aState);
01378 
01379   // This code does not work with trees when rows are
01380   // dynamically inserted, the cache values are invalid.
01381   /*
01382   mMarkingDirty = PR_TRUE;
01383 
01384   // index out of range. Rebuild it all
01385   if (aRowIndex >= GetRowCount(aIsHorizontal) || aColumnIndex >= GetColumnCount(aIsHorizontal))
01386   {
01387     NeedsRebuild(aState);
01388     return;
01389   }
01390 
01391   // dirty our 2 outer nsGridRows. (one for columns and one for rows)
01392   // we need to do this because the rows and column we are given may be Extra ones
01393   // and may not have any Box associated with them. If you dirtied them then
01394   // corresponding nsGridRowGroup around them would never get dirty. So lets just
01395   // do it manually here.
01396 
01397   if (mRowBox)
01398     mRowBox->MarkDirty(aState);
01399 
01400   if (mColumnBox)
01401     mColumnBox->MarkDirty(aState);
01402 
01403   // dirty just our row and column that we were given
01404   nsGridRow* row = GetRowAt(aRowIndex, aIsHorizontal);
01405   row->MarkDirty(aState);
01406 
01407   nsGridRow* column = GetColumnAt(aColumnIndex, aIsHorizontal);
01408   column->MarkDirty(aState);
01409 
01410 
01411   mMarkingDirty = PR_FALSE;
01412   */
01413 }
01414 
01419 void 
01420 nsGrid::RowIsDirty(nsBoxLayoutState& aState, PRInt32 aIndex, PRBool aIsHorizontal)
01421 {
01422   if (mMarkingDirty)
01423     return;
01424 
01425   NeedsRebuild(aState);
01426 }
01427 
01428 /*
01429  * A cell in the given row or columns at the given index has had a child added or removed
01430  */
01431 void 
01432 nsGrid::CellAddedOrRemoved(nsBoxLayoutState& aState, PRInt32 aIndex, PRBool aIsHorizontal)
01433 {
01434   // TBD see if the cell will fit in our current row. If it will
01435   // just add it in. 
01436   // but for now rebuild everything.
01437   if (mMarkingDirty)
01438     return;
01439 
01440   NeedsRebuild(aState);
01441 }
01442 
01446 void 
01447 nsGrid::RowAddedOrRemoved(nsBoxLayoutState& aState, PRInt32 aIndex, PRBool aIsHorizontal)
01448 {
01449   // TBD see if we have extra room in the table and just add the new row in
01450   // for now rebuild the world
01451   if (mMarkingDirty)
01452     return;
01453 
01454   NeedsRebuild(aState);
01455 }
01456 
01457 /*
01458  * Scrollframes are tranparent. If this is given a scrollframe is will return the
01459  * frame inside. If there is no scrollframe it does nothing.
01460  */
01461 nsIBox*
01462 nsGrid::GetScrolledBox(nsIBox* aChild)
01463 {
01464   // first see if it is a scrollframe. If so walk down into it and get the scrolled child
01465       nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(aChild);
01466       if (scrollFrame) {
01467          nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
01468          NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
01469          return scrolledFrame->IsBoxFrame() ? scrolledFrame : nsnull;
01470       }
01471 
01472       return aChild;
01473 }
01474 
01475 /*
01476  * Scrollframes are tranparent. If this is given a child in a scrollframe is will return the
01477  * scrollframe ourside it. If there is no scrollframe it does nothing.
01478  */
01479 nsIBox*
01480 nsGrid::GetScrollBox(nsIBox* aChild)
01481 {
01482   if (!aChild)
01483     return nsnull;
01484 
01485   // get parent
01486   nsIBox* parent = nsnull;
01487   nsCOMPtr<nsIBoxLayout> layout;
01488   nsCOMPtr<nsIGridPart> parentGridRow;
01489 
01490   aChild->GetParentBox(&parent);
01491 
01492   // walk up until we find a scrollframe or a part
01493   // if its a scrollframe return it.
01494   // if its a parent then the child passed does not
01495   // have a scroll frame immediately wrapped around it.
01496   while (parent) {
01497     nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(parent);
01498     // scrollframe? Yep return it.
01499     if (scrollFrame)
01500       return parent;
01501 
01502     parent->GetLayoutManager(getter_AddRefs(layout));
01503     parentGridRow = do_QueryInterface(layout);
01504     // if a part then just return the child
01505     if (parentGridRow) 
01506       break;
01507 
01508     parent->GetParentBox(&parent);
01509   }
01510 
01511   return aChild;
01512 }
01513 
01514 
01515 
01516 #ifdef DEBUG_grid
01517 void
01518 nsGrid::PrintCellMap()
01519 {
01520   
01521   printf("-----Columns------\n");
01522   for (int x=0; x < mColumnCount; x++) 
01523   {
01524    
01525     nsGridRow* column = GetColumnAt(x);
01526     printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
01527   }
01528 
01529   printf("\n-----Rows------\n");
01530   for (x=0; x < mRowCount; x++) 
01531   {
01532     nsGridRow* column = GetRowAt(x);
01533     printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
01534   }
01535 
01536   printf("\n");
01537   
01538 }
01539 #endif