/*
    Copyright (C) 2001, S.R.Haque (srhaque@iee.org).
    This file is part of the KDE project
    Copyright (C) 2005 Thomas Zander <zander@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.

DESCRIPTION

    This file implements KWord tables.
*/

// ### TODO : multi page tables

#include "KWTableFrameSet.h"
#include "KWDocument.h"
#include "KWAnchor.h"
#include "KWCanvas.h"
#include "KWCommand.h"
#include "KWViewMode.h"
#include "KWView.h"
#include "KWordFrameSetIface.h"
#include "KWordTableFrameSetIface.h"
#include "KWFrameList.h"
#include "KWPageManager.h"
#include "KWPage.h"
#include "KWOasisSaver.h"

#include <KoOasisContext.h>
#include <KoXmlWriter.h>
#include <KoDom.h>
#include <KoXmlNS.h>
#include <KoTextObject.h> // for customItemChar !
#include <KoTextParag.h>

#include <kmessagebox.h>
#include <kdebug.h>
#include <klocale.h>
#include <dcopobject.h>
#include <qapplication.h>
#include <qpopupmenu.h>
#include <qclipboard.h>


KWTableFrameSet::KWTableFrameSet( KWDocument *doc, const QString & name ) :
    KWFrameSet( doc )
{
    m_rows = m_cols = m_nr_cells = 0;
    m_name = QString::null;
    m_active = true;
    m_frames.setAutoDelete(false);
    if ( name.isEmpty() )
        m_name = doc->generateFramesetName( i18n( "Table %1" ) );
    else
        m_name = name;
}

KWTableFrameSet::~KWTableFrameSet()
{
    m_doc = 0L;
}

KWordFrameSetIface* KWTableFrameSet::dcopObject()
{
    if ( !m_dcop )
    m_dcop = new KWordTableFrameSetIface( this );

    return m_dcop;
}


KWFrameSetEdit * KWTableFrameSet::createFrameSetEdit( KWCanvas * canvas )
{
    return new KWTableFrameSetEdit( this, canvas );
}

void KWTableFrameSet::updateFrames( int flags )
{
    for(TableIter c(this); c; ++c)
        c.current()->updateFrames( flags );
    if ( isFloating() )  {
        KWAnchor * anchor = findAnchor( 0 );
        if ( anchor )
             anchor->resize();
    }

    KWFrameSet::updateFrames( flags );
}

void KWTableFrameSet::moveFloatingFrame( int /*frameNum TODO */, const KoPoint &position )
{
    // TODO multi-page case

    double dx = position.x() - m_colPositions[0];
    double dy = position.y() - m_rowPositions[0];

    KWTableFrameSet::Cell *daCell = cell(0,0);
    Q_ASSERT(daCell);
    if (! daCell) return; //hack to work around https://bugs.kde.org/show_bug.cgi?id=67216
    int oldPageNumber = daCell->frame(0)->pageNumber();
    // TODO multi-page case

    moveBy( dx, dy );

    if ( dx || dy ) {
        updateFrames();
        cell(0,0)->frame(0)->frameStack()->updateAfterMove( oldPageNumber );
    }
}

KoSize KWTableFrameSet::floatingFrameSize( int /*frameNum*/ )
{
    return boundingRect().size();
}

KCommand * KWTableFrameSet::anchoredObjectCreateCommand( int /*frameNum*/ )
{
    return new KWCreateTableCommand( i18n("Create Table"), this );
}

KCommand * KWTableFrameSet::anchoredObjectDeleteCommand( int /*frameNum*/ )
{
    return new KWDeleteTableCommand( i18n("Delete Table"), this );
}

KWAnchor * KWTableFrameSet::createAnchor( KoTextDocument *txt, int frameNum )
{
    //kdDebug(32004) << "KWTableFrameSet::createAnchor" << endl;
    return new KWAnchor( txt, this, frameNum );
}

void KWTableFrameSet::createAnchors( KoTextParag * parag, int index, bool placeHolderExists /*= false */ /*only used when loading*/,
                                     bool repaint )
{
    //kdDebug(32004) << "KWTableFrameSet::createAnchors" << endl;
    // TODO make one rect per page, and create one anchor per page
    // Anchor this frame, after the previous one
    KWAnchor * anchor = createAnchor( m_anchorTextFs->textDocument(), 0 );
    if ( !placeHolderExists )
        parag->insert( index, KoTextObject::customItemChar() );
    parag->setCustomItem( index, anchor, 0 );
    kdDebug(32004) << "KWTableFrameSet::createAnchors setting anchor" << endl;
    parag->setChanged( true );
    if ( repaint )
        emit repaintChanged( m_anchorTextFs );
}

void KWTableFrameSet::deleteAnchors()
{
    KWAnchor * anchor = findAnchor( 0 );
    kdDebug(32004) << "KWTableFrameSet::deleteAnchors anchor=" << anchor << endl;
    deleteAnchor( anchor );
}


void KWTableFrameSet::addCell( Cell* daCell ) // called add but also used to 'update'
{
    m_rows = kMax( daCell->rowAfter(), m_rows );
    m_cols = kMax( daCell->columnAfter(), m_cols );

    if ( m_rowArray.size() < daCell->rowAfter() )
        m_rowArray.resize( daCell->rowAfter() );
    for ( uint row = daCell->firstRow() ;row < daCell->rowAfter(); ++row )
    {
        if ( !m_rowArray[ row ] )
            m_rowArray.insert( row, new Row );
        m_rowArray[ row ]->addCell( daCell );
    }
}

void KWTableFrameSet::removeCell( Cell* daCell )
{
    for ( uint row = daCell->firstRow() ; row < daCell->rowAfter(); ++row )
        m_rowArray[ row ]->removeCell( daCell );
}

void KWTableFrameSet::insertRowVector(uint index, Row *r)
{
    if(m_rowArray.size() < m_rowArray.count() + 1)
        m_rowArray.resize(m_rowArray.count() + 1);

    for(uint i = m_rowArray.count(); i > index; i--)
        m_rowArray.insert(i, m_rowArray[i-1]);

    m_rowArray.insert(index, r);
}

/*
 * Inserts a new (empty) element into each row vector.
 * Elements in a row vector after index are moved back.
 */
void KWTableFrameSet::insertEmptyColumn(uint index)
{
    for(uint i = 0; i < m_rowArray.count(); ++i) {
       Row *r = m_rowArray[i];
       if(r->m_cellArray.size() < m_cols + 1)
           r->m_cellArray.resize(m_cols + 1);
       for(int j = m_cols - 1; j >= (int)index; --j)
           r->m_cellArray.insert(j + 1, r->m_cellArray[j]);
       r->m_cellArray.insert(index,  0);
    }
}

KWTableFrameSet::Row*
KWTableFrameSet::removeRowVector(uint index)
{
    Q_ASSERT(index < m_rowArray.count() );
    Row *ret = m_rowArray.at(index);
    Row *r;
    for(uint i = index; i < m_rowArray.size() - 1; ++i){
        r = m_rowArray.at(i+1);
        m_rowArray.remove(i+1);
        m_rowArray.insert(i,r);
    }
    return ret;
}


KoRect KWTableFrameSet::boundingRect() {
    KoRect outerRect(m_colPositions[0],    // left
                     m_rowPositions[0],      // top
                     m_colPositions.last()-m_colPositions[0], // width
                     m_rowPositions.last()-m_rowPositions[0]);// height

    // Add 1 'pixel' (at current zoom level) like KWFrame::outerKoRect(),
    // to avoid that the bottom line disappears due to rounding problems
    // (i.e. that it doesn't fit in the calculated paragraph height in pixels,
    // which depends on the paragraph's Y position)
    // Better have one pixel too much (caret looks too big by one pixel)
    // than one missing (bottom line of cell not painted)
    outerRect.rRight() += m_doc->zoomItX( 1 ) / m_doc->zoomedResolutionX();
    outerRect.rBottom() += m_doc->zoomItY( 1 ) / m_doc->zoomedResolutionY();

    return outerRect;

}

double KWTableFrameSet::topWithoutBorder()
{
    double top = 0.0;
    for (uint i = 0; i < getColumns(); i++)
    {
        KWTableFrameSet::Cell *daCell = cell( 0, i );
        top = kMax( top, m_rowPositions[0] + daCell->topBorder() );
    }
    return top;
}


double KWTableFrameSet::leftWithoutBorder()
{
    double left = 0.0;
    for (uint i=0; i < getRows(); i++)
    {
        KWTableFrameSet::Cell *daCell = cell( i, 0 );
        left = kMax( left, m_colPositions[0] + daCell->leftBorder() );
    }
    return left;
}

/* returns the cell that occupies row, col. */
KWTableFrameSet::Cell *KWTableFrameSet::cell( unsigned int row, unsigned int col ) const
{
    if ( row < m_rowArray.size() && col < m_rowArray[row]->size() ) {
        Cell* cell = (*m_rowArray[row])[col];
        if ( cell )
            return cell;
    }
//    kdWarning() << name() << " cell " << row << "," << col << " => returning 0!" << kdBacktrace( 3 ) << endl;
//#ifndef NDEBUG
//    validate();
//    printArrayDebug();
//#endif
    return 0L;
}

KWTableFrameSet::Cell *KWTableFrameSet::cellByPos( double x, double y ) const
{
    KWFrame *f = frameAtPos(x,y);
    if(f) return static_cast<KWTableFrameSet::Cell *> (f->frameSet());
    return 0L;
}

void KWTableFrameSet::recalcCols(unsigned int col,unsigned int row) {
    if(col >= getColumns())
        col = getColumns()-1;
    if(row >= getRows())
        row = getRows()-1;
    Cell *activeCell = cell(row,col);
    Q_ASSERT( activeCell );
    if ( !activeCell )
        return;
    double difference = 0;

    if(activeCell->frame(0)->left() - activeCell->leftBorder() != m_colPositions[activeCell->firstColumn()]) {
        // left border moved.
        col = activeCell->firstRow();
        difference = 0-(activeCell->frame(0)->left() - activeCell->leftBorder() - m_colPositions[activeCell->firstColumn()]);
    }

    if(activeCell->frame(0)->right() - activeCell->rightBorder() !=
            m_colPositions[activeCell->lastColumn()]) { // right border moved

        col = activeCell->columnAfter();
        double difference2 = activeCell->frame(0)->right() + activeCell->rightBorder() - m_colPositions[activeCell->columnAfter()];

        double moved=difference2+difference;
        if(moved > -0.01 && moved < 0.01) { // we were simply moved.
                col=0;
                difference = difference2;
            } else if(difference2!=0)
                difference = difference2;
    }

    m_redrawFromCol=getColumns(); // possible reposition col starting with this one, done in recalcRows
    if(difference!=0) {
        double last=col==0?0:m_colPositions[col-1];
        for(unsigned int i=col; i < m_colPositions.count(); i++) {
            double &colPos = m_colPositions[i];
            colPos = colPos + difference;
            if(colPos-last < s_minFrameWidth) { // Never make it smaller then allowed!
                difference += s_minFrameWidth - colPos;
                colPos = s_minFrameWidth + last;
            }
            last=colPos;
        }
        m_redrawFromCol=col;
        if(col>0) m_redrawFromCol--;
        //if(activeCell) activeCell->frame(0)->setMinimumFrameHeight(0);
    }
    updateFrames();
    //kdDebug(32004) << "end KWTableFrameSet::recalcCols" << endl;
}


// Step through the whole table and recalculate the position and size
// of each cell.

