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   d->activeSubRegionStart = 0;
00311   d->activeSubRegionLength = cells().count();
00312 
00313   if (changedRegion == *this)
00314   {
00315     return;
00316   }
00317   changedRegion.add( region );
00318 
00319   emit changed(changedRegion);
00320 }
00321 
00322 void Selection::update()
00323 {
00324   emit changed(*this);
00325 }
00326 
00327 void Selection::update(const QPoint& point)
00328 {
00329   uint count = cells().count();
00330 
00331   if (cells().isEmpty())
00332   {
00333     add(point);
00334     d->activeSubRegionLength += cells().count() - count;
00335     return;
00336   }
00337   if (d->activeElement == cells().end())
00338   {
00339     // we're not empty, so this will not become again end()
00340     d->activeElement--;
00341   }
00342 
00343   Sheet* sheet = (*d->activeElement)->sheet();
00344   if (sheet != d->view->activeSheet())
00345   {
00346     extend(point);
00347     d->activeSubRegionLength += cells().count() - count;
00348     return;
00349   }
00350 
00351   QPoint topLeft(point);
00352   Cell* cell = d->view->activeSheet()->cellAt(point);
00353   if (cell->isObscured() && cell->isPartOfMerged())
00354   {
00355     cell = cell->obscuringCells().first();
00356     topLeft = QPoint(cell->column(), cell->row());
00357   }
00358 
00359   if (topLeft == d->marker)
00360   {
00361     return;
00362   }
00363 
00364   QRect area1 = (*d->activeElement)->rect().normalize();
00365   QRect newRange = extendToMergedAreas(QRect(d->anchor, topLeft));
00366 
00367   Element* oldElement = *d->activeElement;
00368   // returns iterator to the next element or end
00369   Iterator it = cells().remove(d->activeElement);
00370   delete oldElement;
00371   // returns iterator to the new element (before 'it') or 'it'
00372   d->activeElement = insert(it, newRange, sheet, d->multipleSelection);
00373   d->activeSubRegionLength += cells().count() - count;
00374 
00375   // The call to insert() above can just return the iterator which has been
00376   // passed in. This may be cells.end(), if the old active element was the
00377   // iterator to the list's end (!= last element). So attempts to dereference
00378   // it will fail.
00379   if (d->activeElement == cells().end())
00380   {
00381     d->activeElement--;
00382   }
00383 
00384   QRect area2 = (*d->activeElement)->rect().normalize();
00385   Region changedRegion;
00386 
00387   bool newLeft   = area1.left() != area2.left();
00388   bool newTop    = area1.top() != area2.top();
00389   bool newRight  = area1.right() != area2.right();
00390   bool newBottom = area1.bottom() != area2.bottom();
00391 
00392   /* first, calculate some numbers that we'll use a few times */
00393   int farLeft = QMIN(area1.left(), area2.left());
00394   int innerLeft = QMAX(area1.left(), area2.left());
00395 
00396   int farTop = QMIN(area1.top(), area2.top());
00397   int innerTop = QMAX(area1.top(), area2.top());
00398 
00399   int farRight = QMAX(area1.right(), area2.right());
00400   int innerRight = QMIN(area1.right(), area2.right());
00401 
00402   int farBottom = QMAX(area1.bottom(), area2.bottom());
00403   int innerBottom = QMIN(area1.bottom(), area2.bottom());
00404 
00405   if (newLeft)
00406   {
00407     changedRegion.add(QRect(QPoint(farLeft, innerTop),
00408                       QPoint(innerLeft-1, innerBottom)));
00409     if (newTop)
00410     {
00411       changedRegion.add(QRect(QPoint(farLeft, farTop),
00412                         QPoint(innerLeft-1, innerTop-1)));
00413     }
00414     if (newBottom)
00415     {
00416       changedRegion.add(QRect(QPoint(farLeft, innerBottom+1),
00417                         QPoint(innerLeft-1, farBottom)));
00418     }
00419   }
00420 
00421   if (newTop)
00422   {
00423     changedRegion.add(QRect(QPoint(innerLeft, farTop),
00424                       QPoint(innerRight, innerTop-1)));
00425   }
00426 
00427   if (newRight)
00428   {
00429     changedRegion.add(QRect(QPoint(innerRight+1, innerTop),
00430                       QPoint(farRight, innerBottom)));
00431     if (newTop)
00432     {
00433       changedRegion.add(QRect(QPoint(innerRight+1, farTop),
00434                         QPoint(farRight, innerTop-1)));
00435     }
00436     if (newBottom)
00437     {
00438       changedRegion.add(QRect(QPoint(innerRight+1, innerBottom+1),
00439                         QPoint(farRight, farBottom)));
00440     }
00441   }
00442 
00443   if (newBottom)
00444   {
00445     changedRegion.add(QRect(QPoint(innerLeft, innerBottom+1),
00446                       QPoint(innerRight, farBottom)));
00447   }
00448 
00449   d->marker = topLeft;
00450   d->cursor = point;
00451 
00452   emit changed(changedRegion);
00453 }
00454 
00455 void Selection::extend(const QPoint& point, Sheet* sheet)
00456 {
00457     if (!util_isPointValid(point))
00458         return;
00459 
00460   if (isEmpty())
00461   {
00462     initialize(point, sheet);
00463     return;
00464   }
00465   if (d->activeElement == cells().end())
00466   {
00467     // we're not empty, so this will not become again end()
00468     d->activeElement--;
00469   }
00470 
00471   if (!sheet)
00472   {
00473     if (d->sheet)
00474     {
00475       sheet = d->sheet;
00476     }
00477     else
00478     {
00479       sheet = d->view->activeSheet();
00480     }
00481   }
00482 
00483   Region changedRegion = Region(extendToMergedAreas(QRect(d->marker,d->marker)));
00484 
00485   QPoint topLeft(point);
00486   Cell* cell = d->view->activeSheet()->cellAt(point);
00487   if (cell->isObscured() && cell->isPartOfMerged())
00488   {
00489     cell = cell->obscuringCells().first();
00490     topLeft = QPoint(cell->column(), cell->row());
00491   }
00492 
00493   uint count = cells().count();
00494   if (d->multipleSelection)
00495   {
00496     d->activeElement = insert(++d->activeElement, point, sheet, false);
00497   }
00498   else
00499   {
00500     eor(topLeft, sheet);
00501     d->activeElement = --cells().end();
00502   }
00503   d->anchor = (*d->activeElement)->rect().topLeft();
00504   d->cursor = (*d->activeElement)->rect().bottomRight();
00505   d->marker = d->cursor;
00506 
00507   d->activeSubRegionLength += cells().count() - count;
00508 
00509   changedRegion.add(topLeft, sheet);
00510   changedRegion.add(*this);
00511 
00512   emit changed(changedRegion);
00513 }
00514 
00515 void Selection::extend(const QRect& range, Sheet* sheet)
00516 {
00517     //See comment in Selection::initialize(const QRect& range, Sheet* sheet)
00518     if (!util_isRectValid(range) || (range == QRect(0,0,1,1)))
00519         return;
00520 
00521   if (isEmpty())
00522   {
00523     initialize(range, sheet);
00524     return;
00525   }
00526   if (d->activeElement == cells().end())
00527   {
00528     // we're not empty, so this will not become again end()
00529     d->activeElement--;
00530   }
00531 
00532   if (!sheet)
00533   {
00534     if (d->sheet)
00535     {
00536       sheet = d->sheet;
00537     }
00538     else
00539     {
00540       sheet = d->view->activeSheet();
00541     }
00542   }
00543 
00544   QPoint topLeft(range.topLeft());
00545   Cell* cell = d->view->activeSheet()->cellAt(topLeft);
00546   if (cell->isObscured() && cell->isPartOfMerged())
00547   {
00548     cell = cell->obscuringCells().first();
00549     topLeft = QPoint(cell->column(), cell->row());
00550   }
00551 
00552   QPoint bottomRight(range.bottomRight());
00553   cell = d->view->activeSheet()->cellAt(bottomRight);
00554   if (cell->isObscured() && cell->isPartOfMerged())
00555   {
00556     cell = cell->obscuringCells().first();
00557     bottomRight = QPoint(cell->column(), cell->row());
00558   }
00559 
00560   d->anchor = topLeft;
00561   d->cursor = topLeft;
00562   d->marker = bottomRight;
00563 
00564   uint count = cells().count();
00565   Element* element;
00566   if (d->multipleSelection)
00567   {
00568     d->activeElement = insert(++d->activeElement, extendToMergedAreas(QRect(topLeft, bottomRight)).normalize(), sheet, false);
00569     element = (d->activeElement == cells().end()) ? 0 : *d->activeElement;
00570   }
00571   else
00572   {
00573     element = add(extendToMergedAreas(QRect(topLeft, bottomRight)).normalize(), sheet);
00574     d->activeElement = --cells().end();
00575   }
00576   if (element && element->type() == Element::Point)
00577   {
00578     Point* point = static_cast<Point*>(element);
00579     point->setColor(d->colors[cells().size() % d->colors.size()]);
00580   }
00581   else if (element && element->type() == Element::Range)
00582   {
00583     Range* range = static_cast<Range*>(element);
00584     range->setColor(d->colors[cells().size() % d->colors.size()]);
00585   }
00586 
00587   d->activeSubRegionLength += cells().count() - count;
00588 
00589   emit changed(*this);
00590 }
00591 
00592 void Selection::extend(const Region& region)
00593 {
00594     if (!region.isValid())
00595         return;
00596 
00597   uint count = cells().count();
00598   ConstIterator end(region.constEnd());
00599   for (ConstIterator it = region.constBegin(); it != end; ++it)
00600   {
00601     Element *element = *it;
00602     if (!element) continue;
00603     if (element->type() == Element::Point)
00604     {
00605       Point* point = static_cast<Point*>(element);
00606       extend(point->pos(), element->sheet());
00607     }
00608     else
00609     {
00610       extend(element->rect(), element->sheet());
00611     }
00612   }
00613 
00614   d->activeSubRegionLength += cells().count() - count;
00615 
00616   emit changed(*this);
00617 }
00618 
00619 Selection::Element* Selection::eor(const QPoint& point, Sheet* sheet)
00620 {
00621   if (isSingular())
00622   {
00623     return Region::add(point, sheet);
00624   }
00625   return Region::eor(point, sheet);
00626 }
00627 
00628 const QPoint& Selection::anchor() const
00629 {
00630   return d->anchor;
00631 }
00632 
00633 const QPoint& Selection::cursor() const
00634 {
00635   return d->cursor;
00636 }
00637 
00638 const QPoint& Selection::marker() const
00639 {
00640   return d->marker;
00641 }
00642 
00643 bool Selection::isSingular() const
00644 {
00645   return Region::isSingular();
00646 }
00647 
00648 QRect Selection::selectionHandleArea() const
00649 {
00650   int column, row;
00651 
00652   // complete rows/columns are selected, use the marker.
00653   if (isColumnOrRowSelected())
00654   {
00655     column = d->marker.x();
00656     row = d->marker.y();
00657   }
00658   else
00659   {
00660     column = lastRange().right();
00661     row = lastRange().bottom();
00662   }
00663   const Cell* cell = d->view->activeSheet()->cellAt(column, row);
00664 
00665   double xpos = d->view->activeSheet()->dblColumnPos( column );
00666   double ypos = d->view->activeSheet()->dblRowPos( row );
00667   double width = cell->dblWidth( column );
00668   double height = cell->dblHeight( row );
00669 
00670   QPoint rightBottom( d->view->doc()->zoomItX( xpos + width ),
00671                       d->view->doc()->zoomItY( ypos + height ) );
00672 
00673   QRect handle( ( rightBottom.x() - 2 ),
00674                   ( rightBottom.y() - 2 ),
00675                   ( 5 ),
00676                   ( 5 ) );
00677   return handle;
00678 }
00679 
00680 QString Selection::name(Sheet* sheet) const
00681 {
00682   return Region::name(sheet ? sheet : d->sheet);
00683 }
00684 
00685 void Selection::setSheet(Sheet* sheet)
00686 {
00687   d->sheet = sheet;
00688 }
00689 
00690 Sheet* Selection::sheet() const
00691 {
00692   return d->sheet;
00693 }
00694 
00695 void Selection::setActiveElement(const QPoint& point)
00696 {
00697   uint counter = 0;
00698   Iterator end = cells().end();
00699   for (Iterator it = cells().begin(); it != end; ++it)
00700   {
00701     QRect range = (*it)->rect();
00702     if (range.topLeft() == point || range.bottomRight() == point)
00703     {
00704       d->anchor = range.topLeft();
00705       d->cursor = range.bottomRight();
00706       d->marker = range.bottomRight();
00707       d->activeElement = it;
00708       d->activeSubRegionStart = counter;
00709       d->activeSubRegionLength = 1;
00710       if (d->view->canvasWidget()->editor())
00711       {
00712         d->view->canvasWidget()->editor()->setCursorToRange(counter);
00713       }
00714     }
00715     counter++;
00716   }
00717 }
00718 
00719 void Selection::setActiveElement(uint pos)
00720 {
00721   if (pos >= cells().count())
00722   {
00723     kdDebug() << "Selection::setActiveElement: position exceeds list" << endl;
00724     d->activeElement = cells().begin();
00725     return;
00726   }
00727 
00728   Iterator it = cells().begin() += pos;
00729   QRect range = (*it)->rect();
00730   d->anchor = range.topLeft();
00731   d->cursor = range.bottomRight();
00732   d->marker = range.bottomRight();
00733   d->activeElement = it;
00734 }
00735 
00736 Region::Element* Selection::activeElement() const
00737 {
00738   return (d->activeElement == cells().end()) ? 0 : *d->activeElement;
00739 }
00740 
00741 void Selection::clear()
00742 {
00743   d->activeSubRegionStart = 0;
00744   d->activeSubRegionLength = 0;
00745   Region::clear();
00746   d->activeElement = cells().begin();
00747 }
00748 
00749 void Selection::clearSubRegion()
00750 {
00751   if (isEmpty())
00752   {
00753     return;
00754   }
00755 //   kdDebug() << *this << endl;
00756 //   kdDebug() << d->activeSubRegionStart << endl;
00757 //   kdDebug() << d->activeSubRegionLength << endl;
00758 
00759   Iterator it = cells().begin();
00760   Iterator end = it += d->activeSubRegionStart;
00761   end += d->activeSubRegionLength;
00762   while (it != end)
00763   {
00764 /*    kdDebug() << (*it)->name() << endl;*/
00765     delete *it;
00766     it = cells().remove(it);
00767   }
00768   d->activeSubRegionLength = 0;
00769   d->activeElement = it;
00770 /*  kdDebug() << "ENDE" << endl;*/
00771 }
00772 
00773 void Selection::fixSubRegionDimension()
00774 {
00775   if (d->activeSubRegionStart > cells().count())
00776   {
00777     kdDebug() << "Selection::fixSubRegionDimension: start position exceeds list" << endl;
00778     d->activeSubRegionStart = 0;
00779     d->activeSubRegionLength = cells().count();
00780     return;
00781   }
00782   if (d->activeSubRegionStart + d->activeSubRegionLength > cells().count())
00783   {
00784     kdDebug() << "Selection::fixSubRegionDimension: length exceeds list" << endl;
00785     d->activeSubRegionLength = cells().count() - d->activeSubRegionStart;
00786     return;
00787   }
00788 }
00789 
00790 void Selection::setActiveSubRegion(uint start, uint length)
00791 {
00792 //   kdDebug() << k_funcinfo << endl;
00793   d->activeSubRegionStart = start;
00794   d->activeSubRegionLength = length;
00795   fixSubRegionDimension();
00796   d->activeElement = cells().begin() += d->activeSubRegionStart;
00797 }
00798 
00799 QString Selection::activeSubRegionName() const
00800 {
00801 //   kdDebug() << k_funcinfo << endl;
00802 //   kdDebug() << *this << endl;
00803 //   kdDebug() << "start = " << d->activeSubRegionStart << ", len = " << d->activeSubRegionLength << endl;
00804 
00805   QStringList names;
00806   Iterator it = cells().begin();
00807   it += d->activeSubRegionStart;
00808   Iterator end = it;
00809   end += d->activeSubRegionLength;
00810   while (it != end)
00811   {
00812     names += (*it++)->name(d->sheet);
00813   }
00814 /*  kdDebug() << "ENDE" << endl;*/
00815   return names.isEmpty() ? "" : names.join(";");
00816 }
00817 
00818 void Selection::setMultipleSelection(bool state)
00819 {
00820   d->multipleSelection = state;
00821 }
00822 
00823 const QValueList<QColor>& Selection::colors() const
00824 {
00825   return d->colors;
00826 }
00827 
00828 QRect Selection::lastRange(bool extend) const
00829 {
00830   QRect selection = QRect(d->anchor, d->marker).normalize();
00831   return extend ? extendToMergedAreas(selection) : selection;
00832 }
00833 
00834 QRect Selection::selection(bool extend) const
00835 {
00836   QRect selection = QRect(d->anchor, d->marker).normalize();
00837   return extend ? extendToMergedAreas(selection) : selection;
00838 }
00839 
00840 QRect Selection::extendToMergedAreas(QRect area) const
00841 {
00842   if (!d->view->activeSheet())
00843       return area;
00844 
00845   area = area.normalize(); // TODO Stefan: avoid this
00846   const Cell *cell = d->view->activeSheet()->cellAt(area.left(), area.top());
00847 
00848   if( Region::Range(area).isColumn() || Region::Range(area).isRow() )
00849   {
00850     return area;
00851   }
00852   else if ( !(cell->isObscured() && cell->isPartOfMerged()) &&
00853               (cell->mergedXCells() + 1) >= area.width() &&
00854               (cell->mergedYCells() + 1) >= area.height())
00855   {
00856     /* if just a single cell is selected, we need to merge even when
00857     the obscuring isn't forced.  But only if this is the cell that
00858     is doing the obscuring -- we still want to be able to click on a cell
00859     that is being obscured.
00860     */
00861     area.setWidth(cell->mergedXCells() + 1);
00862     area.setHeight(cell->mergedYCells() + 1);
00863   }
00864   else
00865   {
00866     int top=area.top();
00867     int left=area.left();
00868     int bottom=area.bottom();
00869     int right=area.right();
00870     for ( int x = area.left(); x <= area.right(); x++ )
00871       for ( int y = area.top(); y <= area.bottom(); y++ )
00872     {
00873       cell = d->view->activeSheet()->cellAt( x, y );
00874       if( cell->doesMergeCells())
00875       {
00876         right=QMAX(right,cell->mergedXCells()+x);
00877         bottom=QMAX(bottom,cell->mergedYCells()+y);
00878       }
00879       else if ( cell->isObscured() && cell->isPartOfMerged() )
00880       {
00881         cell = cell->obscuringCells().first();
00882         left=QMIN(left,cell->column());
00883         top=QMIN(top,cell->row());
00884         bottom=QMAX(bottom,cell->row() + cell->mergedYCells());
00885         right=QMAX(right,cell->column() + cell->mergedXCells());
00886       }
00887     }
00888 
00889     area.setCoords(left,top,right,bottom);
00890   }
00891   return area;
00892 }
00893 
00894 Selection::Region::Point* Selection::createPoint(const QPoint& point) const
00895 {
00896   return new Point(point);
00897 }
00898 
00899 Selection::Region::Point* Selection::createPoint(const QString& string) const
00900 {
00901   return new Point(string);
00902 }
00903 
00904 Selection::Region::Point* Selection::createPoint(const Point& point) const
00905 {
00906   return new Point(point);
00907 }
00908 
00909 Selection::Region::Range* Selection::createRange(const QRect& rect) const
00910 {
00911   return new Range(rect);
00912 }
00913 
00914 Selection::Region::Range* Selection::createRange(const QString& string) const
00915 {
00916   return new Range(string);
00917 }
00918 
00919 Selection::Region::Range* Selection::createRange(const Range& range) const
00920 {
00921   return new Range(range);
00922 }
00923 
00924 /***************************************************************************
00925   class Point
00926 ****************************************************************************/
00927 
00928 Selection::Point::Point(const QPoint& point)
00929   : Region::Point(point),
00930     m_color(Qt::black),
00931     m_columnFixed(false),
00932     m_rowFixed(false)
00933 {
00934 }
00935 
00936 Selection::Point::Point(const QString& string)
00937   : Region::Point(string),
00938     m_color(Qt::black),
00939     m_columnFixed(false),
00940     m_rowFixed(false)
00941 {
00942   if (!isValid())
00943   {
00944     return;
00945   }
00946 
00947   uint p = 0;
00948   // Fixed?
00949   if (string[p++] == '$')
00950   {
00951     m_columnFixed = true;
00952   }
00953 
00954   //search for the first character != text
00955   int result = string.find( QRegExp("[^A-Za-z]+"), p );
00956   if (string[result] == '$')
00957   {
00958     m_rowFixed = true;
00959   }
00960 }
00961 
00962 /***************************************************************************
00963   class Range
00964 ****************************************************************************/
00965 
00966 Selection::Range::Range(const QRect& range)
00967   : Region::Range(range),
00968     m_color(Qt::black),
00969     m_leftFixed(false),
00970     m_rightFixed(false),
00971     m_topFixed(false),
00972     m_bottomFixed(false)
00973 {
00974 }
00975 
00976 Selection::Range::Range(const QString& string)
00977   : Region::Range(string),
00978     m_color(Qt::black),
00979     m_leftFixed(false),
00980     m_rightFixed(false),
00981     m_topFixed(false),
00982     m_bottomFixed(false)
00983 {
00984   if (!isValid())
00985   {
00986     return;
00987   }
00988 
00989   int delimiterPos = string.find(':');
00990   if (delimiterPos == -1)
00991   {
00992     return;
00993   }
00994 
00995   Selection::Point ul(string.left(delimiterPos));
00996   Selection::Point lr(string.mid(delimiterPos + 1));
00997 
00998   if (!ul.isValid() || !lr.isValid())
00999   {
01000     return;
01001   }
01002   m_leftFixed = ul.columnFixed();
01003   m_rightFixed = lr.columnFixed();
01004   m_topFixed = ul.rowFixed();
01005   m_bottomFixed = lr.rowFixed();
01006 }
01007 
01008 } // namespace KSpread
01009 #include "selection.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys