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 }