void KWTableFrameSet::recalcRows(unsigned int col, unsigned int row) {
    kdDebug(32004) << name() << " KWTableFrameSet::recalcRows ("<< col <<"," << row << ")" << endl;
    //for(unsigned int i=0; i < m_rowPositions.count() ; i++) kdDebug(32004) << "row: " << i << " = " << m_rowPositions[i] << endl;

    Cell *activeCell = cell(row,col);
    Q_ASSERT( activeCell );
    if ( !activeCell ) // #122807
        return;
    double difference = 0;

    if(activeCell->frame(0)->height() != activeCell->frame(0)->minimumFrameHeight() &&
          activeCell->type() == FT_TEXT) {
        // when the amount of text changed and the frame has to be rescaled we are also called.
        // lets check the minimum size for all the cells in this row.

        // Take a square of table cells which depend on each others height. It is always the full
        // width of the table and the height is determined by joined cells, the minimum is one row.
        double minHeightOtherCols=0;    // The minimum height which the whole square of table cells can take
        double minHeightActiveRow=0;    // The minimum height our cell can get because of cells in his row
        double minHeightMyCol=0;        // The minimum height our column can get in the whole square
        unsigned int rowSpan = activeCell->rowSpan();
        unsigned int startRow = activeCell->firstRow();
        for (uint colCount = 0; colCount < getColumns(); ++colCount )
        {
            // for each column
            unsigned int rowCount=startRow;
            double thisColHeight=0;     // the total height of this column
            double thisColActiveRow=0;  // the total height of all cells in this col, completely in the
                                        // row of the activeCell
            do { // for each row (under startRow)
                Cell *thisCell=cell(rowCount,colCount);
                if ( !thisCell )
                    break; // ###
                if(thisCell->firstRow() < startRow) { // above -> set startRow and restart
                    rowSpan += startRow - thisCell->firstRow();
                    startRow = thisCell->firstRow();
                    break;
                }
                if(thisCell->rowAfter() > startRow + rowSpan) {
                    rowSpan = thisCell->rowAfter() - startRow;
                    break;
                }

                thisColHeight+=thisCell->frame(0)->minimumFrameHeight();
                thisColHeight+=thisCell->topBorder();
                thisColHeight+=thisCell->bottomBorder();

                if(thisCell->firstRow() >= activeCell->firstRow() && thisCell->rowAfter() <= activeCell->rowAfter())
                    thisColActiveRow+=thisCell->frame(0)->minimumFrameHeight();

                rowCount += thisCell->rowSpan();
            } while (rowCount < rowSpan+startRow);

            if(colCount >= activeCell->firstColumn() &&
                  colCount < activeCell->columnAfter() )
                minHeightMyCol = thisColHeight;
            else {
                minHeightOtherCols = kMax(minHeightOtherCols, thisColHeight);
                minHeightActiveRow = kMax(minHeightActiveRow, thisColActiveRow);
            }
        } // for each column

        bool bottomRow = (startRow+rowSpan == activeCell->rowAfter());
        if(!bottomRow) {
            Cell *bottomCell=cell(startRow+rowSpan-1, activeCell->firstColumn());
            bottomCell->frame(0)->setHeight(bottomCell->frame(0)->minimumFrameHeight() +
                    minHeightOtherCols - minHeightMyCol);
            // ### RECURSE ###
            recalcRows(bottomCell->firstColumn(), bottomCell->firstRow());
        }
        if(activeCell->frame(0)->minimumFrameHeight() > activeCell->frame(0)->height()) { // wants to grow
            activeCell->frame(0)->setHeight(activeCell->frame(0)->minimumFrameHeight());
            //kdDebug(32004) << activeCell->name() << " grew to its minheight: " << activeCell->frame(0)->minimumFrameHeight() << endl;
        } else { // wants to shrink
            double newHeight=kMax(activeCell->frame(0)->minimumFrameHeight(),minHeightActiveRow);
            if(bottomRow) // I'm a strech cell
                newHeight=kMax(newHeight, minHeightOtherCols - (minHeightMyCol - activeCell->frame(0)->minimumFrameHeight()));
            activeCell->frame(0)->setHeight(newHeight);
            //kdDebug(32004) << activeCell->name() << " shrunk to: " << newHeight << endl;
        }
    }

    if(activeCell->frame(0)->top() - activeCell->topBorder() != getPositionOfRow(activeCell->firstRow())) {
        // top moved.
        row = activeCell->firstRow();
        difference = 0 - (activeCell->frame(0)->top() - activeCell->topBorder() - getPositionOfRow(row));
    }


    if(activeCell->frame(0)->bottom() + activeCell->bottomBorder() !=
            getPositionOfRow(activeCell->rowAfter())) { // bottom moved

        row = activeCell->rowAfter();
        double difference2 = activeCell->frame(0)->bottom() + activeCell->bottomBorder() - getPositionOfRow(row);
        double moved=difference2+difference;
        if(moved > -0.01 && moved < 0.01) { // we were simply moved.
            row=0;
            difference = difference2;
        } else if( difference2!=0)
            difference = difference2;
    }

    unsigned int fromRow = m_rows; // possible reposition rows starting with this one, default to no repositioning
    unsigned int untilRow=0;     // possible reposition rows ending with this one
    if( QABS( difference ) > 1E-10 ) { // means "difference != 0.0"
        QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
        QValueList<double>::iterator j = m_rowPositions.begin();
        double last=0.0;
        int lineNumber=-1;
        while(j != m_rowPositions.end()) {
            lineNumber++;
            if(pageBound!=m_pageBoundaries.end()) {
                if((int)*pageBound == lineNumber) { // next page
                    if(lineNumber >= (int)row) { // then delete line j
                        QValueList<double>::iterator nextJ = j;
                        ++nextJ;
                        difference -= *(nextJ)-*(j);
                        kdDebug(32004) << "Deleting line with old pos: " << *j << endl;
                        j=m_rowPositions.remove(j);
                        j--;
                        QValueList<unsigned int>::iterator tmp = pageBound;
                        ++pageBound;
                        m_pageBoundaries.remove(tmp);
                        j++;
                        continue;
                    }
                    ++pageBound;
                    lineNumber--;
                }
            }
            if(lineNumber >= (int)row)  { // below changed row
                if(*(j)-last < s_minFrameHeight) // Never make it smaller then allowed!
                    difference += s_minFrameHeight - *(j) + last;
                last=*(j);
                kdDebug(32004) << "moving " << *(j) << " by " << difference << "; to " << (*j) + difference << endl;
                (*j) += difference; // move line.
            }
            j++;
        }
        fromRow=row;
        if(row>0) fromRow--;
    } else {
        row=0;
    }
#if 0
{ QValueList<unsigned int>::iterator pb = m_pageBoundaries.begin();
  unsigned int i=0;
  double last=0;
  do {
      double cur=m_rowPositions[i];
      if(pb!=m_pageBoundaries.end() && *(pb)==i) {
        kdDebug(32004) << "line: " << i << ": " << cur << " *" << (last>cur?" (ALERT)":"") << endl;
        ++pb;
      } else
        kdDebug(32004) << "line: " << i << ": " << cur << (last>cur?" (ALERT)":"") << endl;
      last=cur;
      i++;
  } while( i<m_rowPositions.count());
}
#endif
#if 0 // def SUPPORT_MULTI_PAGE_TABLES

    //double pageHeight = m_doc->ptPaperHeight() - m_doc->ptBottomBorder() - m_doc->ptTopBorder();
    unsigned int pageNumber=cell(0,0)->frame(0)->pageNumber() +1;
    unsigned int lineNumber=1;
    QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
    QValueList<double>::iterator j = m_rowPositions.begin();

    double diff=0.0;
    double pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
    // kdDebug(32004) << "pageBottom; " << pageBottom << endl;
    while(++j!=m_rowPositions.end()) { // stuff for multipage tables.
        if(pageBound!=m_pageBoundaries.end() && *pageBound == lineNumber ) {
            if(*j > pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder() ) { // next page marker exists, and is accurate...
                pageNumber++;
                pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
                // kdDebug(32004) << "pageBottom; " << pageBottom << endl;
                untilRow=kMax(untilRow, *pageBound);
                pageBound++;
            }
        }

//kdDebug() << "checking; " << lineNumber << ", " << (*j) << endl;
        if((*j) + diff > pageBottom) { // a row falls off the page.
//kdDebug(32004) << "row falls off of page"<< endl;
            untilRow = m_rows;
            bool hugeRow = false;
            unsigned int breakRow = lineNumber-1;
            // find out of no cells are spanning multiple rows meaning we have to break higher.
#if 0
    // ### TODO: I did not get a chance do debug this yet!  TZ.
            for(int i=0; i < getColumns() ; i++) {
                kdDebug() << "i: " << i<< endl;
                Cell *c= cell(breakRow, i);
                kdDebug() << "c: " << c->firstRow() << "," << c->m_col << " w: " << c->columnSpan() << ", h: " << c->rowSpan() << endl;
                if(c->firstRow() < breakRow) {
                    breakRow = c->firstRow();
                    i=-1;
                }
            }
            kdDebug() << "breakRow: " << breakRow<< endl;
            fromRow=kMin(fromRow, breakRow);
            if(breakRow < lineNumber+1) {
                for(unsigned int i=lineNumber+1; i > breakRow;i--)
                    kdDebug() << "j--";
                for(unsigned int i=lineNumber+1; i > breakRow;i--)
                    --j;
                lineNumber=breakRow+1;
            }

            // find out if the next row (the new one on the page) does not contain cells higher then page.
            for(unsigned int i=0; i < getColumns() ; i++) {
                if(cell(breakRow+1,i) && cell(breakRow+1,i)->frame(0)->height() > pageHeight)
                    hugeRow=true;
            }
            //if((*pageBound) != breakRow) { // I think that this has to be that way
                // voeg top in in rowPositions
#endif

            double topOfPage = m_doc->ptPaperHeight() * pageNumber + m_doc->ptTopBorder();

            QValueList<double>::iterator tmp = m_rowPositions.at(breakRow);
            diff += topOfPage - (*tmp); // diff between bottom of last row on page and top of new page
//kdDebug() << "diff += " <<  topOfPage  << " - " << (*tmp) << ". diff += " << topOfPage - (*tmp) <<" ="<< diff  << endl;
            lineNumber++;
            m_rowPositions.insert(j, topOfPage);

            // insert new pageBound. It points to last LINE on previous page
            pageBound = m_pageBoundaries.insert(pageBound, breakRow);
            //kdDebug(32004) << "inserting new pageBound: " << breakRow  << " at " << m_rowPositions[breakRow] << endl;
            pageBound++;
            if(!hugeRow) {
                // add header-rij toe. (en zet bool) TODO
                //j++;
                //lineNumber++;
                // m_hasTmpHeaders = true;
            }
            pageNumber++;
            pageBottom = pageNumber * m_doc->ptPaperHeight() - m_doc->ptBottomBorder();
            //kdDebug(32004) << " pageBottom: " << pageBottom << " pageNumber=" << pageNumber << endl;
            if((int)pageNumber > m_doc->numPages()) {
                int num = m_doc->appendPage();
                kdDebug(32004) << "Have appended page: " << num << " (one page mode!)" << endl;
                m_doc->afterInsertPage( num );
            }
        }
        //if(diff > 0)  kdDebug(32004) << "   adding " << diff << ", line " << lineNumber << " " << *(j) <<" -> " << *(j)+diff << endl;
        if(diff > 0)
            (*j) = (*j) + diff;
        lineNumber++;

#if 0 // def SUPPORT_MULTI_PAGE_TABLES
        // Note: produces much ouput!
        int i = 1; // DEBUG
        for ( QValueList<double>::iterator itDebug = m_rowPositions.begin(); itDebug != m_rowPositions.end(); ++itDebug, ++i )
        {
            kdDebug(32004) << "m_rowPosition[" << i << "]= " << (*itDebug) << endl;
        }
#endif

    }
#endif
#if 0
{ QValueList<unsigned int>::iterator pb = m_pageBoundaries.begin();
  unsigned int i=0;
  double last=0;
  do {
      double cur=m_rowPositions[i];
      if(pb!=m_pageBoundaries.end() && *(pb)==i) {
        kdDebug(32004) << "line: " << i << ": " << cur << " *" << (last>cur?" (ALERT)":"") << endl;
        ++pb;
      } else
        kdDebug(32004) << "line: " << i << ": " << cur << (last>cur?" (ALERT)":"") << endl;
      last=cur;
      i++;
  } while( i<m_rowPositions.count());
}
#endif
//for (unsigned int i=0; i < getRows(); kdDebug(32004)<<" pos of row["<<i<<"] = "<<getPositionOfRow(i)<<"/"<<getPositionOfRow(i,true)<<endl,i++);
    //kdDebug () << "Repositioning from row : " << fromRow << " until: " << untilRow << endl;
    //kdDebug () << "Repositioning from col > " << redrawFromCol << endl;
    // do positioning.
    //Cell *cell;
    //bool setMinFrameSize= activeCell->frame(0)->isSelected();

#if 0 // def SUPPORT_MULTI_PAGE_TABLES
    for(TableIter cell(this); cell; ++cell) {
        if((cell->rowAfter() > fromRow && cell->firstRow() < untilRow) || cell->columnAfter() > m_redrawFromCol)
            position(cell, (cell==activeCell && cell->frame(0)->isSelected()));
    }
    m_redrawFromCol = getColumns();

    // check if any rowPosition entries are unused

    //   first create a hash of all row entries
    QMap<unsigned int,int> rows;        // rownr, count
    unsigned int top=m_rowPositions.count() - m_pageBoundaries.count()-1;
    for(unsigned int i=0; i < top; rows[i++]=0);

    //   fill hash with data
    for(TableIter i(this); i; ++i) {
        rows[i->firstRow()] += 1;
    }
    //   check if some entries have stayed unused.
    unsigned int counter=top;
    int adjustment=m_pageBoundaries.count()-1;

    do {
        counter--;
        if(adjustment >= 0 && counter == m_pageBoundaries[adjustment])
            adjustment--;
        if(rows[counter]==0) {
            kdDebug() << k_funcinfo << "no rows at counter=" << counter << " -> erasing" << endl;
            m_rows--;
            m_rowPositions.erase(m_rowPositions.at(counter+(adjustment>0?adjustment:0)));
            for (TableIter cell(this); cell; ++cell) {
                if(cell->firstRow() < counter && cell->rowAfter() > counter)
                    cell->setRowSpan(cell->rowSpan()-1);
                if(cell->firstRow() > counter)
                    cell->setFirstRow(cell->firstRow()-1);
            }

            if(adjustment >= -1) {
                pageBound = m_pageBoundaries.at(adjustment+1);
                while(pageBound!=m_pageBoundaries.end()) {
                    (*pageBound)= (*pageBound)-1;
                    pageBound++;
                }
            }
        }
    } while(counter!=0);
#endif


    m_redrawFromCol = 0;
    for (TableIter cell(this); cell; ++cell) {
        if((cell->rowAfter() > fromRow && cell->firstRow() < untilRow)
           || cell->columnAfter() > m_redrawFromCol)
            position(cell);
    }
    m_redrawFromCol = getColumns();
    kdDebug(32004) << name() << " KWTableFrameSet::recalcRows done" << endl;
    updateFrames();
}

int KWTableFrameSet::columnEdgeAt( double x ) const
{
    // We compare x with the middle of columns (left+right/2),
    // to find which column x is closest to.
    // m_colPositions is sorted, so we can remember the last column we looked at.
    double lastMiddlePos = 0;
    for ( uint i = 0; i < m_colPositions.count() - 1; i++ ) {
        double middlePos = ( m_colPositions[i] + m_colPositions[i+1] ) / 2;
        Q_ASSERT( lastMiddlePos < middlePos );
        if ( x > lastMiddlePos && x <= middlePos )
            return i;
        lastMiddlePos = middlePos;
    }
    return m_colPositions.count() - 1;
}

