kword

KWTableFrameSet.cpp

00001 /*
00002     Copyright (C) 2001, S.R.Haque (srhaque@iee.org).
00003     This file is part of the KDE project
00004     Copyright (C) 2005 Thomas Zander <zander@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 
00021 DESCRIPTION
00022 
00023     This file implements KWord tables.
00024 */
00025 
00026 // ### TODO : multi page tables
00027 
00028 #include "KWTableFrameSet.h"
00029 #include "KWDocument.h"
00030 #include "KWAnchor.h"
00031 #include "KWCanvas.h"
00032 #include "KWCommand.h"
00033 #include "KWViewMode.h"
00034 #include "KWView.h"
00035 #include "KWordFrameSetIface.h"
00036 #include "KWordTableFrameSetIface.h"
00037 #include "KWFrameList.h"
00038 #include "KWPageManager.h"
00039 #include "KWPage.h"
00040 #include "KWOasisSaver.h"
00041 
00042 #include <KoOasisContext.h>
00043 #include <KoXmlWriter.h>
00044 #include <KoDom.h>
00045 #include <KoXmlNS.h>
00046 #include <KoTextObject.h> // for customItemChar !
00047 #include <KoTextParag.h>
00048 
00049 #include <kmessagebox.h>
00050 #include <kdebug.h>
00051 #include <klocale.h>
00052 #include <dcopobject.h>
00053 #include <qapplication.h>
00054 #include <qpopupmenu.h>
00055 #include <qclipboard.h>
00056 
00057 
00058 KWTableFrameSet::KWTableFrameSet( KWDocument *doc, const QString & name ) :
00059     KWFrameSet( doc )
00060 {
00061     m_rows = m_cols = m_nr_cells = 0;
00062     m_name = QString::null;
00063     m_active = true;
00064     m_frames.setAutoDelete(false);
00065     if ( name.isEmpty() )
00066         m_name = doc->generateFramesetName( i18n( "Table %1" ) );
00067     else
00068         m_name = name;
00069 }
00070 
00071 KWTableFrameSet::~KWTableFrameSet()
00072 {
00073     m_doc = 0L;
00074 }
00075 
00076 KWordFrameSetIface* KWTableFrameSet::dcopObject()
00077 {
00078     if ( !m_dcop )
00079     m_dcop = new KWordTableFrameSetIface( this );
00080 
00081     return m_dcop;
00082 }
00083 
00084 
00085 KWFrameSetEdit * KWTableFrameSet::createFrameSetEdit( KWCanvas * canvas )
00086 {
00087     return new KWTableFrameSetEdit( this, canvas );
00088 }
00089 
00090 void KWTableFrameSet::updateFrames( int flags )
00091 {
00092     for(TableIter c(this); c; ++c)
00093         c.current()->updateFrames( flags );
00094     if ( isFloating() )  {
00095         KWAnchor * anchor = findAnchor( 0 );
00096         if ( anchor )
00097              anchor->resize();
00098     }
00099 
00100     KWFrameSet::updateFrames( flags );
00101 }
00102 
00103 void KWTableFrameSet::moveFloatingFrame( int /*frameNum TODO */, const KoPoint &position )
00104 {
00105     // TODO multi-page case
00106 
00107     double dx = position.x() - m_colPositions[0];
00108     double dy = position.y() - m_rowPositions[0];
00109 
00110     int oldPageNumber = cell(0,0)->frame(0)->pageNumber();
00111     // TODO multi-page case
00112 
00113     moveBy( dx, dy );
00114 
00115     if ( dx || dy ) {
00116         updateFrames();
00117         cell(0,0)->frame(0)->frameStack()->updateAfterMove( oldPageNumber );
00118     }
00119 }
00120 
00121 KoSize KWTableFrameSet::floatingFrameSize( int /*frameNum*/ )
00122 {
00123     return boundingRect().size();
00124 }
00125 
00126 KCommand * KWTableFrameSet::anchoredObjectCreateCommand( int /*frameNum*/ )
00127 {
00128     return new KWCreateTableCommand( i18n("Create Table"), this );
00129 }
00130 
00131 KCommand * KWTableFrameSet::anchoredObjectDeleteCommand( int /*frameNum*/ )
00132 {
00133     return new KWDeleteTableCommand( i18n("Delete Table"), this );
00134 }
00135 
00136 KWAnchor * KWTableFrameSet::createAnchor( KoTextDocument *txt, int frameNum )
00137 {
00138     //kdDebug(32004) << "KWTableFrameSet::createAnchor" << endl;
00139     return new KWAnchor( txt, this, frameNum );
00140 }
00141 
00142 void KWTableFrameSet::createAnchors( KoTextParag * parag, int index, bool placeHolderExists /*= false */ /*only used when loading*/,
00143                                      bool repaint )
00144 {
00145     //kdDebug(32004) << "KWTableFrameSet::createAnchors" << endl;
00146     // TODO make one rect per page, and create one anchor per page
00147     // Anchor this frame, after the previous one
00148     KWAnchor * anchor = createAnchor( m_anchorTextFs->textDocument(), 0 );
00149     if ( !placeHolderExists )
00150         parag->insert( index, KoTextObject::customItemChar() );
00151     parag->setCustomItem( index, anchor, 0 );
00152     kdDebug(32004) << "KWTableFrameSet::createAnchors setting anchor" << endl;
00153     parag->setChanged( true );
00154     if ( repaint )
00155         emit repaintChanged( m_anchorTextFs );
00156 }
00157 
00158 void KWTableFrameSet::deleteAnchors()
00159 {
00160     KWAnchor * anchor = findAnchor( 0 );
00161     kdDebug(32004) << "KWTableFrameSet::deleteAnchors anchor=" << anchor << endl;
00162     deleteAnchor( anchor );
00163 }
00164 
00165 
00166 void KWTableFrameSet::addCell( Cell* daCell ) // called add but also used to 'update'
00167 {
00168     m_rows = kMax( daCell->rowAfter(), m_rows );
00169     m_cols = kMax( daCell->columnAfter(), m_cols );
00170 
00171     if ( m_rowArray.size() < daCell->rowAfter() )
00172         m_rowArray.resize( daCell->rowAfter() );
00173     for ( uint row = daCell->firstRow() ;row < daCell->rowAfter(); ++row )
00174     {
00175         if ( !m_rowArray[ row ] )
00176             m_rowArray.insert( row, new Row );
00177         m_rowArray[ row ]->addCell( daCell );
00178     }
00179 }
00180 
00181 void KWTableFrameSet::removeCell( Cell* daCell )
00182 {
00183     for ( uint row = daCell->firstRow() ; row < daCell->rowAfter(); ++row )
00184         m_rowArray[ row ]->removeCell( daCell );
00185 }
00186 
00187 void KWTableFrameSet::insertRowVector(uint index, Row *r)
00188 {
00189     if(m_rowArray.size() < m_rowArray.count() + 1)
00190         m_rowArray.resize(m_rowArray.count() + 1);
00191 
00192     for(uint i = m_rowArray.count(); i > index; i--)
00193         m_rowArray.insert(i, m_rowArray[i-1]);
00194 
00195     m_rowArray.insert(index, r);
00196 }
00197 
00198 /*
00199  * Inserts a new (empty) element into each row vector.
00200  * Elements in a row vector after index are moved back.
00201  */
00202 void KWTableFrameSet::insertEmptyColumn(uint index)
00203 {
00204     for(uint i = 0; i < m_rowArray.count(); ++i) {
00205        Row *r = m_rowArray[i];
00206        if(r->m_cellArray.size() < m_cols + 1)
00207            r->m_cellArray.resize(m_cols + 1);
00208        for(int j = m_cols - 1; j >= (int)index; --j)
00209            r->m_cellArray.insert(j + 1, r->m_cellArray[j]);
00210        r->m_cellArray.insert(index,  0);
00211     }
00212 }
00213 
00214 KWTableFrameSet::Row*
00215 KWTableFrameSet::removeRowVector(uint index)
00216 {
00217     Q_ASSERT(index < m_rowArray.count() );
00218     Row *ret = m_rowArray.at(index);
00219     Row *r;
00220     for(uint i = index; i < m_rowArray.size() - 1; ++i){
00221         r = m_rowArray.at(i+1);
00222         m_rowArray.remove(i+1);
00223         m_rowArray.insert(i,r);
00224     }
00225     return ret;
00226 }
00227 
00228 
00229 KoRect KWTableFrameSet::boundingRect() {
00230     KoRect outerRect(m_colPositions[0],    // left
00231                      m_rowPositions[0],      // top
00232                      m_colPositions.last()-m_colPositions[0], // width
00233                      m_rowPositions.last()-m_rowPositions[0]);// height
00234 
00235     // Add 1 'pixel' (at current zoom level) like KWFrame::outerKoRect(),
00236     // to avoid that the bottom line disappears due to rounding problems
00237     // (i.e. that it doesn't fit in the calculated paragraph height in pixels,
00238     // which depends on the paragraph's Y position)
00239     // Better have one pixel too much (caret looks too big by one pixel)
00240     // than one missing (bottom line of cell not painted)
00241     outerRect.rRight() += m_doc->zoomItX( 1 ) / m_doc->zoomedResolutionX();
00242     outerRect.rBottom() += m_doc->zoomItY( 1 ) / m_doc->zoomedResolutionY();
00243 
00244     return outerRect;
00245 
00246 }
00247 
00248 double KWTableFrameSet::topWithoutBorder()
00249 {
00250     double top = 0.0;
00251     for (uint i = 0; i < getColumns(); i++)
00252     {
00253         KWTableFrameSet::Cell *daCell = cell( 0, i );
00254         top = kMax( top, m_rowPositions[0] + daCell->topBorder() );
00255     }
00256     return top;
00257 }
00258 
00259 
00260 double KWTableFrameSet::leftWithoutBorder()
00261 {
00262     double left = 0.0;
00263     for (uint i=0; i < getRows(); i++)
00264     {
00265         KWTableFrameSet::Cell *daCell = cell( i, 0 );
00266         left = kMax( left, m_colPositions[0] + daCell->leftBorder() );
00267     }
00268     return left;
00269 }
00270 
00271 /* returns the cell that occupies row, col. */
00272 KWTableFrameSet::Cell *KWTableFrameSet::cell( unsigned int row, unsigned int col ) const
00273 {
00274     if ( row < m_rowArray.size() && col < m_rowArray[row]->size() ) {
00275         Cell* cell = (*m_rowArray[row])[col];
00276         if ( cell )
00277             return cell;
00278     }
00279 //    kdWarning() << name() << " cell " << row << "," << col << " => returning 0!" << kdBacktrace( 3 ) << endl;
00280 //#ifndef NDEBUG
00281 //    validate();
00282 //    printArrayDebug();
00283 //#endif
00284     return 0L;
00285 }
00286 
00287 KWTableFrameSet::Cell *KWTableFrameSet::cellByPos( double x, double y ) const
00288 {
00289     KWFrame *f = frameAtPos(x,y);
00290     if(f) return static_cast<KWTableFrameSet::Cell *> (f->frameSet());
00291     return 0L;
00292 }
00293 
00294 void KWTableFrameSet::recalcCols(unsigned int col,unsigned int row) {
00295     if(col >= getColumns())
00296         col = getColumns()-1;
00297     if(row >= getRows())
00298         row = getRows()-1;
00299     Cell *activeCell = cell(row,col);
00300     Q_ASSERT( activeCell );
00301     if ( !activeCell )
00302         return;
00303     double difference = 0;
00304 
00305     if(activeCell->frame(0)->left() - activeCell->leftBorder() != m_colPositions[activeCell->firstColumn()]) {
00306         // left border moved.
00307         col = activeCell->firstRow();
00308         difference = 0-(activeCell->frame(0)->left() - activeCell->leftBorder() - m_colPositions[activeCell->firstColumn()]);
00309     }
00310 
00311     if(activeCell->frame(0)->right() - activeCell->rightBorder() !=
00312             m_colPositions[activeCell->lastColumn()]) { // right border moved
00313 
00314         col = activeCell->columnAfter();
00315         double difference2 = activeCell->frame(0)->right() + activeCell->rightBorder() - m_colPositions[activeCell->columnAfter()];
00316 
00317         double moved=difference2+difference;
00318         if(moved > -0.01 && moved < 0.01) { // we were simply moved.
00319                 col=0;
00320                 difference = difference2;
00321             } else if(difference2!=0)
00322                 difference = difference2;
00323     }
00324 
00325     m_redrawFromCol=getColumns(); // possible reposition col starting with this one, done in recalcRows
00326     if(difference!=0) {
00327         double last=col==0?0:m_colPositions[col-1];
00328         for(unsigned int i=col; i < m_colPositions.count(); i++) {
00329             double &colPos = m_colPositions[i];
00330             colPos = colPos + difference;
00331             if(colPos-last < s_minFrameWidth) { // Never make it smaller then allowed!
00332                 difference += s_minFrameWidth - colPos;
00333                 colPos = s_minFrameWidth + last;
00334             }
00335             last=colPos;
00336         }
00337         m_redrawFromCol=col;
00338         if(col>0) m_redrawFromCol--;
00339         //if(activeCell) activeCell->frame(0)->setMinimumFrameHeight(0);
00340     }
00341     updateFrames();
00342     //kdDebug(32004) << "end KWTableFrameSet::recalcCols" << endl;
00343 }
00344 
00345 
00346 // Step through the whole table and recalculate the position and size
00347 // of each cell.
00348 
00349 void KWTableFrameSet::recalcRows(unsigned int col, unsigned int row) {
00350     kdDebug(32004) << name() << " KWTableFrameSet::recalcRows ("<< col <<"," << row << ")" << endl;
00351     //for(unsigned int i=0; i < m_rowPositions.count() ; i++) kdDebug(32004) << "row: " << i << " = " << m_rowPositions[i] << endl;
00352 
00353     Cell *activeCell = cell(row,col);
00354     Q_ASSERT( activeCell );
00355     if ( !activeCell ) // #122807
00356         return;
00357     double difference = 0;
00358 
00359     if(activeCell->frame(0)->height() != activeCell->frame(0)->minimumFrameHeight() &&
00360           activeCell->type() == FT_TEXT) {
00361         // when the amount of text changed and the frame has to be rescaled we are also called.
00362         // lets check the minimum size for all the cells in this row.
00363 
00364         // Take a square of table cells which depend on each others height. It is always the full
00365         // width of the table and the height is determined by joined cells, the minimum is one row.
00366         double minHeightOtherCols=0;    // The minimum height which the whole square of table cells can take
00367         double minHeightActiveRow=0;    // The minimum height our cell can get because of cells in his row
00368         double minHeightMyCol=0;        // The minimum height our column can get in the whole square
00369         unsigned int rowSpan = activeCell->rowSpan();
00370         unsigned int startRow = activeCell->firstRow();
00371         for (uint colCount = 0; colCount < getColumns(); ++colCount )
00372         {
00373             // for each column
00374             unsigned int rowCount=startRow;
00375             double thisColHeight=0;     // the total height of this column
00376             double thisColActiveRow=0;  // the total height of all cells in this col, completely in the
00377                                         // row of the activeCell
00378             do { // for each row (under startRow)
00379                 Cell *thisCell=cell(rowCount,colCount);
00380                 if ( !thisCell )
00381                     break; // ###
00382                 if(thisCell->firstRow() < startRow) { // above -> set startRow and restart
00383                     rowSpan += startRow - thisCell->firstRow();
00384                     startRow = thisCell->firstRow();
00385                     break;
00386                 }
00387                 if(thisCell->rowAfter() > startRow + rowSpan) {
00388                     rowSpan = thisCell->rowAfter() - startRow;
00389                     break;
00390                 }
00391 
00392                 thisColHeight+=thisCell->frame(0)->minimumFrameHeight();
00393                 thisColHeight+=thisCell->topBorder();
00394                 thisColHeight+=thisCell->bottomBorder();
00395 
00396                 if(thisCell->firstRow() >= activeCell->firstRow() && thisCell->rowAfter() <= activeCell->rowAfter())
00397                     thisColActiveRow+=thisCell->frame(0)->minimumFrameHeight();
00398 
00399                 rowCount += thisCell->rowSpan();
00400             } while (rowCount < rowSpan+startRow);
00401 
00402             if(colCount >= activeCell->firstColumn() &&
00403                   colCount < activeCell->columnAfter() )
00404                 minHeightMyCol = thisColHeight;
00405             else {
00406                 minHeightOtherCols = kMax(minHeightOtherCols, thisColHeight);
00407                 minHeightActiveRow = kMax(minHeightActiveRow, thisColActiveRow);
00408             }
00409         } // for each column
00410 
00411         bool bottomRow = (startRow+rowSpan == activeCell->rowAfter());
00412         if(!bottomRow) {
00413             Cell *bottomCell=cell(startRow+rowSpan-1, activeCell->firstColumn());
00414             bottomCell->frame(0)->setHeight(bottomCell->frame(0)->minimumFrameHeight() +
00415                     minHeightOtherCols - minHeightMyCol);
00416             // ### RECURSE ###
00417             recalcRows(bottomCell->firstColumn(), bottomCell->firstRow());
00418         }
00419         if(activeCell->frame(0)->minimumFrameHeight() > activeCell->frame(0)->height()) { // wants to grow
00420             activeCell->frame(0)->setHeight(activeCell->frame(0)->minimumFrameHeight());
00421             //kdDebug(32004) << activeCell->name() << " grew to its minheight: " << activeCell->frame(0)->minimumFrameHeight() << endl;
00422         } else { // wants to shrink
00423             double newHeight=kMax(activeCell->frame(0)->minimumFrameHeight(),minHeightActiveRow);
00424             if(bottomRow) // I'm a strech cell
00425                 newHeight=kMax(newHeight, minHeightOtherCols - (minHeightMyCol - activeCell->frame(0)->minimumFrameHeight()));
00426             activeCell->frame(0)->setHeight(newHeight);
00427             //kdDebug(32004) << activeCell->name() << " shrunk to: " << newHeight << endl;
00428         }
00429     }
00430 
00431     if(activeCell->frame(0)->top() - activeCell->topBorder() != getPositionOfRow(activeCell->firstRow())) {
00432         // top moved.
00433         row = activeCell->firstRow();
00434         difference = 0 - (activeCell->frame(0)->top() - activeCell->topBorder() - getPositionOfRow(row));
00435     }
00436 
00437 
00438     if(activeCell->frame(0)->bottom() + activeCell->bottomBorder() !=
00439             getPositionOfRow(activeCell->rowAfter())) { // bottom moved
00440 
00441         row = activeCell->rowAfter();
00442         double difference2 = activeCell->frame(0)->bottom() + activeCell->bottomBorder() - getPositionOfRow(row);
00443         double moved=difference2+difference;
00444         if(moved > -0.01 && moved < 0.01) { // we were simply moved.
00445             row=0;
00446             difference = difference2;
00447         } else if( difference2!=0)
00448             difference = difference2;
00449     }
00450 
00451     unsigned int fromRow = m_rows; // possible reposition rows starting with this one, default to no repositioning
00452     unsigned int untilRow=0;     // possible reposition rows ending with this one
00453     if( QABS( difference ) > 1E-10 ) { // means "difference != 0.0"
00454         QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
00455         QValueList<double>::iterator j = m_rowPositions.begin();
00456         double last=0.0;
00457         int lineNumber=-1;
00458         while(j != m_rowPositions.end()) {
00459             lineNumber++;
00460             if(pageBound!=m_pageBoundaries.end()) {
00461                 if((int)*pageBound == lineNumber) { // next page
00462                     if(lineNumber >= (int)row) { // then delete line j
00463                         QValueList<double>::iterator nextJ = j;
00464                         ++nextJ;
00465                         difference -= *(nextJ)-*(j);
00466                         kdDebug(32004) << "Deleting line with old pos: " << *j << endl;
00467                         j=m_rowPositions.remove(j);
00468                         j--;
00469                         QValueList<unsigned int>::iterator tmp = pageBound;
00470                         ++pageBound;
00471                         m_pageBoundaries.remove(tmp);
00472                         j++;
00473                         continue;
00474                     }
00475                     ++pageBound;
00476                     lineNumber--;
00477                 }
00478             }
00479             if(lineNumber >= (int)row)  { // below changed row
00480                 if(*(j)-last < s_minFrameHeight) // Never make it smaller then allowed!
00481                     difference += s_minFrameHeight - *(j) + last;
00482                 last=*(j);
00483                 kdDebug(32004) << "moving " << *(j) << " by " << difference << "; to " << (*j) + difference << endl;
00484                 (*j) += difference; // move line.
00485             }
00486             j++;
00487         }
00488         fromRow=row;
00489         if(row>0) fromRow--;
00490     } else {
00491         row=0;
00492     }
00493 #if 0
00494 { QValueList<unsigned int>::iterator pb = m_pageBoundaries.begin();
00495   unsigned int i=0;
00496   double last=0;
00497   do {
00498       double cur=m_rowPositions[i];
00499       if(pb!=m_pageBoundaries.end() && *(pb)==i) {
00500         kdDebug(32004) << "line: " << i << ": " << cur << " *" << (last>cur?" (ALERT)":"") << endl;
00501         ++pb;
00502       } else
00503         kdDebug(32004) << "line: " << i << ": " << cur << (last>cur?" (ALERT)":"") << endl;
00504       last=cur;
00505       i++;
00506   } while( i<m_rowPositions.count());
00507 }
00508 #endif
00509 #if 0 // def SUPPORT_MULTI_PAGE_TABLES
00510 
00511     //double pageHeight = m_doc->ptPaperHeight() - m_doc->ptBottomBorder() - m_doc->ptTopBorder();
00512     unsigned int pageNumber=cell(0,0)->frame(0)->pageNumber() +1;
00513     unsigned int lineNumber=1;
00514     QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
00515     QValueList<double>::iterator j = m_rowPositions.begin();
00516 
00517     double diff=0.0;
00518     double pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
00519     // kdDebug(32004) << "pageBottom; " << pageBottom << endl;
00520     while(++j!=m_rowPositions.end()) { // stuff for multipage tables.
00521         if(pageBound!=m_pageBoundaries.end() && *pageBound == lineNumber ) {
00522             if(*j > pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder() ) { // next page marker exists, and is accurate...
00523                 pageNumber++;
00524                 pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
00525                 // kdDebug(32004) << "pageBottom; " << pageBottom << endl;
00526                 untilRow=kMax(untilRow, *pageBound);
00527                 pageBound++;
00528             }
00529         }
00530 
00531 //kdDebug() << "checking; " << lineNumber << ", " << (*j) << endl;
00532         if((*j) + diff > pageBottom) { // a row falls off the page.
00533 //kdDebug(32004) << "row falls off of page"<< endl;
00534             untilRow = m_rows;
00535             bool hugeRow = false;
00536             unsigned int breakRow = lineNumber-1;
00537             // find out of no cells are spanning multiple rows meaning we have to break higher.
00538 #if 0
00539     // ### TODO: I did not get a chance do debug this yet!  TZ.
00540             for(int i=0; i < getColumns() ; i++) {
00541                 kdDebug() << "i: " << i<< endl;
00542                 Cell *c= cell(breakRow, i);
00543                 kdDebug() << "c: " << c->firstRow() << "," << c->m_col << " w: " << c->columnSpan() << ", h: " << c->rowSpan() << endl;
00544                 if(c->firstRow() < breakRow) {
00545                     breakRow = c->firstRow();
00546                     i=-1;
00547                 }
00548             }
00549             kdDebug() << "breakRow: " << breakRow<< endl;
00550             fromRow=kMin(fromRow, breakRow);
00551             if(breakRow < lineNumber+1) {
00552                 for(unsigned int i=lineNumber+1; i > breakRow;i--)
00553                     kdDebug() << "j--";
00554                 for(unsigned int i=lineNumber+1; i > breakRow;i--)
00555                     --j;
00556                 lineNumber=breakRow+1;
00557             }
00558 
00559             // find out if the next row (the new one on the page) does not contain cells higher then page.
00560             for(unsigned int i=0; i < getColumns() ; i++) {
00561                 if(cell(breakRow+1,i) && cell(breakRow+1,i)->frame(0)->height() > pageHeight)
00562                     hugeRow=true;
00563             }
00564             //if((*pageBound) != breakRow) { // I think that this has to be that way
00565                 // voeg top in in rowPositions
00566 #endif
00567 
00568             double topOfPage = m_doc->ptPaperHeight() * pageNumber + m_doc->ptTopBorder();
00569 
00570             QValueList<double>::iterator tmp = m_rowPositions.at(breakRow);
00571             diff += topOfPage - (*tmp); // diff between bottom of last row on page and top of new page
00572 //kdDebug() << "diff += " <<  topOfPage  << " - " << (*tmp) << ". diff += " << topOfPage - (*tmp) <<" ="<< diff  << endl;
00573             lineNumber++;
00574             m_rowPositions.insert(j, topOfPage);
00575 
00576             // insert new pageBound. It points to last LINE on previous page
00577             pageBound = m_pageBoundaries.insert(pageBound, breakRow);
00578             //kdDebug(32004) << "inserting new pageBound: " << breakRow  << " at " << m_rowPositions[breakRow] << endl;
00579             pageBound++;
00580             if(!hugeRow) {
00581                 // add header-rij toe. (en zet bool) TODO
00582                 //j++;
00583                 //lineNumber++;
00584                 // m_hasTmpHeaders = true;
00585             }
00586             pageNumber++;
00587             pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
00588             //kdDebug(32004) << " pageBottom: " << pageBottom << " pageNumber=" << pageNumber << endl;
00589             if((int)pageNumber > m_doc->numPages()) {
00590                 int num = m_doc->appendPage();
00591                 kdDebug(32004) << "Have appended page: " << num << " (one page mode!)" << endl;
00592                 m_doc->afterInsertPage( num );
00593             }
00594         }
00595         //if(diff > 0)  kdDebug(32004) << "   adding " << diff << ", line " << lineNumber << " " << *(j) <<" -> " << *(j)+diff << endl;
00596         if(diff > 0)
00597             (*j) = (*j) + diff;
00598         lineNumber++;
00599 
00600 #if 0 // def SUPPORT_MULTI_PAGE_TABLES
00601         // Note: produces much ouput!
00602         int i = 1; // DEBUG
00603         for ( QValueList<double>::iterator itDebug = m_rowPositions.begin(); itDebug != m_rowPositions.end(); ++itDebug, ++i )
00604         {
00605             kdDebug(32004) << "m_rowPosition[" << i << "]= " << (*itDebug) << endl;
00606         }
00607 #endif
00608 
00609     }
00610 #endif
00611 #if 0
00612 { QValueList<unsigned int>::iterator pb = m_pageBoundaries.begin();
00613   unsigned int i=0;
00614   double last=0;
00615   do {
00616       double cur=m_rowPositions[i];
00617       if(pb!=m_pageBoundaries.end() && *(pb)==i) {
00618         kdDebug(32004) << "line: " << i << ": " << cur << " *" << (last>cur?" (ALERT)":"") << endl;
00619         ++pb;
00620       } else
00621         kdDebug(32004) << "line: " << i << ": " << cur << (last>cur?" (ALERT)":"") << endl;
00622       last=cur;
00623       i++;
00624   } while( i<m_rowPositions.count());
00625 }
00626 #endif
00627 //for (unsigned int i=0; i < getRows(); kdDebug(32004)<<" pos of row["<<i<<"] = "<<getPositionOfRow(i)<<"/"<<getPositionOfRow(i,true)<<endl,i++);
00628     //kdDebug () << "Repositioning from row : " << fromRow << " until: " << untilRow << endl;
00629     //kdDebug () << "Repositioning from col > " << redrawFromCol << endl;
00630     // do positioning.
00631     //Cell *cell;
00632     //bool setMinFrameSize= activeCell->frame(0)->isSelected();
00633 
00634 #if 0 // def SUPPORT_MULTI_PAGE_TABLES
00635     for(TableIter cell(this); cell; ++cell) {
00636         if((cell->rowAfter() > fromRow && cell->firstRow() < untilRow) || cell->columnAfter() > m_redrawFromCol)
00637             position(cell, (cell==activeCell && cell->frame(0)->isSelected()));
00638     }
00639     m_redrawFromCol = getColumns();
00640 
00641     // check if any rowPosition entries are unused
00642 
00643     //   first create a hash of all row entries
00644     QMap<unsigned int,int> rows;        // rownr, count
00645     unsigned int top=m_rowPositions.count() - m_pageBoundaries.count()-1;
00646     for(unsigned int i=0; i < top; rows[i++]=0);
00647 
00648     //   fill hash with data
00649     for(TableIter i(this); i; ++i) {
00650         rows[i->firstRow()] += 1;
00651     }
00652     //   check if some entries have stayed unused.
00653     unsigned int counter=top;
00654     int adjustment=m_pageBoundaries.count()-1;
00655 
00656     do {
00657         counter--;
00658         if(adjustment >= 0 && counter == m_pageBoundaries[adjustment])
00659             adjustment--;
00660         if(rows[counter]==0) {
00661             kdDebug() << k_funcinfo << "no rows at counter=" << counter << " -> erasing" << endl;
00662             m_rows--;
00663             m_rowPositions.erase(m_rowPositions.at(counter+(adjustment>0?adjustment:0)));
00664             for (TableIter cell(this); cell; ++cell) {
00665                 if(cell->firstRow() < counter && cell->rowAfter() > counter)
00666                     cell->setRowSpan(cell->rowSpan()-1);
00667                 if(cell->firstRow() > counter)
00668                     cell->setFirstRow(cell->firstRow()-1);
00669             }
00670 
00671             if(adjustment >= -1) {
00672                 pageBound = m_pageBoundaries.at(adjustment+1);
00673                 while(pageBound!=m_pageBoundaries.end()) {
00674                     (*pageBound)= (*pageBound)-1;
00675                     pageBound++;
00676                 }
00677             }
00678         }
00679     } while(counter!=0);
00680 #endif
00681 
00682 
00683     m_redrawFromCol = 0;
00684     for (TableIter cell(this); cell; ++cell) {
00685         if((cell->rowAfter() > fromRow && cell->firstRow() < untilRow)
00686            || cell->columnAfter() > m_redrawFromCol)
00687             position(cell);
00688     }
00689     m_redrawFromCol = getColumns();
00690     kdDebug(32004) << name() << " KWTableFrameSet::recalcRows done" << endl;
00691     updateFrames();
00692 }
00693 
00694 int KWTableFrameSet::columnEdgeAt( double x ) const
00695 {
00696     // We compare x with the middle of columns (left+right/2),
00697     // to find which column x is closest to.
00698     // m_colPositions is sorted, so we can remember the last column we looked at.
00699     double lastMiddlePos = 0;
00700     for ( uint i = 0; i < m_colPositions.count() - 1; i++ ) {
00701         double middlePos = ( m_colPositions[i] + m_colPositions[i+1] ) / 2;
00702         Q_ASSERT( lastMiddlePos < middlePos );
00703         if ( x > lastMiddlePos && x <= middlePos )
00704             return i;
00705         lastMiddlePos = middlePos;
00706     }
00707     return m_colPositions.count() - 1;
00708 }
00709 
00710 int KWTableFrameSet::rowEdgeAt( double y ) const
00711 {
00712     double lastMiddlePos = 0;
00713     for ( uint i = 0; i < m_rowPositions.count() - 1; i++ ) {
00714         double middlePos = ( m_rowPositions[i] + m_rowPositions[i+1] ) / 2;
00715         Q_ASSERT( lastMiddlePos < middlePos );
00716         if ( y > lastMiddlePos && y <= middlePos )
00717             return i;
00718         lastMiddlePos = middlePos;
00719     }
00720     return m_rowPositions.count() - 1;
00721 }
00722 
00723 double KWTableFrameSet::columnSize( unsigned int col )
00724 {
00725   return m_colPositions[ col ];
00726 }
00727 
00728 double KWTableFrameSet::rowSize( unsigned int row )
00729 {
00730   return m_rowPositions[ row ];
00731 }
00732 
00733 void KWTableFrameSet::resizeColumn( unsigned int col, double x )
00734 {
00735     kdDebug() << k_funcinfo << col << "," << x << endl;
00736     if ((col != 0) && (x - m_colPositions[ col-1 ] < s_minFrameWidth))
00737       m_colPositions[ col ] = m_colPositions[ col-1 ] + s_minFrameWidth;
00738     else
00739       if ((col != getColumns()) && (m_colPositions[ col + 1 ] - x < s_minFrameWidth))
00740         m_colPositions[col] = m_colPositions[ col + 1 ] - s_minFrameWidth;
00741       else
00742         m_colPositions[ col ] = x;
00743 
00744     // move all cells right of 'col'
00745     for (TableIter cell(this); cell; ++cell) {
00746         if ( cell->columnAfter() >= col ) {
00747             position(cell);
00748         }
00749     }
00750     recalcCols( col-1, 0 );
00751 }
00752 
00753 void KWTableFrameSet::resizeRow( unsigned int row, double y )
00754 {
00755     kdDebug() << k_funcinfo << row << "," << y << endl;
00756     double difference = m_rowPositions[row];
00757     if ((row != 0) && (y - m_rowPositions[ row-1 ] < s_minFrameHeight))
00758       m_rowPositions[ row ] = m_rowPositions[ row-1 ] + s_minFrameHeight;
00759     else
00760       if ((row != getRows()) && (m_rowPositions[ row + 1 ] - y < s_minFrameHeight))
00761         m_rowPositions[row] = m_rowPositions[ row + 1 ] - s_minFrameHeight;
00762       else
00763         m_rowPositions[ row ] = y;
00764     difference = m_rowPositions[row] - difference;
00765 
00766     //move all rows under 'row'
00767     if (row != 0)
00768        for (unsigned int i=row+1; i<= getRows(); i++)
00769            m_rowPositions[i] = m_rowPositions[i] + difference;
00770 
00771     // move all cells under 'row'
00772     for (TableIter cell(this); cell; ++cell) {
00773         if ( cell->rowAfter() >= row ) {
00774             position(cell);
00775         }
00776     }
00777     recalcRows( 0, row-1 );
00778 }
00779 
00780 void KWTableFrameSet::resizeWidth( double width ) {
00781     Q_ASSERT(width != 0);
00782     Q_ASSERT(boundingRect().width() != 0);
00783     kdDebug() << "bounding width before resize " << boundingRect().width() << endl;
00784     double growth = width / boundingRect().width();
00785 
00786     // since we move all the columns, we also move the 1st one,
00787     // depending where it is on the page.
00788     // just compensate by substracting that offset.
00789     double moveOffset = m_colPositions[0] * growth - m_colPositions[0];
00790 
00791     for (uint i=0; i<m_colPositions.count(); i++) {
00792         m_colPositions[i] = m_colPositions[i] * growth - moveOffset;
00793     }
00794     finalize();
00795     kdDebug() << "bounding width after resize" << boundingRect().width() << endl;
00796     Q_ASSERT(boundingRect().width() - width < 0.01);
00797 }
00798 
00799 void KWTableFrameSet::setBoundingRect( KoRect rect, CellSize widthMode, CellSize heightMode ) {
00800    // Column positions..
00801     m_colPositions.clear();
00802     unsigned int cols=0;
00803     for (TableIter c(this); c; ++c)
00804         cols = kMax(cols, c.current()->columnAfter());
00805     double colWidth = rect.width() / cols;
00806     if ( widthMode == TblAuto ) {
00807         KWPage *page = pageManager()->page(rect);
00808         rect.setLeft( page->leftMargin() );
00809         colWidth = (page->width() - page->leftMargin() - page->rightMargin()) / cols;
00810     }
00811 
00812     for(unsigned int i=0; i <= cols;i++) {
00813         m_colPositions.append(rect.x() + colWidth * i);
00814     }
00815 
00816     // Row positions..
00817     m_rowPositions.clear();
00818     m_pageBoundaries.clear();
00819     double rowHeight = 0;
00820     if( heightMode != TblAuto )
00821         rowHeight = rect.height() / m_rows;
00822     rowHeight=kMax(rowHeight, 22.0); // m_doc->getDefaultParagLayout()->getFormat().ptFontSize()) // TODO use table style font-size
00823 
00824     for(unsigned int i=0; i <= m_rows;i++) {
00825         m_rowPositions.append(rect.y() + rowHeight * i);
00826     }
00827 
00828     double oneMm = MM_TO_POINT( 1.0 );
00829     for (TableIter cell(this); cell; ++cell) {
00830         KWFrame *frame = cell->frame(0);
00831         frame->setPaddingLeft( oneMm );
00832         frame->setPaddingRight( oneMm );
00833         frame->setPaddingTop( oneMm );
00834         frame->setPaddingBottom( oneMm );
00835         frame->setNewFrameBehavior( KWFrame::NoFollowup );
00836         position(cell, true);
00837     }
00838 }
00839 
00840 void KWTableFrameSet::position( Cell *theCell, bool setMinFrameHeight ) {
00841     if(!theCell->frame(0)) { // sanity check.
00842         kdDebug(32004) << "errorous table cell!! row:" << theCell->firstRow()
00843             << ", col: " << theCell->firstColumn() << endl;
00844         return;
00845     }
00846     double x = *m_colPositions.at(theCell->firstColumn());
00847     double y = getPositionOfRow(theCell->firstRow());
00848     double width = (*m_colPositions.at(theCell->columnAfter())) - x;
00849     double height  = getPositionOfRow(theCell->lastRow(), true) - y;
00850 
00851 #if 0
00852     if(theCell->m_col==0) {
00853         kdDebug(32004) << "row "  << theCell->firstRow() << " has top: "
00854             << y << ", and bottom: " << y + height << endl;
00855     }
00856 #endif
00857 
00858     // Now take the border sizes and make the cell smaller so it still fits inside the grid.
00859     KWFrame *theFrame = theCell->frame(0);
00860     x+=theCell->leftBorder();
00861     width-=theCell->leftBorder();
00862     width-=theCell->rightBorder();
00863     y+=theCell->topBorder();
00864     height-=theCell->topBorder();
00865     height-=theCell->bottomBorder();
00866 
00867     theFrame->setRect( x,y,width,height);
00868     if( setMinFrameHeight )
00869         theFrame->setMinimumFrameHeight(height);
00870 
00871     if(!theCell->isVisible())
00872         theCell->setVisible(true);
00873 }
00874 
00875 double KWTableFrameSet::getPositionOfRow( unsigned int row, bool bottom ) {
00876     unsigned int adjustment=0;
00877     QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
00878     while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row + adjustment) {
00879         adjustment++;
00880         pageBound++;
00881     }
00882     if(m_rowPositions.count() < row+adjustment+(bottom?1:0))  // Requested row does not exist.
00883         return 0;
00884     return m_rowPositions[row+adjustment+(bottom?1:0)];
00885 }
00886 
00887 void KWTableFrameSet::moveBy( double dx, double dy ) {
00888     bool redraw=false;
00889     kdDebug(32004) << "KWTableFrameSet(" << name() << ")::moveBy(" << dx<<","<<dy<<")\n";
00890     //for(unsigned int i=0; i < m_rowPositions.count() ; kdDebug(32004) << "row " << i << ": " << m_rowPositions[i++] << endl);
00891     if(!(dy > -0.001 && dy < 0.001)) {
00892         redraw=true;
00893         QValueList<double>::iterator row = m_rowPositions.begin();
00894         while(row != m_rowPositions.end()) {
00895             (*row)= (*row)+dy;
00896             row++;
00897         }
00898     }
00899     if(!(dx > -0.001 && dx < 0.001)) {
00900         redraw=true;
00901         QValueList<double>::iterator col = m_colPositions.begin();
00902         while(col != m_colPositions.end()) {
00903             (*col)= (*col)+dx;
00904             col++;
00905         }
00906     }
00907 
00908     if(redraw) {
00909         for(TableIter cell(this);cell;++cell)
00910             position(cell);
00911     }
00912 }
00913 
00914 /* Delete all cells that are completely in this row.              */
00915 void KWTableFrameSet::deleteRow( unsigned int row, RemovedRow &rr, bool _recalc)
00916 {
00917     Q_ASSERT(row < m_rowArray.size());
00918     const unsigned int rowspan=1;
00919 
00920     double height= getPositionOfRow(row+rowspan-1,true) - getPositionOfRow(row);
00921     QValueList<double>::iterator tmp = m_rowPositions.at(row+rowspan);
00922     tmp=m_rowPositions.erase(tmp);
00923     while(tmp!=m_rowPositions.end()) {
00924         (*tmp)= (*tmp)-height;
00925         tmp++;
00926     }
00927 
00928     rr.m_index = row;
00929     rr.m_rowHeight = height;
00930     rr.m_row = m_rowArray[row];
00931 
00932     // move/delete cells.
00933     for ( TableIter cell(this); cell; ++cell ) {
00934         if ( row >= cell->firstRow() && row < cell->rowAfter()) { // cell is indeed in row
00935             if(cell->rowSpan() == 1) { // cell is wholly contained within row
00936                 m_frames.remove( cell->frame(0) );
00937             } else { // make cell span rowspan less rows
00938                 cell->setRowSpan(cell->rowSpan()-rowspan);
00939                 position(cell);
00940             }
00941 
00942         } else if ( cell->firstRow() > row ) {
00943             // move cell up
00944             cell->setFirstRow( cell->firstRow() - rowspan );
00945             position(cell);
00946         }
00947     }
00948 
00949     removeRowVector(row);
00950     m_rows -= rowspan;
00951     m_rowArray.resize( m_rows );
00952     validate();
00953 
00954     if ( _recalc )
00955         recalcRows( 0, row-1 );
00956 }
00957 
00958 void KWTableFrameSet::reInsertRow(RemovedRow &rr)
00959 {
00960    uint row = rr.index();
00961    Row *r =  rr.row();
00962    uint rlen = r->count();
00963 
00964    // adjust cell positions & sizes
00965    for(MarkedIterator cell(this); cell; ++cell) {
00966 
00967         if ( cell->firstRow() < row && cell->lastRow() >= row ){ // cell is indeed in row
00968                 cell->setRowSpan(cell->rowSpan() + 1);
00969         }
00970         else if(r->m_cellArray[cell->firstColumn()] == cell.current()) {
00971                 cell->setRowSpan(cell->rowSpan() + 1);
00972         }
00973         else if ( cell->firstRow() >= row ) {
00974             // move cell down
00975             cell->setFirstRow( cell->firstRow() + 1);
00976         }
00977    }
00978 
00979    // put back m_frames that were removed
00980    for(uint i = 0; i < rlen; i++){
00981        if( m_frames.findRef((*r)[i]->frame(0)) == -1 )
00982         m_frames.append( (*r)[i]->frame(0) );
00983    }
00984 
00985    // adjust row positions (ignores page boundaries!)a
00986    if(row == m_rows) {  //reinserting at bottom of table
00987        double d = m_rowPositions.last() + rr.height();
00988        m_rowPositions.append(d);
00989    }
00990    else {
00991        QValueList<double>::iterator top = m_rowPositions.at(row);
00992        QValueList<double>::iterator i = m_rowPositions.at(row+1);
00993        i = m_rowPositions.insert(i, *top + rr.height());
00994        i++;
00995        for(; i != m_rowPositions.end(); ++i) {
00996            *i = *i+ rr.height();
00997        }
00998    }
00999 
01000    // reinsert row into array
01001    m_rows++;
01002    insertRowVector(rr.index(), rr.takeRow());
01003 
01004    // don't actually have to visit all the cells, this could be optimised
01005    for(TableIter i(this); i ; ++i)
01006       position(i.current());
01007 
01008    validate();
01009 }
01010 
01011 void KWTableFrameSet::insertNewRow( uint idx, bool recalc, bool _removeable)
01012 {
01013 
01014     (void) _removeable; // unused parameter
01015     unsigned int copyFromRow = idx==0?0:idx-1;
01016     if(idx==0)
01017         copyFromRow=1;
01018     Row *copyRow = m_rowArray[copyFromRow];
01019 
01020     uint new_rows = m_rows + 1;
01021     // What height to use for the new row
01022     double height = getPositionOfRow(copyFromRow,true) - getPositionOfRow(copyFromRow);
01023 
01024     // Calculate offset in QValueList because of page breaks.
01025     unsigned int adjustment=0;
01026     unsigned int untilRow=m_rows;
01027     QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
01028     while(pageBound != m_pageBoundaries.end() && (*pageBound) <= idx) {
01029         // Find out how many pages we already had.
01030         adjustment++;
01031         pageBound++;
01032     }
01033 
01034     // Move all rows down from newRow to bottom of page
01035     QValueList<double>::iterator tmp = m_rowPositions.at(idx);
01036     double newPos = *tmp + height;
01037     tmp++;
01038     m_rowPositions.insert(tmp, newPos);
01039     for(unsigned int i=idx+adjustment+2; i < m_rowPositions.count(); i++) {
01040         double &rowPos = m_rowPositions[i];
01041         kdDebug(32004) << "adjusting " << rowPos << " -> " << rowPos + height << endl;
01042         rowPos = rowPos + height;
01043         if(*pageBound == i) {
01044             untilRow= *pageBound;
01045             break;              // stop at pageBreak.
01046         }
01047     }
01048 
01049     for ( MarkedIterator cells(this); cells; ++cells) {
01050         if ( cells->firstRow() >= idx ) { // move all cells beneath the new row.
01051             cells->setFirstRow(cells->firstRow()+1);
01052         }
01053     }
01054 
01055     insertRowVector(idx, new Row);
01056 
01057     unsigned int i = 0;
01058     while(i < getColumns()) {
01059 
01060         if(idx != 0 && (idx != m_rows)) {
01061             Cell *c = cell(idx - 1, i);
01062             if( c == cell(idx + 1, i) ) {
01063                 m_rowArray[idx]->addCell(c);
01064                 c->setRowSpan(c->rowSpan() + 1);
01065                 i += c->columnSpan();
01066                 continue; // don't need to make a new cell
01067             }
01068         }
01069 
01070         KWFrame *theFrame = new KWFrame(copyRow->m_cellArray[i]->frame(0));
01071         Cell *newCell=new Cell( this, idx, i, QString::null );
01072         newCell->setColumnSpan( cell(copyFromRow,i)->columnSpan() );
01073         addCell(newCell);
01074         newCell->addFrame( theFrame, false );
01075         position(newCell);
01076         i += newCell->columnSpan();
01077    }
01078 
01079     // Position all changed cells.
01080 
01081     m_rows = new_rows;
01082     validate();
01083     if ( recalc )
01084         finalize();
01085 }
01086 
01087 void KWTableFrameSet::deleteColumn(uint col, RemovedColumn &rc)
01088 {
01089     // keep these values in case we have to put it back
01090     if(!rc.m_initialized) {
01091         rc.m_index = col;
01092         rc.m_width = m_colPositions[col+1] - m_colPositions[col];
01093     }
01094 
01095     // move the colomn positions
01096     QValueList<double>::iterator tmp = m_colPositions.at(col+1);
01097     tmp = m_colPositions.erase(tmp);
01098     while(tmp != m_colPositions.end()) {
01099         (*tmp) = (*tmp) - rc.m_width;
01100         tmp++;
01101     }
01102 
01103     // remove cells that are wholy in this column,
01104     // otherwise reduce rowspan. pointers to all cells
01105     // are kept in the RemovedColumn
01106     CheckedIter iter(this);
01107     for(uint i = 0; i < m_rows; ++i) {
01108         Cell *daCell = cell(i, col);
01109 
01110         if(!rc.m_initialized) {
01111             rc.m_column.append(daCell);
01112             rc.m_removed.append(daCell->columnSpan() == 1);
01113         }
01114 
01115         if(daCell->columnSpan() == 1) { // lets remove it
01116             if(daCell->firstRow() == i) {
01117                 m_frames.remove( daCell->frame(0) );
01118                 m_nr_cells--;
01119             }
01120             m_rowArray[i]->m_cellArray.insert(col, 0);
01121         }
01122         else {                    // make cell span 1 less column
01123             if(daCell->firstRow() == i) {
01124                 daCell->setColumnSpan( daCell->columnSpan() - 1 );
01125                 position(daCell);
01126             }
01127         }
01128     }
01129 
01130     // adjust cells in a later column
01131     for(; iter; ++iter) {
01132         if (iter->firstColumn() > col ) {
01133             iter->setFirstColumn( iter->firstColumn() - 1);
01134             position(iter.current());
01135         }
01136     }
01137 
01138     // move pointers in 2d array back one column to occupy
01139     // removed column
01140     for(uint i = 0; i < m_rows; i++) {
01141         for(uint j = col + 1; j < m_cols; j++)
01142              m_rowArray[i]->m_cellArray.insert(j-1, m_rowArray[i]->m_cellArray[j]);
01143     }
01144     m_cols--;
01145     rc.m_initialized = true;
01146 
01147     validate();
01148     recalcCols( col, 0 );
01149     recalcRows( col, 0 );
01150 }
01151 
01152 void KWTableFrameSet::reInsertColumn(RemovedColumn &rc)
01153 {
01154     QValueList<double>::iterator tmp = m_colPositions.at(rc.m_index);
01155 
01156     tmp = m_colPositions.insert(tmp, *tmp);
01157     tmp++;
01158     while(tmp != m_colPositions.end()) {
01159         (*tmp) = (*tmp) + rc.m_width;
01160         tmp++;
01161     }
01162 
01163     // if a cell starts after the column we are inserting, it
01164     // must be moved to the right, except if it is going to
01165     // occury the reinserted column also.
01166     for ( MarkedIterator cells(this); cells ; ++cells ) {
01167         if ( cells->firstColumn() >= rc.m_index &&
01168             (rc.m_column.at(cells->firstRow()) != cells.current())) {
01169 
01170             cells->setFirstColumn(cells->firstColumn() + 1);
01171         }
01172     }
01173     insertEmptyColumn(rc.m_index);
01174     m_cols++;
01175 
01176     for(uint i = 0; i < m_rows; ++i) {
01177         bool removed = rc.m_removed[i];
01178         Cell *daCell = rc.m_column.at(i);
01179         if(i == daCell->firstRow()) {
01180             if(removed) {
01181                 daCell->setColumnSpan(1);
01182                 m_frames.append(daCell->frame(0));
01183                 m_nr_cells++;
01184             }
01185             else  {
01186                daCell->setColumnSpan(daCell->columnSpan() + 1);
01187             }
01188             addCell(daCell);
01189         }
01190     }
01191 
01192     validate();
01193     finalize();
01194 }
01195 
01196 void KWTableFrameSet::insertNewColumn( uint idx, double width)
01197 {
01198     QValueList<double>::iterator tmp = m_colPositions.at(idx);
01199 
01200     tmp = m_colPositions.insert(tmp, *tmp);
01201     tmp++;
01202     while(tmp!=m_colPositions.end()) {
01203         (*tmp)= (*tmp)+width;
01204         tmp++;
01205     }
01206 
01207     for ( MarkedIterator cells(this); cells ; ++cells ) {
01208         if ( cells->firstColumn() >= idx) { // move all cells right of the new col.
01209             cells->setFirstColumn(cells->firstColumn() + 1);
01210         }
01211     }
01212     insertEmptyColumn(idx);
01213     m_cols++;
01214     uint copyCol = (idx == 0) ? 1 : idx - 1 ;
01215 
01216     // make the new cells
01217     // note that the loop counter is mucked with in the loop!
01218     for( unsigned int i = 0; i < getRows(); i++ ) {
01219 
01220         // can't break a cell in half, so if there is the same cell
01221         // on both sides of inserted column, it occupies the new
01222         // column as well
01223         if(idx != 0 && (idx != m_cols -1)) {
01224             Cell *c = cell(i, idx - 1);
01225             if( c == cell(i, idx + 1) ) {
01226 //                m_rowArray[i]->m_cellArray.insert(idx, c);
01227                 c->setColumnSpan(c->columnSpan() + 1);
01228                 addCell(c);
01229                 i += c->rowSpan() - 1;
01230                 continue; // don't need to make a new cell
01231             }
01232         }
01233 
01234         Cell *newCell = new Cell( this, i, idx, QString::null );
01235         KWFrame *theFrame = new KWFrame(cell(i, copyCol)->frame(0));
01236         newCell->addFrame( theFrame, false );
01237         position(newCell);
01238         m_nr_cells++;
01239     }
01240     validate();
01241     finalize();
01242 }
01243 
01244 void KWTableFrameSet::ungroup()
01245 {
01246 //    m_cells.setAutoDelete( false );
01247 //    m_cells.clear();
01248     m_nr_cells = 0;
01249 
01250     m_active = false;
01251 }
01252 
01253 void KWTableFrameSet::group()
01254 {
01255 //   m_cells.setAutoDelete( true );
01256 //   m_cells.clear();
01257 
01258    m_nr_cells = 0;
01259    m_active = true;
01260 }
01261 
01262 KCommand *KWTableFrameSet::joinCells(unsigned int colBegin,unsigned int rowBegin, unsigned int colEnd,unsigned int rowEnd) {
01263     Cell *firstCell = cell(rowBegin, colBegin);
01264     // if just one cell selected for joining; exit.
01265     if(rowBegin == rowEnd && colBegin == colEnd || cell(rowBegin,colBegin) == cell(rowEnd,colEnd))
01266         return 0L;
01267     QPtrList<KWFrameSet> listFrameSet;
01268     QPtrList<KWFrame> listCopyFrame;
01269 
01270     // do the actual merge.
01271     for(unsigned int i=colBegin; i<=colEnd;i++) {
01272         for(unsigned int j=rowBegin; j<=rowEnd;j++) {
01273             Cell *daCell = cell(j,i);
01274             if(daCell && daCell!=firstCell) {
01275                 listFrameSet.append(daCell);
01276                 listCopyFrame.append(daCell->frame(0)->getCopy());
01277                 daCell->deleteFrame( daCell->frame(0));
01278             }
01279         }
01280     }
01281 
01282     Q_ASSERT(firstCell);
01283     // update firstcell properties to reflect the merge
01284     firstCell->setColumnSpan(colEnd-colBegin+1);
01285     firstCell->setRowSpan(rowEnd-rowBegin+1);
01286     addCell(firstCell);
01287     position(firstCell);
01288     validate();
01289 
01290     m_doc->updateAllFrames(); // TODO: only fs->updateFrames() & m_doc->updateFramesOnTopOrBelow(pageNum)
01291     m_doc->repaintAllViews();
01292     return new KWJoinCellCommand( i18n("Join Cells"), this,colBegin,rowBegin, colEnd,rowEnd,listFrameSet,listCopyFrame);
01293 }
01294 
01295 KCommand *KWTableFrameSet::splitCell(unsigned int intoRows, unsigned int intoCols, unsigned int col, unsigned int row, QPtrList<KWFrameSet> listFrameSet, QPtrList<KWFrame>listFrame) {
01296     if(intoRows < 1 || intoCols < 1)
01297         return 0L;
01298 
01299     kdDebug(32004) << "KWTableFrameSet::splitCell" << endl;
01300     Cell *daCell=cell(row,col);
01301     int rowsDiff = intoRows - daCell->rowSpan();
01302     int colsDiff = ((int) intoCols) - daCell->columnSpan();
01303 
01304     if(rowsDiff >0) {
01305         unsigned int adjustment=0;
01306         QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
01307         while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row) {
01308             adjustment++;
01309             pageBound++;
01310         }
01311         double height = (m_rowPositions[row+adjustment+1] - m_rowPositions[row+adjustment])/intoRows;
01312 
01313         QValueList<double>::iterator iRow = m_rowPositions.at(adjustment+row);
01314         for (int i=0; i < rowsDiff; i++) {
01315             double newPos = *iRow + height;
01316             iRow++;
01317             iRow=m_rowPositions.insert(iRow, newPos);
01318         }
01319 
01320         // insert more rows into m_rowArray
01321         for(int i = 0; i < rowsDiff; ++i) {
01322             insertRowVector(row+i+1, new Row);
01323             m_rows++;
01324         }
01325 
01326        // m_rows += rowsDiff;
01327         //for(unsigned int i=0; i < m_rowPositions.count() ; ++i)
01328         //    kdDebug(32004) << "row " << i << ": " << m_rowPositions[i] << endl);
01329     }
01330     if(colsDiff >0) {
01331         double width = (m_colPositions[col+1] - m_colPositions[col])/intoCols;
01332 
01333         QValueList<double>::iterator iCol = m_colPositions.at(col);
01334         for (int i=0; i < colsDiff; i++) {
01335             double newPos = *iCol + width;
01336             iCol++;
01337             iCol=m_colPositions.insert(iCol, newPos);
01338         }
01339 
01340         for(int i = 0; i < colsDiff; i++) {
01341             insertEmptyColumn(col+i+1);
01342             m_cols++;
01343         }
01344         //for(unsigned int i=0; i < m_colPositions.count(); ++i)
01345         //    kdDebug(32004) << "col " << i << ": " << m_colPositions[i] << endl);
01346         //m_cols += colsDiff;
01347     }
01348 
01349     // adjust cellspan and rowspan on other cells.
01350     for (CheckedIter i(this); i ; ++i) {
01351         if(daCell == i) continue;
01352 
01353         if(rowsDiff>0) {
01354             if(row >= i->firstRow()&& row < i->firstRow()+ i->rowSpan())
01355                 i->setRowSpan(i->rowSpan() + rowsDiff);
01356             if(i->firstRow() > row) {
01357                 i->setFirstRow(i->firstRow() + rowsDiff);
01358             //    theCell->frame(0)->setTop(theCell->frame(0)->top()+extraHeight);
01359             }
01360         }
01361         if(colsDiff>0) {
01362             if(col >= i->firstColumn() && col < i->columnAfter())
01363                 i->setColumnSpan(i->columnSpan() + colsDiff);
01364             if(i->firstColumn() > col)
01365                 i->setFirstColumn(i->firstColumn() + colsDiff);
01366         }
01367         /*if(extraHeight != 0 && theCell->firstRow()== row) {
01368             theCell->frame(0)->setHeight(theCell->frame(0)->height()+extraHeight);
01369         } */
01370         if ( rowsDiff > 0 || colsDiff > 0 ) // something changed?
01371             addCell( i ); // update arrays
01372     }
01373 
01374     int i=0;
01375     KWFrame *firstFrame = daCell->frame(0);
01376     // create new cells
01377     for (unsigned int y = 0; y < intoRows; y++) {
01378         for (unsigned int x = 0; x < intoCols; x++){
01379             if(x==0 && y==0)
01380                 continue; // the orig cell takes this spot.
01381 
01382             Cell *lastFrameSet=0L;
01383 
01384             if(listFrameSet.isEmpty())
01385                 lastFrameSet = new Cell( this, y + row, x + col );
01386             else
01387                 lastFrameSet = static_cast<KWTableFrameSet::Cell*> (listFrameSet.at(i));
01388             lastFrameSet->setGroupManager(this);
01389 
01390             KWFrame *theFrame=0L;
01391             if(listFrame.isEmpty())
01392             {
01393                 theFrame=firstFrame->getCopy();
01394                 theFrame->setRunAround( KWFrame::RA_NO );
01395                 theFrame->setFrameBehavior(KWFrame::AutoExtendFrame);
01396                 theFrame->setNewFrameBehavior(KWFrame::NoFollowup);
01397                 lastFrameSet->addFrame( theFrame,false );
01398             }
01399             else
01400                 lastFrameSet->addFrame( listFrame.at(i)->getCopy(),false );
01401             i++;
01402 
01403             // if the orig cell spans more rows/cols than it is split into, make first col/row wider.
01404             if(rowsDiff <0 && y==0)
01405                 lastFrameSet->setRowSpan(lastFrameSet->rowSpan() - rowsDiff);
01406             if(colsDiff <0 && x==0)
01407                 lastFrameSet->setColumnSpan(lastFrameSet->columnSpan() - colsDiff);
01408 
01409             addCell( lastFrameSet );
01410             position(lastFrameSet);
01411         }
01412     }
01413 
01414     // set new row and col-span. Use intermediate ints otherwise we get strange results as the
01415     // intermediate result could be negative (which goes wrong with unsigned ints)
01416     int r = (daCell->rowSpan() +1) - intoRows;
01417     if(r < 1) r=1;
01418     daCell->setRowSpan(r);
01419 
01420     int c = (daCell->columnSpan() + 1) - intoCols;
01421     if(c < 1)  c=1;
01422     daCell->setColumnSpan(c);
01423 
01424     position(daCell);
01425     addCell(daCell);
01426     validate();
01427 
01428     finalize();
01429 
01430     return new KWSplitCellCommand(i18n("Split Cells"),this,col,row,intoCols, intoRows);
01431 }
01432 
01433 void KWTableFrameSet::viewFormatting( QPainter &/*painter*/, int )
01434 {
01435 }
01436 
01437 void KWTableFrameSet::validate()
01438 {
01439     for(CheckedIter cells(this); cells; ++cells) {
01440         if(cells->columnSpan() == 0 || cells->rowSpan() == 0)  {
01441             kdDebug(32004) << " KWTableFrameSet::validate(): zero dimension" << endl;
01442             kdDebug(32004) << cells->firstRow() << " " << cells->firstColumn() << " " << cells->rowSpan()
01443                 << " " << cells->columnSpan() << endl;
01444         }
01445 
01446         for(uint i = cells->firstRow(); i < cells->rowAfter(); ++i) {
01447 
01448              for(uint j = cells->firstColumn(); j < cells->columnAfter(); ++j) {
01449                   if( cell(i,j) != cells.current() ) {
01450 
01451                       QString str = QString("| 0x%1 ").arg( (unsigned long)cells.current(), 0, 16 );
01452                       kdDebug(32004) << " KWTableFrameSet::validate() failed " << endl;
01453                       kdDebug(32004) << "at row:  "<< i << " col: "<< j << " cell: "<<  str << endl;
01454                       kdDebug(32004) << cells->firstRow() << " " << cells->firstColumn() << " " << cells->rowSpan()
01455                            << " " << cells->columnSpan() << endl;
01456                       //printArrayDebug();
01457                   }
01458              }
01459         }
01460     }
01461 }
01462 
01463 void KWTableFrameSet::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode )
01464 {
01465     // Avoid iterating over all cells if we are out of view
01466     if ( !viewMode->normalToView( m_doc->zoomRect( boundingRect() ) ).intersects( crect ) )
01467         return;
01468 
01469     QRect outerRect( viewMode->normalToView( m_doc->zoomRect( boundingRect() )));
01470     outerRect &= crect;
01471         if ( !outerRect.isEmpty() )
01472             emptyRegion = emptyRegion.subtract( outerRect );
01473 
01474     QPtrListIterator<KWFrame> frameIt = frameIterator();
01475     for ( ; frameIt.current(); ++frameIt )
01476     {
01477         QRect outerRect( viewMode->normalToView( frameIt.current()->outerRect(viewMode) ) );
01478         //kdDebug(32004) << "KWTableFrameSet::createEmptyRegion outerRect=" << DEBUGRECT( outerRect )
01479         //          << " crect=" << DEBUGRECT( crect ) << endl;
01480         outerRect &= crect;
01481         if ( !outerRect.isEmpty() )
01482             emptyRegion = emptyRegion.subtract( outerRect );
01483     }
01484 }
01485 
01486 void KWTableFrameSet::drawBorders( QPainter& painter, const QRect &crect, KWViewMode *viewMode ) {
01487 
01488     /*  Draw the borders on top of the lines stores in the m_rowPositions and m_colPositions arrays.
01489      *  check the relevant cells for borders and thus line thickness.
01490      *  We move the outer lines (on row==0 and col==0 plus on col=getColumns() etc) a bit so they will stay
01491      *  inside the boundary of the table!
01492      */
01493     painter.save();
01494     QPen previewLinePen( QApplication::palette().color(  QPalette::Active, QColorGroup::Mid ) );
01495     QColor defaultBorderColor = KoTextFormat::defaultTextColor( &painter );
01496     const int minborder = 1;
01497     bool drawPreviewLines = viewMode && viewMode->drawFrameBorders();
01498 
01499     // *** draw horizontal lines *** //
01500     unsigned int row=0;
01501     QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
01502     for (unsigned int i=0 ; i < m_rowPositions.count() ; i++) {
01503         //kdDebug(32004) << "Horizontal line code. i: " << i << endl;
01504         bool bottom=false;
01505         if( (pageBound!=m_pageBoundaries.end() && (*pageBound) == row)
01506             || i == m_rowPositions.count()-1)
01507             bottom=true;  // at end of page or end of table draw bottom border of cell.
01508 
01509         const KoBorder *border=0;
01510         double startPos =0;
01511         for(unsigned int col=0; col <= getColumns();) {
01512             //kdDebug(32004) << "bottom=" << bottom << " row=" << row << " col=" << col << endl;
01513             Cell *daCell = col < getColumns() ? cell(bottom?row-1:row, col) : 0;
01514             //if(daCell) kdDebug(32004) << "cell (" << daCell->firstRow()<< "," << daCell->firstColumn() << ")" << endl;
01515             //else kdDebug(32004) << "cell: " << daCell << endl;
01516 
01517             if(daCell && daCell->firstRow() != (bottom?row-1:row))
01518                 daCell=0;
01519 
01520             if(startPos!=0 && (!daCell || col == getColumns() || (
01521                     bottom && daCell->frame(0)->bottomBorder()!=*border ||
01522                     !bottom && daCell->frame(0)->topBorder()!=*border
01523                     ))) {
01524                 if(border->width() > 0 || drawPreviewLines) {
01525                     double y = m_rowPositions[i];
01526                     if(row==0)
01527                         y+=border->width() / 2; // move slightly down.
01528                     else if (row == getRows())
01529                         y-=border->width() / 2; // move slightly up.
01530                     int ypix = m_doc->zoomItY(y);
01531                     double offset=0.0;
01532                     if(border->width() > 0 && col!=getColumns()) { // offset border when not at right most cell.
01533                         if(daCell) offset=daCell->leftBorder();
01534                         if ( row > 0 ) {
01535                             Cell *c = cell(row-1, col);
01536                             if(c) offset=kMax(offset, c->leftBorder());
01537                         }
01538                     }
01539                     double x = m_colPositions[col] + offset;
01540                     QPoint topLeft = viewMode->normalToView(QPoint(m_doc->zoomItX(startPos), ypix));
01541                     QPoint bottomRight = viewMode->normalToView(QPoint(m_doc->zoomItX(x), ypix));
01542                     QRect line = QRect(topLeft, bottomRight);
01543                     if(crect.intersects( line )) {
01544                         //if(border->width() <= 0) kdDebug(32004) << "preview line" << endl;
01545                         if(border->width() <= 0)
01546                             painter.setPen( previewLinePen );
01547                         else {
01548                             int borderWidth = KoBorder::zoomWidthY( border->width(), m_doc, minborder );
01549                             painter.setPen( KoBorder::borderPen( *border, borderWidth, defaultBorderColor ) );
01550                         }
01551                         //kdDebug(32004) << "Paint: painter.drawHorizontalLine(" << line.left() << ","  << line.top() << "," <<  line.right() << ","  << line.bottom() << ")\n";
01552                         painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
01553                     }
01554                 }
01555                 // reset startPos
01556                 startPos = 0;
01557             }
01558             if(daCell && startPos==0) {
01559                 if(bottom)
01560                     border=&(daCell->frame(0)->bottomBorder());
01561                 else
01562                     border=&(daCell->frame(0)->topBorder());
01563 
01564                 if(col==0) // left most cell
01565                     startPos = m_colPositions[col];
01566                 else {
01567                     double offset=0.0;
01568                     if(border->width() > 0) { // move line to the left a bit to compensate for the left border
01569                         if(daCell) offset=daCell->leftBorder();
01570                         if ( row > 0 ) {
01571                             Cell *c = cell(row-1, col);
01572                             if(c) offset=kMax(offset, c->leftBorder());
01573                         }
01574                     }
01575                     startPos = m_colPositions[col] - offset;
01576                 }
01577             }
01578             col += daCell ? daCell->columnSpan() : 1;
01579         }
01580         if(pageBound!=m_pageBoundaries.end() && (*pageBound) == row)
01581             pageBound++;
01582         else
01583             row++;
01584     }
01585 
01586     // *** draw vertical lines *** //
01587     for (unsigned int col=0 ; col < m_colPositions.count(); col++) {
01588         //kdDebug(32004) << "Vertical line code. col: " << col << endl;
01589         bool right = false;
01590         if(col == m_colPositions.count()-1)
01591             right = true; // draw right border of cell.
01592         int cellColumn = right?col-1:col; // the column we'll be looking for in the loop below
01593         Q_ASSERT( cellColumn >= 0 );
01594 
01595         const KoBorder *border = 0;
01596         int startRow = -1;
01597         for(unsigned int row=0; row <= getRows();) {
01598             //kdDebug(32004) << "row=" << row << " cellColumn=" << cellColumn << endl;
01599             Cell *daCell = row < getRows() ? cell(row, cellColumn) : 0;
01600 
01601             //kdDebug(32004) << "Drawing vert. Line for cell row: " << row << " col: " << cellColumn << endl;
01602             if(daCell && daCell->firstColumn() != (uint)cellColumn)
01603                 daCell=0;
01604 
01605 #if 0
01606             kdDebug() << "Condition: startRow:" << (startRow!=-1) << endl;
01607             if ( startRow != -1 )  {
01608                 Q_ASSERT( border );
01609                 kdDebug() << "Other conditions: cell:" << !daCell << endl;
01610                 kdDebug() << " or last row:" << ( row == ( int )getRows() ) << endl;
01611                 if ( daCell )
01612                     kdDebug() << "Different border:" <<
01613                 ( ( right && daCell->frame(0)->rightBorder() != *border) ||
01614                 ( !right && daCell->frame(0)->leftBorder() != *border) )
01615                     << endl;
01616             }
01617 #endif
01618 
01619             // be sure that the right border of the table is drawn even for joined cells
01620             if ( !daCell && startRow == -1 && cellColumn == ((int)m_colPositions.count()-2 ) && right )
01621             {
01622               // find the joined cell
01623               int col = cellColumn;
01624               while ( !daCell && col>0 )
01625               {
01626                 col--;
01627                 daCell = cell(row, col);
01628               }
01629               if ( daCell && daCell->isJoinedCell() && ( (int)daCell->columnSpan() + col -1 ) == cellColumn )
01630               {
01631                 border = &(daCell->frame(0)->rightBorder());
01632                 startRow = row;
01633               }
01634               else
01635                 daCell = 0;
01636             }
01637 
01638             // Draw when something changed (different kind of border) or we're at the end
01639             // This code could be rewritten in a more QRT-like way
01640             // (iterate and compare with next, instead of the startRow/cell/border hack...)
01641             if(startRow != -1 &&
01642                (!daCell || row == getRows() ||
01643                 ( right && daCell->frame(0)->rightBorder() != *border) ||
01644                 ( !right && daCell->frame(0)->leftBorder() != *border) )
01645                 ) {
01646                 if(border->width() > 0 || drawPreviewLines) {
01647                     double x = m_colPositions[col];
01648                     if(col==0) {
01649                         x+=border->width() / 2;
01650                     } else if(col==getColumns()) {
01651                         x-=border->width() / 2;
01652                     }
01653                     int xpix = m_doc->zoomItX(x);
01654                     QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
01655                     unsigned int topRow=startRow;
01656                     //kdDebug(32004) << "Drawing from topRow=" << topRow << endl;
01657                     do { // draw minimum of one line per page.
01658                         while( pageBound != m_pageBoundaries.end() && *(pageBound) < topRow )
01659                             pageBound++;
01660 
01661                         unsigned int bottomRow;
01662                         if(pageBound == m_pageBoundaries.end())
01663                             bottomRow = m_rowPositions.count()-1;
01664                         else
01665                             bottomRow = *(pageBound++);
01666 
01667                         //kdDebug(32004) << "from: " << topRow << " to: " << kMin((uint)row, bottomRow) << endl;
01668                         //kdDebug(32004) << "from: " << m_rowPositions[topRow] << " to: " << m_rowPositions[kMin((uint)row, bottomRow)] << endl;
01669                         double offset=0.0;
01670                         if(border->width() > 0) {
01671                             //kdDebug(32004) << "looking at topRow=" << topRow << " col=" << col << endl;
01672                             Cell *c=cell(topRow,col);
01673                             if(c) offset=c->topBorder();
01674                             if ( col > 0 ) {
01675                                 c=cell(topRow,col-1);
01676                                 if(c) offset=kMax(offset,c->topBorder());
01677                             }
01678                             if(topRow==0) offset=0.0;
01679                         }
01680                         double top=m_rowPositions[topRow]-offset;
01681 
01682                         unsigned int toRow=kMin((uint)row,bottomRow);
01683                         offset=0.0;
01684                         if(border->width() > 0 && toRow!=bottomRow) {
01685                             if(daCell) offset=daCell->topBorder();
01686                             Cell *c=cell(toRow,col-1);
01687                             if(c) offset=kMax(offset,c->topBorder());
01688                         }
01689                         double bottom=m_rowPositions[toRow] + offset;
01690 
01691                         QPoint topLeft = viewMode->normalToView(QPoint(xpix, m_doc->zoomItY(top)));
01692                         QPoint bottomRight = viewMode->normalToView(QPoint(xpix, m_doc->zoomItY(bottom)));
01693                         QRect line = QRect(topLeft, bottomRight);
01694                         if(crect.intersects( line )) {
01695                             if(border->width() <= 0)
01696                                 painter.setPen( previewLinePen );
01697                             else {
01698                                 int borderWidth = KoBorder::zoomWidthX( border->width(), m_doc, minborder );
01699                                 painter.setPen(KoBorder::borderPen( *border, borderWidth, defaultBorderColor ));
01700                             }
01701                             //kdDebug(32004) << "drawBorders(): painter.drawVerticalLine(" << line.left() << ","  << line.top() << "," <<  line.right() << ","  << line.bottom() << ")\n";
01702                             painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
01703                         }
01704 
01705                         topRow=bottomRow+1;
01706                     } while(topRow < (uint)row && topRow != m_rowPositions.count());
01707                 } // end "if border to be drawn"
01708 
01709                 // reset startRow
01710                 startRow = -1;
01711             }
01712 
01713             if(daCell && startRow == -1) {
01714                 startRow = row;
01715                 if(right)
01716                     border = &(daCell->frame(0)->rightBorder());
01717                 else
01718                     border = &(daCell->frame(0)->leftBorder());
01719                 //kdDebug(32004) << "startRow set to " << row << endl;
01720             }
01721             row += daCell ? daCell->rowSpan() : 1;
01722             //kdDebug(32004) << "End of loop, row=" << row << endl;
01723         }
01724     }
01725 
01726 #if 0
01727     if(drawPreviewLines) {
01728         QPen minsizeLinePen( red );
01729         painter.setPen( minsizeLinePen );
01730         for ( unsigned int i = 0; i < m_cells.count(); i++ ) {
01731             Cell *daCell = m_cells.at( i );
01732             double y = daCell->frame(0)->top() + daCell->frame(0)->minimumFrameHeight() + 1.5;
01733             if(y >= daCell->frame(0)->bottom()) continue;
01734             int ypix=m_doc->zoomItY(y);
01735             QPoint topLeft = viewMode->normalToView(QPoint(m_doc->zoomItX(daCell->frame(0)->left()), ypix));
01736             QPoint bottomRight = viewMode->normalToView(QPoint(m_doc->zoomItX(daCell->frame(0)->right()), ypix));
01737             QRect line = QRect(topLeft, bottomRight);
01738             if(crect.intersects( line )) {
01739                 painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
01740             }
01741         }
01742     }
01743 #endif
01744 
01745     painter.restore();
01746 }
01747 
01748 void KWTableFrameSet::drawContents( QPainter * painter, const QRect & crect,
01749                                     const QColorGroup & cg, bool onlyChanged, bool resetChanged,
01750                                     KWFrameSetEdit * edit, KWViewMode * viewMode,
01751                                     KWFrameViewManager *fvm )
01752 {
01753     for (TableIter cells(this) ; cells ; ++cells)
01754     {
01755         if (edit)
01756         {
01757             KWTableFrameSetEdit * tableEdit = static_cast<KWTableFrameSetEdit *>(edit);
01758             if ( tableEdit->currentCell() && ((Cell*) cells) == tableEdit->currentCell()->frameSet() )
01759             {
01760                 cells->drawContents( painter, crect, cg, onlyChanged, resetChanged, tableEdit->currentCell(), viewMode, fvm );
01761                 continue;
01762             }
01763         }
01764         cells->drawContents( painter, crect, cg, onlyChanged, resetChanged, 0L, viewMode, fvm );
01765     }
01766     drawBorders( *painter, crect, viewMode );
01767     //kdDebug(32004) << "drawContents()" << endl;
01768 }
01769 
01770 // Called by KWAnchor for inline tables
01771 // TODO: for non-inline ones we need a text-box around us...
01772 // Well, even for inline-as-char ones.... Currently being debated with OASIS.
01773 void KWTableFrameSet::saveOasis( KoXmlWriter& writer, KoSavingContext& context, bool ) const
01774 {
01775     writer.startElement( "table:table" );
01776     writer.addAttribute( "table:name", name() );
01777     KoGenStyle tableStyle( KWDocument::STYLE_TABLE, "table" );
01778     tableStyle.addProperty( "table:align", "margins" );
01779     tableStyle.addPropertyPt( "style:width", m_colPositions.last()-m_colPositions[0] );
01780     const QString tableStyleName = context.mainStyles().lookup( tableStyle, "table" );
01781     writer.addAttribute( "table:style-name", tableStyleName );
01782 
01783     // ### to minimize the XML, we could use table:number-columns-repeated here
01784     // when a number of consecutive columns have the exact same style.
01785     for ( uint colNr = 0; colNr < getColumns(); ++colNr )
01786     {
01787         writer.startElement( "table:table-column" );
01788         KoGenStyle columnStyle( KWDocument::STYLE_TABLE_COLUMN, "table-column" );
01789         columnStyle.addPropertyPt( "style:column-width", m_colPositions[colNr+1] - m_colPositions[colNr] );
01790         const QString colStyleName = context.mainStyles().lookup( columnStyle, "col" );
01791         writer.addAttribute( "table:style-name", colStyleName );
01792         writer.endElement(); // table:table-column
01793     }
01794 
01795     // TODO table-header-rows once supported
01796 
01797     for ( uint row = 0; row < getRows(); ++row )
01798     {
01799         writer.startElement( "table:table-row" );
01800 
01801         KoGenStyle rowStyle( KWDocument::STYLE_TABLE_ROW, "table-row" );
01802         rowStyle.addPropertyPt( "table:row-height", m_rowPositions[row+1] - m_rowPositions[row] );
01803         // TODO is min-row-height or use-optimal-row-height necessary?
01804         const QString rowStyleName = context.mainStyles().lookup( rowStyle, "row" );
01805         writer.addAttribute( "table:style-name", rowStyleName );
01806 
01807         for ( uint col = 0; col < getColumns(); ++col )
01808         {
01809             Cell* daCell = cell(row, col);
01810             Q_ASSERT( daCell );
01811             if ( !daCell )
01812                 continue;
01813 
01814             if ( daCell->isFirstGridPosnFast( row, col ) )
01815             {
01816                 writer.startElement( "table:table-cell" );
01817 
01818                 // Style: background, border, padding.
01819                 KoGenStyle cellStyle( KWDocument::STYLE_TABLE_CELL_AUTO, "table-cell" );
01820                 daCell->frame( 0 )->saveBorderProperties( cellStyle );
01821                 const QString colStyleName = context.mainStyles().lookup( cellStyle, "cell" );
01822                 writer.addAttribute( "table:style-name", colStyleName );
01823 
01824                 // Attributes
01825                 if ( daCell->columnSpan() > 1 )
01826                     writer.addAttribute( "table:number-columns-spanned", daCell->columnSpan() );
01827                 if ( daCell->rowSpan() > 1 )
01828                     writer.addAttribute( "table:number-row-spanned", daCell->rowSpan() );
01829 
01830                 // Content
01831                 daCell->saveOasisContent( writer, context );
01832 
01833                 writer.endElement(); // table:table-cell
01834             }
01835             else
01836             {
01837                 // Empty element for the covered cell
01838                 writer.startElement( "table:covered-table-cell" );
01839                 writer.endElement();
01840             }
01841         }
01842         writer.endElement(); // table:table-row
01843     }
01844 
01845     writer.endElement(); // table:table
01846 }
01847 
01848 void KWTableFrameSet::loadOasis( const QDomElement& tableTag, KoOasisContext& context )
01849 {
01850     // Left position of each column. The last one defined is the right position of the last cell/column.
01851     QMemArray<double> columnLefts(4);
01852     uint maxColumns = columnLefts.size() - 1;
01853 
01854     uint col = 0;
01855     columnLefts[0] = 0.0; // Initialize left of first cell
01856     QDomElement elem;
01857     forEachElement( elem, tableTag )
01858     {
01859         if ( elem.localName() == "table-column" && elem.namespaceURI() == KoXmlNS::table )
01860         {
01861             uint repeat = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", "1").toUInt(); // Default 1 time
01862             if (!repeat)
01863                 repeat=1; // At least one column defined!
01864             KoStyleStack& styleStack = context.styleStack();
01865             styleStack.setTypeProperties( "table-column" );
01866             styleStack.save();
01867             context.fillStyleStack( elem, KoXmlNS::table, "style-name", "table-column" );
01868 
01869             QString strWidth = styleStack.attributeNS( KoXmlNS::style, "column-width" );
01870             double width = KoUnit::parseValue( strWidth );
01871 
01872             if ( width < 1.0 ) // Something is wrong with the width
01873             {
01874                 kdWarning(32004) << "Table column width ridiculous, assuming 1 inch!" << endl;
01875                 width = 72.0;
01876             }
01877             else
01878                 kdDebug(32004) << "- style width " << width << endl;
01879 
01880             for ( uint j = 0; j < repeat; ++j )
01881             {
01882                 ++col;
01883                 if ( col >= maxColumns )
01884                 {
01885                     // We need more columns
01886                     maxColumns += 4;
01887                     columnLefts.resize( maxColumns+1, QGArray::SpeedOptim );
01888                 }
01889                 columnLefts[col] = width + columnLefts[col-1];
01890                 kdDebug(32004) << "Cell column " << col-1 << " left " << columnLefts[col-1] << " right " << columnLefts[col] << endl;
01891             }
01892             styleStack.restore();
01893         }
01894     }
01895 
01896     uint row = 0;
01897     uint column = 0;
01898     parseInsideOfTable( tableTag, context, columnLefts, row, column, 0 );
01899 }
01900 
01901 void KWTableFrameSet::parseInsideOfTable( const QDomElement& parent, KoOasisContext& context,
01902                                           const QMemArray<double> & columnLefts, uint& row, uint& column,
01903                                           double currentRowHeight )
01904 {
01905     kdDebug(32004) << "parseInsideOfTable" << endl;
01906     KoStyleStack& styleStack = context.styleStack();
01907 
01908     QDomElement e;
01909     forEachElement( e, parent )
01910     {
01911         const QString localName = e.localName();
01912         const QString ns = e.namespaceURI();
01913         if ( ns != KoXmlNS::table ) {
01914             kdWarning(32004) << "Skipping element " << e.tagName() << " (in parseInsideOfTable)" << endl;
01915             continue;
01916         }
01917 
01918         styleStack.save();
01919         if ( localName == "table-cell" )
01920         {
01921             loadOasisCell( e, context, columnLefts, row, column, currentRowHeight );
01922             ++column;
01923         }
01924         else if ( localName == "covered-table-cell" )
01925         {
01926             ++column;
01927         }
01928         else if ( localName == "table-row" )
01929         {
01930             context.fillStyleStack( e, KoXmlNS::table, "style-name", "table-row" );
01931             context.styleStack().setTypeProperties( "table-row" );
01932 
01933             // Load row height in case it was set - note that it might not be set (e.g. OOo)
01934             double rowHeight = styleStack.attributeNS( KoXmlNS::table, "row-height" ).toDouble();
01935             column = 0;
01936             parseInsideOfTable( e, context, columnLefts, row, column, rowHeight );
01937             ++row;
01938         }
01939         else if ( localName == "table-header-rows" ) // ###TODO
01940         {
01941             // TODO: do we need to fillStyleStack?
01942             parseInsideOfTable( e, context, columnLefts, row, column, currentRowHeight );
01943         }
01944         else if ( localName == "table-column" )
01945         {
01946             // Already treated in loadOasis, we do not need to do anything here!
01947         }
01948         // TODO sub-table [ add to stack and expand at end of table loading ]
01949         else
01950         {
01951             kdWarning(32004) << "Skipping element " << localName << " (in parseInsideOfTable)" << endl;
01952         }
01953 
01954         styleStack.restore();
01955     }
01956 }
01957 
01958 void KWTableFrameSet::loadOasisCell( const QDomElement& element, KoOasisContext& context,
01959                                      const QMemArray<double> & columnLefts, uint row, uint column,
01960                                      double currentRowHeight )
01961 {
01962     //kdDebug(32004) << k_funcinfo << element.localName() << " " << row << "," << column << endl;
01963 
01964     KoStyleStack& styleStack = context.styleStack();
01965     uint rowSpan = element.attributeNS( KoXmlNS::table, "number-rows-spanned", QString::null ).toUInt();
01966     if ( rowSpan == 0 )
01967         rowSpan = 1;
01968     uint colSpan = element.attributeNS( KoXmlNS::table, "number-columns-spanned", QString::null ).toUInt();
01969     if ( colSpan == 0 )
01970         colSpan = 1;
01971 
01972     // m_rowPositions / m_colPositions could be QMemArrays, or QValueVectors...
01973     while(m_rowPositions.count() <= row + rowSpan + m_pageBoundaries.count()) {
01974         m_rowPositions.append(0);
01975     }
01976     while(m_colPositions.count() <= column + colSpan) {
01977         m_colPositions.append(0);
01978     }
01979 
01980     Cell *daCell = new Cell( this, row, column, QString::null /*unused*/ );
01981 
01982     daCell->setRowSpan( rowSpan );
01983     daCell->setColumnSpan( colSpan );
01984     addCell( daCell ); // rowSpan/colSpan have changed -> update array
01985 
01986     double width = columnLefts[ QMIN( column+colSpan, columnLefts.size()-1 ) ] - columnLefts[column];
01987     double height = currentRowHeight > 0 ? currentRowHeight : 20;
01988     KWFrame* frame = new KWFrame( daCell, columnLefts[column], 0, width, height );
01989     if ( currentRowHeight > 0 )
01990         frame->setMinimumFrameHeight( height ); // ensure that text formatting won't resize it down
01991     frame->setRunAround( KWFrame::RA_NO );
01992     frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01993     frame->setNewFrameBehavior( KWFrame::NoFollowup );
01994     daCell->addFrame( frame, false );
01995 
01996     context.fillStyleStack( element, KoXmlNS::table, "style-name", "table-cell" );
01997     styleStack.setTypeProperties( "table-cell" );
01998 
01999     daCell->frame( 0 )->loadBorderProperties( styleStack );
02000 
02001     daCell->loadOasisContent( element, context );
02002     afterLoadingCell( daCell );
02003 }
02004 
02005 // Old XML
02006 QDomElement KWTableFrameSet::save( QDomElement &parentElem, bool saveFrames ) {
02007     // When saving to a file, we don't have anything specific to the frameset to save.
02008     // Save the cells only.
02009     for (TableIter cells(this) ; cells ; ++cells)
02010         cells->save(parentElem, saveFrames);
02011     return QDomElement(); // No englobing element for tables...
02012 }
02013 
02014 // Old XML
02015 QDomElement KWTableFrameSet::toXML( QDomElement &parentElem, bool saveFrames )
02016 {
02017     QDomElement framesetElem = parentElem.ownerDocument().createElement( "FRAMESET" );
02018     parentElem.appendChild( framesetElem );
02019     KWFrameSet::saveCommon( framesetElem, false ); // Save the frameset attributes
02020     // Save the cells
02021     save( framesetElem, saveFrames );
02022     return framesetElem;
02023 }
02024 
02025 // Old XML
02026 void KWTableFrameSet::fromXML( QDomElement &framesetElem, bool loadFrames, bool useNames )
02027 {
02028     KWFrameSet::load( framesetElem, false ); // Load the frameset attributes
02029     // Load the cells
02030     QDomElement cellElem = framesetElem.firstChild().toElement();
02031     for ( ; !cellElem.isNull() ; cellElem = cellElem.nextSibling().toElement() )
02032     {
02033         if ( cellElem.tagName() == "FRAMESET" )
02034             loadCell( cellElem, loadFrames, useNames );
02035     }
02036 }
02037 
02038 // Old XML
02039 KWTableFrameSet::Cell* KWTableFrameSet::loadCell( QDomElement &framesetElem, bool loadFrames, bool useNames )
02040 {
02041     int _row = KWDocument::getAttribute( framesetElem, "row", 0 );
02042     if(_row <0) _row =0;
02043     unsigned int row=_row;
02044     int _col = KWDocument::getAttribute( framesetElem, "col", 0 );
02045     if(_col <0) _col =0;
02046     int _rows = KWDocument::getAttribute( framesetElem, "rows", 1 );
02047     if(_rows <0) _rows = 1;
02048     int _cols = KWDocument::getAttribute( framesetElem, "cols", 1 );
02049     if(_cols <0) _cols = 1;
02050 
02051     // m_rowPositions / m_colPositions could be QMemArrays, or QValueVectors...
02052     while(m_rowPositions.count() <= static_cast<unsigned int>(row + _rows + m_pageBoundaries.count())) {
02053         m_rowPositions.append(0);
02054     }
02055     while(m_colPositions.count() <= static_cast<unsigned int>(_col + _cols)) {
02056         m_colPositions.append(0);
02057     }
02058 
02059     Cell *daCell = new Cell( this, row, _col, QString::null /*unused*/ );
02060     QString autoName = daCell->name();
02061     //kdDebug(32004) << "KWTableFrameSet::loadCell autoName=" << autoName << endl;
02062     daCell->load( framesetElem, loadFrames );
02063     daCell->setRowSpan(_rows);
02064     daCell->setColumnSpan(_cols);
02065     addCell( daCell ); // rowSpan/colSpan have changed -> update array
02066     afterLoadingCell( daCell );
02067     if ( !useNames )
02068         daCell->setName( autoName );
02069     return daCell;
02070 }
02071 
02072 // Shared between old xml and oasis
02073 void KWTableFrameSet::afterLoadingCell( Cell* daCell )
02074 {
02075     uint row = daCell->firstRow();
02076     uint col = daCell->firstColumn();
02077     uint rowSpan = daCell->rowSpan();
02078     uint colSpan = daCell->columnSpan();
02079     if(m_pageBoundaries.count() > 0) {
02080         unsigned int adjustment=0;
02081         QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
02082         while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row + adjustment) {
02083             adjustment++;
02084             pageBound++;
02085         }
02086         row+=adjustment;
02087     }
02088 
02089     kdDebug(32004) << "loading cell (" << row << "," << col << ")\n";
02090     if(daCell->frame(0)) {
02091         daCell->frame(0)->setMinimumFrameHeight(daCell->frame(0)->height()); // TODO run the formatter over the text here
02092         QValueList<double>::iterator tmp = m_colPositions.at(col);
02093         if(*tmp == 0) (*tmp) = daCell->frame(0)->left();
02094         else (*tmp) = (daCell->frame(0)->left() + *tmp) / 2;
02095 
02096         tmp = m_colPositions.at(col+colSpan);
02097         if(*tmp == 0) (*tmp) = daCell->frame(0)->right();
02098         else (*tmp) = (daCell->frame(0)->right() + *tmp) / 2;
02099 
02100         tmp = m_rowPositions.at(row);
02101         if(*tmp == 0)
02102             (*tmp) = daCell->frame(0)->top();
02103         else {
02104             if (static_cast<int>(*tmp/m_doc->pageLayout().ptHeight) < static_cast<int>(daCell->frame(0)->top()/m_doc->pageLayout().ptHeight)) {
02105                 kdDebug(32004) << "This cell is on a new page" << endl;
02106                 QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
02107                 while(pageBound != m_pageBoundaries.end() && (*pageBound) < row) ++pageBound;
02108                 if(*pageBound!=row) {
02109                     m_pageBoundaries.insert(pageBound,row++);
02110                     ++tmp;
02111                     m_rowPositions.insert(tmp,daCell->frame(0)->top());
02112                 }
02113             } else
02114                 (*tmp) = (daCell->frame(0)->top() + *tmp) / 2;
02115         }
02116 
02117         tmp = m_rowPositions.at( row + rowSpan );
02118         if(*tmp == 0)
02119             (*tmp) = daCell->frame(0)->bottom();
02120         else { // untested...
02121             if (static_cast<int>(*tmp/m_doc->pageLayout().ptHeight) > static_cast<int>(daCell->frame(0)->top()/m_doc->pageLayout().ptHeight)) {
02122                 kdDebug(32004) << "next cell is on a new page" << endl;
02123                 QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
02124                 while(pageBound != m_pageBoundaries.end() && (*pageBound) < row) ++pageBound;
02125                 if(*pageBound!=row) {
02126                     m_pageBoundaries.insert(pageBound,row++);
02127                     m_rowPositions.insert(tmp,daCell->frame(0)->bottom());
02128                 }
02129             } else
02130                 (*tmp) = (daCell->frame(0)->bottom() + *tmp) / 2;
02131         }
02132     }
02133 
02134     if ( m_rowPositions.count() != m_rows + 1 ) {
02135         kdDebug() << name() << " loadCell: m_rowPositions=" << m_rowPositions.count() << " m_rows= " << m_rows << endl;
02136     }
02137 }
02138 
02139 int KWTableFrameSet::paragraphs()
02140 {
02141     int paragraphs = 0;
02142     for (TableIter cells(this) ; cells ; ++cells)
02143         paragraphs += cells->paragraphs();
02144     return paragraphs;
02145 }
02146 
02147 int KWTableFrameSet::paragraphsSelected()
02148 {
02149     int paragraphs = 0;
02150     for (TableIter cells(this) ; cells ; ++cells)
02151         paragraphs += cells->paragraphsSelected();
02152     return paragraphs;
02153 }
02154 
02155 bool KWTableFrameSet::statistics( QProgressDialog *progress, ulong & charsWithSpace, ulong & charsWithoutSpace, ulong & words,
02156     ulong & sentences, ulong & syllables, ulong & lines, bool selected )
02157 {
02158     for (TableIter cells(this) ; cells ; ++cells)
02159         if( ! cells->statistics( progress, charsWithSpace, charsWithoutSpace, words, sentences, syllables, lines, selected ) )
02160         {
02161             return false;
02162         }
02163     return true;
02164 }
02165 
02166 void KWTableFrameSet::finalize( ) {
02167     kdDebug(32004) << "KWTableFrameSet::finalize" << endl;
02168 
02169     for (TableIter cells(this) ; cells ; ++cells)
02170     {
02171         position( cells );
02172         cells->finalize();
02173     }
02174 
02175     recalcCols(0, 0);
02176     recalcRows(0, 0);
02177     KWFrameSet::finalize();
02178 }
02179 
02180 void KWTableFrameSet::layout()
02181 {
02182     for (TableIter cells(this) ; cells ; ++cells)
02183         cells->layout();
02184 }
02185 
02186 void KWTableFrameSet::invalidate()
02187 {
02188     for (TableIter cells(this) ; cells ; ++cells)
02189         cells->invalidate();
02190 }
02191 
02192 void KWTableFrameSet::setVisible( bool v )
02193 {
02194     for (TableIter cells(this) ; cells ; ++cells)
02195         cells->setVisible( v );
02196 
02197     KWFrameSet::setVisible( v );
02198 }
02199 
02200 bool KWTableFrameSet::canRemovePage( int num ) {
02201     /*  This one is a lot simpler then the one it overrides, we simply don't have
02202         to check if the frame contains something, the simple existence of a frame
02203         is enough
02204     */
02205     QPtrListIterator<KWFrame> frameIt( frameIterator() );
02206     for ( ; frameIt.current(); ++frameIt ) {
02207         if ( frameIt.current()->pageNumber() == num ) {
02208             return false;
02209         }
02210     }
02211     return true;
02212 }
02213 
02214 void KWTableFrameSet::addTextFrameSets( QPtrList<KWTextFrameSet> & lst, bool onlyReadWrite )
02215 {
02216     for (TableIter cells(this) ; cells ; ++cells)
02217         if (!cells->textObject()->protectContent() || onlyReadWrite )
02218             lst.append(cells);
02219 }
02220 
02221 KWTextFrameSet* KWTableFrameSet::nextTextObject( KWFrameSet *obj )
02222 {
02223     bool found = false;
02224     KWTableFrameSet::Cell *tmp = dynamic_cast<KWTableFrameSet::Cell *>(obj);
02225 
02226     // make sure we have this cell
02227     if ( tmp ) {
02228         for(TableIter i(this); i; ++i) {
02229             if(i.current() == tmp) {
02230                 found = true;
02231                 break;
02232             }
02233         }
02234     }
02235 
02236     TableIter iter(this);
02237     if(found)
02238         iter.goToCell(tmp);
02239 
02240     for(; iter; ++iter) {
02241         KWTextFrameSet *newFrm = iter->nextTextObject( obj );
02242         if(newFrm && newFrm->textObject()->needSpellCheck())
02243             return newFrm;
02244     }
02245 
02246     return 0L;
02247 }
02248 
02249 void KWTableFrameSet::setZOrder()
02250 {
02251     for( TableIter cells(this) ; cells ; ++cells ) {
02252         cells->setZOrder();
02253     }
02254 
02255 }
02256 
02257 // TODO provide toPlainText() (reimplemented from KWFrameSet)
02258 
02259 QByteArray KWTableFrameSet::convertTableToText() // should be const, but TableIter doesn't allow it
02260 {
02261     KWOasisSaver oasisSaver( m_doc );
02262     for (TableIter cells(this); cells; ++cells)
02263     {
02264         cells->textObject()->saveOasisContent( oasisSaver.bodyWriter(), oasisSaver.savingContext() );
02265     }
02266     if ( !oasisSaver.finish() )
02267         return QByteArray();
02268     return oasisSaver.data();
02269 }
02270 
02271 #ifndef NDEBUG
02272 void KWTableFrameSet::printDebug( KWFrame * theFrame )
02273 {
02274     KWTableFrameSet::Cell *daCell = dynamic_cast<KWTableFrameSet::Cell *>( theFrame->frameSet() );
02275     Q_ASSERT( daCell );
02276     if ( daCell ) {
02277         kdDebug(32004) << " |  |- row :" << daCell->firstRow() << endl;
02278         kdDebug(32004) << " |  |- col :" << daCell->firstColumn() << endl;
02279         kdDebug(32004) << " |  |- rows:" << daCell->rowSpan() << endl;
02280         kdDebug(32004) << " |  +- cols:" << daCell->columnSpan() << endl;
02281     }
02282 }
02283 
02284 void KWTableFrameSet::printArrayDebug() {
02285     kdDebug(32004) << " |  Row/Cell arrays" << endl;
02286     Q_ASSERT( m_rows == m_rowArray.size() );
02287     for ( unsigned int row = 0; row < m_rows; ++row )  {
02288         QString str = QString( " | Row %1: " ).arg( row );
02289         for ( unsigned int col = 0; col < getColumns(); ++col )
02290             str += QString("| 0x%1 ").arg( (unsigned long)(*m_rowArray[row])[col], 0, 16 );
02291         kdDebug(32004) << str<< " |" << endl;
02292     }
02293 }
02294 
02295 void KWTableFrameSet::printDebug() {
02296     kdDebug(32004) << " |  Table size (" << m_rows << "x" << getColumns() << ")" << endl;
02297     kdDebug(32004) << " |  col  " << 0 << ": " << m_colPositions[0] << endl;
02298     for(unsigned int i=1;i<m_colPositions.count(); ++i)
02299         kdDebug(32004) << " |    |  " << i << ": " << m_colPositions[i] << endl;
02300     kdDebug(32004) << " |  row  " << 0 << ": " << m_rowPositions[0] << endl;
02301     for(unsigned int i=1;i<m_rowPositions.count(); ++i)
02302         kdDebug(32004) << " |    |  " << i << ": " << m_rowPositions[i] << endl;
02303 
02304     printArrayDebug();
02305     KWFrameSet::printDebug();
02306 }
02307 
02308 #endif
02309 
02310 // ===
02311 
02312 KWTableFrameSet::Cell::Cell( KWTableFrameSet *table, unsigned int row, unsigned int col, const QString &/*name*/ ) :
02313     KWTextFrameSet( table->m_doc,
02314                     // Generate frameset name from table_name+row+col
02315                     i18n("Hello dear translator :), 1 is the table name, 2 and 3 are row and column", "%1 Cell %2,%3")
02316                     .arg( table->name() ).arg(row).arg(col) )
02317 {
02318     m_row = row;
02319     m_col = col;
02320     m_rows = 1;
02321     m_cols = 1;
02322     m_isJoinedCell = false;
02323     setGroupManager( table );
02324     table->addCell( this );
02325 }
02326 
02327 KWTableFrameSet::Cell::Cell( KWTableFrameSet *table, const Cell &original ) :
02328     KWTextFrameSet( table->m_doc, original.m_name+'_' )
02329 {
02330     m_row = original.m_row;
02331     m_col = original.m_col;
02332     m_rows = original.m_rows;
02333     m_cols = original.m_cols;
02334     m_isJoinedCell = original.m_isJoinedCell;
02335     setGroupManager( table );
02336     table->addCell( this );
02337 }
02338 
02339 KWTableFrameSet::Cell::~Cell()
02340 {
02341 }
02342 
02343 bool KWTableFrameSet::Cell::isAboveOrLeftOf( unsigned row, unsigned col ) const
02344 {
02345     return ( m_row < row ) || ( ( m_row == row ) && ( m_col < col ) );
02346 }
02347 
02348 bool KWTableFrameSet::Cell::containsCell( unsigned row, unsigned col ) const
02349 {
02350     return ( m_row <= row &&
02351              m_col <= col &&
02352              rowAfter() > row &&
02353              columnAfter() > col );
02354 }
02355 
02356 void KWTableFrameSet::Cell::addFrame(KWFrame *_frame, bool recalc) {
02357     if(groupmanager())
02358         groupmanager()->addFrame(_frame, recalc);
02359     KWTextFrameSet::addFrame(_frame, recalc);
02360 }
02361 
02362 void KWTableFrameSet::Cell::frameDeleted( KWFrame* frm, bool recalc )
02363 {
02364     if(groupmanager())
02365         groupmanager()->deleteFrame( frm, false, recalc );
02366 }
02367 
02368 double KWTableFrameSet::Cell::leftBorder() {
02369     double b = frame(0)->leftBorder().width();
02370     if(b==0.0)
02371         return 0.0;
02372     if(m_col==0) // left most cell
02373         return b;
02374     return (b / 2);
02375 }
02376 
02377 double KWTableFrameSet::Cell::rightBorder() {
02378     double b=frame(0)->rightBorder().width();
02379     if(b==0.0)
02380         return 0.0;
02381     if(m_col+m_cols==m_groupmanager->getColumns()) // right most cell
02382         return b;
02383     return (b / 2);
02384 }
02385 
02386 double KWTableFrameSet::Cell::topBorder() {
02387     double b = frame(0)->topBorder().width();
02388     if(b==0.0)
02389         return 0.0;
02390     if(m_row==0) // top most cell
02391         return b;
02392     return (b / 2);
02393 }
02394 
02395 double KWTableFrameSet::Cell::bottomBorder() {
02396     double b = frame(0)->bottomBorder().width();
02397     if(b==0.0)
02398         return 0.0;
02399     if(rowAfter() == m_groupmanager->m_rows) // bottom most cell
02400         return b;
02401     return (b / 2);
02402 }
02403 
02404 void KWTableFrameSet::Cell::setLeftBorder(KoBorder newBorder) {
02405     KWFrame *f = frame(0);
02406     double diff = f->leftBorder().width() - newBorder.width();
02407     f->setLeftBorder(newBorder);
02408 
02409     if((diff > 0.01 || diff < -0.01) && m_col!=0) {
02410         diff = diff / 2; // if not outer edge only use halve
02411         m_groupmanager->cell(m_row, m_col-1)->setRightBorder(newBorder);
02412     }
02413     f->setLeft(f->left() - diff);
02414 }
02415 
02416 void KWTableFrameSet::Cell::setRightBorder(KoBorder newBorder) {
02417     KWFrame *f = frame(0);
02418     double diff = f->rightBorder().width() - newBorder.width();
02419     f->setRightBorder(newBorder);
02420 
02421     if((diff > 0.01 || diff < -0.01) && m_col+m_cols!=m_groupmanager->getColumns()) {
02422         diff = diff / 2; // if not outer edge only use halve
02423         m_groupmanager->cell(m_row, m_col+1)->setLeftBorder(newBorder);
02424     }
02425     f->setRight(f->right() + diff);
02426 }
02427 
02428 void KWTableFrameSet::Cell::setTopBorder(KoBorder newBorder) {
02429     KWFrame *f = frame(0);
02430     double diff = f->topBorder().width() - newBorder.width();
02431     f->setTopBorder(newBorder);
02432 
02433     if((diff > 0.01 || diff < -0.01) && m_row!=0) {
02434         diff = diff / 2; // if not outer edge only use halve
02435         m_groupmanager->cell(m_row-1, m_col)->setBottomBorder(newBorder);
02436     }
02437     f->setTop(f->top() - diff);
02438 }
02439 
02440 void KWTableFrameSet::Cell::setBottomBorder(KoBorder newBorder) {
02441     KWFrame *f = frame(0);
02442     double diff = f->bottomBorder().width() - newBorder.width();
02443     f->setBottomBorder(newBorder);
02444 
02445     if((diff > 0.01 || diff < -0.01) && rowAfter() != m_groupmanager->m_rows) {
02446         diff = diff / 2; // if not outer edge only use halve
02447         m_groupmanager->cell(m_row+1, m_col)->setTopBorder(newBorder);
02448     }
02449     f->setBottom(f->bottom() + diff);
02450 }
02451 
02452 void KWTableFrameSet::Cell::setZOrder()
02453 {
02454     QPtrListIterator<KWFrame> frameIt = frameIterator();
02455     for ( ; frameIt.current(); ++frameIt )
02456     {
02457         (*frameIt)->setZOrder( kWordDocument()->maxZOrder( (*frameIt)->pageNumber() ) + 1 );
02458     }
02459 }
02460 
02461 void KWTableFrameSet::Cell::drawContents( QPainter * painter, const QRect & crect,
02462         const QColorGroup & cg, bool onlyChanged, bool resetChanged,
02463         KWFrameSetEdit * edit, KWViewMode * viewMode, KWFrameViewManager *fvm )
02464 {
02465     bool printing = painter->device()->devType() == QInternal::Printer;
02466     bool drawPreviewLines = viewMode && viewMode->drawFrameBorders();
02467     QRect cellRect = crect;
02468     if(!printing && drawPreviewLines) {
02469         // Make sure the clipping is changed so the preview lines (frame borders) are not overwritten.
02470         QRect zoomedRect( m_doc->zoomRect(*frame(0)) );
02471         QRect innerFrameRect( viewMode->normalToView( zoomedRect ) );
02472         innerFrameRect.addCoords(1, 1, -1, -1); // move and shrink
02473         cellRect = innerFrameRect.intersect(crect);
02474     }
02475     KWTextFrameSet::drawContents(painter, cellRect, cg, onlyChanged, resetChanged, edit, viewMode, fvm);
02476 }
02477 
02478 KWTableFrameSetEdit::~KWTableFrameSetEdit()
02479 {
02480     if ( m_currentCell )
02481         m_currentCell->terminate();
02482     delete m_currentCell;
02483 }
02484 
02485 void KWTableFrameSetEdit::mousePressEvent( QMouseEvent * e, const QPoint & nPoint, const KoPoint & dPoint )
02486 {
02487     setCurrentCell( dPoint );
02488     if ( m_currentCell )
02489         m_currentCell->mousePressEvent( e, nPoint, dPoint );
02490 }
02491 
02492 void KWTableFrameSetEdit::setCurrentCell( const KoPoint & dPoint )
02493 {
02494     KWFrameSet *fs = tableFrameSet()->cellByPos( dPoint.x(), dPoint.y() );
02495     KWTextFrameSet *textframeSet = dynamic_cast<KWTextFrameSet *>(fs);
02496 
02497     if ( textframeSet&& textframeSet->protectContent() && !tableFrameSet()->kWordDocument()->cursorInProtectedArea())
02498         return;
02499 
02500     if ( fs && ( !m_currentCell || fs != m_currentCell->frameSet() ) )
02501         setCurrentCell( fs );
02502 }
02503 
02504 void KWTableFrameSetEdit::setCurrentCell( KWFrameSet * fs, bool eraseSelection )
02505 {
02506     bool oldProtectContent = false;
02507     KWTextFrameSet *textframeSet=0L;
02508     if ( m_currentCell )
02509         textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
02510     if ( textframeSet )
02511         oldProtectContent = textframeSet->protectContent();
02512 
02513     if ( m_currentCell )
02514     {
02515         m_currentCell->terminate(eraseSelection);
02516         delete m_currentCell;
02517     }
02518     m_currentCell = fs->createFrameSetEdit( m_canvas );
02519     textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
02520     if ( textframeSet )
02521     {
02522         if ( oldProtectContent != textframeSet->protectContent())
02523         {
02524             m_canvas->kWordDocument()->updateTextFrameSetEdit();
02525         }
02526     }
02527 
02528 
02529     m_currentFrame = fs->frame( 0 );
02530     KWTextFrameSetEdit *textframeSetEdit = dynamic_cast<KWTextFrameSetEdit *>(m_currentCell);
02531     if ( textframeSetEdit )
02532     {
02533         textframeSetEdit->ensureCursorVisible();
02534         //refresh koruler
02535         m_canvas->gui()->getView()->slotUpdateRuler();
02536     }
02537 }
02538 
02539 KWFrameSetEdit* KWTableFrameSetEdit::currentTextEdit()
02540 {
02541     return m_currentCell;
02542 }
02543 
02544 
02545 void KWTableFrameSetEdit::keyPressEvent( QKeyEvent * e )
02546 {
02547     // This method handles the up/left/down/right navigation keys in tables
02548     if ( !m_currentCell )
02549         return;
02550     KWTableFrameSet::Cell *cell = static_cast<KWTableFrameSet::Cell *>(m_currentCell->frameSet());
02551     KWTextFrameSet *textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
02552     bool moveToOtherCell = true;
02553     if(textframeSet)
02554     {
02555         // don't move to an adjacent cell when we are selecting text
02556         KoTextDocument * textdoc = textframeSet->textDocument();
02557         if(textdoc->hasSelection( KoTextDocument::Standard ))
02558             moveToOtherCell=false;
02559     }
02560     KWTableFrameSet::Cell *fs = 0L;
02561 
02562     bool tab=false; // No tab key pressed
02563     if(moveToOtherCell)
02564     {
02565         switch( e->key() ) {
02566             case QKeyEvent::Qt::Key_Up:
02567             {
02568                 if(!(static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor()->parag()->prev())
02569                 {
02570                     KWTableFrameSet* tableFrame=tableFrameSet();
02571                     int row = cell->firstRow() - 1;
02572                     int col = cell->firstColumn();
02573                     if (row < 0) {  // Wrap at top of table
02574                         col--; // Goes to column on the left
02575                         row = tableFrame->getRows() - 1;
02576                     }
02577                     if (col < 0) { // It was the first column
02578                         // Maybe exit the table instead?
02579                         col = tableFrame->getColumns() - 1;
02580                         row = tableFrame->getRows() - 1;
02581                     }
02582                     fs=tableFrame->cell(row,col);
02583                     // Not needed. cell gives us the right one already
02584                     //if (fs && fs->firstRow() != static_cast<unsigned int>(row)) { // Merged cell
02585                     //    fs=tableFrame->cell( row - fs->rowSpan() + 1, col );
02586                     //}
02587                 }
02588             }
02589             break;
02590             case QKeyEvent::Qt::Key_Down:
02591             {
02592                 if(!(static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor()->parag()->next())
02593                 {
02594                     KWTableFrameSet* tableFrame=tableFrameSet();
02595                     unsigned int row = cell->rowAfter();
02596                     unsigned int col = cell->firstColumn();
02597                     if(row >= tableFrame->getRows()) { // Wrap at bottom of table
02598                         row=0;
02599                         col++; // Go to next column
02600                     }
02601                     if(col >= tableFrame->getColumns()) { // It was the last one
02602                         // Maybe exit the table instead?
02603                         col=0;
02604                         row=0;
02605                     }
02606                     fs=tableFrame->cell(row,col);
02607                     Q_ASSERT( fs );
02608                     Q_ASSERT( fs->firstRow() == row ); // We can't end up in the middle of a merged cell here.
02609                 }
02610             }
02611             break;
02612             case QKeyEvent::Qt::Key_Backtab:
02613                 tab=true;
02614                 if (e->state() & QKeyEvent::ControlButton)
02615                     break; // Break if tab was pressed with Control (in *any* key combination)
02616                 // Do not break
02617             case QKeyEvent::Qt::Key_Left:
02618             {
02619                 KoTextCursor *cur = (static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor();
02620                 if ( tab || (!cur->parag()->prev()&&cur->index()==0) )
02621                 {
02622                     KWTableFrameSet* tableFrame=tableFrameSet();
02623                     int row=cell->firstRow();
02624                     int col=cell->firstColumn() - 1;
02625                     if(col < 0) { // Wrap at first column
02626                         col = (int)tableFrame->getColumns()-1;
02627                         row--; // Go up
02628                     }
02629                     if(row < 0) { // It was the first row
02630                         // Maybe exit the table instead?
02631                         col = (int)tableFrame->getColumns()-1;
02632                         row = (int)tableFrame->getRows()-1;
02633                     }
02634                     fs=tableFrame->cell(row,col);
02635                     // Not needed. cell gives us the right one already
02636                     //if(fs && (int)fs->m_col != col) { // Merged cell
02637                     //    fs=tableFrame->cell( row, col - fs->columnSpan() + 1 );
02638                     //}
02639                 }
02640             }
02641             break;
02642             case QKeyEvent::Qt::Key_Tab:
02643                 tab=true;
02644                 if (e->state() & QKeyEvent::ControlButton)
02645                     break; // Break if tab was pressed with Control (in *any* key combination)
02646                 // Do not break
02647             case QKeyEvent::Qt::Key_Right:
02648             {
02649                 KoTextCursor *cur = (static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor();
02650                 if( tab || (!cur->parag()->next()&&cur->index()==cur->parag()->string()->length()-1) )
02651                 {
02652                     KWTableFrameSet* tableFrame=tableFrameSet();
02653                     unsigned int row = cell->firstRow();
02654                     unsigned int col = cell->columnAfter();
02655                     if(col >= tableFrame->getColumns()) { // Wrap after last column
02656                         col = 0;
02657                         row++; // Go down one row
02658                     }
02659                     if(row >= tableFrame->getRows()) { // It was the last row
02660                         // Maybe exit the table instead?
02661                         col = 0;
02662                         row = 0;
02663                     }
02664                     fs=tableFrame->cell(row,col);
02665                     Q_ASSERT( fs );
02666                     Q_ASSERT( fs->firstRow() == row ); // We can't end up in the middle of a merged cell here.
02667                 }
02668             }
02669             break;
02670         }
02671     }
02672     if ( fs )
02673     {
02674         //don't switch to a protected cell protected when cursor in protected areas was disabled.
02675         if ( fs->textObject()->protectContent() && !tableFrameSet()->kWordDocument()->cursorInProtectedArea())
02676             return;
02677         setCurrentCell( fs );
02678     }
02679     else if ( textframeSet )
02680     {
02681         if ( !textframeSet->textObject()->protectContent() )
02682         {
02683             if (tab && (e->state() & QKeyEvent::ControlButton) )
02684             {
02685                 QKeyEvent event(QEvent::KeyPress, QKeyEvent::Qt::Key_Tab, 9, 0, QChar(9));
02686                 m_currentCell->keyPressEvent( &event );
02687             }
02688             else
02689                 m_currentCell->keyPressEvent( e );
02690         }
02691         else if(e->text().length() > 0)
02692             KMessageBox::information(0L, i18n("Read-only content cannot be changed. No modifications will be accepted."));
02693     }
02694 }
02695 
02696 void KWTableFrameSetEdit::keyReleaseEvent( QKeyEvent * e )
02697 {
02698     if ( m_currentCell )
02699         m_currentCell->keyReleaseEvent( e );
02700 }
02701 
02702 void KWTableFrameSetEdit::dragMoveEvent( QDragMoveEvent * e, const QPoint &n, const KoPoint &d )
02703 {
02704     kdDebug(32004)<<"m_currentCell :"<<m_currentCell<<endl;
02705     if ( m_currentCell )
02706     {
02707         KWFrameSet *fs = tableFrameSet()->cellByPos( d.x(), d.y() );
02708         kdDebug(32004)<<"fs :"<<fs <<endl;
02709         if(fs && fs != m_currentCell->frameSet())
02710             setCurrentCell(fs, false);
02711         if(m_currentCell)
02712             m_currentCell->dragMoveEvent( e, n, d );
02713     }
02714     else
02715     {
02716         setCurrentCell( d );
02717         kdDebug(32004)<<"after m_currentCell :"<<m_currentCell<<endl;
02718         if(m_currentCell)
02719             m_currentCell->dragMoveEvent( e, n, d );
02720     }
02721 }
02722 
02723 void KWTableFrameSet::Row::addCell( Cell *cell )
02724 {
02725     if ( m_cellArray.size() < cell->columnAfter())
02726         m_cellArray.resize( cell->columnAfter() );
02727     for ( uint col = cell->firstColumn() ; col < cell->columnAfter(); ++col )
02728         m_cellArray.insert( col, cell );
02729 }
02730 
02731 void KWTableFrameSet::Row::removeCell( Cell* cell )
02732 {
02733     for ( uint col = cell->firstColumn() ; col <  cell->columnAfter(); ++col )
02734         m_cellArray.remove( col );
02735 }
02736 
02737 template<>
02738 KWTableFrameSet::Cell*
02739 KWTableFrameSet::TableIterator<KWTableFrameSet::VISIT_CELL>::operator++()
02740 {
02741     if(!m_cell) return 0;
02742 
02743     Cell *ret = m_cell;
02744 
02745     do{
02746         // check for end of row first
02747         if(m_table->cell(m_row,m_col)->lastColumn() >= m_limit[RIGHT] ) {
02748             // now check for end of column
02749             if (m_row >= m_limit[LOW]){
02750                 // at end of traversal
02751                 m_cell = 0;
02752                 break;
02753             }
02754             else {
02755                 // goto first grid position in next row
02756                 m_row += 1;
02757                 m_col = m_limit[LEFT];
02758             }
02759         }
02760         else {
02761             // goto next cell in row
02762             m_col = m_table->cell(m_row, m_col)->columnAfter();
02763         }
02764 
02765         m_cell = m_table->cell(m_row,m_col);
02766     } while( m_cell && !m_cell->isFirstGridPosnFast(m_row,m_col) );
02767 
02768     return ret;
02769 }
02770 
02771 template<>
02772 KWTableFrameSet::Cell*
02773 KWTableFrameSet::TableIterator<KWTableFrameSet::VISIT_GRID>::operator++()
02774 {
02775     if(!m_cell) return 0;
02776 
02777     Cell *ret = m_cell;
02778     // check for end of row
02779     if(m_col == m_limit[RIGHT]) {
02780         if(m_row == m_limit[LOW]) { // end of traversal
02781             m_row = 0;
02782             m_col = 0;
02783             m_cell = 0;
02784         }
02785         else { // go to next row
02786             m_row += 1;
02787             m_col = m_limit[LEFT];
02788             m_cell = m_table->cell(m_row, m_col);
02789         }
02790     }
02791     else { // move to next cell in row
02792         m_col += 1;
02793         m_cell = m_table->cell(m_row, m_col);
02794     }
02795 
02796     return ret;
02797 }
02798 
02799 KWTableFrameSet::MarkedIterator::MarkedIterator(KWTableFrameSet *table) :
02800     GridIter(table)
02801 {
02802     // clear all the cell marks
02803     for(GridIter cell(table); cell; ++cell)
02804         cell->clearMark();
02805 
02806     if ( current() ) {
02807 //      kdDebug() << "MarkedIterator: visit: "
02808 //          << QString("| 0x%1 ").arg((unsigned long)current(), 0, 16) << endl;
02809         current()->setMark();
02810     }
02811 }
02812 
02813 KWTableFrameSet::Cell *
02814 KWTableFrameSet::MarkedIterator::operator++()
02815 {
02816     Cell *ret = GridIter::operator++();
02817 
02818     while ( current() && current()->marked() ) {
02819         GridIter::operator++();
02820     }
02821     if ( current() ) {
02822 //      kdDebug() << "MarkedIterator: visit: "
02823 //          << QString("| 0x%1 ").arg((unsigned long)current(), 0, 16) << endl;
02824         current()->setMark();
02825     }
02826     return ret;
02827 }
02828 
02829 template<>
02830 KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::TableIterator(KWTableFrameSet *table):
02831     m_table(table)
02832 {
02833     Q_ASSERT(m_table);
02834     set_limits(0, (int)m_table->getColumns() - 1, 0, (int)m_table->getRows() - 1);
02835 
02836     Cell *c = 0;
02837     for(uint i = m_limit[HIGH]; i <= m_limit[LOW]; ++i)
02838         for(uint j = m_limit[LEFT]; j <= m_limit[RIGHT]; ++j) {
02839 
02840             c = m_table->cell(i,j);
02841             if(c) c->clearMark();
02842         }
02843     toFirstCell();
02844 }
02845 
02846 template<>
02847 KWTableFrameSet::Cell*
02848 KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::operator++ ()
02849 {
02850 
02851     Cell *ret = m_cell;
02852     if(!ret) return 0;
02853 
02854     ret->setMark();
02855     m_cell = 0;
02856     uint i = m_row; uint j = m_col;
02857 
02858     for(; i <= m_limit[LOW]; ++i) {
02859 
02860         for(j = 0; j <= m_limit[RIGHT]; ++j) {
02861             m_cell = m_table->cell(i,j);
02862             if( m_cell && !m_cell->marked() ){
02863                 m_row = i; m_col = j;
02864                 goto out;
02865             }
02866             else if(i == m_limit[LOW] && j == m_limit[RIGHT]){
02867                 m_cell = 0;
02868                 goto out;
02869             }
02870         }
02871     }
02872 
02873     out:
02874     return ret;
02875 }
02876 
02877 template<>
02878 KWTableFrameSet::Cell*
02879 KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::toFirstCell ()
02880 {
02881     m_cell = 0;
02882     for(uint i = m_limit[HIGH]; i <= m_limit[LOW]; ++i)
02883         for(uint j = m_limit[LEFT]; j <= m_limit[RIGHT]; ++j) {
02884             m_cell = m_table->cell(i,j);
02885             if(m_cell) {
02886                 m_row = i; m_col = j;
02887                 goto out;
02888             }
02889         }
02890 
02891     out:
02892     return m_cell;
02893 }
02894 
02895 RemovedRow::RemovedRow() :
02896     m_row(0), m_index(0), m_rowHeight(0.0)
02897 {
02898 
02899 }
02900 
02901 RemovedRow::~RemovedRow()
02902 {
02903     // free cells as well ???
02904     delete m_row;
02905 }
02906 
02907 KWTableFrameSet::Row *RemovedRow::takeRow()
02908 {
02909     Q_ASSERT(m_row);
02910     KWTableFrameSet::Row *ret = m_row;
02911     m_row = 0;
02912     return ret;
02913 }
02914 
02915 RemovedColumn::RemovedColumn()
02916     : m_column(), m_removed(), m_index(0), m_width(0), m_initialized(false){ }
02917 
02918 
02919 #include "KWTableFrameSet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys