File indexing completed on 2024-05-19 16:08:53

0001 /* This file is part of the KDE project
0002    Copyright 2006-2008 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003    Copyright 2006 Robert Knight <robertknight@gmail.com>
0004    Copyright 2006 Inge Wallin <inge@lysator.liu.se>
0005    Copyright 1999-2002,2004 Laurent Montel <montel@kde.org>
0006    Copyright 2002-2005 Ariya Hidayat <ariya@kde.org>
0007    Copyright 1999-2004 David Faure <faure@kde.org>
0008    Copyright 2004-2005 Meni Livne <livne@kde.org>
0009    Copyright 2001-2003 Philipp Mueller <philipp.mueller@gmx.de>
0010    Copyright 2002-2003 Norbert Andres <nandres@web.de>
0011    Copyright 2003 Hamish Rodda <rodda@kde.org>
0012    Copyright 2003 Joseph Wenninger <jowenn@kde.org>
0013    Copyright 2003 Lukas Tinkl <lukas@kde.org>
0014    Copyright 2000-2002 Werner Trobin <trobin@kde.org>
0015    Copyright 2002 Harri Porten <porten@kde.org>
0016    Copyright 2002 John Dailey <dailey@vt.edu>
0017    Copyright 2002 Daniel Naber <daniel.naber@t-online.de>
0018    Copyright 1999-2000 Torben Weis <weis@kde.org>
0019    Copyright 1999-2000 Stephan Kulow <coolo@kde.org>
0020    Copyright 2000 Bernd Wuebben <wuebben@kde.org>
0021    Copyright 2000 Wilco Greven <greven@kde.org>
0022    Copyright 2000 Simon Hausmann <hausmann@kde.org
0023    Copyright 1999 Michael Reiher <michael.reiher@gmx.de>
0024    Copyright 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
0025    Copyright 1999 Reginald Stadlbauer <reggie@kde.org>
0026 
0027    This library is free software; you can redistribute it and/or
0028    modify it under the terms of the GNU Library General Public
0029    License as published by the Free Software Foundation; either
0030    version 2 of the License, or(at your option) any later version.
0031 
0032    This library is distributed in the hope that it will be useful,
0033    but WITHOUT ANY WARRANTY; without even the implied warranty of
0034    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0035    Library General Public License for more details.
0036 
0037    You should have received a copy of the GNU Library General Public License
0038    along with this library; see the file COPYING.LIB.  If not, write to
0039    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0040    Boston, MA 02110-1301, USA.
0041 */
0042 
0043 #include "CellToolBase_p.h"
0044 #include "CellToolBase.h"
0045 
0046 // Sheets
0047 #include "ApplicationSettings.h"
0048 #include "CalculationSettings.h"
0049 #include "CellStorage.h"
0050 #include "Map.h"
0051 #include "RowColumnFormat.h"
0052 #include "RowFormatStorage.h"
0053 #include "Selection.h"
0054 #include "Sheet.h"
0055 
0056 // commands
0057 #include "commands/DataManipulators.h"
0058 #include "commands/StyleCommand.h"
0059 
0060 // ui
0061 #include "ui/CellEditor.h"
0062 #include "ui/ExternalEditor.h"
0063 #include "ui/SheetView.h"
0064 
0065 // Calligra
0066 #include <KoCanvasBase.h>
0067 #include <KoCanvasController.h>
0068 #include <KoCanvasResourceManager.h>
0069 #include <KoViewConverter.h>
0070 #include <KoColor.h>
0071 #include <KoIcon.h>
0072 
0073 // KF5
0074 #include <kfontaction.h>
0075 #include <kfontsizeaction.h>
0076 #include <klocale.h>
0077 
0078 // Qt
0079 #include <QApplication>
0080 #include <QGridLayout>
0081 #include <QPainter>
0082 #include <QToolButton>
0083 
0084 using namespace Calligra::Sheets;
0085 
0086 void CellToolBase::Private::updateEditor(const Cell& cell)
0087 {
0088     if (!externalEditor) return;
0089     const Cell& theCell = cell.isPartOfMerged() ? cell.masterCell() : cell;
0090     const Style style = theCell.style();
0091     if (q->selection()->activeSheet()->isProtected() && style.hideFormula()) {
0092         externalEditor->setPlainText(theCell.displayText());
0093     } else if (q->selection()->activeSheet()->isProtected() && style.hideAll()) {
0094         externalEditor->clear();
0095     } else {
0096         externalEditor->setPlainText(theCell.userInput());
0097     }
0098 }
0099 
0100 #define ACTION_EXEC( name, command ) { \
0101         QAction *a = q->action(name); \
0102         const bool blocked = a->blockSignals(true); \
0103         a->command; \
0104         a->blockSignals(blocked); \
0105     }
0106 
0107 void CellToolBase::Private::updateActions(const Cell& cell)
0108 {
0109     const Style style = cell.style();
0110 
0111     // -- font actions --
0112     ACTION_EXEC("bold", setChecked(style.bold()));
0113     ACTION_EXEC("italic", setChecked(style.italic()));
0114     ACTION_EXEC("underline", setChecked(style.underline()));
0115     ACTION_EXEC("strikeOut", setChecked(style.strikeOut()));
0116 
0117     static_cast<KFontAction*>(q->action("font"))->setFont(style.fontFamily());
0118     static_cast<KFontSizeAction*>(q->action("fontSize"))->setFontSize(style.fontSize());
0119     // -- horizontal alignment actions --
0120     ACTION_EXEC("alignLeft", setChecked(style.halign() == Style::Left));
0121     ACTION_EXEC("alignCenter", setChecked(style.halign() == Style::Center));
0122     ACTION_EXEC("alignRight", setChecked(style.halign() == Style::Right));
0123     // -- vertical alignment actions --
0124     ACTION_EXEC("alignTop", setChecked(style.valign() == Style::Top));
0125     ACTION_EXEC("alignMiddle", setChecked(style.valign() == Style::Middle));
0126     ACTION_EXEC("alignBottom", setChecked(style.valign() == Style::Bottom));
0127 
0128     ACTION_EXEC("verticalText", setChecked(style.verticalText()));
0129     ACTION_EXEC("wrapText", setChecked(style.wrapText()));
0130 
0131     Format::Type ft = style.formatType();
0132     ACTION_EXEC("percent", setChecked(ft == Format::Percentage));
0133     ACTION_EXEC("currency", setChecked(ft == Format::Money));
0134 
0135     const bool showFormulas = q->selection()->activeSheet()->getShowFormula();
0136     q->action("alignLeft")->setEnabled(!showFormulas);
0137     q->action("alignCenter")->setEnabled(!showFormulas);
0138     q->action("alignRight")->setEnabled(!showFormulas);
0139 
0140     if (!q->selection()->activeSheet()->isProtected() || style.notProtected()) {
0141         q->action("clearComment")->setEnabled(!cell.comment().isEmpty());
0142         q->action("decreaseIndentation")->setEnabled(style.indentation() > 0.0);
0143     }
0144 
0145     // Now, activate/deactivate some actions depending on what is selected.
0146     if (!q->selection()->activeSheet()->isProtected()) {
0147         const bool colSelected = q->selection()->isColumnSelected();
0148         const bool rowSelected = q->selection()->isRowSelected();
0149         // -- column & row actions --
0150         q->action("resizeCol")->setEnabled(!rowSelected);
0151         q->action("insertColumn")->setEnabled(!rowSelected);
0152         q->action("deleteColumn")->setEnabled(!rowSelected);
0153         q->action("hideColumn")->setEnabled(!rowSelected);
0154         q->action("equalizeCol")->setEnabled(!rowSelected);
0155         q->action("resizeRow")->setEnabled(!colSelected);
0156         q->action("deleteRow")->setEnabled(!colSelected);
0157         q->action("insertRow")->setEnabled(!colSelected);
0158         q->action("hideRow")->setEnabled(!colSelected);
0159         q->action("equalizeRow")->setEnabled(!colSelected);
0160         // -- data insert actions --
0161         q->action("textToColumns")->setEnabled(!rowSelected);
0162 
0163         const bool simpleSelection = q->selection()->isSingular() || colSelected || rowSelected;
0164         q->action("sheetFormat")->setEnabled(!simpleSelection);
0165         q->action("sort")->setEnabled(!simpleSelection);
0166         q->action("sortDec")->setEnabled(!simpleSelection);
0167         q->action("sortInc")->setEnabled(!simpleSelection);
0168         q->action("mergeCells")->setEnabled(!simpleSelection);
0169         q->action("mergeCellsHorizontal")->setEnabled(!simpleSelection);
0170         q->action("mergeCellsVertical")->setEnabled(!simpleSelection);
0171         q->action("fillRight")->setEnabled(!simpleSelection);
0172         q->action("fillUp")->setEnabled(!simpleSelection);
0173         q->action("fillDown")->setEnabled(!simpleSelection);
0174         q->action("fillLeft")->setEnabled(!simpleSelection);
0175         q->action("createStyleFromCell")->setEnabled(simpleSelection); // just from one cell
0176 
0177         const bool contiguousSelection = q->selection()->isContiguous();
0178         q->action("subtotals")->setEnabled(contiguousSelection);
0179     }
0180 }
0181 
0182 void CellToolBase::Private::setProtectedActionsEnabled(bool enable)
0183 {
0184     // Enable/disable actions.
0185     const QList<QAction*> actions = q->actions().values();
0186     for (int i = 0; i < actions.count(); ++i)
0187         actions[i]->setEnabled(enable);
0188     q->action("insertFormula")->setEnabled(enable);
0189     if (externalEditor) externalEditor->setEnabled(enable);
0190 
0191     // These actions are always enabled.
0192     q->action("copy")->setEnabled(true);
0193     q->action("gotoCell")->setEnabled(true);
0194     q->action("edit_find")->setEnabled(true);
0195     q->action("edit_find_next")->setEnabled(true);
0196     q->action("edit_find_last")->setEnabled(true);
0197 }
0198 
0199 void CellToolBase::Private::processEnterKey(QKeyEvent* event)
0200 {
0201 // array is true, if ctrl+alt are pressed
0202     bool array = (event->modifiers() & Qt::AltModifier) &&
0203                  (event->modifiers() & Qt::ControlModifier);
0204 
0205     /* save changes to the current editor */
0206     q->deleteEditor(true, array);
0207 
0208     /* use the configuration setting to see which direction we're supposed to move
0209         when enter is pressed.
0210     */
0211     Calligra::Sheets::MoveTo direction = q->selection()->activeSheet()->map()->settings()->moveToValue();
0212 
0213 //if shift Button clicked inverse move direction
0214     if (event->modifiers() & Qt::ShiftModifier) {
0215         switch (direction) {
0216         case Bottom:
0217             direction = Top;
0218             break;
0219         case Top:
0220             direction = Bottom;
0221             break;
0222         case Left:
0223             direction = Right;
0224             break;
0225         case Right:
0226             direction = Left;
0227             break;
0228         case BottomFirst:
0229             direction = BottomFirst;
0230             break;
0231         case NoMovement:
0232             direction = NoMovement;
0233             break;
0234         }
0235     }
0236 
0237     /* never extend a selection with the enter key -- the shift key reverses
0238         direction, not extends the selection
0239     */
0240     QRect r(moveDirection(direction, false));
0241     event->accept(); // QKeyEvent
0242 }
0243 
0244 void CellToolBase::Private::processArrowKey(QKeyEvent *event)
0245 {
0246     /* NOTE:  hitting the tab key also calls this function.  Don't forget
0247         to account for it
0248     */
0249     register Sheet * const sheet = q->selection()->activeSheet();
0250     if (!sheet)
0251         return;
0252 
0253     /* save changes to the current editor */
0254     q->selection()->emitCloseEditor(true);
0255 
0256     Calligra::Sheets::MoveTo direction = Bottom;
0257     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0258 
0259     switch (event->key()) {
0260     case Qt::Key_Down:
0261         direction = Bottom;
0262         break;
0263     case Qt::Key_Up:
0264         direction = Top;
0265         break;
0266     case Qt::Key_Left:
0267         if (sheet->layoutDirection() == Qt::RightToLeft)
0268             direction = Right;
0269         else
0270             direction = Left;
0271         break;
0272     case Qt::Key_Right:
0273         if (sheet->layoutDirection() == Qt::RightToLeft)
0274             direction = Left;
0275         else
0276             direction = Right;
0277         break;
0278     case Qt::Key_Tab:
0279         direction = Right;
0280         break;
0281     case Qt::Key_Backtab:
0282         //Shift+Tab moves to the left
0283         direction = Left;
0284         makingSelection = false;
0285         break;
0286     default:
0287         Q_ASSERT(false);
0288         break;
0289     }
0290 
0291     QRect r(moveDirection(direction, makingSelection));
0292     event->accept(); // QKeyEvent
0293 }
0294 
0295 void CellToolBase::Private::processEscapeKey(QKeyEvent * event)
0296 {
0297     q->selection()->emitCloseEditor(false); // discard changes
0298     event->accept(); // QKeyEvent
0299 }
0300 
0301 bool CellToolBase::Private::processHomeKey(QKeyEvent* event)
0302 {
0303     register Sheet * const sheet = q->selection()->activeSheet();
0304     if (!sheet)
0305         return false;
0306 
0307     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0308 
0309     if (q->editor()) {
0310         // We are in edit mode -> go beginning of line
0311         QApplication::sendEvent(q->editor()->widget(), event);
0312         return false;
0313     } else {
0314         QPoint destination;
0315         /* start at the first used cell in the row and cycle through the right until
0316             we find a cell that has some output text.  But don't look past the current
0317             marker.
0318             The end result we want is to move to the left to the first cell with text,
0319             or just to the first column if there is no more text to the left.
0320 
0321             But why?  In excel, home key sends you to the first column always.
0322             We might want to change to that behavior.
0323         */
0324 
0325         if (event->modifiers() & Qt::ControlModifier) {
0326             /* ctrl + Home will always just send us to location (1,1) */
0327             destination = QPoint(1, 1);
0328         } else {
0329             QPoint marker = q->selection()->marker();
0330 
0331             Cell cell = sheet->cellStorage()->firstInRow(marker.y(), CellStorage::VisitContent);
0332             while (!cell.isNull() && cell.column() < marker.x() && cell.isEmpty()) {
0333                 cell = sheet->cellStorage()->nextInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0334             }
0335 
0336             int col = (!cell.isNull() ? cell.column() : 1);
0337             if (col == marker.x())
0338                 col = 1;
0339             destination = QPoint(col, marker.y());
0340         }
0341 
0342         if (q->selection()->marker() == destination)
0343             return false;
0344 
0345         if (makingSelection) {
0346             q->selection()->update(destination);
0347         } else {
0348             q->selection()->initialize(destination, sheet);
0349         }
0350         q->scrollToCell(destination);
0351         event->accept(); // QKeyEvent
0352     }
0353     return true;
0354 }
0355 
0356 bool CellToolBase::Private::processEndKey(QKeyEvent *event)
0357 {
0358     register Sheet * const sheet = q->selection()->activeSheet();
0359     if (!sheet)
0360         return false;
0361 
0362     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0363     Cell cell;
0364     QPoint marker = q->selection()->marker();
0365 
0366     if (q->editor()) {
0367         // We are in edit mode -> go end of line
0368         QApplication::sendEvent(q->editor()->widget(), event);
0369         return false;
0370     } else {
0371         // move to the last used cell in the row
0372         int col = 1;
0373 
0374         cell = sheet->cellStorage()->lastInRow(marker.y(), CellStorage::VisitContent);
0375         while (!cell.isNull() && cell.column() > q->selection()->marker().x() && cell.isEmpty()) {
0376             cell = sheet->cellStorage()->prevInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0377         }
0378 
0379         col = (cell.isNull()) ? q->maxCol() : cell.column();
0380 
0381         QPoint destination(col, marker.y());
0382         if (destination == marker)
0383             return false;
0384 
0385         if (makingSelection) {
0386             q->selection()->update(destination);
0387         } else {
0388             q->selection()->initialize(destination, sheet);
0389         }
0390         q->scrollToCell(destination);
0391         event->accept(); // QKeyEvent
0392     }
0393     return true;
0394 }
0395 
0396 bool CellToolBase::Private::processPriorKey(QKeyEvent *event)
0397 {
0398     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0399     q->selection()->emitCloseEditor(true); // save changes
0400 
0401     QPoint marker = q->selection()->marker();
0402 
0403     QPoint destination(marker.x(), qMax(1, marker.y() - 10));
0404     if (destination == marker)
0405         return false;
0406 
0407     if (makingSelection) {
0408         q->selection()->update(destination);
0409     } else {
0410         q->selection()->initialize(destination, q->selection()->activeSheet());
0411     }
0412     q->scrollToCell(destination);
0413     event->accept(); // QKeyEvent
0414     return true;
0415 }
0416 
0417 bool CellToolBase::Private::processNextKey(QKeyEvent *event)
0418 {
0419     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0420 
0421     q->selection()->emitCloseEditor(true); // save changes
0422 
0423     QPoint marker = q->selection()->marker();
0424     QPoint destination(marker.x(), qMax(1, marker.y() + 10));
0425 
0426     if (marker == destination)
0427         return false;
0428 
0429     if (makingSelection) {
0430         q->selection()->update(destination);
0431     } else {
0432         q->selection()->initialize(destination, q->selection()->activeSheet());
0433     }
0434     q->scrollToCell(destination);
0435     event->accept(); // QKeyEvent
0436     return true;
0437 }
0438 
0439 void CellToolBase::Private::processOtherKey(QKeyEvent *event)
0440 {
0441     register Sheet * const sheet = q->selection()->activeSheet();
0442 
0443     // No null character ...
0444     if (event->text().isEmpty() || !q->selection()->activeSheet()->map()->isReadWrite() ||
0445             !sheet || sheet->isProtected()) {
0446         event->accept(); // QKeyEvent
0447     } else {
0448         if (!q->editor()) {
0449             // Switch to editing mode
0450             q->createEditor();
0451         }
0452         // Send it to the embedded editor.
0453         QApplication::sendEvent(q->editor()->widget(), event);
0454     }
0455 }
0456 
0457 bool CellToolBase::Private::processControlArrowKey(QKeyEvent *event)
0458 {
0459     register Sheet * const sheet = q->selection()->activeSheet();
0460     if (!sheet)
0461         return false;
0462 
0463     bool makingSelection = event->modifiers() & Qt::ShiftModifier;
0464 
0465     Cell cell;
0466     Cell lastCell;
0467     QPoint destination;
0468     bool searchThroughEmpty = true;
0469     int row;
0470     int col;
0471 
0472     QPoint marker = q->selection()->marker();
0473 
0474     /* here, we want to move to the first or last cell in the given direction that is
0475         actually being used.  Ignore empty cells and cells on hidden rows/columns */
0476     switch (event->key()) {
0477         //Ctrl+Qt::Key_Up
0478     case Qt::Key_Up:
0479 
0480         cell = Cell(sheet, marker.x(), marker.y());
0481         if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.y() != 1)) {
0482             lastCell = cell;
0483             row = marker.y() - 1;
0484             cell = Cell(sheet, cell.column(), row);
0485             while ((!cell.isNull()) && (row > 0) && (!cell.isEmpty())) {
0486                 if (!sheet->rowFormats()->isHiddenOrFiltered(cell.row())) {
0487                     lastCell = cell;
0488                     searchThroughEmpty = false;
0489                 }
0490                 row--;
0491                 if (row > 0)
0492                     cell = Cell(sheet, cell.column(), row);
0493             }
0494             cell = lastCell;
0495         }
0496         if (searchThroughEmpty) {
0497             cell = sheet->cellStorage()->prevInColumn(marker.x(), marker.y(), CellStorage::VisitContent);
0498 
0499             while ((!cell.isNull()) &&
0500                     (cell.isEmpty() || (sheet->rowFormats()->isHiddenOrFiltered(cell.row())))) {
0501                 cell = sheet->cellStorage()->prevInColumn(cell.column(), cell.row(), CellStorage::VisitContent);
0502             }
0503         }
0504 
0505         if (cell.isNull())
0506             row = 1;
0507         else
0508             row = cell.row();
0509 
0510         int lastHiddenOrFiltered;
0511         while (sheet->rowFormats()->isHiddenOrFiltered(row, &lastHiddenOrFiltered)) {
0512             row = lastHiddenOrFiltered + 1;
0513         }
0514 
0515         destination.setX(qBound(1, marker.x(), q->maxCol()));
0516         destination.setY(qBound(1, row, q->maxRow()));
0517         break;
0518 
0519         //Ctrl+Qt::Key_Down
0520     case Qt::Key_Down:
0521 
0522         cell = Cell(sheet, marker.x(), marker.y());
0523         if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.y() != q->maxRow())) {
0524             lastCell = cell;
0525             row = marker.y() + 1;
0526             cell = Cell(sheet, cell.column(), row);
0527             while ((!cell.isNull()) && (row < q->maxRow()) && (!cell.isEmpty())) {
0528                 if (!(sheet->rowFormats()->isHiddenOrFiltered(cell.row()))) {
0529                     lastCell = cell;
0530                     searchThroughEmpty = false;
0531                 }
0532                 row++;
0533                 cell = Cell(sheet, cell.column(), row);
0534             }
0535             cell = lastCell;
0536         }
0537         if (searchThroughEmpty) {
0538             cell = sheet->cellStorage()->nextInColumn(marker.x(), marker.y(), CellStorage::VisitContent);
0539 
0540             while ((!cell.isNull()) &&
0541                     (cell.isEmpty() || (sheet->rowFormats()->isHiddenOrFiltered(cell.row())))) {
0542                 cell = sheet->cellStorage()->nextInColumn(cell.column(), cell.row(), CellStorage::VisitContent);
0543             }
0544         }
0545 
0546         if (cell.isNull())
0547             row = marker.y();
0548         else
0549             row = cell.row();
0550 
0551         int firstHiddenOrFiltered;
0552         while (row >= 1 && sheet->rowFormats()->isHiddenOrFiltered(row, 0, &firstHiddenOrFiltered)) {
0553             row = firstHiddenOrFiltered - 1;
0554         }
0555 
0556         destination.setX(qBound(1, marker.x(), q->maxCol()));
0557         destination.setY(qBound(1, row, q->maxRow()));
0558         break;
0559 
0560 //Ctrl+Qt::Key_Left
0561     case Qt::Key_Left:
0562 
0563         if (sheet->layoutDirection() == Qt::RightToLeft) {
0564             cell = Cell(sheet, marker.x(), marker.y());
0565             if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.x() != q->maxCol())) {
0566                 lastCell = cell;
0567                 col = marker.x() + 1;
0568                 cell = Cell(sheet, col, cell.row());
0569                 while ((!cell.isNull()) && (col < q->maxCol()) && (!cell.isEmpty())) {
0570                     if (!(sheet->columnFormat(cell.column())->isHiddenOrFiltered())) {
0571                         lastCell = cell;
0572                         searchThroughEmpty = false;
0573                     }
0574                     col++;
0575                     cell = Cell(sheet, col, cell.row());
0576                 }
0577                 cell = lastCell;
0578             }
0579             if (searchThroughEmpty) {
0580                 cell = sheet->cellStorage()->nextInRow(marker.x(), marker.y(), CellStorage::VisitContent);
0581 
0582                 while ((!cell.isNull()) &&
0583                         (cell.isEmpty() || (sheet->columnFormat(cell.column())->isHiddenOrFiltered()))) {
0584                     cell = sheet->cellStorage()->nextInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0585                 }
0586             }
0587 
0588             if (cell.isNull())
0589                 col = marker.x();
0590             else
0591                 col = cell.column();
0592 
0593             while (sheet->columnFormat(col)->isHiddenOrFiltered()) {
0594                 col--;
0595             }
0596 
0597             destination.setX(qBound(1, col, q->maxCol()));
0598             destination.setY(qBound(1, marker.y(), q->maxRow()));
0599         } else {
0600             cell = Cell(sheet, marker.x(), marker.y());
0601             if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.x() != 1)) {
0602                 lastCell = cell;
0603                 col = marker.x() - 1;
0604                 cell = Cell(sheet, col, cell.row());
0605                 while ((!cell.isNull()) && (col > 0) && (!cell.isEmpty())) {
0606                     if (!(sheet->columnFormat(cell.column())->isHiddenOrFiltered())) {
0607                         lastCell = cell;
0608                         searchThroughEmpty = false;
0609                     }
0610                     col--;
0611                     if (col > 0)
0612                         cell = Cell(sheet, col, cell.row());
0613                 }
0614                 cell = lastCell;
0615             }
0616             if (searchThroughEmpty) {
0617                 cell = sheet->cellStorage()->prevInRow(marker.x(), marker.y(), CellStorage::VisitContent);
0618 
0619                 while ((!cell.isNull()) &&
0620                         (cell.isEmpty() || (sheet->columnFormat(cell.column())->isHiddenOrFiltered()))) {
0621                     cell = sheet->cellStorage()->prevInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0622                 }
0623             }
0624 
0625             if (cell.isNull())
0626                 col = 1;
0627             else
0628                 col = cell.column();
0629 
0630             while (sheet->columnFormat(col)->isHiddenOrFiltered()) {
0631                 col++;
0632             }
0633 
0634             destination.setX(qBound(1, col, q->maxCol()));
0635             destination.setY(qBound(1, marker.y(), q->maxRow()));
0636         }
0637         break;
0638 
0639 //Ctrl+Qt::Key_Right
0640     case Qt::Key_Right:
0641 
0642         if (sheet->layoutDirection() == Qt::RightToLeft) {
0643             cell = Cell(sheet, marker.x(), marker.y());
0644             if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.x() != 1)) {
0645                 lastCell = cell;
0646                 col = marker.x() - 1;
0647                 cell = Cell(sheet, col, cell.row());
0648                 while ((!cell.isNull()) && (col > 0) && (!cell.isEmpty())) {
0649                     if (!(sheet->columnFormat(cell.column())->isHiddenOrFiltered())) {
0650                         lastCell = cell;
0651                         searchThroughEmpty = false;
0652                     }
0653                     col--;
0654                     if (col > 0)
0655                         cell = Cell(sheet, col, cell.row());
0656                 }
0657                 cell = lastCell;
0658             }
0659             if (searchThroughEmpty) {
0660                 cell = sheet->cellStorage()->prevInRow(marker.x(), marker.y(), CellStorage::VisitContent);
0661 
0662                 while ((!cell.isNull()) &&
0663                         (cell.isEmpty() || (sheet->columnFormat(cell.column())->isHiddenOrFiltered()))) {
0664                     cell = sheet->cellStorage()->prevInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0665                 }
0666             }
0667 
0668             if (cell.isNull())
0669                 col = 1;
0670             else
0671                 col = cell.column();
0672 
0673             while (sheet->columnFormat(col)->isHiddenOrFiltered()) {
0674                 col++;
0675             }
0676 
0677             destination.setX(qBound(1, col, q->maxCol()));
0678             destination.setY(qBound(1, marker.y(), q->maxRow()));
0679         } else {
0680             cell = Cell(sheet, marker.x(), marker.y());
0681             if ((!cell.isNull()) && (!cell.isEmpty()) && (marker.x() != q->maxCol())) {
0682                 lastCell = cell;
0683                 col = marker.x() + 1;
0684                 cell = Cell(sheet, col, cell.row());
0685                 while ((!cell.isNull()) && (col < q->maxCol()) && (!cell.isEmpty())) {
0686                     if (!(sheet->columnFormat(cell.column())->isHiddenOrFiltered())) {
0687                         lastCell = cell;
0688                         searchThroughEmpty = false;
0689                     }
0690                     col++;
0691                     cell = Cell(sheet, col, cell.row());
0692                 }
0693                 cell = lastCell;
0694             }
0695             if (searchThroughEmpty) {
0696                 cell = sheet->cellStorage()->nextInRow(marker.x(), marker.y(), CellStorage::VisitContent);
0697 
0698                 while ((!cell.isNull()) &&
0699                         (cell.isEmpty() || (sheet->columnFormat(cell.column())->isHiddenOrFiltered()))) {
0700                     cell = sheet->cellStorage()->nextInRow(cell.column(), cell.row(), CellStorage::VisitContent);
0701                 }
0702             }
0703 
0704             if (cell.isNull())
0705                 col = marker.x();
0706             else
0707                 col = cell.column();
0708 
0709             while (sheet->columnFormat(col)->isHiddenOrFiltered()) {
0710                 col--;
0711             }
0712 
0713             destination.setX(qBound(1, col, q->maxCol()));
0714             destination.setY(qBound(1, marker.y(), q->maxRow()));
0715         }
0716         break;
0717 
0718     }
0719 
0720     if (marker == destination)
0721         return false;
0722 
0723     if (makingSelection) {
0724         q->selection()->update(destination);
0725     } else {
0726         q->selection()->initialize(destination, sheet);
0727     }
0728     q->scrollToCell(destination);
0729     return true;
0730 }
0731 
0732 bool CellToolBase::Private::formatKeyPress(QKeyEvent * _ev)
0733 {
0734     if (!(_ev->modifiers() & Qt::ControlModifier))
0735         return false;
0736 
0737     int key = _ev->key();
0738     if (key != Qt::Key_Exclam && key != Qt::Key_At &&
0739             key != Qt::Key_Ampersand && key != Qt::Key_Dollar &&
0740             key != Qt::Key_Percent && key != Qt::Key_AsciiCircum &&
0741             key != Qt::Key_NumberSign)
0742         return false;
0743 
0744     StyleCommand* command = new StyleCommand();
0745     command->setSheet(q->selection()->activeSheet());
0746 
0747     switch (_ev->key()) {
0748     case Qt::Key_Exclam:
0749         command->setText(kundo2_i18n("Number Format"));
0750         command->setFormatType(Format::Number);
0751         command->setPrecision(2);
0752         break;
0753 
0754     case Qt::Key_Dollar:
0755         command->setText(kundo2_i18n("Currency Format"));
0756         command->setFormatType(Format::Money);
0757         command->setPrecision(q->selection()->activeSheet()->map()->calculationSettings()->locale()->monetaryDecimalPlaces());
0758         break;
0759 
0760     case Qt::Key_Percent:
0761         command->setText(kundo2_i18n("Percentage Format"));
0762         command->setFormatType(Format::Percentage);
0763         break;
0764 
0765     case Qt::Key_At:
0766         command->setText(kundo2_i18n("Time Format"));
0767         command->setFormatType(Format::SecondeTime);
0768         break;
0769 
0770     case Qt::Key_NumberSign:
0771         command->setText(kundo2_i18n("Date Format"));
0772         command->setFormatType(Format::ShortDate);
0773         break;
0774 
0775     case Qt::Key_AsciiCircum:
0776         command->setText(kundo2_i18n("Scientific Format"));
0777         command->setFormatType(Format::Scientific);
0778         break;
0779 
0780     case Qt::Key_Ampersand:
0781         command->setText(kundo2_i18n("Change Border"));
0782         command->setTopBorderPen(QPen(q->canvas()->resourceManager()->foregroundColor().toQColor(), 1, Qt::SolidLine));
0783         command->setBottomBorderPen(QPen(q->canvas()->resourceManager()->foregroundColor().toQColor(), 1, Qt::SolidLine));
0784         command->setLeftBorderPen(QPen(q->canvas()->resourceManager()->foregroundColor().toQColor(), 1, Qt::SolidLine));
0785         command->setRightBorderPen(QPen(q->canvas()->resourceManager()->foregroundColor().toQColor(), 1, Qt::SolidLine));
0786         break;
0787 
0788     default:
0789         delete command;
0790         return false;
0791     }
0792 
0793     command->add(*q->selection());
0794     command->execute();
0795     _ev->accept(); // QKeyEvent
0796 
0797     return true;
0798 }
0799 
0800 QRect CellToolBase::Private::moveDirection(Calligra::Sheets::MoveTo direction, bool extendSelection)
0801 {
0802     debugSheetsUI << "Canvas::moveDirection";
0803 
0804     register Sheet * const sheet = q->selection()->activeSheet();
0805     if (!sheet)
0806         return QRect();
0807 
0808     QPoint destination;
0809     QPoint cursor = q->selection()->cursor();
0810 
0811     QPoint cellCorner = cursor;
0812     Cell cell(sheet, cursor.x(), cursor.y());
0813 
0814     /* cell is either the same as the marker, or the cell that is forced obscuring
0815         the marker cell
0816     */
0817     if (cell.isPartOfMerged()) {
0818         cell = cell.masterCell();
0819         cellCorner = QPoint(cell.column(), cell.row());
0820     }
0821 
0822     /* how many cells must we move to get to the next cell? */
0823     int offset = 0;
0824     const ColumnFormat *cl = 0;
0825     switch (direction)
0826         /* for each case, figure out how far away the next cell is and then keep
0827             going one row/col at a time after that until a visible row/col is found
0828 
0829             NEVER use cell.column() or cell.row() -- it might be a default cell
0830         */
0831     {
0832     case Bottom:
0833         offset = cell.mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
0834         while (((cursor.y() + offset) <= q->maxRow()) && sheet->rowFormats()->isHiddenOrFiltered(cursor.y() + offset)) {
0835             offset++;
0836         }
0837 
0838         destination = QPoint(cursor.x(), qMin(cursor.y() + offset, q->maxRow()));
0839         break;
0840     case Top:
0841         offset = (cellCorner.y() - cursor.y()) - 1;
0842         while (((cursor.y() + offset) >= 1) && sheet->rowFormats()->isHiddenOrFiltered(cursor.y() + offset)) {
0843             offset--;
0844         }
0845         destination = QPoint(cursor.x(), qMax(cursor.y() + offset, 1));
0846         break;
0847     case Left:
0848         offset = (cellCorner.x() - cursor.x()) - 1;
0849         cl = sheet->columnFormat(cursor.x() + offset);
0850         while (((cursor.x() + offset) >= 1) && cl->isHiddenOrFiltered()) {
0851             offset--;
0852             cl = sheet->columnFormat(cursor.x() + offset);
0853         }
0854         destination = QPoint(qMax(cursor.x() + offset, 1), cursor.y());
0855         break;
0856     case Right:
0857         offset = cell.mergedXCells() - (cursor.x() - cellCorner.x()) + 1;
0858         cl = sheet->columnFormat(cursor.x() + offset);
0859         while (((cursor.x() + offset) <= q->maxCol()) && cl->isHiddenOrFiltered()) {
0860             offset++;
0861             cl = sheet->columnFormat(cursor.x() + offset);
0862         }
0863         destination = QPoint(qMin(cursor.x() + offset, q->maxCol()), cursor.y());
0864         break;
0865     case BottomFirst:
0866         offset = cell.mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
0867         while (((cursor.y() + offset) <= q->maxRow()) && sheet->rowFormats()->isHiddenOrFiltered(cursor.y() + offset)) {
0868             ++offset;
0869         }
0870 
0871         destination = QPoint(1, qMin(cursor.y() + offset, q->maxRow()));
0872         break;
0873     case NoMovement:
0874         destination = cursor;
0875         break;
0876     }
0877 
0878     if (extendSelection) {
0879         q->selection()->update(destination);
0880     } else {
0881         q->selection()->initialize(destination, sheet);
0882     }
0883     q->scrollToCell(destination);
0884     updateEditor(Cell(q->selection()->activeSheet(), q->selection()->cursor()));
0885 
0886     return QRect(cursor, destination);
0887 }
0888 
0889 void CellToolBase::Private::paintSelection(QPainter &painter, const QRectF &viewRect)
0890 {
0891     if (q->selection()->referenceSelection() || q->editor()) {
0892         return;
0893     }
0894     Sheet *const sheet = q->selection()->activeSheet();
0895 
0896     // save the painter state
0897     painter.save();
0898     // disable antialiasing
0899     painter.setRenderHint(QPainter::Antialiasing, false);
0900     // Extend the clip rect by one in each direction to avoid artefacts caused by rounding errors.
0901     // TODO Stefan: This unites the region's rects. May be bad. Check!
0902     painter.setClipRegion(painter.clipRegion().boundingRect().adjusted(-1, -1, 1, 1));
0903 
0904     QLineF line;
0905     QPen pen(QApplication::palette().text().color(), q->canvas()->viewConverter()->viewToDocumentX(2.0));
0906     painter.setPen(pen);
0907 
0908     const Calligra::Sheets::Selection* selection = q->selection();
0909     const QRect currentRange = selection->extendToMergedAreas(QRect(selection->anchor(), selection->marker()));
0910     Region::ConstIterator end(selection->constEnd());
0911     for (Region::ConstIterator it(selection->constBegin()); it != end; ++it) {
0912         const QRect range = (*it)->isAll() ? (*it)->rect() : selection->extendToMergedAreas((*it)->rect());
0913 
0914         // Only the active element (the one with the anchor) will be drawn with a border
0915         const bool current = (currentRange == range);
0916 
0917         double positions[4];
0918         bool paintSides[4];
0919         retrieveMarkerInfo(range, viewRect, positions, paintSides);
0920 
0921         double left =   positions[0];
0922         double top =    positions[1];
0923         double right =  positions[2];
0924         double bottom = positions[3];
0925         if (sheet->layoutDirection() == Qt::RightToLeft) {
0926             // The painter's origin is translated by the negative canvas offset.
0927             // viewRect.left() is the canvas offset. Add it once to the
0928             // coordinates. Then, the upper left corner of the canvas has to
0929             // match the correct document position, which is the scrolling
0930             // offset (viewRect.left()) plus the width of the visible area
0931             // (viewRect.width()); that's the right border (left+width).
0932             const qreal offset = /*2 * viewRect.left() +*/ viewRect.width();
0933             left = offset - positions[2];
0934             right = offset - positions[0];
0935         }
0936 
0937         bool paintLeft =   paintSides[0];
0938         bool paintTop =    paintSides[1];
0939         bool paintRight =  paintSides[2];
0940         bool paintBottom = paintSides[3];
0941         if (sheet->layoutDirection() == Qt::RightToLeft) {
0942             paintLeft  = paintSides[2];
0943             paintRight = paintSides[0];
0944         }
0945 
0946         const double unzoomedPixelX = q->canvas()->viewConverter()->viewToDocumentX(1.0);
0947         const double unzoomedPixelY = q->canvas()->viewConverter()->viewToDocumentY(1.0);
0948         // get the transparent selection color
0949         QColor selectionColor(QApplication::palette().highlight().color());
0950         selectionColor.setAlpha(127);
0951         if (current) {
0952             // save old clip region
0953             const QRegion clipRegion = painter.clipRegion();
0954             // clip out the cursor region
0955             const QRect cursor = QRect(selection->cursor(), selection->cursor());
0956             const QRect extCursor = selection->extendToMergedAreas(cursor);
0957             QRectF cursorRect = sheet->cellCoordinatesToDocument(extCursor);
0958             if (sheet->layoutDirection() == Qt::RightToLeft) {
0959                 // See comment above.
0960                 const qreal offset = /*2 * viewRect.left() +*/ viewRect.width();
0961                 const qreal left = offset - cursorRect.right();
0962                 const qreal right = offset - cursorRect.left();
0963                 cursorRect.setLeft(left);
0964                 cursorRect.setRight(right);
0965             }
0966             cursorRect.adjust(unzoomedPixelX, unzoomedPixelY, unzoomedPixelX, unzoomedPixelY);
0967             painter.setClipRegion(clipRegion.subtracted(cursorRect.toRect()));
0968             // draw the transparent selection background
0969             painter.fillRect(QRectF(left, top, right - left, bottom - top), selectionColor);
0970             // restore clip region
0971             painter.setClipRegion(clipRegion);
0972         } else {
0973             // draw the transparent selection background
0974             painter.fillRect(QRectF(left, top, right - left, bottom - top), selectionColor);
0975         }
0976 
0977         if (paintTop) {
0978             line = QLineF(left, top, right, top);
0979             painter.drawLine(line);
0980         }
0981         if (selection->activeSheet()->layoutDirection() == Qt::RightToLeft) {
0982             if (paintRight) {
0983                 line = QLineF(right, top, right, bottom);
0984                 painter.drawLine(line);
0985             }
0986             if (paintLeft && paintBottom && current) {
0987                 /* then the 'handle' in the bottom left corner is visible. */
0988                 line = QLineF(left, top, left, bottom - 3 * unzoomedPixelY);
0989                 painter.drawLine(line);
0990                 line = QLineF(left + 4 * unzoomedPixelX,  bottom, right + unzoomedPixelY, bottom);
0991                 painter.drawLine(line);
0992                 painter.fillRect(QRectF(left - 2 * unzoomedPixelX, bottom - 2 * unzoomedPixelY,
0993                                         5 * unzoomedPixelX, 5 * unzoomedPixelY), painter.pen().color());
0994             } else {
0995                 if (paintLeft) {
0996                     line = QLineF(left, top, left, bottom);
0997                     painter.drawLine(line);
0998                 }
0999                 if (paintBottom) {
1000                     line = QLineF(left, bottom, right, bottom);
1001                     painter.drawLine(line);
1002                 }
1003             }
1004         } else { // activeSheet()->layoutDirection() == Qt::LeftToRight
1005             if (paintLeft) {
1006                 line = QLineF(left, top, left, bottom);
1007                 painter.drawLine(line);
1008             }
1009             if (paintRight && paintBottom && current) {
1010                 /* then the 'handle' in the bottom right corner is visible. */
1011                 line = QLineF(right, top, right, bottom - 3 * unzoomedPixelY);
1012                 painter.drawLine(line);
1013                 line = QLineF(left, bottom, right - 3 * unzoomedPixelX, bottom);
1014                 painter.drawLine(line);
1015                 painter.fillRect(QRectF(right - 2 * unzoomedPixelX, bottom - 2 * unzoomedPixelX,
1016                                         5 * unzoomedPixelX, 5 * unzoomedPixelY), painter.pen().color());
1017             } else {
1018                 if (paintRight) {
1019                     line = QLineF(right, top, right, bottom);
1020                     painter.drawLine(line);
1021                 }
1022                 if (paintBottom) {
1023                     line = QLineF(left, bottom, right, bottom);
1024                     painter.drawLine(line);
1025                 }
1026             }
1027         }
1028     }
1029     // restore painter state
1030     painter.restore();
1031 }
1032 
1033 void CellToolBase::Private::paintReferenceSelection(QPainter &painter, const QRectF &viewRect)
1034 {
1035     Q_UNUSED(viewRect);
1036     if (!q->selection()->referenceSelection()) {
1037         return;
1038     }
1039     // save painter state
1040     painter.save();
1041 
1042     // Define the reference selection handle.
1043     const qreal pixelX = q->canvas()->viewConverter()->viewToDocumentX(1);
1044     const qreal pixelY = q->canvas()->viewConverter()->viewToDocumentY(1);
1045     const QRectF handleArea(-3 * pixelX, -3 * pixelY, 6 * pixelX, 6 * pixelY);
1046 
1047     // A list of already found regions to color the same region with the same color.
1048     QSet<QString> alreadyFoundRegions;
1049     // The colors for the referenced ranges and the color index.
1050     const QList<QColor> colors = q->selection()->colors();
1051     int index = 0;
1052 
1053     // Iterate over the referenced ranges.
1054     const Region::ConstIterator end(q->selection()->constEnd());
1055     for (Region::ConstIterator it(q->selection()->constBegin()); it != end; ++it) {
1056         Sheet *const sheet = (*it)->sheet();
1057         // Only paint ranges or cells on the current sheet
1058         if (sheet != q->selection()->activeSheet()) {
1059             index++;
1060             continue;
1061         }
1062         // Only paint a reference once.
1063         if (alreadyFoundRegions.contains((*it)->name())) {
1064             continue;
1065         }
1066         alreadyFoundRegions.insert((*it)->name());
1067 
1068         const QRect range = q->selection()->extendToMergedAreas((*it)->rect());
1069         QRectF area = sheet->cellCoordinatesToDocument(range);
1070 
1071         // Convert region from sheet coordinates to canvas coordinates for use with the painter
1072         // retrieveMarkerInfo(region,viewRect,positions,paintSides);
1073 
1074         // Now adjust the highlight rectangle is slightly inside the cell borders (this means
1075         // that multiple highlighted cells look nicer together as the borders do not clash)
1076         area.adjust(pixelX, pixelY, -pixelX, -pixelY);
1077 
1078         // The current color.
1079         const QColor color = colors[index++ % colors.size()];
1080 
1081         // Paint the reference range's outline.
1082         if ((*it)->sheet()->layoutDirection() == Qt::RightToLeft) {
1083             // See comment in paintSelection().
1084             const qreal offset = /*2 * viewRect.left() +*/ viewRect.width();
1085             const qreal left = offset - area.right();
1086             const qreal right = offset - area.left();
1087             area.setLeft(left);
1088             area.setRight(right);
1089         }
1090 
1091         painter.setBrush(QBrush());
1092         painter.setPen(QPen(color, 0));
1093         painter.drawRect(area);
1094 
1095         // Now draw the size grip (the little rectangle on the bottom right-hand corner of
1096         // the range which the user can click and drag to resize the region)
1097         painter.setPen(QPen(Qt::white, 0));
1098         painter.setBrush(color);
1099         const bool rtl = sheet->layoutDirection() == Qt::RightToLeft;
1100         const QPointF corner(rtl ? area.bottomLeft() : area.bottomRight());
1101         painter.drawRect(handleArea.translated(corner));
1102     }
1103 
1104     // restore painter state
1105     painter.restore();
1106 }
1107 
1108 void CellToolBase::Private::retrieveMarkerInfo(const QRect &cellRange, const QRectF &viewRect,
1109         double positions[], bool paintSides[])
1110 {
1111     // Everything is in document coordinates here.
1112     // The layout direction, which is view dependent, is applied afterwards.
1113 
1114     const Sheet* sheet = q->selection()->activeSheet();
1115     const QRectF visibleRect = sheet->cellCoordinatesToDocument(cellRange);
1116 
1117     /* these vars are used for clarity, the array for simpler function arguments  */
1118     qreal left = visibleRect.left();
1119     qreal top = visibleRect.top();
1120     qreal right = visibleRect.right();
1121     qreal bottom = visibleRect.bottom();
1122 
1123     /* left, top, right, bottom */
1124     paintSides[0] = (viewRect.left() <= left) && (left <= viewRect.right()) &&
1125                     (bottom >= viewRect.top()) && (top <= viewRect.bottom());
1126     paintSides[1] = (viewRect.top() <= top) && (top <= viewRect.bottom()) &&
1127                     (right >= viewRect.left()) && (left <= viewRect.right());
1128     paintSides[2] = (viewRect.left() <= right) && (right <= viewRect.right()) &&
1129                     (bottom >= viewRect.top()) && (top <= viewRect.bottom());
1130     paintSides[3] = (viewRect.top() <= bottom) && (bottom <= viewRect.bottom()) &&
1131                     (right >= viewRect.left()) && (left <= viewRect.right());
1132 
1133     positions[0] = qMax(left,   viewRect.left());
1134     positions[1] = qMax(top,    viewRect.top());
1135     positions[2] = qMin(right,  viewRect.right());
1136     positions[3] = qMin(bottom, viewRect.bottom());
1137 }
1138 
1139 QList<QAction*> CellToolBase::Private::popupActionList() const
1140 {
1141     QList<QAction*> actions;
1142     const Cell cell = Cell(q->selection()->activeSheet(), q->selection()->marker());
1143     const bool isProtected = !q->selection()->activeSheet()->map()->isReadWrite() ||
1144                              (q->selection()->activeSheet()->isProtected() &&
1145                               !(cell.style().notProtected() && q->selection()->isSingular()));
1146     if (!isProtected) {
1147         actions.append(q->action("cellStyle"));
1148         actions.append(popupMenuActions["separator1"]);
1149         actions.append(q->action("cut"));
1150     }
1151     actions.append(q->action("copy"));
1152     if (!isProtected) {
1153         actions.append(q->action("paste"));
1154         actions.append(q->action("specialPaste"));
1155         actions.append(q->action("pasteWithInsertion"));
1156         actions.append(popupMenuActions["separator2"]);
1157         actions.append(q->action("clearAll"));
1158         actions.append(q->action("adjust"));
1159         actions.append(q->action("setDefaultStyle"));
1160         actions.append(q->action("setAreaName"));
1161 
1162         if (!q->selection()->isColumnOrRowSelected()) {
1163             actions.append(popupMenuActions["separator3"]);
1164             actions.append(popupMenuActions["insertCell"]);
1165             actions.append(popupMenuActions["deleteCell"]);
1166         } else if (q->selection()->isColumnSelected()) {
1167             actions.append(q->action("resizeCol"));
1168             actions.append(popupMenuActions["adjustColumn"]);
1169             actions.append(popupMenuActions["separator4"]);
1170             actions.append(popupMenuActions["insertColumn"]);
1171             actions.append(popupMenuActions["deleteColumn"]);
1172             actions.append(q->action("hideColumn"));
1173 
1174             q->action("showSelColumns")->setEnabled(false);
1175             const ColumnFormat* columnFormat;
1176             Region::ConstIterator endOfList = q->selection()->constEnd();
1177             for (Region::ConstIterator it = q->selection()->constBegin(); it != endOfList; ++it) {
1178                 QRect range = (*it)->rect();
1179                 int col;
1180                 for (col = range.left(); col < range.right(); ++col) {
1181                     columnFormat = q->selection()->activeSheet()->columnFormat(col);
1182                     if (columnFormat->isHidden()) {
1183                         q->action("showSelColumns")->setEnabled(true);
1184                         actions.append(q->action("showSelColumns"));
1185                         break;
1186                     }
1187                 }
1188                 if (range.left() > 1 && col == range.right()) {
1189                     bool allHidden = true;
1190                     for (col = 1; col < range.left(); ++col) {
1191                         columnFormat = q->selection()->activeSheet()->columnFormat(col);
1192                         allHidden &= columnFormat->isHidden();
1193                     }
1194                     if (allHidden) {
1195                         q->action("showSelColumns")->setEnabled(true);
1196                         actions.append(q->action("showSelColumns"));
1197                         break;
1198                     }
1199                 } else {
1200                     break;
1201                 }
1202             }
1203         } else if (q->selection()->isRowSelected()) {
1204             actions.append(q->action("resizeRow"));
1205             actions.append(popupMenuActions["adjustRow"]);
1206             actions.append(popupMenuActions["separator5"]);
1207             actions.append(popupMenuActions["insertRow"]);
1208             actions.append(popupMenuActions["deleteRow"]);
1209             actions.append(q->action("hideRow"));
1210 
1211             q->action("showSelRows")->setEnabled(false);
1212             Region::ConstIterator endOfList = q->selection()->constEnd();
1213             for (Region::ConstIterator it = q->selection()->constBegin(); it != endOfList; ++it) {
1214                 QRect range = (*it)->rect();
1215                 int row;
1216                 for (row = range.top(); row < range.bottom(); ++row) {
1217                     if (q->selection()->activeSheet()->rowFormats()->isHidden(row)) {
1218                         q->action("showSelRows")->setEnabled(true);
1219                         actions.append(q->action("showSelRows"));
1220                         break;
1221                     }
1222                 }
1223                 if (range.top() > 1 && row == range.bottom()) {
1224                     bool allHidden = true;
1225                     for (row = 1; row < range.top(); ++row) {
1226                         allHidden &= q->selection()->activeSheet()->rowFormats()->isHidden(row);
1227                     }
1228                     if (allHidden) {
1229                         q->action("showSelRows")->setEnabled(true);
1230                         actions.append(q->action("showSelRows"));
1231                         break;
1232                     }
1233                 } else {
1234                     break;
1235                 }
1236             }
1237         }
1238         actions.append(popupMenuActions["separator6"]);
1239         actions.append(popupMenuActions["comment"]);
1240         if (!cell.comment().isEmpty()) {
1241             actions.append(popupMenuActions["clearComment"]);
1242         }
1243 
1244         if (testListChoose(q->selection())) {
1245             actions.append(popupMenuActions["separator7"]);
1246             actions.append(popupMenuActions["listChoose"]);
1247         }
1248     }
1249     return actions;
1250 }
1251 
1252 void CellToolBase::Private::createPopupMenuActions()
1253 {
1254     QAction* action = 0;
1255 
1256     for (int i = 1; i <= 7; ++i) {
1257         action = new QAction(q);
1258         action->setSeparator(true);
1259         popupMenuActions.insert(QString("separator%1").arg(i), action);
1260     }
1261 
1262     action = new QAction(koIcon("insertcell"), i18n("Insert Cells..."), q);
1263     connect(action, SIGNAL(triggered(bool)), q, SLOT(insertCells()));
1264     popupMenuActions.insert("insertCell", action);
1265 
1266     action = new QAction(koIcon("removecell"), i18n("Delete Cells..."), q);
1267     connect(action, SIGNAL(triggered(bool)), q, SLOT(deleteCells()));
1268     popupMenuActions.insert("deleteCell", action);
1269 
1270     action = new QAction(koIcon("adjustcol"), i18n("Adjust Column"), q);
1271     connect(action, SIGNAL(triggered(bool)), q, SLOT(adjustColumn()));
1272     popupMenuActions.insert("adjustColumn", action);
1273 
1274     action = new QAction(koIcon("edit-table-insert-column-left"), i18n("Insert Columns"), q);
1275     connect(action, SIGNAL(triggered(bool)), q, SLOT(insertColumn()));
1276     popupMenuActions.insert("insertColumn", action);
1277 
1278     action = new QAction(koIcon("edit-table-delete-column"), i18n("Delete Columns"), q);
1279     connect(action, SIGNAL(triggered(bool)), q, SLOT(deleteColumn()));
1280     popupMenuActions.insert("deleteColumn", action);
1281 
1282     action = new QAction(koIcon("adjustrow"), i18n("Adjust Row"), q);
1283     connect(action, SIGNAL(triggered(bool)), q, SLOT(adjustRow()));
1284     popupMenuActions.insert("adjustRow", action);
1285 
1286     action = new QAction(koIcon("edit-table-insert-row-above"), i18n("Insert Rows"), q);
1287     connect(action, SIGNAL(triggered(bool)), q, SLOT(insertRow()));
1288     popupMenuActions.insert("insertRow", action);
1289 
1290     action = new QAction(koIcon("edit-table-delete-row"), i18n("Delete Rows"), q);
1291     connect(action, SIGNAL(triggered(bool)), q, SLOT(deleteRow()));
1292     popupMenuActions.insert("deleteRow", action);
1293 
1294     action = new QAction(i18n("Selection List..."), q);
1295     connect(action, SIGNAL(triggered(bool)), q, SLOT(listChoosePopupMenu()));
1296     popupMenuActions.insert("listChoose", action);
1297 
1298     action = new QAction(koIcon("edit-comment"), i18n("Comment"), q);
1299     connect(action, SIGNAL(triggered(bool)), q, SLOT(comment()));
1300     popupMenuActions.insert("comment", action);
1301 
1302     action = new QAction(koIcon("delete-comment"),i18n("Clear Comment"), q);
1303     connect(action, SIGNAL(triggered(bool)), q, SLOT(clearComment()));
1304     popupMenuActions.insert("clearComment", action);
1305 
1306 }
1307 
1308 bool CellToolBase::Private::testListChoose(Selection *selection) const
1309 {
1310     const Sheet *const sheet = selection->activeSheet();
1311     const Cell cursorCell(sheet, selection->cursor());
1312     const CellStorage *const storage = sheet->cellStorage();
1313 
1314     const Region::ConstIterator end(selection->constEnd());
1315     for (Region::ConstIterator it(selection->constBegin()); it != end; ++it) {
1316         const QRect range = (*it)->rect();
1317         if (cursorCell.column() < range.left() || cursorCell.column() > range.right()) {
1318             continue; // next range
1319         }
1320         Cell cell;
1321         if (range.top() == 1) {
1322             cell = storage->firstInColumn(cursorCell.column(), CellStorage::Values);
1323         } else {
1324             cell = storage->nextInColumn(cursorCell.column(), range.top() - 1, CellStorage::Values);
1325         }
1326         while (!cell.isNull() && cell.row() <= range.bottom()) {
1327             if (cell.isDefault() || cell.isPartOfMerged()
1328                     || cell.isFormula() || cell.isTime() || cell.isDate()
1329                     || cell.value().isNumber() || cell.value().asString().isEmpty()
1330                     || (cell == cursorCell)) {
1331                 cell = storage->nextInColumn(cell.column(), cell.row(), CellStorage::Values);
1332                 continue;
1333             }
1334             if (cell.userInput() != cursorCell.userInput()) {
1335                 return true;
1336             }
1337             cell = storage->nextInColumn(cell.column(), cell.row(), CellStorage::Values);
1338         }
1339     }
1340     return false;
1341 }