int KWTableFrameSet::rowEdgeAt( double y ) const
{
    double lastMiddlePos = 0;
    for ( uint i = 0; i < m_rowPositions.count() - 1; i++ ) {
        double middlePos = ( m_rowPositions[i] + m_rowPositions[i+1] ) / 2;
        Q_ASSERT( lastMiddlePos < middlePos );
        if ( y > lastMiddlePos && y <= middlePos )
            return i;
        lastMiddlePos = middlePos;
    }
    return m_rowPositions.count() - 1;
}

double KWTableFrameSet::columnSize( unsigned int col )
{
  return m_colPositions[ col ];
}

double KWTableFrameSet::rowSize( unsigned int row )
{
  return m_rowPositions[ row ];
}

void KWTableFrameSet::resizeColumn( unsigned int col, double x )
{
    kdDebug() << k_funcinfo << col << "," << x << endl;
    if ((col != 0) && (x - m_colPositions[ col-1 ] < s_minFrameWidth))
      m_colPositions[ col ] = m_colPositions[ col-1 ] + s_minFrameWidth;
    else
      if ((col != getColumns()) && (m_colPositions[ col + 1 ] - x < s_minFrameWidth))
        m_colPositions[col] = m_colPositions[ col + 1 ] - s_minFrameWidth;
      else
        m_colPositions[ col ] = x;

    // move all cells right of 'col'
    for (TableIter cell(this); cell; ++cell) {
        if ( cell->columnAfter() >= col ) {
            position(cell);
        }
    }
    recalcCols( col-1, 0 );
}

void KWTableFrameSet::resizeRow( unsigned int row, double y )
{
    kdDebug() << k_funcinfo << row << "," << y << endl;
    double difference = m_rowPositions[row];
    if ((row != 0) && (y - m_rowPositions[ row-1 ] < s_minFrameHeight))
      m_rowPositions[ row ] = m_rowPositions[ row-1 ] + s_minFrameHeight;
    else
      if ((row != getRows()) && (m_rowPositions[ row + 1 ] - y < s_minFrameHeight))
        m_rowPositions[row] = m_rowPositions[ row + 1 ] - s_minFrameHeight;
      else
        m_rowPositions[ row ] = y;
    difference = m_rowPositions[row] - difference;

    //move all rows under 'row'
    if (row != 0)
       for (unsigned int i=row+1; i<= getRows(); i++)
           m_rowPositions[i] = m_rowPositions[i] + difference;

    // move all cells under 'row'
    for (TableIter cell(this); cell; ++cell) {
        if ( cell->rowAfter() >= row ) {
            position(cell);
        }
    }
    recalcRows( 0, row-1 );
}

void KWTableFrameSet::resizeWidth( double width ) {
    Q_ASSERT(width != 0);
    Q_ASSERT(boundingRect().width() != 0);
    kdDebug() << "bounding width before resize " << boundingRect().width() << endl;
    double growth = width / boundingRect().width();

    // since we move all the columns, we also move the 1st one,
    // depending where it is on the page.
    // just compensate by substracting that offset.
    double moveOffset = m_colPositions[0] * growth - m_colPositions[0];

    for (uint i=0; i<m_colPositions.count(); i++) {
        m_colPositions[i] = m_colPositions[i] * growth - moveOffset;
    }
    finalize();
    kdDebug() << "bounding width after resize" << boundingRect().width() << endl;
    Q_ASSERT(boundingRect().width() - width < 0.01);
}

void KWTableFrameSet::setBoundingRect( KoRect rect, CellSize widthMode, CellSize heightMode ) {
   // Column positions..
    m_colPositions.clear();
    unsigned int cols=0;
    for (TableIter c(this); c; ++c)
        cols = kMax(cols, c.current()->columnAfter());
    double colWidth = rect.width() / cols;
    if ( widthMode == TblAuto ) {
        KWPage *page = pageManager()->page(rect);
        rect.setLeft( page->leftMargin() );
        colWidth = (page->width() - page->leftMargin() - page->rightMargin()) / cols;
    }

    for(unsigned int i=0; i <= cols;i++) {
        m_colPositions.append(rect.x() + colWidth * i);
    }

    // Row positions..
    m_rowPositions.clear();
    m_pageBoundaries.clear();
    double rowHeight = 0;
    if( heightMode != TblAuto )
        rowHeight = rect.height() / m_rows;
    rowHeight=kMax(rowHeight, 22.0); // m_doc->getDefaultParagLayout()->getFormat().ptFontSize()) // TODO use table style font-size

    for(unsigned int i=0; i <= m_rows;i++) {
        m_rowPositions.append(rect.y() + rowHeight * i);
    }

    double oneMm = MM_TO_POINT( 1.0 );
    for (TableIter cell(this); cell; ++cell) {
        KWFrame *frame = cell->frame(0);
        frame->setPaddingLeft( oneMm );
        frame->setPaddingRight( oneMm );
        frame->setPaddingTop( oneMm );
        frame->setPaddingBottom( oneMm );
        frame->setNewFrameBehavior( KWFrame::NoFollowup );
        position(cell, true);
    }
}

void KWTableFrameSet::position( Cell *theCell, bool setMinFrameHeight ) {
    if(!theCell->frame(0)) { // sanity check.
        kdDebug(32004) << "errorous table cell!! row:" << theCell->firstRow()
            << ", col: " << theCell->firstColumn() << endl;
        return;
    }
    double x = *m_colPositions.at(theCell->firstColumn());
    double y = getPositionOfRow(theCell->firstRow());
    double width = (*m_colPositions.at(theCell->columnAfter())) - x;
    double height  = getPositionOfRow(theCell->lastRow(), true) - y;

#if 0
    if(theCell->m_col==0) {
        kdDebug(32004) << "row "  << theCell->firstRow() << " has top: "
            << y << ", and bottom: " << y + height << endl;
    }
#endif

    // Now take the border sizes and make the cell smaller so it still fits inside the grid.
    KWFrame *theFrame = theCell->frame(0);
    x+=theCell->leftBorder();
    width-=theCell->leftBorder();
    width-=theCell->rightBorder();
    y+=theCell->topBorder();
    height-=theCell->topBorder();
    height-=theCell->bottomBorder();

    theFrame->setRect( x,y,width,height);
    if( setMinFrameHeight )
        theFrame->setMinimumFrameHeight(height);

    if(!theCell->isVisible())
        theCell->setVisible(true);
}

double KWTableFrameSet::getPositionOfRow( unsigned int row, bool bottom ) {
    unsigned int adjustment=0;
    QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
    while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row + adjustment) {
        adjustment++;
        pageBound++;
    }
    if(m_rowPositions.count() < row+adjustment+(bottom?1:0))  // Requested row does not exist.
        return 0;
    return m_rowPositions[row+adjustment+(bottom?1:0)];
}

void KWTableFrameSet::moveBy( double dx, double dy ) {
    bool redraw=false;
    kdDebug(32004) << "KWTableFrameSet(" << name() << ")::moveBy(" << dx<<","<<dy<<")\n";
    //for(unsigned int i=0; i < m_rowPositions.count() ; kdDebug(32004) << "row " << i << ": " << m_rowPositions[i++] << endl);
    if(!(dy > -0.001 && dy < 0.001)) {
        redraw=true;
        QValueList<double>::iterator row = m_rowPositions.begin();
        while(row != m_rowPositions.end()) {
            (*row)= (*row)+dy;
            row++;
        }
    }
    if(!(dx > -0.001 && dx < 0.001)) {
        redraw=true;
        QValueList<double>::iterator col = m_colPositions.begin();
        while(col != m_colPositions.end()) {
            (*col)= (*col)+dx;
            col++;
        }
    }

    if(redraw) {
        for(TableIter cell(this);cell;++cell)
            position(cell);
    }
}

/* Delete all cells that are completely in this row.              */
void KWTableFrameSet::deleteRow( unsigned int row, RemovedRow &rr, bool _recalc)
{
    Q_ASSERT(row < m_rowArray.size());
    const unsigned int rowspan=1;

    double height= getPositionOfRow(row+rowspan-1,true) - getPositionOfRow(row);
    QValueList<double>::iterator tmp = m_rowPositions.at(row+rowspan);
    tmp=m_rowPositions.erase(tmp);
    while(tmp!=m_rowPositions.end()) {
        (*tmp)= (*tmp)-height;
        tmp++;
    }

    rr.m_index = row;
    rr.m_rowHeight = height;
    rr.m_row = m_rowArray[row];

    // move/delete cells.
    for ( TableIter cell(this); cell; ++cell ) {
        if ( row >= cell->firstRow() && row < cell->rowAfter()) { // cell is indeed in row
            if(cell->rowSpan() == 1) { // cell is wholly contained within row
                m_frames.remove( cell->frame(0) );
            } else { // make cell span rowspan less rows
                cell->setRowSpan(cell->rowSpan()-rowspan);
                position(cell);
            }

        } else if ( cell->firstRow() > row ) {
            // move cell up
            cell->setFirstRow( cell->firstRow() - rowspan );
            position(cell);
        }
    }

    removeRowVector(row);
    m_rows -= rowspan;
    m_rowArray.resize( m_rows );
    validate();

    if ( _recalc )
        recalcRows( 0, row-1 );
}

void KWTableFrameSet::reInsertRow(RemovedRow &rr)
{
   uint row = rr.index();
   Row *r =  rr.row();
   uint rlen = r->count();

   // adjust cell positions & sizes
   for(MarkedIterator cell(this); cell; ++cell) {

        if ( cell->firstRow() < row && cell->lastRow() >= row ){ // cell is indeed in row
                cell->setRowSpan(cell->rowSpan() + 1);
        }
        else if(r->m_cellArray[cell->firstColumn()] == cell.current()) {
                cell->setRowSpan(cell->rowSpan() + 1);
        }
        else if ( cell->firstRow() >= row ) {
            // move cell down
            cell->setFirstRow( cell->firstRow() + 1);
        }
   }

   // put back m_frames that were removed
   for(uint i = 0; i < rlen; i++){
       if( m_frames.findRef((*r)[i]->frame(0)) == -1 )
        m_frames.append( (*r)[i]->frame(0) );
   }

   // adjust row positions (ignores page boundaries!)a
   if(row == m_rows) {  //reinserting at bottom of table
       double d = m_rowPositions.last() + rr.height();
       m_rowPositions.append(d);
   }
   else {
       QValueList<double>::iterator top = m_rowPositions.at(row);
       QValueList<double>::iterator i = m_rowPositions.at(row+1);
       i = m_rowPositions.insert(i, *top + rr.height());
       i++;
       for(; i != m_rowPositions.end(); ++i) {
           *i = *i+ rr.height();
       }
   }

   // reinsert row into array
   m_rows++;
   insertRowVector(rr.index(), rr.takeRow());

   // don't actually have to visit all the cells, this could be optimised
   for(TableIter i(this); i ; ++i)
      position(i.current());

   validate();
}

void KWTableFrameSet::insertNewRow( uint idx, bool recalc, bool _removeable)
{

    (void) _removeable; // unused parameter
    unsigned int copyFromRow = idx==0?0:idx-1;
    if(idx==0)
        copyFromRow=1;
    Row *copyRow = m_rowArray[copyFromRow];

    uint new_rows = m_rows + 1;
    // What height to use for the new row
    double height = getPositionOfRow(copyFromRow,true) - getPositionOfRow(copyFromRow);

    // Calculate offset in QValueList because of page breaks.
    unsigned int adjustment=0;
    unsigned int untilRow=m_rows;
    QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
    while(pageBound != m_pageBoundaries.end() && (*pageBound) <= idx) {
        // Find out how many pages we already had.
        adjustment++;
        pageBound++;
    }

    // Move all rows down from newRow to bottom of page
    QValueList<double>::iterator tmp = m_rowPositions.at(idx);
    double newPos = *tmp + height;
    tmp++;
    m_rowPositions.insert(tmp, newPos);
    for(unsigned int i=idx+adjustment+2; i < m_rowPositions.count(); i++) {
        double &rowPos = m_rowPositions[i];
        kdDebug(32004) << "adjusting " << rowPos << " -> " << rowPos + height << endl;
        rowPos = rowPos + height;
        if(*pageBound == i) {
            untilRow= *pageBound;
            break;              // stop at pageBreak.
        }
    }

    for ( MarkedIterator cells(this); cells; ++cells) {
        if ( cells->firstRow() >= idx ) { // move all cells beneath the new row.
            cells->setFirstRow(cells->firstRow()+1);
        }
    }

    insertRowVector(idx, new Row);

    unsigned int i = 0;
    while(i < getColumns()) {

        if(idx != 0 && (idx != m_rows)) {
            Cell *c = cell(idx - 1, i);
            if( c == cell(idx + 1, i) ) {
                m_rowArray[idx]->addCell(c);
                c->setRowSpan(c->rowSpan() + 1);
                i += c->columnSpan();
                continue; // don't need to make a new cell
            }
        }

        KWFrame *theFrame = new KWFrame(copyRow->m_cellArray[i]->frame(0));
        Cell *newCell=new Cell( this, idx, i, QString::null );
        newCell->setColumnSpan( cell(copyFromRow,i)->columnSpan() );
        addCell(newCell);
        newCell->addFrame( theFrame, false );
        position(newCell);
        i += newCell->columnSpan();
   }

    // Position all changed cells.

    m_rows = new_rows;
    validate();
    if ( recalc )
        finalize();
}

