kspread

selection.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2005-2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qregexp.h>
00022 
00023 #include <kdebug.h>
00024 
00025 #include "kspread_canvas.h"
00026 #include "kspread_cell.h"
00027 #include "kspread_doc.h"
00028 #include "kspread_editors.h"
00029 #include "kspread_sheet.h"
00030 #include "kspread_view.h"
00031 #include "kspread_util.h"
00032 
00033 #include "selection.h"
00034 
00035 // TODO Stefan: Substract points in selections
00036 // TODO Stefan: KPart signal (kspread_events.h)
00037 
00038 using namespace KSpread;
00039 
00040 /***************************************************************************
00041   class Selection::Private
00042 ****************************************************************************/
00043 
00044 class Selection::Private
00045 {
00046 public:
00047   Private(View *v)
00048   {
00049     view = v;
00050     sheet = 0;
00051     anchor = QPoint(1,1);
00052     cursor = QPoint(1,1);
00053     marker = QPoint(1,1);
00054 
00055     colors.push_back(Qt::red);
00056     colors.push_back(Qt::blue);
00057     colors.push_back(Qt::magenta);
00058     colors.push_back(Qt::darkRed);
00059     colors.push_back(Qt::darkGreen);
00060     colors.push_back(Qt::darkMagenta);
00061     colors.push_back(Qt::darkCyan);
00062     colors.push_back(Qt::darkYellow);
00063 
00064     multipleSelection = false;
00065 
00066     activeElement = Iterator();
00067     activeSubRegionStart = 0;
00068     activeSubRegionLength = 0;
00069   }
00070 
00071   View*  view;
00072   Sheet* sheet;
00073   QPoint anchor;
00074   QPoint cursor;
00075   QPoint marker;
00076   QValueList<QColor> colors;
00077 
00078   bool multipleSelection : 1;
00079 
00080   Selection::Iterator activeElement;
00081   uint activeSubRegionStart;
00082   uint activeSubRegionLength;
00083 };
00084 
00085 /***************************************************************************
00086   class Selection
00087 ****************************************************************************/
00088 namespace KSpread {
00089 
00090 Selection::Selection(View *view)
00091   : QObject(view), Region(1,1)
00092 {
00093   d = new Private(view);
00094   d->activeSubRegionStart = 0;
00095   d->activeSubRegionLength = 1;
00096 }
00097 
00098 Selection::Selection(const Selection& selection)
00099   : QObject(selection.d->view), Region()
00100 {
00101 /*  kdDebug() << k_funcinfo << endl;*/
00102   d = new Private(selection.d->view);
00103   d->sheet = selection.d->sheet;
00104   d->activeSubRegionStart = 0;
00105   d->activeSubRegionLength = cells().count();
00106 }
00107 
00108 Selection::~Selection()
00109 {
00110   delete d;
00111 }
00112 
00113 void Selection::initialize(const QPoint& point, Sheet* sheet)
00114 {
00115     if (!util_isPointValid(point))
00116         return;
00117 
00118     if (!d->view->activeSheet())
00119         return;
00120 
00121   if (!sheet)
00122   {
00123     if (d->sheet)
00124     {
00125       sheet = d->sheet;
00126     }
00127     else
00128     {
00129       sheet = d->view->activeSheet();
00130     }
00131   }
00132 
00133   Region changedRegion(*this);
00134   changedRegion.add(extendToMergedAreas(QRect(d->anchor,d->marker)));
00135 
00136   QPoint topLeft(point);
00137   Cell* cell = d->view->activeSheet()->cellAt(point);
00138   if (cell->isObscured() && cell->isPartOfMerged())
00139   {
00140     cell = cell->obscuringCells().first();
00141     topLeft = QPoint(cell->column(), cell->row());
00142   }
00143 
00144   d->anchor = topLeft;
00145   d->cursor = point;
00146   d->marker = topLeft;
00147 
00148   fixSubRegionDimension(); // TODO remove this sanity check
00149   Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
00150   if (it != insert(it, topLeft, sheet/*, true*/))
00151   {
00152     // if the point was inserted
00153     clearSubRegion();
00154   }
00155   Element* element = *(cells().begin() += d->activeSubRegionStart);
00156   // we end up with one element in the subregion
00157   d->activeSubRegionLength = 1;
00158   if (element && element->type() == Element::Point)
00159   {
00160     Point* point = static_cast<Point*>(element);
00161     point->setColor(d->colors[cells().size() % d->colors.size()]);
00162   }
00163   else if (element && element->type() == Element::Range)
00164   {
00165     Range* range = static_cast<Range*>(element);
00166     range->setColor(d->colors[cells().size() % d->colors.size()]);
00167   }
00168 
00169   d->activeElement = cells().begin();
00170 
00171   if (changedRegion == *this)
00172   {
00173     emit changed(Region(topLeft, sheet));
00174     return;
00175   }
00176   changedRegion.add(topLeft, sheet);
00177 
00178   emit changed(changedRegion);
00179 }
00180 
00181 void Selection::initialize(const QRect& range, Sheet* sheet)
00182 {
00183     if (!util_isRectValid(range) || ( range == QRect(0,0,1,1) ))
00184         return;
00185 
00186   if (!sheet)
00187   {
00188     if (d->sheet)
00189     {
00190       sheet = d->sheet;
00191     }
00192     else
00193     {
00194       sheet = d->view->activeSheet();
00195     }
00196   }
00197 
00198   Region changedRegion(*this);
00199   changedRegion.add(extendToMergedAreas(QRect(d->anchor,d->marker)));
00200 
00201   QPoint topLeft(range.topLeft());
00202   Cell* cell = d->view->activeSheet()->cellAt(topLeft);
00203   if (cell->isObscured() && cell->isPartOfMerged())
00204   {
00205     cell = cell->obscuringCells().first();
00206     topLeft = QPoint(cell->column(), cell->row());
00207   }
00208 
00209   QPoint bottomRight(range.bottomRight());
00210   cell = d->view->activeSheet()->cellAt(bottomRight);
00211   if (cell->isObscured() && cell->isPartOfMerged())
00212   {
00213     cell = cell->obscuringCells().first();
00214     bottomRight = QPoint(cell->column(), cell->row());
00215   }
00216 
00217   d->anchor = topLeft;
00218   d->cursor = bottomRight;
00219   d->marker = bottomRight;
00220 
00221   fixSubRegionDimension(); // TODO remove this sanity check
00222   Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
00223   if (it != insert(it, QRect(topLeft, bottomRight), sheet/*, true*/))
00224   {
00225     // if the range was inserted
00226     clearSubRegion();
00227   }
00228 
00229   Element* element = *(cells().begin() += d->activeSubRegionStart);
00230   // we end up with one element in the subregion
00231   d->activeSubRegionLength = 1;
00232   if (element && element->type() == Element::Point)
00233   {
00234     Point* point = static_cast<Point*>(element);
00235     point->setColor(d->colors[cells().size() % d->colors.size()]);
00236   }
00237   else if (element && element->type() == Element::Range)
00238   {
00239     Range* range = static_cast<Range*>(element);
00240     range->setColor(d->colors[cells().size() % d->colors.size()]);
00241   }
00242 
00243   d->activeElement = cells().begin();
00244 
00245   if (changedRegion == *this)
00246   {
00247     return;
00248   }
00249   changedRegion.add(QRect(topLeft, bottomRight), sheet);
00250 
00251   emit changed(changedRegion);
00252 }
00253 
00254 void Selection::initialize(const Region& region, Sheet* sheet)
00255 {
00256     if (!region.isValid())
00257         return;
00258 
00259   if (!sheet)
00260   {
00261     if (d->sheet)
00262     {
00263       sheet = d->sheet;
00264     }
00265     else
00266     {
00267       sheet = d->view->activeSheet();
00268     }
00269   }
00270 
00271   Region changedRegion(*this);
00272   changedRegion.add(extendToMergedAreas(QRect(d->anchor,d->marker)));
00273 
00274   // TODO Stefan: handle subregion insertion
00275   // TODO Stefan: handle obscured cells correctly
00276   clear();
00277   Element* element = add(region);
00278   if (element && element->type() == Element::Point)
00279   {
00280     Point* point = static_cast<Point*>(element);
00281     point->setColor(d->colors[cells().size() % d->colors.size()]);
00282   }
00283   else if (element && element->type() == Element::Range)
00284   {
00285     Range* range = static_cast<Range*>(element);
00286     range->setColor(d->colors[cells().size() % d->colors.size()]);
00287   }
00288 
00289   QPoint topLeft(cells().last()->rect().normalize().topLeft());
00290   Cell* cell = d->view->activeSheet()->cellAt(topLeft);
00291   if (cell->isObscured() && cell->isPartOfMerged())
00292   {
00293     cell = cell->obscuringCells().first();
00294     topLeft = QPoint(cell->column(), cell->row());
00295   }
00296 
00297   QPoint bottomRight(cells().last()->rect().normalize().bottomRight());
00298   cell = d->view->activeSheet()->cellAt(bottomRight);
00299   if (cell->isObscured() && cell->isPartOfMerged())
00300   {
00301     cell = cell->obscuringCells().first();
00302     bottomRight = QPoint(cell->column(), cell->row());
00303   }
00304 
00305   d->anchor = topLeft;
00306   d->cursor = topLeft;
00307   d->marker = bottomRight;
00308 
00309   d->activeElement = --cells().end();
00310 
00311   if (changedRegion == *this)
00312   {
00313     return;
00314   }
00315 
00316   emit changed(changedRegion);
00317 }
00318 
00319 void Selection::update()
00320 {
00321   emit changed(*this);
00322 }
00323 
00324 void Selection::update(const QPoint& point)
00325 {
00326   uint count = cells().count();
00327 
00328   if (cells().isEmpty())
00329   {
00330     add(point);
00331     d->activeSubRegionLength += cells().count() - count;
00332     return;
00333   }
00334   if (d->activeElement == cells().end())
00335   {
00336     // we're not empty, so this will not become again end()
00337     d->activeElement--;
00338   }
00339 
00340   Sheet* sheet = (*d->activeElement)->sheet();
00341   if (sheet != d->view->activeSheet())
00342   {
00343     extend(point);
00344     d->activeSubRegionLength += cells().count() - count;
00345     return;
00346   }
00347 
00348   QPoint topLeft(point);
00349   Cell* cell = d->view->activeSheet()->cellAt(point);
00350   if (cell->isObscured() && cell->isPartOfMerged())
00351   {
00352     cell = cell->obscuringCells().first();
00353     topLeft = QPoint(cell->column(), cell->row());
00354   }
00355 
00356   if (topLeft == d->marker)
00357   {
00358     return;
00359   }
00360 
00361   QRect area1 = (*d->activeElement)->rect().normalize();
00362   QRect newRange = extendToMergedAreas(QRect(d->anchor, topLeft));
00363 
00364   Element* oldElement = *d->activeElement;
00365   // returns iterator to the next element or end
00366   Iterator it = cells().remove(d->activeElement);
00367   delete oldElement;
00368   // returns iterator to the new element (before 'it') or 'it'
00369   d->activeElement = insert(it, newRange, sheet, d->multipleSelection);
00370   d->activeSubRegionLength += cells().count() - count;
00371 
00372   // The call to insert() above can just return the iterator which has been
00373   // passed in. This may be cells.end(), if the old active element was the
00374   // iterator to the list's end (!= last element). So attempts to dereference
00375   // it will fail.
00376   if (d->activeElement == cells().end())
00377   {
00378     d->activeElement--;
00379   }
00380 
00381   QRect area2 = (*d->activeElement)->rect().normalize();
00382   Region changedRegion;
00383 
00384   bool newLeft   = area1.left() != area2.left();
00385   bool newTop    = area1.top() != area2.top();
00386   bool newRight  = area1.right() != area2.right();
00387   bool newBottom = area1.bottom() != area2.bottom();
00388 
00389   /* first, calculate some numbers that we'll use a few times */
00390   int farLeft = QMIN(area1.left(), area2.left());
00391   int innerLeft = QMAX(area1.left(), area2.left());
00392 
00393   int farTop = QMIN(area1.top(), area2.top());
00394   int innerTop = QMAX(area1.top(), area2.top());
00395 
00396   int farRight = QMAX(area1.right(), area2.right());
00397   int innerRight = QMIN(area1.right(), area2.right());
00398 
00399   int farBottom = QMAX(area1.bottom(), area2.bottom());
00400   int innerBottom = QMIN(area1.bottom(), area2.bottom());
00401 
00402   if (newLeft)
00403   {
00404     changedRegion.add(QRect(QPoint(farLeft, innerTop),
00405                       QPoint(innerLeft-1, innerBottom)));
00406     if (newTop)
00407     {
00408       changedRegion.add(QRect(QPoint(farLeft, farTop),
00409                         QPoint(innerLeft-1, innerTop-1)));
00410     }
00411     if (newBottom)
00412     {
00413       changedRegion.add(QRect(QPoint(farLeft, innerBottom+1),
00414                         QPoint(innerLeft-1, farBottom)));
00415     }
00416   }
00417 
00418   if (newTop)
00419   {
00420     changedRegion.add(QRect(QPoint(innerLeft, farTop),
00421                       QPoint(innerRight, innerTop-1)));
00422   }
00423 
00424   if (newRight)
00425   {
00426     changedRegion.add(QRect(QPoint(innerRight+1, innerTop),
00427                       QPoint(farRight, innerBottom)));
00428     if (newTop)
00429     {
00430       changedRegion.add(QRect(QPoint(innerRight+1, farTop),
00431                         QPoint(farRight, innerTop-1)));
00432     }
00433     if (newBottom)
00434     {
00435       changedRegion.add(QRect(QPoint(innerRight+1, innerBottom+1),
00436                         QPoint(farRight, farBottom)));
00437     }
00438   }
00439 
00440   if (newBottom)
00441   {
00442     changedRegion.add(QRect(QPoint(innerLeft, innerBottom+1),
00443                       QPoint(innerRight, farBottom)));
00444   }
00445 
00446   d->marker = topLeft;
00447   d->cursor = point;
00448 
00449   emit changed(changedRegion);
00450 }
00451 
00452 void Selection::extend(const QPoint& point, Sheet* sheet)
00453 {
00454     if (!util_isPointValid(point))
00455         return;
00456 
00457   if (isEmpty())
00458   {
00459     initialize(point, sheet);
00460     return;
00461   }
00462   if (d->activeElement == cells().end())
00463   {
00464     // we're not empty, so this will not become again end()
00465     d->activeElement--;
00466   }
00467 
00468   if (!sheet)
00469   {
00470     if (d->sheet)
00471     {
00472       sheet = d->sheet;
00473     }
00474     else
00475     {
00476       sheet = d->view->activeSheet();
00477     }
00478   }
00479 
00480   Region changedRegion = Region(extendToMergedAreas(QRect(d->marker,d->marker)));
00481 
00482   QPoint topLeft(point);
00483   Cell* cell = d->view->activeSheet()->cellAt(point);
00484   if (cell->isObscured() && cell->isPartOfMerged())
00485   {
00486     cell = cell->obscuringCells().first();
00487     topLeft = QPoint(cell->column(), cell->row());
00488   }
00489 
00490   uint count = cells().count();
00491   if (d->multipleSelection)
00492   {
00493     d->activeElement = insert(++d->activeElement, point, sheet, false);
00494   }
00495   else
00496   {
00497     eor(topLeft, sheet);
00498     d->activeElement = --cells().end();
00499   }
00500   d->anchor = (*d->activeElement)->rect().topLeft();
00501   d->cursor = (*d->activeElement)->rect().bottomRight();
00502   d->marker = d->cursor;
00503 
00504   d->activeSubRegionLength += cells().count() - count;
00505 
00506   changedRegion.add(topLeft, sheet);
00507   changedRegion.add(*this);
00508 
00509   emit changed(changedRegion);
00510 }
00511 
00512 void Selection::extend(const QRect& range, Sheet* sheet)
00513 {
00514     //See comment in Selection::initialize(const QRect& range, Sheet* sheet)
00515     if (!util_isRectValid(range) || (range == QRect(0,0,1,1)))
00516         return;
00517 
00518   if (isEmpty())
00519   {
00520     initialize(range, sheet);
00521     return;
00522   }
00523   if (d->activeElement == cells().end())
00524   {
00525     // we're not empty, so this will not become again end()
00526     d->activeElement--;
00527   }
00528 
00529   if (!sheet)
00530   {
00531     if (d->sheet)
00532     {
00533       sheet = d->sheet;
00534     }
00535     else
00536     {
00537       sheet = d->view->activeSheet();
00538     }
00539   }
00540 
00541   QPoint topLeft(range.topLeft());
00542   Cell* cell = d->view->activeSheet()->cellAt(topLeft);
00543   if (cell->isObscured() && cell->isPartOfMerged())
00544   {
00545     cell = cell->obscuringCells().first();
00546     topLeft = QPoint(cell->column(), cell->row());
00547   }
00548 
00549   QPoint bottomRight(range.bottomRight());
00550   cell = d->view->activeSheet()->cellAt(bottomRight);
00551   if (cell->isObscured() && cell->isPartOfMerged())
00552   {
00553     cell = cell->obscuringCells().first();
00554     bottomRight = QPoint(cell->column(), cell->row());
00555   }
00556 
00557   d->anchor = topLeft;
00558   d->cursor = topLeft;
00559   d->marker = bottomRight;
00560 
00561   uint count = cells().count();
00562   Element* element;
00563   if (d->multipleSelection)
00564   {
00565     d->activeElement = insert(++d->activeElement, extendToMergedAreas(QRect(topLeft, bottomRight)).normalize(), sheet, false);
00566     element = *d->activeElement;
00567   }
00568   else
00569   {
00570     element = add(extendToMergedAreas(QRect(topLeft, bottomRight)).normalize(), sheet);
00571     d->activeElement = --cells().end();
00572   }
00573   if (element && element->type() == Element::Point)
00574   {
00575     Point* point = static_cast<Point*>(element);
00576     point->setColor(d->colors[cells().size() % d->colors.size()]);
00577   }
00578   else if (element && element->type() == Element::Range)
00579   {
00580     Range* range = static_cast<Range*>(element);
00581     range->setColor(d->colors[cells().size() % d->colors.size()]);
00582   }
00583 
00584   d->activeSubRegionLength += cells().count() - count;
00585 
00586   emit changed(*this);
00587 }
00588 
00589 void Selection::extend(const Region& region)
00590 {
00591     if (!region.isValid())
00592         return;
00593 
00594   uint count = cells().count();
00595   ConstIterator end(region.constEnd());
00596   for (ConstIterator it = region.constBegin(); it != end; ++it)
00597   {
00598     Element *element = *it;
00599     if (element && element->type() == Element::Point)
00600     {
00601       Point* point = static_cast<Point*>(element);
00602       extend(point->pos(), element->sheet());
00603     }
00604     else
00605     {
00606       extend(element->rect(), element->sheet());
00607     }
00608   }
00609 
00610   d->activeSubRegionLength += cells().count() - count;
00611 
00612   emit changed(*this);
00613 }
00614 
00615 Selection::Element* Selection::eor(const QPoint& point, Sheet* sheet)
00616 {
00617   if (isSingular())
00618   {
00619     return Region::add(point, sheet);
00620   }
00621   return Region::eor(point, sheet);
00622 }
00623 
00624 const QPoint& Selection::anchor() const
00625 {
00626   return d->anchor;
00627 }
00628 
00629 const QPoint& Selection::cursor() const
00630 {
00631   return d->cursor;
00632 }
00633 
00634 const QPoint& Selection::marker() const
00635 {
00636   return d->marker;
00637 }
00638 
00639 bool Selection::isSingular() const
00640 {
00641   return Region::isSingular();
00642 }
00643 
00644 QRect Selection::selectionHandleArea() const
00645 {
00646   int column, row;
00647 
00648   // complete rows/columns are selected, use the marker.
00649   if (isColumnOrRowSelected())
00650   {
00651     column = d->marker.x();
00652     row = d->marker.y();
00653   }
00654   else
00655   {
00656     column = lastRange().right();
00657     row = lastRange().bottom();
00658   }
00659   const Cell* cell = d->view->activeSheet()->cellAt(column, row);
00660 
00661   double xpos = d->view->activeSheet()->dblColumnPos( column );
00662   double ypos = d->view->activeSheet()->dblRowPos( row );
00663   double width = cell->dblWidth( column );
00664   double height = cell->dblHeight( row );
00665 
00666   QPoint rightBottom( d->view->doc()->zoomItX( xpos + width ),
00667                       d->view->doc()->zoomItY( ypos + height ) );
00668 
00669   QRect handle( ( rightBottom.x() - 2 ),
00670                   ( rightBottom.y() - 2 ),
00671                   ( 5 ),
00672                   ( 5 ) );
00673   return handle;
00674 }
00675 
00676 QString Selection::name(Sheet* sheet) const
00677 {
00678   return Region::name(sheet ? sheet : d->sheet);
00679 }
00680 
00681 void Selection::setSheet(Sheet* sheet)
00682 {
00683   d->sheet = sheet;
00684 }
00685 
00686 Sheet* Selection::sheet() const
00687 {
00688   return d->sheet;
00689 }
00690 
00691 void Selection::setActiveElement(const QPoint& point)
00692 {
00693   uint counter = 0;
00694   Iterator end = cells().end();
00695   for (Iterator it = cells().begin(); it != end; ++it)
00696   {
00697     QRect range = (*it)->rect();
00698     if (range.topLeft() == point || range.bottomRight() == point)
00699     {
00700       d->anchor = range.topLeft();
00701       d->cursor = range.bottomRight();
00702       d->marker = range.bottomRight();
00703       d->activeElement = it;
00704       d->activeSubRegionStart = counter;
00705       d->activeSubRegionLength = 1;
00706       if (d->view->canvasWidget()->editor())
00707       {
00708         d->view->canvasWidget()->editor()->setCursorToRange(counter);
00709       }
00710     }
00711     counter++;
00712   }
00713 }
00714 
00715 void Selection::setActiveElement(uint pos)
00716 {
00717   if (pos >= cells().count())
00718   {
00719     kdDebug() << "Selection::setActiveElement: position exceeds list" << endl;
00720     d->activeElement = cells().begin();
00721     return;
00722   }
00723 
00724   Iterator it = cells().begin() += pos;
00725   QRect range = (*it)->rect();
00726   d->anchor = range.topLeft();
00727   d->cursor = range.bottomRight();
00728   d->marker = range.bottomRight();
00729   d->activeElement = it;
00730 }
00731 
00732 Region::Element* Selection::activeElement() const
00733 {
00734   return (d->activeElement == cells().end()) ? 0 : *d->activeElement;
00735 }
00736 
00737 void Selection::clear()
00738 {
00739   d->activeSubRegionStart = 0;
00740   d->activeSubRegionLength = 0;
00741   Region::clear();
00742   d->activeElement = cells().begin();
00743 }
00744 
00745 void Selection::clearSubRegion()
00746 {
00747   if (isEmpty())
00748   {
00749     return;
00750   }
00751 //   kdDebug() << *this << endl;
00752 //   kdDebug() << d->activeSubRegionStart << endl;
00753 //   kdDebug() << d->activeSubRegionLength << endl;
00754 
00755   Iterator it = cells().begin();
00756   Iterator end = it += d->activeSubRegionStart;
00757   end += d->activeSubRegionLength;
00758   while (it != end)
00759   {
00760 /*    kdDebug() << (*it)->name() << endl;*/
00761     delete *it;
00762     it = cells().remove(it);
00763   }
00764   d->activeSubRegionLength = 0;
00765   d->activeElement = it;
00766 /*  kdDebug() << "ENDE" << endl;*/
00767 }
00768 
00769 void Selection::fixSubRegionDimension()
00770 {
00771   if (d->activeSubRegionStart > cells().count())
00772   {
00773     kdDebug() << "Selection::fixSubRegionDimension: start position exceeds list" << endl;
00774     d->activeSubRegionStart = 0;
00775     d->activeSubRegionLength = cells().count();
00776     return;
00777   }
00778   if (d->activeSubRegionStart + d->activeSubRegionLength > cells().count())
00779   {
00780     kdDebug() << "Selection::fixSubRegionDimension: length exceeds list" << endl;
00781     d->activeSubRegionLength = cells().count() - d->activeSubRegionStart;
00782     return;
00783   }
00784 }
00785 
00786 void Selection::setActiveSubRegion(uint start, uint length)
00787 {
00788 //   kdDebug() << k_funcinfo << endl;
00789   d->activeSubRegionStart = start;
00790   d->activeSubRegionLength = length;
00791   fixSubRegionDimension();
00792   d->activeElement = cells().begin() += d->activeSubRegionStart;
00793 }
00794 
00795 QString Selection::activeSubRegionName() const
00796 {
00797 //   kdDebug() << k_funcinfo << endl;
00798 //   kdDebug() << *this << endl;
00799 //   kdDebug() << "start = " << d->activeSubRegionStart << ", len = " << d->activeSubRegionLength << endl;
00800 
00801   QStringList names;
00802   Iterator it = cells().begin();
00803   it += d->activeSubRegionStart;
00804   Iterator end = it;
00805   end += d->activeSubRegionLength;
00806   while (it != end)
00807   {
00808     names += (*it++)->name(d->sheet);
00809   }
00810 /*  kdDebug() << "ENDE" << endl;*/
00811   return names.isEmpty() ? "" : names.join(";");
00812 }
00813 
00814 void Selection::setMultipleSelection(bool state)
00815 {
00816   d->multipleSelection = state;
00817 }
00818 
00819 const QValueList<QColor>& Selection::colors() const
00820 {
00821   return d->colors;
00822 }
00823 
00824 QRect Selection::lastRange(bool extend) const
00825 {
00826   QRect selection = QRect(d->anchor, d->marker).normalize();
00827   return extend ? extendToMergedAreas(selection) : selection;
00828 }
00829 
00830 QRect Selection::selection(bool extend) const
00831 {
00832   QRect selection = QRect(d->anchor, d->marker).normalize();
00833   return extend ? extendToMergedAreas(selection) : selection;
00834 }
00835 
00836 QRect Selection::extendToMergedAreas(QRect area) const
00837 {
00838   if (!d->view->activeSheet())
00839       return area;
00840 
00841   area = area.normalize(); // TODO Stefan: avoid this
00842   const Cell *cell = d->view->activeSheet()->cellAt(area.left(), area.top());
00843 
00844   if( Region::Range(area).isColumn() || Region::Range(area).isRow() )
00845   {
00846     return area;
00847   }
00848   else if ( !(cell->isObscured() && cell->isPartOfMerged()) &&
00849               (cell->mergedXCells() + 1) >= area.width() &&
00850               (cell->mergedYCells() + 1) >= area.height())
00851   {
00852     /* if just a single cell is selected, we need to merge even when
00853     the obscuring isn't forced.  But only if this is the cell that
00854     is doing the obscuring -- we still want to be able to click on a cell
00855     that is being obscured.
00856     */
00857     area.setWidth(cell->mergedXCells() + 1);
00858     area.setHeight(cell->mergedYCells() + 1);
00859   }
00860   else
00861   {
00862     int top=area.top();
00863     int left=area.left();
00864     int bottom=area.bottom();
00865     int right=area.right();
00866     for ( int x = area.left(); x <= area.right(); x++ )
00867       for ( int y = area.top(); y <= area.bottom(); y++ )
00868     {
00869       cell = d->view->activeSheet()->cellAt( x, y );
00870       if( cell->doesMergeCells())
00871       {
00872         right=QMAX(right,cell->mergedXCells()+x);
00873         bottom=QMAX(bottom,cell->mergedYCells()+y);
00874       }
00875       else if ( cell->isObscured() && cell->isPartOfMerged() )
00876       {
00877         cell = cell->obscuringCells().first();
00878         left=QMIN(left,cell->column());
00879         top=QMIN(top,cell->row());
00880         bottom=QMAX(bottom,cell->row() + cell->mergedYCells());
00881         right=QMAX(right,cell->column() + cell->mergedXCells());
00882       }
00883     }
00884 
00885     area.setCoords(left,top,right,bottom);
00886   }
00887   return area;
00888 }
00889 
00890 Selection::Region::Point* Selection::createPoint(const QPoint& point) const
00891 {
00892   return new Point(point);
00893 }
00894 
00895 Selection::Region::Point* Selection::createPoint(const QString& string) const
00896 {
00897   return new Point(string);
00898 }
00899 
00900 Selection::Region::Point* Selection::createPoint(const Point& point) const
00901 {
00902   return new Point(point);
00903 }
00904 
00905 Selection::Region::Range* Selection::createRange(const QRect& rect) const
00906 {
00907   return new Range(rect);
00908 }
00909 
00910 Selection::Region::Range* Selection::createRange(const QString& string) const
00911 {
00912   return new Range(string);
00913 }
00914 
00915 Selection::Region::Range* Selection::createRange(const Range& range) const
00916 {
00917   return new Range(range);
00918 }
00919 
00920 /***************************************************************************
00921   class Point
00922 ****************************************************************************/
00923 
00924 Selection::Point::Point(const QPoint& point)
00925   : Region::Point(point),
00926     m_color(Qt::black),
00927     m_columnFixed(false),
00928     m_rowFixed(false)
00929 {
00930 }
00931 
00932 Selection::Point::Point(const QString& string)
00933   : Region::Point(string),
00934     m_color(Qt::black),
00935     m_columnFixed(false),
00936     m_rowFixed(false)
00937 {
00938   if (!isValid())
00939   {
00940     return;
00941   }
00942 
00943   uint p = 0;
00944   // Fixed?
00945   if (string[p++] == '$')
00946   {
00947     m_columnFixed = true;
00948   }
00949 
00950   //search for the first character != text
00951   int result = string.find( QRegExp("[^A-Za-z]+"), p );
00952   if (string[result] == '$')
00953   {
00954     m_rowFixed = true;
00955   }
00956 }
00957 
00958 /***************************************************************************
00959   class Range
00960 ****************************************************************************/
00961 
00962 Selection::Range::Range(const QRect& range)
00963   : Region::Range(range),
00964     m_color(Qt::black),
00965     m_leftFixed(false),
00966     m_rightFixed(false),
00967     m_topFixed(false),
00968     m_bottomFixed(false)
00969 {
00970 }
00971 
00972 Selection::Range::Range(const QString& string)
00973   : Region::Range(string),
00974     m_color(Qt::black),
00975     m_leftFixed(false),
00976     m_rightFixed(false),
00977     m_topFixed(false),
00978     m_bottomFixed(false)
00979 {
00980   if (!isValid())
00981   {
00982     return;
00983   }
00984 
00985   int delimiterPos = string.find(':');
00986   if (delimiterPos == -1)
00987   {
00988     return;
00989   }
00990 
00991   Selection::Point ul(string.left(delimiterPos));
00992   Selection::Point lr(string.mid(delimiterPos + 1));
00993 
00994   if (!ul.isValid() || !lr.isValid())
00995   {
00996     return;
00997   }
00998   m_leftFixed = ul.columnFixed();
00999   m_rightFixed = lr.columnFixed();
01000   m_topFixed = ul.rowFixed();
01001   m_bottomFixed = lr.rowFixed();
01002 }
01003 
01004 } // namespace KSpread
01005 #include "selection.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys