You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1010 lines
25 KiB
1010 lines
25 KiB
15 years ago
|
/* 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 <qregexp.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 = QPoint(1,1);
|
||
|
cursor = QPoint(1,1);
|
||
|
marker = QPoint(1,1);
|
||
|
|
||
|
colors.push_back(Qt::red);
|
||
|
colors.push_back(Qt::blue);
|
||
|
colors.push_back(Qt::magenta);
|
||
|
colors.push_back(Qt::darkRed);
|
||
|
colors.push_back(Qt::darkGreen);
|
||
|
colors.push_back(Qt::darkMagenta);
|
||
|
colors.push_back(Qt::darkCyan);
|
||
|
colors.push_back(Qt::darkYellow);
|
||
|
|
||
|
multipleSelection = false;
|
||
|
|
||
|
activeElement = Iterator();
|
||
|
activeSubRegionStart = 0;
|
||
|
activeSubRegionLength = 0;
|
||
|
}
|
||
|
|
||
|
View* view;
|
||
|
Sheet* sheet;
|
||
|
QPoint anchor;
|
||
|
QPoint cursor;
|
||
|
QPoint marker;
|
||
|
QValueList<QColor> colors;
|
||
|
|
||
|
bool multipleSelection : 1;
|
||
|
|
||
|
Selection::Iterator activeElement;
|
||
|
uint activeSubRegionStart;
|
||
|
uint activeSubRegionLength;
|
||
|
};
|
||
|
|
||
|
/***************************************************************************
|
||
|
class Selection
|
||
|
****************************************************************************/
|
||
|
namespace KSpread {
|
||
|
|
||
|
Selection::Selection(View *view)
|
||
|
: QObject(view), Region(1,1)
|
||
|
{
|
||
|
d = new Private(view);
|
||
|
d->activeSubRegionStart = 0;
|
||
|
d->activeSubRegionLength = 1;
|
||
|
}
|
||
|
|
||
|
Selection::Selection(const Selection& selection)
|
||
|
: QObject(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 QPoint& 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(QRect(d->anchor,d->marker)));
|
||
|
|
||
|
QPoint topLeft(point);
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(point);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(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 QRect& range, Sheet* sheet)
|
||
|
{
|
||
|
if (!util_isRectValid(range) || ( range == QRect(0,0,1,1) ))
|
||
|
return;
|
||
|
|
||
|
if (!sheet)
|
||
|
{
|
||
|
if (d->sheet)
|
||
|
{
|
||
|
sheet = d->sheet;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sheet = d->view->activeSheet();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Region changedRegion(*this);
|
||
|
changedRegion.add(extendToMergedAreas(QRect(d->anchor,d->marker)));
|
||
|
|
||
|
QPoint topLeft(range.topLeft());
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(topLeft);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(cell->column(), cell->row());
|
||
|
}
|
||
|
|
||
|
QPoint bottomRight(range.bottomRight());
|
||
|
cell = d->view->activeSheet()->cellAt(bottomRight);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
bottomRight = QPoint(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, QRect(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(QRect(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(QRect(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()]);
|
||
|
}
|
||
|
|
||
|
QPoint topLeft(cells().last()->rect().normalize().topLeft());
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(topLeft);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(cell->column(), cell->row());
|
||
|
}
|
||
|
|
||
|
QPoint bottomRight(cells().last()->rect().normalize().bottomRight());
|
||
|
cell = d->view->activeSheet()->cellAt(bottomRight);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
bottomRight = QPoint(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 QPoint& 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;
|
||
|
}
|
||
|
|
||
|
QPoint topLeft(point);
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(point);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(cell->column(), cell->row());
|
||
|
}
|
||
|
|
||
|
if (topLeft == d->marker)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QRect area1 = (*d->activeElement)->rect().normalize();
|
||
|
QRect newRange = extendToMergedAreas(QRect(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--;
|
||
|
}
|
||
|
|
||
|
QRect 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 = QMIN(area1.left(), area2.left());
|
||
|
int innerLeft = QMAX(area1.left(), area2.left());
|
||
|
|
||
|
int farTop = QMIN(area1.top(), area2.top());
|
||
|
int innerTop = QMAX(area1.top(), area2.top());
|
||
|
|
||
|
int farRight = QMAX(area1.right(), area2.right());
|
||
|
int innerRight = QMIN(area1.right(), area2.right());
|
||
|
|
||
|
int farBottom = QMAX(area1.bottom(), area2.bottom());
|
||
|
int innerBottom = QMIN(area1.bottom(), area2.bottom());
|
||
|
|
||
|
if (newLeft)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(farLeft, innerTop),
|
||
|
QPoint(innerLeft-1, innerBottom)));
|
||
|
if (newTop)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(farLeft, farTop),
|
||
|
QPoint(innerLeft-1, innerTop-1)));
|
||
|
}
|
||
|
if (newBottom)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(farLeft, innerBottom+1),
|
||
|
QPoint(innerLeft-1, farBottom)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (newTop)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(innerLeft, farTop),
|
||
|
QPoint(innerRight, innerTop-1)));
|
||
|
}
|
||
|
|
||
|
if (newRight)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(innerRight+1, innerTop),
|
||
|
QPoint(farRight, innerBottom)));
|
||
|
if (newTop)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(innerRight+1, farTop),
|
||
|
QPoint(farRight, innerTop-1)));
|
||
|
}
|
||
|
if (newBottom)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(innerRight+1, innerBottom+1),
|
||
|
QPoint(farRight, farBottom)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (newBottom)
|
||
|
{
|
||
|
changedRegion.add(QRect(QPoint(innerLeft, innerBottom+1),
|
||
|
QPoint(innerRight, farBottom)));
|
||
|
}
|
||
|
|
||
|
d->marker = topLeft;
|
||
|
d->cursor = point;
|
||
|
|
||
|
emit changed(changedRegion);
|
||
|
}
|
||
|
|
||
|
void Selection::extend(const QPoint& 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(QRect(d->marker,d->marker)));
|
||
|
|
||
|
QPoint topLeft(point);
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(point);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(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 QRect& range, Sheet* sheet)
|
||
|
{
|
||
|
//See comment in Selection::initialize(const QRect& range, Sheet* sheet)
|
||
|
if (!util_isRectValid(range) || (range == QRect(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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QPoint topLeft(range.topLeft());
|
||
|
Cell* cell = d->view->activeSheet()->cellAt(topLeft);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
topLeft = QPoint(cell->column(), cell->row());
|
||
|
}
|
||
|
|
||
|
QPoint bottomRight(range.bottomRight());
|
||
|
cell = d->view->activeSheet()->cellAt(bottomRight);
|
||
|
if (cell->isObscured() && cell->isPartOfMerged())
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
bottomRight = QPoint(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(QRect(topLeft, bottomRight)).normalize(), sheet, false);
|
||
|
element = (d->activeElement == cells().end()) ? 0 : *d->activeElement;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
element = add(extendToMergedAreas(QRect(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 QPoint& point, Sheet* sheet)
|
||
|
{
|
||
|
if (isSingular())
|
||
|
{
|
||
|
return Region::add(point, sheet);
|
||
|
}
|
||
|
return Region::eor(point, sheet);
|
||
|
}
|
||
|
|
||
|
const QPoint& Selection::anchor() const
|
||
|
{
|
||
|
return d->anchor;
|
||
|
}
|
||
|
|
||
|
const QPoint& Selection::cursor() const
|
||
|
{
|
||
|
return d->cursor;
|
||
|
}
|
||
|
|
||
|
const QPoint& Selection::marker() const
|
||
|
{
|
||
|
return d->marker;
|
||
|
}
|
||
|
|
||
|
bool Selection::isSingular() const
|
||
|
{
|
||
|
return Region::isSingular();
|
||
|
}
|
||
|
|
||
|
QRect 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 );
|
||
|
|
||
|
QPoint rightBottom( d->view->doc()->zoomItX( xpos + width ),
|
||
|
d->view->doc()->zoomItY( ypos + height ) );
|
||
|
|
||
|
QRect handle( ( rightBottom.x() - 2 ),
|
||
|
( rightBottom.y() - 2 ),
|
||
|
( 5 ),
|
||
|
( 5 ) );
|
||
|
return handle;
|
||
|
}
|
||
|
|
||
|
QString 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 QPoint& point)
|
||
|
{
|
||
|
uint counter = 0;
|
||
|
Iterator end = cells().end();
|
||
|
for (Iterator it = cells().begin(); it != end; ++it)
|
||
|
{
|
||
|
QRect 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;
|
||
|
QRect 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;
|
||
|
}
|
||
|
|
||
|
QString Selection::activeSubRegionName() const
|
||
|
{
|
||
|
// kdDebug() << k_funcinfo << endl;
|
||
|
// kdDebug() << *this << endl;
|
||
|
// kdDebug() << "start = " << d->activeSubRegionStart << ", len = " << d->activeSubRegionLength << endl;
|
||
|
|
||
|
QStringList 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 QValueList<QColor>& Selection::colors() const
|
||
|
{
|
||
|
return d->colors;
|
||
|
}
|
||
|
|
||
|
QRect Selection::lastRange(bool extend) const
|
||
|
{
|
||
|
QRect selection = QRect(d->anchor, d->marker).normalize();
|
||
|
return extend ? extendToMergedAreas(selection) : selection;
|
||
|
}
|
||
|
|
||
|
QRect Selection::selection(bool extend) const
|
||
|
{
|
||
|
QRect selection = QRect(d->anchor, d->marker).normalize();
|
||
|
return extend ? extendToMergedAreas(selection) : selection;
|
||
|
}
|
||
|
|
||
|
QRect Selection::extendToMergedAreas(QRect 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=QMAX(right,cell->mergedXCells()+x);
|
||
|
bottom=QMAX(bottom,cell->mergedYCells()+y);
|
||
|
}
|
||
|
else if ( cell->isObscured() && cell->isPartOfMerged() )
|
||
|
{
|
||
|
cell = cell->obscuringCells().first();
|
||
|
left=QMIN(left,cell->column());
|
||
|
top=QMIN(top,cell->row());
|
||
|
bottom=QMAX(bottom,cell->row() + cell->mergedYCells());
|
||
|
right=QMAX(right,cell->column() + cell->mergedXCells());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
area.setCoords(left,top,right,bottom);
|
||
|
}
|
||
|
return area;
|
||
|
}
|
||
|
|
||
|
Selection::Region::Point* Selection::createPoint(const QPoint& point) const
|
||
|
{
|
||
|
return new Point(point);
|
||
|
}
|
||
|
|
||
|
Selection::Region::Point* Selection::createPoint(const QString& 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 QRect& rect) const
|
||
|
{
|
||
|
return new Range(rect);
|
||
|
}
|
||
|
|
||
|
Selection::Region::Range* Selection::createRange(const QString& 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 QPoint& point)
|
||
|
: Region::Point(point),
|
||
|
m_color(Qt::black),
|
||
|
m_columnFixed(false),
|
||
|
m_rowFixed(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Selection::Point::Point(const QString& string)
|
||
|
: Region::Point(string),
|
||
|
m_color(Qt::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( QRegExp("[^A-Za-z]+"), p );
|
||
|
if (string[result] == '$')
|
||
|
{
|
||
|
m_rowFixed = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
class Range
|
||
|
****************************************************************************/
|
||
|
|
||
|
Selection::Range::Range(const QRect& range)
|
||
|
: Region::Range(range),
|
||
|
m_color(Qt::black),
|
||
|
m_leftFixed(false),
|
||
|
m_rightFixed(false),
|
||
|
m_topFixed(false),
|
||
|
m_bottomFixed(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Selection::Range::Range(const QString& string)
|
||
|
: Region::Range(string),
|
||
|
m_color(Qt::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"
|