/* This file is part of the KDE project Copyright (C) 2005 Stefan Nikolaus 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 #include #include #include #include #include #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::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::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::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::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::Iterator it2; for ( it2 = m_lstRowFormats.begin(); it2 != m_lstRowFormats.end(); ++it2 ) { RowFormat * row = m_sheet->nonDefaultRowFormat( (*it2).row ); row->copy( *(*it2).l ); } } TQValueList::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 & list, TQValueList & listCol, TQValueList & listRow) { TQValueList::Iterator end = list.end(); for (TQValueList::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 heights; TQMap 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 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; }