void KWTableFrameSet::deleteColumn(uint col, RemovedColumn &rc)
{
    // keep these values in case we have to put it back
    if(!rc.m_initialized) {
        rc.m_index = col;
        rc.m_width = m_colPositions[col+1] - m_colPositions[col];
    }

    // move the colomn positions
    QValueList<double>::iterator tmp = m_colPositions.at(col+1);
    tmp = m_colPositions.erase(tmp);
    while(tmp != m_colPositions.end()) {
        (*tmp) = (*tmp) - rc.m_width;
        tmp++;
    }

    // remove cells that are wholy in this column,
    // otherwise reduce rowspan. pointers to all cells
    // are kept in the RemovedColumn
    CheckedIter iter(this);
    for(uint i = 0; i < m_rows; ++i) {
        Cell *daCell = cell(i, col);

        if(!rc.m_initialized) {
            rc.m_column.append(daCell);
            rc.m_removed.append(daCell->columnSpan() == 1);
        }

        if(daCell->columnSpan() == 1) { // lets remove it
            if(daCell->firstRow() == i) {
                m_frames.remove( daCell->frame(0) );
                m_nr_cells--;
            }
            m_rowArray[i]->m_cellArray.insert(col, 0);
        }
        else {                    // make cell span 1 less column
            if(daCell->firstRow() == i) {
                daCell->setColumnSpan( daCell->columnSpan() - 1 );
                position(daCell);
            }
        }
    }

    // adjust cells in a later column
    for(; iter; ++iter) {
        if (iter->firstColumn() > col ) {
            iter->setFirstColumn( iter->firstColumn() - 1);
            position(iter.current());
        }
    }

    // move pointers in 2d array back one column to occupy
    // removed column
    for(uint i = 0; i < m_rows; i++) {
        for(uint j = col + 1; j < m_cols; j++)
             m_rowArray[i]->m_cellArray.insert(j-1, m_rowArray[i]->m_cellArray[j]);
    }
    m_cols--;
    rc.m_initialized = true;

    validate();
    recalcCols( col, 0 );
    recalcRows( col, 0 );
}

void KWTableFrameSet::reInsertColumn(RemovedColumn &rc)
{
    QValueList<double>::iterator tmp = m_colPositions.at(rc.m_index);

    tmp = m_colPositions.insert(tmp, *tmp);
    tmp++;
    while(tmp != m_colPositions.end()) {
        (*tmp) = (*tmp) + rc.m_width;
        tmp++;
    }

    // if a cell starts after the column we are inserting, it
    // must be moved to the right, except if it is going to
    // occury the reinserted column also.
    for ( MarkedIterator cells(this); cells ; ++cells ) {
        if ( cells->firstColumn() >= rc.m_index &&
            (rc.m_column.at(cells->firstRow()) != cells.current())) {

            cells->setFirstColumn(cells->firstColumn() + 1);
        }
    }
    insertEmptyColumn(rc.m_index);
    m_cols++;

    for(uint i = 0; i < m_rows; ++i) {
        bool removed = rc.m_removed[i];
        Cell *daCell = rc.m_column.at(i);
        if(i == daCell->firstRow()) {
            if(removed) {
                daCell->setColumnSpan(1);
                m_frames.append(daCell->frame(0));
                m_nr_cells++;
            }
            else  {
               daCell->setColumnSpan(daCell->columnSpan() + 1);
            }
            addCell(daCell);
        }
    }

    validate();
    finalize();
}

void KWTableFrameSet::insertNewColumn( uint idx, double width)
{
    QValueList<double>::iterator tmp = m_colPositions.at(idx);

    tmp = m_colPositions.insert(tmp, *tmp);
    tmp++;
    while(tmp!=m_colPositions.end()) {
        (*tmp)= (*tmp)+width;
        tmp++;
    }

    for ( MarkedIterator cells(this); cells ; ++cells ) {
        if ( cells->firstColumn() >= idx) { // move all cells right of the new col.
            cells->setFirstColumn(cells->firstColumn() + 1);
        }
    }
    insertEmptyColumn(idx);
    m_cols++;
    uint copyCol = (idx == 0) ? 1 : idx - 1 ;

    // make the new cells
    // note that the loop counter is mucked with in the loop!
    for( unsigned int i = 0; i < getRows(); i++ ) {

        // can't break a cell in half, so if there is the same cell
        // on both sides of inserted column, it occupies the new
        // column as well
        if(idx != 0 && (idx != m_cols -1)) {
            Cell *c = cell(i, idx - 1);
            if( c == cell(i, idx + 1) ) {
//                m_rowArray[i]->m_cellArray.insert(idx, c);
                c->setColumnSpan(c->columnSpan() + 1);
                addCell(c);
                i += c->rowSpan() - 1;
                continue; // don't need to make a new cell
            }
        }

        Cell *newCell = new Cell( this, i, idx, QString::null );
        KWFrame *theFrame = new KWFrame(cell(i, copyCol)->frame(0));
        newCell->addFrame( theFrame, false );
        position(newCell);
        m_nr_cells++;
    }
    validate();
    finalize();
}

void KWTableFrameSet::ungroup()
{
//    m_cells.setAutoDelete( false );
//    m_cells.clear();
    m_nr_cells = 0;

    m_active = false;
}

void KWTableFrameSet::group()
{
//   m_cells.setAutoDelete( true );
//   m_cells.clear();

   m_nr_cells = 0;
   m_active = true;
}

KCommand *KWTableFrameSet::joinCells(unsigned int colBegin,unsigned int rowBegin, unsigned int colEnd,unsigned int rowEnd) {
    Cell *firstCell = cell(rowBegin, colBegin);
    // if just one cell selected for joining; exit.
    if(rowBegin == rowEnd && colBegin == colEnd || cell(rowBegin,colBegin) == cell(rowEnd,colEnd))
        return 0L;
    QPtrList<KWFrameSet> listFrameSet;
    QPtrList<KWFrame> listCopyFrame;

    // do the actual merge.
    for(unsigned int i=colBegin; i<=colEnd;i++) {
        for(unsigned int j=rowBegin; j<=rowEnd;j++) {
            Cell *daCell = cell(j,i);
            if(daCell && daCell!=firstCell) {
                listFrameSet.append(daCell);
                KWFrame* frame = daCell->frame(0);
                Q_ASSERT(frame);
                if(! frame) continue; // see bug #132642
                listCopyFrame.append(frame->getCopy());
                daCell->deleteFrame(frame);
            }
        }
    }

    Q_ASSERT(firstCell);
    // update firstcell properties to reflect the merge
    firstCell->setColumnSpan(colEnd-colBegin+1);
    firstCell->setRowSpan(rowEnd-rowBegin+1);
    addCell(firstCell);
    position(firstCell);
    validate();

    m_doc->updateAllFrames(); // TODO: only fs->updateFrames() & m_doc->updateFramesOnTopOrBelow(pageNum)
    m_doc->repaintAllViews();
    return new KWJoinCellCommand( i18n("Join Cells"), this,colBegin,rowBegin, colEnd,rowEnd,listFrameSet,listCopyFrame);
}

KCommand *KWTableFrameSet::splitCell(unsigned int intoRows, unsigned int intoCols, unsigned int col, unsigned int row, QPtrList<KWFrameSet> listFrameSet, QPtrList<KWFrame>listFrame) {
    if(intoRows < 1 || intoCols < 1)
        return 0L;

    kdDebug(32004) << "KWTableFrameSet::splitCell" << endl;
    Cell *daCell=cell(row,col);
    int rowsDiff = intoRows - daCell->rowSpan();
    int colsDiff = ((int) intoCols) - daCell->columnSpan();

    if(rowsDiff >0) {
        unsigned int adjustment=0;
        QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
        while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row) {
            adjustment++;
            pageBound++;
        }
        double height = (m_rowPositions[row+adjustment+1] - m_rowPositions[row+adjustment])/intoRows;

        QValueList<double>::iterator iRow = m_rowPositions.at(adjustment+row);
        for (int i=0; i < rowsDiff; i++) {
            double newPos = *iRow + height;
            iRow++;
            iRow=m_rowPositions.insert(iRow, newPos);
        }

        // insert more rows into m_rowArray
        for(int i = 0; i < rowsDiff; ++i) {
            insertRowVector(row+i+1, new Row);
            m_rows++;
        }

       // m_rows += rowsDiff;
        //for(unsigned int i=0; i < m_rowPositions.count() ; ++i)
        //    kdDebug(32004) << "row " << i << ": " << m_rowPositions[i] << endl);
    }
    if(colsDiff >0) {
        double width = (m_colPositions[col+1] - m_colPositions[col])/intoCols;

        QValueList<double>::iterator iCol = m_colPositions.at(col);
        for (int i=0; i < colsDiff; i++) {
            double newPos = *iCol + width;
            iCol++;
            iCol=m_colPositions.insert(iCol, newPos);
        }

        for(int i = 0; i < colsDiff; i++) {
            insertEmptyColumn(col+i+1);
            m_cols++;
        }
        //for(unsigned int i=0; i < m_colPositions.count(); ++i)
        //    kdDebug(32004) << "col " << i << ": " << m_colPositions[i] << endl);
        //m_cols += colsDiff;
    }

    // adjust cellspan and rowspan on other cells.
    for (CheckedIter i(this); i ; ++i) {
        if(daCell == i) continue;

        if(rowsDiff>0) {
            if(row >= i->firstRow()&& row < i->firstRow()+ i->rowSpan())
                i->setRowSpan(i->rowSpan() + rowsDiff);
            if(i->firstRow() > row) {
                i->setFirstRow(i->firstRow() + rowsDiff);
            //    theCell->frame(0)->setTop(theCell->frame(0)->top()+extraHeight);
            }
        }
        if(colsDiff>0) {
            if(col >= i->firstColumn() && col < i->columnAfter())
                i->setColumnSpan(i->columnSpan() + colsDiff);
            if(i->firstColumn() > col)
                i->setFirstColumn(i->firstColumn() + colsDiff);
        }
        /*if(extraHeight != 0 && theCell->firstRow()== row) {
            theCell->frame(0)->setHeight(theCell->frame(0)->height()+extraHeight);
        } */
        if ( rowsDiff > 0 || colsDiff > 0 ) // something changed?
            addCell( i ); // update arrays
    }

    int i=0;
    KWFrame *firstFrame = daCell->frame(0);
    // create new cells
    for (unsigned int y = 0; y < intoRows; y++) {
        for (unsigned int x = 0; x < intoCols; x++){
            if(x==0 && y==0)
                continue; // the orig cell takes this spot.

            Cell *lastFrameSet=0L;

            if(listFrameSet.isEmpty())
                lastFrameSet = new Cell( this, y + row, x + col );
            else
                lastFrameSet = static_cast<KWTableFrameSet::Cell*> (listFrameSet.at(i));
            lastFrameSet->setGroupManager(this);

            KWFrame *theFrame=0L;
            if(listFrame.isEmpty())
            {
                theFrame=firstFrame->getCopy();
                theFrame->setRunAround( KWFrame::RA_NO );
                theFrame->setFrameBehavior(KWFrame::AutoExtendFrame);
                theFrame->setNewFrameBehavior(KWFrame::NoFollowup);
                lastFrameSet->addFrame( theFrame,false );
            }
            else
                lastFrameSet->addFrame( listFrame.at(i)->getCopy(),false );
            i++;

            // if the orig cell spans more rows/cols than it is split into, make first col/row wider.
            if(rowsDiff <0 && y==0)
                lastFrameSet->setRowSpan(lastFrameSet->rowSpan() - rowsDiff);
            if(colsDiff <0 && x==0)
                lastFrameSet->setColumnSpan(lastFrameSet->columnSpan() - colsDiff);

            addCell( lastFrameSet );
            position(lastFrameSet);
        }
    }

    // set new row and col-span. Use intermediate ints otherwise we get strange results as the
    // intermediate result could be negative (which goes wrong with unsigned ints)
    int r = (daCell->rowSpan() +1) - intoRows;
    if(r < 1) r=1;
    daCell->setRowSpan(r);

    int c = (daCell->columnSpan() + 1) - intoCols;
    if(c < 1)  c=1;
    daCell->setColumnSpan(c);

    position(daCell);
    addCell(daCell);
    validate();

    finalize();

    return new KWSplitCellCommand(i18n("Split Cells"),this,col,row,intoCols, intoRows);
}

void KWTableFrameSet::viewFormatting( QPainter &/*painter*/, int )
{
}

void KWTableFrameSet::validate()
{
    for(CheckedIter cells(this); cells; ++cells) {
        if(cells->columnSpan() == 0 || cells->rowSpan() == 0)  {
            kdDebug(32004) << " KWTableFrameSet::validate(): zero dimension" << endl;
            kdDebug(32004) << cells->firstRow() << " " << cells->firstColumn() << " " << cells->rowSpan()
                << " " << cells->columnSpan() << endl;
        }

        for(uint i = cells->firstRow(); i < cells->rowAfter(); ++i) {

             for(uint j = cells->firstColumn(); j < cells->columnAfter(); ++j) {
                  if( cell(i,j) != cells.current() ) {

                      QString str = QString("| 0x%1 ").arg( (unsigned long)cells.current(), 0, 16 );
                      kdDebug(32004) << " KWTableFrameSet::validate() failed " << endl;
                      kdDebug(32004) << "at row:  "<< i << " col: "<< j << " cell: "<<  str << endl;
                      kdDebug(32004) << cells->firstRow() << " " << cells->firstColumn() << " " << cells->rowSpan()
                           << " " << cells->columnSpan() << endl;
                      //printArrayDebug();
                  }
             }
        }
    }
}

