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