File indexing completed on 2024-05-12 16:35:49
0001 /* This file is part of the KDE project 0002 Copyright 2006-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0003 Copyright 2005-2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net> 0004 Copyright 2002-2005 Ariya Hidayat <ariya@kde.org> 0005 Copyright 1999-2003 Laurent Montel <montel@kde.org> 0006 Copyright 2002-2003 Norbert Andres <nandres@web.de> 0007 Copyright 2002-2003 Philipp Mueller <philipp.mueller@gmx.de> 0008 Copyright 2002-2003 John Dailey <dailey@vt.edu> 0009 Copyright 1999-2003 David Faure <faure@kde.org> 0010 Copyright 1999-2001 Simon Hausmann <hausmann@kde.org> 0011 Copyright 1998-2000 Torben Weis <weis@kde.org> 0012 Copyright 2010 Boudewijn Rempt <boud@kogmbh.com> 0013 0014 This library is free software; you can redistribute it and/or 0015 modify it under the terms of the GNU Library General Public 0016 License as published by the Free Software Foundation; either 0017 version 2 of the License, or (at your option) any later version. 0018 0019 This library is distributed in the hope that it will be useful, 0020 but WITHOUT ANY WARRANTY; without even the implied warranty of 0021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0022 Library General Public License for more details. 0023 0024 You should have received a copy of the GNU Library General Public License 0025 along with this library; see the file COPYING.LIB. If not, write to 0026 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0027 Boston, MA 02110-1301, USA. 0028 */ 0029 0030 // Local 0031 #include "View.h" 0032 #include "TabBar.h" 0033 0034 // standard C/C++ includes 0035 #include <assert.h> 0036 #include <stdlib.h> 0037 #include <time.h> 0038 0039 // Qt includes 0040 #include <QBuffer> 0041 #include <QByteArray> 0042 #include <QClipboard> 0043 #include <QCursor> 0044 #include <QEvent> 0045 #include <QFrame> 0046 #include <QGridLayout> 0047 #include <QHBoxLayout> 0048 #include <QKeyEvent> 0049 #include <QList> 0050 #include <QMenu> 0051 #include <QPixmap> 0052 #include <QResizeEvent> 0053 #include <QToolButton> 0054 #ifndef QT_NO_SQL 0055 #include <QSqlDatabase> 0056 #endif 0057 #include <QSizePolicy> 0058 #include <QScrollBar> 0059 #include <QStatusBar> 0060 #include <QInputDialog> 0061 #include <QTimer> 0062 0063 // KF5 includes 0064 #include <kactioncollection.h> 0065 #include <kconfig.h> 0066 0067 #include <kmessagebox.h> 0068 #include <kstandardaction.h> 0069 #include <ktoggleaction.h> 0070 #include <kxmlguifactory.h> 0071 #include <kstandardguiitem.h> 0072 0073 // Calligra includes 0074 #include <KoComponentData.h> 0075 #include <KoPluginLoader.h> 0076 #include <KoGlobal.h> 0077 #include <KoColor.h> 0078 #include <KoCanvasControllerWidget.h> 0079 #include <KoMainWindow.h> 0080 #include <KoShapeController.h> 0081 #include <KoShapeManager.h> 0082 #include <KoSelection.h> 0083 #include <KoDockerManager.h> 0084 #include <KoToolManager.h> 0085 #include <KoTemplateCreateDia.h> 0086 #include <KoXmlNS.h> 0087 #include <KoZoomAction.h> 0088 #include <KoZoomController.h> 0089 #include <KoZoomHandler.h> 0090 #include <KoToolProxy.h> 0091 #include <KoModeBoxFactory.h> 0092 #include <KoIcon.h> 0093 #include <KoCanvasResourceManager.h> 0094 #include <KoCanvasResourceIdentities.h> 0095 0096 // Sheets includes 0097 #include "SheetsDebug.h" 0098 #include "ApplicationSettings.h" 0099 #include "BindingManager.h" 0100 #include "CalculationSettings.h" 0101 #include "CellStorage.h" 0102 #include "Damages.h" 0103 #include "DependencyManager.h" 0104 #include "Doc.h" 0105 #include "Factory.h" 0106 #include "HeaderFooter.h" 0107 #include "LoadingInfo.h" 0108 #include "Canvas.h" 0109 #include "Global.h" 0110 #include "Headers.h" 0111 #include "HeaderWidgets.h" 0112 #include "Localization.h" 0113 #include "Map.h" 0114 #include "NamedAreaManager.h" 0115 #include "PrintSettings.h" 0116 #include "RecalcManager.h" 0117 #include "RowColumnFormat.h" 0118 #include "ShapeApplicationData.h" 0119 #include "Sheet.h" 0120 #include "SheetPrint.h" 0121 #include "Style.h" 0122 #include "StyleManager.h" 0123 #include "StyleStorage.h" 0124 #include "ToolRegistry.h" 0125 #include "Util.h" 0126 #include "ValueCalc.h" 0127 #include "ValueConverter.h" 0128 #include "PrintJob.h" 0129 #include "ElapsedTime_p.h" 0130 0131 // commands 0132 #include "commands/CopyCommand.h" 0133 #include "commands/DefinePrintRangeCommand.h" 0134 #include "commands/SheetCommands.h" 0135 0136 // dialogs 0137 #include "dialogs/PageLayoutDialog.h" 0138 #include "dialogs/PreferenceDialog.h" 0139 #include "dialogs/ShowDialog.h" 0140 0141 #include "dialogs/SheetPropertiesDialog.h" 0142 0143 // ui 0144 #include "ui/CellView.h" 0145 #include "ui/MapViewModel.h" 0146 #include "ui/RightToLeftPaintingStrategy.h" 0147 #include "ui/Selection.h" 0148 #include "ui/SheetView.h" 0149 #include "ui/PixmapCachingSheetView.h" 0150 0151 // D-Bus 0152 #ifndef QT_NO_DBUS 0153 #include "interfaces/ViewAdaptor.h" 0154 #include <knotifyconfigwidget.h> 0155 #endif 0156 0157 using namespace Calligra::Sheets; 0158 0159 class ViewActions; 0160 0161 class Q_DECL_HIDDEN View::Private 0162 { 0163 public: 0164 View* view; 0165 Doc* doc; 0166 0167 // the active sheet, may be 0 0168 // this is the sheet which has the input focus 0169 Sheet* activeSheet; 0170 MapViewModel* mapViewModel; 0171 QHash<const Sheet*, QPointer<SheetView> > sheetViews; 0172 0173 // GUI elements 0174 QWidget *frame; 0175 Canvas *canvas; 0176 KoCanvasController* canvasController; 0177 KoZoomController* zoomController; 0178 KoZoomHandler* zoomHandler; 0179 RowHeaderWidget *rowHeader; 0180 ColumnHeaderWidget *columnHeader; 0181 SelectAllButtonWidget* selectAllButton; 0182 QScrollBar *horzScrollBar; 0183 QScrollBar *vertScrollBar; 0184 TabBar *tabBar; 0185 QLabel* calcLabel; 0186 QGridLayout* viewLayout; 0187 QGridLayout* tabScrollBarLayout; 0188 0189 // all UI actions 0190 ViewActions* actions; 0191 0192 // if true, Calligra Sheets is still loading the document 0193 // don't try to refresh the view 0194 bool loading; 0195 0196 // selection/marker 0197 Selection* selection; 0198 QMap<Sheet*, QPoint> savedAnchors; 0199 QMap<Sheet*, QPoint> savedMarkers; 0200 QMap<Sheet*, QPointF> savedOffsets; 0201 0202 void initActions(); 0203 void adjustActions(bool mode); 0204 0205 // On timeout this will execute the status bar operation (e.g. SUM). 0206 // This is delayed to speed up the selection. 0207 QTimer statusBarOpTimer; 0208 0209 QTimer *scrollTimer; 0210 }; 0211 0212 class ViewActions 0213 { 0214 public: 0215 // sheet/workbook operations 0216 QAction * sheetProperties; 0217 QAction * insertSheet; 0218 QAction * duplicateSheet; 0219 QAction * deleteSheet; 0220 QAction * renameSheet; 0221 QAction * hideSheet; 0222 QAction * showSheet; 0223 0224 //Shape manipulation 0225 QAction * deleteShape; 0226 0227 // page layout 0228 QAction * paperLayout; 0229 QAction * resetPrintRange; 0230 KToggleAction* showPageOutline; 0231 0232 // recalculation 0233 QAction * recalcWorksheet; 0234 QAction * recalcWorkbook; 0235 0236 // protection 0237 KToggleAction* protectSheet; 0238 KToggleAction* protectDoc; 0239 0240 // navigation 0241 QAction * nextSheet; 0242 QAction * prevSheet; 0243 QAction * firstSheet; 0244 QAction * lastSheet; 0245 0246 // misc 0247 QAction * createTemplate; 0248 KSelectAction* shapeAnchor; 0249 0250 // settings 0251 KToggleAction* showColumnHeader; 0252 KToggleAction* showRowHeader; 0253 KToggleAction* showHorizontalScrollBar; 0254 KToggleAction* showVerticalScrollBar; 0255 KToggleAction* showStatusBar; 0256 KToggleAction* showTabBar; 0257 QAction * preference; 0258 0259 // running calculation 0260 KToggleAction* calcNone; 0261 KToggleAction* calcMin; 0262 KToggleAction* calcMax; 0263 KToggleAction* calcAverage; 0264 KToggleAction* calcCount; 0265 KToggleAction* calcSum; 0266 KToggleAction* calcCountA; 0267 }; 0268 0269 0270 void View::Private::initActions() 0271 { 0272 actions = new ViewActions; 0273 0274 KActionCollection* ac = view->actionCollection(); 0275 0276 // -- sheet/workbook actions -- 0277 actions->sheetProperties = new QAction(i18n("Sheet Properties..."), view); 0278 ac->addAction("sheetProperties", actions->sheetProperties); 0279 connect(actions->sheetProperties, SIGNAL(triggered(bool)), view, SLOT(sheetProperties())); 0280 actions->sheetProperties->setToolTip(i18n("Modify current sheet's properties")); 0281 0282 actions->insertSheet = new QAction(koIcon("insert-table"), i18n("Sheet"), view); 0283 actions->insertSheet->setIconText(i18n("Insert Sheet")); 0284 actions->insertSheet->setToolTip(i18n("Insert a new sheet")); 0285 ac->addAction("insertSheet", actions->insertSheet); 0286 connect(actions->insertSheet, SIGNAL(triggered(bool)), view, SLOT(insertSheet())); 0287 0288 actions->duplicateSheet = new QAction(/*koIcon("inserttable"),*/ i18n("Duplicate Sheet"), view); 0289 actions->duplicateSheet->setToolTip(i18n("Duplicate the selected sheet")); 0290 ac->addAction("duplicateSheet", actions->duplicateSheet); 0291 connect(actions->duplicateSheet, SIGNAL(triggered(bool)), view, SLOT(duplicateSheet())); 0292 0293 actions->deleteSheet = new QAction(koIcon("edit-delete"), i18n("Sheet"), view); 0294 actions->deleteSheet->setIconText(i18n("Remove Sheet")); 0295 actions->deleteSheet->setToolTip(i18n("Remove the active sheet")); 0296 ac->addAction("deleteSheet", actions->deleteSheet); 0297 connect(actions->deleteSheet, SIGNAL(triggered(bool)), view, SLOT(deleteSheet())); 0298 0299 actions->renameSheet = new QAction(i18n("Rename Sheet..."), view); 0300 ac->addAction("renameSheet", actions->renameSheet); 0301 connect(actions->renameSheet, SIGNAL(triggered(bool)), view, SLOT(slotRename())); 0302 actions->renameSheet->setToolTip(i18n("Rename the active sheet")); 0303 0304 actions->showSheet = new QAction(i18n("Show Sheet..."), view); 0305 ac->addAction("showSheet", actions->showSheet); 0306 connect(actions->showSheet, SIGNAL(triggered(bool)), view, SLOT(showSheet())); 0307 actions->showSheet->setToolTip(i18n("Show a hidden sheet")); 0308 0309 actions->hideSheet = new QAction(i18n("Hide Sheet"), view); 0310 ac->addAction("hideSheet", actions->hideSheet); 0311 connect(actions->hideSheet, SIGNAL(triggered(bool)), view, SLOT(hideSheet())); 0312 actions->hideSheet->setToolTip(i18n("Hide the active sheet")); 0313 0314 actions->paperLayout = new QAction(i18n("Page Layout..."), view); 0315 ac->addAction("paperLayout", actions->paperLayout); 0316 connect(actions->paperLayout, SIGNAL(triggered(bool)), view, SLOT(paperLayoutDlg())); 0317 actions->paperLayout->setToolTip(i18n("Specify the layout of the spreadsheet for a printout")); 0318 0319 actions->resetPrintRange = new QAction(i18n("Reset Print Range"), view); 0320 ac->addAction("resetPrintRange", actions->resetPrintRange); 0321 connect(actions->resetPrintRange, SIGNAL(triggered(bool)), view, SLOT(resetPrintRange())); 0322 actions->resetPrintRange->setToolTip(i18n("Reset the print range in the current sheet")); 0323 0324 actions->showPageOutline = new KToggleAction(i18n("Page Outline"), view); 0325 actions->showPageOutline->setToolTip(i18n("Show on the spreadsheet where the page boundary will be")); 0326 ac->addAction("showPageOutline", actions->showPageOutline); 0327 connect(actions->showPageOutline, SIGNAL(toggled(bool)), view, SLOT(togglePageOutline(bool))); 0328 0329 actions->recalcWorksheet = new QAction(i18n("Recalculate Sheet"), view); 0330 actions->recalcWorksheet->setIcon(koIcon("view-refresh")); 0331 actions->recalcWorksheet->setIconText(i18n("Recalculate")); 0332 ac->addAction("RecalcWorkSheet", actions->recalcWorksheet); 0333 actions->recalcWorksheet->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F9)); 0334 connect(actions->recalcWorksheet, SIGNAL(triggered(bool)), view, SLOT(recalcWorkSheet())); 0335 actions->recalcWorksheet->setToolTip(i18n("Recalculate the value of every cell in the current worksheet")); 0336 0337 actions->recalcWorkbook = new QAction(i18n("Recalculate Document"), view); 0338 actions->recalcWorkbook->setIcon(koIcon("view-refresh")); 0339 actions->recalcWorkbook->setIconText(i18n("Recalculate")); 0340 ac->addAction("RecalcWorkBook", actions->recalcWorkbook); 0341 actions->recalcWorkbook->setShortcut(QKeySequence(Qt::Key_F9)); 0342 connect(actions->recalcWorkbook, SIGNAL(triggered(bool)), view, SLOT(recalcWorkBook())); 0343 actions->recalcWorkbook->setToolTip(i18n("Recalculate the value of every cell in all worksheets")); 0344 0345 actions->protectSheet = new KToggleAction(i18n("Protect &Sheet..."), view); 0346 ac->addAction("protectSheet", actions->protectSheet); 0347 actions->protectSheet->setToolTip(i18n("Protect the sheet from being modified")); 0348 connect(actions->protectSheet, SIGNAL(triggered(bool)), 0349 view, SLOT(toggleProtectSheet(bool))); 0350 0351 actions->protectDoc = new KToggleAction(i18n("Protect &Document..."), view); 0352 ac->addAction("protectDoc", actions->protectDoc); 0353 actions->protectDoc->setToolTip(i18n("Protect the document from being modified")); 0354 connect(actions->protectDoc, SIGNAL(triggered(bool)), view, SLOT(toggleProtectDoc(bool))); 0355 0356 // -- misc actions -- 0357 0358 actions->createTemplate = new QAction(i18n("&Create Template From Document..."), view); 0359 ac->addAction("createTemplate", actions->createTemplate); 0360 connect(actions->createTemplate, SIGNAL(triggered(bool)), view, SLOT(createTemplate())); 0361 0362 actions->shapeAnchor = new KSelectAction(i18n("Anchor"), view); 0363 actions->shapeAnchor->addAction(i18n("Cell")); 0364 actions->shapeAnchor->addAction(i18n("Page")); 0365 actions->shapeAnchor->setEnabled(false); 0366 actions->shapeAnchor->setToolTip(i18n("Switch shape anchoring")); 0367 ac->addAction("shapeAnchor", actions->shapeAnchor); 0368 connect(actions->shapeAnchor, SIGNAL(triggered(QString)), 0369 view, SLOT(setShapeAnchoring(QString))); 0370 0371 // -- navigation actions -- 0372 0373 actions->nextSheet = new QAction(koIcon("go-next"), i18n("Next Sheet"), view); 0374 actions->nextSheet->setIconText(i18n("Next")); 0375 actions->nextSheet->setToolTip(i18n("Move to the next sheet")); 0376 ac->addAction("go_next", actions->nextSheet); 0377 actions->nextSheet->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageDown)); 0378 connect(actions->nextSheet, SIGNAL(triggered(bool)), view, SLOT(nextSheet())); 0379 0380 actions->prevSheet = new QAction(koIcon("go-previous"), i18n("Previous Sheet"), view); 0381 actions->prevSheet->setIconText(i18n("Previous")); 0382 actions->prevSheet->setToolTip(i18n("Move to the previous sheet")); 0383 ac->addAction("go_previous", actions->prevSheet); 0384 actions->prevSheet->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageUp)); 0385 connect(actions->prevSheet, SIGNAL(triggered(bool)), view, SLOT(previousSheet())); 0386 0387 actions->firstSheet = new QAction(koIcon("go-first"), i18n("First Sheet"), view); 0388 actions->firstSheet->setIconText(i18n("First")); 0389 actions->firstSheet->setToolTip(i18n("Move to the first sheet")); 0390 ac->addAction("go_first", actions->firstSheet); 0391 connect(actions->firstSheet, SIGNAL(triggered(bool)), view, SLOT(firstSheet())); 0392 0393 actions->lastSheet = new QAction(koIcon("go-last"), i18n("Last Sheet"), view); 0394 actions->lastSheet->setIconText(i18nc("Move to the last sheet", "Last")); 0395 actions->lastSheet->setToolTip(i18n("Move to the last sheet")); 0396 ac->addAction("go_last", actions->lastSheet); 0397 connect(actions->lastSheet, SIGNAL(triggered(bool)), view, SLOT(lastSheet())); 0398 0399 // -- settings actions -- 0400 0401 actions->showColumnHeader = new KToggleAction(i18n("Column Header"), view); 0402 actions->showColumnHeader->setToolTip(i18n("Show the column header")); 0403 ac->addAction("showColumnHeader", actions->showColumnHeader); 0404 connect(actions->showColumnHeader, SIGNAL(toggled(bool)), 0405 view, SLOT(showColumnHeader(bool))); 0406 0407 actions->showRowHeader = new KToggleAction(i18n("Row Header"), view); 0408 actions->showRowHeader->setToolTip(i18n("Show the row header")); 0409 ac->addAction("showRowHeader", actions->showRowHeader); 0410 connect(actions->showRowHeader, SIGNAL(toggled(bool)), 0411 view, SLOT(showRowHeader(bool))); 0412 0413 actions->showHorizontalScrollBar = new KToggleAction(i18n("Horizontal Scrollbar"), view); 0414 actions->showHorizontalScrollBar->setToolTip(i18n("Show the horizontal scrollbar")); 0415 ac->addAction("showHorizontalScrollBar", actions->showHorizontalScrollBar); 0416 connect(actions->showHorizontalScrollBar, SIGNAL(toggled(bool)), 0417 view, SLOT(showHorizontalScrollBar(bool))); 0418 0419 actions->showVerticalScrollBar = new KToggleAction(i18n("Vertical Scrollbar"), view); 0420 actions->showVerticalScrollBar->setToolTip(i18n("Show the vertical scrollbar")); 0421 ac->addAction("showVerticalScrollBar", actions->showVerticalScrollBar); 0422 connect(actions->showVerticalScrollBar, SIGNAL(toggled(bool)), 0423 view, SLOT(showVerticalScrollBar(bool))); 0424 0425 actions->showStatusBar = new KToggleAction(i18n("Status Bar"), view); 0426 actions->showStatusBar->setToolTip(i18n("Show the status bar")); 0427 ac->addAction("showStatusBar", actions->showStatusBar); 0428 connect(actions->showStatusBar, SIGNAL(toggled(bool)), 0429 view, SLOT(showStatusBar(bool))); 0430 0431 actions->showTabBar = new KToggleAction(i18n("Tab Bar"), view); 0432 actions->showTabBar->setToolTip(i18n("Show the tab bar")); 0433 ac->addAction("showTabBar", actions->showTabBar); 0434 connect(actions->showTabBar, SIGNAL(toggled(bool)), 0435 view, SLOT(showTabBar(bool))); 0436 0437 actions->preference = KStandardAction::preferences(view, SLOT(preference()), view); 0438 actions->preference->setToolTip(i18n("Set various Calligra Sheets options")); 0439 ac->addAction("preference", actions->preference); 0440 0441 QAction *notifyAction = KStandardAction::configureNotifications(view, SLOT(optionsNotifications()), view); 0442 ac->addAction("configureNotifications", notifyAction); 0443 0444 // -- calculation actions -- 0445 // 0446 QActionGroup* groupCalc = new QActionGroup(view); 0447 actions->calcNone = new KToggleAction(i18n("None"), view); 0448 ac->addAction("menu_none", actions->calcNone); 0449 connect(actions->calcNone, SIGNAL(toggled(bool)), 0450 view, SLOT(menuCalc(bool))); 0451 actions->calcNone->setToolTip(i18n("No calculation")); 0452 actions->calcNone->setActionGroup(groupCalc); 0453 0454 actions->calcSum = new KToggleAction(i18n("Sum"), view); 0455 ac->addAction("menu_sum", actions->calcSum); 0456 connect(actions->calcSum, SIGNAL(toggled(bool)), 0457 view, SLOT(menuCalc(bool))); 0458 actions->calcSum->setToolTip(i18n("Calculate using sum")); 0459 actions->calcSum->setActionGroup(groupCalc); 0460 0461 actions->calcMin = new KToggleAction(i18n("Min"), view); 0462 ac->addAction("menu_min", actions->calcMin); 0463 connect(actions->calcMin, SIGNAL(toggled(bool)), 0464 view, SLOT(menuCalc(bool))); 0465 actions->calcMin->setToolTip(i18n("Calculate using minimum")); 0466 actions->calcMin->setActionGroup(groupCalc); 0467 0468 actions->calcMax = new KToggleAction(i18n("Max"), view); 0469 ac->addAction("menu_max", actions->calcMax); 0470 connect(actions->calcMax, SIGNAL(toggled(bool)), 0471 view, SLOT(menuCalc(bool))); 0472 actions->calcMax->setToolTip(i18n("Calculate using maximum")); 0473 actions->calcMax->setActionGroup(groupCalc); 0474 0475 actions->calcAverage = new KToggleAction(i18n("Average"), view); 0476 ac->addAction("menu_average", actions->calcAverage); 0477 connect(actions->calcAverage, SIGNAL(toggled(bool)), 0478 view, SLOT(menuCalc(bool))); 0479 actions->calcAverage->setToolTip(i18n("Calculate using average")); 0480 actions->calcAverage->setActionGroup(groupCalc); 0481 0482 actions->calcCount = new KToggleAction(i18n("Count"), view); 0483 ac->addAction("menu_count", actions->calcCount); 0484 connect(actions->calcCount, SIGNAL(toggled(bool)), 0485 view, SLOT(menuCalc(bool))); 0486 actions->calcCount->setToolTip(i18n("Calculate using the count")); 0487 actions->calcCount->setActionGroup(groupCalc); 0488 0489 actions->calcCountA = new KToggleAction(i18n("CountA"), view); 0490 ac->addAction("menu_counta", actions->calcCountA); 0491 connect(actions->calcCountA, SIGNAL(toggled(bool)), 0492 view, SLOT(menuCalc(bool))); 0493 actions->calcCountA->setToolTip(i18n("Calculate using the countA")); 0494 actions->calcCountA->setActionGroup(groupCalc); 0495 0496 //Shape actions 0497 actions->deleteShape = new QAction(koIcon("edit-delete"), i18n("Delete"), view); 0498 actions->deleteShape->setShortcut(QKeySequence("Del")); 0499 connect(actions->deleteShape, SIGNAL(triggered()), view, SLOT(editDeleteSelection())); 0500 connect(canvas->toolProxy(), SIGNAL(selectionChanged(bool)), actions->deleteShape, SLOT(setEnabled(bool))); 0501 ac->addAction("edit_delete", actions->deleteShape); 0502 0503 // -- special action, only for developers -- 0504 // 0505 0506 ac->addAssociatedWidget(view->canvasWidget()); 0507 foreach(QAction* action, ac->actions()) { 0508 action->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0509 } 0510 } 0511 0512 void View::Private::adjustActions(bool mode) 0513 { 0514 actions->recalcWorkbook->setEnabled(mode); 0515 actions->recalcWorksheet->setEnabled(mode); 0516 actions->paperLayout->setEnabled(mode); 0517 actions->resetPrintRange->setEnabled(mode); 0518 actions->deleteSheet->setEnabled(mode); 0519 actions->calcMin->setEnabled(mode); 0520 actions->calcMax->setEnabled(mode); 0521 actions->calcAverage->setEnabled(mode); 0522 actions->calcCount->setEnabled(mode); 0523 actions->calcCountA->setEnabled(mode); 0524 actions->calcSum->setEnabled(mode); 0525 actions->calcNone->setEnabled(mode); 0526 0527 if (mode && !view->doc()->map()->isProtected()) 0528 actions->renameSheet->setEnabled(true); 0529 else 0530 actions->renameSheet->setEnabled(false); 0531 0532 actions->showColumnHeader->setChecked(view->doc()->map()->settings()->showColumnHeader()); 0533 actions->showRowHeader->setChecked(view->doc()->map()->settings()->showRowHeader()); 0534 actions->showHorizontalScrollBar->setChecked(view->doc()->map()->settings()->showHorizontalScrollBar()); 0535 actions->showVerticalScrollBar->setChecked(view->doc()->map()->settings()->showVerticalScrollBar()); 0536 actions->showStatusBar->setChecked(view->doc()->map()->settings()->showStatusBar()); 0537 actions->showTabBar->setChecked(view->doc()->map()->settings()->showTabBar()); 0538 0539 if (activeSheet) 0540 selection->update(); 0541 } 0542 0543 0544 /***************************************************************************** 0545 * 0546 * View 0547 * 0548 *****************************************************************************/ 0549 0550 View::View(KoPart *part, QWidget *_parent, Doc *_doc) 0551 : KoView(part, _doc, _parent) 0552 , d(new Private) 0553 { 0554 ElapsedTime et("View constructor"); 0555 0556 d->view = this; 0557 d->doc = _doc; 0558 0559 d->activeSheet = 0; 0560 0561 d->loading = true; 0562 0563 setComponentName(Factory::global().componentName(), Factory::global().componentDisplayName()); 0564 setXMLFile("calligrasheets.rc"); 0565 0566 // GUI Initializations 0567 initView(); 0568 0569 d->initActions(); 0570 0571 const QList<KPluginFactory *> pluginFactories = 0572 KoPluginLoader::instantiatePluginFactories(QStringLiteral("calligrasheets/extensions")); 0573 0574 foreach (KPluginFactory* factory, pluginFactories) { 0575 QObject *object = factory->create<QObject>(this, QVariantList()); 0576 KXMLGUIClient *clientPlugin = dynamic_cast<KXMLGUIClient*>(object); 0577 if (clientPlugin) { 0578 insertChildClient(clientPlugin); 0579 } else { 0580 // not our/valid plugin, so delete the created object 0581 object->deleteLater(); 0582 } 0583 } 0584 0585 // Connect updateView() signal to View::update() in order to repaint its 0586 // child widgets: the column/row headers and the select all button. 0587 // Connect to Canvas::update() explicitly as it lives in the viewport 0588 // of the KoCanvasController. 0589 connect(doc(), SIGNAL(updateView()), 0590 this, SLOT(update())); 0591 connect(doc(), SIGNAL(updateView()), 0592 d->canvas, SLOT(update())); 0593 connect(doc()->map(), SIGNAL(sheetAdded(Sheet*)), 0594 this, SLOT(addSheet(Sheet*))); 0595 connect(doc()->map(), SIGNAL(sheetRemoved(Sheet*)), 0596 this, SLOT(removeSheet(Sheet*))); 0597 connect(doc()->map(), SIGNAL(sheetRevived(Sheet*)), 0598 this, SLOT(addSheet(Sheet*))); 0599 connect(doc()->map(), SIGNAL(damagesFlushed(QList<Damage*>)), 0600 this, SLOT(handleDamages(QList<Damage*>))); 0601 if (statusBar()) { 0602 connect(doc()->map(), SIGNAL(statusMessage(QString,int)), 0603 statusBar(), SLOT(showMessage(QString,int))); 0604 } 0605 0606 connect(&d->statusBarOpTimer, SIGNAL(timeout()), this, SLOT(calcStatusBarOp())); 0607 0608 // Delay the setting of the initial position, because we need to have 0609 // a sensible widget size, which is not always the case from the beginning 0610 // of the View's lifetime. 0611 // Therefore, initialPosition(), the last operation in the "View loading" 0612 // process, is called from resizeEvent(). The loading flag will be unset 0613 // at the end of initialPosition(). 0614 0615 #ifndef QT_NO_DBUS 0616 new ViewAdaptor(this); 0617 #endif 0618 0619 d->scrollTimer = new QTimer(this); 0620 connect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll())); 0621 0622 initialPosition(); 0623 0624 d->canvas->setFocus(); 0625 } 0626 0627 View::~View() 0628 { 0629 selection()->emitCloseEditor(true); // save changes 0630 0631 // if (d->calcLabel) disconnect(d->calcLabel,SIGNAL(pressed(int)),this,SLOT(statusBarClicked(int))); 0632 0633 d->selection->emitCloseEditor(false); 0634 d->selection->endReferenceSelection(false); 0635 d->activeSheet = 0; // set the active sheet to 0 so that when during destruction 0636 // of embedded child documents possible repaints in Sheet are not 0637 // performed. 0638 0639 // delete the sheetView's after calling d->selection->emitCloseEditor cause the 0640 // emitCloseEditor may trigger over the Selection::emitChanged a Canvas::scrollToCell 0641 // which in turn needs the sheetview's to access the sheet itself. 0642 qDeleteAll(d->sheetViews.values()); 0643 0644 delete d->scrollTimer; 0645 0646 delete d->selection; 0647 d->selection = 0; 0648 delete d->calcLabel; 0649 delete d->actions; 0650 delete d->zoomHandler; 0651 0652 // NOTE sebsauer: first unregister the event-handler, then delete the canvas and then we are save to 0653 // call removeCanvasController without crashing. 0654 //d->canvasController->canvas()->canvasWidget()->removeEventFilter(d->canvasController); 0655 //delete d->canvasController->canvas(); 0656 // NOTE sebsauer: We need to remove the canvasController right before deleting it and 0657 // nothing needs to be done in between cause flake does first delete the TableTool 0658 // on removeCanvasController and the proxytool which points to that TableTool later 0659 // while the canvasController is destroyed. That means, that we will have a dangling 0660 // pointer in the KoToolProxy that points to the KoToolBase the time in between. 0661 KoToolManager::instance()->removeCanvasController(d->canvasController); 0662 // NOTE Stefan: Delete the Canvas explicitly, even if it has this view as 0663 // parent. Otherwise, it leads to crashes, because it tries to 0664 // access this View in some events (Bug #126492). 0665 // The KoCanvasController takes ownership of the Canvas and does the deletion. 0666 delete d->canvasController; 0667 delete d; 0668 } 0669 0670 Doc* View::doc() const 0671 { 0672 return d->doc; 0673 } 0674 0675 // should be called only once, from the constructor 0676 /* 0677 * Central part is the canvas, row header and vertical scrollbar. 0678 * Bottom part is the tab bar and horizontal scrollbar. 0679 * 0680 * Note that canvas must the one to be created, since other 0681 * widgets might depend on it. 0682 */ 0683 0684 void View::initView() 0685 { 0686 d->viewLayout = new QGridLayout(this); 0687 d->viewLayout->setMargin(0); 0688 d->viewLayout->setSpacing(0); 0689 0690 // Setup the Canvas and its controller. 0691 d->canvas = new Canvas(this); 0692 KoCanvasControllerWidget *canvasController = new KoCanvasControllerWidget(actionCollection(), this); 0693 d->canvasController = canvasController; 0694 d->canvasController->setCanvas(d->canvas); 0695 d->canvasController->setCanvasMode(KoCanvasController::Spreadsheet); 0696 canvasController->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0697 canvasController->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0698 0699 // Setup the map model. 0700 d->mapViewModel = new MapViewModel(d->doc->map(), d->canvas, this); 0701 connect(d->mapViewModel, SIGNAL(addCommandRequested(KUndo2Command*)), 0702 doc(), SLOT(addCommand(KUndo2Command*))); 0703 connect(d->mapViewModel, SIGNAL(activeSheetChanged(Sheet*)), 0704 this, SLOT(setActiveSheet(Sheet*))); 0705 0706 // Setup the selection. 0707 d->selection = new Selection(d->canvas); 0708 connect(d->selection, SIGNAL(changed(Region)), this, SLOT(slotChangeSelection(Region))); 0709 connect(d->selection, SIGNAL(changed(Region)), this, SLOT(slotScrollChoice(Region))); 0710 connect(d->selection, SIGNAL(aboutToModify(Region)), this, SLOT(aboutToModify(Region))); 0711 connect(d->selection, SIGNAL(modified(Region)), this, SLOT(refreshSelection(Region))); 0712 connect(d->selection, SIGNAL(visibleSheetRequested(Sheet*)), this, SLOT(setActiveSheet(Sheet*))); 0713 connect(d->selection, SIGNAL(refreshSheetViews()), this, SLOT(refreshSheetViews())); 0714 connect(d->selection, SIGNAL(updateAccessedCellRange(Sheet*,QPoint)), this, SLOT(updateAccessedCellRange(Sheet*,QPoint))); 0715 connect(this, SIGNAL(documentReadWriteToggled(bool)), 0716 d->selection, SIGNAL(documentReadWriteToggled(bool))); 0717 connect(this, SIGNAL(sheetProtectionToggled(bool)), 0718 d->selection, SIGNAL(sheetProtectionToggled(bool))); 0719 0720 // Let the selection pointer become a canvas resource. 0721 QVariant variant; 0722 variant.setValue<void*>(d->selection); 0723 d->canvas->resourceManager()->setResource(::Sheets::CanvasResource::Selection, variant); 0724 variant.setValue<QObject*>(doc()->map()->bindingManager()); 0725 0726 // Load the Calligra Sheets Tools 0727 ToolRegistry::instance()->loadTools(); 0728 0729 if (mainWindow()) 0730 { 0731 KoToolManager::instance()->addController(d->canvasController); 0732 KoToolManager::instance()->registerTools(actionCollection(), d->canvasController); 0733 KoModeBoxFactory modeBoxFactory(canvasController, qApp->applicationName(), i18n("Tools")); 0734 QDockWidget* modeBox = mainWindow()->createDockWidget(&modeBoxFactory); 0735 mainWindow()->dockerManager()->removeToolOptionsDocker(); 0736 dynamic_cast<KoCanvasObserverBase*>(modeBox)->setObservedCanvas(d->canvas); 0737 0738 // Setup the tool options dock widget manager. 0739 //connect(canvasController, SIGNAL(toolOptionWidgetsChanged(QList<QPointer<QWidget> >)), 0740 // mainWindow()->dockerManager(), SLOT(newOptionWidgets(QList<QPointer<QWidget> >))); 0741 } 0742 // Setup the zoom controller. 0743 d->zoomHandler = new KoZoomHandler(); 0744 d->zoomController = new KoZoomController(d->canvasController, d->zoomHandler, actionCollection(), 0, this); 0745 d->zoomController->zoomAction()->setZoomModes(KoZoomMode::ZOOM_CONSTANT); 0746 QWidget *zoomWidget = d->zoomController->zoomAction()->createWidget(statusBar()); 0747 zoomWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0748 addStatusBarItem(zoomWidget, 0, true); 0749 connect(d->zoomController, SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), 0750 this, SLOT(viewZoom(KoZoomMode::Mode,qreal))); 0751 0752 d->columnHeader = new ColumnHeaderWidget(this, d->canvas, this); 0753 d->rowHeader = new RowHeaderWidget(this, d->canvas , this); 0754 d->columnHeader->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); 0755 d->rowHeader->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); 0756 d->selectAllButton = new SelectAllButtonWidget(d->canvas); 0757 d->selectAllButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); 0758 0759 d->canvas->setFocusPolicy(Qt::StrongFocus); 0760 QWidget::setFocusPolicy(Qt::StrongFocus); 0761 setFocusProxy(d->canvas); 0762 0763 // Vert. Scroll Bar 0764 d->calcLabel = 0; 0765 d->vertScrollBar = new QScrollBar(this); 0766 canvasController->setVerticalScrollBar(d->vertScrollBar); 0767 connect(d->vertScrollBar, SIGNAL(valueChanged(int)), canvasController, SLOT(updateCanvasOffsetY())); 0768 d->vertScrollBar->setOrientation(Qt::Vertical); 0769 d->vertScrollBar->setSingleStep(60); //just random guess based on what feels okay 0770 d->vertScrollBar->setPageStep(60); //This should be controlled dynamically, depending on how many rows are shown 0771 0772 QWidget* bottomPart = new QWidget(this); 0773 d->tabScrollBarLayout = new QGridLayout(bottomPart); 0774 d->tabScrollBarLayout->setMargin(0); 0775 d->tabScrollBarLayout->setSpacing(0); 0776 d->tabScrollBarLayout->setColumnStretch(1, 1); 0777 d->tabBar = new TabBar(0); 0778 d->tabScrollBarLayout->addWidget(d->tabBar, 0, 0); 0779 d->horzScrollBar = new QScrollBar(0); 0780 canvasController->setHorizontalScrollBar(d->horzScrollBar); 0781 connect(d->horzScrollBar, SIGNAL(valueChanged(int)), canvasController, SLOT(updateCanvasOffsetX())); 0782 d->tabScrollBarLayout->addWidget(d->horzScrollBar, 0, 1, 2, 1, Qt::AlignVCenter); 0783 0784 d->horzScrollBar->setOrientation(Qt::Horizontal); 0785 d->horzScrollBar->setSingleStep(60); //just random guess based on what feels okay 0786 d->horzScrollBar->setPageStep(60); 0787 0788 connect(d->tabBar, SIGNAL(tabChanged(QString)), this, SLOT(changeSheet(QString))); 0789 connect(d->tabBar, SIGNAL(tabMoved(unsigned,unsigned)), 0790 this, SLOT(moveSheet(unsigned,unsigned))); 0791 connect(d->tabBar, SIGNAL(contextMenu(QPoint)), 0792 this, SLOT(popupTabBarMenu(QPoint))); 0793 connect(d->tabBar, SIGNAL(doubleClicked()), 0794 this, SLOT(slotRename())); 0795 0796 int extent = this->style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0797 if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) { 0798 extent += style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; 0799 } 0800 0801 d->viewLayout->setColumnStretch(1, 10); 0802 d->viewLayout->setRowStretch(2, 10); 0803 d->viewLayout->addWidget(d->selectAllButton, 1, 0); 0804 d->viewLayout->addWidget(d->columnHeader, 1, 1, 1, 1); 0805 d->viewLayout->addWidget(d->rowHeader, 2, 0); 0806 d->viewLayout->addWidget(canvasController, 2, 1); 0807 d->viewLayout->addWidget(d->vertScrollBar, 1, 2, 2, 1, Qt::AlignHCenter); 0808 d->viewLayout->addWidget(bottomPart, 3, 0, 1, 2); 0809 d->viewLayout->setColumnMinimumWidth(2, extent); 0810 d->viewLayout->setRowMinimumHeight(3, extent); 0811 0812 QStatusBar * sb = statusBar(); 0813 d->calcLabel = sb ? new QLabel(sb) : 0; 0814 if (d->calcLabel) { 0815 d->calcLabel->setContextMenuPolicy(Qt::CustomContextMenu); 0816 addStatusBarItem(d->calcLabel, 0); 0817 connect(d->calcLabel , SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(statusBarClicked(QPoint))); 0818 } 0819 0820 // signal slot 0821 connect(d->canvas, SIGNAL(documentSizeChanged(QSize)), 0822 d->canvasController->proxyObject, SLOT(updateDocumentSize(QSize))); 0823 connect(d->canvasController->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), 0824 d->canvas, SLOT(setDocumentOffset(QPoint))); 0825 connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), 0826 this, SLOT(shapeSelectionChanged())); 0827 } 0828 0829 Canvas* View::canvasWidget() const 0830 { 0831 return d->canvas; 0832 } 0833 0834 KoZoomController *View::zoomController() const 0835 { 0836 return d->zoomController; 0837 } 0838 0839 KoCanvasController* View::canvasController() const 0840 { 0841 return d->canvasController; 0842 } 0843 0844 ColumnHeaderWidget* View::columnHeader()const 0845 { 0846 return d->columnHeader; 0847 } 0848 0849 RowHeaderWidget* View::rowHeader()const 0850 { 0851 return d->rowHeader; 0852 } 0853 0854 QScrollBar* View::horzScrollBar()const 0855 { 0856 return d->horzScrollBar; 0857 } 0858 0859 QScrollBar* View::vertScrollBar()const 0860 { 0861 return d->vertScrollBar; 0862 } 0863 0864 TabBar* View::tabBar() const 0865 { 0866 return d->tabBar; 0867 } 0868 0869 KoZoomHandler* View::zoomHandler() const 0870 { 0871 return d->zoomHandler; 0872 } 0873 0874 bool View::isLoading() const 0875 { 0876 return d->loading; 0877 } 0878 0879 Selection* View::selection() const 0880 { 0881 return d->selection; 0882 } 0883 0884 Sheet* View::activeSheet() const 0885 { 0886 return d->activeSheet; 0887 } 0888 0889 void View::sheetDestroyed(QObject* obj) 0890 { 0891 if (Sheet *sheet = dynamic_cast<Sheet*>(obj)) { 0892 Q_ASSERT(d->sheetViews.contains(sheet)); 0893 d->sheetViews.remove(sheet); 0894 // The SheetView will be proper destroyed already cause it's a QObject-child of the sheet. 0895 } 0896 } 0897 0898 SheetView* View::sheetView(const Sheet* sheet) const 0899 { 0900 SheetView *sheetView = d->sheetViews.value(sheet); 0901 if (!sheetView) { 0902 debugSheetsRender << "View: Creating SheetView for" << sheet->sheetName(); 0903 sheetView = new SheetView(sheet); 0904 d->sheetViews.insert(sheet, sheetView); 0905 sheetView->setViewConverter(zoomHandler()); 0906 connect(sheetView, SIGNAL(visibleSizeChanged(QSizeF)), 0907 d->canvas, SLOT(setDocumentSize(QSizeF))); 0908 connect(sheetView, SIGNAL(visibleSizeChanged(QSizeF)), 0909 d->zoomController, SLOT(setDocumentSize(QSizeF))); 0910 connect(sheet, SIGNAL(visibleSizeChanged()), 0911 sheetView, SLOT(updateAccessedCellRange())); 0912 connect(sheet, SIGNAL(destroyed(QObject*)), 0913 this, SLOT(sheetDestroyed(QObject*))); 0914 } 0915 return sheetView; 0916 } 0917 0918 void View::refreshSheetViews() 0919 { 0920 QList<const Sheet*> sheets = d->sheetViews.keys(); 0921 QList< QPointer<SheetView> > sheetViews = d->sheetViews.values(); 0922 0923 foreach(const Sheet *sheet, d->sheetViews.keys()) { 0924 disconnect(sheet, SIGNAL(destroyed(QObject*)), this, SLOT(sheetDestroyed(QObject*))); 0925 } 0926 0927 foreach (SheetView *sheetView, sheetViews) { 0928 disconnect(sheetView, SIGNAL(visibleSizeChanged(QSizeF)), 0929 d->canvas, SLOT(setDocumentSize(QSizeF))); 0930 disconnect(sheetView, SIGNAL(visibleSizeChanged(QSizeF)), 0931 d->zoomController, SLOT(setDocumentSize(QSizeF))); 0932 disconnect(sheetView->sheet(), SIGNAL(visibleSizeChanged()), 0933 sheetView, SLOT(updateAccessedCellRange())); 0934 } 0935 0936 qDeleteAll(sheetViews); 0937 d->sheetViews.clear(); 0938 0939 foreach(const Sheet *sheet, d->doc->map()->sheetList()) { 0940 sheet->cellStorage()->invalidateStyleCache(); 0941 } 0942 } 0943 0944 void View::refreshSelection(const Region& region) 0945 { 0946 doc()->map()->addDamage(new CellDamage(activeSheet(), region, CellDamage::Appearance)); 0947 } 0948 0949 void View::aboutToModify(const Region& region) 0950 { 0951 Q_UNUSED(region); 0952 selection()->emitCloseEditor(true); // save changes 0953 } 0954 0955 void View::initConfig() 0956 { 0957 KSharedConfigPtr config = Factory::global().config(); 0958 const KConfigGroup parameterGroup = config->group("Parameters"); 0959 const bool configFromDoc = doc()->configLoadFromFile(); 0960 if (!configFromDoc) { 0961 doc()->map()->settings()->setShowHorizontalScrollBar(parameterGroup.readEntry("Horiz ScrollBar", true)); 0962 doc()->map()->settings()->setShowVerticalScrollBar(parameterGroup.readEntry("Vert ScrollBar", true)); 0963 } 0964 doc()->map()->settings()->setShowColumnHeader(parameterGroup.readEntry("Column Header", true)); 0965 doc()->map()->settings()->setShowRowHeader(parameterGroup.readEntry("Row Header", true)); 0966 if (!configFromDoc) 0967 doc()->map()->settings()->setCompletionMode((KCompletion::CompletionMode)parameterGroup.readEntry("Completion Mode", (int)(KCompletion::CompletionAuto))); 0968 doc()->map()->settings()->setMoveToValue((Calligra::Sheets::MoveTo)parameterGroup.readEntry("Move", (int)(Bottom))); 0969 doc()->map()->settings()->setIndentValue(parameterGroup.readEntry("Indent", 10.0)); 0970 doc()->map()->settings()->setTypeOfCalc((MethodOfCalc)parameterGroup.readEntry("Method of Calc", (int)(SumOfNumber))); 0971 if (!configFromDoc) 0972 doc()->map()->settings()->setShowTabBar(parameterGroup.readEntry("Tabbar", true)); 0973 0974 doc()->map()->settings()->setShowStatusBar(parameterGroup.readEntry("Status bar", true)); 0975 0976 changeNbOfRecentFiles(parameterGroup.readEntry("NbRecentFile", 10)); 0977 //autosave value is stored as a minute. 0978 //but default value is stored as seconde. 0979 doc()->setAutoSave(parameterGroup.readEntry("AutoSave", KoDocument::defaultAutoSave() / 60)*60); 0980 doc()->setBackupFile(parameterGroup.readEntry("BackupFile", true)); 0981 0982 const KConfigGroup colorGroup = config->group("KSpread Color"); 0983 doc()->map()->settings()->setGridColor(colorGroup.readEntry("GridColor", QColor(Qt::lightGray))); 0984 doc()->map()->settings()->changePageOutlineColor(colorGroup.readEntry("PageOutlineColor", QColor(Qt::red))); 0985 0986 initCalcMenu(); 0987 calcStatusBarOp(); 0988 } 0989 0990 void View::changeNbOfRecentFiles(int _nb) 0991 { 0992 if (mainWindow()) 0993 mainWindow()->setMaxRecentItems(_nb); 0994 } 0995 0996 void View::initCalcMenu() 0997 { 0998 switch (doc()->map()->settings()->getTypeOfCalc()) { 0999 case SumOfNumber: 1000 d->actions->calcSum->setChecked(true); 1001 break; 1002 case Min: 1003 d->actions->calcMin->setChecked(true); 1004 break; 1005 case Max: 1006 d->actions->calcMax->setChecked(true); 1007 break; 1008 case Average: 1009 d->actions->calcAverage->setChecked(true); 1010 break; 1011 case Count: 1012 d->actions->calcCount->setChecked(true); 1013 break; 1014 case CountA: 1015 d->actions->calcCountA->setChecked(true); 1016 break; 1017 case NoneCalc: 1018 d->actions->calcNone->setChecked(true); 1019 break; 1020 default : 1021 d->actions->calcSum->setChecked(true); 1022 break; 1023 } 1024 1025 } 1026 1027 1028 void View::recalcWorkBook() 1029 { 1030 doc()->map()->recalcManager()->recalcMap(); 1031 } 1032 1033 void View::recalcWorkSheet() 1034 { 1035 if (!activeSheet()) 1036 return; 1037 doc()->map()->recalcManager()->recalcSheet(activeSheet()); 1038 } 1039 1040 void View::shapeSelectionChanged() 1041 { 1042 const KoSelection* selection = d->canvas->shapeManager()->selection(); 1043 const QList<KoShape*> shapes = selection->selectedShapes(KoFlake::StrippedSelection); 1044 1045 if (shapes.isEmpty()) { 1046 d->actions->shapeAnchor->setEnabled(false); 1047 return; 1048 } 1049 d->actions->shapeAnchor->setEnabled(true); 1050 1051 // start with the first shape 1052 const KoShape* shape = shapes[0]; 1053 const ShapeApplicationData* data = dynamic_cast<ShapeApplicationData*>(shape->applicationData()); 1054 if (!data) { 1055 // Container children do not have the application data set, deselect the anchoring action. 1056 d->actions->shapeAnchor->setCurrentAction(0); 1057 return; 1058 } 1059 bool anchoredToCell = data->isAnchoredToCell(); 1060 d->actions->shapeAnchor->setCurrentAction(anchoredToCell ? i18n("Cell") : i18n("Page")); 1061 1062 // go on with the remaining shapes 1063 for (int i = 1; i < shapes.count(); ++i) { 1064 shape = shapes[i]; 1065 data = dynamic_cast<ShapeApplicationData*>(shape->applicationData()); 1066 Q_ASSERT(data); 1067 if (anchoredToCell != data->isAnchoredToCell()) { 1068 // If the anchoring differs between shapes, deselect the anchoring action and stop here. 1069 d->actions->shapeAnchor->setCurrentAction(0); 1070 break; 1071 } 1072 } 1073 } 1074 1075 1076 void View::editDeleteSelection() 1077 { 1078 d->canvas->toolProxy()->deleteSelection(); 1079 } 1080 1081 void View::initialPosition() 1082 { 1083 // Loading completed, pick initial worksheet 1084 foreach(Sheet* sheet, doc()->map()->sheetList()) { 1085 addSheet(sheet); 1086 } 1087 1088 // Set the initial X and Y offsets for the view (OpenDocument loading) 1089 const LoadingInfo* loadingInfo = doc()->map()->loadingInfo(); 1090 if (loadingInfo->fileFormat() == LoadingInfo::OpenDocument) { 1091 d->savedAnchors = loadingInfo->cursorPositions(); 1092 d->savedMarkers = loadingInfo->cursorPositions(); 1093 d->savedOffsets = loadingInfo->scrollingOffsets(); 1094 } 1095 1096 Sheet* sheet = loadingInfo->initialActiveSheet(); 1097 if (!sheet) { 1098 //activate first table which is not hiding 1099 sheet = doc()->map()->visibleSheets().isEmpty() ? 0 : doc()->map()->findSheet(doc()->map()->visibleSheets().first()); 1100 if (!sheet) { 1101 sheet = doc()->map()->sheet(0); 1102 if (sheet) { 1103 sheet->setHidden(false); 1104 QString tabName = sheet->sheetName(); 1105 d->tabBar->addTab(tabName); 1106 } 1107 } 1108 } 1109 setActiveSheet(sheet); 1110 d->mapViewModel->setActiveSheet(sheet); 1111 1112 // Set the initial X and Y offsets for the view (Native format loading) 1113 if (loadingInfo->fileFormat() == LoadingInfo::NativeFormat) { 1114 const QPoint offset = zoomHandler()->documentToView(loadingInfo->scrollingOffsets()[sheet]).toPoint(); 1115 d->canvas->setDocumentOffset(offset); 1116 d->horzScrollBar->setValue(offset.x()); 1117 d->vertScrollBar->setValue(offset.y()); 1118 // Set the initial position for the marker as stored in the XML file, 1119 // (1,1) otherwise 1120 const QPoint marker = loadingInfo->cursorPositions()[sheet]; 1121 d->selection->initialize((marker.x() <= 0 || marker.y() <= 0) ? QPoint(1, 1) : marker); 1122 } 1123 1124 updateShowSheetMenu(); 1125 1126 // Initialize shape anchoring action. 1127 shapeSelectionChanged(); 1128 1129 initConfig(); 1130 1131 d->canvas->setFocus(); 1132 1133 QTimer::singleShot(50, this, SLOT(finishLoading())); 1134 } 1135 1136 void View::finishLoading() 1137 { 1138 // finish the "View Loading" process 1139 d->loading = false; 1140 doc()->map()->deleteLoadingInfo(); 1141 1142 setHeaderMinima(); 1143 1144 // Activate the cell tool. 1145 if (mainWindow()) 1146 KoToolManager::instance()->switchToolRequested("KSpreadCellToolId"); 1147 } 1148 1149 void View::updateReadWrite(bool readwrite) 1150 { 1151 // inform the cell tool 1152 emit documentReadWriteToggled(readwrite); 1153 1154 const QList<QAction*> actions = actionCollection()->actions(); 1155 for (int i = 0; i < actions.count(); ++i) { 1156 // The action collection contains also the flake tool actions. Skip them. 1157 if (actions[i]->parent() == this) 1158 actions[i]->setEnabled(readwrite); 1159 } 1160 1161 if (!doc() || !doc()->map() || doc()->map()->isProtected()) { 1162 d->actions->showSheet->setEnabled(false); 1163 d->actions->hideSheet->setEnabled(false); 1164 } else { 1165 d->actions->showSheet->setEnabled(true); 1166 d->actions->hideSheet->setEnabled(true); 1167 } 1168 d->actions->showPageOutline->setEnabled(true); 1169 d->tabBar->setReadOnly(doc()->map()->isProtected()); 1170 } 1171 1172 void View::createTemplate() 1173 { 1174 KoTemplateCreateDia::createTemplate(doc()->documentPart()->templatesResourcePath(), ".ots", 1175 doc(), this); 1176 } 1177 1178 void View::setActiveSheet(Sheet* sheet, bool updateSheet) 1179 { 1180 // It can happen that our tabBar->activeTab() is not in sync with our activeSheet() if 1181 // setActiveSheet() was previously called before the delayed View::initialPosition() 1182 // was called and had a change to proper TabBar::setTabs(). 1183 if (sheet == d->activeSheet && (!sheet || d->tabBar->activeTab() == sheet->sheetName())) 1184 return; 1185 1186 if (d->activeSheet != 0 && !d->selection->referenceSelectionMode()) { 1187 selection()->emitCloseEditor(true); // save changes 1188 saveCurrentSheetSelection(); 1189 } 1190 1191 const Sheet* oldSheet = d->activeSheet; 1192 d->activeSheet = sheet; 1193 1194 if (d->activeSheet == 0) { 1195 return; 1196 } 1197 1198 // flake 1199 // Change the active shape controller and its shapes. 1200 d->canvas->shapeController()->setShapeControllerBase(d->activeSheet); 1201 // and then update the toolmanager separately 1202 KoToolManager::instance()->updateShapeControllerBase(d->activeSheet, d->canvas->canvasController()); 1203 1204 d->canvas->shapeManager()->setShapes(d->activeSheet->shapes()); 1205 // Tell the Canvas about the new visible sheet size. 1206 sheetView(d->activeSheet)->updateAccessedCellRange(); 1207 1208 // If there was no sheet before or the layout directions differ. 1209 if (!oldSheet || oldSheet->layoutDirection() != d->activeSheet->layoutDirection()) { 1210 // Propagate the layout direction to the canvas and horz. scrollbar. 1211 const Qt::LayoutDirection direction = d->activeSheet->layoutDirection(); 1212 d->canvas->setLayoutDirection(direction); 1213 d->horzScrollBar->setLayoutDirection(direction); 1214 // Replace the painting strategy for painting shapes. 1215 KoShapeManager *const shapeManager = d->canvas->shapeManager(); 1216 KoShapeManagerPaintingStrategy *paintingStrategy = 0; 1217 if (direction == Qt::LeftToRight) { 1218 paintingStrategy = new KoShapeManagerPaintingStrategy(shapeManager); 1219 } else { 1220 paintingStrategy = new RightToLeftPaintingStrategy(shapeManager, d->canvas); 1221 } 1222 shapeManager->setPaintingStrategy(paintingStrategy); 1223 } 1224 // If there was no sheet before or the formula visibilities differ. 1225 if (!oldSheet || oldSheet->getShowFormula() != d->activeSheet->getShowFormula()) { 1226 const bool showFormulas = d->activeSheet->getShowFormula(); 1227 stateChanged("show_formulas", showFormulas ? StateNoReverse : StateReverse); 1228 } 1229 1230 // Restore the old scrolling offset. 1231 QMap<Sheet*, QPointF>::ConstIterator it3 = d->savedOffsets.constFind(d->activeSheet); 1232 if (it3 != d->savedOffsets.constEnd()) { 1233 const QPoint offset = zoomHandler()->documentToView(*it3).toPoint(); 1234 d->canvas->setDocumentOffset(offset); 1235 d->horzScrollBar->setValue(offset.x()); 1236 d->vertScrollBar->setValue(offset.y()); 1237 } 1238 1239 // tell the resource manager of the newly active page 1240 d->canvas->resourceManager()->setResource(KoCanvasResourceManager::CurrentPage, QVariant(sheet->map()->indexOf(sheet) + 1)); 1241 1242 // Always repaint the visible cells. 1243 d->canvas->update(); 1244 d->rowHeader->update(); 1245 d->columnHeader->update(); 1246 d->selectAllButton->update(); 1247 1248 // Prevents an endless loop, if called by the TabBar. 1249 if (updateSheet) { 1250 d->tabBar->setActiveTab(d->activeSheet->sheetName()); 1251 } 1252 1253 if (d->selection->referenceSelectionMode()) { 1254 d->selection->setActiveSheet(d->activeSheet); 1255 return; 1256 } 1257 1258 /* see if there was a previous selection on this other sheet */ 1259 QMap<Sheet*, QPoint>::ConstIterator it = d->savedAnchors.constFind(d->activeSheet); 1260 QMap<Sheet*, QPoint>::ConstIterator it2 = d->savedMarkers.constFind(d->activeSheet); 1261 1262 // restore the old anchor and marker 1263 const QPoint newAnchor = (it == d->savedAnchors.constEnd()) ? QPoint(1, 1) : *it; 1264 const QPoint newMarker = (it2 == d->savedMarkers.constEnd()) ? QPoint(1, 1) : *it2; 1265 1266 d->selection->clear(); 1267 d->selection->setActiveSheet(d->activeSheet); 1268 d->selection->setOriginSheet(d->activeSheet); 1269 d->selection->initialize(newAnchor); 1270 d->selection->update(newMarker); 1271 1272 d->actions->showPageOutline->blockSignals(true); 1273 d->actions->showPageOutline->setChecked(d->activeSheet->isShowPageOutline()); 1274 d->actions->showPageOutline->blockSignals(false); 1275 1276 d->actions->protectSheet->blockSignals(true); 1277 d->actions->protectSheet->setChecked(d->activeSheet->isProtected()); 1278 d->actions->protectSheet->blockSignals(false); 1279 1280 d->actions->protectDoc->blockSignals(true); 1281 d->actions->protectDoc->setChecked(doc()->map()->isProtected()); 1282 d->actions->protectDoc->blockSignals(false); 1283 1284 d->adjustActions(!d->activeSheet->isProtected()); 1285 const bool protect = d->activeSheet->isProtected(); 1286 stateChanged("sheet_is_protected", protect ? StateNoReverse : StateReverse); 1287 1288 // Auto calculation state for the INFO function. 1289 const bool autoCalc = d->activeSheet->isAutoCalculationEnabled(); 1290 d->doc->map()->calculationSettings()->setAutoCalculationEnabled(autoCalc); 1291 1292 calcStatusBarOp(); 1293 } 1294 1295 void View::changeSheet(const QString& _name) 1296 { 1297 if (activeSheet()->sheetName() == _name) 1298 return; 1299 1300 Sheet *t = doc()->map()->findSheet(_name); 1301 if (!t) { 1302 debugSheets << "Unknown sheet" << _name; 1303 return; 1304 } 1305 setActiveSheet(t, false /* False: Endless loop because of setActiveTab() => do the visual area update manually*/); 1306 d->mapViewModel->setActiveSheet(t); 1307 } 1308 1309 void View::moveSheet(unsigned sheet, unsigned target) 1310 { 1311 if (doc()->map()->isProtected()) return; 1312 1313 QStringList vs = doc()->map()->visibleSheets(); 1314 1315 if (target >= (uint) vs.count()) 1316 doc()->map()->moveSheet(vs[ sheet ], vs[ vs.count()-1 ], false); 1317 else 1318 doc()->map()->moveSheet(vs[ sheet ], vs[ target ], true); 1319 1320 d->tabBar->moveTab(sheet, target); 1321 } 1322 1323 void View::sheetProperties() 1324 { 1325 // sanity check, shouldn't happen 1326 if (doc()->map()->isProtected()) return; 1327 if (d->activeSheet->isProtected()) return; 1328 1329 bool directionChanged = false; 1330 bool formulaVisibilityChanged = false; 1331 1332 QPointer<SheetPropertiesDialog> dlg = new SheetPropertiesDialog(this); 1333 dlg->setLayoutDirection(d->activeSheet->layoutDirection()); 1334 dlg->setAutoCalculationEnabled(d->activeSheet->isAutoCalculationEnabled()); 1335 dlg->setShowGrid(d->activeSheet->getShowGrid()); 1336 dlg->setShowPageOutline(d->activeSheet->isShowPageOutline()); 1337 dlg->setShowFormula(d->activeSheet->getShowFormula()); 1338 dlg->setHideZero(d->activeSheet->getHideZero()); 1339 dlg->setShowFormulaIndicator(d->activeSheet->getShowFormulaIndicator()); 1340 dlg->setShowCommentIndicator(d->activeSheet->getShowCommentIndicator()); 1341 dlg->setColumnAsNumber(d->activeSheet->getShowColumnNumber()); 1342 dlg->setLcMode(d->activeSheet->getLcMode()); 1343 dlg->setCapitalizeFirstLetter(d->activeSheet->getFirstLetterUpper()); 1344 1345 if (dlg->exec()) { 1346 SheetPropertiesCommand* command = new SheetPropertiesCommand(d->activeSheet); 1347 1348 if (d->activeSheet->layoutDirection() != dlg->layoutDirection()) 1349 directionChanged = true; 1350 if (d->activeSheet->getShowFormula() != dlg->showFormula()) { 1351 formulaVisibilityChanged = true; 1352 } 1353 1354 command->setLayoutDirection(dlg->layoutDirection()); 1355 command->setAutoCalculationEnabled(dlg->autoCalc()); 1356 command->setShowGrid(dlg->showGrid()); 1357 command->setShowPageOutline(dlg->showPageOutline()); 1358 command->setShowFormula(dlg->showFormula()); 1359 command->setHideZero(dlg->hideZero()); 1360 command->setShowFormulaIndicator(dlg->showFormulaIndicator()); 1361 command->setShowCommentIndicator(dlg->showCommentIndicator()); 1362 command->setColumnAsNumber(dlg->columnAsNumber()); 1363 command->setLcMode(dlg->lcMode()); 1364 command->setCapitalizeFirstLetter(dlg->capitalizeFirstLetter()); 1365 doc()->addCommand(command); 1366 } 1367 1368 delete dlg; 1369 1370 if (directionChanged) { 1371 // the scrollbar and hborder remain reversed otherwise 1372 d->canvas->setLayoutDirection(d->activeSheet->layoutDirection()); // for scrolling 1373 d->horzScrollBar->setLayoutDirection(d->activeSheet->layoutDirection()); 1374 d->columnHeader->update(); 1375 // Replace the painting strategy for painting shapes. 1376 KoShapeManager *const shapeManager = d->canvas->shapeManager(); 1377 KoShapeManagerPaintingStrategy *paintingStrategy = 0; 1378 if (d->activeSheet->layoutDirection() == Qt::LeftToRight) { 1379 paintingStrategy = new KoShapeManagerPaintingStrategy(shapeManager); 1380 } else { 1381 paintingStrategy = new RightToLeftPaintingStrategy(shapeManager, d->canvas); 1382 } 1383 shapeManager->setPaintingStrategy(paintingStrategy); 1384 } 1385 if (formulaVisibilityChanged) { 1386 const bool showFormulas = d->activeSheet->getShowFormula(); 1387 stateChanged("show_formulas", showFormulas ? StateNoReverse : StateReverse); 1388 sheetView(d->activeSheet)->invalidate(); 1389 d->canvas->update(); 1390 } 1391 } 1392 1393 void View::insertSheet() 1394 { 1395 if (doc()->map()->isProtected()) { 1396 KMessageBox::error(0, i18n("You cannot change a protected sheet.")); 1397 return; 1398 } 1399 1400 selection()->emitCloseEditor(true); // save changes 1401 Sheet * t = doc()->map()->createSheet(); 1402 KUndo2Command* command = new AddSheetCommand(t); 1403 doc()->addCommand(command); 1404 setActiveSheet(t); 1405 1406 if (doc()->map()->visibleSheets().count() > 1) { 1407 d->actions->deleteSheet->setEnabled(true); 1408 d->actions->hideSheet->setEnabled(true); 1409 } 1410 } 1411 1412 void View::duplicateSheet() 1413 { 1414 if (doc()->map()->isProtected()) { 1415 KMessageBox::error(this, i18n("You cannot change a protected sheet.")); 1416 return; 1417 } 1418 1419 DuplicateSheetCommand* command = new DuplicateSheetCommand(); 1420 command->setSheet(activeSheet()); 1421 doc()->addCommand(command); 1422 1423 if (doc()->map()->visibleSheets().count() > 1) { 1424 d->actions->deleteSheet->setEnabled(true); 1425 d->actions->hideSheet->setEnabled(true); 1426 } 1427 } 1428 1429 void View::hideSheet() 1430 { 1431 if (!d->activeSheet) 1432 return; 1433 1434 if (doc()->map()->visibleSheets().count() == 1) { 1435 KMessageBox::error(this, i18n("You cannot hide the last visible sheet.")); 1436 return; 1437 } 1438 1439 QStringList vs = doc()->map()->visibleSheets(); 1440 int i = vs.indexOf(d->activeSheet->sheetName()) - 1; 1441 if (i < 0) i = 1; 1442 QString sn = vs[i]; 1443 1444 KUndo2Command* command = new HideSheetCommand(activeSheet()); 1445 doc()->addCommand(command); 1446 1447 d->tabBar->removeTab(d->activeSheet->sheetName()); 1448 d->tabBar->setActiveTab(sn); 1449 } 1450 1451 void View::showSheet() 1452 { 1453 if (!d->activeSheet) 1454 return; 1455 1456 ShowDialog dialog(this, d->selection); 1457 dialog.exec(); 1458 } 1459 1460 void View::copyAsText() 1461 { 1462 if (!d->activeSheet) 1463 return; 1464 QMimeData* mimeData = new QMimeData(); 1465 mimeData->setText(CopyCommand::saveAsPlainText(*selection())); 1466 1467 QApplication::clipboard()->setMimeData(mimeData); 1468 } 1469 1470 1471 void View::setShapeAnchoring(const QString& mode) 1472 { 1473 const KoSelection* selection = d->canvas->shapeManager()->selection(); 1474 const QList<KoShape*> shapes = selection->selectedShapes(KoFlake::StrippedSelection); 1475 for (int i = 0; i < shapes.count(); ++i) { 1476 const KoShape* shape = shapes[i]; 1477 ShapeApplicationData* data = dynamic_cast<ShapeApplicationData*>(shape->applicationData()); 1478 Q_ASSERT(data); 1479 data->setAnchoredToCell(mode == i18n("Cell")); 1480 } 1481 } 1482 1483 void View::toggleProtectDoc(bool mode) 1484 { 1485 if (!doc() || !doc()->map()) 1486 return; 1487 1488 bool success; 1489 if (mode) { 1490 success = doc()->map()->showPasswordDialog(this, ProtectableObject::Lock, 1491 i18n("Protect Document")); 1492 } else { 1493 success = doc()->map()->showPasswordDialog(this, ProtectableObject::Unlock, 1494 i18n("Unprotect Document")); 1495 } 1496 if (!success) { 1497 d->actions->protectDoc->setChecked(!mode); 1498 return; 1499 } 1500 1501 doc()->setModified(true); 1502 stateChanged("map_is_protected", mode ? StateNoReverse : StateReverse); 1503 d->tabBar->setReadOnly(doc()->map()->isProtected()); 1504 } 1505 1506 void View::toggleProtectSheet(bool mode) 1507 { 1508 if (!d->activeSheet) 1509 return; 1510 1511 bool success; 1512 if (mode) { 1513 success = activeSheet()->showPasswordDialog(this, ProtectableObject::Lock, 1514 i18n("Protect Sheet")); 1515 } else { 1516 success = activeSheet()->showPasswordDialog(this, ProtectableObject::Unlock, 1517 i18n("Unprotect Sheet")); 1518 } 1519 if (!success) { 1520 d->actions->protectSheet->setChecked(!mode); 1521 return; 1522 } 1523 1524 doc()->setModified(true); 1525 d->adjustActions(!mode); 1526 1527 // The sheet protection change may hide/unhide some values or formulas, 1528 // so the cached visual data has become invalid. 1529 refreshSheetViews(); 1530 d->canvas->update(); 1531 1532 // inform the cell tool 1533 emit sheetProtectionToggled(mode); 1534 } 1535 1536 void View::togglePageOutline(bool mode) 1537 { 1538 if (!d->activeSheet) 1539 return; 1540 1541 d->activeSheet->setShowPageOutline(mode); 1542 } 1543 1544 void View::viewZoom(KoZoomMode::Mode mode, qreal zoom) 1545 { 1546 Q_UNUSED(zoom) 1547 #ifdef NDEBUG 1548 Q_UNUSED(mode); 1549 #endif 1550 Q_ASSERT(mode == KoZoomMode::ZOOM_CONSTANT); 1551 selection()->emitCloseEditor(true); // save changes 1552 setHeaderMinima(); 1553 d->canvas->update(); 1554 d->columnHeader->update(); 1555 d->rowHeader->update(); 1556 d->selectAllButton->update(); 1557 } 1558 1559 void View::showColumnHeader(bool enable) 1560 { 1561 doc()->map()->settings()->setShowColumnHeader(enable); 1562 d->columnHeader->setVisible(enable); 1563 d->selectAllButton->setVisible(enable && d->rowHeader->isVisible()); 1564 } 1565 1566 void View::showRowHeader(bool enable) 1567 { 1568 doc()->map()->settings()->setShowRowHeader(enable); 1569 d->rowHeader->setVisible(enable); 1570 d->selectAllButton->setVisible(enable && d->columnHeader->isVisible()); 1571 } 1572 1573 void View::showHorizontalScrollBar(bool enable) 1574 { 1575 doc()->map()->settings()->setShowHorizontalScrollBar(enable); 1576 d->horzScrollBar->setVisible(enable); 1577 } 1578 1579 void View::showVerticalScrollBar(bool enable) 1580 { 1581 doc()->map()->settings()->setShowVerticalScrollBar(enable); 1582 d->vertScrollBar->setVisible(enable); 1583 } 1584 1585 void View::showStatusBar(bool enable) 1586 { 1587 doc()->map()->settings()->setShowStatusBar(enable); 1588 if (statusBar()) { 1589 statusBar()->setVisible(enable); 1590 } 1591 } 1592 1593 void View::showTabBar(bool enable) 1594 { 1595 doc()->map()->settings()->setShowTabBar(enable); 1596 d->tabBar->setVisible(enable); 1597 } 1598 1599 void View::optionsNotifications() 1600 { 1601 #ifndef QT_NO_DBUS 1602 KNotifyConfigWidget::configure(this); 1603 #endif 1604 } 1605 1606 void View::preference() 1607 { 1608 PreferenceDialog dialog(this); 1609 dialog.exec(); 1610 } 1611 1612 void View::nextSheet() 1613 { 1614 Sheet * t = doc()->map()->nextSheet(activeSheet()); 1615 if (!t) { 1616 debugSheets << "Unknown sheet"; 1617 return; 1618 } 1619 selection()->emitCloseEditor(true); // save changes 1620 setActiveSheet(t); 1621 d->tabBar->setActiveTab(t->sheetName()); 1622 d->tabBar->ensureVisible(t->sheetName()); 1623 } 1624 1625 void View::previousSheet() 1626 { 1627 Sheet * t = doc()->map()->previousSheet(activeSheet()); 1628 if (!t) { 1629 debugSheets << "Unknown sheet"; 1630 return; 1631 } 1632 selection()->emitCloseEditor(true); // save changes 1633 setActiveSheet(t); 1634 d->tabBar->setActiveTab(t->sheetName()); 1635 d->tabBar->ensureVisible(t->sheetName()); 1636 } 1637 1638 void View::firstSheet() 1639 { 1640 Sheet *t = doc()->map()->sheet(0); 1641 if (!t) { 1642 debugSheets << "Unknown sheet"; 1643 return; 1644 } 1645 selection()->emitCloseEditor(true); // save changes 1646 setActiveSheet(t); 1647 d->tabBar->setActiveTab(t->sheetName()); 1648 d->tabBar->ensureVisible(t->sheetName()); 1649 } 1650 1651 void View::lastSheet() 1652 { 1653 Sheet *t = doc()->map()->sheet(doc()->map()->count() - 1); 1654 if (!t) { 1655 debugSheets << "Unknown sheet"; 1656 return; 1657 } 1658 selection()->emitCloseEditor(true); // save changes 1659 setActiveSheet(t); 1660 d->tabBar->setActiveTab(t->sheetName()); 1661 d->tabBar->ensureVisible(t->sheetName()); 1662 } 1663 1664 void View::keyPressEvent(QKeyEvent *event) 1665 { 1666 #ifndef NDEBUG 1667 if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::ShiftModifier)) { 1668 if (event->key() == Qt::Key_V) { // Ctrl+Shift+V to show debug (similar to Words) 1669 d->activeSheet->printDebug(); 1670 } 1671 } 1672 #endif 1673 QWidget::keyPressEvent(event); 1674 } 1675 1676 int View::leftBorder() const 1677 { 1678 return (int)(((RowHeader*)d->rowHeader)->width()); 1679 } 1680 1681 int View::rightBorder() const 1682 { 1683 return d->vertScrollBar->width(); 1684 } 1685 1686 int View::topBorder() const 1687 { 1688 return (int)(((ColumnHeader*)d->columnHeader)->height()); 1689 } 1690 1691 int View::bottomBorder() const 1692 { 1693 return d->horzScrollBar->height(); 1694 } 1695 1696 void View::setHeaderMinima() 1697 { 1698 if (d->loading) // "View Loading" not finished yet 1699 return; 1700 QFont font(KoGlobal::defaultFont()); 1701 QFontMetricsF fm(font, 0); 1702 qreal h = fm.height() + 3; 1703 qreal w = fm.width(QString::fromLatin1("99999")) + 3; 1704 d->columnHeader->setMinimumHeight(qRound(h)); 1705 d->rowHeader->setMinimumWidth(qRound(w)); 1706 d->selectAllButton->setMinimumHeight(qRound(h)); 1707 d->selectAllButton->setMinimumWidth(qRound(w)); 1708 } 1709 1710 void View::paperLayoutDlg() 1711 { 1712 selection()->emitCloseEditor(true); // save changes 1713 SheetPrint* print = d->activeSheet->print(); 1714 1715 KoPageLayout pl = print->settings()->pageLayout(); 1716 1717 1718 /* 1719 const HeaderFooter *const headerFooter = print->headerFooter(); 1720 HeadFoot hf; 1721 hf.headLeft = headerFooter->localizeHeadFootLine(headerFooter->headLeft()); 1722 hf.headRight = headerFooter->localizeHeadFootLine(headerFooter->headRight()); 1723 hf.headMid = headerFooter->localizeHeadFootLine(headerFooter->headMid()); 1724 hf.footLeft = headerFooter->localizeHeadFootLine(headerFooter->footLeft()); 1725 hf.footRight = headerFooter->localizeHeadFootLine(headerFooter->footRight()); 1726 hf.footMid = headerFooter->localizeHeadFootLine(headerFooter->footMid()); 1727 */ 1728 PageLayoutDialog dialog(this, d->activeSheet); 1729 dialog.exec(); 1730 } 1731 1732 void View::resetPrintRange() 1733 { 1734 DefinePrintRangeCommand* command = new DefinePrintRangeCommand(); 1735 command->setText(kundo2_i18n("Reset Print Range")); 1736 command->setSheet(activeSheet()); 1737 command->add(Region(QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax)), activeSheet())); 1738 doc()->addCommand(command); 1739 } 1740 1741 void View::deleteSheet() 1742 { 1743 if (doc()->map()->count() <= 1 || (doc()->map()->visibleSheets().count() <= 1)) { 1744 KMessageBox::sorry(this, i18n("You cannot delete the only sheet."), i18n("Remove Sheet")); 1745 return; 1746 } 1747 int ret = KMessageBox::warningContinueCancel(this, i18n("You are about to remove the active sheet.\nDo you want to continue?"), 1748 i18n("Remove Sheet"), KStandardGuiItem::del()); 1749 1750 if (ret == KMessageBox::Continue) { 1751 selection()->emitCloseEditor(false); // discard changes 1752 doc()->setModified(true); 1753 Sheet * tbl = activeSheet(); 1754 KUndo2Command* command = new RemoveSheetCommand(tbl); 1755 doc()->addCommand(command); 1756 } 1757 } 1758 1759 1760 void View::slotRename() 1761 { 1762 1763 Sheet * sheet = activeSheet(); 1764 1765 if (sheet->isProtected()) { 1766 KMessageBox::error(0, i18n("You cannot change a protected sheet.")); 1767 return; 1768 } 1769 1770 bool ok; 1771 QString activeName = sheet->sheetName(); 1772 QString newName = QInputDialog::getText(this, i18n("Rename Sheet"), i18n("Enter name:"), QLineEdit::Normal, activeName, &ok); 1773 1774 if (!ok) return; 1775 1776 if ((newName.trimmed()).isEmpty()) { // Sheet name is empty. 1777 KMessageBox::information(this, i18n("Sheet name cannot be empty."), i18n("Change Sheet Name")); 1778 // Recursion 1779 slotRename(); 1780 } else if (newName != activeName) { // Sheet name changed. 1781 // Is the name already used 1782 if (doc()->map()->findSheet(newName)) { 1783 KMessageBox::information(this, i18n("This name is already used."), i18n("Change Sheet Name")); 1784 // Recursion 1785 slotRename(); 1786 return; 1787 } 1788 1789 KUndo2Command* command = new RenameSheetCommand(sheet, newName); 1790 doc()->addCommand(command); 1791 1792 doc()->setModified(true); 1793 } 1794 } 1795 1796 //------------------------------------------------ 1797 // 1798 // Document signals 1799 // 1800 //------------------------------------------------ 1801 1802 void View::slotChangeSelection(const Calligra::Sheets::Region& changedRegion) 1803 { 1804 if (!changedRegion.isValid()) 1805 return; 1806 1807 if (d->selection->referenceSelectionMode()) { 1808 doc()->map()->addDamage(new SelectionDamage(changedRegion)); 1809 debugSheetsFormula << "Choice:" << *selection(); 1810 return; 1811 } 1812 1813 // delayed recalculation of the operation shown in the status bar 1814 d->statusBarOpTimer.setSingleShot(true); 1815 d->statusBarOpTimer.start(250); 1816 1817 if (!d->loading && !doc()->map()->isLoading()) { 1818 doc()->map()->addDamage(new SelectionDamage(changedRegion)); 1819 } 1820 d->rowHeader->update(); 1821 d->columnHeader->update(); 1822 d->selectAllButton->update(); 1823 1824 if (d->selection->isColumnSelected() || d->selection->isRowSelected()) { 1825 return; 1826 } 1827 1828 d->canvas->validateSelection(); 1829 } 1830 1831 void View::slotScrollChoice(const Calligra::Sheets::Region& changedRegion) 1832 { 1833 if (!selection()->referenceSelectionMode() || !changedRegion.isValid()) { 1834 return; 1835 } 1836 } 1837 1838 void View::calcStatusBarOp() 1839 { 1840 Sheet * sheet = activeSheet(); 1841 ValueCalc* calc = doc()->map()->calc(); 1842 Value val; 1843 QString prefix = ""; 1844 1845 MethodOfCalc tmpMethod = doc()->map()->settings()->getTypeOfCalc(); 1846 if (sheet && tmpMethod != NoneCalc) { 1847 Value range = sheet->cellStorage()->valueRegion(*d->selection); 1848 switch (tmpMethod) { 1849 case SumOfNumber: 1850 val = calc->sum(range); 1851 prefix = i18n("Sum: "); 1852 break; 1853 case Average: 1854 val = calc->avg(range); 1855 prefix = i18n("Average: "); 1856 break; 1857 case Min: 1858 val = calc->min(range); 1859 prefix = i18n("Min: "); 1860 break; 1861 case Max: 1862 val = calc->max(range); 1863 prefix = i18n("Max: "); 1864 break; 1865 case CountA: 1866 val = Value(calc->count(range)); 1867 prefix = i18n("Count: "); 1868 break; 1869 case Count: 1870 val = Value(calc->count(range, false)); 1871 prefix = i18n("CountA: "); 1872 case NoneCalc: 1873 break; 1874 default: 1875 break; 1876 } 1877 if ((range.columns() > 1) || (range.rows() > 1)) { 1878 QString size = i18n("%1x%2", range.columns(), range.rows()); 1879 prefix = prefix.size() ? size + ", " + prefix : size; 1880 } 1881 } 1882 1883 QString res = doc()->map()->converter()->asString(val).asString(); 1884 QString tmp; 1885 if (res.length()) tmp = prefix + res; 1886 1887 if (d->calcLabel) 1888 d->calcLabel->setText(QString(' ') + tmp + ' '); 1889 } 1890 1891 void View::statusBarClicked(const QPoint&) 1892 { 1893 QPoint mousepos = QCursor::pos(); 1894 if (factory()) 1895 if (QMenu* menu = dynamic_cast<QMenu*>(factory()->container("calc_popup" , this))) 1896 menu->popup(mousepos); 1897 } 1898 1899 void View::menuCalc(bool) 1900 { 1901 if (d->actions->calcMin->isChecked()) { 1902 doc()->map()->settings()->setTypeOfCalc(Min); 1903 } else if (d->actions->calcMax->isChecked()) { 1904 doc()->map()->settings()->setTypeOfCalc(Max); 1905 } else if (d->actions->calcCount->isChecked()) { 1906 doc()->map()->settings()->setTypeOfCalc(Count); 1907 } else if (d->actions->calcAverage->isChecked()) { 1908 doc()->map()->settings()->setTypeOfCalc(Average); 1909 } else if (d->actions->calcSum->isChecked()) { 1910 doc()->map()->settings()->setTypeOfCalc(SumOfNumber); 1911 } else if (d->actions->calcCountA->isChecked()) { 1912 doc()->map()->settings()->setTypeOfCalc(CountA); 1913 } else if (d->actions->calcNone->isChecked()) 1914 doc()->map()->settings()->setTypeOfCalc(NoneCalc); 1915 1916 calcStatusBarOp(); 1917 } 1918 1919 QWidget* View::canvas() const 1920 { 1921 return d->canvas; 1922 } 1923 1924 void View::popupTabBarMenu(const QPoint & _point) 1925 { 1926 if (!factory()) 1927 return; 1928 if (d->tabBar) { 1929 QMenu* const menu = static_cast<QMenu*>(factory()->container("menupage_popup", this)); 1930 if (!menu) 1931 return; 1932 1933 QAction* insertSheet = new QAction(koIcon("insert-table"), i18n("Insert Sheet"), this); 1934 insertSheet->setToolTip(i18n("Remove the active sheet")); 1935 connect(insertSheet, SIGNAL(triggered(bool)), this, SLOT(insertSheet())); 1936 menu->insertAction(d->actions->duplicateSheet, insertSheet); 1937 1938 QAction* deleteSheet = new QAction(koIcon("delete_table"), i18n("Remove Sheet"), this); 1939 deleteSheet->setToolTip(i18n("Remove the active sheet")); 1940 connect(deleteSheet, SIGNAL(triggered(bool)), this, SLOT(deleteSheet())); 1941 menu->insertAction(d->actions->hideSheet, deleteSheet); 1942 1943 bool state = (doc()->map()->visibleSheets().count() > 1); 1944 if (d->activeSheet && d->activeSheet->isProtected()) { 1945 deleteSheet->setEnabled(false); 1946 d->actions->hideSheet->setEnabled(false); 1947 d->actions->showSheet->setEnabled(false); 1948 } else { 1949 deleteSheet->setEnabled(state); 1950 d->actions->hideSheet->setEnabled(state); 1951 d->actions->showSheet->setEnabled(doc()->map()->hiddenSheets().count() > 0); 1952 } 1953 if (!doc() || !doc()->map() || doc()->map()->isProtected()) { 1954 insertSheet->setEnabled(false); 1955 deleteSheet->setEnabled(false); 1956 d->actions->renameSheet->setEnabled(false); 1957 d->actions->showSheet->setEnabled(false); 1958 d->actions->hideSheet->setEnabled(false); 1959 } 1960 menu->exec(_point); 1961 menu->removeAction(insertSheet); 1962 menu->removeAction(deleteSheet); 1963 delete insertSheet; 1964 delete deleteSheet; 1965 } 1966 } 1967 1968 void View::updateBorderButton() 1969 { 1970 if (d->activeSheet) 1971 d->actions->showPageOutline->setChecked(d->activeSheet->isShowPageOutline()); 1972 } 1973 1974 void View::addSheet(Sheet *sheet) 1975 { 1976 if (!sheet->isHidden()) { 1977 d->tabBar->addTab(sheet->sheetName()); 1978 } 1979 const bool state = (doc()->map()->visibleSheets().count() > 1); 1980 d->actions->deleteSheet->setEnabled(state); 1981 d->actions->hideSheet->setEnabled(state); 1982 1983 // Connect some signals 1984 connect(sheet, SIGNAL(shapeAdded(Sheet*,KoShape*)), 1985 d->mapViewModel, SLOT(addShape(Sheet*,KoShape*))); 1986 connect(sheet, SIGNAL(shapeRemoved(Sheet*,KoShape*)), 1987 d->mapViewModel, SLOT(removeShape(Sheet*,KoShape*))); 1988 } 1989 1990 void View::removeSheet(Sheet *sheet) 1991 { 1992 d->tabBar->removeTab(sheet->sheetName()); 1993 setActiveSheet(doc()->map()->sheet(0)); 1994 1995 const bool state = (doc()->map()->visibleSheets().count() > 1); 1996 d->actions->deleteSheet->setEnabled(state); 1997 d->actions->hideSheet->setEnabled(state); 1998 1999 // Disconnect signals. 2000 disconnect(sheet, 0, d->mapViewModel, 0); 2001 } 2002 2003 QColor View::borderColor() const 2004 { 2005 return d->canvas->resourceManager()->foregroundColor().toQColor(); 2006 } 2007 2008 void View::updateShowSheetMenu() 2009 { 2010 if (d->activeSheet) { 2011 if (d->activeSheet->map()->isProtected()) 2012 d->actions->showSheet->setEnabled(false); 2013 else 2014 d->actions->showSheet->setEnabled(doc()->map()->hiddenSheets().count() > 0); 2015 } 2016 } 2017 2018 QPoint View::markerFromSheet(Sheet* sheet) const 2019 { 2020 QMap<Sheet*, QPoint>::ConstIterator it = d->savedMarkers.constFind(sheet); 2021 QPoint newMarker = (it == d->savedMarkers.constEnd()) ? QPoint(1, 1) : *it; 2022 return newMarker; 2023 } 2024 2025 QPointF View::offsetFromSheet(Sheet* sheet) const 2026 { 2027 QMap<Sheet*, QPointF>::ConstIterator it = d->savedOffsets.constFind(sheet); 2028 QPointF offset = (it == d->savedOffsets.constEnd()) ? QPointF() : *it; 2029 return offset; 2030 } 2031 2032 void View::saveCurrentSheetSelection() 2033 { 2034 /* save the current selection on this sheet */ 2035 if (d->activeSheet != 0) { 2036 d->savedAnchors.remove(d->activeSheet); 2037 d->savedAnchors.insert(d->activeSheet, d->selection->anchor()); 2038 debugSheetsUI << " Current scrollbar vert value:" << d->vertScrollBar->value(); 2039 debugSheetsUI << "Saving marker pos:" << d->selection->marker(); 2040 d->savedMarkers.remove(d->activeSheet); 2041 d->savedMarkers.insert(d->activeSheet, d->selection->marker()); 2042 d->savedOffsets.remove(d->activeSheet); 2043 d->savedOffsets.insert(d->activeSheet, QPointF(d->canvas->xOffset(), 2044 d->canvas->yOffset())); 2045 } 2046 } 2047 2048 void View::handleDamages(const QList<Damage*>& damages) 2049 { 2050 QRegion paintRegion; 2051 enum { Nothing, Everything, Clipped } paintMode = Nothing; 2052 2053 QList<Damage*>::ConstIterator end(damages.end()); 2054 for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) { 2055 Damage* damage = *it; 2056 if (!damage) continue; 2057 2058 if (damage->type() == Damage::Cell) { 2059 CellDamage* cellDamage = static_cast<CellDamage*>(damage); 2060 debugSheetsDamage << "Processing\t" << *cellDamage; 2061 Sheet* const damagedSheet = cellDamage->sheet(); 2062 2063 if (cellDamage->changes() & CellDamage::Appearance) { 2064 const Region& region = cellDamage->region(); 2065 sheetView(damagedSheet)->invalidateRegion(region); 2066 paintMode = Everything; 2067 } 2068 continue; 2069 } 2070 2071 if (damage->type() == Damage::Sheet) { 2072 SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage); 2073 debugSheetsDamage << *sheetDamage; 2074 const SheetDamage::Changes changes = sheetDamage->changes(); 2075 if (changes & (SheetDamage::Name | SheetDamage::Shown)) { 2076 d->tabBar->setTabs(doc()->map()->visibleSheets()); 2077 paintMode = Everything; 2078 } 2079 if (changes & (SheetDamage::Shown | SheetDamage::Hidden)) { 2080 updateShowSheetMenu(); 2081 paintMode = Everything; 2082 } 2083 // The following changes only affect the active sheet. 2084 if (sheetDamage->sheet() != d->activeSheet) { 2085 continue; 2086 } 2087 if (changes.testFlag(SheetDamage::ContentChanged)) { 2088 update(); 2089 paintMode = Everything; 2090 } 2091 if (changes.testFlag(SheetDamage::PropertiesChanged)) { 2092 sheetView(d->activeSheet)->invalidate(); 2093 paintMode = Everything; 2094 } 2095 if (sheetDamage->changes() & SheetDamage::ColumnsChanged) 2096 columnHeader()->update(); 2097 if (sheetDamage->changes() & SheetDamage::RowsChanged) 2098 rowHeader()->update(); 2099 continue; 2100 } 2101 2102 if (damage->type() == Damage::Selection) { 2103 SelectionDamage* selectionDamage = static_cast<SelectionDamage*>(damage); 2104 debugSheetsDamage << "Processing\t" << *selectionDamage; 2105 const Region region = selectionDamage->region(); 2106 2107 if (paintMode == Clipped) { 2108 const QRectF rect = canvasWidget()->cellCoordinatesToView(region.boundingRect()); 2109 paintRegion += rect.toRect().adjusted(-3, -3, 4, 4); 2110 } else { 2111 paintMode = Everything; 2112 } 2113 continue; 2114 } 2115 2116 debugSheetsDamage << "Unhandled\t" << *damage; 2117 } 2118 2119 // At last repaint the dirty cells. 2120 if (paintMode == Clipped) { 2121 canvas()->update(paintRegion); 2122 } else if (paintMode == Everything) { 2123 canvas()->update(); 2124 } 2125 } 2126 2127 KoPrintJob * View::createPrintJob() 2128 { 2129 if (!activeSheet()) 2130 return 0; 2131 // About to print; close the editor. 2132 selection()->emitCloseEditor(true); // save changes 2133 return new PrintJob(this); 2134 } 2135 2136 void View::updateAccessedCellRange(Sheet* sheet, const QPoint &location) 2137 { 2138 sheetView(sheet)->updateAccessedCellRange(location); 2139 } 2140 2141 void View::enableAutoScroll() 2142 { 2143 d->scrollTimer->start(50); 2144 } 2145 2146 void View::disableAutoScroll() 2147 { 2148 d->scrollTimer->stop(); 2149 } 2150 2151 int View::autoScrollAcceleration(int offset) const 2152 { 2153 if (offset < 40) 2154 return offset; 2155 else 2156 return offset*offset / 40; 2157 } 2158 2159 void View::slotAutoScroll() 2160 { 2161 QPoint scrollDistance; 2162 bool actuallyDoScroll = false; 2163 QPoint pos(mapFromGlobal(QCursor::pos())); 2164 2165 //Provide progressive scrolling depending on the mouse position 2166 if (pos.y() < topBorder()) { 2167 scrollDistance.setY((int) - autoScrollAcceleration(- pos.y() + topBorder())); 2168 actuallyDoScroll = true; 2169 } else if (pos.y() > height() - bottomBorder()) { 2170 scrollDistance.setY((int) autoScrollAcceleration(pos.y() - height() + bottomBorder())); 2171 actuallyDoScroll = true; 2172 } 2173 2174 if (pos.x() < leftBorder()) { 2175 scrollDistance.setX((int) - autoScrollAcceleration(- pos.x() + leftBorder())); 2176 actuallyDoScroll = true; 2177 } else if (pos.x() > width() - rightBorder()) { 2178 scrollDistance.setX((int) autoScrollAcceleration(pos.x() - width() + rightBorder())); 2179 actuallyDoScroll = true; 2180 } 2181 2182 if (actuallyDoScroll) { 2183 pos = canvas()->mapFrom(this, pos); 2184 QMouseEvent* event = new QMouseEvent(QEvent::MouseMove, pos, Qt::NoButton, Qt::NoButton, 2185 QApplication::keyboardModifiers()); 2186 2187 QApplication::postEvent(canvas(), event); 2188 emit autoScroll(scrollDistance); 2189 } 2190 }