00001 #ifndef hpp_TableLayout_hpp
00002 #define hpp_TableLayout_hpp
00003
00004
00005 #include "../HTMLParser/DOM.hpp"
00006
00007 #include "../Containers/Container.hpp"
00008
00009 #include "BoxHierarchy.hpp"
00010
00011 namespace HTML
00012 {
00013 namespace Renderer
00014 {
00019 class TableLayout
00020 {
00021
00022 public:
00030 struct Cell
00031 {
00032 public:
00034 enum { NoWidthDeclared = (uint32)-1 };
00036 uint32 width;
00038 uint32 horizontalSpan;
00040 uint32 verticalSpan;
00041
00043 const void * userData;
00044
00046 void * userData2;
00048 uint32 minimumWidth;
00050 uint32 maximumWidth;
00051
00053 Cell(const uint32 _width = NoWidthDeclared, const uint32 hspan = 1, const uint32 vspan = 1, const void * user = 0) : width(_width), horizontalSpan(hspan), verticalSpan(vspan), userData(user), userData2(0) {}
00054 };
00055
00060 struct Row
00061 {
00062 public:
00064 Container::PlainOldData<Cell>::Array cellArray;
00066 enum RowType
00067 {
00068 Header = 0,
00069 Data = 1,
00070 Footer = 2,
00071 } rowType;
00072
00073
00074 public:
00076 inline Cell & operator[] (const uint32 index) { return cellArray[index]; }
00077
00082 inline Cell * getCellOnColumn(int32 index)
00083 {
00084 if (index > (int32)cellArray.getSize()) return 0;
00085 for (uint32 i = 0; index > 0 && i < cellArray.getSize(); i++)
00086 {
00087 uint32 hspan = cellArray[i].horizontalSpan;
00088 if (hspan > (uint32)index) return &cellArray[i];
00089 index -= hspan;
00090 }
00091 return 0;
00092 }
00093
00095 inline const uint32 cellCount() const { return cellArray.getSize(); }
00097 inline const RowType getRowType() const { return rowType; }
00098
00102 inline void appendCell(const Cell & cell) { cellArray.Append(cell); }
00109 inline void ensureSize(const uint32 size, const bool multipleCells = true)
00110 {
00111 if (size <= cellCount()) return;
00112 uint32 nbMissing = size - cellCount();
00113 if (multipleCells) while (nbMissing--) appendCell(Cell()); else appendCell(Cell(Cell::NoWidthDeclared, nbMissing));
00114 }
00115
00117 Row(const RowType type = Data) : rowType(Data) {}
00118 };
00119
00121 struct Column
00122 {
00125 enum WidthType
00126 {
00127 Fixed = 1,
00128 Percentage = 2,
00129 Multiple = 3,
00130 } widthType;
00132 uint32 width;
00134 uint32 span;
00135
00137 uint32 maximumWidth;
00139 uint32 minimumWidth;
00140
00142 Column(const WidthType type = Multiple, const uint32 _width = 1, const uint32 _span = 1) : widthType(type), width(_width), span(_span), maximumWidth(0), minimumWidth(-1) {}
00143 };
00144
00147 typedef Container::WithCopyConstructor<Row>::Array RowArray;
00149 typedef Container::WithCopyConstructor<Column>::Array ColumnArray;
00150
00151
00152
00153 private:
00155 Cell *** cellMap;
00157 uint32 cellMapWidth;
00159 uint32 cellMapHeight;
00160
00162 RowArray rowArray;
00164 ColumnArray columnArray;
00165
00166 public:
00168 uint32 maximumWidth;
00170 uint32 minimumWidth;
00171
00172
00173 private:
00176 inline const uint32 typedRowCount(const Row::RowType type) const
00177 {
00178 uint32 count = 0;
00179 for (uint32 i = 0; i < rowArray.getSize(); i++)
00180 count += rowArray[i].getRowType() == type;
00181 return count;
00182 }
00183
00185 inline void cleanCellMap()
00186 {
00187 if (cellMap) { for (uint32 i = 0; i < cellMapHeight; i++) delete[] cellMap[i]; }
00188 delete[] cellMap; cellMap = 0;
00189 cellMapWidth = cellMapHeight = 0;
00190 }
00191
00222 inline bool createCellMap()
00223 {
00224 cleanCellMap();
00225 cellMap = new Cell ** [rowArray.getSize()];
00226 if (!cellMap) return false;
00227
00228 cellMapHeight = rowArray.getSize();
00229 cellMapWidth = realColumnCount();
00230 uint32 i = 0;
00231 for (; i < cellMapHeight; i++)
00232 {
00233 cellMap[i] = new Cell* [cellMapWidth];
00234 if (!cellMap[i]) { cleanCellMap(); return false; }
00235 memset(cellMap[i], 0, sizeof(cellMap[i][0]) * cellMapWidth);
00236 }
00237
00238 for (i = 0; i < cellMapHeight; i++)
00239 {
00240 Row & row = rowArray[i];
00241 uint32 j = 0; uint32 index = 0;
00242 while (j < cellMapWidth && index < row.cellCount())
00243 {
00244 Cell & cell = row[index++];
00245 uint32 z = 0, t = 0;
00246
00247 while (cellMap[i][j] && j < cellMapWidth) j+=cellMap[i][j]->horizontalSpan;
00248 for (; z < cell.verticalSpan && (i+z) < cellMapHeight; z++)
00249 {
00250 for (t = 0; t < cell.horizontalSpan && (j+t) < cellMapWidth; t++)
00251 {
00252
00253 if (!cellMap[i+z][j+t]) cellMap[i+z][j+t] = &cell;
00254 }
00255 }
00256
00257 j += cell.horizontalSpan;
00258 }
00259 }
00260 return true;
00261 }
00262
00263
00264 public:
00266 inline Row & operator[](const uint32 index) { return rowArray[index]; }
00269 inline const uint32 dataRowCount() const { return typedRowCount(Row::Data); }
00272 inline const uint32 headerRowCount() const { return typedRowCount(Row::Header); }
00275 inline const uint32 footerRowCount() const { return typedRowCount(Row::Footer); }
00278 inline const uint32 rowCount() const { return rowArray.getSize(); }
00279
00281 inline const uint32 realColumnCount() const
00282 {
00283 uint32 count = 0;
00284 for (uint32 i = 0; i < columnArray.getSize(); i++) { count += columnArray[i].span; }
00285 return count;
00286 }
00287
00291 inline void appendColumn(const Column & col)
00292 {
00293 columnArray.Append(col);
00294
00295
00296
00297 cleanCellMap();
00298 }
00299
00304 inline void appendMultipleColumns(uint32 count, const Column & col)
00305 {
00306 while (count--) columnArray.Append(col);
00307
00308
00309
00310 cleanCellMap();
00311 }
00312
00313
00319 inline void updateRowAt(const uint32 index, const Row & row)
00320 {
00321 if (index < rowCount()) { rowArray[index] = row; }
00322 else if (index == rowCount()) { rowArray.Append(row); cleanCellMap(); }
00323 }
00324
00328 inline Column * columnAt(const uint32 index) { if (index < realColumnCount()) return &columnArray[index]; return 0; }
00333 inline Column & unsafeColumnAt(const uint32 index) { return columnArray[index]; }
00334
00340 inline Cell * findCell(const void * data, const bool findFirstData = true)
00341 {
00342 for (uint32 i = 0; i < rowArray.getSize(); i++)
00343 {
00344 Row & row = rowArray[i];
00345 for (uint32 j = 0; j < row.cellCount(); j++)
00346 {
00347 if ((findFirstData && row[j].userData == data) || (!findFirstData && row[j].userData2 == data) ) return &row[j];
00348 }
00349 }
00350 return 0;
00351 }
00352
00359 inline Cell * findCellAt(const uint32 rowIndex, const uint32 colIndex)
00360 {
00361
00362 uint32 maxColumnCount = realColumnCount();
00363 if (rowIndex >= rowArray.getSize() || colIndex >= maxColumnCount) return 0;
00364 if (!cellMap)
00365 if (!createCellMap()) return 0;
00366 return cellMap[rowIndex][colIndex];
00367 }
00368
00369
00370 public:
00372 TableLayout() : cellMap(0) {}
00374 ~TableLayout() { cleanCellMap(); }
00375 };
00376
00377
00378 }
00379 }
00380
00381 #endif