void KWTableFrameSet::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode )
{
    // Avoid iterating over all cells if we are out of view
    if ( !viewMode->normalToView( m_doc->zoomRect( boundingRect() ) ).intersects( crect ) )
        return;

    QRect outerRect( viewMode->normalToView( m_doc->zoomRect( boundingRect() )));
    outerRect &= crect;
        if ( !outerRect.isEmpty() )
            emptyRegion = emptyRegion.subtract( outerRect );

    QPtrListIterator<KWFrame> frameIt = frameIterator();
    for ( ; frameIt.current(); ++frameIt )
    {
        QRect outerRect( viewMode->normalToView( frameIt.current()->outerRect(viewMode) ) );
        //kdDebug(32004) << "KWTableFrameSet::createEmptyRegion outerRect=" << DEBUGRECT( outerRect )
        //          << " crect=" << DEBUGRECT( crect ) << endl;
        outerRect &= crect;
        if ( !outerRect.isEmpty() )
            emptyRegion = emptyRegion.subtract( outerRect );
    }
}

void KWTableFrameSet::drawBorders( QPainter& painter, const QRect &crect, KWViewMode *viewMode ) {

    /*  Draw the borders on top of the lines stores in the m_rowPositions and m_colPositions arrays.
     *  check the relevant cells for borders and thus line thickness.
     *  We move the outer lines (on row==0 and col==0 plus on col=getColumns() etc) a bit so they will stay
     *  inside the boundary of the table!
     */
    painter.save();
    QPen previewLinePen( QApplication::palette().color(  QPalette::Active, QColorGroup::Mid ) );
    QColor defaultBorderColor = KoTextFormat::defaultTextColor( &painter );
    const int minborder = 1;
    bool drawPreviewLines = viewMode && viewMode->drawFrameBorders();

    // *** draw horizontal lines *** //
    unsigned int row=0;
    QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
    for (unsigned int i=0 ; i < m_rowPositions.count() ; i++) {
        //kdDebug(32004) << "Horizontal line code. i: " << i << endl;
        bool bottom=false;
        if( (pageBound!=m_pageBoundaries.end() && (*pageBound) == row)
            || i == m_rowPositions.count()-1)
            bottom=true;  // at end of page or end of table draw bottom border of cell.

        const KoBorder *border=0;
        double startPos =0;
        for(unsigned int col=0; col <= getColumns();) {
            //kdDebug(32004) << "bottom=" << bottom << " row=" << row << " col=" << col << endl;
            Cell *daCell = col < getColumns() ? cell(bottom?row-1:row, col) : 0;
            //if(daCell) kdDebug(32004) << "cell (" << daCell->firstRow()<< "," << daCell->firstColumn() << ")" << endl;
            //else kdDebug(32004) << "cell: " << daCell << endl;

            if(daCell && daCell->firstRow() != (bottom?row-1:row))
                daCell=0;

            if(startPos!=0 && (!daCell || col == getColumns() || (
                    bottom && daCell->frame(0)->bottomBorder()!=*border ||
                    !bottom && daCell->frame(0)->topBorder()!=*border
                    ))) {
                if(border->width() > 0 || drawPreviewLines) {
                    double y = m_rowPositions[i];
                    if(row==0)
                        y+=border->width() / 2; // move slightly down.
                    else if (row == getRows())
                        y-=border->width() / 2; // move slightly up.
                    int ypix = m_doc->zoomItY(y);
                    double offset=0.0;
                    if(border->width() > 0 && col!=getColumns()) { // offset border when not at right most cell.
                        if(daCell) offset=daCell->leftBorder();
                        if ( row > 0 ) {
                            Cell *c = cell(row-1, col);
                            if(c) offset=kMax(offset, c->leftBorder());
                        }
                    }
                    double x = m_colPositions[col] + offset;
                    QPoint topLeft = viewMode->normalToView(QPoint(m_doc->zoomItX(startPos), ypix));
                    QPoint bottomRight = viewMode->normalToView(QPoint(m_doc->zoomItX(x), ypix));
                    QRect line = QRect(topLeft, bottomRight);
                    if(crect.intersects( line )) {
                        //if(border->width() <= 0) kdDebug(32004) << "preview line" << endl;
                        if(border->width() <= 0)
                            painter.setPen( previewLinePen );
                        else {
                            int borderWidth = KoBorder::zoomWidthY( border->width(), m_doc, minborder );
                            painter.setPen( KoBorder::borderPen( *border, borderWidth, defaultBorderColor ) );
                        }
                        //kdDebug(32004) << "Paint: painter.drawHorizontalLine(" << line.left() << ","  << line.top() << "," <<  line.right() << ","  << line.bottom() << ")\n";
                        painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
                    }
                }
                // reset startPos
                startPos = 0;
            }
            if(daCell && startPos==0) {
                if(bottom)
                    border=&(daCell->frame(0)->bottomBorder());
                else
                    border=&(daCell->frame(0)->topBorder());

                if(col==0) // left most cell
                    startPos = m_colPositions[col];
                else {
                    double offset=0.0;
                    if(border->width() > 0) { // move line to the left a bit to compensate for the left border
                        if(daCell) offset=daCell->leftBorder();
                        if ( row > 0 ) {
                            Cell *c = cell(row-1, col);
                            if(c) offset=kMax(offset, c->leftBorder());
                        }
                    }
                    startPos = m_colPositions[col] - offset;
                }
            }
            col += daCell ? daCell->columnSpan() : 1;
        }
        if(pageBound!=m_pageBoundaries.end() && (*pageBound) == row)
            pageBound++;
        else
            row++;
    }

    // *** draw vertical lines *** //
    for (unsigned int col=0 ; col < m_colPositions.count(); col++) {
        //kdDebug(32004) << "Vertical line code. col: " << col << endl;
        bool right = false;
        if(col == m_colPositions.count()-1)
            right = true; // draw right border of cell.
        int cellColumn = right?col-1:col; // the column we'll be looking for in the loop below
        Q_ASSERT( cellColumn >= 0 );

        const KoBorder *border = 0;
        int startRow = -1;
        for(unsigned int row=0; row <= getRows();) {
            //kdDebug(32004) << "row=" << row << " cellColumn=" << cellColumn << endl;
            Cell *daCell = row < getRows() ? cell(row, cellColumn) : 0;

            //kdDebug(32004) << "Drawing vert. Line for cell row: " << row << " col: " << cellColumn << endl;
            if(daCell && daCell->firstColumn() != (uint)cellColumn)
                daCell=0;

#if 0
            kdDebug() << "Condition: startRow:" << (startRow!=-1) << endl;
            if ( startRow != -1 )  {
                Q_ASSERT( border );
                kdDebug() << "Other conditions: cell:" << !daCell << endl;
                kdDebug() << " or last row:" << ( row == ( int )getRows() ) << endl;
                if ( daCell )
                    kdDebug() << "Different border:" <<
                ( ( right && daCell->frame(0)->rightBorder() != *border) ||
                ( !right && daCell->frame(0)->leftBorder() != *border) )
                    << endl;
            }
#endif

            // be sure that the right border of the table is drawn even for joined cells
            if ( !daCell && startRow == -1 && cellColumn == ((int)m_colPositions.count()-2 ) && right )
            {
              // find the joined cell
              int col = cellColumn;
              while ( !daCell && col>0 )
              {
                col--;
                daCell = cell(row, col);
              }
              if ( daCell && daCell->isJoinedCell() && ( (int)daCell->columnSpan() + col -1 ) == cellColumn )
              {
                border = &(daCell->frame(0)->rightBorder());
                startRow = row;
              }
              else
                daCell = 0;
            }

            // Draw when something changed (different kind of border) or we're at the end
            // This code could be rewritten in a more QRT-like way
            // (iterate and compare with next, instead of the startRow/cell/border hack...)
            if(startRow != -1 &&
               (!daCell || row == getRows() ||
                ( right && daCell->frame(0)->rightBorder() != *border) ||
                ( !right && daCell->frame(0)->leftBorder() != *border) )
                ) {
                if(border->width() > 0 || drawPreviewLines) {
                    double x = m_colPositions[col];
                    if(col==0) {
                        x+=border->width() / 2;
                    } else if(col==getColumns()) {
                        x-=border->width() / 2;
                    }
                    int xpix = m_doc->zoomItX(x);
                    QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
                    unsigned int topRow=startRow;
                    //kdDebug(32004) << "Drawing from topRow=" << topRow << endl;
                    do { // draw minimum of one line per page.
                        while( pageBound != m_pageBoundaries.end() && *(pageBound) < topRow )
                            pageBound++;

                        unsigned int bottomRow;
                        if(pageBound == m_pageBoundaries.end())
                            bottomRow = m_rowPositions.count()-1;
                        else
                            bottomRow = *(pageBound++);

                        //kdDebug(32004) << "from: " << topRow << " to: " << kMin((uint)row, bottomRow) << endl;
                        //kdDebug(32004) << "from: " << m_rowPositions[topRow] << " to: " << m_rowPositions[kMin((uint)row, bottomRow)] << endl;
                        double offset=0.0;
                        if(border->width() > 0) {
                            //kdDebug(32004) << "looking at topRow=" << topRow << " col=" << col << endl;
                            Cell *c=cell(topRow,col);
                            if(c) offset=c->topBorder();
                            if ( col > 0 ) {
                                c=cell(topRow,col-1);
                                if(c) offset=kMax(offset,c->topBorder());
                            }
                            if(topRow==0) offset=0.0;
                        }
                        double top=m_rowPositions[topRow]-offset;

                        unsigned int toRow=kMin((uint)row,bottomRow);
                        offset=0.0;
                        if(border->width() > 0 && toRow!=bottomRow) {
                            if(daCell) offset=daCell->topBorder();
                            Cell *c=cell(toRow,col-1);
                            if(c) offset=kMax(offset,c->topBorder());
                        }
                        double bottom=m_rowPositions[toRow] + offset;

                        QPoint topLeft = viewMode->normalToView(QPoint(xpix, m_doc->zoomItY(top)));
                        QPoint bottomRight = viewMode->normalToView(QPoint(xpix, m_doc->zoomItY(bottom)));
                        QRect line = QRect(topLeft, bottomRight);
                        if(crect.intersects( line )) {
                            if(border->width() <= 0)
                                painter.setPen( previewLinePen );
                            else {
                                int borderWidth = KoBorder::zoomWidthX( border->width(), m_doc, minborder );
                                painter.setPen(KoBorder::borderPen( *border, borderWidth, defaultBorderColor ));
                            }
                            //kdDebug(32004) << "drawBorders(): painter.drawVerticalLine(" << line.left() << ","  << line.top() << "," <<  line.right() << ","  << line.bottom() << ")\n";
                            painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
                        }

                        topRow=bottomRow+1;
                    } while(topRow < (uint)row && topRow != m_rowPositions.count());
                } // end "if border to be drawn"

                // reset startRow
                startRow = -1;
            }

            if(daCell && startRow == -1) {
                startRow = row;
                if(right)
                    border = &(daCell->frame(0)->rightBorder());
                else
                    border = &(daCell->frame(0)->leftBorder());
                //kdDebug(32004) << "startRow set to " << row << endl;
            }
            row += daCell ? daCell->rowSpan() : 1;
            //kdDebug(32004) << "End of loop, row=" << row << endl;
        }
    }

#if 0
    if(drawPreviewLines) {
        QPen minsizeLinePen( red );
        painter.setPen( minsizeLinePen );
        for ( unsigned int i = 0; i < m_cells.count(); i++ ) {
            Cell *daCell = m_cells.at( i );
            double y = daCell->frame(0)->top() + daCell->frame(0)->minimumFrameHeight() + 1.5;
            if(y >= daCell->frame(0)->bottom()) continue;
            int ypix=m_doc->zoomItY(y);
            QPoint topLeft = viewMode->normalToView(QPoint(m_doc->zoomItX(daCell->frame(0)->left()), ypix));
            QPoint bottomRight = viewMode->normalToView(QPoint(m_doc->zoomItX(daCell->frame(0)->right()), ypix));
            QRect line = QRect(topLeft, bottomRight);
            if(crect.intersects( line )) {
                painter.drawLine( line.left(), line.top(), line.right(), line.bottom());
            }
        }
    }
#endif

    painter.restore();
}

void KWTableFrameSet::drawContents( QPainter * painter, const QRect & crect,
                                    const QColorGroup & cg, bool onlyChanged, bool resetChanged,
                                    KWFrameSetEdit * edit, KWViewMode * viewMode,
                                    KWFrameViewManager *fvm )
{
    for (TableIter cells(this) ; cells ; ++cells)
    {
        if (edit)
        {
            KWTableFrameSetEdit * tableEdit = static_cast<KWTableFrameSetEdit *>(edit);
            if ( tableEdit->currentCell() && ((Cell*) cells) == tableEdit->currentCell()->frameSet() )
            {
                cells->drawContents( painter, crect, cg, onlyChanged, resetChanged, tableEdit->currentCell(), viewMode, fvm );
                continue;
            }
        }
        cells->drawContents( painter, crect, cg, onlyChanged, resetChanged, 0L, viewMode, fvm );
    }
    drawBorders( *painter, crect, viewMode );
    //kdDebug(32004) << "drawContents()" << endl;
}

