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.type == Fixed && w.value > 0 ) {
00120 effWidth = w.value;
00121 effWidth = QMIN( 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.type == Fixed || w.type == Percent) && 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 ) {
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.type == Fixed || w.type == Percent) && w.value > 0 ) {
00184 effWidth = w.value;
00185 effWidth = QMIN( 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].type == Variable && w.type != Variable ) {
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().type == Fixed ? 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].type == Fixed) ) {
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].type == Fixed ) {
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].type == Percent )
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].type == Percent ) {
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].type == Variable )
00315 totalVariable++;
00316
00317 for ( int i = 0; available > 0 && i < nEffCols; i++ ) {
00318 if ( width[i].type == Variable ) {
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 if ( w.value > 32760 )
00395 w.value = 32760;
00396 if ( w.value < 0 )
00397 w.value = 0;
00398 switch( w.type ) {
00399 case Fixed:
00400
00401 if ( w.value > 0 && (int)l.width.type != Percent ) {
00402
00403 int wval = w.value + table->cellPadding() * 2;
00404 if ( l.width.type == Fixed ) {
00405
00406 if ((wval > l.width.value) ||
00407 ((l.width.value == wval) && (maxContributor == cell))) {
00408 l.width.value = wval;
00409 fixedContributor = cell;
00410 }
00411 } else {
00412 l.width.type = Fixed;
00413 l.width.value = wval;
00414 fixedContributor = cell;
00415 }
00416 }
00417 break;
00418 case Percent:
00419 hasPercent = true;
00420 if ( w.value > 0 && (l.width.type != Percent || w.value > l.width.value ) )
00421 l.width = w;
00422 break;
00423 case Relative:
00424 if ( w.type == Variable || (w.type == Relative && w.value > l.width.value ) )
00425 l.width = w;
00426 default:
00427 break;
00428 }
00429 } else {
00430 if ( !effCol || section->cellAt( i, effCol-1 ) != cell )
00431 insertSpanCell( cell );
00432 last = cell;
00433 }
00434 }
00435 }
00436 child = child->nextSibling();
00437 }
00438
00439
00440 if ( l.width.type == Fixed ) {
00441 if ( table->style()->htmlHacks()
00442 && (l.maxWidth > l.width.value) && (fixedContributor != maxContributor)) {
00443 l.width = Length();
00444 fixedContributor = 0;
00445 }
00446 }
00447
00448 l.maxWidth = kMax(l.maxWidth, l.minWidth);
00449 #ifdef DEBUG_LAYOUT
00450 qDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.value, l.width.type );
00451 #endif
00452
00453
00454 }
00455
00456
00457 void AutoTableLayout::fullRecalc()
00458 {
00459 percentagesDirty = true;
00460 hasPercent = false;
00461 effWidthDirty = true;
00462
00463 int nEffCols = table->numEffCols();
00464 layoutStruct.resize( nEffCols );
00465 layoutStruct.fill( Layout() );
00466 spanCells.fill( 0 );
00467
00468 RenderObject *child = table->firstChild();
00469 Length grpWidth;
00470 int cCol = 0;
00471 while ( child ) {
00472 if ( child->isTableCol() ) {
00473 RenderTableCol *col = static_cast<RenderTableCol *>(child);
00474 int span = col->span();
00475 if ( col->firstChild() ) {
00476 grpWidth = col->style()->width();
00477 } else {
00478 Length w = col->style()->width();
00479 if ( w.isVariable() )
00480 w = grpWidth;
00481 if ( (w.type == Fixed && w.value == 0) ||
00482 (w.type == Percent && w.value == 0) )
00483 w = Length();
00484 int cEffCol = table->colToEffCol( cCol );
00485 #ifdef DEBUG_LAYOUT
00486 qDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value, w.type, span, table->spanOfEffCol(cEffCol ) );
00487 #endif
00488 if ( (int)w.type != Variable && span == 1 && cEffCol < nEffCols ) {
00489 if ( table->spanOfEffCol( cEffCol ) == 1 ) {
00490 layoutStruct[cEffCol].width = w;
00491 if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value)
00492 layoutStruct[cEffCol].maxWidth = w.value;
00493 }
00494 }
00495 cCol += span;
00496 }
00497 } else {
00498 break;
00499 }
00500
00501 RenderObject *next = child->firstChild();
00502 if ( !next )
00503 next = child->nextSibling();
00504 if ( !next && child->parent()->isTableCol() ) {
00505 next = child->parent()->nextSibling();
00506 grpWidth = Length();
00507 }
00508 child = next;
00509 }
00510
00511
00512 for ( int i = 0; i < nEffCols; i++ )
00513 recalcColumn( i );
00514 }
00515
00516
00517 void AutoTableLayout::calcMinMaxWidth()
00518 {
00519 #ifdef DEBUG_LAYOUT
00520 qDebug("AutoTableLayout::calcMinMaxWidth");
00521 #endif
00522 fullRecalc();
00523
00524 int spanMaxWidth = calcEffectiveWidth();
00525 int minWidth = 0;
00526 int maxWidth = 0;
00527 int maxPercent = 0;
00528 int maxNonPercent = 0;
00529
00530 for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
00531 minWidth += layoutStruct[i].effMinWidth;
00532 maxWidth += layoutStruct[i].effMaxWidth;
00533 if ( layoutStruct[i].effWidth.type == Percent ) {
00534 int pw = ( layoutStruct[i].effMaxWidth * 100) / layoutStruct[i].effWidth.value;
00535 maxPercent = kMax( pw, maxPercent );
00536 } else {
00537 maxNonPercent += layoutStruct[i].effMaxWidth;
00538 }
00539 }
00540
00541 int totalpct = totalPercent();
00542 if ( totalpct < 100 ) {
00543 maxNonPercent = (maxNonPercent * 100 + 50) / (100-totalpct);
00544 maxWidth = kMax( maxNonPercent, maxWidth );
00545 }
00546 maxWidth = kMax( maxWidth, maxPercent );
00547 maxWidth = kMax( maxWidth, spanMaxWidth );
00548
00549 int bs = table->bordersAndSpacing();
00550 minWidth += bs;
00551 maxWidth += bs;
00552
00553 Length tw = table->style()->width();
00554 if ( tw.isFixed() && tw.value > 0 ) {
00555 minWidth = kMax( minWidth, int( tw.value ) );
00556 maxWidth = minWidth;
00557 }
00558
00559 table->m_maxWidth = maxWidth;
00560 table->m_minWidth = minWidth;
00561 #ifdef DEBUG_LAYOUT
00562 qDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth );
00563 #endif
00564 }
00565
00566
00567
00568
00569
00570 int AutoTableLayout::calcEffectiveWidth()
00571 {
00572 int tMaxWidth = 0;
00573
00574 unsigned int nEffCols = layoutStruct.size();
00575 int spacing = table->cellSpacing();
00576 #ifdef DEBUG_LAYOUT
00577 qDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols );
00578 #endif
00579 for ( unsigned int i = 0; i < nEffCols; i++ ) {
00580 layoutStruct[i].effWidth = layoutStruct[i].width;
00581 layoutStruct[i].effMinWidth = layoutStruct[i].minWidth;
00582 layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth;
00583 }
00584
00585 for ( unsigned int i = 0; i < spanCells.size(); i++ ) {
00586 RenderTableCell *cell = spanCells[i];
00587 if ( !cell || cell == (RenderTableCell *)-1 )
00588 break;
00589 int span = cell->colSpan();
00590
00591 Length w = cell->style()->width();
00592 if ( !(w.type == Relative) && w.value == 0 )
00593 w = Length();
00594
00595 int col = table->colToEffCol( cell->col() );
00596 unsigned int lastCol = col;
00597 int cMinWidth = cell->minWidth() + spacing;
00598 int cMaxWidth = cell->maxWidth() + spacing;
00599 int totalPercent = 0;
00600 int minWidth = 0;
00601 int maxWidth = 0;
00602 bool allColsArePercent = true;
00603 bool allColsAreFixed = true;
00604 bool haveVariable = false;
00605 int fixedWidth = 0;
00606 #ifdef DEBUG_LAYOUT
00607 int cSpan = span;
00608 #endif
00609 while ( lastCol < nEffCols && span > 0 ) {
00610 switch( layoutStruct[lastCol].width.type ) {
00611 case Percent:
00612 totalPercent += layoutStruct[lastCol].width.value;
00613 allColsAreFixed = false;
00614 break;
00615 case Fixed:
00616 if (layoutStruct[lastCol].width.value > 0) {
00617 fixedWidth += layoutStruct[lastCol].width.value;
00618 allColsArePercent = false;
00619
00620
00621 break;
00622 }
00623
00624 case Variable:
00625 haveVariable = true;
00626
00627 default:
00628 layoutStruct[lastCol].effWidth = Length();
00629 allColsArePercent = false;
00630 allColsAreFixed = false;
00631 }
00632 span -= table->spanOfEffCol( lastCol );
00633 minWidth += layoutStruct[lastCol].effMinWidth;
00634 maxWidth += layoutStruct[lastCol].effMaxWidth;
00635 lastCol++;
00636 cMinWidth -= spacing;
00637 cMaxWidth -= spacing;
00638 }
00639 #ifdef DEBUG_LAYOUT
00640 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 );
00641 #endif
00642
00643
00644 if ( w.type == Percent ) {
00645 if ( totalPercent > w.value || allColsArePercent ) {
00646
00647 w = Length();
00648 } else {
00649 int spanMax = QMAX( maxWidth, cMaxWidth );
00650 #ifdef DEBUG_LAYOUT
00651 qDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value, totalPercent );
00652 #endif
00653 tMaxWidth = QMAX( tMaxWidth, spanMax * 100 / w.value );
00654
00655
00656 int percentMissing = w.value - totalPercent;
00657 int totalWidth = 0;
00658 for ( unsigned int pos = col; pos < lastCol; pos++ ) {
00659 if ( !(layoutStruct[pos].width.type == Percent ) )
00660 totalWidth += layoutStruct[pos].effMaxWidth;
00661 }
00662
00663 for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) {
00664 if ( !(layoutStruct[pos].width.type == Percent ) ) {
00665 int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth;
00666 #ifdef DEBUG_LAYOUT
00667 qDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth );
00668 #endif
00669 totalWidth -= layoutStruct[pos].effMaxWidth;
00670 percentMissing -= percent;
00671 if ( percent > 0 )
00672 layoutStruct[pos].effWidth = Length( percent, Percent );
00673 else
00674 layoutStruct[pos].effWidth = Length();
00675 }
00676 }
00677
00678 }
00679 }
00680
00681
00682 if ( cMinWidth > minWidth ) {
00683 if ( allColsAreFixed ) {
00684 #ifdef DEBUG_LAYOUT
00685 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol-1, cMinWidth, minWidth, fixedWidth );
00686 #endif
00687 for ( unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++ ) {
00688 int w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].width.value / fixedWidth );
00689 #ifdef DEBUG_LAYOUT
00690 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
00691 #endif
00692 fixedWidth -= layoutStruct[pos].width.value;
00693 cMinWidth -= w;
00694 layoutStruct[pos].effMinWidth = w;
00695 }
00696
00697 } else {
00698 #ifdef DEBUG_LAYOUT
00699 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol-1, cMinWidth, minWidth );
00700 #endif
00701 int maxw = maxWidth;
00702 for ( unsigned int pos = col; minWidth > 0 && pos < lastCol; pos++ ) {
00703
00704 int w;
00705 if ( layoutStruct[pos].width.type == Fixed && haveVariable && fixedWidth <= cMinWidth ) {
00706 w = QMAX( layoutStruct[pos].effMinWidth, layoutStruct[pos].width.value );
00707 fixedWidth -= layoutStruct[pos].width.value;
00708 } else {
00709 w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].effMaxWidth / maxw );
00710 }
00711 #ifdef DEBUG_LAYOUT
00712 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
00713 #endif
00714 maxw -= layoutStruct[pos].effMaxWidth;
00715 cMinWidth -= w;
00716 layoutStruct[pos].effMinWidth = w;
00717 }
00718 }
00719 }
00720 if ( !(w.type == Percent ) ) {
00721 if ( cMaxWidth > maxWidth ) {
00722 #ifdef DEBUG_LAYOUT
00723 qDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol-1, cMaxWidth );
00724 #endif
00725 for ( unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++ ) {
00726 int w = QMAX( layoutStruct[pos].effMaxWidth, cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth );
00727 #ifdef DEBUG_LAYOUT
00728 qDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w );
00729 #endif
00730 maxWidth -= layoutStruct[pos].effMaxWidth;
00731 cMaxWidth -= w;
00732 layoutStruct[pos].effMaxWidth = w;
00733 }
00734 }
00735 } else {
00736 for ( unsigned int pos = col; pos < lastCol; pos++ )
00737 layoutStruct[pos].maxWidth = QMAX(layoutStruct[pos].maxWidth, layoutStruct[pos].minWidth );
00738 }
00739 }
00740 effWidthDirty = false;
00741
00742
00743 return tMaxWidth;
00744 }
00745
00746
00747
00748
00749 void AutoTableLayout::insertSpanCell( RenderTableCell *cell )
00750 {
00751 if ( !cell || cell == (RenderTableCell *)-1 || cell->colSpan() == 1 )
00752 return;
00753
00754
00755 int size = spanCells.size();
00756 if ( !size || spanCells[size-1] != 0 ) {
00757 spanCells.resize( size + 10 );
00758 for ( int i = 0; i < 10; i++ )
00759 spanCells[size+i] = 0;
00760 size += 10;
00761 }
00762
00763
00764 unsigned int pos = 0;
00765 int span = cell->colSpan();
00766 while ( pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan() )
00767 pos++;
00768 memmove( spanCells.data()+pos+1, spanCells.data()+pos, (size-pos-1)*sizeof( RenderTableCell * ) );
00769 spanCells[pos] = cell;
00770 }
00771
00772
00773 void AutoTableLayout::layout()
00774 {
00775
00776 int tableWidth = table->width() - table->bordersAndSpacing();
00777 int available = tableWidth;
00778 int nEffCols = table->numEffCols();
00779
00780 if ( nEffCols != (int)layoutStruct.size() ) {
00781 qWarning("WARNING: nEffCols is not equal to layoutstruct!" );
00782 fullRecalc();
00783 nEffCols = table->numEffCols();
00784 }
00785 #ifdef DEBUG_LAYOUT
00786 qDebug("AutoTableLayout::layout()");
00787 #endif
00788
00789 if ( effWidthDirty )
00790 calcEffectiveWidth();
00791
00792 #ifdef DEBUG_LAYOUT
00793 qDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols );
00794 for ( int i = 0; i < nEffCols; i++ ) {
00795 qDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d",
00796 i, layoutStruct[i].width.type, layoutStruct[i].width.value,
00797 layoutStruct[i].minWidth, layoutStruct[i].maxWidth );
00798 qDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d",
00799 layoutStruct[i].effWidth.type, layoutStruct[i].effWidth.value,
00800 layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth );
00801 }
00802 #endif
00803
00804 bool havePercent = false;
00805 bool haveRelative = false;
00806 int totalRelative = 0;
00807 int numVariable = 0;
00808 int numFixed = 0;
00809 int totalVariable = 0;
00810 int totalFixed = 0;
00811 int totalPercent = 0;
00812 int allocVariable = 0;
00813
00814
00815 for ( int i = 0; i < nEffCols; i++ ) {
00816 int w = layoutStruct[i].effMinWidth;
00817 layoutStruct[i].calcWidth = w;
00818 available -= w;
00819 Length& width = layoutStruct[i].effWidth;
00820 switch( width.type) {
00821 case Percent:
00822 havePercent = true;
00823 totalPercent += width.value;
00824 break;
00825 case Relative:
00826 haveRelative = true;
00827 totalRelative += width.value;
00828 break;
00829 case Fixed:
00830 numFixed++;
00831 totalFixed += layoutStruct[i].effMaxWidth;
00832
00833 break;
00834 case Variable:
00835 case Static:
00836 numVariable++;
00837 totalVariable += layoutStruct[i].effMaxWidth;
00838 allocVariable += w;
00839 }
00840 }
00841
00842
00843 if ( available > 0 ) {
00844 for ( int i = 0; i < nEffCols; ++i ) {
00845 Length &width = layoutStruct[i].effWidth;
00846 if ( width.type == Fixed && width.value > layoutStruct[i].calcWidth ) {
00847 available += layoutStruct[i].calcWidth - width.value;
00848 layoutStruct[i].calcWidth = width.value;
00849 }
00850 }
00851 }
00852 #ifdef DEBUG_LAYOUT
00853 qDebug("fixed satisfied: available is %d", available);
00854 #endif
00855
00856
00857 if ( available > 0 && havePercent ) {
00858 for ( int i = 0; i < nEffCols; i++ ) {
00859 Length &width = layoutStruct[i].effWidth;
00860 if ( width.type == Percent ) {
00861 int w = kMax ( int( layoutStruct[i].effMinWidth ), width.minWidth( tableWidth ) );
00862 available += layoutStruct[i].calcWidth - w;
00863 layoutStruct[i].calcWidth = w;
00864 }
00865 }
00866 if ( totalPercent > 100 ) {
00867
00868 int excess = tableWidth*(totalPercent-100)/100;
00869 for ( int i = nEffCols-1; i >= 0; i-- ) {
00870 if ( layoutStruct[i].effWidth.type == Percent ) {
00871 int w = layoutStruct[i].calcWidth;
00872 int reduction = kMin( w, excess );
00873
00874 excess -= reduction;
00875 int newWidth = kMax( int (layoutStruct[i].effMinWidth), w - reduction );
00876 available += w - newWidth;
00877 layoutStruct[i].calcWidth = newWidth;
00878
00879 }
00880 }
00881 }
00882 }
00883 #ifdef DEBUG_LAYOUT
00884 qDebug("percent satisfied: available is %d", available);
00885 #endif
00886
00887
00888 if ( available > 0 ) {
00889 for ( int i = 0; i < nEffCols; i++ ) {
00890 Length &width = layoutStruct[i].effWidth;
00891 if ( width.type == Relative && width.value != 0 ) {
00892
00893 int w = width.value*tableWidth/totalRelative;
00894 available += layoutStruct[i].calcWidth - w;
00895 layoutStruct[i].calcWidth = w;
00896 }
00897 }
00898 }
00899
00900
00901 if ( available > 0 && numVariable ) {
00902 available += allocVariable;
00903
00904 for ( int i = 0; i < nEffCols; i++ ) {
00905 Length &width = layoutStruct[i].effWidth;
00906 if ( width.type == Variable && totalVariable != 0 ) {
00907 int w = kMax( int ( layoutStruct[i].calcWidth ),
00908 available * layoutStruct[i].effMaxWidth / totalVariable );
00909 available -= w;
00910 totalVariable -= layoutStruct[i].effMaxWidth;
00911 layoutStruct[i].calcWidth = w;
00912 }
00913 }
00914 }
00915 #ifdef DEBUG_LAYOUT
00916 qDebug("variable satisfied: available is %d", available );
00917 #endif
00918
00919
00920 if ( available > 0 && numFixed) {
00921
00922 for ( int i = 0; i < nEffCols; i++ ) {
00923 Length &width = layoutStruct[i].effWidth;
00924 if ( width.isFixed() ) {
00925 int w = available * layoutStruct[i].effMaxWidth / totalFixed;
00926 available -= w;
00927 totalFixed -= layoutStruct[i].effMaxWidth;
00928 layoutStruct[i].calcWidth += w;
00929 }
00930 }
00931 }
00932
00933 #ifdef DEBUG_LAYOUT
00934 qDebug("after fixed distribution: available=%d", available );
00935 #endif
00936
00937
00938 if ( available > 0 && hasPercent && totalPercent < 100) {
00939
00940 for ( int i = 0; i < nEffCols; i++ ) {
00941 Length &width = layoutStruct[i].effWidth;
00942 if ( width.isPercent() ) {
00943 int w = available * width.value / totalPercent;
00944 available -= w;
00945 totalPercent -= width.value;
00946 layoutStruct[i].calcWidth += w;
00947 if (!available || !totalPercent) break;
00948 }
00949 }
00950 }
00951
00952 #ifdef DEBUG_LAYOUT
00953 qDebug("after percent distribution: available=%d", available );
00954 #endif
00955
00956
00957 if ( available > 0 ) {
00958 int total = nEffCols;
00959
00960 int i = nEffCols;
00961 while ( i-- ) {
00962 int w = available / total;
00963 available -= w;
00964 total--;
00965 layoutStruct[i].calcWidth += w;
00966 }
00967 }
00968
00969 #ifdef DEBUG_LAYOUT
00970 qDebug("after equal distribution: available=%d", available );
00971 #endif
00972
00973
00974 if ( available < 0 ) {
00975 int mw = 0;
00976 for ( int i = nEffCols-1; i >= 0; i-- )
00977 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
00978 for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
00979 int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
00980 int reduce = available * minMaxDiff / mw;
00981 layoutStruct[i].calcWidth += reduce;
00982 available -= reduce;
00983 mw -= minMaxDiff;
00984 if ( available >= 0 )
00985 break;
00986 }
00987 }
00988
00989
00990
00991 int pos = 0;
00992 for ( int i = 0; i < nEffCols; i++ ) {
00993 #ifdef DEBUG_LAYOUT
00994 qDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth );
00995 #endif
00996 table->columnPos[i] = pos;
00997 pos += layoutStruct[i].calcWidth + table->cellSpacing();
00998 }
00999 table->columnPos[table->columnPos.size()-1] = pos;
01000
01001 }
01002
01003
01004 void AutoTableLayout::calcPercentages() const
01005 {
01006 total_percent = 0;
01007 for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
01008 if ( layoutStruct[i].width.type == Percent )
01009 total_percent += layoutStruct[i].width.value;
01010 }
01011 percentagesDirty = false;
01012 }
01013
01014 #undef DEBUG_LAYOUT