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/kspread/manipulator.cc

1724 lines
44 KiB

/* This file is part of the KDE project
Copyright (C) 2005 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
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.
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.
*/
#include <float.h>
#include <tqcolor.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kstaticdeleter.h>
#include "kspread_canvas.h"
#include "kspread_cell.h"
#include "kspread_doc.h"
#include "kspread_map.h"
#include "kspread_sheet.h"
#include "kspread_style.h"
#include "kspread_style_manager.h"
#include "kspread_undo.h"
#include "kspread_view.h"
#include "manipulator.h"
using namespace KSpread;
//BEGIN Non-contiguous selection adaption todos
// TODO Stefan: InsertColumn
// TODO Stefan: InsertRow
// TODO Stefan: DeleteColumn
// TODO Stefan: DeleteRow
// TODO Stefan: SortInc
// TODO Stefan: SortDec
// TODO Stefan: FillSelection ?
// TODO Stefan: RemoveComment (works, but not a manipulator yet)
// TODO Stefan: ClearText (works, but not a manipulator yet)
// TODO Stefan: ClearValidity (works, but not a manipulator yet)
// TODO Stefan: Validity (works, but not a manipulator yet)
// TODO Stefan: Conditional (works, but not a manipulator yet)
// TODO Stefan: Copy (works, but not a manipulator yet)
// TODO Stefan: Delete (works, but not a manipulator yet)
// TODO Stefan: Cut (works, but not a manipulator yet)
// TODO Stefan: Paste (works, but not a manipulator yet)
// TODO Stefan: Paste Special (works, but not a manipulator yet)
// TODO Stefan: Paste with insertion (works, but not a manipulator yet)
// TODO Stefan: more ????
//END
//BEGIN NOTE Stefan: some words on operations
//
// 1. SubTotal
// a) Makes no sense to extend to non-contiguous selections (NCS) as
// it refers to a change in one column.
// b) No special undo command available yet.
//
// 2. AutoSum
// a) should insert cell at the end of the selection, if the last
// is not empty
// b) opens an editor, if the user's intention is fuzzy -> hard to
// convert to NCS
//END
/***************************************************************************
class Manipulator
****************************************************************************/
Manipulator::Manipulator()
: Region(),
KCommand(),
m_sheet(0),
m_creation(true),
m_reverse(false),
m_firstrun(true),
m_format(true),
m_register(true)
{
}
Manipulator::~Manipulator()
{
}
void Manipulator::execute()
{
if (!m_sheet)
{
kdWarning() << "Manipulator::execute(): No explicit m_sheet is set. "
<< "Manipulating all sheets of the region." << endl;
}
bool successfully = true;
successfully = preProcessing();
if (!successfully)
{
kdWarning() << "Manipulator::execute(): preprocessing was not successful!" << endl;
return; // do nothing if pre-processing fails
}
m_sheet->doc()->setModified(true);
m_sheet->doc()->undoLock ();
m_sheet->doc()->emitBeginOperation();
successfully = true;
Region::Iterator endOfList(cells().end());
for (Region::Iterator it = cells().begin(); it != endOfList; ++it)
{
successfully = successfully && process(*it);
}
if (!successfully)
{
kdWarning() << "Manipulator::execute(): processing was not successful!" << endl;
}
successfully = true;
successfully = postProcessing();
if (!successfully)
{
kdWarning() << "Manipulator::execute(): postprocessing was not successful!" << endl;
}
m_sheet->setRegionPaintDirty( *this );
m_sheet->doc()->emitEndOperation();
m_sheet->doc()->undoUnlock ();
// add me to undo if needed
if (m_firstrun && m_register)
{
// addCommand itself checks for undo lock
m_sheet->doc()->addCommand (this);
// if we add something to undo, then the document surely is modified ...
m_sheet->doc()->setModified (true);
}
m_firstrun = false;
}
void Manipulator::unexecute()
{
m_reverse = !m_reverse;
execute();
m_reverse = !m_reverse;
}
bool Manipulator::process(Element* element)
{
Sheet* sheet = m_sheet; // TODO Stefan: element->sheet();
if (m_sheet && sheet != m_sheet)
{
return true;
}
TQRect range = element->rect().normalize();
if (m_format && element->isColumn())
{
for (int col = range.left(); col <= range.right(); ++col)
{
kdDebug() << "Processing column " << col << "." << endl;
ColumnFormat* format = sheet->nonDefaultColumnFormat(col);
process(format);
// TODO Stefan: process cells with this property
}
}
else if (m_format && element->isRow())
{
for (int row = range.top(); row <= range.bottom(); ++row)
{
kdDebug() << "Processing row " << row << "." << endl;
RowFormat* format = sheet->nonDefaultRowFormat(row);
process(format);
// TODO Stefan: process cells with this property
}
}
else
{
kdDebug() << "Processing cell(s) at " << range << "." << endl;
for (int col = range.left(); col <= range.right(); ++col)
{
sheet->enableScrollBarUpdates(false);
for (int row = range.top(); row <= range.bottom(); ++row)
{
Cell* cell = sheet->cellAt(col, row);
/* (Tomas) don't force working on obscurring cells - most manipulators don't want this, and those that do can do that manually ... Plus I think that no manipulator should do it anyway ...
if ( cell->isPartOfMerged() )
{
cell = cell->obscuringCells().first();
}
*/
//if (testCondition(cell))
{
if (cell == sheet->defaultCell() && m_creation)
{
Style* style = sheet->doc()->styleManager()->defaultStyle();
cell = new Cell(sheet, style, col, row);
sheet->insertCell(cell);
}
if (!process(cell))
{
return false;
}
}
}
sheet->enableScrollBarUpdates(true);
sheet->checkRangeVBorder(range.bottom());
}
sheet->checkRangeHBorder(range.right());
}
return true;
}
/***************************************************************************
class FormatManipulator
****************************************************************************/
FormatManipulator::FormatManipulator()
{
m_properties = 0;
// initialize pens with invalid color
m_topBorderPen = TQPen(TQColor(), 0, TQt::NoPen);
m_bottomBorderPen = TQPen(TQColor(), 0, TQt::NoPen);
m_leftBorderPen = TQPen(TQColor(), 0, TQt::NoPen);
m_rightBorderPen = TQPen(TQColor(), 0, TQt::NoPen);
m_horizontalPen = TQPen(TQColor(), 0, TQt::NoPen);
m_verticalPen = TQPen(TQColor(), 0, TQt::NoPen);
m_fallDiagonalPen = TQPen(TQColor(), 0, TQt::NoPen);
m_goUpDiagonalPen = TQPen(TQColor(), 0, TQt::NoPen);
}
FormatManipulator::~FormatManipulator()
{
TQValueList<layoutCell>::Iterator it2;
for ( it2 = m_lstFormats.begin(); it2 != m_lstFormats.end(); ++it2 )
{
delete (*it2).l;
}
m_lstFormats.clear();
for ( it2 = m_lstRedoFormats.begin(); it2 != m_lstRedoFormats.end(); ++it2 )
{
delete (*it2).l;
}
m_lstRedoFormats.clear();
TQValueList<layoutColumn>::Iterator it3;
for ( it3 = m_lstColFormats.begin(); it3 != m_lstColFormats.end(); ++it3 )
{
delete (*it3).l;
}
m_lstColFormats.clear();
for ( it3 = m_lstRedoColFormats.begin(); it3 != m_lstRedoColFormats.end(); ++it3 )
{
delete (*it3).l;
}
m_lstRedoColFormats.clear();
TQValueList<layoutRow>::Iterator it4;
for ( it4 = m_lstRowFormats.begin(); it4 != m_lstRowFormats.end(); ++it4 )
{
delete (*it4).l;
}
m_lstRowFormats.clear();
for ( it4 = m_lstRedoRowFormats.begin(); it4 != m_lstRedoRowFormats.end(); ++it4 )
{
delete (*it4).l;
}
m_lstRedoRowFormats.clear();
}
bool FormatManipulator::preProcessing ()
{
if (m_reverse)
copyFormat (m_lstRedoFormats, m_lstRedoColFormats, m_lstRedoRowFormats);
else
copyFormat (m_lstFormats, m_lstColFormats, m_lstRowFormats);
return true;
}
bool FormatManipulator::process (Element *element)
{
// see what is selected; if nothing, take marker position
TQRect range = element->rect().normalize();
if (!m_reverse) {
int top = range.top();
int left = range.left();
int bottom = range.bottom();
int right = range.right();
// create cells in rows if complete columns selected
Cell * cell;
if ( element->isColumn() )
{
for ( RowFormat * row = m_sheet->firstRow(); row; row = row->next() )
{
if ( !row->isDefault() )
{
for ( int col = left; col <= right; ++col )
{
cell = m_sheet->nonDefaultCell( col, row->row() );
}
}
}
}
// complete rows selected ?
if ( element->isRow() )
{
for ( int row = top; row <= bottom; ++row )
{
cell = m_sheet->getFirstCellRow( row );
while ( cell )
{
prepareCell( cell );
cell = m_sheet->getNextCellRight( cell->column(), row );
}
RowFormat * rowFormat = m_sheet->nonDefaultRowFormat(row);
doWork(rowFormat, row==top, row==bottom, false, false);
}
}
// complete columns selected ?
else if ( element->isColumn() )
{
for ( int col = left; col <= right; ++col )
{
cell = m_sheet->getFirstCellColumn( col );
while ( cell )
{
prepareCell( cell );
cell = m_sheet->getNextCellDown( col, cell->row() );
}
ColumnFormat * colFormat = m_sheet->nonDefaultColumnFormat( col );
doWork(colFormat, false, false, col==left, col==right);
}
for ( RowFormat * rowFormat = m_sheet->firstRow(); rowFormat; rowFormat = rowFormat->next() )
{
if ( !rowFormat->isDefault() && testCondition( rowFormat ) )
{
for ( int col = left; col <= right; ++col )
{
cell = m_sheet->nonDefaultCell(col, rowFormat->row() );
doWork(cell->format(), false, false, col==left, col==right );
}
}
}
}
// cell region selected
else
{
for ( int col = left; col <= right; ++col )
{
for ( int row = top; row <= bottom; ++row )
{
cell = m_sheet->nonDefaultCell(col,row);
if ( !cell->isPartOfMerged() )
{
cell->setDisplayDirtyFlag();
doWork(cell->format(), row==top, row==bottom, col==left, col==right);
cell->clearDisplayDirtyFlag();
}
}
}
}
}
else
{ // undoing
if( element->isColumn() )
{
TQValueList<layoutColumn>::Iterator it2;
for ( it2 = m_lstColFormats.begin(); it2 != m_lstColFormats.end(); ++it2 )
{
ColumnFormat * col = m_sheet->nonDefaultColumnFormat( (*it2).col );
col->copy( *(*it2).l );
}
}
else if( element->isRow() )
{
TQValueList<layoutRow>::Iterator it2;
for ( it2 = m_lstRowFormats.begin(); it2 != m_lstRowFormats.end(); ++it2 )
{
RowFormat * row = m_sheet->nonDefaultRowFormat( (*it2).row );
row->copy( *(*it2).l );
}
}
TQValueList<layoutCell>::Iterator it2;
for ( it2 = m_lstFormats.begin(); it2 != m_lstFormats.end(); ++it2 )
{
Cell *cell = m_sheet->nonDefaultCell( (*it2).col,(*it2).row );
cell->format()->copy( *(*it2).l );
cell->setLayoutDirtyFlag();
cell->setDisplayDirtyFlag();
m_sheet->updateCell( cell, (*it2).col, (*it2).row );
}
}
return true;
}
void FormatManipulator::copyFormat(TQValueList<layoutCell> & list,
TQValueList<layoutColumn> & listCol,
TQValueList<layoutRow> & listRow)
{
TQValueList<layoutCell>::Iterator end = list.end();
for (TQValueList<layoutCell>::Iterator it2 = list.begin(); it2 != end; ++it2)
{
delete (*it2).l;
}
list.clear();
Cell * cell;
Region::ConstIterator endOfList(cells().constEnd());
for (Region::ConstIterator it = cells().constBegin(); it != endOfList; ++it)
{
TQRect range = (*it)->rect().normalize();
int bottom = range.bottom();
int right = range.right();
if ( (*it)->isColumn() )
{
/* Don't need to go through the loop twice...
for (int i = range.left(); i <= right; ++i)
{
layoutColumn tmplayout;
tmplayout.col = i;
tmplayout.l = new ColumnFormat( m_sheet, i );
tmplayout.l->copy( *(m_sheet->columnFormat( i )) );
listCol.append(tmplayout);
}
*/
for ( int col = range.left(); col <= right; ++col )
{
layoutColumn tmplayout;
tmplayout.col = col;
tmplayout.l = new ColumnFormat( m_sheet, col );
tmplayout.l->copy( *(m_sheet->columnFormat( col )) );
listCol.append(tmplayout);
cell = m_sheet->getFirstCellColumn( col );
while ( cell )
{
if ( cell->isPartOfMerged() )
{
cell = m_sheet->getNextCellDown( col, cell->row() );
continue;
}
layoutCell tmplayout;
tmplayout.col = col;
tmplayout.row = cell->row();
tmplayout.l = new Format( m_sheet, 0 );
tmplayout.l->copy( *(m_sheet->cellAt( tmplayout.col, tmplayout.row )->format()) );
list.append(tmplayout);
cell = m_sheet->getNextCellDown( col, cell->row() );
}
}
/*
Cell * cell = m_sheet->firstCell();
for( ; cell; cell = cell->nextCell() )
{
int col = cell->column();
if ( range.left() <= col && right >= col
&& !cell->isPartOfMerged())
{
layoutCell tmplayout;
tmplayout.col = cell->column();
tmplayout.row = cell->row();
tmplayout.l = new Format( m_sheet, 0 );
tmplayout.l->copy( *(m_sheet->cellAt( tmplayout.col, tmplayout.row )) );
list.append(tmplayout);
}
}
*/
}
else if ((*it)->isRow())
{
for ( int row = range.top(); row <= bottom; ++row )
{
layoutRow tmplayout;
tmplayout.row = row;
tmplayout.l = new RowFormat( m_sheet, row );
tmplayout.l->copy( *(m_sheet->rowFormat( row )) );
listRow.append(tmplayout);
cell = m_sheet->getFirstCellRow( row );
while ( cell )
{
if ( cell->isPartOfMerged() )
{
cell = m_sheet->getNextCellRight( cell->column(), row );
continue;
}
layoutCell tmplayout;
tmplayout.col = cell->column();
tmplayout.row = row;
tmplayout.l = new Format( m_sheet, 0 );
tmplayout.l->copy( *(m_sheet->cellAt( cell->column(), row )->format()) );
list.append(tmplayout);
cell = m_sheet->getNextCellRight( cell->column(), row );
}
}
/*
Cell * cell = m_sheet->firstCell();
for( ; cell; cell = cell->nextCell() )
{
int row = cell->row();
if ( range.top() <= row && bottom >= row
&& !cell->isPartOfMerged())
{
layoutCell tmplayout;
tmplayout.col = cell->column();
tmplayout.row = cell->row();
tmplayout.l = new Format( m_sheet, 0 );
tmplayout.l->copy( *(m_sheet->cellAt( tmplayout.col, tmplayout.row )) );
list.append(tmplayout);
}
}
*/
}
else
{
for ( int row = range.top(); row <= bottom; ++row )
for ( int col = range.left(); col <= right; ++col )
{
Cell * cell = m_sheet->nonDefaultCell( col, row );
if ( !cell->isPartOfMerged() )
{
layoutCell tmplayout;
tmplayout.col = col;
tmplayout.row = row;
tmplayout.l = new Format( m_sheet, 0 );
tmplayout.l->copy( *(m_sheet->cellAt( col, row )->format()) );
list.append(tmplayout);
}
}
}
}
}
bool FormatManipulator::testCondition(RowFormat* row)
{
for (TQ_UINT32 property = Format::PAlign;
property <= Format::PHideFormula;
property *= 2)
{
if (m_properties & property)
{
return ( row->hasProperty((Format::Properties) property) );
}
}
return false;
}
void FormatManipulator::doWork(Format* format,
bool isTop, bool isBottom,
bool isLeft, bool isRight)
{
// SetSelectionFontWorker
// SetSelectionSizeWorker
if (m_properties & Format::PFont)
{
if ( !m_font.isEmpty() )
format->setTextFontFamily( m_font );
if ( m_size > 0 )
format->setTextFontSize( m_size );
if ( m_italic >= 0 )
format->setTextFontItalic( (bool)m_italic );
if ( m_bold >= 0 )
format->setTextFontBold( (bool)m_bold );
if ( m_underline >= 0 )
format->setTextFontUnderline( (bool)m_underline );
if ( m_strike >= 0 )
format->setTextFontStrike( (bool)m_strike );
}
// SetSelectionAngleWorker
if (m_properties & Format::PAngle)
{
format->setAngle( m_angle );
}
// SetSelectionTextColorWorker
if (m_properties & Format::PTextPen)
{
format->setTextColor( m_textColor );
}
// SetSelectionBgColorWorker
if (m_properties & Format::PBackgroundColor)
{
format->setBgColor( m_backgroundColor );
}
// SetSelectionBorderAllWorker
if (m_properties & Format::PLeftBorder)
{
if (isLeft)
{
if (m_leftBorderPen.color().isValid())
{
format->setLeftBorderPen(m_leftBorderPen);
}
}
else
{
if (m_verticalPen.color().isValid())
{
format->setLeftBorderPen(m_verticalPen);
}
}
}
if (m_properties & Format::PRightBorder)
{
if (isRight)
{
if (m_rightBorderPen.color().isValid())
{
format->setRightBorderPen(m_rightBorderPen);
}
}
else
{
if (m_verticalPen.color().isValid())
{
format->setRightBorderPen(m_verticalPen);
}
}
}
if (m_properties & Format::PTopBorder)
{
if (isTop)
{
if (m_topBorderPen.color().isValid())
{
format->setTopBorderPen(m_topBorderPen);
}
}
else
{
if (m_horizontalPen.color().isValid())
{
format->setTopBorderPen(m_horizontalPen);
}
}
}
if (m_properties & Format::PBottomBorder)
{
if (isBottom)
{
if (m_bottomBorderPen.color().isValid())
{
format->setBottomBorderPen(m_bottomBorderPen);
}
}
else
{
if (m_horizontalPen.color().isValid())
{
format->setBottomBorderPen(m_horizontalPen);
}
}
}
if (m_properties & Format::PFallDiagonal)
{
format->setFallDiagonalPen(m_fallDiagonalPen);
}
if (m_properties & Format::PGoUpDiagonal)
{
format->setGoUpDiagonalPen(m_goUpDiagonalPen);
}
// SetSelectionAlignWorker
if (m_properties & Format::PAlign)
{
format->setAlign( m_horAlign );
}
// SetSelectionAlignYWorker
if (m_properties & Format::PAlignY)
{
format->setAlignY( m_verAlign );
}
if (m_properties & Format::PPrefix)
{
format->setPrefix(m_prefix);
}
if (m_properties & Format::PPostfix)
{
format->setPostfix(m_postfix);
}
if (m_properties & Format::PBackgroundBrush)
{
format->setBackGroundBrush(m_backgroundBrush);
}
if (m_properties & Format::PFloatFormat)
{
format->setFloatFormat(m_floatFormat);
}
if (m_properties & Format::PFloatColor)
{
format->setFloatColor(m_floatColor);
}
if (m_properties & Format::PMultiRow)
{
format->setMultiRow(m_multiRow);
}
if (m_properties & Format::PVerticalText)
{
format->setVerticalText(m_verticalText);
}
if (m_properties & Format::PPrecision)
{
format->setPrecision(m_precision);
}
if (m_properties & Format::PFormatType)
{
format->setFormatType(m_formatType);
if (m_formatType == Money_format)
{
format->setCurrency(m_currencyType, m_currencySymbol);
}
}
if (m_properties & Format::PComment)
{
format->setComment(m_comment);
}
if (m_properties & Format::PIndent)
{
format->setIndent(m_indent);
}
if (m_properties & Format::PDontPrintText)
{
format->setDontPrintText(m_dontPrintText);
}
if (m_properties & Format::PCustomFormat)
{
//TODO
}
if (m_properties & Format::PNotProtected)
{
format->setNotProtected(m_notProtected);
}
if (m_properties & Format::PHideAll)
{
format->setHideAll(m_hideAll);
}
if (m_properties & Format::PHideFormula)
{
format->setHideFormula(m_hideFormula);
}
}
void FormatManipulator::prepareCell(Cell* cell)
{
for (TQ_UINT32 property = Format::PAlign;
property <= Format::PHideFormula;
property *= 2)
{
if (m_properties & property)
{
cell->format()->clearProperty((Format::Properties) property);
cell->format()->clearNoFallBackProperties((Format::Properties) property);
}
}
}
/***************************************************************************
class MergeManipulator
****************************************************************************/
MergeManipulator::MergeManipulator()
: Manipulator(),
m_merge(true),
m_mergeHorizontal(false),
m_mergeVertical(false),
m_unmerger(0)
{
}
MergeManipulator::~MergeManipulator()
{
delete m_unmerger;
}
bool MergeManipulator::process(Element* element)
{
if (element->type() != Element::Range || element->isRow() || element->isColumn())
{
// TODO Stefan: remove these elements?!
return true;
}
// sanity check
if( m_sheet->isProtected() || m_sheet->workbook()->isProtected() )
{
return false;
}
TQRect range = element->rect().normalize();
int left = range.left();
int right = range.right();
int top = range.top();
int bottom = range.bottom();
int height = range.height();
int width = range.width();
bool doMerge = m_reverse ? (!m_merge) : m_merge;
if (doMerge)
{
if (m_mergeHorizontal)
{
for (int row = top; row <= bottom; ++row)
{
int rows = 0;
for (int col = left; col <= right; ++col)
{
Cell *cell = m_sheet->cellAt( col, row );
if (cell->doesMergeCells())
{
rows = TQMAX(rows, cell->mergedYCells());
cell->mergeCells( col, row, 0, 0 );
}
}
Cell *cell = m_sheet->nonDefaultCell( left, row );
if (!cell->isPartOfMerged())
{
cell->mergeCells( left, row, width - 1, rows );
}
}
}
else if (m_mergeVertical)
{
for (int col = left; col <= right; ++col)
{
int cols = 0;
for (int row = top; row <= bottom; ++row)
{
Cell *cell = m_sheet->cellAt( col, row );
if (cell->doesMergeCells())
{
cols = TQMAX(cols, cell->mergedXCells());
cell->mergeCells( col, row, 0, 0 );
}
}
Cell *cell = m_sheet->nonDefaultCell( col, top );
if (!cell->isPartOfMerged())
{
cell->mergeCells( col, top, cols, height - 1);
}
}
}
else
{
Cell *cell = m_sheet->nonDefaultCell( left, top );
cell->mergeCells( left, top, width - 1, height - 1);
}
}
else // dissociate
{
for (int col = left; col <= right; ++col)
{
for (int row = top; row <= bottom; ++row)
{
Cell *cell = m_sheet->cellAt( col, row );
if (!cell->doesMergeCells())
{
continue;
}
cell->mergeCells( col, row, 0, 0 );
}
}
}
return true;
}
TQString MergeManipulator::name() const
{
if (m_merge) // MergeManipulator
{
if (m_mergeHorizontal)
{
return i18n("Merge Cells Horizontally");
}
else if (m_mergeVertical)
{
return i18n("Merge Cells Vertically");
}
else
{
return i18n("Merge Cells");
}
}
return i18n("Dissociate Cells");
}
bool MergeManipulator::preProcessing()
{
if (isColumnOrRowSelected())
{
KMessageBox::information( 0, i18n( "Merging of columns or rows is not supported." ) );
return false;
}
if (m_firstrun)
{
// reduce the region to the region occupied by merged cells
Region mergedCells;
ConstIterator endOfList = constEnd();
for (ConstIterator it = constBegin(); it != endOfList; ++it)
{
Element* element = *it;
TQRect range = element->rect().normalize();
int right = range.right();
int bottom = range.bottom();
for (int row = range.top(); row <= bottom; ++row)
{
for (int col = range.left(); col <= right; ++col)
{
Cell *cell = m_sheet->cellAt(col, row);
if (cell->doesMergeCells())
{
TQRect rect(col, row, cell->mergedXCells() + 1, cell->mergedYCells() + 1);
mergedCells.add(rect);
}
}
}
}
if (m_merge) // MergeManipulator
{
// we're in the manipulator's first execution
// initialize the undo manipulator
m_unmerger = new MergeManipulator();
if (!m_mergeHorizontal && !m_mergeVertical)
{
m_unmerger->setReverse(true);
}
m_unmerger->setSheet(m_sheet);
m_unmerger->setRegisterUndo(false);
m_unmerger->add(mergedCells);
}
else // DissociateManipulator
{
clear();
add(mergedCells);
}
}
if (m_merge) // MergeManipulator
{
if (m_reverse) // dissociate
{
}
else // merge
{
// Dissociate cells before merging the whole region.
// For horizontal/vertical merging the cells stay
// as they are. E.g. the region contains a merged cell
// occupying two rows. Then the horizontal merge should
// keep the height of two rows and extend the merging to the
// region's width. In this case the unmerging is done while
// processing each region element.
if (!m_mergeHorizontal && !m_mergeVertical)
{
m_unmerger->execute();
}
}
}
return true;
}
bool MergeManipulator::postProcessing()
{
if (m_merge) // MergeManipulator
{
if (m_reverse) // dissociate
{
// restore the old merge status
if (m_mergeHorizontal || m_mergeVertical)
{
m_unmerger->execute();
}
else
{
m_unmerger->unexecute();
}
}
}
if (!m_reverse)
{
if (m_sheet->getAutoCalc())
{
m_sheet->recalc();
}
}
else
{
m_sheet->refreshMergedCell();
}
return true;
}
/***************************************************************************
class DilationManipulator
****************************************************************************/
DilationManipulator::DilationManipulator()
: Manipulator()
{
}
DilationManipulator::~DilationManipulator()
{
}
void DilationManipulator::execute()
{
Region extendedRegion;
ConstIterator end(cells().constEnd());
for (ConstIterator it = cells().constBegin(); it != end; ++it)
{
Element* element = *it;
TQRect area = element->rect().normalize();
ColumnFormat *col;
RowFormat *rl;
//look at if column is hiding.
//if it's hiding refreshing column+1 (or column -1 )
int left = area.left();
int right = area.right();
int top = area.top();
int bottom = area.bottom();
// a merged cells is selected
if (element->type() == Region::Element::Point)
{
Cell* cell = m_sheet->cellAt(left, top);
if (cell->doesMergeCells())
{
// extend to the merged region
// prevents artefacts of the selection rectangle
right += cell->mergedXCells();
bottom += cell->mergedYCells();
}
}
if ( right < KS_colMax )
{
do
{
right++;
col = m_sheet->columnFormat( right );
} while ( col->isHide() && right != KS_colMax );
}
if ( left > 1 )
{
do
{
left--;
col = m_sheet->columnFormat( left );
} while ( col->isHide() && left != 1);
}
if ( bottom < KS_rowMax )
{
do
{
bottom++;
rl = m_sheet->rowFormat( bottom );
} while ( rl->isHide() && bottom != KS_rowMax );
}
if ( top > 1 )
{
do
{
top--;
rl = m_sheet->rowFormat( top );
} while ( rl->isHide() && top != 1);
}
area.setLeft(left);
area.setRight(right);
area.setTop(top);
area.setBottom(bottom);
extendedRegion.add(area, element->sheet());
}
clear();
add(extendedRegion);
}
void DilationManipulator::unexecute()
{
kdError() << "DilationManipulator::unexecute(): "
<< "An undo of dilating a region is not possible." << endl;
}
/***************************************************************************
class ResizeColumnManipulator
****************************************************************************/
ResizeColumnManipulator::ResizeColumnManipulator()
{
}
ResizeColumnManipulator::~ResizeColumnManipulator()
{
}
bool ResizeColumnManipulator::process(Element* element)
{
TQRect range = element->rect().normalize();
for (int col = range.right(); col >= range.left(); --col)
{
ColumnFormat *format = m_sheet->nonDefaultColumnFormat( col );
format->setDblWidth( TQMAX( 2.0, m_reverse ? m_oldSize : m_newSize ) );
}
return true;
}
/***************************************************************************
class ResizeRowManipulator
****************************************************************************/
ResizeRowManipulator::ResizeRowManipulator()
{
}
ResizeRowManipulator::~ResizeRowManipulator()
{
}
bool ResizeRowManipulator::process(Element* element)
{
TQRect range = element->rect().normalize();
for (int row = range.bottom(); row >= range.top(); --row)
{
RowFormat* rl = m_sheet->nonDefaultRowFormat( row );
rl->setDblHeight( TQMAX( 2.0, m_reverse ? m_oldSize : m_newSize ) );
}
return true;
}
/***************************************************************************
class AdjustColumnRowManipulator
****************************************************************************/
AdjustColumnRowManipulator::AdjustColumnRowManipulator()
: Manipulator(),
m_adjustColumn(false),
m_adjustRow(false)
{
}
AdjustColumnRowManipulator::~AdjustColumnRowManipulator()
{
}
bool AdjustColumnRowManipulator::process(Element* element)
{
Sheet* sheet = m_sheet; // TODO Stefan: element->sheet();
if (m_sheet && sheet != m_sheet)
{
return true;
}
TQMap<int,double> heights;
TQMap<int,double> widths;
if (m_reverse)
{
heights = m_oldHeights;
widths = m_oldWidths;
}
else
{
heights = m_newHeights;
widths = m_newWidths;
}
TQRect range = element->rect().normalize();
if (m_adjustColumn)
{
if (element->isRow())
{
for (int row = range.top(); row <= range.bottom(); ++row)
{
Cell* cell = sheet->getFirstCellRow( row );
while ( cell )
{
int col = cell->column();
if ( !cell->isEmpty() && !cell->isObscured())
{
if (widths.contains(col) && widths[col] != -1.0)
{
ColumnFormat* format = sheet->nonDefaultColumnFormat(col);
if ( kAbs(format->dblWidth() - widths[col] ) > DBL_EPSILON )
{
format->setDblWidth( TQMAX( 2.0, widths[col] ) );
}
}
}
cell = sheet->getNextCellRight(col, row);
}
}
}
else
{
for (int col = range.left(); col <= range.right(); ++col)
{
if (widths.contains(col) && widths[col] != -1.0)
{
ColumnFormat* format = sheet->nonDefaultColumnFormat(col);
if ( kAbs(format->dblWidth() - widths[col] ) > DBL_EPSILON )
{
format->setDblWidth( TQMAX( 2.0, widths[col] ) );
}
}
}
}
}
if (m_adjustRow)
{
if (element->isColumn())
{
for (int col = range.left(); col <= range.right(); ++col)
{
Cell* cell = sheet->getFirstCellColumn( col );
while ( cell )
{
int row = cell->row();
if ( !cell->isEmpty() && !cell->isObscured())
{
if (heights.contains(row) && heights[row] != -1.0)
{
RowFormat* format = sheet->nonDefaultRowFormat(row);
if ( kAbs(format->dblHeight() - heights[row] ) > DBL_EPSILON )
{
format->setDblHeight( TQMAX( 2.0, heights[row] ) );
}
}
}
cell = sheet->getNextCellDown( col, row );
}
}
}
else
{
for (int row = range.top(); row <= range.bottom(); ++row)
{
if (heights.contains(row) && heights[row] != -1.0)
{
RowFormat* format = sheet->nonDefaultRowFormat(row);
if ( kAbs(format->dblHeight() - heights[row] ) > DBL_EPSILON )
{
format->setDblHeight( TQMAX( 2.0, heights[row] ) );
}
}
}
}
}
return true;
}
bool AdjustColumnRowManipulator::preProcessing()
{
if (m_reverse)
{
}
else
{
if (!m_newHeights.isEmpty() || !m_newWidths.isEmpty())
{
return true;
}
// createUndo();
ConstIterator endOfList(cells().end());
for (ConstIterator it = cells().begin(); it != endOfList; ++it)
{
Element* element = *it;
TQRect range = element->rect().normalize();
if (element->isColumn())
{
for (int col = range.left(); col <= range.right(); ++col)
{
Cell* cell = m_sheet->getFirstCellColumn( col );
while ( cell )
{
int row = cell->row();
if (m_adjustColumn)
{
if (!m_newWidths.contains(col))
{
m_newWidths[col] = -1.0;
ColumnFormat* format = m_sheet->columnFormat(col);
m_oldWidths[col] = format->dblWidth();
}
if (!cell->isEmpty() && !cell->isObscured())
{
m_newWidths[col] = TQMAX(adjustColumnHelper(cell, col, row),
m_newWidths[col] );
}
}
if (m_adjustRow)
{
if (!m_newHeights.contains(row))
{
m_newHeights[row] = -1.0;
RowFormat* format = m_sheet->rowFormat(row);
m_oldHeights[row] = format->dblHeight();
}
if (!cell->isEmpty() && !cell->isObscured())
{
m_newHeights[row] = TQMAX(adjustRowHelper(cell, col, row),
m_newHeights[row]);
}
}
cell = m_sheet->getNextCellDown( col, row );
}
}
}
else if (element->isRow())
{
for (int row = range.top(); row <= range.bottom(); ++row)
{
Cell* cell = m_sheet->getFirstCellRow( row );
while ( cell )
{
int col = cell->column();
if (m_adjustColumn)
{
if (!m_newWidths.contains(col))
{
m_newWidths[col] = -1.0;
ColumnFormat* format = m_sheet->columnFormat(col);
m_oldWidths[col] = format->dblWidth();
}
if (cell != m_sheet->defaultCell() && !cell->isEmpty() && !cell->isObscured())
{
m_newWidths[col] = TQMAX(adjustColumnHelper(cell, col, row),
m_newWidths[col] );
}
}
if (m_adjustRow)
{
if (!m_newHeights.contains(row))
{
m_newHeights[row] = -1.0;
RowFormat* format = m_sheet->rowFormat(row);
m_oldHeights[row] = format->dblHeight();
}
if (cell != m_sheet->defaultCell() && !cell->isEmpty() && !cell->isObscured())
{
m_newHeights[row] = TQMAX(adjustRowHelper(cell, col, row),
m_newHeights[row]);
}
}
cell = m_sheet->getNextCellRight(col, row);
}
}
}
else
{
Cell* cell;
for (int col = range.left(); col <= range.right(); ++col)
{
for ( int row = range.top(); row <= range.bottom(); ++row )
{
cell = m_sheet->cellAt( col, row );
if (m_adjustColumn)
{
if (!m_newWidths.contains(col))
{
m_newWidths[col] = -1.0;
ColumnFormat* format = m_sheet->columnFormat(col);
m_oldWidths[col] = format->dblWidth();
}
if (cell != m_sheet->defaultCell() && !cell->isEmpty() && !cell->isObscured())
{
m_newWidths[col] = TQMAX(adjustColumnHelper(cell, col, row),
m_newWidths[col] );
}
}
if (m_adjustRow)
{
if (!m_newHeights.contains(row))
{
m_newHeights[row] = -1.0;
RowFormat* format = m_sheet->rowFormat(row);
m_oldHeights[row] = format->dblHeight();
}
if (cell != m_sheet->defaultCell() && !cell->isEmpty() && !cell->isObscured())
{
m_newHeights[row] = TQMAX(adjustRowHelper(cell, col, row),
m_newHeights[row]);
}
}
}
}
}
}
}
return true;
}
double AdjustColumnRowManipulator::adjustColumnHelper(Cell* cell, int col, int row )
{
double long_max = 0.0;
cell->calculateTextParameters( m_sheet->painter(), col, row );
if ( cell->textWidth() > long_max )
{
double indent = 0.0;
Format::Align alignment = cell->format()->align(cell->column(), cell->row());
if (alignment == Format::Undefined)
{
if (cell->value().isNumber() || cell->isDate() || cell->isTime())
{
alignment = Format::Right;
}
else
{
alignment = Format::Left;
}
}
if (alignment == Format::Left)
{
indent = cell->format()->getIndent( cell->column(), cell->row() );
}
long_max = indent + cell->textWidth()
+ cell->format()->leftBorderWidth( cell->column(), cell->row() )
+ cell->format()->rightBorderWidth( cell->column(), cell->row() );
}
// add 4 because long_max is the length of the text
// but column has borders
if ( long_max == 0.0 )
{
return -1.0;
}
else
{
return long_max + 4;
}
}
double AdjustColumnRowManipulator::adjustRowHelper(Cell* cell, int col, int row)
{
double long_max = 0.0;
cell->calculateTextParameters( m_sheet->painter(), col, row);
if ( cell->textHeight() > long_max )
{
long_max = cell->textHeight()
+ cell->format()->topBorderWidth(col, row)
+ cell->format()->bottomBorderWidth(col, row);
}
// add 1 because long_max is the height of the text
// but row has borders
if ( long_max == 0.0 )
{
return -1.0;
}
else
{
return long_max + 1;
}
}
TQString AdjustColumnRowManipulator::name() const
{
if (m_adjustColumn && m_adjustRow)
{
return i18n("Adjust Columns/Rows");
}
else if (m_adjustColumn)
{
return i18n("Adjust Columns");
}
else
{
return i18n("Adjust Rows");
}
}
/***************************************************************************
class HideShowManipulator
****************************************************************************/
HideShowManipulator::HideShowManipulator()
: m_manipulateColumns(false),
m_manipulateRows(false)
{
}
HideShowManipulator::~HideShowManipulator()
{
}
bool HideShowManipulator::process(Element* element)
{
TQRect range = element->rect().normalize();
if (m_manipulateColumns)
{
for (int col = range.left(); col <= range.right(); ++col)
{
ColumnFormat* format = m_sheet->nonDefaultColumnFormat(col);
format->setHide(!m_reverse);
}
}
if (m_manipulateRows)
{
for (int row = range.top(); row <= range.bottom(); ++row)
{
RowFormat* format = m_sheet->nonDefaultRowFormat(row);
format->setHide(!m_reverse);
}
}
return true;
}
bool HideShowManipulator::preProcessing()
{
Region region;
ConstIterator endOfList = cells().constEnd();
for (ConstIterator it = cells().constBegin(); it != endOfList; ++it)
{
if (m_reverse)
{
TQRect range = (*it)->rect().normalize();
if (m_manipulateColumns)
{
if (range.left() > 1)
{
int col;
for (col = 1; col < range.left(); ++col)
{
ColumnFormat* format = m_sheet->columnFormat(col);
if (!format->isHide())
{
break;
}
}
if (col == range.left())
{
region.add(TQRect(1, 1, range.left()-1, KS_rowMax));
}
}
for (int col = range.left(); col <= range.right(); ++col)
{
ColumnFormat* format = m_sheet->columnFormat(col);
if (format->isHide())
{
region.add(TQRect(col, 1, 1, KS_rowMax));
}
}
}
if (m_manipulateRows)
{
if (range.top() > 1)
{
int row;
for (row = 1; row < range.top(); ++row)
{
RowFormat* format = m_sheet->rowFormat(row);
if (!format->isHide())
{
break;
}
}
if (row == range.top())
{
region.add(TQRect(1, 1, KS_colMax, range.top()-1));
}
}
for (int row = range.top(); row <= range.bottom(); ++row)
{
RowFormat* format = m_sheet->rowFormat(row);
if (format->isHide())
{
region.add(TQRect(1, row, KS_colMax, 1));
}
}
}
}
if (((*it)->isRow() && m_manipulateColumns) ||
((*it)->isColumn() && m_manipulateRows))
{
/* KMessageBox::error( this, i18n( "Area is too large." ) );*/
return false;
}
}
if (m_reverse)
{
clear();
add(region);
}
return true;
}
bool HideShowManipulator::postProcessing()
{
if (m_manipulateColumns)
{
m_sheet->emitHideColumn();
}
if (m_manipulateRows)
{
m_sheet->emitHideRow();
}
return true;
}
TQString HideShowManipulator::name() const
{
TQString name;
if (m_reverse)
{
name = "Show ";
}
else
{
name = "Hide ";
}
if (m_manipulateColumns)
{
name += "Columns";
}
if (m_manipulateColumns && m_manipulateRows)
{
name += "/";
}
if (m_manipulateRows)
{
name += "Rows";
}
return name;
}
/***************************************************************************
class ManipulatorManager
****************************************************************************/
ManipulatorManager* ManipulatorManager::m_self = 0;
static KStaticDeleter<ManipulatorManager> staticManipulatorManagerDeleter;
ManipulatorManager* ManipulatorManager::self()
{
if (!m_self)
{
staticManipulatorManagerDeleter.setObject(m_self, new ManipulatorManager());
}
return m_self;
}
ManipulatorManager::ManipulatorManager()
{
}
ManipulatorManager::~ManipulatorManager()
{
}
Manipulator* ManipulatorManager::create(const TQString& type)
{
if (type == "bgcolor")
{
kdDebug() << "Background color manipulator created." << endl;
// return new FontColorManipulator();
}
else if (type == "textcolor")
{
kdDebug() << "Text color manipulator created." << endl;
// return new FontColorManipulator();
}
// no manipulator of this type found
kdError() << "Unknown manipulator!" << endl;
return 0;
}