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 }