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 }