// Called by KWAnchor for inline tables
// TODO: for non-inline ones we need a text-box around us...
// Well, even for inline-as-char ones.... Currently being debated with OASIS.
void KWTableFrameSet::saveOasis( KoXmlWriter& writer, KoSavingContext& context, bool ) const
{
    writer.startElement( "table:table" );
    writer.addAttribute( "table:name", name() );
    KoGenStyle tableStyle( KWDocument::STYLE_TABLE, "table" );
    tableStyle.addProperty( "table:align", "margins" );
    tableStyle.addPropertyPt( "style:width", m_colPositions.last()-m_colPositions[0] );
    const QString tableStyleName = context.mainStyles().lookup( tableStyle, "table" );
    writer.addAttribute( "table:style-name", tableStyleName );

    // ### to minimize the XML, we could use table:number-columns-repeated here
    // when a number of consecutive columns have the exact same style.
    for ( uint colNr = 0; colNr < getColumns(); ++colNr )
    {
        writer.startElement( "table:table-column" );
        KoGenStyle columnStyle( KWDocument::STYLE_TABLE_COLUMN, "table-column" );
        columnStyle.addPropertyPt( "style:column-width", m_colPositions[colNr+1] - m_colPositions[colNr] );
        const QString colStyleName = context.mainStyles().lookup( columnStyle, "col" );
        writer.addAttribute( "table:style-name", colStyleName );
        writer.endElement(); // table:table-column
    }

    // TODO table-header-rows once supported

    for ( uint row = 0; row < getRows(); ++row )
    {
        writer.startElement( "table:table-row" );

        KoGenStyle rowStyle( KWDocument::STYLE_TABLE_ROW, "table-row" );
        rowStyle.addPropertyPt( "table:row-height", m_rowPositions[row+1] - m_rowPositions[row] );
        // TODO is min-row-height or use-optimal-row-height necessary?
        const QString rowStyleName = context.mainStyles().lookup( rowStyle, "row" );
        writer.addAttribute( "table:style-name", rowStyleName );

        for ( uint col = 0; col < getColumns(); ++col )
        {
            Cell* daCell = cell(row, col);
            Q_ASSERT( daCell );
            if ( !daCell )
                continue;

            if ( daCell->isFirstGridPosnFast( row, col ) )
            {
                writer.startElement( "table:table-cell" );

                // Style: background, border, padding.
                KoGenStyle cellStyle( KWDocument::STYLE_TABLE_CELL_AUTO, "table-cell" );
                daCell->frame( 0 )->saveBorderProperties( cellStyle );
                const QString colStyleName = context.mainStyles().lookup( cellStyle, "cell" );
                writer.addAttribute( "table:style-name", colStyleName );

                // Attributes
                if ( daCell->columnSpan() > 1 )
                    writer.addAttribute( "table:number-columns-spanned", daCell->columnSpan() );
                if ( daCell->rowSpan() > 1 )
                    writer.addAttribute( "table:number-row-spanned", daCell->rowSpan() );

                // Content
                daCell->saveOasisContent( writer, context );

                writer.endElement(); // table:table-cell
            }
            else
            {
                // Empty element for the covered cell
                writer.startElement( "table:covered-table-cell" );
                writer.endElement();
            }
        }
        writer.endElement(); // table:table-row
    }

    writer.endElement(); // table:table
}

void KWTableFrameSet::loadOasis( const QDomElement& tableTag, KoOasisContext& context )
{
    // Left position of each column. The last one defined is the right position of the last cell/column.
    QMemArray<double> columnLefts(4);
    uint maxColumns = columnLefts.size() - 1;

    uint col = 0;
    columnLefts[0] = 0.0; // Initialize left of first cell
    QDomElement elem;
    forEachElement( elem, tableTag )
    {
        if ( elem.localName() == "table-column" && elem.namespaceURI() == KoXmlNS::table )
        {
            uint repeat = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", "1").toUInt(); // Default 1 time
            if (!repeat)
                repeat=1; // At least one column defined!
            KoStyleStack& styleStack = context.styleStack();
            styleStack.setTypeProperties( "table-column" );
            styleStack.save();
            context.fillStyleStack( elem, KoXmlNS::table, "style-name", "table-column" );

            QString strWidth = styleStack.attributeNS( KoXmlNS::style, "column-width" );
            double width = KoUnit::parseValue( strWidth );

            if ( width < 1.0 ) // Something is wrong with the width
            {
                kdWarning(32004) << "Table column width ridiculous, assuming 1 inch!" << endl;
                width = 72.0;
            }
            else
                kdDebug(32004) << "- style width " << width << endl;

            for ( uint j = 0; j < repeat; ++j )
            {
                ++col;
                if ( col >= maxColumns )
                {
                    // We need more columns
                    maxColumns += 4;
                    columnLefts.resize( maxColumns+1, QGArray::SpeedOptim );
                }
                columnLefts[col] = width + columnLefts[col-1];
                kdDebug(32004) << "Cell column " << col-1 << " left " << columnLefts[col-1] << " right " << columnLefts[col] << endl;
            }
            styleStack.restore();
        }
    }

    uint row = 0;
    uint column = 0;
    parseInsideOfTable( tableTag, context, columnLefts, row, column, 0 );
}

void KWTableFrameSet::parseInsideOfTable( const QDomElement& parent, KoOasisContext& context,
                                          const QMemArray<double> & columnLefts, uint& row, uint& column,
                                          double currentRowHeight )
{
    kdDebug(32004) << "parseInsideOfTable" << endl;
    KoStyleStack& styleStack = context.styleStack();

    QDomElement e;
    forEachElement( e, parent )
    {
        const QString localName = e.localName();
        const QString ns = e.namespaceURI();
        if ( ns != KoXmlNS::table ) {
            kdWarning(32004) << "Skipping element " << e.tagName() << " (in parseInsideOfTable)" << endl;
            continue;
        }

        styleStack.save();
        if ( localName == "table-cell" )
        {
            loadOasisCell( e, context, columnLefts, row, column, currentRowHeight );
            ++column;
        }
        else if ( localName == "covered-table-cell" )
        {
            ++column;
        }
        else if ( localName == "table-row" )
        {
            context.fillStyleStack( e, KoXmlNS::table, "style-name", "table-row" );
            context.styleStack().setTypeProperties( "table-row" );

            // Load row height in case it was set - note that it might not be set (e.g. OOo)
            double rowHeight = styleStack.attributeNS( KoXmlNS::table, "row-height" ).toDouble();
            column = 0;
            parseInsideOfTable( e, context, columnLefts, row, column, rowHeight );
            ++row;
        }
        else if ( localName == "table-header-rows" ) // ###TODO
        {
            // TODO: do we need to fillStyleStack?
            parseInsideOfTable( e, context, columnLefts, row, column, currentRowHeight );
        }
        else if ( localName == "table-column" )
        {
            // Already treated in loadOasis, we do not need to do anything here!
        }
        // TODO sub-table [ add to stack and expand at end of table loading ]
        else
        {
            kdWarning(32004) << "Skipping element " << localName << " (in parseInsideOfTable)" << endl;
        }

        styleStack.restore();
    }
}

void KWTableFrameSet::loadOasisCell( const QDomElement& element, KoOasisContext& context,
                                     const QMemArray<double> & columnLefts, uint row, uint column,
                                     double currentRowHeight )
{
    //kdDebug(32004) << k_funcinfo << element.localName() << " " << row << "," << column << endl;

    KoStyleStack& styleStack = context.styleStack();
    uint rowSpan = element.attributeNS( KoXmlNS::table, "number-rows-spanned", QString::null ).toUInt();
    if ( rowSpan == 0 )
        rowSpan = 1;
    uint colSpan = element.attributeNS( KoXmlNS::table, "number-columns-spanned", QString::null ).toUInt();
    if ( colSpan == 0 )
        colSpan = 1;

    // m_rowPositions / m_colPositions could be QMemArrays, or QValueVectors...
    while(m_rowPositions.count() <= row + rowSpan + m_pageBoundaries.count()) {
        m_rowPositions.append(0);
    }
    while(m_colPositions.count() <= column + colSpan) {
        m_colPositions.append(0);
    }

    Cell *daCell = new Cell( this, row, column, QString::null /*unused*/ );

    daCell->setRowSpan( rowSpan );
    daCell->setColumnSpan( colSpan );
    addCell( daCell ); // rowSpan/colSpan have changed -> update array

    double width = columnLefts[ QMIN( column+colSpan, columnLefts.size()-1 ) ] - columnLefts[column];
    double height = currentRowHeight > 0 ? currentRowHeight : 20;
    KWFrame* frame = new KWFrame( daCell, columnLefts[column], 0, width, height );
    if ( currentRowHeight > 0 )
        frame->setMinimumFrameHeight( height ); // ensure that text formatting won't resize it down
    frame->setRunAround( KWFrame::RA_NO );
    frame->setFrameBehavior( KWFrame::AutoExtendFrame );
    frame->setNewFrameBehavior( KWFrame::NoFollowup );
    daCell->addFrame( frame, false );

    context.fillStyleStack( element, KoXmlNS::table, "style-name", "table-cell" );
    styleStack.setTypeProperties( "table-cell" );

    daCell->frame( 0 )->loadBorderProperties( styleStack );

    daCell->loadOasisContent( element, context );
    afterLoadingCell( daCell );
}

// Old XML
QDomElement KWTableFrameSet::save( QDomElement &parentElem, bool saveFrames ) {
    // When saving to a file, we don't have anything specific to the frameset to save.
    // Save the cells only.
    for (TableIter cells(this) ; cells ; ++cells)
        cells->save(parentElem, saveFrames);
    return QDomElement(); // No englobing element for tables...
}

// Old XML
QDomElement KWTableFrameSet::toXML( QDomElement &parentElem, bool saveFrames )
{
    QDomElement framesetElem = parentElem.ownerDocument().createElement( "FRAMESET" );
    parentElem.appendChild( framesetElem );
    KWFrameSet::saveCommon( framesetElem, false ); // Save the frameset attributes
    // Save the cells
    save( framesetElem, saveFrames );
    return framesetElem;
}

// Old XML
void KWTableFrameSet::fromXML( QDomElement &framesetElem, bool loadFrames, bool useNames )
{
    KWFrameSet::load( framesetElem, false ); // Load the frameset attributes
    // Load the cells
    QDomElement cellElem = framesetElem.firstChild().toElement();
    for ( ; !cellElem.isNull() ; cellElem = cellElem.nextSibling().toElement() )
    {
        if ( cellElem.tagName() == "FRAMESET" )
            loadCell( cellElem, loadFrames, useNames );
    }
}

// Old XML
KWTableFrameSet::Cell* KWTableFrameSet::loadCell( QDomElement &framesetElem, bool loadFrames, bool useNames )
{
    int _row = KWDocument::getAttribute( framesetElem, "row", 0 );
    if(_row <0) _row =0;
    unsigned int row=_row;
    int _col = KWDocument::getAttribute( framesetElem, "col", 0 );
    if(_col <0) _col =0;
    int _rows = KWDocument::getAttribute( framesetElem, "rows", 1 );
    if(_rows <0) _rows = 1;
    int _cols = KWDocument::getAttribute( framesetElem, "cols", 1 );
    if(_cols <0) _cols = 1;

    // m_rowPositions / m_colPositions could be QMemArrays, or QValueVectors...
    while(m_rowPositions.count() <= static_cast<unsigned int>(row + _rows + m_pageBoundaries.count())) {
        m_rowPositions.append(0);
    }
    while(m_colPositions.count() <= static_cast<unsigned int>(_col + _cols)) {
        m_colPositions.append(0);
    }

    Cell *daCell = new Cell( this, row, _col, QString::null /*unused*/ );
    QString autoName = daCell->name();
    //kdDebug(32004) << "KWTableFrameSet::loadCell autoName=" << autoName << endl;
    daCell->load( framesetElem, loadFrames );
    daCell->setRowSpan(_rows);
    daCell->setColumnSpan(_cols);
    addCell( daCell ); // rowSpan/colSpan have changed -> update array
    afterLoadingCell( daCell );
    if ( !useNames )
        daCell->setName( autoName );
    return daCell;
}

// Shared between old xml and oasis
void KWTableFrameSet::afterLoadingCell( Cell* daCell )
{
    uint row = daCell->firstRow();
    uint col = daCell->firstColumn();
    uint rowSpan = daCell->rowSpan();
    uint colSpan = daCell->columnSpan();
    if(m_pageBoundaries.count() > 0) {
        unsigned int adjustment=0;
        QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
        while(pageBound != m_pageBoundaries.end() && (*pageBound) <= row + adjustment) {
            adjustment++;
            pageBound++;
        }
        row+=adjustment;
    }

    kdDebug(32004) << "loading cell (" << row << "," << col << ")\n";
    if(daCell->frame(0)) {
        daCell->frame(0)->setMinimumFrameHeight(daCell->frame(0)->height()); // TODO run the formatter over the text here
        QValueList<double>::iterator tmp = m_colPositions.at(col);
        if(*tmp == 0) (*tmp) = daCell->frame(0)->left();
        else (*tmp) = (daCell->frame(0)->left() + *tmp) / 2;

        tmp = m_colPositions.at(col+colSpan);
        if(*tmp == 0) (*tmp) = daCell->frame(0)->right();
        else (*tmp) = (daCell->frame(0)->right() + *tmp) / 2;

        tmp = m_rowPositions.at(row);
        if(*tmp == 0)
            (*tmp) = daCell->frame(0)->top();
        else {
            if (static_cast<int>(*tmp/m_doc->pageLayout().ptHeight) < static_cast<int>(daCell->frame(0)->top()/m_doc->pageLayout().ptHeight)) {
                kdDebug(32004) << "This cell is on a new page" << endl;
                QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
                while(pageBound != m_pageBoundaries.end() && (*pageBound) < row) ++pageBound;
                if(*pageBound!=row) {
                    m_pageBoundaries.insert(pageBound,row++);
                    ++tmp;
                    m_rowPositions.insert(tmp,daCell->frame(0)->top());
                }
            } else
                (*tmp) = (daCell->frame(0)->top() + *tmp) / 2;
        }

        tmp = m_rowPositions.at( row + rowSpan );
        if(*tmp == 0)
            (*tmp) = daCell->frame(0)->bottom();
        else { // untested...
            if (static_cast<int>(*tmp/m_doc->pageLayout().ptHeight) > static_cast<int>(daCell->frame(0)->top()/m_doc->pageLayout().ptHeight)) {
                kdDebug(32004) << "next cell is on a new page" << endl;
                QValueList<unsigned int>::iterator pageBound = m_pageBoundaries.begin();
                while(pageBound != m_pageBoundaries.end() && (*pageBound) < row) ++pageBound;
                if(*pageBound!=row) {
                    m_pageBoundaries.insert(pageBound,row++);
                    m_rowPositions.insert(tmp,daCell->frame(0)->bottom());
                }
            } else
                (*tmp) = (daCell->frame(0)->bottom() + *tmp) / 2;
        }
    }

    if ( m_rowPositions.count() != m_rows + 1 ) {
        kdDebug() << name() << " loadCell: m_rowPositions=" << m_rowPositions.count() << " m_rows= " << m_rows << endl;
    }
}

