You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kword/KWTableFrameSet.cpp

2944 lines
106 KiB

/*
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"