summaryrefslogtreecommitdiffstats
path: root/kword/KWTableFrameSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kword/KWTableFrameSet.cpp')
-rw-r--r--kword/KWTableFrameSet.cpp2943
1 files changed, 2943 insertions, 0 deletions
diff --git a/kword/KWTableFrameSet.cpp b/kword/KWTableFrameSet.cpp
new file mode 100644
index 00000000..983c9e07
--- /dev/null
+++ b/kword/KWTableFrameSet.cpp
@@ -0,0 +1,2943 @@
+/*
+ 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"