int KWTableFrameSet::paragraphs()
{
    int paragraphs = 0;
    for (TableIter cells(this) ; cells ; ++cells)
        paragraphs += cells->paragraphs();
    return paragraphs;
}

int KWTableFrameSet::paragraphsSelected()
{
    int paragraphs = 0;
    for (TableIter cells(this) ; cells ; ++cells)
        paragraphs += cells->paragraphsSelected();
    return paragraphs;
}

bool KWTableFrameSet::statistics( QProgressDialog *progress, ulong & charsWithSpace, ulong & charsWithoutSpace, ulong & words,
    ulong & sentences, ulong & syllables, ulong & lines, bool selected )
{
    for (TableIter cells(this) ; cells ; ++cells)
        if( ! cells->statistics( progress, charsWithSpace, charsWithoutSpace, words, sentences, syllables, lines, selected ) )
        {
            return false;
        }
    return true;
}

void KWTableFrameSet::finalize( ) {
    kdDebug(32004) << "KWTableFrameSet::finalize" << endl;

    for (TableIter cells(this) ; cells ; ++cells)
    {
        position( cells );
        cells->finalize();
    }

    recalcCols(0, 0);
    recalcRows(0, 0);
    KWFrameSet::finalize();
}

void KWTableFrameSet::layout()
{
    for (TableIter cells(this) ; cells ; ++cells)
        cells->layout();
}

void KWTableFrameSet::invalidate()
{
    for (TableIter cells(this) ; cells ; ++cells)
        cells->invalidate();
}

void KWTableFrameSet::setVisible( bool v )
{
    for (TableIter cells(this) ; cells ; ++cells)
        cells->setVisible( v );

    KWFrameSet::setVisible( v );
}

bool KWTableFrameSet::canRemovePage( int num ) {
    /*  This one is a lot simpler then the one it overrides, we simply don't have
        to check if the frame contains something, the simple existence of a frame
        is enough
    */
    QPtrListIterator<KWFrame> frameIt( frameIterator() );
    for ( ; frameIt.current(); ++frameIt ) {
        if ( frameIt.current()->pageNumber() == num ) {
            return false;
        }
    }
    return true;
}

void KWTableFrameSet::addTextFrameSets( QPtrList<KWTextFrameSet> & lst, bool onlyReadWrite )
{
    for (TableIter cells(this) ; cells ; ++cells)
        if (!cells->textObject()->protectContent() || onlyReadWrite )
            lst.append(cells);
}

KWTextFrameSet* KWTableFrameSet::nextTextObject( KWFrameSet *obj )
{
    bool found = false;
    KWTableFrameSet::Cell *tmp = dynamic_cast<KWTableFrameSet::Cell *>(obj);

    // make sure we have this cell
    if ( tmp ) {
        for(TableIter i(this); i; ++i) {
            if(i.current() == tmp) {
                found = true;
                break;
            }
        }
    }

    TableIter iter(this);
    if(found)
        iter.goToCell(tmp);

    for(; iter; ++iter) {
        KWTextFrameSet *newFrm = iter->nextTextObject( obj );
        if(newFrm && newFrm->textObject()->needSpellCheck())
            return newFrm;
    }

    return 0L;
}

void KWTableFrameSet::setZOrder()
{
    for( TableIter cells(this) ; cells ; ++cells ) {
        cells->setZOrder();
    }

}

// TODO provide toPlainText() (reimplemented from KWFrameSet)

QByteArray KWTableFrameSet::convertTableToText() // should be const, but TableIter doesn't allow it
{
    KWOasisSaver oasisSaver( m_doc );
    for (TableIter cells(this); cells; ++cells)
    {
        cells->textObject()->saveOasisContent( oasisSaver.bodyWriter(), oasisSaver.savingContext() );
    }
    if ( !oasisSaver.finish() )
        return QByteArray();
    return oasisSaver.data();
}

#ifndef NDEBUG
void KWTableFrameSet::printDebug( KWFrame * theFrame )
{
    KWTableFrameSet::Cell *daCell = dynamic_cast<KWTableFrameSet::Cell *>( theFrame->frameSet() );
    Q_ASSERT( daCell );
    if ( daCell ) {
        kdDebug(32004) << " |  |- row :" << daCell->firstRow() << endl;
        kdDebug(32004) << " |  |- col :" << daCell->firstColumn() << endl;
        kdDebug(32004) << " |  |- rows:" << daCell->rowSpan() << endl;
        kdDebug(32004) << " |  +- cols:" << daCell->columnSpan() << endl;
    }
}

void KWTableFrameSet::printArrayDebug() {
    kdDebug(32004) << " |  Row/Cell arrays" << endl;
    Q_ASSERT( m_rows == m_rowArray.size() );
    for ( unsigned int row = 0; row < m_rows; ++row )  {
        QString str = QString( " | Row %1: " ).arg( row );
        for ( unsigned int col = 0; col < getColumns(); ++col )
            str += QString("| 0x%1 ").arg( (unsigned long)(*m_rowArray[row])[col], 0, 16 );
        kdDebug(32004) << str<< " |" << endl;
    }
}

void KWTableFrameSet::printDebug() {
    kdDebug(32004) << " |  Table size (" << m_rows << "x" << getColumns() << ")" << endl;
    kdDebug(32004) << " |  col  " << 0 << ": " << m_colPositions[0] << endl;
    for(unsigned int i=1;i<m_colPositions.count(); ++i)
        kdDebug(32004) << " |    |  " << i << ": " << m_colPositions[i] << endl;
    kdDebug(32004) << " |  row  " << 0 << ": " << m_rowPositions[0] << endl;
    for(unsigned int i=1;i<m_rowPositions.count(); ++i)
        kdDebug(32004) << " |    |  " << i << ": " << m_rowPositions[i] << endl;

    printArrayDebug();
    KWFrameSet::printDebug();
}

#endif

// ===

KWTableFrameSet::Cell::Cell( KWTableFrameSet *table, unsigned int row, unsigned int col, const QString &/*name*/ ) :
    KWTextFrameSet( table->m_doc,
                    // Generate frameset name from table_name+row+col
                    i18n("Hello dear translator :), 1 is the table name, 2 and 3 are row and column", "%1 Cell %2,%3")
                    .arg( table->name() ).arg(row).arg(col) )
{
    m_row = row;
    m_col = col;
    m_rows = 1;
    m_cols = 1;
    m_isJoinedCell = false;
    setGroupManager( table );
    table->addCell( this );
}

KWTableFrameSet::Cell::Cell( KWTableFrameSet *table, const Cell &original ) :
    KWTextFrameSet( table->m_doc, original.m_name+'_' )
{
    m_row = original.m_row;
    m_col = original.m_col;
    m_rows = original.m_rows;
    m_cols = original.m_cols;
    m_isJoinedCell = original.m_isJoinedCell;
    setGroupManager( table );
    table->addCell( this );
}

KWTableFrameSet::Cell::~Cell()
{
}

bool KWTableFrameSet::Cell::isAboveOrLeftOf( unsigned row, unsigned col ) const
{
    return ( m_row < row ) || ( ( m_row == row ) && ( m_col < col ) );
}

bool KWTableFrameSet::Cell::containsCell( unsigned row, unsigned col ) const
{
    return ( m_row <= row &&
             m_col <= col &&
             rowAfter() > row &&
             columnAfter() > col );
}

void KWTableFrameSet::Cell::addFrame(KWFrame *_frame, bool recalc) {
    if(groupmanager())
        groupmanager()->addFrame(_frame, recalc);
    KWTextFrameSet::addFrame(_frame, recalc);
}

void KWTableFrameSet::Cell::frameDeleted( KWFrame* frm, bool recalc )
{
    if(groupmanager())
        groupmanager()->deleteFrame( frm, false, recalc );
}

double KWTableFrameSet::Cell::leftBorder() {
    double b = frame(0)->leftBorder().width();
    if(b==0.0)
        return 0.0;
    if(m_col==0) // left most cell
        return b;
    return (b / 2);
}

double KWTableFrameSet::Cell::rightBorder() {
    double b=frame(0)->rightBorder().width();
    if(b==0.0)
        return 0.0;
    if(m_col+m_cols==m_groupmanager->getColumns()) // right most cell
        return b;
    return (b / 2);
}

double KWTableFrameSet::Cell::topBorder() {
    double b = frame(0)->topBorder().width();
    if(b==0.0)
        return 0.0;
    if(m_row==0) // top most cell
        return b;
    return (b / 2);
}

double KWTableFrameSet::Cell::bottomBorder() {
    double b = frame(0)->bottomBorder().width();
    if(b==0.0)
        return 0.0;
    if(rowAfter() == m_groupmanager->m_rows) // bottom most cell
        return b;
    return (b / 2);
}

void KWTableFrameSet::Cell::setLeftBorder(KoBorder newBorder) {
    KWFrame *f = frame(0);
    double diff = f->leftBorder().width() - newBorder.width();
    f->setLeftBorder(newBorder);

    if((diff > 0.01 || diff < -0.01) && m_col!=0) {
        diff = diff / 2; // if not outer edge only use halve
        m_groupmanager->cell(m_row, m_col-1)->setRightBorder(newBorder);
    }
    f->setLeft(f->left() - diff);
}

void KWTableFrameSet::Cell::setRightBorder(KoBorder newBorder) {
    KWFrame *f = frame(0);
    double diff = f->rightBorder().width() - newBorder.width();
    f->setRightBorder(newBorder);

    if((diff > 0.01 || diff < -0.01) && m_col+m_cols!=m_groupmanager->getColumns()) {
        diff = diff / 2; // if not outer edge only use halve
        m_groupmanager->cell(m_row, m_col+1)->setLeftBorder(newBorder);
    }
    f->setRight(f->right() + diff);
}

void KWTableFrameSet::Cell::setTopBorder(KoBorder newBorder) {
    KWFrame *f = frame(0);
    double diff = f->topBorder().width() - newBorder.width();
    f->setTopBorder(newBorder);

    if((diff > 0.01 || diff < -0.01) && m_row!=0) {
        diff = diff / 2; // if not outer edge only use halve
        m_groupmanager->cell(m_row-1, m_col)->setBottomBorder(newBorder);
    }
    f->setTop(f->top() - diff);
}

void KWTableFrameSet::Cell::setBottomBorder(KoBorder newBorder) {
    KWFrame *f = frame(0);
    double diff = f->bottomBorder().width() - newBorder.width();
    f->setBottomBorder(newBorder);

    if((diff > 0.01 || diff < -0.01) && rowAfter() != m_groupmanager->m_rows) {
        diff = diff / 2; // if not outer edge only use halve
        m_groupmanager->cell(m_row+1, m_col)->setTopBorder(newBorder);
    }
    f->setBottom(f->bottom() + diff);
}

void KWTableFrameSet::Cell::setZOrder()
{
    QPtrListIterator<KWFrame> frameIt = frameIterator();
    for ( ; frameIt.current(); ++frameIt )
    {
        (*frameIt)->setZOrder( kWordDocument()->maxZOrder( (*frameIt)->pageNumber() ) + 1 );
    }
}

void KWTableFrameSet::Cell::drawContents( QPainter * painter, const QRect & crect,
        const QColorGroup & cg, bool onlyChanged, bool resetChanged,
        KWFrameSetEdit * edit, KWViewMode * viewMode, KWFrameViewManager *fvm )
{
    bool printing = painter->device()->devType() == QInternal::Printer;
    bool drawPreviewLines = viewMode && viewMode->drawFrameBorders();
    QRect cellRect = crect;
    if(!printing && drawPreviewLines) {
        // Make sure the clipping is changed so the preview lines (frame borders) are not overwritten.
        QRect zoomedRect( m_doc->zoomRect(*frame(0)) );
        QRect innerFrameRect( viewMode->normalToView( zoomedRect ) );
        innerFrameRect.addCoords(1, 1, -1, -1); // move and shrink
        cellRect = innerFrameRect.intersect(crect);
    }
    KWTextFrameSet::drawContents(painter, cellRect, cg, onlyChanged, resetChanged, edit, viewMode, fvm);
}

KWTableFrameSetEdit::~KWTableFrameSetEdit()
{
    if ( m_currentCell )
        m_currentCell->terminate();
    delete m_currentCell;
}

void KWTableFrameSetEdit::mousePressEvent( QMouseEvent * e, const QPoint & nPoint, const KoPoint & dPoint )
{
    setCurrentCell( dPoint );
    if ( m_currentCell )
        m_currentCell->mousePressEvent( e, nPoint, dPoint );
}

void KWTableFrameSetEdit::setCurrentCell( const KoPoint & dPoint )
{
    KWFrameSet *fs = tableFrameSet()->cellByPos( dPoint.x(), dPoint.y() );
    KWTextFrameSet *textframeSet = dynamic_cast<KWTextFrameSet *>(fs);

    if ( textframeSet&& textframeSet->protectContent() && !tableFrameSet()->kWordDocument()->cursorInProtectedArea())
        return;

    if ( fs && ( !m_currentCell || fs != m_currentCell->frameSet() ) )
        setCurrentCell( fs );
}

