summaryrefslogtreecommitdiffstats
path: root/kspread/selection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kspread/selection.cpp')
-rw-r--r--kspread/selection.cpp1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/kspread/selection.cpp b/kspread/selection.cpp
new file mode 100644
index 000000000..f05a6db50
--- /dev/null
+++ b/kspread/selection.cpp
@@ -0,0 +1,1009 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2005-2006 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, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <tqregexp.h>
+
+#include <kdebug.h>
+
+#include "kspread_canvas.h"
+#include "kspread_cell.h"
+#include "kspread_doc.h"
+#include "kspread_editors.h"
+#include "kspread_sheet.h"
+#include "kspread_view.h"
+#include "kspread_util.h"
+
+#include "selection.h"
+
+// TODO Stefan: Substract points in selections
+// TODO Stefan: KPart signal (kspread_events.h)
+
+using namespace KSpread;
+
+/***************************************************************************
+ class Selection::Private
+****************************************************************************/
+
+class Selection::Private
+{
+public:
+ Private(View *v)
+ {
+ view = v;
+ sheet = 0;
+ anchor = TQPoint(1,1);
+ cursor = TQPoint(1,1);
+ marker = TQPoint(1,1);
+
+ colors.push_back(TQt::red);
+ colors.push_back(TQt::blue);
+ colors.push_back(TQt::magenta);
+ colors.push_back(TQt::darkRed);
+ colors.push_back(TQt::darkGreen);
+ colors.push_back(TQt::darkMagenta);
+ colors.push_back(TQt::darkCyan);
+ colors.push_back(TQt::darkYellow);
+
+ multipleSelection = false;
+
+ activeElement = Iterator();
+ activeSubRegionStart = 0;
+ activeSubRegionLength = 0;
+ }
+
+ View* view;
+ Sheet* sheet;
+ TQPoint anchor;
+ TQPoint cursor;
+ TQPoint marker;
+ TQValueList<TQColor> colors;
+
+ bool multipleSelection : 1;
+
+ Selection::Iterator activeElement;
+ uint activeSubRegionStart;
+ uint activeSubRegionLength;
+};
+
+/***************************************************************************
+ class Selection
+****************************************************************************/
+namespace KSpread {
+
+Selection::Selection(View *view)
+ : TQObject(view), Region(1,1)
+{
+ d = new Private(view);
+ d->activeSubRegionStart = 0;
+ d->activeSubRegionLength = 1;
+}
+
+Selection::Selection(const Selection& selection)
+ : TQObject(selection.d->view), Region()
+{
+/* kdDebug() << k_funcinfo << endl;*/
+ d = new Private(selection.d->view);
+ d->sheet = selection.d->sheet;
+ d->activeSubRegionStart = 0;
+ d->activeSubRegionLength = cells().count();
+}
+
+Selection::~Selection()
+{
+ delete d;
+}
+
+void Selection::initialize(const TQPoint& point, Sheet* sheet)
+{
+ if (!util_isPointValid(point))
+ return;
+
+ if (!d->view->activeSheet())
+ return;
+
+ if (!sheet)
+ {
+ if (d->sheet)
+ {
+ sheet = d->sheet;
+ }
+ else
+ {
+ sheet = d->view->activeSheet();
+ }
+ }
+
+ Region changedRegion(*this);
+ changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
+
+ TQPoint topLeft(point);
+ Cell* cell = d->view->activeSheet()->cellAt(point);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ d->anchor = topLeft;
+ d->cursor = point;
+ d->marker = topLeft;
+
+ fixSubRegionDimension(); // TODO remove this sanity check
+ Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
+ if (it != insert(it, topLeft, sheet/*, true*/))
+ {
+ // if the point was inserted
+ clearSubRegion();
+ }
+ Element* element = *(cells().begin() += d->activeSubRegionStart);
+ // we end up with one element in the subregion
+ d->activeSubRegionLength = 1;
+ if (element && element->type() == Element::Point)
+ {
+ Point* point = static_cast<Point*>(element);
+ point->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+ else if (element && element->type() == Element::Range)
+ {
+ Range* range = static_cast<Range*>(element);
+ range->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+
+ d->activeElement = cells().begin();
+
+ if (changedRegion == *this)
+ {
+ emit changed(Region(topLeft, sheet));
+ return;
+ }
+ changedRegion.add(topLeft, sheet);
+
+ emit changed(changedRegion);
+}
+
+void Selection::initialize(const TQRect& range, Sheet* sheet)
+{
+ if (!util_isRectValid(range) || ( range == TQRect(0,0,1,1) ))
+ return;
+
+ if (!sheet)
+ {
+ if (d->sheet)
+ {
+ sheet = d->sheet;
+ }
+ else
+ {
+ sheet = d->view->activeSheet();
+ }
+ }
+
+ Region changedRegion(*this);
+ changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
+
+ TQPoint topLeft(range.topLeft());
+ Cell* cell = d->view->activeSheet()->cellAt(topLeft);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ TQPoint bottomRight(range.bottomRight());
+ cell = d->view->activeSheet()->cellAt(bottomRight);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ bottomRight = TQPoint(cell->column(), cell->row());
+ }
+
+ d->anchor = topLeft;
+ d->cursor = bottomRight;
+ d->marker = bottomRight;
+
+ fixSubRegionDimension(); // TODO remove this sanity check
+ Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
+ if (it != insert(it, TQRect(topLeft, bottomRight), sheet/*, true*/))
+ {
+ // if the range was inserted
+ clearSubRegion();
+ }
+
+ Element* element = *(cells().begin() += d->activeSubRegionStart);
+ // we end up with one element in the subregion
+ d->activeSubRegionLength = 1;
+ if (element && element->type() == Element::Point)
+ {
+ Point* point = static_cast<Point*>(element);
+ point->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+ else if (element && element->type() == Element::Range)
+ {
+ Range* range = static_cast<Range*>(element);
+ range->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+
+ d->activeElement = cells().begin();
+
+ if (changedRegion == *this)
+ {
+ return;
+ }
+ changedRegion.add(TQRect(topLeft, bottomRight), sheet);
+
+ emit changed(changedRegion);
+}
+
+void Selection::initialize(const Region& region, Sheet* sheet)
+{
+ if (!region.isValid())
+ return;
+
+ if (!sheet)
+ {
+ if (d->sheet)
+ {
+ sheet = d->sheet;
+ }
+ else
+ {
+ sheet = d->view->activeSheet();
+ }
+ }
+
+ Region changedRegion(*this);
+ changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
+
+ // TODO Stefan: handle subregion insertion
+ // TODO Stefan: handle obscured cells correctly
+ clear();
+ Element* element = add(region);
+ if (element && element->type() == Element::Point)
+ {
+ Point* point = static_cast<Point*>(element);
+ point->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+ else if (element && element->type() == Element::Range)
+ {
+ Range* range = static_cast<Range*>(element);
+ range->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+
+ TQPoint topLeft(cells().last()->rect().normalize().topLeft());
+ Cell* cell = d->view->activeSheet()->cellAt(topLeft);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ TQPoint bottomRight(cells().last()->rect().normalize().bottomRight());
+ cell = d->view->activeSheet()->cellAt(bottomRight);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ bottomRight = TQPoint(cell->column(), cell->row());
+ }
+
+ d->anchor = topLeft;
+ d->cursor = topLeft;
+ d->marker = bottomRight;
+
+ d->activeElement = --cells().end();
+ d->activeSubRegionStart = 0;
+ d->activeSubRegionLength = cells().count();
+
+ if (changedRegion == *this)
+ {
+ return;
+ }
+ changedRegion.add( region );
+
+ emit changed(changedRegion);
+}
+
+void Selection::update()
+{
+ emit changed(*this);
+}
+
+void Selection::update(const TQPoint& point)
+{
+ uint count = cells().count();
+
+ if (cells().isEmpty())
+ {
+ add(point);
+ d->activeSubRegionLength += cells().count() - count;
+ return;
+ }
+ if (d->activeElement == cells().end())
+ {
+ // we're not empty, so this will not become again end()
+ d->activeElement--;
+ }
+
+ Sheet* sheet = (*d->activeElement)->sheet();
+ if (sheet != d->view->activeSheet())
+ {
+ extend(point);
+ d->activeSubRegionLength += cells().count() - count;
+ return;
+ }
+
+ TQPoint topLeft(point);
+ Cell* cell = d->view->activeSheet()->cellAt(point);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ if (topLeft == d->marker)
+ {
+ return;
+ }
+
+ TQRect area1 = (*d->activeElement)->rect().normalize();
+ TQRect newRange = extendToMergedAreas(TQRect(d->anchor, topLeft));
+
+ Element* oldElement = *d->activeElement;
+ // returns iterator to the next element or end
+ Iterator it = cells().remove(d->activeElement);
+ delete oldElement;
+ // returns iterator to the new element (before 'it') or 'it'
+ d->activeElement = insert(it, newRange, sheet, d->multipleSelection);
+ d->activeSubRegionLength += cells().count() - count;
+
+ // The call to insert() above can just return the iterator which has been
+ // passed in. This may be cells.end(), if the old active element was the
+ // iterator to the list's end (!= last element). So attempts to dereference
+ // it will fail.
+ if (d->activeElement == cells().end())
+ {
+ d->activeElement--;
+ }
+
+ TQRect area2 = (*d->activeElement)->rect().normalize();
+ Region changedRegion;
+
+ bool newLeft = area1.left() != area2.left();
+ bool newTop = area1.top() != area2.top();
+ bool newRight = area1.right() != area2.right();
+ bool newBottom = area1.bottom() != area2.bottom();
+
+ /* first, calculate some numbers that we'll use a few times */
+ int farLeft = TQMIN(area1.left(), area2.left());
+ int innerLeft = TQMAX(area1.left(), area2.left());
+
+ int farTop = TQMIN(area1.top(), area2.top());
+ int innerTop = TQMAX(area1.top(), area2.top());
+
+ int farRight = TQMAX(area1.right(), area2.right());
+ int innerRight = TQMIN(area1.right(), area2.right());
+
+ int farBottom = TQMAX(area1.bottom(), area2.bottom());
+ int innerBottom = TQMIN(area1.bottom(), area2.bottom());
+
+ if (newLeft)
+ {
+ changedRegion.add(TQRect(TQPoint(farLeft, innerTop),
+ TQPoint(innerLeft-1, innerBottom)));
+ if (newTop)
+ {
+ changedRegion.add(TQRect(TQPoint(farLeft, farTop),
+ TQPoint(innerLeft-1, innerTop-1)));
+ }
+ if (newBottom)
+ {
+ changedRegion.add(TQRect(TQPoint(farLeft, innerBottom+1),
+ TQPoint(innerLeft-1, farBottom)));
+ }
+ }
+
+ if (newTop)
+ {
+ changedRegion.add(TQRect(TQPoint(innerLeft, farTop),
+ TQPoint(innerRight, innerTop-1)));
+ }
+
+ if (newRight)
+ {
+ changedRegion.add(TQRect(TQPoint(innerRight+1, innerTop),
+ TQPoint(farRight, innerBottom)));
+ if (newTop)
+ {
+ changedRegion.add(TQRect(TQPoint(innerRight+1, farTop),
+ TQPoint(farRight, innerTop-1)));
+ }
+ if (newBottom)
+ {
+ changedRegion.add(TQRect(TQPoint(innerRight+1, innerBottom+1),
+ TQPoint(farRight, farBottom)));
+ }
+ }
+
+ if (newBottom)
+ {
+ changedRegion.add(TQRect(TQPoint(innerLeft, innerBottom+1),
+ TQPoint(innerRight, farBottom)));
+ }
+
+ d->marker = topLeft;
+ d->cursor = point;
+
+ emit changed(changedRegion);
+}
+
+void Selection::extend(const TQPoint& point, Sheet* sheet)
+{
+ if (!util_isPointValid(point))
+ return;
+
+ if (isEmpty())
+ {
+ initialize(point, sheet);
+ return;
+ }
+ if (d->activeElement == cells().end())
+ {
+ // we're not empty, so this will not become again end()
+ d->activeElement--;
+ }
+
+ if (!sheet)
+ {
+ if (d->sheet)
+ {
+ sheet = d->sheet;
+ }
+ else
+ {
+ sheet = d->view->activeSheet();
+ }
+ }
+
+ Region changedRegion = Region(extendToMergedAreas(TQRect(d->marker,d->marker)));
+
+ TQPoint topLeft(point);
+ Cell* cell = d->view->activeSheet()->cellAt(point);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ uint count = cells().count();
+ if (d->multipleSelection)
+ {
+ d->activeElement = insert(++d->activeElement, point, sheet, false);
+ }
+ else
+ {
+ eor(topLeft, sheet);
+ d->activeElement = --cells().end();
+ }
+ d->anchor = (*d->activeElement)->rect().topLeft();
+ d->cursor = (*d->activeElement)->rect().bottomRight();
+ d->marker = d->cursor;
+
+ d->activeSubRegionLength += cells().count() - count;
+
+ changedRegion.add(topLeft, sheet);
+ changedRegion.add(*this);
+
+ emit changed(changedRegion);
+}
+
+void Selection::extend(const TQRect& range, Sheet* sheet)
+{
+ //See comment in Selection::initialize(const TQRect& range, Sheet* sheet)
+ if (!util_isRectValid(range) || (range == TQRect(0,0,1,1)))
+ return;
+
+ if (isEmpty())
+ {
+ initialize(range, sheet);
+ return;
+ }
+ if (d->activeElement == cells().end())
+ {
+ // we're not empty, so this will not become again end()
+ d->activeElement--;
+ }
+
+ if (!sheet)
+ {
+ if (d->sheet)
+ {
+ sheet = d->sheet;
+ }
+ else
+ {
+ sheet = d->view->activeSheet();
+ }
+ }
+
+ TQPoint topLeft(range.topLeft());
+ Cell* cell = d->view->activeSheet()->cellAt(topLeft);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ topLeft = TQPoint(cell->column(), cell->row());
+ }
+
+ TQPoint bottomRight(range.bottomRight());
+ cell = d->view->activeSheet()->cellAt(bottomRight);
+ if (cell->isObscured() && cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ bottomRight = TQPoint(cell->column(), cell->row());
+ }
+
+ d->anchor = topLeft;
+ d->cursor = topLeft;
+ d->marker = bottomRight;
+
+ uint count = cells().count();
+ Element* element;
+ if (d->multipleSelection)
+ {
+ d->activeElement = insert(++d->activeElement, extendToMergedAreas(TQRect(topLeft, bottomRight)).normalize(), sheet, false);
+ element = (d->activeElement == cells().end()) ? 0 : *d->activeElement;
+ }
+ else
+ {
+ element = add(extendToMergedAreas(TQRect(topLeft, bottomRight)).normalize(), sheet);
+ d->activeElement = --cells().end();
+ }
+ if (element && element->type() == Element::Point)
+ {
+ Point* point = static_cast<Point*>(element);
+ point->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+ else if (element && element->type() == Element::Range)
+ {
+ Range* range = static_cast<Range*>(element);
+ range->setColor(d->colors[cells().size() % d->colors.size()]);
+ }
+
+ d->activeSubRegionLength += cells().count() - count;
+
+ emit changed(*this);
+}
+
+void Selection::extend(const Region& region)
+{
+ if (!region.isValid())
+ return;
+
+ uint count = cells().count();
+ ConstIterator end(region.constEnd());
+ for (ConstIterator it = region.constBegin(); it != end; ++it)
+ {
+ Element *element = *it;
+ if (!element) continue;
+ if (element->type() == Element::Point)
+ {
+ Point* point = static_cast<Point*>(element);
+ extend(point->pos(), element->sheet());
+ }
+ else
+ {
+ extend(element->rect(), element->sheet());
+ }
+ }
+
+ d->activeSubRegionLength += cells().count() - count;
+
+ emit changed(*this);
+}
+
+Selection::Element* Selection::eor(const TQPoint& point, Sheet* sheet)
+{
+ if (isSingular())
+ {
+ return Region::add(point, sheet);
+ }
+ return Region::eor(point, sheet);
+}
+
+const TQPoint& Selection::anchor() const
+{
+ return d->anchor;
+}
+
+const TQPoint& Selection::cursor() const
+{
+ return d->cursor;
+}
+
+const TQPoint& Selection::marker() const
+{
+ return d->marker;
+}
+
+bool Selection::isSingular() const
+{
+ return Region::isSingular();
+}
+
+TQRect Selection::selectionHandleArea() const
+{
+ int column, row;
+
+ // complete rows/columns are selected, use the marker.
+ if (isColumnOrRowSelected())
+ {
+ column = d->marker.x();
+ row = d->marker.y();
+ }
+ else
+ {
+ column = lastRange().right();
+ row = lastRange().bottom();
+ }
+ const Cell* cell = d->view->activeSheet()->cellAt(column, row);
+
+ double xpos = d->view->activeSheet()->dblColumnPos( column );
+ double ypos = d->view->activeSheet()->dblRowPos( row );
+ double width = cell->dblWidth( column );
+ double height = cell->dblHeight( row );
+
+ TQPoint rightBottom( d->view->doc()->zoomItX( xpos + width ),
+ d->view->doc()->zoomItY( ypos + height ) );
+
+ TQRect handle( ( rightBottom.x() - 2 ),
+ ( rightBottom.y() - 2 ),
+ ( 5 ),
+ ( 5 ) );
+ return handle;
+}
+
+TQString Selection::name(Sheet* sheet) const
+{
+ return Region::name(sheet ? sheet : d->sheet);
+}
+
+void Selection::setSheet(Sheet* sheet)
+{
+ d->sheet = sheet;
+}
+
+Sheet* Selection::sheet() const
+{
+ return d->sheet;
+}
+
+void Selection::setActiveElement(const TQPoint& point)
+{
+ uint counter = 0;
+ Iterator end = cells().end();
+ for (Iterator it = cells().begin(); it != end; ++it)
+ {
+ TQRect range = (*it)->rect();
+ if (range.topLeft() == point || range.bottomRight() == point)
+ {
+ d->anchor = range.topLeft();
+ d->cursor = range.bottomRight();
+ d->marker = range.bottomRight();
+ d->activeElement = it;
+ d->activeSubRegionStart = counter;
+ d->activeSubRegionLength = 1;
+ if (d->view->canvasWidget()->editor())
+ {
+ d->view->canvasWidget()->editor()->setCursorToRange(counter);
+ }
+ }
+ counter++;
+ }
+}
+
+void Selection::setActiveElement(uint pos)
+{
+ if (pos >= cells().count())
+ {
+ kdDebug() << "Selection::setActiveElement: position exceeds list" << endl;
+ d->activeElement = cells().begin();
+ return;
+ }
+
+ Iterator it = cells().begin() += pos;
+ TQRect range = (*it)->rect();
+ d->anchor = range.topLeft();
+ d->cursor = range.bottomRight();
+ d->marker = range.bottomRight();
+ d->activeElement = it;
+}
+
+Region::Element* Selection::activeElement() const
+{
+ return (d->activeElement == cells().end()) ? 0 : *d->activeElement;
+}
+
+void Selection::clear()
+{
+ d->activeSubRegionStart = 0;
+ d->activeSubRegionLength = 0;
+ Region::clear();
+ d->activeElement = cells().begin();
+}
+
+void Selection::clearSubRegion()
+{
+ if (isEmpty())
+ {
+ return;
+ }
+// kdDebug() << *this << endl;
+// kdDebug() << d->activeSubRegionStart << endl;
+// kdDebug() << d->activeSubRegionLength << endl;
+
+ Iterator it = cells().begin();
+ Iterator end = it += d->activeSubRegionStart;
+ end += d->activeSubRegionLength;
+ while (it != end)
+ {
+/* kdDebug() << (*it)->name() << endl;*/
+ delete *it;
+ it = cells().remove(it);
+ }
+ d->activeSubRegionLength = 0;
+ d->activeElement = it;
+/* kdDebug() << "ENDE" << endl;*/
+}
+
+void Selection::fixSubRegionDimension()
+{
+ if (d->activeSubRegionStart > cells().count())
+ {
+ kdDebug() << "Selection::fixSubRegionDimension: start position exceeds list" << endl;
+ d->activeSubRegionStart = 0;
+ d->activeSubRegionLength = cells().count();
+ return;
+ }
+ if (d->activeSubRegionStart + d->activeSubRegionLength > cells().count())
+ {
+ kdDebug() << "Selection::fixSubRegionDimension: length exceeds list" << endl;
+ d->activeSubRegionLength = cells().count() - d->activeSubRegionStart;
+ return;
+ }
+}
+
+void Selection::setActiveSubRegion(uint start, uint length)
+{
+// kdDebug() << k_funcinfo << endl;
+ d->activeSubRegionStart = start;
+ d->activeSubRegionLength = length;
+ fixSubRegionDimension();
+ d->activeElement = cells().begin() += d->activeSubRegionStart;
+}
+
+TQString Selection::activeSubRegionName() const
+{
+// kdDebug() << k_funcinfo << endl;
+// kdDebug() << *this << endl;
+// kdDebug() << "start = " << d->activeSubRegionStart << ", len = " << d->activeSubRegionLength << endl;
+
+ TQStringList names;
+ Iterator it = cells().begin();
+ it += d->activeSubRegionStart;
+ Iterator end = it;
+ end += d->activeSubRegionLength;
+ while (it != end)
+ {
+ names += (*it++)->name(d->sheet);
+ }
+/* kdDebug() << "ENDE" << endl;*/
+ return names.isEmpty() ? "" : names.join(";");
+}
+
+void Selection::setMultipleSelection(bool state)
+{
+ d->multipleSelection = state;
+}
+
+const TQValueList<TQColor>& Selection::colors() const
+{
+ return d->colors;
+}
+
+TQRect Selection::lastRange(bool extend) const
+{
+ TQRect selection = TQRect(d->anchor, d->marker).normalize();
+ return extend ? extendToMergedAreas(selection) : selection;
+}
+
+TQRect Selection::selection(bool extend) const
+{
+ TQRect selection = TQRect(d->anchor, d->marker).normalize();
+ return extend ? extendToMergedAreas(selection) : selection;
+}
+
+TQRect Selection::extendToMergedAreas(TQRect area) const
+{
+ if (!d->view->activeSheet())
+ return area;
+
+ area = area.normalize(); // TODO Stefan: avoid this
+ const Cell *cell = d->view->activeSheet()->cellAt(area.left(), area.top());
+
+ if( Region::Range(area).isColumn() || Region::Range(area).isRow() )
+ {
+ return area;
+ }
+ else if ( !(cell->isObscured() && cell->isPartOfMerged()) &&
+ (cell->mergedXCells() + 1) >= area.width() &&
+ (cell->mergedYCells() + 1) >= area.height())
+ {
+ /* if just a single cell is selected, we need to merge even when
+ the obscuring isn't forced. But only if this is the cell that
+ is doing the obscuring -- we still want to be able to click on a cell
+ that is being obscured.
+ */
+ area.setWidth(cell->mergedXCells() + 1);
+ area.setHeight(cell->mergedYCells() + 1);
+ }
+ else
+ {
+ int top=area.top();
+ int left=area.left();
+ int bottom=area.bottom();
+ int right=area.right();
+ for ( int x = area.left(); x <= area.right(); x++ )
+ for ( int y = area.top(); y <= area.bottom(); y++ )
+ {
+ cell = d->view->activeSheet()->cellAt( x, y );
+ if( cell->doesMergeCells())
+ {
+ right=TQMAX(right,cell->mergedXCells()+x);
+ bottom=TQMAX(bottom,cell->mergedYCells()+y);
+ }
+ else if ( cell->isObscured() && cell->isPartOfMerged() )
+ {
+ cell = cell->obscuringCells().first();
+ left=TQMIN(left,cell->column());
+ top=TQMIN(top,cell->row());
+ bottom=TQMAX(bottom,cell->row() + cell->mergedYCells());
+ right=TQMAX(right,cell->column() + cell->mergedXCells());
+ }
+ }
+
+ area.setCoords(left,top,right,bottom);
+ }
+ return area;
+}
+
+Selection::Region::Point* Selection::createPoint(const TQPoint& point) const
+{
+ return new Point(point);
+}
+
+Selection::Region::Point* Selection::createPoint(const TQString& string) const
+{
+ return new Point(string);
+}
+
+Selection::Region::Point* Selection::createPoint(const Point& point) const
+{
+ return new Point(point);
+}
+
+Selection::Region::Range* Selection::createRange(const TQRect& rect) const
+{
+ return new Range(rect);
+}
+
+Selection::Region::Range* Selection::createRange(const TQString& string) const
+{
+ return new Range(string);
+}
+
+Selection::Region::Range* Selection::createRange(const Range& range) const
+{
+ return new Range(range);
+}
+
+/***************************************************************************
+ class Point
+****************************************************************************/
+
+Selection::Point::Point(const TQPoint& point)
+ : Region::Point(point),
+ m_color(TQt::black),
+ m_columnFixed(false),
+ m_rowFixed(false)
+{
+}
+
+Selection::Point::Point(const TQString& string)
+ : Region::Point(string),
+ m_color(TQt::black),
+ m_columnFixed(false),
+ m_rowFixed(false)
+{
+ if (!isValid())
+ {
+ return;
+ }
+
+ uint p = 0;
+ // Fixed?
+ if (string[p++] == '$')
+ {
+ m_columnFixed = true;
+ }
+
+ //search for the first character != text
+ int result = string.find( TQRegExp("[^A-Za-z]+"), p );
+ if (string[result] == '$')
+ {
+ m_rowFixed = true;
+ }
+}
+
+/***************************************************************************
+ class Range
+****************************************************************************/
+
+Selection::Range::Range(const TQRect& range)
+ : Region::Range(range),
+ m_color(TQt::black),
+ m_leftFixed(false),
+ m_rightFixed(false),
+ m_topFixed(false),
+ m_bottomFixed(false)
+{
+}
+
+Selection::Range::Range(const TQString& string)
+ : Region::Range(string),
+ m_color(TQt::black),
+ m_leftFixed(false),
+ m_rightFixed(false),
+ m_topFixed(false),
+ m_bottomFixed(false)
+{
+ if (!isValid())
+ {
+ return;
+ }
+
+ int delimiterPos = string.find(':');
+ if (delimiterPos == -1)
+ {
+ return;
+ }
+
+ Selection::Point ul(string.left(delimiterPos));
+ Selection::Point lr(string.mid(delimiterPos + 1));
+
+ if (!ul.isValid() || !lr.isValid())
+ {
+ return;
+ }
+ m_leftFixed = ul.columnFixed();
+ m_rightFixed = lr.columnFixed();
+ m_topFixed = ul.rowFixed();
+ m_bottomFixed = lr.rowFixed();
+}
+
+} // namespace KSpread
+#include "selection.moc"