Warning, file /office/calligra/libs/main/KoApplication.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) 2009 Thomas Zander <zander@kde.org>
0004    Copyright (C) 2012 Boudewijn Rempt <boud@valdyas.org>
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 "KoApplication.h"
0023 
0024 #include "KoGlobal.h"
0025 
0026 #ifndef QT_NO_DBUS
0027 #include "KoApplicationAdaptor.h"
0028 #include <QDBusConnection>
0029 #include <QDBusReply>
0030 #include <QDBusConnectionInterface>
0031 #endif
0032 
0033 #include "KoPrintJob.h"
0034 #include "KoDocumentEntry.h"
0035 #include "KoDocument.h"
0036 #include "KoMainWindow.h"
0037 #include "KoAutoSaveRecoveryDialog.h"
0038 #include <KoDpi.h>
0039 #include "KoPart.h"
0040 #include <KoPluginLoader.h>
0041 #include <KoConfig.h>
0042 #include <KoResourcePaths.h>
0043 #include <KoComponentData.h>
0044 
0045 #include <klocalizedstring.h>
0046 #include <kdesktopfile.h>
0047 #include <kmessagebox.h>
0048 #include <kiconloader.h>
0049 #include <MainDebug.h>
0050 #include <kconfig.h>
0051 #include <kconfiggroup.h>
0052 #include <krecentdirs.h>
0053 #include <KAboutData>
0054 #include <KSharedConfig>
0055 #include <KDBusService>
0056 
0057 #include <QFile>
0058 #include <QWidget>
0059 #include <QSysInfo>
0060 #include <QStringList>
0061 #include <QProcessEnvironment>
0062 #include <QDir>
0063 #include <QPluginLoader>
0064 #include <QCommandLineParser>
0065 #include <QMimeDatabase>
0066 #include <QTimer>
0067 
0068 #include <stdlib.h>
0069 
0070 #ifdef Q_OS_WIN
0071 #include <windows.h>
0072 #include <tchar.h>
0073 #endif
0074 
0075 
0076 #include "MainDebug.h"
0077 #include <QDesktopWidget>
0078 
0079 KoApplication* KoApplication::KoApp = 0;
0080 
0081 namespace {
0082 const QTime appStartTime(QTime::currentTime());
0083 }
0084 
0085 class KoApplicationPrivate
0086 {
0087 public:
0088     KoApplicationPrivate()
0089         : splashScreen(0)
0090     {}
0091     QByteArray nativeMimeType;
0092     QWidget *splashScreen;
0093     QList<KoPart *> partList;
0094     QString roundtripFileName;
0095     QString pdfFileName;
0096 };
0097 
0098 class KoApplication::ResetStarting
0099 {
0100 public:
0101     ResetStarting(QWidget *splash = 0)
0102         : m_splash(splash)
0103     {
0104     }
0105 
0106     ~ResetStarting()  {
0107         if (m_splash) {
0108 
0109             KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen");
0110             bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false);
0111             if (hideSplash) {
0112                 m_splash->hide();
0113             }
0114             else {
0115                 m_splash->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
0116                 QRect r(QPoint(), m_splash->size());
0117                 m_splash->move(QApplication::desktop()->screenGeometry().center() - r.center());
0118                 m_splash->setWindowTitle(qAppName());
0119                 foreach(QObject *o, m_splash->children()) {
0120                     QWidget *w = qobject_cast<QWidget*>(o);
0121                     if (w && w->isHidden()) {
0122                         w->setVisible(true);
0123                     }
0124                 }
0125 
0126                 m_splash->show();
0127             }
0128         }
0129     }
0130 
0131     QWidget *m_splash;
0132 };
0133 
0134 
0135 KoApplication::KoApplication(const QByteArray &nativeMimeType,
0136                              const QString &windowIconName,
0137                              AboutDataGenerator aboutDataGenerator,
0138                              int &argc, char **argv)
0139     : QApplication(argc, argv)
0140     , d(new KoApplicationPrivate())
0141 {
0142     QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
0143 
0144     QScopedPointer<KAboutData> aboutData(aboutDataGenerator());
0145     KAboutData::setApplicationData(*aboutData);
0146 
0147     setWindowIcon(QIcon::fromTheme(windowIconName, windowIcon()));
0148 
0149     KoApplication::KoApp = this;
0150 
0151     d->nativeMimeType = nativeMimeType;
0152     // Tell the iconloader about share/apps/calligra/icons
0153     KIconLoader::global()->addAppDir("calligra");
0154 
0155     // Initialize all Calligra directories etc.
0156     KoGlobal::initialize();
0157 
0158 #ifndef QT_NO_DBUS
0159     KDBusService service(KDBusService::Multiple);
0160 
0161     new KoApplicationAdaptor(this);
0162     QDBusConnection::sessionBus().registerObject("/application", this);
0163 #endif
0164 
0165 #ifdef Q_OS_MACX
0166     if ( QSysInfo::MacintoshVersion > QSysInfo::MV_10_8 )
0167     {
0168         // fix Mac OS X 10.9 (mavericks) font issue
0169         // https://bugreports.qt-project.org/browse/QTBUG-32789
0170         QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
0171     }
0172 
0173     setAttribute(Qt::AA_DontShowIconsInMenus, true);
0174 #endif
0175 }
0176 
0177 #if defined(Q_OS_WIN) && defined(ENV32BIT)
0178 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
0179 
0180 LPFN_ISWOW64PROCESS fnIsWow64Process;
0181 
0182 BOOL isWow64()
0183 {
0184     BOOL bIsWow64 = FALSE;
0185 
0186     //IsWow64Process is not available on all supported versions of Windows.
0187     //Use GetModuleHandle to get a handle to the DLL that contains the function
0188     //and GetProcAddress to get a pointer to the function if available.
0189 
0190     fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
0191         GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
0192 
0193     if(0 != fnIsWow64Process)
0194     {
0195         if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
0196         {
0197             //handle error
0198         }
0199     }
0200     return bIsWow64;
0201 }
0202 #endif
0203 
0204 bool KoApplication::start()
0205 {
0206     KAboutData aboutData = KAboutData::applicationData();
0207     // process commandline parameters
0208     QCommandLineParser parser;
0209     aboutData.setupCommandLine(&parser);
0210 
0211     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("print"), i18n("Only print and exit")));
0212     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("template"), i18n("Open a new document based on the given template (desktopfile name)")));
0213     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("new"), i18n("Open a new document based on the given template file")));
0214     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("dpi"), i18n("Override display DPI"), QStringLiteral("dpiX,dpiY")));
0215     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("export-pdf"), i18n("Only export to PDF and exit")));
0216     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("export-filename"), i18n("Filename for export-pdf"), QStringLiteral("filename")));
0217     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("benchmark-loading"), i18n("just load the file and then exit")));
0218     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("benchmark-loading-show-window"), i18n("load the file, show the window and progressbar and then exit")));
0219     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("profile-filename"), i18n("Filename to write profiling information into."), QStringLiteral("filename")));
0220     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("roundtrip-filename"), i18n("Load a file and save it as an ODF file. Meant for debugging."), QStringLiteral("filename")));
0221     parser.addPositionalArgument(QStringLiteral("[file(s)]"), i18n("File(s) or URL(s) to open"));
0222 
0223     parser.process(*this);
0224 
0225     aboutData.processCommandLine(&parser);
0226 
0227 #if defined(Q_OS_WIN) || defined (Q_OS_MACX)
0228 #ifdef ENV32BIT
0229     if (isWow64()) {
0230         KMessageBox::information(0,
0231                                  i18n("You are running a 32 bits build on a 64 bits Windows.\n"
0232                                       "This is not recommended.\n"
0233                                       "Please download and install the x64 build instead."),
0234                                  qApp->applicationName(),
0235                                  "calligra_32_on_64_warning");
0236 
0237     }
0238 #endif
0239     QDir appdir(applicationDirPath());
0240     appdir.cdUp();
0241 
0242     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
0243     if (!env.contains("XDG_DATA_DIRS")) {
0244         qputenv("XDG_DATA_DIRS", QFile::encodeName(appdir.absolutePath() + "/share"));
0245     }
0246     qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";"
0247                                       + appdir.absolutePath() + "/lib" + ";"
0248                                       + appdir.absolutePath() + "/lib/kde4" + ";"
0249                                       + appdir.absolutePath() + "/Frameworks" + ";"
0250                                       + appdir.absolutePath()));
0251 #endif
0252 
0253     if (d->splashScreen) {
0254         d->splashScreen->show();
0255         d->splashScreen->repaint();
0256         processEvents();
0257     }
0258 
0259     ResetStarting resetStarting(d->splashScreen); // remove the splash when done
0260     Q_UNUSED(resetStarting);
0261 
0262     // Find the part component file corresponding to the application instance name
0263     KoDocumentEntry entry;
0264     QList<QPluginLoader*> pluginLoaders = KoPluginLoader::pluginLoaders("calligra/parts", d->nativeMimeType);
0265     Q_FOREACH (QPluginLoader *loader, pluginLoaders) {
0266         if (loader->fileName().contains(applicationName()+QString("part"))) {
0267             entry = KoDocumentEntry(loader);
0268             pluginLoaders.removeOne(loader);
0269             break;
0270         }
0271     }
0272     qDeleteAll(pluginLoaders);
0273 
0274     if (entry.isEmpty()) {
0275         QMessageBox::critical(0, i18n("%1: Critical Error", applicationName()), i18n("Essential application components could not be found.\n"
0276                                                                                     "This might be an installation issue.\n"
0277                                                                                     "Try restarting or reinstalling."));
0278         return false;
0279     }
0280 
0281     // Get the command line arguments which we have to parse
0282     QString dpiValues = parser.value("dpi");
0283     if (!dpiValues.isEmpty()) {
0284         int sep = dpiValues.indexOf(QRegExp("[x, ]"));
0285         int dpiX;
0286         int dpiY = 0;
0287         bool ok = true;
0288         if (sep != -1) {
0289             dpiY = dpiValues.mid(sep + 1).toInt(&ok);
0290             dpiValues.truncate(sep);
0291         }
0292         if (ok) {
0293             dpiX = dpiValues.toInt(&ok);
0294             if (ok) {
0295                 if (!dpiY) dpiY = dpiX;
0296                 KoDpi::setDPI(dpiX, dpiY);
0297             }
0298         }
0299     }
0300     // No argument -> create an empty document
0301     const QStringList fileUrls = parser.positionalArguments();
0302 
0303     if (fileUrls.isEmpty()) {
0304         // if there's no document, add the current working directory
0305         // to the recent dirs so the open dialog and open pane show
0306         // the directory from where the app was started, instead of
0307         // the last directory from where we opened a file
0308         KRecentDirs::add(":OpenDialog", QDir::currentPath());
0309         QString errorMsg;
0310         KoPart *part = entry.createKoPart(&errorMsg);
0311         d->partList << part;
0312 
0313         if (!part) {
0314             if (!errorMsg.isEmpty())
0315                 KMessageBox::error(0, errorMsg);
0316             return false;
0317         }
0318 
0319         // XXX: the document should be separate plugin
0320         KoDocument *doc = part->document();
0321 
0322         KoMainWindow *mainWindow = part->createMainWindow();
0323         mainWindow->show();
0324         QObject::connect(doc, SIGNAL(sigProgress(int)), mainWindow, SLOT(slotProgress(int)));
0325         // for initDoc to fill in the recent docs list
0326         // and for KoDocument::slotStarted
0327         part->addMainWindow(mainWindow);
0328 
0329         // Check for autosave files from a previous run. There can be several, and
0330         // we want to offer a restore for every one. Including a nice thumbnail!
0331         QStringList autoSaveFiles;
0332 
0333         // get all possible autosave files in the home dir, this is for unsaved document autosave files
0334         // Using the extension allows to avoid relying on the mime magic when opening
0335         QMimeType mimeType = QMimeDatabase().mimeTypeForName(doc->nativeFormatMimeType());
0336         if (!mimeType.isValid()) {
0337             qFatal("It seems your installation is broken/incomplete because we failed to load the native mimetype \"%s\".", doc->nativeFormatMimeType().constData());
0338         }
0339         const QString extension = mimeType.preferredSuffix();
0340 
0341         QStringList filters;
0342         filters << QString(".%1-%2-%3-autosave%4").arg(part->componentData().componentName()).arg("*").arg("*").arg(extension);
0343 
0344 #ifdef Q_OS_WIN
0345         QDir autosaveDir = QDir::tempPath();
0346 #else
0347         QDir autosaveDir = QDir::home();
0348 #endif
0349         // all autosave files for our application
0350         autoSaveFiles = autosaveDir.entryList(filters, QDir::Files | QDir::Hidden);
0351 
0352         QStringList pids;
0353         QString ourPid;
0354         ourPid.setNum(applicationPid());
0355 
0356 #ifndef QT_NO_DBUS
0357         // all running instances of our application -- bit hackish, but we cannot get at the dbus name here, for some reason
0358         QDBusReply<QStringList> reply = QDBusConnection::sessionBus().interface()->registeredServiceNames();
0359 
0360         foreach (const QString &name, reply.value()) {
0361             if (name.contains(part->componentData().componentName())) {
0362                 // we got another instance of ourselves running, let's get the pid
0363                 QString pid = name.split('-').last();
0364                 if (pid != ourPid) {
0365                     pids << pid;
0366                 }
0367             }
0368         }
0369 #endif
0370 
0371         // remove the autosave files that are saved for other, open instances of ourselves
0372         foreach(const QString &autoSaveFileName, autoSaveFiles) {
0373             if (!QFile::exists(autosaveDir.absolutePath() + QDir::separator() + autoSaveFileName)) {
0374                 autoSaveFiles.removeAll(autoSaveFileName);
0375                 continue;
0376             }
0377             QStringList split = autoSaveFileName.split('-');
0378             if (split.size() == 4) {
0379                 if (pids.contains(split[1])) {
0380                     // We've got an active, owned autosave file. Remove.
0381                     autoSaveFiles.removeAll(autoSaveFileName);
0382                 }
0383             }
0384         }
0385 
0386         // Allow the user to make their selection
0387         if (autoSaveFiles.size() > 0) {
0388             KoAutoSaveRecoveryDialog dlg(autoSaveFiles);
0389             if (dlg.exec() == QDialog::Accepted) {
0390                 QStringList filesToRecover = dlg.recoverableFiles();
0391                 foreach (const QString &autoSaveFileName, autoSaveFiles) {
0392                     if (!filesToRecover.contains(autoSaveFileName)) {
0393                         // remove the files the user didn't want to recover
0394                         QFile::remove(autosaveDir.absolutePath() + QDir::separator() + autoSaveFileName);
0395                     }
0396                 }
0397                 autoSaveFiles = filesToRecover;
0398             }
0399             else {
0400                 // don't recover any of the files, but don't delete them either
0401                 autoSaveFiles.clear();
0402             }
0403         }
0404 
0405         if (autoSaveFiles.size() > 0) {
0406             short int numberOfOpenDocuments = 0; // number of documents open
0407             // bah, we need to re-use the document that was already created
0408             QUrl url = QUrl::fromLocalFile(autosaveDir.absolutePath() + QDir::separator() + autoSaveFiles.takeFirst());
0409             if (mainWindow->openDocument(part, url)) {
0410                 doc->resetURL();
0411                 doc->setModified(true);
0412                 // TODO: what if the app crashes immediately, before another autosave was made? better keep & rename
0413                 QFile::remove(url.toLocalFile());
0414                 numberOfOpenDocuments++;
0415             }
0416 
0417             // And then for the other autosave files, we copy & paste the code
0418             // and loop through them.
0419             foreach(const QString &autoSaveFile, autoSaveFiles) {
0420                 // For now create an empty document
0421                 QString errorMsg;
0422                 KoPart *part = entry.createKoPart(&errorMsg);
0423                 d->partList << part;
0424                 if (part) {
0425                     url = QUrl::fromLocalFile(autosaveDir.absolutePath() + QDir::separator() + autoSaveFile);
0426 
0427                     KoMainWindow *mainWindow = part->createMainWindow();
0428                     mainWindow->show();
0429                     if (mainWindow->openDocument(part, url)) {
0430                         doc->resetURL();
0431                         doc->setModified(true);
0432                         // TODO: what if the app crashes immediately, before another autosave was made? better keep & rename
0433                         QFile::remove(url.toLocalFile());
0434                         numberOfOpenDocuments++;
0435                     }
0436                 }
0437             }
0438             return (numberOfOpenDocuments > 0);
0439         }
0440         else {
0441             part->showStartUpWidget(mainWindow);
0442         }
0443 
0444     }
0445     else {
0446         const bool print = parser.isSet("print");
0447         const bool exportAsPdf = parser.isSet("export-pdf");
0448         d->pdfFileName = parser.value("export-filename");
0449         d->roundtripFileName = parser.value("roundtrip-filename");
0450         const bool doTemplate = parser.isSet("template");
0451         const bool doNew = parser.isSet("new");
0452         const bool benchmarkLoading = parser.isSet("benchmark-loading")
0453                 || parser.isSet("benchmark-loading-show-window")
0454                 || !d->roundtripFileName.isEmpty();
0455         // only show the mainWindow when no command-line mode option is passed
0456         const bool showmainWindow =
0457                 parser.isSet("benchmark-loading-show-window") || (
0458                     parser.isSet("export-pdf")) || (
0459                     !parser.isSet("benchmark-loading")
0460                     && !parser.isSet("roundtrip-filename")
0461                     && d->roundtripFileName.isEmpty());
0462         const QString profileFileName = parser.value("profile-filename");
0463 
0464         QTextStream profileoutput;
0465         QFile profileFile(profileFileName);
0466         if (!profileFileName.isEmpty()
0467                 && profileFile.open(QFile::WriteOnly | QFile::Truncate)) {
0468             profileoutput.setDevice(&profileFile);
0469         }
0470 
0471         // Loop through arguments
0472 
0473         short int numberOfOpenDocuments = 0; // number of documents open
0474         short int nPrinted = 0;
0475         // TODO: remove once Qt has proper handling itself
0476         const QRegExp withProtocolChecker( QStringLiteral("^[a-zA-Z]+:") );
0477         for (int argNumber = 0; argNumber < fileUrls.size(); ++argNumber) {
0478             const QString fileUrl = fileUrls.at(argNumber);
0479             // convert to an url
0480             const bool startsWithProtocol = (withProtocolChecker.indexIn(fileUrl) == 0);
0481             const QUrl url = startsWithProtocol ?
0482                 QUrl::fromUserInput(fileUrl) :
0483                 QUrl::fromLocalFile(QDir::current().absoluteFilePath(fileUrl));
0484 
0485             // For now create an empty document
0486             QString errorMsg;
0487             KoPart *part = entry.createKoPart(&errorMsg);
0488             d->partList << part;
0489             if (part) {
0490                 KoDocument *doc = part->document();
0491                 // show a mainWindow asap
0492                 KoMainWindow *mainWindow = part->createMainWindow();
0493                 if (showmainWindow) {
0494                     mainWindow->show();
0495                 }
0496                 if (benchmarkLoading) {
0497                     doc->setReadWrite(false);
0498                 }
0499 
0500                 if (profileoutput.device()) {
0501                     doc->setProfileStream(&profileoutput);
0502                     profileoutput << "KoApplication::start\t"
0503                                   << appStartTime.msecsTo(QTime::currentTime())
0504                                   <<"\t0" << endl;
0505                     doc->setAutoErrorHandlingEnabled(false);
0506                 }
0507                 doc->setProfileReferenceTime(appStartTime);
0508 
0509                 // are we just trying to open a Calligra-style template?
0510                 if (doTemplate) {
0511                     QString templatePath;
0512                     if (url.isLocalFile() && QFile::exists(url.toLocalFile())) {
0513                         templatePath = url.toLocalFile();
0514                         debugMain << "using full path...";
0515                     } else {
0516                         QString desktopName(fileUrls.at(argNumber));
0517                         const QString templatesResourcePath = part->templatesResourcePath();
0518 
0519                         QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName);
0520                         if (paths.isEmpty()) {
0521                             paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName);
0522                         }
0523                         if (paths.isEmpty()) {
0524                             KMessageBox::error(0, i18n("No template found for: %1", desktopName));
0525                             delete mainWindow;
0526                         } else if (paths.count() > 1) {
0527                             KMessageBox::error(0, i18n("Too many templates found for: %1", desktopName));
0528                             delete mainWindow;
0529                         } else {
0530                             templatePath = paths.at(0);
0531                         }
0532                     }
0533 
0534                     if (!templatePath.isEmpty()) {
0535                         QUrl templateBase;
0536                         templateBase.setPath(templatePath);
0537                         KDesktopFile templateInfo(templatePath);
0538 
0539                         QString templateName = templateInfo.readUrl();
0540                         QUrl templateURL;
0541                         templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName);
0542                         if (mainWindow->openDocument(part, templateURL)) {
0543                             doc->resetURL();
0544                             doc->setEmpty();
0545                             doc->setTitleModified();
0546                             debugMain << "Template loaded...";
0547                             numberOfOpenDocuments++;
0548                         } else {
0549                             KMessageBox::error(0, i18n("Template %1 failed to load.", templateURL.toDisplayString()));
0550                             delete mainWindow;
0551                         }
0552                     }
0553                     // now try to load
0554                 }
0555                 else if (doNew) {
0556                     if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) {
0557                         KMessageBox::error(0, i18n("No template found at: %1", url.toDisplayString()));
0558                         delete mainWindow;
0559                     } else {
0560                         if (mainWindow->openDocument(part, url)) {
0561                             doc->resetURL();
0562                             doc->setEmpty();
0563                             doc->setTitleModified();
0564                             debugMain << "Template loaded...";
0565                             numberOfOpenDocuments++;
0566                         } else {
0567                             KMessageBox::error(0, i18n("Template %1 failed to load.", url.toDisplayString()));
0568                             delete mainWindow;
0569                         }
0570                     }
0571                 }
0572                 else {
0573                     if (print) {
0574                         connect(
0575                             mainWindow, SIGNAL(loadCompleted(KoMainWindow *)),
0576                             this, SLOT(slotFilePrint(KoMainWindow *)));
0577                     } else if (exportAsPdf) {
0578                         connect(mainWindow, SIGNAL(loadCompleted(KoMainWindow*)),
0579                                 this, SLOT(slotExportToPdf(KoMainWindow*)));
0580                     }
0581                     if (mainWindow->openDocument(part, url)) {
0582                         if (benchmarkLoading) {
0583                             if (profileoutput.device()) {
0584                                 profileoutput << "KoApplication::start\t"
0585                                             << appStartTime.msecsTo(QTime::currentTime())
0586                                             <<"\t100" << endl;
0587                             }
0588                             QTimer::singleShot(0, this, SLOT(benchmarkLoadingFinished()));
0589                             return true; // only load one document!
0590                         }
0591                         if (print || exportAsPdf)
0592                             nPrinted++;
0593                         else
0594                             numberOfOpenDocuments++;
0595                     } else {
0596                         // .... if failed
0597                         // delete doc; done by openDocument
0598                         // delete mainWindow; done by ~KoDocument
0599                     }
0600                 }
0601 
0602                 if (profileoutput.device()) {
0603                     profileoutput << "KoApplication::start\t"
0604                                   << appStartTime.msecsTo(QTime::currentTime())
0605                                   <<"\t100" << endl;
0606                 }
0607 
0608             }
0609         }
0610         if (benchmarkLoading) {
0611             return false; // no valid urls found.
0612         }
0613         if (print || exportAsPdf)
0614             return nPrinted > 0;
0615         if (numberOfOpenDocuments == 0) // no doc, e.g. all URLs were malformed
0616             return false;
0617     }
0618 
0619     // not calling this before since the program will quit there.
0620     return true;
0621 }
0622 
0623 KoApplication::~KoApplication()
0624 {
0625     delete d;
0626 }
0627 
0628 void KoApplication::benchmarkLoadingFinished()
0629 {
0630     KoPart *part = d->partList.value(0);
0631     if (!part) {
0632         return;
0633     }
0634     KoMainWindow *mainWindow = part->mainWindows().value(0);
0635     if (!mainWindow) {
0636         return;
0637     }
0638     if (!d->roundtripFileName.isEmpty()) {
0639         part->document()->saveAs(QUrl("file:" + d->roundtripFileName));
0640     }
0641     // close the document
0642     mainWindow->slotFileQuit();
0643 }
0644 
0645 void KoApplication::setSplashScreen(QWidget *splashScreen)
0646 {
0647     d->splashScreen = splashScreen;
0648 }
0649 
0650 QList<KoPart*> KoApplication::partList() const
0651 {
0652     return d->partList;
0653 }
0654 
0655 QStringList KoApplication::mimeFilter(KoFilterManager::Direction direction) const
0656 {
0657     KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(d->nativeMimeType);
0658     QJsonObject json = entry.metaData();
0659 #ifdef CALLIGRA_OLD_PLUGIN_METADATA
0660     QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
0661 #else
0662     QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList();
0663 #endif
0664 
0665     return KoFilterManager::mimeFilter(d->nativeMimeType, direction, mimeTypes);
0666 }
0667 
0668 
0669 bool KoApplication::notify(QObject *receiver, QEvent *event)
0670 {
0671     try {
0672         return QApplication::notify(receiver, event);
0673     } catch (std::exception &e) {
0674         qWarning("Error %s sending event %i to object %s",
0675                  e.what(), event->type(), qPrintable(receiver->objectName()));
0676     } catch (...) {
0677         qWarning("Error <unknown> sending event %i to object %s",
0678                  event->type(), qPrintable(receiver->objectName()));
0679     }
0680     return false;
0681 
0682 }
0683 
0684 void KoApplication::slotFilePrint(KoMainWindow *mainWindow)
0685 {
0686     mainWindow->slotFilePrint();
0687     //delete mainWindow; done by ~KoDocument
0688 }
0689 
0690 void KoApplication::slotExportToPdf(KoMainWindow *mainWindow)
0691 {
0692     KoPrintJob *job = mainWindow->exportToPdf(d->pdfFileName);
0693     // TODO: exit if all jobs over
0694 }
0695 
0696 KoApplication *KoApplication::koApplication()
0697 {
0698     return KoApp;
0699 }