void KWTableFrameSetEdit::setCurrentCell( KWFrameSet * fs, bool eraseSelection )
{
    bool oldProtectContent = false;
    KWTextFrameSet *textframeSet=0L;
    if ( m_currentCell )
        textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
    if ( textframeSet )
        oldProtectContent = textframeSet->protectContent();

    if ( m_currentCell )
    {
        m_currentCell->terminate(eraseSelection);
        delete m_currentCell;
    }
    m_currentCell = fs->createFrameSetEdit( m_canvas );
    textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
    if ( textframeSet )
    {
        if ( oldProtectContent != textframeSet->protectContent())
        {
            m_canvas->kWordDocument()->updateTextFrameSetEdit();
        }
    }


    m_currentFrame = fs->frame( 0 );
    KWTextFrameSetEdit *textframeSetEdit = dynamic_cast<KWTextFrameSetEdit *>(m_currentCell);
    if ( textframeSetEdit )
    {
        textframeSetEdit->ensureCursorVisible();
        //refresh koruler
        m_canvas->gui()->getView()->slotUpdateRuler();
    }
}

KWFrameSetEdit* KWTableFrameSetEdit::currentTextEdit()
{
    return m_currentCell;
}


void KWTableFrameSetEdit::keyPressEvent( QKeyEvent * e )
{
    // This method handles the up/left/down/right navigation keys in tables
    if ( !m_currentCell )
        return;
    KWTableFrameSet::Cell *cell = static_cast<KWTableFrameSet::Cell *>(m_currentCell->frameSet());
    KWTextFrameSet *textframeSet = dynamic_cast<KWTextFrameSet *>(m_currentCell->frameSet());
    bool moveToOtherCell = true;
    if(textframeSet)
    {
        // don't move to an adjacent cell when we are selecting text
        KoTextDocument * textdoc = textframeSet->textDocument();
        if(textdoc->hasSelection( KoTextDocument::Standard ))
            moveToOtherCell=false;
    }
    KWTableFrameSet::Cell *fs = 0L;

    bool tab=false; // No tab key pressed
    if(moveToOtherCell)
    {
        switch( e->key() ) {
            case QKeyEvent::Qt::Key_Up:
            {
                if(!(static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor()->parag()->prev())
                {
                    KWTableFrameSet* tableFrame=tableFrameSet();
                    int row = cell->firstRow() - 1;
                    int col = cell->firstColumn();
                    if (row < 0) {  // Wrap at top of table
                        col--; // Goes to column on the left
                        row = tableFrame->getRows() - 1;
                    }
                    if (col < 0) { // It was the first column
                        // Maybe exit the table instead?
                        col = tableFrame->getColumns() - 1;
                        row = tableFrame->getRows() - 1;
                    }
                    fs=tableFrame->cell(row,col);
                    // Not needed. cell gives us the right one already
                    //if (fs && fs->firstRow() != static_cast<unsigned int>(row)) { // Merged cell
                    //    fs=tableFrame->cell( row - fs->rowSpan() + 1, col );
                    //}
                }
            }
            break;
            case QKeyEvent::Qt::Key_Down:
            {
                if(!(static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor()->parag()->next())
                {
                    KWTableFrameSet* tableFrame=tableFrameSet();
                    unsigned int row = cell->rowAfter();
                    unsigned int col = cell->firstColumn();
                    if(row >= tableFrame->getRows()) { // Wrap at bottom of table
                        row=0;
                        col++; // Go to next column
                    }
                    if(col >= tableFrame->getColumns()) { // It was the last one
                        // Maybe exit the table instead?
                        col=0;
                        row=0;
                    }
                    fs=tableFrame->cell(row,col);
                    Q_ASSERT( fs );
                    Q_ASSERT( fs->firstRow() == row ); // We can't end up in the middle of a merged cell here.
                }
            }
            break;
            case QKeyEvent::Qt::Key_Backtab:
                tab=true;
                if (e->state() & QKeyEvent::ControlButton)
                    break; // Break if tab was pressed with Control (in *any* key combination)
                // Do not break
            case QKeyEvent::Qt::Key_Left:
            {
                KoTextCursor *cur = (static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor();
                if ( tab || (!cur->parag()->prev()&&cur->index()==0) )
                {
                    KWTableFrameSet* tableFrame=tableFrameSet();
                    int row=cell->firstRow();
                    int col=cell->firstColumn() - 1;
                    if(col < 0) { // Wrap at first column
                        col = (int)tableFrame->getColumns()-1;
                        row--; // Go up
                    }
                    if(row < 0) { // It was the first row
                        // Maybe exit the table instead?
                        col = (int)tableFrame->getColumns()-1;
                        row = (int)tableFrame->getRows()-1;
                    }
                    fs=tableFrame->cell(row,col);
                    // Not needed. cell gives us the right one already
                    //if(fs && (int)fs->m_col != col) { // Merged cell
                    //    fs=tableFrame->cell( row, col - fs->columnSpan() + 1 );
                    //}
                }
            }
            break;
            case QKeyEvent::Qt::Key_Tab:
                tab=true;
                if (e->state() & QKeyEvent::ControlButton)
                    break; // Break if tab was pressed with Control (in *any* key combination)
                // Do not break
            case QKeyEvent::Qt::Key_Right:
            {
                KoTextCursor *cur = (static_cast<KWTextFrameSetEdit *>(m_currentCell))->cursor();
                if( tab || (!cur->parag()->next()&&cur->index()==cur->parag()->string()->length()-1) )
                {
                    KWTableFrameSet* tableFrame=tableFrameSet();
                    unsigned int row = cell->firstRow();
                    unsigned int col = cell->columnAfter();
                    if(col >= tableFrame->getColumns()) { // Wrap after last column
                        col = 0;
                        row++; // Go down one row
                    }
                    if(row >= tableFrame->getRows()) { // It was the last row
                        // Maybe exit the table instead?
                        col = 0;
                        row = 0;
                    }
                    fs=tableFrame->cell(row,col);
                    Q_ASSERT( fs );
                    Q_ASSERT( fs->firstRow() == row ); // We can't end up in the middle of a merged cell here.
                }
            }
            break;
        }
    }
    if ( fs )
    {
        //don't switch to a protected cell protected when cursor in protected areas was disabled.
        if ( fs->textObject()->protectContent() && !tableFrameSet()->kWordDocument()->cursorInProtectedArea())
            return;
        setCurrentCell( fs );
    }
    else if ( textframeSet )
    {
        if ( !textframeSet->textObject()->protectContent() )
        {
            if (tab && (e->state() & QKeyEvent::ControlButton) )
            {
                QKeyEvent event(QEvent::KeyPress, QKeyEvent::Qt::Key_Tab, 9, 0, QChar(9));
                m_currentCell->keyPressEvent( &event );
            }
            else
                m_currentCell->keyPressEvent( e );
        }
        else if(e->text().length() > 0)
            KMessageBox::information(0L, i18n("Read-only content cannot be changed. No modifications will be accepted."));
    }
}

void KWTableFrameSetEdit::keyReleaseEvent( QKeyEvent * e )
{
    if ( m_currentCell )
        m_currentCell->keyReleaseEvent( e );
}

void KWTableFrameSetEdit::imStartEvent( QIMEvent* e )
{
    if ( m_currentCell )
        m_currentCell->imStartEvent( e );
}

void KWTableFrameSetEdit::imComposeEvent( QIMEvent* e )
{
    if ( m_currentCell )
        m_currentCell->imComposeEvent( e );
}

void KWTableFrameSetEdit::imEndEvent( QIMEvent* e )
{
    if ( m_currentCell )
        m_currentCell->imEndEvent( e );
}

void KWTableFrameSetEdit::dragMoveEvent( QDragMoveEvent * e, const QPoint &n, const KoPoint &d )
{
    kdDebug(32004)<<"m_currentCell :"<<m_currentCell<<endl;
    if ( m_currentCell )
    {
        KWFrameSet *fs = tableFrameSet()->cellByPos( d.x(), d.y() );
        kdDebug(32004)<<"fs :"<<fs <<endl;
        if(fs && fs != m_currentCell->frameSet())
            setCurrentCell(fs, false);
        if(m_currentCell)
            m_currentCell->dragMoveEvent( e, n, d );
    }
    else
    {
        setCurrentCell( d );
        kdDebug(32004)<<"after m_currentCell :"<<m_currentCell<<endl;
        if(m_currentCell)
            m_currentCell->dragMoveEvent( e, n, d );
    }
}

void KWTableFrameSet::Row::addCell( Cell *cell )
{
    if ( m_cellArray.size() < cell->columnAfter())
        m_cellArray.resize( cell->columnAfter() );
    for ( uint col = cell->firstColumn() ; col < cell->columnAfter(); ++col )
        m_cellArray.insert( col, cell );
}

void KWTableFrameSet::Row::removeCell( Cell* cell )
{
    for ( uint col = cell->firstColumn() ; col <  cell->columnAfter(); ++col )
        m_cellArray.remove( col );
}

template<>
KWTableFrameSet::Cell*
KWTableFrameSet::TableIterator<KWTableFrameSet::VISIT_CELL>::operator++()
{
    if(!m_cell) return 0;

    Cell *ret = m_cell;

    do{
        // check for end of row first
        if(m_table->cell(m_row,m_col)->lastColumn() >= m_limit[RIGHT] ) {
            // now check for end of column
            if (m_row >= m_limit[LOW]){
                // at end of traversal
                m_cell = 0;
                break;
            }
            else {
                // goto first grid position in next row
                m_row += 1;
                m_col = m_limit[LEFT];
            }
        }
        else {
            // goto next cell in row
            m_col = m_table->cell(m_row, m_col)->columnAfter();
        }

        m_cell = m_table->cell(m_row,m_col);
    } while( m_cell && !m_cell->isFirstGridPosnFast(m_row,m_col) );

    return ret;
}

template<>
KWTableFrameSet::Cell*
KWTableFrameSet::TableIterator<KWTableFrameSet::VISIT_GRID>::operator++()
{
    if(!m_cell) return 0;

    Cell *ret = m_cell;
    // check for end of row
    if(m_col == m_limit[RIGHT]) {
        if(m_row == m_limit[LOW]) { // end of traversal
            m_row = 0;
            m_col = 0;
            m_cell = 0;
        }
        else { // go to next row
            m_row += 1;
            m_col = m_limit[LEFT];
            m_cell = m_table->cell(m_row, m_col);
        }
    }
    else { // move to next cell in row
        m_col += 1;
        m_cell = m_table->cell(m_row, m_col);
    }

    return ret;
}

KWTableFrameSet::MarkedIterator::MarkedIterator(KWTableFrameSet *table) :
    GridIter(table)
{
    // clear all the cell marks
    for(GridIter cell(table); cell; ++cell)
        cell->clearMark();

    if ( current() ) {
//      kdDebug() << "MarkedIterator: visit: "
//          << QString("| 0x%1 ").arg((unsigned long)current(), 0, 16) << endl;
        current()->setMark();
    }
}

KWTableFrameSet::Cell *
KWTableFrameSet::MarkedIterator::operator++()
{
    Cell *ret = GridIter::operator++();

    while ( current() && current()->marked() ) {
        GridIter::operator++();
    }
    if ( current() ) {
//      kdDebug() << "MarkedIterator: visit: "
//          << QString("| 0x%1 ").arg((unsigned long)current(), 0, 16) << endl;
        current()->setMark();
    }
    return ret;
}

template<>
KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::TableIterator(KWTableFrameSet *table):
    m_table(table)
{
    Q_ASSERT(m_table);
    set_limits(0, (int)m_table->getColumns() - 1, 0, (int)m_table->getRows() - 1);

    Cell *c = 0;
    for(uint i = m_limit[HIGH]; i <= m_limit[LOW]; ++i)
        for(uint j = m_limit[LEFT]; j <= m_limit[RIGHT]; ++j) {

            c = m_table->cell(i,j);
            if(c) c->clearMark();
        }
    toFirstCell();
}

template<>
KWTableFrameSet::Cell*
KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::operator++ ()
{

    Cell *ret = m_cell;
    if(!ret) return 0;

    ret->setMark();
    m_cell = 0;
    uint i = m_row; uint j = m_col;

    for(; i <= m_limit[LOW]; ++i) {

        for(j = 0; j <= m_limit[RIGHT]; ++j) {
            m_cell = m_table->cell(i,j);
            if( m_cell && !m_cell->marked() ){
                m_row = i; m_col = j;
                goto out;
            }
            else if(i == m_limit[LOW] && j == m_limit[RIGHT]){
                m_cell = 0;
                goto out;
            }
        }
    }

    out:
    return ret;
}

template<>
KWTableFrameSet::Cell*
KWTableFrameSet::TableIterator<KWTableFrameSet::CHECKED>::toFirstCell ()
{
    m_cell = 0;
    for(uint i = m_limit[HIGH]; i <= m_limit[LOW]; ++i)
        for(uint j = m_limit[LEFT]; j <= m_limit[RIGHT]; ++j) {
            m_cell = m_table->cell(i,j);
            if(m_cell) {
                m_row = i; m_col = j;
                goto out;
            }
        }

    out:
    return m_cell;
}

RemovedRow::RemovedRow() :
    m_row(0), m_index(0), m_rowHeight(0.0)
{

}

RemovedRow::~RemovedRow()
{
    // free cells as well ???
    delete m_row;
}

KWTableFrameSet::Row *RemovedRow::takeRow()
{
    Q_ASSERT(m_row);
    KWTableFrameSet::Row *ret = m_row;
    m_row = 0;
    return ret;
}

RemovedColumn::RemovedColumn()
    : m_column(), m_removed(), m_index(0), m_width(0), m_initialized(false){ }


#include "KWTableFrameSet.moc"
