diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kspread/manipulator.cc | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kspread/manipulator.cc')
-rw-r--r-- | kspread/manipulator.cc | 1723 |
1 files changed, 1723 insertions, 0 deletions
diff --git a/kspread/manipulator.cc b/kspread/manipulator.cc new file mode 100644 index 00000000..0bca8c81 --- /dev/null +++ b/kspread/manipulator.cc @@ -0,0 +1,1723 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Stefan Nikolaus <[email protected]> + + 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 <qcolor.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.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; + } + + QRect 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 = QPen(QColor(), 0, Qt::NoPen); + m_bottomBorderPen = QPen(QColor(), 0, Qt::NoPen); + m_leftBorderPen = QPen(QColor(), 0, Qt::NoPen); + m_rightBorderPen = QPen(QColor(), 0, Qt::NoPen); + m_horizontalPen = QPen(QColor(), 0, Qt::NoPen); + m_verticalPen = QPen(QColor(), 0, Qt::NoPen); + m_fallDiagonalPen = QPen(QColor(), 0, Qt::NoPen); + m_goUpDiagonalPen = QPen(QColor(), 0, Qt::NoPen); +} + +FormatManipulator::~FormatManipulator() +{ + QValueList<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(); + + QValueList<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(); + + QValueList<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 + QRect 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() ) + { + QValueList<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() ) + { + QValueList<layoutRow>::Iterator it2; + for ( it2 = m_lstRowFormats.begin(); it2 != m_lstRowFormats.end(); ++it2 ) + { + RowFormat * row = m_sheet->nonDefaultRowFormat( (*it2).row ); + row->copy( *(*it2).l ); + } + } + + QValueList<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(QValueList<layoutCell> & list, + QValueList<layoutColumn> & listCol, + QValueList<layoutRow> & listRow) +{ + QValueList<layoutCell>::Iterator end = list.end(); + for (QValueList<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) + { + QRect 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 (Q_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 (Q_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; + } + + QRect 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 = QMAX(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 = QMAX(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; +} + +QString 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; + QRect 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()) + { + QRect 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; + QRect 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) +{ + QRect range = element->rect().normalize(); + for (int col = range.right(); col >= range.left(); --col) + { + ColumnFormat *format = m_sheet->nonDefaultColumnFormat( col ); + format->setDblWidth( QMAX( 2.0, m_reverse ? m_oldSize : m_newSize ) ); + } + return true; +} + + + +/*************************************************************************** + class ResizeRowManipulator +****************************************************************************/ + +ResizeRowManipulator::ResizeRowManipulator() +{ +} + +ResizeRowManipulator::~ResizeRowManipulator() +{ +} + +bool ResizeRowManipulator::process(Element* element) +{ + QRect range = element->rect().normalize(); + for (int row = range.bottom(); row >= range.top(); --row) + { + RowFormat* rl = m_sheet->nonDefaultRowFormat( row ); + rl->setDblHeight( QMAX( 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; + } + + QMap<int,double> heights; + QMap<int,double> widths; + if (m_reverse) + { + heights = m_oldHeights; + widths = m_oldWidths; + } + else + { + heights = m_newHeights; + widths = m_newWidths; + } + + QRect 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( QMAX( 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( QMAX( 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( QMAX( 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( QMAX( 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; + QRect 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] = QMAX(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] = QMAX(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] = QMAX(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] = QMAX(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] = QMAX(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] = QMAX(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; + } +} + +QString 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) +{ + QRect 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) + { + QRect 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(QRect(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(QRect(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(QRect(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(QRect(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; +} + +QString HideShowManipulator::name() const +{ + QString 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 QString& 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; +} |