Warning, file /office/calligra/gemini/MainWindow.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 * SPDX-FileCopyrightText: 2012 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * SPDX-FileCopyrightText: 2012 KO GmbH. Contact : Boudewijn Rempt <boud@kogmbh.com> 0004 * SPDX-FileCopyrightText: 2013 Dan Leinir Turthra Jensen <admin@leinir.dk> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "MainWindow.h" 0010 #include <QHBoxLayout> 0011 #include "desktopviewproxy.h" 0012 0013 #include <QApplication> 0014 #include <QResizeEvent> 0015 #include <QQuickWidget> 0016 #include <QQmlContext> 0017 #include <QQmlEngine> 0018 #include <QGraphicsObject> 0019 #include <QDir> 0020 #include <QFile> 0021 #include <QMessageBox> 0022 #include <QToolButton> 0023 #include <QMenuBar> 0024 #include <QAction> 0025 #include <QDesktopWidget> 0026 #include <QFileInfo> 0027 #include <QUrl> 0028 #include <QStandardPaths> 0029 0030 #include <kactioncollection.h> 0031 #include <ktoolbar.h> 0032 #include <kmessagebox.h> 0033 #include <KConfigGroup> 0034 #include <KSharedConfig> 0035 0036 #include <gemini/ViewModeSwitchEvent.h> 0037 #include <KoCanvasBase.h> 0038 #include <KoToolManager.h> 0039 #include <KoMainWindow.h> 0040 #include <KoGlobal.h> 0041 #include <KoDocumentInfo.h> 0042 #include <KoView.h> 0043 #include <KoPart.h> 0044 #include <KoDocumentEntry.h> 0045 #include <KoFilterManager.h> 0046 #include <part/KWFactory.h> 0047 #include <stage/part/KPrDocument.h> 0048 #include <stage/part/KPrFactory.h> 0049 #include <stage/part/KPrViewModePresentation.h> 0050 #include <KoAbstractGradient.h> 0051 #include <KoZoomController.h> 0052 #include <KoFileDialog.h> 0053 #include <KoDialog.h> 0054 #include <KoIcon.h> 0055 0056 #include "PropertyContainer.h" 0057 #include "RecentFileManager.h" 0058 #include "DocumentManager.h" 0059 #include "QmlGlobalEngine.h" 0060 #include "Settings.h" 0061 #include "Theme.h" 0062 #include "DocumentListModel.h" 0063 #include "Constants.h" 0064 #include "SimpleTouchArea.h" 0065 #include "ToolManager.h" 0066 #include "ParagraphStylesModel.h" 0067 #include "KeyboardModel.h" 0068 #include "ScribbleArea.h" 0069 #include "RecentImageImageProvider.h" 0070 #include "RecentFilesModel.h" 0071 #include "TemplatesModel.h" 0072 #include "CloudAccountsModel.h" 0073 0074 #ifdef Q_OS_WIN 0075 // Slate mode/docked detection stuff 0076 #include <Shellapi.h> 0077 #define SM_CONVERTIBLESLATEMODE 0x2003 0078 #define SM_SYSTEMDOCKED 0x2004 0079 #endif 0080 0081 class MainWindow::Private 0082 { 0083 public: 0084 Private(MainWindow* qq) 0085 : q(qq) 0086 , allowClose(true) 0087 , touchView(0) 0088 , desktopView(0) 0089 , currentView(0) 0090 , settings(0) 0091 , slateMode(false) 0092 , docked(false) 0093 , touchKoView(0) 0094 , touchEventReceiver(0) 0095 , desktopKoView(0) 0096 , desktopViewProxy(0) 0097 , forceDesktop(false) 0098 , forceTouch(false) 0099 , temporaryFile(false) 0100 , syncObject(0) 0101 , toDesktop(0) 0102 , toTouch(0) 0103 , switcher(0) 0104 , alternativeSaveAction(0) 0105 { 0106 #ifdef Q_OS_WIN 0107 // slateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); 0108 // docked = (GetSystemMetrics(SM_SYSTEMDOCKED) != 0); 0109 #endif 0110 fullScreenThrottle = new QTimer(qq); 0111 fullScreenThrottle->setInterval(500); 0112 fullScreenThrottle->setSingleShot(true); 0113 } 0114 MainWindow* q; 0115 bool allowClose; 0116 QQuickWidget* touchView; 0117 QPointer<KoMainWindow> desktopView; 0118 QObject* currentView; 0119 Settings *settings; 0120 0121 bool slateMode; 0122 bool docked; 0123 QString currentTouchPage; 0124 KoView* touchKoView; 0125 QObject* touchEventReceiver; 0126 KoView* desktopKoView; 0127 DesktopViewProxy* desktopViewProxy; 0128 0129 bool forceDesktop; 0130 bool forceTouch; 0131 bool temporaryFile; 0132 ViewModeSynchronisationObject* syncObject; 0133 0134 QAction* toDesktop; 0135 QAction* toTouch; 0136 QToolButton* switcher; 0137 QAction* alternativeSaveAction; 0138 QTimer* fullScreenThrottle; 0139 0140 void shouldAcceptTouchEvents(QWidget* widget) { 0141 // See https://bugreports.qt.io/browse/QTBUG-66718 0142 static QVersionNumber qtVersion = QVersionNumber::fromString(qVersion()); 0143 static bool shouldWidgetAcceptTouchEvents = qtVersion > QVersionNumber(5, 9, 3) && qtVersion.normalized() != QVersionNumber(5, 10); 0144 if(shouldWidgetAcceptTouchEvents) 0145 { 0146 widget->setAttribute(Qt::WA_AcceptTouchEvents, true); 0147 } 0148 } 0149 0150 void initTouchView(QObject* parent) 0151 { 0152 touchView = new QQuickWidget(); 0153 shouldAcceptTouchEvents(touchView); 0154 QmlGlobalEngine::instance()->setEngine(touchView->engine()); 0155 touchView->engine()->rootContext()->setContextObject(new KLocalizedContext(touchView)); 0156 touchView->engine()->addImageProvider(QLatin1String("recentimage"), new RecentImageImageProvider); 0157 touchView->engine()->rootContext()->setContextProperty("mainWindow", parent); 0158 0159 settings = new Settings( q ); 0160 DocumentManager::instance()->setSettingsManager( settings ); 0161 touchView->engine()->rootContext()->setContextProperty("DocumentManager", DocumentManager::instance()); 0162 touchView->engine()->rootContext()->setContextProperty("Settings", settings); 0163 touchView->engine()->rootContext()->setContextProperty("Constants", new Constants( q )); 0164 touchView->engine()->rootContext()->setContextProperty("RecentFileManager", DocumentManager::instance()->recentFileManager()); 0165 touchView->engine()->rootContext()->setContextProperty("WORDS_MIME_TYPE", QString(WORDS_MIME_TYPE)); 0166 touchView->engine()->rootContext()->setContextProperty("STAGE_MIME_TYPE", QString(STAGE_MIME_TYPE)); 0167 0168 #ifdef Q_OS_WIN 0169 QDir appdir(qApp->applicationDirPath()); 0170 0171 // Corrects for mismatched case errors in path (qtdeclarative fails to load) 0172 wchar_t buffer[1024]; 0173 QString absolute = appdir.absolutePath(); 0174 DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024); 0175 rv = ::GetLongPathName(buffer, buffer, 1024); 0176 QString correctedPath((QChar *)buffer); 0177 appdir.setPath(correctedPath); 0178 0179 // for now, the app in bin/ and we still use the env.bat script 0180 appdir.cdUp(); 0181 0182 // QT5TODO: adapt to QML_IMPORT_PATH usage and install to ${QML_INSTALL_DIR} 0183 touchView->engine()->addImportPath(appdir.canonicalPath() + "/imports"); 0184 touchView->engine()->addImportPath(appdir.canonicalPath() + "/lib/calligra/imports"); 0185 touchView->engine()->addImportPath(appdir.canonicalPath() + "/lib64/calligra/imports"); 0186 touchView->engine()->addImportPath(appdir.canonicalPath() + "/bin/data/calligragemini"); 0187 QString mainqml = appdir.canonicalPath() + "/bin/data/calligragemini/calligragemini.qml"; 0188 #else 0189 QString mainqml = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("calligragemini/calligragemini.qml")); 0190 #endif 0191 0192 Q_ASSERT(QFile::exists(mainqml)); 0193 if (!QFile::exists(mainqml)) { 0194 QMessageBox::warning(0, "No QML found", mainqml + " doesn't exist."); 0195 } 0196 QFileInfo fi(mainqml); 0197 0198 touchView->setSource(QUrl::fromLocalFile(fi.canonicalFilePath())); 0199 touchView->setResizeMode( QQuickWidget::SizeRootObjectToView ); 0200 0201 toDesktop = new QAction(q); 0202 toDesktop->setEnabled(true); 0203 toDesktop->setText(tr("Switch to Desktop")); 0204 // useful for monkey-testing to crash... 0205 //toDesktop->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_D); 0206 //q->addAction(toDesktop); 0207 //connect(toDesktop, SIGNAL(triggered(bool)), q, SLOT(switchDesktopForced())); 0208 connect(toDesktop, &QAction::triggered, q, &MainWindow::switchToDesktop); 0209 touchView->engine()->rootContext()->setContextProperty("switchToDesktopAction", toDesktop); 0210 } 0211 0212 void initDesktopView() 0213 { 0214 if(settings->currentFile().isEmpty()) { 0215 return; 0216 } 0217 // Initialize all Calligra directories etc. 0218 KoGlobal::initialize(); 0219 0220 // The default theme is not what we want for Gemini 0221 KConfigGroup group(KSharedConfig::openConfig(), "theme"); 0222 if(group.readEntry("Theme", "no-theme-is-set") == QLatin1String("no-theme-is-set")) { 0223 group.writeEntry("Theme", "Krita-dark"); 0224 } 0225 0226 if(settings->currentFileClass() == WORDS_MIME_TYPE) { 0227 qApp->setApplicationName("calligrawords"); 0228 desktopView = new KoMainWindow(WORDS_MIME_TYPE, KWFactory::componentData()); 0229 } else if(settings->currentFileClass() == STAGE_MIME_TYPE) { 0230 qApp->setApplicationName("calligrastage"); 0231 desktopView = new KoMainWindow(STAGE_MIME_TYPE, KPrFactory::componentData()); 0232 } else { 0233 desktopView = 0; 0234 qDebug() << "Big trouble, things gonna break. desktopView is not created." << settings->currentFileClass(); 0235 return; 0236 } 0237 0238 toTouch = new QAction(desktopView); 0239 toTouch->setEnabled(false); 0240 toTouch->setText(tr("Switch to Touch")); 0241 toTouch->setIcon(koIcon("system-reboot")); 0242 toTouch->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_S); 0243 //connect(toTouch, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), q, SLOT(switchTouchForced())); 0244 connect(toTouch, &QAction::triggered, q, &MainWindow::switchToTouch); 0245 desktopView->actionCollection()->addAction("SwitchToTouchView", toTouch); 0246 switcher = new QToolButton(); 0247 switcher->setEnabled(false); 0248 switcher->setText(tr("Switch to Touch")); 0249 switcher->setIcon(koIcon("system-reboot")); 0250 switcher->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0251 //connect(switcher, SIGNAL(clicked(bool)), q, SLOT(switchDesktopForced())); 0252 connect(switcher, &QAbstractButton::clicked, q, &MainWindow::switchToTouch); 0253 desktopView->menuBar()->setCornerWidget(switcher); 0254 0255 // DesktopViewProxy connects itself up to everything appropriate on construction, 0256 // and destroys itself again when the view is removed 0257 desktopViewProxy = new DesktopViewProxy(q, desktopView); 0258 connect(desktopViewProxy, &DesktopViewProxy::documentSaved, q, &MainWindow::documentSaved); 0259 connect(desktopViewProxy, &DesktopViewProxy::documentSaved, q, &MainWindow::resetWindowTitle); 0260 connect(desktopViewProxy, &DesktopViewProxy::documentSaved, q, &MainWindow::enableAltSaveAction); 0261 } 0262 0263 void notifySlateModeChange(); 0264 void notifyDockingModeChange(); 0265 bool queryClose(); 0266 void altSaveQuery(); 0267 }; 0268 0269 MainWindow::MainWindow(QStringList fileNames, QWidget* parent, Qt::WindowFlags flags ) 0270 : QMainWindow( parent, flags ), d( new Private(this) ) 0271 { 0272 qmlRegisterUncreatableType<PropertyContainer>("org.calligra", 1, 0, "PropertyContainer", "Contains properties and naively extends QML to support dynamic properties"); 0273 qmlRegisterType<Theme>("org.calligra", 1, 0, "Theme"); 0274 qmlRegisterType<DocumentListModel>("org.calligra", 1, 0, "DocumentListModel"); 0275 qmlRegisterType<SimpleTouchArea>("org.calligra", 1, 0, "SimpleTouchArea"); 0276 qmlRegisterType<ToolManager>("org.calligra", 1, 0, "ToolManager"); 0277 qmlRegisterType<ParagraphStylesModel>("org.calligra", 1, 0, "ParagraphStylesModel"); 0278 qmlRegisterType<KeyboardModel>("org.calligra", 1, 0, "KeyboardModel"); 0279 qmlRegisterType<ScribbleArea>("org.calligra", 1, 0, "ScribbleArea"); 0280 qmlRegisterType<RecentFilesModel>("org.calligra", 1, 0, "RecentFilesModel"); 0281 qmlRegisterType<TemplatesModel>("org.calligra", 1, 0, "TemplatesModel"); 0282 qmlRegisterType<CloudAccountsModel>("org.calligra", 1, 0, "CloudAccountsModel"); 0283 qmlRegisterType<KPrViewModePresentation>(); 0284 qRegisterMetaType<QAction*>(); 0285 0286 qApp->setActiveWindow( this ); 0287 setWindowTitle(i18n("Calligra Gemini")); 0288 setWindowIcon(koIcon("calligragemini"));//gemini")); 0289 resize(QApplication::desktop()->availableGeometry().size() * 3/4); 0290 d->shouldAcceptTouchEvents(this); 0291 0292 foreach(const QString &fileName, fileNames) { 0293 DocumentManager::instance()->recentFileManager()->addRecent( QDir::current().absoluteFilePath( fileName ) ); 0294 } 0295 0296 connect(DocumentManager::instance(), &DocumentManager::documentChanged, this, &MainWindow::documentChanged); 0297 connect(DocumentManager::instance(), &DocumentManager::documentChanged, this, &MainWindow::resetWindowTitle); 0298 connect(DocumentManager::instance(), &DocumentManager::documentSaved, this, &MainWindow::resetWindowTitle); 0299 connect(DocumentManager::instance(), &DocumentManager::documentSaved, this, &MainWindow::enableAltSaveAction); 0300 connect(DocumentManager::instance(), &DocumentManager::aboutToDeleteDocument, this, &MainWindow::closeWindow); 0301 0302 d->initTouchView(this); 0303 0304 // Set the initial view to touch... because reasons. 0305 // Really, this allows us to show the pleasant welcome screen from Touch 0306 switchToTouch(); 0307 0308 if(!fileNames.isEmpty()) { 0309 //It feels a little hacky, but call a QML function to open files. 0310 //This saves a lot of hassle required to change state for loading dialogs etc. 0311 QMetaObject::invokeMethod(d->touchView->rootObject(), "openFile", Q_ARG(QVariant, fileNames.at(0))); 0312 } 0313 } 0314 0315 void MainWindow::resetWindowTitle() 0316 { 0317 KoDocument* document = DocumentManager::instance()->document(); 0318 if (!document) 0319 return; 0320 QUrl url = document->url(); 0321 QString fileName = url.fileName(); 0322 if(url.scheme() == "temp" || url.isEmpty()) 0323 fileName = i18n("Untitled"); 0324 0325 KoDialog::CaptionFlags flags = KoDialog::HIGCompliantCaption; 0326 if ( document->isModified() ) { 0327 flags |= KoDialog::ModifiedCaption; 0328 } 0329 0330 setWindowTitle( KoDialog::makeStandardCaption(fileName, this, flags) ); 0331 } 0332 0333 void MainWindow::switchDesktopForced() 0334 { 0335 if (d->slateMode) 0336 d->forceDesktop = true; 0337 d->forceTouch = false; 0338 } 0339 0340 void MainWindow::switchTouchForced() 0341 { 0342 if (!d->slateMode) 0343 d->forceTouch = true; 0344 d->forceDesktop = false; 0345 } 0346 0347 void MainWindow::switchToTouch() 0348 { 0349 QElapsedTimer timer; 0350 timer.start(); 0351 qDebug() << "Switching to touch"; 0352 0353 if (d->toTouch) 0354 { 0355 d->toTouch->setEnabled(false); 0356 d->switcher->setEnabled(false); 0357 } 0358 0359 d->syncObject = new ViewModeSynchronisationObject; 0360 0361 if (d->desktopView && centralWidget() == d->desktopView) { 0362 if (KoView* view = d->desktopView->rootView()) { 0363 //Notify the view we are switching away from that we are about to switch away from it 0364 //giving it the possibility to set up the synchronisation object. 0365 ViewModeSwitchEvent aboutToSwitchEvent(ViewModeSwitchEvent::AboutToSwitchViewModeEvent, view, d->touchView, d->syncObject); 0366 QApplication::sendEvent(view, &aboutToSwitchEvent); 0367 } 0368 d->desktopView->setParent(0); 0369 } 0370 0371 setCentralWidget(d->touchView); 0372 qApp->processEvents(); 0373 d->touchView->setVisible(true); 0374 resize(size()); 0375 emit switchedToTouch(); 0376 0377 if (d->slateMode) { 0378 if (d->syncObject->initialized) 0379 QTimer::singleShot(50, this, &MainWindow::touchChange); 0380 } 0381 else 0382 QTimer::singleShot(50, this, &MainWindow::touchChange); 0383 0384 //qDebug() << "milliseconds to switch to touch:" << timer.elapsed(); 0385 } 0386 0387 void MainWindow::touchChange() 0388 { 0389 if (centralWidget() != d->touchView || !d->syncObject) 0390 return; 0391 0392 if (d->desktopView) 0393 { 0394 //if (/*!d->touchKoView ||*/ !d->touchView->canvasWidget()) 0395 //{ 0396 // QTimer::singleShot(100, this, SLOT(touchChange())); 0397 // return; 0398 //} 0399 qApp->processEvents(); 0400 KoView* view = d->desktopView->rootView(); 0401 //Notify the new view that we just switched to it, passing our synchronisation object 0402 //so it can use those values to sync with the old view. 0403 ViewModeSwitchEvent switchedEvent(ViewModeSwitchEvent::SwitchedToTouchModeEvent, view, d->touchView, d->syncObject); 0404 QApplication::sendEvent(d->touchEventReceiver, &switchedEvent); 0405 d->syncObject = 0; 0406 qApp->processEvents(); 0407 } 0408 if (d->toDesktop) 0409 { 0410 qApp->processEvents(); 0411 d->toDesktop->setEnabled(true); 0412 } 0413 } 0414 0415 void MainWindow::switchToDesktop() 0416 { 0417 QElapsedTimer timer; 0418 timer.start(); 0419 qDebug() << "Switching to desktop"; 0420 0421 if (d->toDesktop) 0422 d->toDesktop->setEnabled(false); 0423 0424 ViewModeSynchronisationObject* syncObject = new ViewModeSynchronisationObject; 0425 0426 KoView* view = 0; 0427 if (d->desktopView) { 0428 view = d->desktopView->rootView(); 0429 } 0430 0431 if (!view) { 0432 return; 0433 } 0434 0435 //Notify the view we are switching away from that we are about to switch away from it 0436 //giving it the possibility to set up the synchronisation object. 0437 ViewModeSwitchEvent aboutToSwitchEvent(ViewModeSwitchEvent::AboutToSwitchViewModeEvent, d->touchView, view, syncObject); 0438 QApplication::sendEvent(d->touchEventReceiver, &aboutToSwitchEvent); 0439 qApp->processEvents(); 0440 0441 if (d->currentTouchPage == "MainPage") 0442 { 0443 d->touchView->setParent(0); 0444 d->touchView->setVisible(false); 0445 setCentralWidget(d->desktopView); 0446 } 0447 0448 //Notify the new view that we just switched to it, passing our synchronisation object 0449 //so it can use those values to sync with the old view. 0450 ViewModeSwitchEvent switchedEvent(ViewModeSwitchEvent::SwitchedToDesktopModeEvent, d->touchView, view, syncObject); 0451 QApplication::sendEvent(view, &switchedEvent); 0452 0453 qApp->processEvents(); 0454 d->toTouch->setEnabled(true); 0455 d->switcher->setEnabled(true); 0456 0457 //qDebug() << "milliseconds to switch to desktop:" << timer.elapsed(); 0458 } 0459 0460 void MainWindow::setDocAndPart(QObject* document, QObject* part) 0461 { 0462 if(DocumentManager::instance()->document()) { 0463 disconnect(DocumentManager::instance()->document(), &KoDocument::modified, this, &MainWindow::resetWindowTitle); 0464 } 0465 qDebug() << "Attempting to set doc and part to" << document << "and" << part; 0466 d->touchEventReceiver = d->touchView->rootObject()->findChild<QQuickItem*>("controllerItem"); 0467 DocumentManager::instance()->setDocAndPart(qobject_cast<KoDocument*>(document), qobject_cast<KoPart*>(part)); 0468 if(DocumentManager::instance()->document()) { 0469 connect(DocumentManager::instance()->document(), &KoDocument::modified, this, &MainWindow::resetWindowTitle); 0470 } 0471 if(document && part && !d->settings->currentFile().isEmpty()) { 0472 QAction* undo = qobject_cast<KoPart*>(part)->views().at(0)->action("edit_undo"); 0473 d->touchView->rootContext()->setContextProperty("undoaction", undo); 0474 QAction* redo = qobject_cast<KoPart*>(part)->views().at(0)->action("edit_redo"); 0475 d->touchView->rootContext()->setContextProperty("redoaction", redo); 0476 } 0477 resetWindowTitle(); 0478 } 0479 0480 void MainWindow::documentChanged() 0481 { 0482 if (d->desktopView) { 0483 d->desktopView->deleteLater(); 0484 d->desktopView = 0; 0485 qApp->processEvents(); 0486 } 0487 d->initDesktopView(); 0488 if(d->desktopView) { 0489 d->desktopView->setRootDocument(DocumentManager::instance()->document(), DocumentManager::instance()->part(), false); 0490 qApp->processEvents(); 0491 d->desktopKoView = d->desktopView->rootView(); 0492 emit desktopKoViewChanged(); 0493 // d->desktopKoView->setQtMainWindow(d->desktopView); 0494 // connect(d->desktopKoView, SIGNAL(sigLoadingFinished()), d->centerer, SLOT(start())); 0495 // connect(d->desktopKoView, SIGNAL(sigSavingFinished()), this, SLOT(resetWindowTitle())); 0496 // KWView* wordsview = qobject_cast<KWView*>(d->desktopView->rootView()); 0497 // if(wordsview) { 0498 // connect(wordsview->canvasBase()->resourceManager(), SIGNAL(canvasResourceChanged(int, const QVariant&)), 0499 // this, SLOT(resourceChanged(int, const QVariant&))); 0500 // } 0501 if (!d->forceTouch && !d->slateMode) 0502 switchToDesktop(); 0503 } 0504 } 0505 0506 bool MainWindow::allowClose() const 0507 { 0508 return d->allowClose; 0509 } 0510 0511 void MainWindow::setAllowClose(bool allow) 0512 { 0513 d->allowClose = allow; 0514 } 0515 0516 bool MainWindow::slateMode() const 0517 { 0518 return d->slateMode; 0519 } 0520 0521 QString MainWindow::currentTouchPage() const 0522 { 0523 return d->currentTouchPage; 0524 } 0525 0526 void MainWindow::setCurrentTouchPage(QString newPage) 0527 { 0528 d->currentTouchPage = newPage; 0529 emit currentTouchPageChanged(); 0530 0531 if (newPage == "MainPage") 0532 { 0533 if (!d->forceTouch && !d->slateMode) 0534 { 0535 // Just loaded to desktop, do nothing 0536 } 0537 else 0538 { 0539 //QTimer::singleShot(3000, this, SLOT(adjustZoomOnDocumentChangedAndStuff())); 0540 } 0541 } 0542 } 0543 0544 void MainWindow::setAlternativeSaveAction(QAction* altAction) 0545 { 0546 // if mainwindow exists, and alt action exists, remove alt action from current mainwindow 0547 if(d->desktopView && d->alternativeSaveAction) { 0548 d->desktopView->actionCollection()->removeAction(d->alternativeSaveAction); 0549 d->desktopView->actionCollection()->action("file_save")->disconnect(d->alternativeSaveAction); 0550 } 0551 d->alternativeSaveAction = altAction; 0552 // if mainwindow exists, set alt action into current mainwindow 0553 if(d->desktopView && d->alternativeSaveAction) { 0554 QAction* cloudSave = d->desktopView->actionCollection()->addAction("cloud_save", d->alternativeSaveAction); 0555 KToolBar* tb = d->desktopView->toolBar("mainToolBar"); 0556 if(tb) { 0557 tb->removeAction(cloudSave); 0558 // find the action /after/ the save action (because we want the alt save there, not before it) 0559 QAction* saveAction = d->desktopView->actionCollection()->action("file_save"); 0560 QAction* afterSave = 0; 0561 bool useNext = false; 0562 Q_FOREACH(QAction* action, tb->actions()) { 0563 if(useNext) { 0564 afterSave = action; 0565 break; 0566 } 0567 if(action == saveAction) { 0568 useNext = true; 0569 } 0570 } 0571 if(afterSave) { 0572 tb->insertAction(afterSave, cloudSave); 0573 } else { 0574 tb->addAction(cloudSave); 0575 } 0576 } 0577 } 0578 if(d->alternativeSaveAction) { 0579 // disabled for a start - this is called on load completion, so let's just assume we're not ready to reupload yet 0580 d->alternativeSaveAction->setEnabled(false); 0581 } 0582 } 0583 0584 void MainWindow::enableAltSaveAction() 0585 { 0586 if(d->alternativeSaveAction) { 0587 d->alternativeSaveAction->setEnabled(true); 0588 } 0589 } 0590 0591 void MainWindow::openFile() 0592 { 0593 QStringList mimeFilter; 0594 0595 KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(WORDS_MIME_TYPE); 0596 if (!entry.isEmpty()) { 0597 QJsonObject json = entry.metaData(); 0598 QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList(); 0599 0600 mimeFilter << KoFilterManager::mimeFilter(WORDS_MIME_TYPE, 0601 KoFilterManager::Import, 0602 mimeTypes); 0603 } 0604 entry = KoDocumentEntry::queryByMimeType(STAGE_MIME_TYPE); 0605 if (!entry.isEmpty()) { 0606 QJsonObject json = entry.metaData(); 0607 QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList(); 0608 mimeFilter << KoFilterManager::mimeFilter(STAGE_MIME_TYPE, 0609 KoFilterManager::Import, 0610 mimeTypes); 0611 } 0612 0613 KoFileDialog dialog(d->desktopView, KoFileDialog::OpenFile, "OpenDocument"); 0614 dialog.setCaption(i18n("Open Document")); 0615 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); 0616 dialog.setMimeTypeFilters(mimeFilter); 0617 QString filename = dialog.filename(); 0618 if(!filename.isEmpty()) { 0619 QMetaObject::invokeMethod(d->touchView->rootObject(), "openFile", Q_ARG(QVariant, filename), Q_ARG(QVariant, 0)); 0620 } 0621 } 0622 0623 bool MainWindow::temporaryFile() const 0624 { 0625 return d->temporaryFile; 0626 } 0627 0628 void MainWindow::setTemporaryFile(bool newValue) 0629 { 0630 d->temporaryFile = newValue; 0631 emit temporaryFileChanged(); 0632 } 0633 0634 bool MainWindow::fullScreen() const 0635 { 0636 return Qt::WindowFullScreen == (windowState() & Qt::WindowFullScreen); 0637 } 0638 0639 void MainWindow::setFullScreen(bool newValue) 0640 { 0641 if(newValue) { 0642 if(d->fullScreenThrottle->isActive()) { 0643 // not a good thing... you need to avoid this happening. This exists to avoid a death-loop, 0644 // such as what might happen if readermode is enabled when the window is not maximised 0645 // as this causes a resize loop which makes readermode switch between enabled and disabled, 0646 // which in turn makes fullScreen be set and reset all the time... very bad, so let's try 0647 // and avoid that. 0648 } 0649 else { 0650 setWindowState(windowState() | Qt::WindowFullScreen); 0651 } 0652 } 0653 else { 0654 // this is really unpleasant... however, fullscreen is very twitchy, and exiting it as below 0655 // will cause an inconsistent state, so we simply assume exiting fullscreen leaves you maximised. 0656 // It isn't optimal, but it is the best state for now, this has taken too long to work out. 0657 // setWindowState(windowState() & ~Qt::WindowFullScreen); 0658 // should really do it, but... it doesn't. So, we end up with what we have next: 0659 showMaximized(); 0660 } 0661 d->fullScreenThrottle->start(); 0662 emit fullScreenChanged(); 0663 } 0664 0665 QObject* MainWindow::desktopKoView() const 0666 { 0667 return d->desktopKoView; 0668 } 0669 0670 int MainWindow::lastScreen() const 0671 { 0672 QDesktopWidget desktop; 0673 return desktop.screenCount() - 1; 0674 } 0675 0676 void MainWindow::resourceChanged(int key, const QVariant& v) 0677 { 0678 Q_UNUSED(key) 0679 Q_UNUSED(v) 0680 if(centralWidget() == d->touchView) 0681 return; 0682 } 0683 0684 void MainWindow::resourceChangedTouch(int key, const QVariant& v) 0685 { 0686 Q_UNUSED(key) 0687 Q_UNUSED(v) 0688 if(centralWidget() == d->desktopView) 0689 return; 0690 } 0691 0692 void MainWindow::minimize() 0693 { 0694 setWindowState(windowState() ^ Qt::WindowMinimized); 0695 } 0696 0697 void MainWindow::closeWindow() 0698 { 0699 if (d->desktopView) { 0700 d->desktopView->setNoCleanup(true); 0701 if (centralWidget() == d->desktopView) 0702 d->allowClose = d->queryClose(); 0703 } 0704 0705 if (d->allowClose) 0706 { 0707 d->altSaveQuery(); 0708 d->settings->setCurrentFile(""); 0709 } 0710 qApp->processEvents(); 0711 qApp->quit(); 0712 } 0713 0714 bool MainWindow::Private::queryClose() 0715 { 0716 desktopView->setNoCleanup(true); 0717 if (DocumentManager::instance()->document() == 0) 0718 return true; 0719 0720 // main doc + internally stored child documents 0721 if (DocumentManager::instance()->document()->isModified()) { 0722 auto url = DocumentManager::instance()->document()->defaultUrl(); 0723 0724 int res = KMessageBox::warningYesNoCancel(q, 0725 i18n("<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>", url.fileName()), 0726 QString(), 0727 KStandardGuiItem::save(), 0728 KStandardGuiItem::discard()); 0729 0730 switch (res) { 0731 case KMessageBox::Yes : { 0732 if (DocumentManager::instance()->isTemporaryFile() && !desktopViewProxy->fileSaveAs()) 0733 return false; 0734 if (!DocumentManager::instance()->save()) 0735 return false; 0736 break; 0737 } 0738 case KMessageBox::No : 0739 DocumentManager::instance()->document()->removeAutoSaveFiles(); 0740 DocumentManager::instance()->document()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything. 0741 break; 0742 default : // case KMessageBox::Cancel : 0743 return false; 0744 } 0745 } 0746 return true; 0747 } 0748 0749 void MainWindow::Private::altSaveQuery() 0750 { 0751 if(alternativeSaveAction && alternativeSaveAction->isEnabled()) 0752 { 0753 int res = KMessageBox::warningYesNo(q, i18n("<p>The cloud copy of the document is out of date. Do you want to upload a new copy?</p>")); 0754 switch (res) { 0755 case KMessageBox::Yes : { 0756 alternativeSaveAction->trigger(); 0757 while(alternativeSaveAction->isEnabled()) { 0758 qApp->processEvents(); 0759 } 0760 break; 0761 } 0762 case KMessageBox::No : 0763 default: 0764 break; 0765 } 0766 } 0767 } 0768 0769 void MainWindow::closeEvent(QCloseEvent* event) 0770 { 0771 if (centralWidget() == d->desktopView) 0772 { 0773 KoDocument* document = DocumentManager::instance()->document(); 0774 if (document && document->isLoading()) { 0775 event->ignore(); 0776 return; 0777 } 0778 } 0779 0780 event->accept(); 0781 closeWindow(); 0782 } 0783 0784 MainWindow::~MainWindow() 0785 { 0786 delete d; 0787 } 0788 0789 #ifdef Q_OS_WIN 0790 bool MainWindow::winEvent( MSG * message, long * result ) 0791 { 0792 if (message && message->message == WM_SETTINGCHANGE && message->lParam) 0793 { 0794 if (wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) message->lParam) == 0) 0795 d->notifySlateModeChange(); 0796 else if (wcscmp(TEXT("SystemDockMode"), (TCHAR *) message->lParam) == 0) 0797 d->notifyDockingModeChange(); 0798 *result = 0; 0799 return true; 0800 } 0801 return false; 0802 } 0803 #endif 0804 0805 void MainWindow::Private::notifySlateModeChange() 0806 { 0807 #ifdef Q_OS_WIN 0808 bool bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); 0809 0810 if (slateMode != bSlateMode) 0811 { 0812 slateMode = bSlateMode; 0813 emit q->slateModeChanged(); 0814 if (forceTouch || (slateMode && !forceDesktop)) 0815 { 0816 if (!toTouch || (toTouch && toTouch->isEnabled())) 0817 q->switchToTouch(); 0818 } 0819 else 0820 { 0821 q->switchToDesktop(); 0822 } 0823 //qDebug() << "Slate mode is now" << slateMode; 0824 } 0825 #endif 0826 } 0827 0828 void MainWindow::Private::notifyDockingModeChange() 0829 { 0830 #ifdef Q_OS_WIN 0831 bool bDocked = (GetSystemMetrics(SM_SYSTEMDOCKED) != 0); 0832 0833 if (docked != bDocked) 0834 { 0835 docked = bDocked; 0836 //qDebug() << "Docking mode is now" << docked; 0837 } 0838 #endif 0839 }