00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "table_layout.h"
00025 #include "render_table.h"
00026
00027 #include <kglobal.h>
00028
00029 using namespace khtml;
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 FixedTableLayout::FixedTableLayout( RenderTable *table )
00083 : TableLayout ( table )
00084 {
00085 }
00086
00087 FixedTableLayout::~FixedTableLayout()
00088 {
00089 }
00090
00091 int FixedTableLayout::calcWidthArray( int tableWidth )
00092 {
00093 int usedWidth = 0;
00094
00095
00096 RenderObject *child = table->firstChild();
00097 int cCol = 0;
00098 int nEffCols = table->numEffCols();
00099 width.resize( nEffCols );
00100 width.fill( Length( Variable ) );
00101
00102 #ifdef DEBUG_LAYOUT
00103 qDebug("FixedTableLayout::calcWidthArray( %d )", tableWidth );
00104 qDebug(" col elements:");
00105 #endif
00106
00107 Length grpWidth;
00108 while ( child ) {
00109 if ( child->isTableCol() ) {
00110 RenderTableCol *col = static_cast<RenderTableCol *>(child);
00111 int span = col->span();
00112 if ( col->firstChild() ) {
00113 grpWidth = col->style()->width();
00114 } else {
00115 Length w = col->style()->width();
00116 if ( w.isVariable() )
00117 w = grpWidth;
00118 int effWidth = 0;
00119 if ( w.isFixed() && w.value() > 0 ) {
00120 effWidth = w.value();
00121 effWidth = KMIN( effWidth, 32760 );
00122 }
00123 #ifdef DEBUG_LAYOUT
00124 qDebug(" col element: effCol=%d, span=%d: %d w=%d type=%d",
00125 cCol, span, effWidth, w.value, w.type);
00126 #endif
00127 int usedSpan = 0;
00128 int i = 0;
00129 while ( usedSpan < span ) {
00130 if( cCol + i >= nEffCols ) {
00131 table->appendColumn( span - usedSpan );
00132 nEffCols++;
00133 width.resize( nEffCols );
00134 width[nEffCols-1] = Length();
00135 }
00136 int eSpan = table->spanOfEffCol( cCol+i );
00137 if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) {
00138 width[cCol+i] = Length( w.value() * eSpan, w.type() );
00139 usedWidth += effWidth * eSpan;
00140 #ifdef DEBUG_LAYOUT
00141 qDebug(" setting effCol %d (span=%d) to width %d(type=%d)",
00142 cCol+i, eSpan, width[cCol+i].value, width[cCol+i].type );
00143 #endif
00144 }
00145 usedSpan += eSpan;
00146 i++;
00147 }
00148 cCol += i;
00149 }
00150 } else {
00151 break;
00152 }
00153
00154 RenderObject *next = child->firstChild();
00155 if ( !next )
00156 next = child->nextSibling();
00157 if ( !next && child->parent()->isTableCol() ) {
00158 next = child->parent()->nextSibling();
00159 grpWidth = Length();
00160 }
00161 child = next;
00162 }
00163
00164 #ifdef DEBUG_LAYOUT
00165 qDebug(" first row:");
00166 #endif
00167
00168 RenderTableSection *section = table->head;
00169 if ( !section )
00170 section = table->firstBody;
00171 if ( !section )
00172 section = table->foot;
00173 if ( section && section->firstChild() ) {
00174 cCol = 0;
00175
00176 child = section->firstChild()->firstChild();
00177 while ( child ) {
00178 if ( child->isTableCell() ) {
00179 RenderTableCell *cell = static_cast<RenderTableCell *>(child);
00180 Length w = cell->style()->width();
00181 int span = cell->colSpan();
00182 int effWidth = 0;
00183 if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) {
00184 effWidth = w.value();
00185 effWidth = kMin( effWidth, 32760 );
00186 }
00187 #ifdef DEBUG_LAYOUT
00188 qDebug(" table cell: effCol=%d, span=%d: %d", cCol, span, effWidth);
00189 #endif
00190 int usedSpan = 0;
00191 int i = 0;
00192 while ( usedSpan < span ) {
00193 Q_ASSERT( cCol + i < nEffCols );
00194 int eSpan = table->spanOfEffCol( cCol+i );
00195
00196 if ( width[cCol+i].isVariable() && !w.isVariable() ) {
00197 width[cCol+i] = Length( w.value()*eSpan, w.type() );
00198 usedWidth += effWidth*eSpan;
00199 #ifdef DEBUG_LAYOUT
00200 qDebug(" setting effCol %d (span=%d) to width %d(type=%d)",
00201 cCol+i, eSpan, width[cCol+i].value, width[cCol+i].type );
00202 #endif
00203 }
00204 #ifdef DEBUG_LAYOUT
00205 else {
00206 qDebug(" width of col %d already defined (span=%d)", cCol, table->spanOfEffCol( cCol ) );
00207 }
00208 #endif
00209 usedSpan += eSpan;
00210 i++;
00211 }
00212 cCol += i;
00213 } else {
00214 Q_ASSERT( false );
00215 }
00216 child = child->nextSibling();
00217 }
00218 }
00219
00220 return usedWidth;
00221
00222 }
00223
00224 void FixedTableLayout::calcMinMaxWidth()
00225 {
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 int bs = table->bordersAndSpacing();
00237 table->m_minWidth = 0;
00238 table->m_maxWidth = 0;
00239 short tableWidth = table->style()->width().isFixed() ? table->style()->width().value() - bs : 0;
00240
00241 table->m_minWidth = calcWidthArray( tableWidth );
00242 table->m_minWidth += bs;
00243
00244 table->m_minWidth = kMax( table->m_minWidth, tableWidth );
00245 table->m_maxWidth = table->m_minWidth;
00246 if ( !tableWidth ) {
00247 bool haveNonFixed = false;
00248 for ( unsigned int i = 0; i < width.size(); i++ ) {
00249 if ( !width[i].isFixed() ) {
00250 haveNonFixed = true;
00251 break;
00252 }
00253 }
00254 if ( haveNonFixed )
00255 table->m_maxWidth = 0x7fff;
00256 }
00257 #ifdef DEBUG_LAYOUT
00258 qDebug("FixedTableLayout::calcMinMaxWidth: minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth );
00259 #endif
00260 }
00261
00262 void FixedTableLayout::layout()
00263 {
00264 int tableWidth = table->width() - table->bordersAndSpacing();
00265 int available = tableWidth;
00266 int nEffCols = table->numEffCols();
00267 #ifdef DEBUG_LAYOUT
00268 qDebug("FixedTableLayout::layout: tableWidth=%d, numEffCols=%d", tableWidth, nEffCols);
00269 #endif
00270
00271
00272 QMemArray<short> calcWidth;
00273 calcWidth.resize( nEffCols );
00274 calcWidth.fill( -1 );
00275
00276
00277 for ( int i = 0; i < nEffCols; i++ ) {
00278 if ( width[i].isFixed() ) {
00279 calcWidth[i] = width[i].value();
00280 available -= width[i].value();
00281 }
00282 }
00283
00284
00285 if ( available > 0 ) {
00286 int totalPercent = 0;
00287 for ( int i = 0; i < nEffCols; i++ )
00288 if ( width[i].isPercent() )
00289 totalPercent += width[i].value();
00290
00291
00292 int base = tableWidth * totalPercent / 100;
00293 if ( base > available )
00294 base = available;
00295 else
00296 totalPercent = 100;
00297
00298 #ifdef DEBUG_LAYOUT
00299 qDebug("FixedTableLayout::layout: assigning percent width, base=%d, totalPercent=%d", base, totalPercent);
00300 #endif
00301 for ( int i = 0; available > 0 && i < nEffCols; i++ ) {
00302 if ( width[i].isPercent() ) {
00303 int w = base * width[i].value() / totalPercent;
00304 available -= w;
00305 calcWidth[i] = w;
00306 }
00307 }
00308 }
00309
00310
00311 if ( available > 0 ) {
00312 int totalVariable = 0;
00313 for ( int i = 0; i < nEffCols; i++ )
00314 if ( width[i].isVariable() )
00315 totalVariable++;
00316
00317 for ( int i = 0; available > 0 && i < nEffCols; i++ ) {
00318 if ( width[i].isVariable() ) {
00319 int w = available / totalVariable;
00320 available -= w;
00321 calcWidth[i] = w;
00322 totalVariable--;
00323 }
00324 }
00325 }
00326
00327 for ( int i = 0; i < nEffCols; i++ )
00328 if ( calcWidth[i] <= 0 )
00329 calcWidth[i] = 0;
00330
00331 int pos = 0;
00332 int spacing = table->cellSpacing();
00333 for ( int i = 0; i < nEffCols; i++ ) {
00334 #ifdef DEBUG_LAYOUT
00335 qDebug("col %d: %d (width %d)", i, pos, calcWidth[i] );
00336 #endif
00337 table->columnPos[i] = pos;
00338 pos += calcWidth[i] + spacing;
00339 }
00340 table->columnPos[table->columnPos.size()-1] = pos;
00341 }
00342
00343
00344
00345
00346
00347 AutoTableLayout::AutoTableLayout( RenderTable* table )
00348 : TableLayout( table )
00349 {
00350 percentagesDirty = true;
00351 effWidthDirty = true;
00352 total_percent = 0;
00353 hasPercent = false;
00354 }
00355
00356 AutoTableLayout::~AutoTableLayout()
00357 {
00358 }
00359
00360
00361
00362
00363
00364 void AutoTableLayout::recalcColumn( int effCol )
00365 {
00366 Layout &l = layoutStruct[effCol];
00367
00368 RenderObject *child = table->firstChild();
00369
00370
00371 RenderTableCell *fixedContributor = 0;
00372 RenderTableCell *maxContributor = 0;
00373
00374 while ( child ) {
00375 if ( child->isTableSection() ) {
00376 RenderTableSection *section = static_cast<RenderTableSection *>(child);
00377 int numRows = section->numRows();
00378 RenderTableCell *last = 0;
00379 for ( int i = 0; i < numRows; i++ ) {
00380 RenderTableCell *cell = section->cellAt( i, effCol );
00381 if ( cell == (RenderTableCell *)-1 )
00382 continue;
00383 if ( cell && cell->colSpan() == 1 ) {
00384 if ( !cell->minMaxKnown() )
00385 cell->calcMinMaxWidth();
00386 if ( cell->minWidth() > l.minWidth )
00387 l.minWidth = cell->minWidth();
00388 if ( cell->maxWidth() > l.maxWidth ) {
00389 l.maxWidth = cell->maxWidth();
00390 maxContributor = cell;
00391 }
00392
00393 Length w = cell->style()->width();
00394 w.l.value = kMin( 32767, kMax( 0, w.value() ) );
00395 switch( w.type() ) {
00396 case Fixed:
00397
00398 if ( w.value() > 0 && !l.width.isPercent() ) {
00399
00400 int wval = w.value() + table->cellPadding() * 2;
00401 if ( l.width.isFixed() ) {
00402
00403 if ((wval > l.width.value()) ||
00404 ((l.width.value() == wval) && (maxContributor == cell))) {
00405 l.width.l.value = wval;
00406 fixedContributor = cell;
00407 }
00408 } else {
00409 l.width = Length( wval, Fixed );
00410 fixedContributor = cell;
00411 }
00412 }
00413 break;
00414 case Percent:
00415 hasPercent = true;
00416 if ( w.value() > 0 && (!l.width.isPercent() || w.value() > l.width.value() ) )
00417 l.width = w;
00418 break;
00419 case Relative:
00420 if ( w.isVariable() || (w.isRelative() && w.value() > l.width.value() ) )
00421 l.width = w;
00422 default:
00423 break;
00424 }
00425 } else {
00426 if ( !effCol || section->cellAt( i, effCol-1 ) != cell )
00427 insertSpanCell( cell );
00428 last = cell;
00429 }
00430 }
00431 }
00432 child = child->nextSibling();
00433 }
00434
00435
00436 if ( l.width.isFixed() ) {
00437 if ( table->style()->htmlHacks()
00438 && (l.maxWidth > l.width.value()) && (fixedContributor != maxContributor)) {
00439 l.width = Length();
00440 fixedContributor = 0;
00441 }
00442 }
00443
00444 l.maxWidth = kMax(l.maxWidth, l.minWidth);
00445 #ifdef DEBUG_LAYOUT
00446 qDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.value, l.width.type );
00447 #endif
00448
00449
00450 }
00451
00452
00453 void AutoTableLayout::fullRecalc()
00454 {
00455 percentagesDirty = true;
00456 hasPercent = false;
00457 effWidthDirty = true;
00458
00459 int nEffCols = table->numEffCols();
00460 layoutStruct.resize( nEffCols );
00461 layoutStruct.fill( Layout() );
00462 spanCells.fill( 0 );
00463
00464 RenderObject *child = table->firstChild();
00465 Length grpWidth;
00466 int cCol = 0;
00467 while ( child ) {
00468 if ( child->isTableCol() ) {
00469 RenderTableCol *col = static_cast<RenderTableCol *>(child);
00470 int span = col->span();
00471 if ( col->firstChild() ) {
00472 grpWidth = col->style()->width();
00473 } else {
00474 Length w = col->style()->width();
00475 if ( w.isVariable() )
00476 w = grpWidth;
00477 if ( (w.isFixed() && w.value() == 0) ||
00478 (w.isPercent() && w.value() == 0) )
00479 w = Length();
00480 int cEffCol = table->colToEffCol( cCol );
00481 #ifdef DEBUG_LAYOUT
00482 qDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value, w.type, span, table->spanOfEffCol(cEffCol ) );
00483 #endif
00484 if ( !w.isVariable() && span == 1 && cEffCol < nEffCols ) {
00485 if ( table->spanOfEffCol( cEffCol ) == 1 ) {
00486 layoutStruct[cEffCol].width = w;
00487 if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value())
00488 layoutStruct[cEffCol].maxWidth = w.value();
00489 }
00490 }
00491 cCol += span;
00492 }
00493 } else {
00494 break;
00495 }
00496
00497 RenderObject *next = child->firstChild();
00498 if ( !next )
00499 next = child->nextSibling();
00500 if ( !next && child->parent()->isTableCol() ) {
00501 next = child->parent()->nextSibling();
00502 grpWidth = Length();
00503 }
00504 child = next;
00505 }
00506
00507
00508 for ( int i = 0; i < nEffCols; i++ )
00509 recalcColumn( i );
00510 }
00511
00512
00513 void AutoTableLayout::calcMinMaxWidth()
00514 {
00515 #ifdef DEBUG_LAYOUT
00516 qDebug("AutoTableLayout::calcMinMaxWidth");
00517 #endif
00518 fullRecalc();
00519
00520 int spanMaxWidth = calcEffectiveWidth();
00521 int minWidth = 0;
00522 int maxWidth = 0;
00523 int maxPercent = 0;
00524 int maxNonPercent = 0;
00525
00526 for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
00527 minWidth += layoutStruct[i].effMinWidth;
00528 maxWidth += layoutStruct[i].effMaxWidth;
00529 if ( layoutStruct[i].effWidth.isPercent() ) {
00530 int pw = ( layoutStruct[i].effMaxWidth * 100) / layoutStruct[i].effWidth.value();
00531 maxPercent = kMax( pw, maxPercent );
00532 } else {
00533 maxNonPercent += layoutStruct[i].effMaxWidth;
00534 }
00535 }
00536
00537 int totalpct = totalPercent();
00538 if ( totalpct < 100 ) {
00539 maxNonPercent = (maxNonPercent * 100 + 50) / (100-totalpct);
00540 maxWidth = kMax( maxNonPercent, maxWidth );
00541 }
00542 maxWidth = kMax( maxWidth, maxPercent );
00543 maxWidth = kMax( maxWidth, spanMaxWidth );
00544
00545 int bs = table->bordersAndSpacing();
00546 minWidth += bs;
00547 maxWidth += bs;
00548
00549 Length tw = table->style()->width();
00550 if ( tw.isFixed() && tw.value() > 0 ) {
00551 minWidth = kMax( minWidth, int( tw.value() ) );
00552 maxWidth = minWidth;
00553 }
00554
00555 table->m_maxWidth = maxWidth;
00556 table->m_minWidth = minWidth;
00557 #ifdef DEBUG_LAYOUT
00558 qDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth );
00559 #endif
00560 }
00561
00562
00563
00564
00565
00566 int AutoTableLayout::calcEffectiveWidth()
00567 {
00568 int tMaxWidth = 0;
00569
00570 unsigned int nEffCols = layoutStruct.size();
00571 int spacing = table->cellSpacing();
00572 #ifdef DEBUG_LAYOUT
00573 qDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols );
00574 #endif
00575 for ( unsigned int i = 0; i < nEffCols; i++ ) {
00576 layoutStruct[i].effWidth = layoutStruct[i].width;
00577 layoutStruct[i].effMinWidth = layoutStruct[i].minWidth;
00578 layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth;
00579 }
00580
00581 for ( unsigned int i = 0; i < spanCells.size(); i++ ) {
00582 RenderTableCell *cell = spanCells[i];
00583 if ( !cell || cell == (RenderTableCell *)-1 )
00584 break;
00585 int span = cell->colSpan();
00586
00587 Length w = cell->style()->width();
00588 if ( !w.isRelative() && w.value() == 0 )
00589 w = Length();
00590
00591 int col = table->colToEffCol( cell->col() );
00592 unsigned int lastCol = col;
00593 int cMinWidth = cell->minWidth() + spacing;
00594 int cMaxWidth = cell->maxWidth() + spacing;
00595 int totalPercent = 0;
00596 int minWidth = 0;
00597 int maxWidth = 0;
00598 bool allColsArePercent = true;
00599 bool allColsAreFixed = true;
00600 bool haveVariable = false;
00601 int fixedWidth = 0;
00602 #ifdef DEBUG_LAYOUT
00603 int cSpan = span;
00604 #endif
00605 while ( lastCol < nEffCols && span > 0 ) {
00606 switch( layoutStruct[lastCol].width.type() ) {
00607 case Percent:
00608 totalPercent += layoutStruct[lastCol].width.value();
00609 allColsAreFixed = false;
00610 break;
00611 case Fixed:
00612 if (layoutStruct[lastCol].width.value() > 0) {
00613 fixedWidth += layoutStruct[lastCol].width.value();
00614 allColsArePercent = false;
00615
00616
00617 break;
00618 }
00619
00620 case Variable:
00621 haveVariable = true;
00622
00623 default:
00624 layoutStruct[lastCol].effWidth = Length();
00625 allColsArePercent = false;
00626 allColsAreFixed = false;
00627 }
00628 span -= table->spanOfEffCol( lastCol );
00629 minWidth += layoutStruct[lastCol].effMinWidth;
00630 maxWidth += layoutStruct[lastCol].effMaxWidth;
00631 lastCol++;
00632 cMinWidth -= spacing;
00633 cMaxWidth -= spacing;
00634 }
00635 #ifdef DEBUG_LAYOUT
00636 qDebug(" colspan cell %p at effCol %d, span %d, type %d, value %d cmin=%d min=%d fixedwidth=%d", cell, col, cSpan, w.type, w.value, cMinWidth, minWidth, fixedWidth );
00637 #endif
00638
00639
00640 if ( w.isPercent() ) {
00641 if ( totalPercent > w.value() || allColsArePercent ) {
00642
00643 w = Length();
00644 } else {
00645 int spanMax = QMAX( maxWidth, cMaxWidth );
00646 #ifdef DEBUG_LAYOUT
00647 qDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value(), totalPercent );
00648 #endif
00649 tMaxWidth = QMAX( tMaxWidth, spanMax * 100 / w.value() );
00650
00651
00652 int percentMissing = w.value() - totalPercent;
00653 int totalWidth = 0;
00654 for ( unsigned int pos = col; pos < lastCol; pos++ ) {
00655 if ( !(layoutStruct[pos].width.isPercent() ) )
00656 totalWidth += layoutStruct[pos].effMaxWidth;
00657 }
00658
00659 for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) {
00660 if ( !(layoutStruct[pos].width.isPercent() ) ) {
00661 int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth;
00662 #ifdef DEBUG_LAYOUT
00663 qDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth );
00664 #endif
00665 totalWidth -= layoutStruct[pos].effMaxWidth;
00666 percentMissing -= percent;
00667 if ( percent > 0 )
00668 layoutStruct[pos].effWidth = Length( percent, Percent );
00669 else
00670 layoutStruct[pos].effWidth = Length();
00671 }
00672 }
00673
00674 }
00675 }
00676
00677
00678 if ( cMinWidth > minWidth ) {
00679 if ( allColsAreFixed ) {
00680 #ifdef DEBUG_LAYOUT
00681 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol-1, cMinWidth, minWidth, fixedWidth );
00682 #endif
00683 for ( unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++ ) {
00684 int w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].width.value() / fixedWidth );
00685 #ifdef DEBUG_LAYOUT
00686 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
00687 #endif
00688 fixedWidth -= layoutStruct[pos].width.value();
00689 cMinWidth -= w;
00690 layoutStruct[pos].effMinWidth = w;
00691 }
00692
00693 } else {
00694 #ifdef DEBUG_LAYOUT
00695 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol-1, cMinWidth, minWidth );
00696 #endif
00697 int maxw = maxWidth;
00698 for ( unsigned int pos = col; minWidth > 0 && pos < lastCol; pos++ ) {
00699
00700 int w;
00701 if ( layoutStruct[pos].width.isFixed() && haveVariable && fixedWidth <= cMinWidth ) {
00702 w = QMAX( layoutStruct[pos].effMinWidth, layoutStruct[pos].width.value() );
00703 fixedWidth -= layoutStruct[pos].width.value();
00704 } else {
00705 w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].effMaxWidth / maxw );
00706 }
00707 #ifdef DEBUG_LAYOUT
00708 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
00709 #endif
00710 maxw -= layoutStruct[pos].effMaxWidth;
00711 cMinWidth -= w;
00712 layoutStruct[pos].effMinWidth = w;
00713 }
00714 }
00715 }
00716 if ( !w.isPercent() ) {
00717 if ( cMaxWidth > maxWidth ) {
00718 #ifdef DEBUG_LAYOUT
00719 qDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol-1, cMaxWidth );
00720 #endif
00721 for ( unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++ ) {
00722 int w = QMAX( layoutStruct[pos].effMaxWidth, cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth );
00723 #ifdef DEBUG_LAYOUT
00724 qDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w );
00725 #endif
00726 maxWidth -= layoutStruct[pos].effMaxWidth;
00727 cMaxWidth -= w;
00728 layoutStruct[pos].effMaxWidth = w;
00729 }
00730 }
00731 } else {
00732 for ( unsigned int pos = col; pos < lastCol; pos++ )
00733 layoutStruct[pos].maxWidth = QMAX(layoutStruct[pos].maxWidth, layoutStruct[pos].minWidth );
00734 }
00735 }
00736 effWidthDirty = false;
00737
00738
00739 return tMaxWidth;
00740 }
00741
00742
00743
00744
00745 void AutoTableLayout::insertSpanCell( RenderTableCell *cell )
00746 {
00747 if ( !cell || cell == (RenderTableCell *)-1 || cell->colSpan() == 1 )
00748 return;
00749
00750
00751 int size = spanCells.size();
00752 if ( !size || spanCells[size-1] != 0 ) {
00753 spanCells.resize( size + 10 );
00754 for ( int i = 0; i < 10; i++ )
00755 spanCells[size+i] = 0;
00756 size += 10;
00757 }
00758
00759
00760 unsigned int pos = 0;
00761 int span = cell->colSpan();
00762 while ( pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan() )
00763 pos++;
00764 memmove( spanCells.data()+pos+1, spanCells.data()+pos, (size-pos-1)*sizeof( RenderTableCell * ) );
00765 spanCells[pos] = cell;
00766 }
00767
00768
00769 void AutoTableLayout::layout()
00770 {
00771
00772 int tableWidth = table->width() - table->bordersAndSpacing();
00773 int available = tableWidth;
00774 int nEffCols = table->numEffCols();
00775
00776 if ( nEffCols != (int)layoutStruct.size() ) {
00777 qWarning("WARNING: nEffCols is not equal to layoutstruct!" );
00778 fullRecalc();
00779 nEffCols = table->numEffCols();
00780 }
00781 #ifdef DEBUG_LAYOUT
00782 qDebug("AutoTableLayout::layout()");
00783 #endif
00784
00785 if ( effWidthDirty )
00786 calcEffectiveWidth();
00787
00788 #ifdef DEBUG_LAYOUT
00789 qDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols );
00790 for ( int i = 0; i < nEffCols; i++ ) {
00791 qDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d",
00792 i, layoutStruct[i].width.type, layoutStruct[i].width.value,
00793 layoutStruct[i].minWidth, layoutStruct[i].maxWidth );
00794 qDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d",
00795 layoutStruct[i].effWidth.type, layoutStruct[i].effWidth.value,
00796 layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth );
00797 }
00798 #endif
00799
00800 bool havePercent = false;
00801 bool haveRelative = false;
00802 int totalRelative = 0;
00803 int numVariable = 0;
00804 int numFixed = 0;
00805 int totalVariable = 0;
00806 int totalFixed = 0;
00807 int totalPercent = 0;
00808 int allocVariable = 0;
00809
00810
00811 for ( int i = 0; i < nEffCols; i++ ) {
00812 int w = layoutStruct[i].effMinWidth;
00813 layoutStruct[i].calcWidth = w;
00814 available -= w;
00815 Length& width = layoutStruct[i].effWidth;
00816 switch( width.type()) {
00817 case Percent:
00818 havePercent = true;
00819 totalPercent += width.value();
00820 break;
00821 case Relative:
00822 haveRelative = true;
00823 totalRelative += width.value();
00824 break;
00825 case Fixed:
00826 numFixed++;
00827 totalFixed += layoutStruct[i].effMaxWidth;
00828
00829 break;
00830 case Variable:
00831 case Static:
00832 numVariable++;
00833 totalVariable += layoutStruct[i].effMaxWidth;
00834 allocVariable += w;
00835 }
00836 }
00837
00838
00839 if ( available > 0 ) {
00840 for ( int i = 0; i < nEffCols; ++i ) {
00841 Length w = layoutStruct[i].effWidth;
00842 if ( w.isFixed() && w.value() > layoutStruct[i].calcWidth ) {
00843 available += layoutStruct[i].calcWidth - w.value();
00844 layoutStruct[i].calcWidth = w.value();
00845 }
00846 }
00847 }
00848 #ifdef DEBUG_LAYOUT
00849 qDebug("fixed satisfied: available is %d", available);
00850 #endif
00851
00852
00853 if ( available > 0 && havePercent ) {
00854 for ( int i = 0; i < nEffCols; i++ ) {
00855 Length width = layoutStruct[i].effWidth;
00856 if ( width.isPercent() ) {
00857 int w = kMax ( int( layoutStruct[i].effMinWidth ), width.minWidth( tableWidth ) );
00858 available += layoutStruct[i].calcWidth - w;
00859 layoutStruct[i].calcWidth = w;
00860 }
00861 }
00862 if ( totalPercent > 100 ) {
00863
00864 int excess = tableWidth*(totalPercent-100)/100;
00865 for ( int i = nEffCols-1; i >= 0; i-- ) {
00866 if ( layoutStruct[i].effWidth.isPercent() ) {
00867 int w = layoutStruct[i].calcWidth;
00868 int reduction = kMin( w, excess );
00869
00870 excess -= reduction;
00871 int newWidth = kMax( int (layoutStruct[i].effMinWidth), w - reduction );
00872 available += w - newWidth;
00873 layoutStruct[i].calcWidth = newWidth;
00874
00875 }
00876 }
00877 }
00878 }
00879 #ifdef DEBUG_LAYOUT
00880 qDebug("percent satisfied: available is %d", available);
00881 #endif
00882
00883
00884 if ( available > 0 ) {
00885 for ( int i = 0; i < nEffCols; i++ ) {
00886 Length &width = layoutStruct[i].effWidth;
00887 if ( width.isRelative() && width.value() ) {
00888
00889 int w = width.value()*tableWidth/totalRelative;
00890 available += layoutStruct[i].calcWidth - w;
00891 layoutStruct[i].calcWidth = w;
00892 }
00893 }
00894 }
00895
00896
00897 if ( available > 0 && numVariable ) {
00898 available += allocVariable;
00899
00900 for ( int i = 0; i < nEffCols; i++ ) {
00901 Length &width = layoutStruct[i].effWidth;
00902 if ( width.isVariable() && totalVariable != 0 ) {
00903 int w = kMax( int ( layoutStruct[i].calcWidth ),
00904 available * layoutStruct[i].effMaxWidth / totalVariable );
00905 available -= w;
00906 totalVariable -= layoutStruct[i].effMaxWidth;
00907 layoutStruct[i].calcWidth = w;
00908 }
00909 }
00910 }
00911 #ifdef DEBUG_LAYOUT
00912 qDebug("variable satisfied: available is %d", available );
00913 #endif
00914
00915
00916 if ( available > 0 && numFixed) {
00917
00918 for ( int i = 0; i < nEffCols; i++ ) {
00919 Length &width = layoutStruct[i].effWidth;
00920 if ( width.isFixed() ) {
00921 int w = available * layoutStruct[i].effMaxWidth / totalFixed;
00922 available -= w;
00923 totalFixed -= layoutStruct[i].effMaxWidth;
00924 layoutStruct[i].calcWidth += w;
00925 }
00926 }
00927 }
00928
00929 #ifdef DEBUG_LAYOUT
00930 qDebug("after fixed distribution: available=%d", available );
00931 #endif
00932
00933
00934 if ( available > 0 && hasPercent && totalPercent < 100) {
00935
00936 for ( int i = 0; i < nEffCols; i++ ) {
00937 Length &width = layoutStruct[i].effWidth;
00938 if ( width.isPercent() ) {
00939 int w = available * width.value() / totalPercent;
00940 available -= w;
00941 totalPercent -= width.value();
00942 layoutStruct[i].calcWidth += w;
00943 if (!available || !totalPercent) break;
00944 }
00945 }
00946 }
00947
00948 #ifdef DEBUG_LAYOUT
00949 qDebug("after percent distribution: available=%d", available );
00950 #endif
00951
00952
00953 if ( available > 0 ) {
00954 int total = nEffCols;
00955
00956 int i = nEffCols;
00957 while ( i-- ) {
00958 int w = available / total;
00959 available -= w;
00960 total--;
00961 layoutStruct[i].calcWidth += w;
00962 }
00963 }
00964
00965 #ifdef DEBUG_LAYOUT
00966 qDebug("after equal distribution: available=%d", available );
00967 #endif
00968
00969
00970 if ( available < 0 ) {
00971 int mw = 0;
00972 for ( int i = nEffCols-1; i >= 0; i-- )
00973 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
00974 for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
00975 int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
00976 int reduce = available * minMaxDiff / mw;
00977 layoutStruct[i].calcWidth += reduce;
00978 available -= reduce;
00979 mw -= minMaxDiff;
00980 if ( available >= 0 )
00981 break;
00982 }
00983 }
00984
00985
00986
00987 int pos = 0;
00988 for ( int i = 0; i < nEffCols; i++ ) {
00989 #ifdef DEBUG_LAYOUT
00990 qDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth );
00991 #endif
00992 table->columnPos[i] = pos;
00993 pos += layoutStruct[i].calcWidth + table->cellSpacing();
00994 }
00995 table->columnPos[table->columnPos.size()-1] = pos;
00996
00997 }
00998
00999
01000 void AutoTableLayout::calcPercentages() const
01001 {
01002 total_percent = 0;
01003 for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
01004 if ( layoutStruct[i].width.isPercent() )
01005 total_percent += layoutStruct[i].width.value();
01006 }
01007 percentagesDirty = false;
01008 }
01009
01010 #undef DEBUG_LAYOUT