Warning, file /office/calligra/libs/main/KoMainWindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
0003    Copyright (C) 2000-2006 David Faure <faure@kde.org>
0004    Copyright (C) 2007, 2009 Thomas zander <zander@kde.org>
0005    Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "KoMainWindow.h"
0024 
0025 #include "KoView.h"
0026 #include "KoDocument.h"
0027 #include "KoFilterManager.h"
0028 #include "KoDocumentInfo.h"
0029 #include "KoDocumentInfoDlg.h"
0030 #include "KoFileDialog.h"
0031 #include "KoVersionDialog.h"
0032 #include "KoDockFactoryBase.h"
0033 #include "KoDockWidgetTitleBar.h"
0034 #include "KoPrintJob.h"
0035 #include "KoDocumentEntry.h"
0036 #include "KoDockerManager.h"
0037 #include "KoPart.h"
0038 #include <KoPageLayoutDialog.h>
0039 #include <KoPageLayout.h>
0040 #include "KoApplication.h"
0041 #include <KoIcon.h>
0042 #include "KoResourcePaths.h"
0043 #include "KoComponentData.h"
0044 #include <KoConfig.h>
0045 #include <KoDockRegistry.h>
0046 #include "calligraversion.h"
0047 
0048 #include <krecentdirs.h>
0049 #include <khelpmenu.h>
0050 #include <krecentfilesaction.h>
0051 #include <kaboutdata.h>
0052 #include <ktoggleaction.h>
0053 #include <kmessagebox.h>
0054 #include <KoNetAccess.h>
0055 #include <kedittoolbar.h>
0056 #include <QTemporaryFile>
0057 #include <krecentdocument.h>
0058 #include <klocalizedstring.h>
0059 #include <ktoolinvocation.h>
0060 #include <kxmlguifactory.h>
0061 #include <kfileitem.h>
0062 #include <ktoolbar.h>
0063 #include <kactionmenu.h>
0064 #include <kactioncollection.h>
0065 #include <KWindowConfig>
0066 
0067 #ifdef HAVE_KACTIVITIES
0068 #include <KActivities/ResourceInstance>
0069 #endif
0070 
0071 //   // qt includes
0072 #include <QDockWidget>
0073 #include <QApplication>
0074 #include <QLayout>
0075 #include <QLabel>
0076 #include <QProgressBar>
0077 #include <QTabBar>
0078 #include <QPrinter>
0079 #include <QPrintDialog>
0080 #include <QDesktopWidget>
0081 #include <QPrintPreviewDialog>
0082 #include <QCloseEvent>
0083 #include <QPointer>
0084 #include <QByteArray>
0085 #include <QMutex>
0086 #include <QMutexLocker>
0087 #include <QFontDatabase>
0088 #include <QMimeDatabase>
0089 #include <QStatusBar>
0090 #include <QMenuBar>
0091 
0092 #include "MainDebug.h"
0093 
0094 class KoMainWindowPrivate
0095 {
0096 public:
0097     KoMainWindowPrivate(const QByteArray &_nativeMimeType, const KoComponentData &componentData_, KoMainWindow *w)
0098         : componentData(componentData_)
0099     {
0100         nativeMimeType = _nativeMimeType;
0101         parent = w;
0102         rootDocument = 0;
0103         rootPart = 0;
0104         partToOpen = 0;
0105         mainWindowGuiIsBuilt = false;
0106         forQuit = false;
0107         activePart = 0;
0108         activeView = 0;
0109         firstTime = true;
0110         progress = 0;
0111         showDocumentInfo = 0;
0112         saveAction = 0;
0113         saveActionAs = 0;
0114         printAction = 0;
0115         printActionPreview = 0;
0116         sendFileAction = 0;
0117         exportPdf = 0;
0118         closeFile = 0;
0119         reloadFile = 0;
0120         showFileVersions = 0;
0121         importFile = 0;
0122         exportFile = 0;
0123         encryptDocument = 0;
0124 #ifndef NDEBUG
0125         uncompressToDir = 0;
0126 #endif
0127         isImporting = false;
0128         isExporting = false;
0129         windowSizeDirty = false;
0130         lastExportSpecialOutputFlag = 0;
0131         readOnly = false;
0132         dockWidgetMenu = 0;
0133         dockerManager = 0;
0134         deferredClosingEvent = 0;
0135 #ifdef HAVE_KACTIVITIES
0136         activityResource = 0;
0137 #endif
0138 
0139         m_helpMenu = 0;
0140 
0141         // PartManger
0142         m_activeWidget = 0;
0143         m_activePart = 0;
0144 
0145         noCleanup = false;
0146         openingDocument = false;
0147     }
0148 
0149     ~KoMainWindowPrivate() {
0150         qDeleteAll(toolbarList);
0151     }
0152 
0153     void applyDefaultSettings(QPrinter &printer) {
0154         QString title = rootDocument->documentInfo()->aboutInfo("title");
0155         if (title.isEmpty()) {
0156             title = rootDocument->url().fileName();
0157             // strip off the native extension (I don't want foobar.kwd.ps when printing into a file)
0158             QMimeType mime = QMimeDatabase().mimeTypeForName(rootDocument->outputMimeType());
0159             if (mime.isValid()) {
0160                 const QString extension = mime.preferredSuffix();
0161 
0162                 if (title.endsWith(extension))
0163                     title.chop(extension.length());
0164             }
0165         }
0166 
0167         if (title.isEmpty()) {
0168             // #139905
0169             title = i18n("%1 unsaved document (%2)", parent->componentData().componentDisplayName(),
0170                          QLocale().toString(QDate::currentDate(), QLocale::ShortFormat));
0171         }
0172         printer.setDocName(title);
0173     }
0174 
0175     QByteArray nativeMimeType;
0176 
0177     KoMainWindow *parent;
0178     QPointer<KoDocument> rootDocument;
0179     QList<KoView*> rootViews;
0180 
0181     // PartManager
0182     QPointer<KoPart> rootPart;
0183     QPointer<KoPart> partToOpen;
0184     QPointer<KoPart> activePart;
0185     QPointer<KoPart> m_activePart;
0186     QPointer<KoPart> m_registeredPart;
0187 
0188     KoView *activeView;
0189     QWidget *m_activeWidget;
0190 
0191     QPointer<QProgressBar> progress;
0192     QMutex progressMutex;
0193 
0194     QList<QAction *> toolbarList;
0195 
0196     bool mainWindowGuiIsBuilt;
0197     bool forQuit;
0198     bool firstTime;
0199     bool windowSizeDirty;
0200     bool readOnly;
0201 
0202     QAction *showDocumentInfo;
0203     QAction *saveAction;
0204     QAction *saveActionAs;
0205     QAction *printAction;
0206     QAction *printActionPreview;
0207     QAction *sendFileAction;
0208     QAction *exportPdf;
0209     QAction *closeFile;
0210     QAction *reloadFile;
0211     QAction *showFileVersions;
0212     QAction *importFile;
0213     QAction *exportFile;
0214     QAction *encryptDocument;
0215 #ifndef NDEBUG
0216     QAction *uncompressToDir;
0217 #endif
0218     KToggleAction *toggleDockers;
0219     KToggleAction *toggleDockerTitleBars;
0220     KRecentFilesAction *recent;
0221 
0222     bool isImporting;
0223     bool isExporting;
0224 
0225     QUrl lastExportUrl;
0226     QByteArray lastExportedFormat;
0227     int lastExportSpecialOutputFlag;
0228 
0229     QMap<QString, QDockWidget *> dockWidgetsMap;
0230     KActionMenu *dockWidgetMenu;
0231     QMap<QDockWidget *, bool> dockWidgetVisibilityMap;
0232     KoDockerManager *dockerManager;
0233     QList<QDockWidget *> dockWidgets;
0234     QByteArray m_dockerStateBeforeHiding;
0235 
0236     QCloseEvent *deferredClosingEvent;
0237 
0238 #ifdef HAVE_KACTIVITIES
0239     KActivities::ResourceInstance *activityResource;
0240 #endif
0241 
0242     KoComponentData componentData;
0243 
0244     KHelpMenu *m_helpMenu;
0245 
0246     bool noCleanup;
0247     bool openingDocument;
0248 
0249 };
0250 
0251 KoMainWindow::KoMainWindow(const QByteArray &nativeMimeType, const KoComponentData &componentData)
0252     : KXmlGuiWindow()
0253     , d(new KoMainWindowPrivate(nativeMimeType, componentData, this))
0254 {
0255     setStandardToolBarMenuEnabled(true);
0256 
0257     setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
0258 
0259     connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts()));
0260 
0261     // PartManager
0262     // End
0263 
0264     QString doc;
0265     const QStringList allFiles = KoResourcePaths::findAllResources("data", "calligra/calligra_shell.rc");
0266     setXMLFile(findMostRecentXMLFile(allFiles, doc));
0267     setLocalXMLFile(KoResourcePaths::locateLocal("data", "calligra/calligra_shell.rc"));
0268 
0269     actionCollection()->addAction(KStandardAction::New, "file_new", this, SLOT(slotFileNew()));
0270     actionCollection()->addAction(KStandardAction::Open, "file_open", this, SLOT(slotFileOpen()));
0271     d->recent = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection());
0272     connect(d->recent, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles()));
0273     d->saveAction = actionCollection()->addAction(KStandardAction::Save,  "file_save", this, SLOT(slotFileSave()));
0274     d->saveActionAs = actionCollection()->addAction(KStandardAction::SaveAs,  "file_save_as", this, SLOT(slotFileSaveAs()));
0275     d->printAction = actionCollection()->addAction(KStandardAction::Print,  "file_print", this, SLOT(slotFilePrint()));
0276     d->printActionPreview = actionCollection()->addAction(KStandardAction::PrintPreview,  "file_print_preview", this, SLOT(slotFilePrintPreview()));
0277 
0278     d->exportPdf  = new QAction(i18n("Export as PDF..."), this);
0279     d->exportPdf->setIcon(koIcon("application-pdf"));
0280     actionCollection()->addAction("file_export_pdf", d->exportPdf);
0281     connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf()));
0282 
0283     d->sendFileAction = actionCollection()->addAction(KStandardAction::Mail,  "file_send_file", this, SLOT(slotEmailFile()));
0284 
0285     d->closeFile = actionCollection()->addAction(KStandardAction::Close,  "file_close", this, SLOT(slotFileClose()));
0286     actionCollection()->addAction(KStandardAction::Quit,  "file_quit", this, SLOT(slotFileQuit()));
0287 
0288     d->reloadFile  = new QAction(i18n("Reload"), this);
0289     actionCollection()->addAction("file_reload_file", d->reloadFile);
0290     connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile()));
0291 
0292     d->showFileVersions  = new QAction(i18n("Versions..."), this);
0293     actionCollection()->addAction("file_versions_file", d->showFileVersions);
0294     connect(d->showFileVersions, SIGNAL(triggered(bool)), this, SLOT(slotVersionsFile()));
0295 
0296     d->importFile  = new QAction(koIcon("document-import"), i18n("Open ex&isting Document as Untitled Document..."), this);
0297     actionCollection()->addAction("file_import_file", d->importFile);
0298     connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile()));
0299 
0300     d->exportFile  = new QAction(koIcon("document-export"), i18n("E&xport..."), this);
0301     actionCollection()->addAction("file_export_file", d->exportFile);
0302     connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile()));
0303 
0304     d->encryptDocument = new QAction(i18n("En&crypt Document"), this);
0305     actionCollection()->addAction("file_encrypt_doc", d->encryptDocument);
0306     connect(d->encryptDocument, SIGNAL(triggered(bool)), this, SLOT(slotEncryptDocument()));
0307 
0308 #ifndef NDEBUG
0309     d->uncompressToDir = new QAction(i18n("&Uncompress to Directory"), this);
0310     actionCollection()->addAction("file_uncompress_doc", d->uncompressToDir);
0311     connect(d->uncompressToDir, SIGNAL(triggered(bool)), this, SLOT(slotUncompressToDir()));
0312 #endif
0313 
0314     QAction *actionNewView  = new QAction(koIcon("window-new"), i18n("&New View"), this);
0315     actionCollection()->addAction("view_newview", actionNewView);
0316     connect(actionNewView, SIGNAL(triggered(bool)), this, SLOT(newView()));
0317 
0318     /* The following entry opens the document information dialog.  Since the action is named so it
0319         intends to show data this entry should not have a trailing ellipses (...).  */
0320     d->showDocumentInfo  = new QAction(koIcon("document-properties"), i18n("Document Information"), this);
0321     actionCollection()->addAction("file_documentinfo", d->showDocumentInfo);
0322     connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo()));
0323 
0324     KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
0325     KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbars()), actionCollection());
0326 
0327     d->showDocumentInfo->setEnabled(false);
0328     d->saveActionAs->setEnabled(false);
0329     d->reloadFile->setEnabled(false);
0330     d->showFileVersions->setEnabled(false);
0331     d->importFile->setEnabled(true);    // always enabled like File --> Open
0332     d->exportFile->setEnabled(false);
0333     d->saveAction->setEnabled(false);
0334     d->printAction->setEnabled(false);
0335     d->printActionPreview->setEnabled(false);
0336     d->sendFileAction->setEnabled(false);
0337     d->exportPdf->setEnabled(false);
0338     d->closeFile->setEnabled(false);
0339     d->encryptDocument->setEnabled(false);
0340 #ifndef NDEBUG
0341     d->uncompressToDir->setEnabled(false);
0342 #endif
0343 
0344     KToggleAction *fullscreenAction  = new KToggleAction(koIcon("view-fullscreen"), i18n("Full Screen Mode"), this);
0345     actionCollection()->addAction("view_fullscreen", fullscreenAction);
0346     actionCollection()->setDefaultShortcut(fullscreenAction, QKeySequence::FullScreen);
0347     connect(fullscreenAction, SIGNAL(toggled(bool)), this, SLOT(viewFullscreen(bool)));
0348 
0349     d->toggleDockers = new KToggleAction(i18n("Show Dockers"), this);
0350     d->toggleDockers->setChecked(true);
0351     actionCollection()->addAction("view_toggledockers", d->toggleDockers);
0352     connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool)));
0353 
0354     d->toggleDockerTitleBars = new KToggleAction(i18nc("@action:inmenu", "Show Docker Titlebars"), this);
0355     KConfigGroup configGroupInterface =  KSharedConfig::openConfig()->group("Interface");
0356     d->toggleDockerTitleBars->setChecked(configGroupInterface.readEntry("ShowDockerTitleBars", true));
0357     d->toggleDockerTitleBars->setVisible(false);
0358     actionCollection()->addAction("view_toggledockertitlebars", d->toggleDockerTitleBars);
0359     connect(d->toggleDockerTitleBars, SIGNAL(toggled(bool)), SLOT(showDockerTitleBars(bool)));
0360 
0361     d->dockWidgetMenu  = new KActionMenu(i18n("Dockers"), this);
0362     actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu);
0363     d->dockWidgetMenu->setVisible(false);
0364     d->dockWidgetMenu->setDelayed(false);
0365 
0366     // Load list of recent files
0367     KSharedConfigPtr configPtr = componentData.config();
0368     d->recent->loadEntries(configPtr->group("RecentFiles"));
0369 
0370 
0371     createMainwindowGUI();
0372     d->mainWindowGuiIsBuilt = true;
0373 
0374     // we first figure out some good default size and restore the x,y position. See bug 285804Z.
0375     KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow");
0376     QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray()));
0377     if (!restoreGeometry(geom)) {
0378         const int scnum = QApplication::desktop()->screenNumber(parentWidget());
0379         QRect desk = QApplication::desktop()->availableGeometry(scnum);
0380         // if the desktop is virtual then use virtual screen size
0381         if (QApplication::desktop()->isVirtualDesktop()) {
0382             desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen());
0383             desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum));
0384         }
0385 
0386         quint32 x = desk.x();
0387         quint32 y = desk.y();
0388         quint32 w = 0;
0389         quint32 h = 0;
0390 
0391         // Default size -- maximize on small screens, something useful on big screens
0392         const int deskWidth = desk.width();
0393         if (deskWidth > 1024) {
0394             // a nice width, and slightly less than total available
0395             // height to componensate for the window decs
0396             w = (deskWidth / 3) * 2;
0397             h = (desk.height() / 3) * 2;
0398         }
0399         else {
0400             w = desk.width();
0401             h = desk.height();
0402         }
0403 
0404         x += (desk.width() - w) / 2;
0405         y += (desk.height() - h) / 2;
0406 
0407         move(x,y);
0408         setGeometry(geometry().x(), geometry().y(), w, h);
0409     }
0410     restoreState(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray())));
0411 
0412     d->dockerManager = new KoDockerManager(this);
0413 }
0414 
0415 void KoMainWindow::setNoCleanup(bool noCleanup)
0416 {
0417     d->noCleanup = noCleanup;
0418 }
0419 
0420 KoMainWindow::~KoMainWindow()
0421 {
0422     KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow");
0423     cfg.writeEntry("ko_geometry", saveGeometry().toBase64());
0424     cfg.writeEntry("ko_windowstate", saveState().toBase64());
0425 
0426     // Explicitly delete the docker manager to ensure that it is deleted before the dockers
0427     delete d->dockerManager;
0428     d->dockerManager = 0;
0429 
0430     // The doc and view might still exist (this is the case when closing the window)
0431     if (d->rootPart)
0432         d->rootPart->removeMainWindow(this);
0433 
0434     if (d->partToOpen) {
0435         d->partToOpen->removeMainWindow(this);
0436         delete d->partToOpen;
0437     }
0438 
0439     // safety first ;)
0440     setActivePart(0, 0);
0441 
0442     if (d->rootViews.indexOf(d->activeView) == -1) {
0443         delete d->activeView;
0444         d->activeView = 0;
0445     }
0446     while (!d->rootViews.isEmpty()) {
0447         delete d->rootViews.takeFirst();
0448     }
0449 
0450     if(d->noCleanup)
0451         return;
0452     // We have to check if this was a root document.
0453     // This has to be checked from queryClose, too :)
0454     if (d->rootPart && d->rootPart->viewCount() == 0) {
0455         //debugMain <<"Destructor. No more views, deleting old doc" << d->rootDoc;
0456         delete d->rootDocument;
0457     }
0458 
0459     delete d;
0460 }
0461 
0462 void KoMainWindow::setRootDocument(KoDocument *doc, KoPart *part, bool deletePrevious)
0463 {
0464     if (d->rootDocument == doc)
0465         return;
0466 
0467     if (d->partToOpen && d->partToOpen->document() != doc) {
0468         d->partToOpen->removeMainWindow(this);
0469         if (deletePrevious) delete d->partToOpen;
0470     }
0471     d->partToOpen = 0;
0472 
0473     //debugMain <<"KoMainWindow::setRootDocument this =" << this <<" doc =" << doc;
0474     QList<KoView*> oldRootViews = d->rootViews;
0475     d->rootViews.clear();
0476     KoDocument *oldRootDoc = d->rootDocument;
0477     KoPart *oldRootPart = d->rootPart;
0478 
0479     if (oldRootDoc) {
0480         oldRootDoc->disconnect(this);
0481         oldRootPart->removeMainWindow(this);
0482 
0483         if (dockerManager()) {
0484             dockerManager()->resetToolDockerWidgets();
0485         }
0486 
0487         // Hide all dockwidgets and remember their old state
0488         d->dockWidgetVisibilityMap.clear();
0489 
0490         foreach(QDockWidget* dockWidget, d->dockWidgetsMap) {
0491             d->dockWidgetVisibilityMap.insert(dockWidget, dockWidget->isVisible());
0492             dockWidget->setVisible(false);
0493         }
0494 
0495         d->toggleDockerTitleBars->setVisible(false);
0496         d->dockWidgetMenu->setVisible(false);
0497     }
0498 
0499     d->rootDocument = doc;
0500     // XXX remove this after the splitting
0501     if (!part && doc) {
0502         d->rootPart = doc->documentPart();
0503     }
0504     else {
0505         d->rootPart = part;
0506     }
0507 
0508     if (doc) {
0509         d->toggleDockerTitleBars->setVisible(true);
0510         d->dockWidgetMenu->setVisible(true);
0511         d->m_registeredPart = d->rootPart.data();
0512 
0513         KoView *view = d->rootPart->createView(doc, this);
0514         setCentralWidget(view);
0515         d->rootViews.append(view);
0516 
0517         view->show();
0518         view->setFocus();
0519 
0520         // The addMainWindow has been done already if using openUrl
0521         if (!d->rootPart->mainWindows().contains(this)) {
0522             d->rootPart->addMainWindow(this);
0523         }
0524     }
0525 
0526     bool enable = d->rootDocument != 0 ? true : false;
0527     d->showDocumentInfo->setEnabled(enable);
0528     d->saveAction->setEnabled(enable);
0529     d->saveActionAs->setEnabled(enable);
0530     d->importFile->setEnabled(enable);
0531     d->exportFile->setEnabled(enable);
0532     d->encryptDocument->setEnabled(enable);
0533 #ifndef NDEBUG
0534     d->uncompressToDir->setEnabled(enable);
0535 #endif
0536     d->printAction->setEnabled(enable);
0537     d->printActionPreview->setEnabled(enable);
0538     d->sendFileAction->setEnabled(enable);
0539     d->exportPdf->setEnabled(enable);
0540     d->closeFile->setEnabled(enable);
0541     updateCaption();
0542 
0543     setActivePart(d->rootPart, doc ? d->rootViews.first() : 0);
0544     emit restoringDone();
0545 
0546     while(!oldRootViews.isEmpty()) {
0547         delete oldRootViews.takeFirst();
0548     }
0549     if (oldRootPart && oldRootPart->viewCount() == 0) {
0550         //debugMain <<"No more views, deleting old doc" << oldRootDoc;
0551         oldRootDoc->clearUndoHistory();
0552         if(deletePrevious)
0553             delete oldRootDoc;
0554     }
0555 
0556     if (doc && !d->dockWidgetVisibilityMap.isEmpty()) {
0557         foreach(QDockWidget* dockWidget, d->dockWidgetsMap) {
0558             dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget));
0559         }
0560     }
0561 
0562     if (!d->rootDocument) {
0563         statusBar()->setVisible(false);
0564     }
0565     else {
0566 #ifdef Q_OS_MAC
0567         statusBar()->setMaximumHeight(28);
0568 #endif
0569         connect(d->rootDocument, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified(QString,bool)));
0570     }
0571 }
0572 
0573 void KoMainWindow::updateReloadFileAction(KoDocument *doc)
0574 {
0575     d->reloadFile->setEnabled(doc && !doc->url().isEmpty());
0576 }
0577 
0578 void KoMainWindow::updateVersionsFileAction(KoDocument *doc)
0579 {
0580     //TODO activate it just when we save it in oasis file format
0581     d->showFileVersions->setEnabled(doc && !doc->url().isEmpty() && (doc->outputMimeType() == doc->nativeOasisMimeType() || doc->outputMimeType() == doc->nativeOasisMimeType() + "-template"));
0582 }
0583 
0584 void KoMainWindow::setReadWrite(bool readwrite)
0585 {
0586     d->saveAction->setEnabled(readwrite);
0587     d->importFile->setEnabled(readwrite);
0588     d->readOnly =  !readwrite;
0589     updateCaption();
0590 }
0591 
0592 void KoMainWindow::addRecentURL(const QUrl &url)
0593 {
0594     debugMain << "KoMainWindow::addRecentURL url=" << url.toDisplayString();
0595     // Add entry to recent documents list
0596     // (call coming from KoDocument because it must work with cmd line, template dlg, file/open, etc.)
0597     if (!url.isEmpty()) {
0598         bool ok = true;
0599         if (url.isLocalFile()) {
0600             QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile();
0601             const QStringList tmpDirs = QStandardPaths::standardLocations(QStandardPaths::TempLocation);
0602             foreach (const QString &tmpDir, tmpDirs) {
0603                 if (path.startsWith(tmpDir)) {
0604                     ok = false; // it's in the tmp resource
0605                     break;
0606                 }
0607             }
0608             if (ok) {
0609                 KRecentDocument::add(QUrl::fromLocalFile(path));
0610                 KRecentDirs::add(":OpenDialog", QFileInfo(path).dir().canonicalPath());
0611             }
0612         } else {
0613             KRecentDocument::add(url.adjusted(QUrl::StripTrailingSlash));
0614         }
0615         if (ok) {
0616             d->recent->addUrl(url);
0617         }
0618         saveRecentFiles();
0619 
0620 #ifdef HAVE_KACTIVITIES
0621         if (!d->activityResource) {
0622             d->activityResource = new KActivities::ResourceInstance(winId(), this);
0623         }
0624         d->activityResource->setUri(url);
0625 #endif
0626     }
0627 }
0628 
0629 void KoMainWindow::saveRecentFiles()
0630 {
0631     // Save list of recent files
0632     KSharedConfigPtr config = componentData().config();
0633     debugMain << this << " Saving recent files list into config. componentData()=" << componentData().componentName();
0634     d->recent->saveEntries(config->group("RecentFiles"));
0635     config->sync();
0636 
0637     // Tell all windows to reload their list, after saving
0638     // Doesn't work multi-process, but it's a start
0639     foreach(KMainWindow* window, KMainWindow::memberList())
0640         static_cast<KoMainWindow *>(window)->reloadRecentFileList();
0641 }
0642 
0643 void KoMainWindow::reloadRecentFileList()
0644 {
0645     KSharedConfigPtr config = componentData().config();
0646     d->recent->loadEntries(config->group("RecentFiles"));
0647 }
0648 
0649 KoPart* KoMainWindow::createPart() const
0650 {
0651     KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(d->nativeMimeType);
0652     QString errorMsg;
0653     KoPart *part = entry.createKoPart(&errorMsg);
0654 
0655     if (!part || !errorMsg.isEmpty()) {
0656         return 0;
0657     }
0658     return part;
0659 }
0660 
0661 void KoMainWindow::updateCaption()
0662 {
0663     debugMain << "KoMainWindow::updateCaption()";
0664     if (!d->rootDocument) {
0665         updateCaption(QString(), false);
0666     }
0667     else {
0668         QString caption( d->rootDocument->caption() );
0669         if (d->readOnly) {
0670             caption += ' ' + i18n("(write protected)");
0671         }
0672 
0673         updateCaption(caption, d->rootDocument->isModified());
0674         if (!rootDocument()->url().fileName().isEmpty())
0675             d->saveAction->setToolTip(i18n("Save as %1", d->rootDocument->url().fileName()));
0676         else
0677             d->saveAction->setToolTip(i18n("Save"));
0678     }
0679 }
0680 
0681 void KoMainWindow::updateCaption(const QString & caption, bool mod)
0682 {
0683     debugMain << "KoMainWindow::updateCaption(" << caption << "," << mod << ")";
0684 #ifdef CALLIGRA_ALPHA
0685     setCaption(QString("ALPHA %1: %2").arg(CALLIGRA_ALPHA).arg(caption), mod);
0686     return;
0687 #endif
0688 #ifdef CALLIGRA_BETA
0689     setCaption(QString("BETA %1: %2").arg(CALLIGRA_BETA).arg(caption), mod);
0690     return;
0691 #endif
0692 #ifdef CALLIGRA_RC
0693     setCaption(QString("RELEASE CANDIDATE %1: %2").arg(CALLIGRA_RC).arg(caption), mod);
0694     return;
0695 #endif
0696 
0697     setCaption(caption, mod);
0698 }
0699 
0700 KoDocument *KoMainWindow::rootDocument() const
0701 {
0702     return d->rootDocument;
0703 }
0704 
0705 KoView *KoMainWindow::rootView() const
0706 {
0707     if (d->rootViews.indexOf(d->activeView) != -1)
0708         return d->activeView;
0709     return d->rootViews.empty() ? nullptr : d->rootViews.first();
0710 }
0711 
0712 bool KoMainWindow::openDocument(const QUrl &url)
0713 {
0714     if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) {
0715         KMessageBox::error(0, i18n("The file %1 does not exist.", url.url()));
0716         d->recent->removeUrl(url); //remove the file from the recent-opened-file-list
0717         saveRecentFiles();
0718         return false;
0719     }
0720     return openDocumentInternal(url);
0721 }
0722 
0723 bool KoMainWindow::openDocument(KoPart *newPart, const QUrl &url)
0724 {
0725     // the part always has a document; the document doesn't know about the part.
0726     KoDocument *newdoc = newPart->document();
0727     if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) {
0728         newdoc->initEmpty(); //create an empty document
0729         setRootDocument(newdoc, newPart);
0730         newdoc->setUrl(url);
0731         QMimeType mime = QMimeDatabase().mimeTypeForUrl(url);
0732         QString mimetype = (!mime.isValid() || mime.isDefault()) ? newdoc->nativeFormatMimeType() : mime.name();
0733         newdoc->setMimeTypeAfterLoading(mimetype);
0734         updateCaption();
0735         return true;
0736     }
0737     return openDocumentInternal(url, newPart, newdoc);
0738 }
0739 
0740 bool KoMainWindow::openDocumentInternal(const QUrl &url, KoPart *newpart, KoDocument *newdoc)
0741 {
0742     debugMain <<"KoMainWindow::openDocument" << url.url();
0743 
0744     if (!newpart)
0745         newpart = createPart();
0746 
0747     if (!newpart)
0748         return false;
0749 
0750     if (!newdoc)
0751         newdoc = newpart->document();
0752 
0753     d->firstTime = true;
0754     connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
0755     connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
0756     connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
0757     d->openingDocument = true;
0758     newpart->addMainWindow(this);   // used by openUrl
0759     bool openRet = (!isImporting()) ? newdoc->openUrl(url) : newdoc->importDocument(url);
0760     if (!openRet) {
0761         newpart->removeMainWindow(this);
0762         delete newdoc;
0763         delete newpart;
0764         d->openingDocument = false;
0765         return false;
0766     }
0767     updateReloadFileAction(newdoc);
0768     updateVersionsFileAction(newdoc);
0769 
0770     KFileItem file(url, newdoc->mimeType(), KFileItem::Unknown);
0771     if (!file.isWritable()) {
0772         setReadWrite(false);
0773     }
0774     return true;
0775 }
0776 
0777 // Separate from openDocument to handle async loading (remote URLs)
0778 void KoMainWindow::slotLoadCompleted()
0779 {
0780     debugMain << "KoMainWindow::slotLoadCompleted";
0781     KoDocument *newdoc = qobject_cast<KoDocument*>(sender());
0782     KoPart *newpart = newdoc->documentPart();
0783 
0784     if (d->rootDocument && d->rootDocument->isEmpty()) {
0785         // Replace current empty document
0786         setRootDocument(newdoc);
0787         emit loadCompleted(this);
0788     } else if (d->rootDocument && !d->rootDocument->isEmpty()) {
0789         // Open in a new main window
0790         // (Note : could create the main window first and the doc next for this
0791         // particular case, that would give a better user feedback...)
0792         KoMainWindow *s = newpart->createMainWindow();
0793         s->show();
0794         newpart->removeMainWindow(this);
0795         s->setRootDocument(newdoc, newpart);
0796         emit loadCompleted(s);
0797     } else {
0798         // We had no document, set the new one
0799         setRootDocument(newdoc);
0800         emit loadCompleted(this);
0801     }
0802 
0803     slotProgress(-1);
0804     disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
0805     disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
0806     disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
0807     d->openingDocument = false;
0808 }
0809 
0810 void KoMainWindow::slotLoadCanceled(const QString & errMsg)
0811 {
0812     debugMain << "KoMainWindow::slotLoadCanceled";
0813     if (!errMsg.isEmpty())   // empty when canceled by user
0814         KMessageBox::error(this, errMsg);
0815     // ... can't delete the document, it's the one who emitted the signal...
0816 
0817     KoDocument* doc = qobject_cast<KoDocument*>(sender());
0818     Q_ASSERT(doc);
0819     disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
0820     disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
0821     disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
0822     d->openingDocument = false;
0823     emit loadCanceled();
0824 }
0825 
0826 void KoMainWindow::slotSaveCanceled(const QString &errMsg)
0827 {
0828     debugMain << "KoMainWindow::slotSaveCanceled";
0829     if (!errMsg.isEmpty())   // empty when canceled by user
0830         KMessageBox::error(this, errMsg);
0831     slotSaveCompleted();
0832 }
0833 
0834 void KoMainWindow::slotSaveCompleted()
0835 {
0836     debugMain << "KoMainWindow::slotSaveCompleted";
0837     KoDocument* doc = qobject_cast<KoDocument*>(sender());
0838     Q_ASSERT(doc);
0839     disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
0840     disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
0841     disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString)));
0842 
0843     if (d->deferredClosingEvent) {
0844         KXmlGuiWindow::closeEvent(d->deferredClosingEvent);
0845     }
0846 }
0847 
0848 // returns true if we should save, false otherwise.
0849 bool KoMainWindow::exportConfirmation(const QByteArray &outputFormat)
0850 {
0851     KConfigGroup group =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
0852     if (!group.readEntry("WantExportConfirmation", true)) {
0853         return true;
0854     }
0855 
0856     QMimeType mime = QMimeDatabase().mimeTypeForName(outputFormat);
0857     QString comment = mime.isValid() ? mime.comment() : i18n("%1 (unknown file type)", QString::fromLatin1(outputFormat));
0858 
0859     // Warn the user
0860     int ret;
0861     if (!isExporting()) { // File --> Save
0862         ret = KMessageBox::warningContinueCancel
0863                 (
0864                     this,
0865                     i18n("<qt>Saving as a %1 may result in some loss of formatting."
0866                          "<p>Do you still want to save in this format?</qt>",
0867                          QString("<b>%1</b>").arg(comment)),      // in case we want to remove the bold later
0868                     i18n("Confirm Save"),
0869                     KStandardGuiItem::save(),
0870                     KStandardGuiItem::cancel(),
0871                     "NonNativeSaveConfirmation"
0872                     );
0873     } else { // File --> Export
0874         ret = KMessageBox::warningContinueCancel
0875                 (
0876                     this,
0877                     i18n("<qt>Exporting as a %1 may result in some loss of formatting."
0878                          "<p>Do you still want to export to this format?</qt>",
0879                          QString("<b>%1</b>").arg(comment)),      // in case we want to remove the bold later
0880                     i18n("Confirm Export"),
0881                     KGuiItem(i18n("Export")),
0882                     KStandardGuiItem::cancel(),
0883                     "NonNativeExportConfirmation" // different to the one used for Save (above)
0884                     );
0885     }
0886 
0887     return (ret == KMessageBox::Continue);
0888 }
0889 
0890 bool KoMainWindow::saveDocument(bool saveas, bool silent, int specialOutputFlag)
0891 {
0892     if (!d->rootDocument || !d->rootPart) {
0893         return true;
0894     }
0895 
0896     bool reset_url;
0897 
0898     if (d->rootDocument->url().isEmpty()) {
0899         emit saveDialogShown();
0900         reset_url = true;
0901         saveas = true;
0902     } else {
0903         reset_url = false;
0904     }
0905 
0906     connect(d->rootDocument, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
0907     connect(d->rootDocument, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
0908     connect(d->rootDocument, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString)));
0909 
0910     QUrl oldURL = d->rootDocument->url();
0911     QString oldFile = d->rootDocument->localFilePath();
0912 
0913     QByteArray _native_format = d->rootDocument->nativeFormatMimeType();
0914     QByteArray oldOutputFormat = d->rootDocument->outputMimeType();
0915 
0916     int oldSpecialOutputFlag = d->rootDocument->specialOutputFlag();
0917 
0918     QUrl suggestedURL = d->rootDocument->url();
0919 
0920     QStringList mimeFilter;
0921     QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format);
0922     if (!mime.isValid())
0923         // QT5TODO: find if there is no better way to get an object for the default type
0924         mime = QMimeDatabase().mimeTypeForName(QStringLiteral("application/octet-stream"));
0925     if (specialOutputFlag)
0926         mimeFilter = mime.globPatterns();
0927     else
0928         mimeFilter = KoFilterManager::mimeFilter(_native_format,
0929                                                  KoFilterManager::Export,
0930                                                  d->rootDocument->extraNativeMimeTypes());
0931 
0932 
0933     if (!mimeFilter.contains(oldOutputFormat) && !isExporting()) {
0934         debugMain << "KoMainWindow::saveDocument no export filter for" << oldOutputFormat;
0935 
0936         // --- don't setOutputMimeType in case the user cancels the Save As
0937         // dialog and then tries to just plain Save ---
0938 
0939         // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :))
0940         QString suggestedFilename = suggestedURL.fileName();
0941         if (!suggestedFilename.isEmpty()) {  // ".kra" looks strange for a name
0942             int c = suggestedFilename.lastIndexOf('.');
0943 
0944             const QString ext = mime.preferredSuffix();
0945             if (!ext.isEmpty()) {
0946                 if (c < 0)
0947                     suggestedFilename += ext;
0948                 else
0949                     suggestedFilename = suggestedFilename.left(c) + ext;
0950             } else { // current filename extension wrong anyway
0951                 if (c > 0) {
0952                     // this assumes that a . signifies an extension, not just a .
0953                     suggestedFilename = suggestedFilename.left(c);
0954                 }
0955             }
0956 
0957             suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
0958             suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
0959         }
0960 
0961         // force the user to choose outputMimeType
0962         saveas = true;
0963     }
0964 
0965     bool ret = false;
0966 
0967     if (d->rootDocument->url().isEmpty() || saveas) {
0968         // if you're just File/Save As'ing to change filter options you
0969         // don't want to be reminded about overwriting files etc.
0970         bool justChangingFilterOptions = false;
0971 
0972         KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument");
0973         dialog.setCaption(i18n("untitled"));
0974         dialog.setDefaultDir((isExporting() && !d->lastExportUrl.isEmpty()) ?
0975                                 d->lastExportUrl.toLocalFile() : suggestedURL.toLocalFile());
0976         dialog.setMimeTypeFilters(mimeFilter);
0977         QUrl newURL = QUrl::fromUserInput(dialog.filename());
0978 
0979         if (newURL.isLocalFile()) {
0980             QString fn = newURL.toLocalFile();
0981             if (QFileInfo(fn).completeSuffix().isEmpty()) {
0982                 QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format);
0983                 fn.append(mime.preferredSuffix());
0984                 newURL = QUrl::fromLocalFile(fn);
0985             }
0986         }
0987 
0988         QByteArray outputFormat = _native_format;
0989 
0990         if (!specialOutputFlag) {
0991             QMimeType mime = QMimeDatabase().mimeTypeForUrl(newURL);
0992             outputFormat = mime.name().toLatin1();
0993         }
0994 
0995 
0996         if (!isExporting())
0997             justChangingFilterOptions = (newURL == d->rootDocument->url()) &&
0998                     (outputFormat == d->rootDocument->mimeType()) &&
0999                     (specialOutputFlag == oldSpecialOutputFlag);
1000         else
1001             justChangingFilterOptions = (newURL == d->lastExportUrl) &&
1002                     (outputFormat == d->lastExportedFormat) &&
1003                     (specialOutputFlag == d->lastExportSpecialOutputFlag);
1004 
1005 
1006         bool bOk = true;
1007         if (newURL.isEmpty()) {
1008             bOk = false;
1009         }
1010 
1011         // adjust URL before doing checks on whether the file exists.
1012         if (specialOutputFlag) {
1013             QString fileName = newURL.fileName();
1014             if ( specialOutputFlag== KoDocument::SaveAsDirectoryStore) {
1015                 // Do nothing
1016             }
1017             else if (specialOutputFlag == KoDocument::SaveEncrypted) {
1018                 int dot = fileName.lastIndexOf('.');
1019                 QString ext = mime.preferredSuffix();
1020                 if (!ext.isEmpty()) {
1021                     if (dot < 0) fileName += ext;
1022                     else fileName = fileName.left(dot) + ext;
1023                 } else { // current filename extension wrong anyway
1024                     if (dot > 0) fileName = fileName.left(dot);
1025                 }
1026                 newURL = newURL.adjusted(QUrl::RemoveFilename);
1027                 newURL.setPath(newURL.path() + fileName);
1028             }
1029         }
1030 
1031         if (bOk) {
1032             bool wantToSave = true;
1033 
1034             // don't change this line unless you know what you're doing :)
1035             if (!justChangingFilterOptions || d->rootDocument->confirmNonNativeSave(isExporting())) {
1036                 if (!d->rootDocument->isNativeFormat(outputFormat))
1037                     wantToSave = exportConfirmation(outputFormat);
1038             }
1039 
1040             if (wantToSave) {
1041                 //
1042                 // Note:
1043                 // If the user is stupid enough to Export to the current URL,
1044                 // we do _not_ change this operation into a Save As.  Reasons
1045                 // follow:
1046                 //
1047                 // 1. A check like "isExporting() && oldURL == newURL"
1048                 //    doesn't _always_ work on case-insensitive filesystems
1049                 //    and inconsistent behaviour is bad.
1050                 // 2. It is probably not a good idea to change d->rootDocument->mimeType
1051                 //    and friends because the next time the user File/Save's,
1052                 //    (not Save As) they won't be expecting that they are
1053                 //    using their File/Export settings
1054                 //
1055                 // As a bad side-effect of this, the modified flag will not
1056                 // be updated and it is possible that what is currently on
1057                 // their screen is not what is stored on disk (through loss
1058                 // of formatting).  But if you are dumb enough to change
1059                 // mimetype but not the filename, then arguably, _you_ are
1060                 // the "bug" :)
1061                 //
1062                 // - Clarence
1063                 //
1064 
1065 
1066                 d->rootDocument->setOutputMimeType(outputFormat, specialOutputFlag);
1067                 if (!isExporting()) {  // Save As
1068                     ret = d->rootDocument->saveAs(newURL);
1069 
1070                     if (ret) {
1071                         debugMain << "Successful Save As!";
1072                         addRecentURL(newURL);
1073                         setReadWrite(true);
1074                     } else {
1075                         debugMain << "Failed Save As!";
1076                         d->rootDocument->setUrl(oldURL);
1077                         d->rootDocument->setLocalFilePath(oldFile);
1078                         d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag);
1079                     }
1080                 } else { // Export
1081                     ret = d->rootDocument->exportDocument(newURL);
1082 
1083                     if (ret) {
1084                         // a few file dialog convenience things
1085                         d->lastExportUrl = newURL;
1086                         d->lastExportedFormat = outputFormat;
1087                         d->lastExportSpecialOutputFlag = specialOutputFlag;
1088                     }
1089 
1090                     // always restore output format
1091                     d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag);
1092                 }
1093 
1094                 if (silent) // don't let the document change the window caption
1095                     d->rootDocument->setTitleModified();
1096             }   // if (wantToSave)  {
1097             else
1098                 ret = false;
1099         }   // if (bOk) {
1100         else
1101             ret = false;
1102     } else { // saving
1103 
1104         bool needConfirm = d->rootDocument->confirmNonNativeSave(false) && !d->rootDocument->isNativeFormat(oldOutputFormat);
1105 
1106         if (!needConfirm ||
1107                 (needConfirm && exportConfirmation(oldOutputFormat /* not so old :) */))
1108                 ) {
1109             // be sure d->rootDocument has the correct outputMimeType!
1110             if (isExporting() || d->rootDocument->isModified() || d->rootDocument->alwaysAllowSaving()) {
1111                 ret = d->rootDocument->save();
1112             }
1113 
1114             if (!ret) {
1115                 debugMain << "Failed Save!";
1116                 d->rootDocument->setUrl(oldURL);
1117                 d->rootDocument->setLocalFilePath(oldFile);
1118             }
1119         } else
1120             ret = false;
1121     }
1122 
1123 
1124     if (!ret && reset_url)
1125         d->rootDocument->resetURL(); //clean the suggested filename as the save dialog was rejected
1126 
1127     updateReloadFileAction(d->rootDocument);
1128     updateCaption();
1129 
1130     return ret;
1131 }
1132 
1133 void KoMainWindow::closeEvent(QCloseEvent *e)
1134 {
1135     // If we are in the process of opening a new document, rootDocument() may not have been set yet,
1136     // so we must prevent closing to avoid crash.
1137     if(d->openingDocument || (rootDocument() && rootDocument()->isLoading())) {
1138         e->setAccepted(false);
1139         return;
1140     }
1141     if (queryClose()) {
1142         d->deferredClosingEvent = e;
1143         if (d->partToOpen) {
1144             // The open pane is visible
1145             d->partToOpen->deleteOpenPane(true);
1146         }
1147         if (!d->m_dockerStateBeforeHiding.isEmpty()) {
1148             restoreState(d->m_dockerStateBeforeHiding);
1149         }
1150         statusBar()->setVisible(true);
1151         menuBar()->setVisible(true);
1152 
1153         saveWindowSettings();
1154         if(d->noCleanup)
1155             return;
1156         setRootDocument(0);
1157         if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency
1158             foreach(QDockWidget* dockWidget, d->dockWidgetsMap)
1159                 dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget));
1160         }
1161     } else {
1162         e->setAccepted(false);
1163     }
1164 }
1165 
1166 void KoMainWindow::saveWindowSettings()
1167 {
1168     KSharedConfigPtr config = componentData().config();
1169 
1170     if (d->windowSizeDirty ) {
1171 
1172         // Save window size into the config file of our componentData
1173         // TODO: check if this is ever read again, seems lost over the years
1174         debugMain << "KoMainWindow::saveWindowSettings";
1175         KConfigGroup mainWindowConfigGroup = config->group("MainWindow");
1176         KWindowConfig::saveWindowSize(windowHandle(), mainWindowConfigGroup);
1177         config->sync();
1178         d->windowSizeDirty = false;
1179     }
1180 
1181     if ( rootDocument() && d->rootPart) {
1182 
1183         // Save toolbar position into the config file of the app, under the doc's component name
1184         KConfigGroup group =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
1185         //debugMain <<"KoMainWindow::closeEvent -> saveMainWindowSettings rootdoc's componentData=" << d->rootPart->componentData().componentName();
1186         saveMainWindowSettings(group);
1187 
1188         // Save collapsable state of dock widgets
1189         for (QMap<QString, QDockWidget*>::const_iterator i = d->dockWidgetsMap.constBegin();
1190              i != d->dockWidgetsMap.constEnd(); ++i) {
1191             if (i.value()->widget()) {
1192                 KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key());
1193                 dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden());
1194                 dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool());
1195                 dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value()));
1196             }
1197         }
1198 
1199     }
1200 
1201      KSharedConfig::openConfig()->sync();
1202     resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down
1203 
1204 }
1205 
1206 void KoMainWindow::resizeEvent(QResizeEvent * e)
1207 {
1208     d->windowSizeDirty = true;
1209     KXmlGuiWindow::resizeEvent(e);
1210 }
1211 
1212 bool KoMainWindow::queryClose()
1213 {
1214     if (rootDocument() == 0)
1215         return true;
1216     //debugMain <<"KoMainWindow::queryClose() viewcount=" << rootDocument()->viewCount()
1217     //               << " mainWindowCount=" << rootDocument()->mainWindowCount() << endl;
1218     if (!d->forQuit && d->rootPart && d->rootPart->mainwindowCount() > 1)
1219         // there are more open, and we are closing just one, so no problem for closing
1220         return true;
1221 
1222     // main doc + internally stored child documents
1223     if (d->rootDocument->isModified()) {
1224         QString name;
1225         if (rootDocument()->documentInfo()) {
1226             name = rootDocument()->documentInfo()->aboutInfo("title");
1227         }
1228         if (name.isEmpty())
1229             name = rootDocument()->url().fileName();
1230 
1231         if (name.isEmpty())
1232             name = i18n("Untitled");
1233 
1234         int res = KMessageBox::warningYesNoCancel(this,
1235                                                   i18n("<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>", name),
1236                                                   QString(),
1237                                                   KStandardGuiItem::save(),
1238                                                   KStandardGuiItem::discard());
1239 
1240         switch (res) {
1241         case KMessageBox::Yes : {
1242             bool isNative = (d->rootDocument->outputMimeType() == d->rootDocument->nativeFormatMimeType());
1243             if (!saveDocument(!isNative))
1244                 return false;
1245             break;
1246         }
1247         case KMessageBox::No :
1248             rootDocument()->removeAutoSaveFiles();
1249             rootDocument()->setModified(false);   // Now when queryClose() is called by closeEvent it won't do anything.
1250             break;
1251         default : // case KMessageBox::Cancel :
1252             return false;
1253         }
1254     }
1255 
1256     return true;
1257 }
1258 
1259 // Helper method for slotFileNew and slotFileClose
1260 void KoMainWindow::chooseNewDocument(InitDocFlags initDocFlags)
1261 {
1262     KoDocument* doc = rootDocument();
1263     KoPart *newpart = createPart();
1264     KoDocument *newdoc = newpart->document();
1265 
1266     if (!newdoc)
1267         return;
1268 
1269     disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
1270 
1271     if ((!doc && initDocFlags == InitDocFileNew) || (doc && !doc->isEmpty())) {
1272         KoMainWindow *s = newpart->createMainWindow();
1273         s->show();
1274         newpart->addMainWindow(s);
1275         newpart->showStartUpWidget(s, true /*Always show widget*/);
1276         return;
1277     }
1278 
1279     if (doc) {
1280         setRootDocument(0);
1281         if(d->rootDocument)
1282             d->rootDocument->clearUndoHistory();
1283         delete d->rootDocument;
1284         d->rootDocument = 0;
1285     }
1286 
1287     newpart->addMainWindow(this);
1288     newpart->showStartUpWidget(this, true /*Always show widget*/);
1289 }
1290 
1291 void KoMainWindow::slotFileNew()
1292 {
1293     chooseNewDocument(InitDocFileNew);
1294 }
1295 
1296 void KoMainWindow::slotFileOpen()
1297 {
1298     QUrl url;
1299     if (!isImporting()) {
1300         KoFileDialog dialog(this, KoFileDialog::OpenFile, "OpenDocument");
1301         dialog.setCaption(i18n("Open Document"));
1302         dialog.setDefaultDir(qApp->applicationName().contains("karbon")
1303                                ? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
1304                                : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
1305         dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import));
1306         dialog.setHideNameFilterDetailsOption();
1307         url = QUrl::fromUserInput(dialog.filename());
1308     } else {
1309         KoFileDialog dialog(this, KoFileDialog::ImportFile, "OpenDocument");
1310         dialog.setCaption(i18n("Import Document"));
1311         dialog.setDefaultDir(qApp->applicationName().contains("karbon")
1312                                 ? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
1313                                 : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
1314         dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import));
1315         dialog.setHideNameFilterDetailsOption();
1316         url = QUrl::fromUserInput(dialog.filename());
1317     }
1318 
1319     if (url.isEmpty())
1320         return;
1321 
1322     (void) openDocument(url);
1323 }
1324 
1325 void KoMainWindow::slotFileOpenRecent(const QUrl & url)
1326 {
1327     // Create a copy, because the original QUrl in the map of recent files in
1328     // KRecentFilesAction may get deleted.
1329     (void) openDocument(QUrl(url));
1330 }
1331 
1332 void KoMainWindow::slotFileSave()
1333 {
1334     if (saveDocument())
1335         emit documentSaved();
1336 }
1337 
1338 void KoMainWindow::slotFileSaveAs()
1339 {
1340     if (saveDocument(true))
1341         emit documentSaved();
1342 }
1343 
1344 void KoMainWindow::slotEncryptDocument()
1345 {
1346     if (saveDocument(false, false, KoDocument::SaveEncrypted))
1347         emit documentSaved();
1348 }
1349 
1350 void KoMainWindow::slotUncompressToDir()
1351 {
1352     if (saveDocument(true, false, KoDocument::SaveAsDirectoryStore))
1353         emit documentSaved();
1354 }
1355 
1356 void KoMainWindow::slotDocumentInfo()
1357 {
1358     if (!rootDocument())
1359         return;
1360 
1361     KoDocumentInfo *docInfo = rootDocument()->documentInfo();
1362 
1363     if (!docInfo)
1364         return;
1365 
1366     KoDocumentInfoDlg *dlg = d->rootDocument->createDocumentInfoDialog(this, docInfo);
1367 
1368     if (dlg->exec()) {
1369         if (dlg->isDocumentSaved()) {
1370             rootDocument()->setModified(false);
1371         } else {
1372             rootDocument()->setModified(true);
1373         }
1374         rootDocument()->setTitleModified();
1375     }
1376 
1377     delete dlg;
1378 }
1379 
1380 void KoMainWindow::slotFileClose()
1381 {
1382     if (queryClose()) {
1383         saveWindowSettings();
1384         setRootDocument(0);   // don't delete this main window when deleting the document
1385         if(d->rootDocument)
1386             d->rootDocument->clearUndoHistory();
1387         delete d->rootDocument;
1388         d->rootDocument = 0;
1389         chooseNewDocument(InitDocFileClose);
1390     }
1391 }
1392 
1393 void KoMainWindow::slotFileQuit()
1394 {
1395     close();
1396 }
1397 
1398 void KoMainWindow::slotFilePrint()
1399 {
1400     if (!rootView())
1401         return;
1402     KoPrintJob *printJob = rootView()->createPrintJob();
1403     if (printJob == 0)
1404         return;
1405     d->applyDefaultSettings(printJob->printer());
1406     QPrintDialog *printDialog = rootView()->createPrintDialog( printJob, this );
1407     if (printDialog && printDialog->exec() == QDialog::Accepted)
1408         printJob->startPrinting(KoPrintJob::DeleteWhenDone);
1409     else
1410         delete printJob;
1411     delete printDialog;
1412 }
1413 
1414 void KoMainWindow::slotFilePrintPreview()
1415 {
1416     if (!rootView())
1417         return;
1418     KoPrintJob *printJob = rootView()->createPrintJob();
1419     if (printJob == 0)
1420         return;
1421 
1422     /* Sets the startPrinting() slot to be blocking.
1423      The Qt print-preview dialog requires the printing to be completely blocking
1424      and only return when the full document has been printed.
1425      By default the KoPrintingDialog is non-blocking and
1426      multithreading, setting blocking to true will allow it to be used in the preview dialog */
1427     printJob->setProperty("blocking", true);
1428     QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this);
1429     printJob->setParent(preview); // will take care of deleting the job
1430     connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting()));
1431     preview->exec();
1432     delete preview;
1433 }
1434 
1435 KoPrintJob* KoMainWindow::exportToPdf(const QString &pdfFileName)
1436 {
1437     if (!rootView())
1438         return 0;
1439     KoPageLayout pageLayout;
1440     pageLayout = rootView()->pageLayout();
1441     return exportToPdf(pageLayout, pdfFileName);
1442 }
1443 
1444 KoPrintJob* KoMainWindow::exportToPdf(const KoPageLayout &_pageLayout, const QString &_pdfFileName)
1445 {
1446     if (!rootView())
1447         return 0;
1448 
1449     KoPageLayout pageLayout = _pageLayout;
1450     QString pdfFileName = _pdfFileName;
1451 
1452     if (pdfFileName.isEmpty()) {
1453         KConfigGroup group =  KSharedConfig::openConfig()->group("File Dialogs");
1454         QString defaultDir = group.readEntry("SavePdfDialog");
1455         if (defaultDir.isEmpty())
1456             defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
1457         QUrl startUrl = QUrl::fromLocalFile(defaultDir);
1458         KoDocument* pDoc = rootDocument();
1459         /** if document has a file name, take file name and replace extension with .pdf */
1460         if (pDoc && pDoc->url().isValid()) {
1461             startUrl = pDoc->url();
1462             QString fileName = startUrl.fileName();
1463             fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" );
1464             startUrl = startUrl.adjusted(QUrl::RemoveFilename);
1465             startUrl.setPath(startUrl.path() +  fileName );
1466         }
1467 
1468         QPointer<KoPageLayoutDialog> layoutDlg(new KoPageLayoutDialog(this, pageLayout));
1469         layoutDlg->setWindowModality(Qt::WindowModal);
1470         if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) {
1471             delete layoutDlg;
1472             return 0;
1473         }
1474         pageLayout = layoutDlg->pageLayout();
1475         delete layoutDlg;
1476 
1477         KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument");
1478         dialog.setCaption(i18n("Export as PDF"));
1479         dialog.setDefaultDir(startUrl.toLocalFile());
1480         dialog.setMimeTypeFilters(QStringList() << "application/pdf");
1481         QUrl url = QUrl::fromUserInput(dialog.filename());
1482 
1483         pdfFileName = url.toLocalFile();
1484         if (pdfFileName.isEmpty())
1485             return 0;
1486     }
1487 
1488     KoPrintJob *printJob = rootView()->createPdfPrintJob();
1489     if (printJob == 0)
1490         return 0;
1491     if (isHidden()) {
1492         printJob->setProperty("noprogressdialog", true);
1493     }
1494 
1495     d->applyDefaultSettings(printJob->printer());
1496     // TODO for remote files we have to first save locally and then upload.
1497     printJob->printer().setOutputFileName(pdfFileName);
1498     printJob->printer().setColorMode(QPrinter::Color);
1499 
1500     if (pageLayout.format == KoPageFormat::CustomSize) {
1501         printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter);
1502     } else {
1503         printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format));
1504     }
1505 
1506     switch (pageLayout.orientation) {
1507     case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break;
1508     case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break;
1509     }
1510 
1511     printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter);
1512 
1513     //before printing check if the printer can handle printing
1514     if (!printJob->canPrint()) {
1515         KMessageBox::error(this, i18n("Cannot export to the specified file"));
1516     }
1517 
1518     printJob->startPrinting(KoPrintJob::DeleteWhenDone);
1519     return printJob;
1520 }
1521 
1522 void KoMainWindow::slotConfigureKeys()
1523 {
1524     QAction* undoAction=0;
1525     QAction* redoAction=0;
1526     QString oldUndoText;
1527     QString oldRedoText;
1528     if(currentView()) {
1529         //The undo/redo action text is "undo" + command, replace by simple text while inside editor
1530         undoAction = currentView()->actionCollection()->action("edit_undo");
1531         redoAction = currentView()->actionCollection()->action("edit_redo");
1532         oldUndoText = undoAction->text();
1533         oldRedoText = redoAction->text();
1534         undoAction->setText(i18n("Undo"));
1535         redoAction->setText(i18n("Redo"));
1536     }
1537 
1538     guiFactory()->configureShortcuts();
1539 
1540     if(currentView()) {
1541         undoAction->setText(oldUndoText);
1542         redoAction->setText(oldRedoText);
1543     }
1544 
1545     emit keyBindingsChanged();
1546 }
1547 
1548 void KoMainWindow::slotConfigureToolbars()
1549 {
1550     if (rootDocument()) {
1551         KConfigGroup componentConfigGroup =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
1552         saveMainWindowSettings(componentConfigGroup);
1553     }
1554 
1555     KEditToolBar edit(factory(), this);
1556     connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig()));
1557     (void) edit.exec();
1558 }
1559 
1560 void KoMainWindow::slotNewToolbarConfig()
1561 {
1562     if (rootDocument()) {
1563         KConfigGroup componentConfigGroup =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
1564         applyMainWindowSettings(componentConfigGroup);
1565     }
1566 
1567     KXMLGUIFactory *factory = guiFactory();
1568     Q_UNUSED(factory);
1569 
1570     // Check if there's an active view
1571     if (!d->activeView)
1572         return;
1573 
1574     plugActionList("toolbarlist", d->toolbarList);
1575 }
1576 
1577 void KoMainWindow::slotToolbarToggled(bool toggle)
1578 {
1579     //debugMain <<"KoMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true;
1580     // The action (sender) and the toolbar have the same name
1581     KToolBar * bar = toolBar(sender()->objectName());
1582     if (bar) {
1583         if (toggle)
1584             bar->show();
1585         else
1586             bar->hide();
1587 
1588         if (rootDocument()) {
1589             KConfigGroup componentConfigGroup =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
1590             saveMainWindowSettings(componentConfigGroup);
1591         }
1592     } else
1593         warnMain << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!";
1594 }
1595 
1596 bool KoMainWindow::toolbarIsVisible(const char *tbName)
1597 {
1598     QWidget *tb = toolBar(tbName);
1599     return !tb->isHidden();
1600 }
1601 
1602 void KoMainWindow::showToolbar(const char * tbName, bool shown)
1603 {
1604     QWidget * tb = toolBar(tbName);
1605     if (!tb) {
1606         warnMain << "KoMainWindow: toolbar " << tbName << " not found.";
1607         return;
1608     }
1609     if (shown)
1610         tb->show();
1611     else
1612         tb->hide();
1613 
1614     // Update the action appropriately
1615     foreach(QAction* action, d->toolbarList) {
1616         if (action->objectName() != tbName) {
1617             //debugMain <<"KoMainWindow::showToolbar setChecked" << shown;
1618             static_cast<KToggleAction *>(action)->setChecked(shown);
1619             break;
1620         }
1621     }
1622 }
1623 
1624 void KoMainWindow::viewFullscreen(bool fullScreen)
1625 {
1626     if (fullScreen) {
1627         window()->setWindowState(window()->windowState() | Qt::WindowFullScreen);   // set
1628     } else {
1629         window()->setWindowState(window()->windowState() & ~Qt::WindowFullScreen);   // reset
1630     }
1631 }
1632 
1633 void KoMainWindow::slotProgress(int value)
1634 {
1635     QMutexLocker locker(&d->progressMutex);
1636     debugMain << "KoMainWindow::slotProgress" << value;
1637     if (value <= -1 || value >= 100) {
1638         if (d->progress) {
1639             statusBar()->removeWidget(d->progress);
1640             delete d->progress;
1641             d->progress = 0;
1642         }
1643         d->firstTime = true;
1644         return;
1645     }
1646     if (d->firstTime || !d->progress) {
1647         // The statusbar might not even be created yet.
1648         // So check for that first, and create it if necessary
1649         QStatusBar *bar = findChild<QStatusBar *>();
1650         if (!bar) {
1651             statusBar()->show();
1652             QApplication::sendPostedEvents(this, QEvent::ChildAdded);
1653         }
1654 
1655         if (d->progress) {
1656             statusBar()->removeWidget(d->progress);
1657             delete d->progress;
1658             d->progress = 0;
1659         }
1660 
1661         d->progress = new QProgressBar(statusBar());
1662         d->progress->setMaximumHeight(statusBar()->fontMetrics().height());
1663         d->progress->setRange(0, 100);
1664         statusBar()->addPermanentWidget(d->progress);
1665         d->progress->show();
1666         d->firstTime = false;
1667     }
1668     if (!d->progress.isNull()) {
1669         d->progress->setValue(value);
1670     }
1671     locker.unlock();
1672     qApp->processEvents();
1673 }
1674 
1675 void KoMainWindow::setMaxRecentItems(uint _number)
1676 {
1677     d->recent->setMaxItems(_number);
1678 }
1679 
1680 void KoMainWindow::slotEmailFile()
1681 {
1682     if (!rootDocument())
1683         return;
1684 
1685     // Subject = Document file name
1686     // Attachment = The current file
1687     // Message Body = The current document in HTML export? <-- This may be an option.
1688     QString theSubject;
1689     QStringList urls;
1690     QString fileURL;
1691     if (rootDocument()->url().isEmpty() ||
1692             rootDocument()->isModified()) {
1693         //Save the file as a temporary file
1694         bool const tmp_modified = rootDocument()->isModified();
1695         QUrl const tmp_url = rootDocument()->url();
1696         QByteArray const tmp_mimetype = rootDocument()->outputMimeType();
1697 
1698         // a little open, close, delete dance to make sure we have a nice filename
1699         // to use, but won't block windows from creating a new file with this name.
1700         QTemporaryFile *tmpfile = new QTemporaryFile();
1701         tmpfile->open();
1702         QString fileName = tmpfile->fileName();
1703         tmpfile->close();
1704         delete tmpfile;
1705 
1706         QUrl u = QUrl::fromLocalFile(fileName);
1707         rootDocument()->setUrl(u);
1708         rootDocument()->setModified(true);
1709         rootDocument()->setOutputMimeType(rootDocument()->nativeFormatMimeType());
1710 
1711         saveDocument(false, true);
1712 
1713         fileURL = fileName;
1714         theSubject = i18n("Document");
1715         urls.append(fileURL);
1716 
1717         rootDocument()->setUrl(tmp_url);
1718         rootDocument()->setModified(tmp_modified);
1719         rootDocument()->setOutputMimeType(tmp_mimetype);
1720     } else {
1721         fileURL = rootDocument()->url().url();
1722         theSubject = i18n("Document - %1", rootDocument()->url().fileName());
1723         urls.append(fileURL);
1724     }
1725 
1726     debugMain << "(" << fileURL << ")";
1727 
1728     if (!fileURL.isEmpty()) {
1729         KToolInvocation::invokeMailer(QString(), QString(), QString(), theSubject,
1730                                       QString(), //body
1731                                       QString(),
1732                                       urls); // attachments
1733     }
1734 }
1735 
1736 void KoMainWindow::slotVersionsFile()
1737 {
1738     if (!rootDocument())
1739         return;
1740     KoVersionDialog *dlg = new KoVersionDialog(this, rootDocument());
1741     dlg->exec();
1742     delete dlg;
1743 }
1744 
1745 void KoMainWindow::slotReloadFile()
1746 {
1747     KoDocument* pDoc = rootDocument();
1748     if (!pDoc || pDoc->url().isEmpty() || !pDoc->isModified())
1749         return;
1750 
1751     bool bOk = KMessageBox::questionYesNo(this,
1752                                           i18n("You will lose all changes made since your last save\n"
1753                                                "Do you want to continue?"),
1754                                           i18n("Warning")) == KMessageBox::Yes;
1755     if (!bOk)
1756         return;
1757 
1758     QUrl url = pDoc->url();
1759     if (!pDoc->isEmpty()) {
1760         saveWindowSettings();
1761         setRootDocument(0);   // don't delete this main window when deleting the document
1762         if(d->rootDocument)
1763             d->rootDocument->clearUndoHistory();
1764         delete d->rootDocument;
1765         d->rootDocument = 0;
1766     }
1767     openDocument(url);
1768     return;
1769 
1770 }
1771 
1772 void KoMainWindow::slotImportFile()
1773 {
1774     debugMain << "slotImportFile()";
1775 
1776     d->isImporting = true;
1777     slotFileOpen();
1778     d->isImporting = false;
1779 }
1780 
1781 void KoMainWindow::slotExportFile()
1782 {
1783     debugMain << "slotExportFile()";
1784 
1785     d->isExporting = true;
1786     slotFileSaveAs();
1787     d->isExporting = false;
1788 }
1789 
1790 bool KoMainWindow::isImporting() const
1791 {
1792     return d->isImporting;
1793 }
1794 
1795 bool KoMainWindow::isExporting() const
1796 {
1797     return d->isExporting;
1798 }
1799 
1800 void KoMainWindow::setPartToOpen(KoPart *part)
1801 {
1802     d->partToOpen = part;
1803 }
1804 
1805 KoComponentData KoMainWindow::componentData() const
1806 {
1807     return d->componentData;
1808 }
1809 
1810 QDockWidget* KoMainWindow::createDockWidget(KoDockFactoryBase* factory)
1811 {
1812     QDockWidget* dockWidget = 0;
1813 
1814     if (!d->dockWidgetsMap.contains(factory->id())) {
1815         dockWidget = factory->createDockWidget();
1816 
1817         // It is quite possible that a dock factory cannot create the dock; don't
1818         // do anything in that case.
1819         if (!dockWidget) return 0;
1820         d->dockWidgets.push_back(dockWidget);
1821 
1822         KoDockWidgetTitleBar *titleBar = 0;
1823         // Check if the dock widget is supposed to be collapsable
1824         if (!dockWidget->titleBarWidget()) {
1825             titleBar = new KoDockWidgetTitleBar(dockWidget);
1826             dockWidget->setTitleBarWidget(titleBar);
1827             titleBar->setCollapsable(factory->isCollapsable());
1828         }
1829 
1830         dockWidget->setObjectName(factory->id());
1831         dockWidget->setParent(this);
1832 
1833         if (dockWidget->widget() && dockWidget->widget()->layout())
1834             dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
1835 
1836         Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
1837         bool visible = factory->defaultVisible();
1838 
1839         switch (factory->defaultDockPosition()) {
1840         case KoDockFactoryBase::DockTornOff:
1841             dockWidget->setFloating(true); // position nicely?
1842             break;
1843         case KoDockFactoryBase::DockTop:
1844             side = Qt::TopDockWidgetArea; break;
1845         case KoDockFactoryBase::DockLeft:
1846             side = Qt::LeftDockWidgetArea; break;
1847         case KoDockFactoryBase::DockBottom:
1848             side = Qt::BottomDockWidgetArea; break;
1849         case KoDockFactoryBase::DockRight:
1850             side = Qt::RightDockWidgetArea; break;
1851         case KoDockFactoryBase::DockMinimized:
1852         default:
1853             side = Qt::RightDockWidgetArea;
1854             visible = false;
1855         }
1856 
1857         if (rootDocument()) {
1858             KConfigGroup group =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id());
1859             side = static_cast<Qt::DockWidgetArea>(group.readEntry("DockArea", static_cast<int>(side)));
1860             if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
1861         }
1862         addDockWidget(side, dockWidget);
1863         if (dockWidget->features() & QDockWidget::DockWidgetClosable) {
1864             d->dockWidgetMenu->addAction(dockWidget->toggleViewAction());
1865             if (!visible)
1866                 dockWidget->hide();
1867         }
1868 
1869         bool collapsed = factory->defaultCollapsed();
1870         bool locked = false;
1871         if (rootDocument()) {
1872             KConfigGroup group =  KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id());
1873             collapsed = group.readEntry("Collapsed", collapsed);
1874             locked = group.readEntry("Locked", locked);
1875         }
1876         if (titleBar && collapsed)
1877             titleBar->setCollapsed(true);
1878         if (titleBar && locked)
1879             titleBar->setLocked(true);
1880 
1881         if (titleBar) {
1882             KConfigGroup configGroupInterface =  KSharedConfig::openConfig()->group("Interface");
1883             titleBar->setVisible(configGroupInterface.readEntry("ShowDockerTitleBars", true));
1884         }
1885 
1886         d->dockWidgetsMap.insert(factory->id(), dockWidget);
1887     } else {
1888         dockWidget = d->dockWidgetsMap[ factory->id()];
1889     }
1890 
1891 #ifdef Q_OS_MAC
1892     dockWidget->setAttribute(Qt::WA_MacSmallSize, true);
1893 #endif
1894     dockWidget->setFont(KoDockRegistry::dockFont());
1895 
1896     connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts()));
1897 
1898     return dockWidget;
1899 }
1900 
1901 void KoMainWindow::forceDockTabFonts()
1902 {
1903     QObjectList chis = children();
1904     for (int i = 0; i < chis.size(); ++i) {
1905         if (chis.at(i)->inherits("QTabBar")) {
1906             ((QTabBar *)chis.at(i))->setFont(KoDockRegistry::dockFont());
1907         }
1908     }
1909 }
1910 
1911 QList<QDockWidget*> KoMainWindow::dockWidgets() const
1912 {
1913     return d->dockWidgetsMap.values();
1914 }
1915 
1916 QList<KoCanvasObserverBase*> KoMainWindow::canvasObservers() const
1917 {
1918 
1919     QList<KoCanvasObserverBase*> observers;
1920 
1921     foreach(QDockWidget *docker, dockWidgets()) {
1922         KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
1923         if (observer) {
1924             observers << observer;
1925         }
1926     }
1927     return observers;
1928 }
1929 
1930 
1931 KoDockerManager * KoMainWindow::dockerManager() const
1932 {
1933     return d->dockerManager;
1934 }
1935 
1936 void KoMainWindow::toggleDockersVisibility(bool visible)
1937 {
1938     if (!visible) {
1939         d->m_dockerStateBeforeHiding = saveState();
1940 
1941         foreach(QObject* widget, children()) {
1942             if (widget->inherits("QDockWidget")) {
1943                 QDockWidget* dw = static_cast<QDockWidget*>(widget);
1944                 if (dw->isVisible()) {
1945                     dw->hide();
1946                 }
1947             }
1948         }
1949     }
1950     else {
1951         restoreState(d->m_dockerStateBeforeHiding);
1952     }
1953 }
1954 
1955 KRecentFilesAction *KoMainWindow::recentAction() const
1956 {
1957     return d->recent;
1958 }
1959 
1960 KoView* KoMainWindow::currentView() const
1961 {
1962     // XXX
1963     if (d->activeView) {
1964         return d->activeView;
1965     }
1966     else if (!d->rootViews.isEmpty()) {
1967         return d->rootViews.first();
1968     }
1969     return 0;
1970 }
1971 
1972 void KoMainWindow::newView()
1973 {
1974     Q_ASSERT((d != 0 && d->activeView && d->activePart && d->activeView->koDocument()));
1975 
1976     KoMainWindow *mainWindow = d->activePart->createMainWindow();
1977     mainWindow->setRootDocument(d->activeView->koDocument(), d->activePart);
1978     mainWindow->show();
1979 }
1980 
1981 void KoMainWindow::createMainwindowGUI()
1982 {
1983     if ( isHelpMenuEnabled() && !d->m_helpMenu ) {
1984         d->m_helpMenu = new KHelpMenu( this, componentData().aboutData(), true );
1985 
1986         KActionCollection *actions = actionCollection();
1987         QAction *helpContentsAction = d->m_helpMenu->action(KHelpMenu::menuHelpContents);
1988         QAction *whatsThisAction = d->m_helpMenu->action(KHelpMenu::menuWhatsThis);
1989         QAction *reportBugAction = d->m_helpMenu->action(KHelpMenu::menuReportBug);
1990         QAction *switchLanguageAction = d->m_helpMenu->action(KHelpMenu::menuSwitchLanguage);
1991         QAction *aboutAppAction = d->m_helpMenu->action(KHelpMenu::menuAboutApp);
1992         QAction *aboutKdeAction = d->m_helpMenu->action(KHelpMenu::menuAboutKDE);
1993 
1994         if (helpContentsAction) {
1995             actions->addAction(helpContentsAction->objectName(), helpContentsAction);
1996         }
1997         if (whatsThisAction) {
1998             actions->addAction(whatsThisAction->objectName(), whatsThisAction);
1999         }
2000         if (reportBugAction) {
2001             actions->addAction(reportBugAction->objectName(), reportBugAction);
2002         }
2003         if (switchLanguageAction) {
2004             actions->addAction(switchLanguageAction->objectName(), switchLanguageAction);
2005         }
2006         if (aboutAppAction) {
2007             actions->addAction(aboutAppAction->objectName(), aboutAppAction);
2008         }
2009         if (aboutKdeAction) {
2010             actions->addAction(aboutKdeAction->objectName(), aboutKdeAction);
2011         }
2012     }
2013 
2014     QString f = xmlFile();
2015     setXMLFile( QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("ui/ui_standards.rc")) );
2016     if ( !f.isEmpty() )
2017         setXMLFile( f, true );
2018     else
2019     {
2020         QString auto_file( componentData().componentName() + "ui.rc" );
2021         setXMLFile( auto_file, true );
2022     }
2023 
2024     guiFactory()->addClient( this );
2025 
2026 }
2027 
2028 // PartManager
2029 
2030 void KoMainWindow::removePart( KoPart *part )
2031 {
2032     if (d->m_registeredPart.data() != part) {
2033         return;
2034     }
2035     d->m_registeredPart = 0;
2036     if ( part == d->m_activePart ) {
2037         setActivePart(0, 0);
2038     }
2039 }
2040 
2041 void KoMainWindow::setActivePart(KoPart *part, QWidget *widget )
2042 {
2043     if (part && d->m_registeredPart.data() != part) {
2044         warnMain << "trying to activate a non-registered part!" << part->objectName();
2045         return; // don't allow someone call setActivePart with a part we don't know about
2046     }
2047 
2048     // don't activate twice
2049     if ( d->m_activePart && part && d->m_activePart == part &&
2050          (!widget || d->m_activeWidget == widget) )
2051         return;
2052 
2053     KoPart *oldActivePart = d->m_activePart;
2054     QWidget *oldActiveWidget = d->m_activeWidget;
2055 
2056     d->m_activePart = part;
2057     d->m_activeWidget = widget;
2058 
2059     if (oldActivePart) {
2060         KoPart *savedActivePart = part;
2061         QWidget *savedActiveWidget = widget;
2062 
2063         if ( oldActiveWidget ) {
2064             disconnect( oldActiveWidget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestroyed()) );
2065         }
2066 
2067         d->m_activePart = savedActivePart;
2068         d->m_activeWidget = savedActiveWidget;
2069     }
2070 
2071     if (d->m_activePart && d->m_activeWidget ) {
2072         connect( d->m_activeWidget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestroyed()) );
2073     }
2074     // Set the new active instance in KGlobal
2075 //     KGlobal::setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KGlobal::mainComponent());
2076 
2077     // old slot called from part manager
2078     KoPart *newPart = static_cast<KoPart*>(d->m_activePart.data());
2079 
2080     if (d->activePart && d->activePart == newPart) {
2081         //debugMain <<"no need to change the GUI";
2082         return;
2083     }
2084 
2085     KXMLGUIFactory *factory = guiFactory();
2086 
2087     if (d->activeView) {
2088 
2089         factory->removeClient(d->activeView);
2090 
2091         unplugActionList("toolbarlist");
2092         qDeleteAll(d->toolbarList);
2093         d->toolbarList.clear();
2094     }
2095 
2096     if (!d->mainWindowGuiIsBuilt) {
2097         createMainwindowGUI();
2098     }
2099 
2100     if (newPart && d->m_activeWidget && d->m_activeWidget->inherits("KoView")) {
2101         d->activeView = qobject_cast<KoView *>(d->m_activeWidget);
2102         d->activeView->actionCollection()->addAction("view_newview", actionCollection()->action("view_newview"));
2103         d->activePart = newPart;
2104         //debugMain <<"new active part is" << d->activePart;
2105 
2106         factory->addClient(d->activeView);
2107 
2108         // Position and show toolbars according to user's preference
2109         setAutoSaveSettings(newPart->componentData().componentName(), false);
2110 
2111         KConfigGroup configGroupInterface =  KSharedConfig::openConfig()->group("Interface");
2112         const bool showDockerTitleBar = configGroupInterface.readEntry("ShowDockerTitleBars", true);
2113         foreach (QDockWidget *wdg, d->dockWidgets) {
2114             if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
2115                 if (wdg->titleBarWidget()) {
2116                     wdg->titleBarWidget()->setVisible(showDockerTitleBar);
2117                 }
2118                 wdg->setVisible(true);
2119             }
2120         }
2121 
2122         // Create and plug toolbar list for Settings menu
2123         foreach(QWidget* it, factory->containers("ToolBar")) {
2124             KToolBar * toolBar = ::qobject_cast<KToolBar *>(it);
2125             if (toolBar) {
2126                 KToggleAction * act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this);
2127                 actionCollection()->addAction(toolBar->objectName().toUtf8(), act);
2128                 act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle())));
2129                 connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool)));
2130                 act->setChecked(!toolBar->isHidden());
2131                 d->toolbarList.append(act);
2132             } else
2133                 warnMain << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!";
2134         }
2135         plugActionList("toolbarlist", d->toolbarList);
2136 
2137     }
2138     else {
2139         d->activeView = 0;
2140         d->activePart = 0;
2141     }
2142 
2143     if (d->activeView) {
2144         d->activeView->guiActivateEvent(true);
2145     }
2146 }
2147 
2148 void KoMainWindow::slotWidgetDestroyed()
2149 {
2150     debugMain;
2151     if ( static_cast<const QWidget *>( sender() ) == d->m_activeWidget )
2152         setActivePart(0, 0); //do not remove the part because if the part's widget dies, then the
2153     //part will delete itself anyway, invoking removePart() in its destructor
2154 }
2155 
2156 void KoMainWindow::slotDocumentTitleModified(const QString &caption, bool mod)
2157 {
2158     updateCaption(caption, mod);
2159     updateReloadFileAction(d->rootDocument);
2160     updateVersionsFileAction(d->rootDocument);
2161 
2162 }
2163 
2164 void KoMainWindow::showDockerTitleBars(bool show)
2165 {
2166     foreach (QDockWidget *dock, dockWidgets()) {
2167         if (dock->titleBarWidget()) {
2168             dock->titleBarWidget()->setVisible(show);
2169         }
2170     }
2171 
2172     KConfigGroup configGroupInterface =  KSharedConfig::openConfig()->group("Interface");
2173     configGroupInterface.writeEntry("ShowDockerTitleBars", show);
2174 }