diff --git a/discover/DiscoverObject.cpp b/discover/DiscoverObject.cpp index 65b7438a..c74a27a6 100644 --- a/discover/DiscoverObject.cpp +++ b/discover/DiscoverObject.cpp @@ -1,510 +1,511 @@ /* * Copyright (C) 2012 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser General Public License * version 2, or (at your option) any later version, as published by the * Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library/Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "DiscoverObject.h" #include "PaginateModel.h" #include "UnityLauncher.h" #include "FeaturedModel.h" #include "CachedNetworkAccessManager.h" #include "DiscoverDeclarativePlugin.h" #include "DiscoverBackendsFactory.h" // Qt includes #include #include "discover_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #include #include #include // #include // DiscoverCommon includes #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_FEEDBACK #include "plasmauserfeedback.h" #endif #include "discoversettings.h" class CachedNetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory { virtual QNetworkAccessManager * create(QObject *parent) override { return new CachedNetworkAccessManager(QStringLiteral("images"), parent); } }; class OurSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) public: void classBegin() override {} void componentComplete() override { if (dynamicSortFilter()) sort(0); } }; -DiscoverObject::DiscoverObject(CompactMode mode) +DiscoverObject::DiscoverObject(CompactMode mode, const QVariantMap &initialProperties) : QObject() , m_engine(new QQmlApplicationEngine) , m_mode(mode) , m_networkAccessManagerFactory(new CachedNetworkAccessManagerFactory) { setObjectName(QStringLiteral("DiscoverMain")); m_engine->rootContext()->setContextObject(new KLocalizedContext(m_engine)); auto factory = m_engine->networkAccessManagerFactory(); m_engine->setNetworkAccessManagerFactory(nullptr); delete factory; m_engine->setNetworkAccessManagerFactory(m_networkAccessManagerFactory.data()); qmlRegisterType("org.kde.discover.app", 1, 0, "UnityLauncher"); qmlRegisterType("org.kde.discover.app", 1, 0, "PaginateModel"); qmlRegisterType("org.kde.discover.app", 1, 0, "KConcatenateRowsProxyModel"); qmlRegisterType("org.kde.discover.app", 1, 0, "FeaturedModel"); qmlRegisterType("org.kde.discover.app", 1, 0, "QSortFilterProxyModel"); #ifdef WITH_FEEDBACK qmlRegisterSingletonType("org.kde.discover.app", 1, 0, "UserFeedbackSettings", [](QQmlEngine*, QJSEngine*) -> QObject* { return new PlasmaUserFeedback(KSharedConfig::openConfig(QStringLiteral("PlasmaUserFeedback"), KConfig::NoGlobals)); }); #endif qmlRegisterSingletonType("org.kde.discover.app", 1, 0, "DiscoverSettings", [](QQmlEngine*, QJSEngine*) -> QObject* { auto r = new DiscoverSettings; connect(r, &DiscoverSettings::installedPageSortingChanged, r, &DiscoverSettings::save); connect(r, &DiscoverSettings::appsListPageSortingChanged, r, &DiscoverSettings::save); return r; }); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterUncreatableType("org.kde.discover.app", 1, 0, "DiscoverMainWindow", QStringLiteral("don't do that")); setupActions(); auto uri = "org.kde.discover"; DiscoverDeclarativePlugin* plugin = new DiscoverDeclarativePlugin; plugin->setParent(this); plugin->initializeEngine(m_engine, uri); plugin->registerTypes(uri); + m_engine->setInitialProperties(initialProperties); m_engine->rootContext()->setContextProperty(QStringLiteral("app"), this); m_engine->rootContext()->setContextProperty(QStringLiteral("discoverAboutData"), QVariant::fromValue(KAboutData::applicationData())); connect(m_engine, &QQmlApplicationEngine::objectCreated, this, &DiscoverObject::integrateObject); m_engine->load(QUrl(QStringLiteral("qrc:/qml/DiscoverWindow.qml"))); connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, [this](){ const auto objs = m_engine->rootObjects(); for(auto o: objs) delete o; }); auto action = new OneTimeAction( [this]() { bool found = DiscoverBackendsFactory::hasRequestedBackends(); const auto backends = ResourcesModel::global()->backends(); for (auto b : backends) found |= b->hasApplications(); if (!found) Q_EMIT openErrorPage(i18n("No application back-ends found, please report to your distribution.")); } , this); if (ResourcesModel::global()->backends().isEmpty()) { connect(ResourcesModel::global(), &ResourcesModel::allInitialized, action, &OneTimeAction::trigger); } else { action->trigger(); } } DiscoverObject::~DiscoverObject() { delete m_engine; } bool DiscoverObject::isRoot() { return ::getuid() == 0; } QStringList DiscoverObject::modes() const { QStringList ret; QObject* obj = rootObject(); for(int i = obj->metaObject()->propertyOffset(); imetaObject()->propertyCount(); i++) { QMetaProperty p = obj->metaObject()->property(i); QByteArray compName = p.name(); if(compName.startsWith("top") && compName.endsWith("Comp")) { ret += QString::fromLatin1(compName.mid(3, compName.length()-7)); } } return ret; } void DiscoverObject::openMode(const QString& _mode) { QObject* obj = rootObject(); if (!obj) { qCWarning(DISCOVER_LOG) << "could not get the main object"; return; } if(!modes().contains(_mode, Qt::CaseInsensitive)) qCWarning(DISCOVER_LOG) << "unknown mode" << _mode << modes(); QString mode = _mode; mode[0] = mode[0].toUpper(); const QByteArray propertyName = "top"+mode.toLatin1()+"Comp"; const QVariant modeComp = obj->property(propertyName.constData()); if (!modeComp.isValid()) qCWarning(DISCOVER_LOG) << "couldn't open mode" << _mode; else obj->setProperty("currentTopLevel", modeComp); } void DiscoverObject::openMimeType(const QString& mime) { emit listMimeInternal(mime); } void DiscoverObject::openCategory(const QString& category) { setRootObjectProperty("defaultStartup", false); auto action = new OneTimeAction( [this, category]() { Category* cat = CategoryModel::global()->findCategoryByName(category); if (cat) { emit listCategoryInternal(cat); } else { showPassiveNotification(i18n("Could not find category '%1'", category)); setRootObjectProperty("defaultStartup", true); } } , this); if (CategoryModel::global()->rootCategories().isEmpty()) { connect(CategoryModel::global(), &CategoryModel::rootCategoriesChanged, action, &OneTimeAction::trigger); } else { action->trigger(); } } void DiscoverObject::openLocalPackage(const QUrl& localfile) { if (!QFile::exists(localfile.toLocalFile())) { // showPassiveNotification(i18n("Trying to open unexisting file '%1'", localfile.toString())); qCWarning(DISCOVER_LOG) << "Trying to open unexisting file" << localfile; return; } setRootObjectProperty("defaultStartup", false); auto action = new OneTimeAction( [this, localfile]() { AbstractResourcesBackend::Filters f; f.resourceUrl = localfile; auto stream = new StoredResultsStream({ResourcesModel::global()->search(f)}); connect(stream, &StoredResultsStream::finishedResources, this, [this, localfile](const QVector &res) { if (res.count() == 1) { emit openApplicationInternal(res.first()); } else { QMimeDatabase db; auto mime = db.mimeTypeForUrl(localfile); auto fIsFlatpakBackend = [](AbstractResourcesBackend* backend) { return backend->metaObject()->className() == QByteArray("FlatpakBackend"); }; if (mime.name().startsWith(QLatin1String("application/vnd.flatpak")) && !kContains(ResourcesModel::global()->backends(), fIsFlatpakBackend)) { openApplication(QUrl(QStringLiteral("appstream://org.kde.discover.flatpak"))); showPassiveNotification(i18n("Cannot interact with flatpak resources without the flatpak backend %1. Please install it first.", localfile.toDisplayString())); } else { setRootObjectProperty("defaultStartup", true); showPassiveNotification(i18n("Couldn't open %1", localfile.toDisplayString())); } } }); } , this); if (ResourcesModel::global()->backends().isEmpty()) { connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, action, &OneTimeAction::trigger); } else { action->trigger(); } } void DiscoverObject::openApplication(const QUrl& url) { Q_ASSERT(!url.isEmpty()); setRootObjectProperty("defaultStartup", false); auto action = new OneTimeAction( [this, url]() { AbstractResourcesBackend::Filters f; f.resourceUrl = url; auto stream = new StoredResultsStream({ResourcesModel::global()->search(f)}); connect(stream, &StoredResultsStream::finishedResources, this, [this, url](const QVector &res) { if (res.count() >= 1) { emit openApplicationInternal(res.first()); } else { setRootObjectProperty("defaultStartup", true); Q_EMIT openErrorPage(i18n("Couldn't open %1", url.toDisplayString())); } }); } , this); if (ResourcesModel::global()->backends().isEmpty()) { connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, action, &OneTimeAction::trigger); } else { action->trigger(); } } void DiscoverObject::integrateObject(QObject* object) { if (!object) { qCWarning(DISCOVER_LOG) << "Errors when loading the GUI"; QTimer::singleShot(0, QCoreApplication::instance(), [](){ QCoreApplication::instance()->exit(1); }); return; } Q_ASSERT(object == rootObject()); KConfigGroup window(KSharedConfig::openConfig(), "Window"); if (window.hasKey("geometry")) rootObject()->setGeometry(window.readEntry("geometry", QRect())); if (window.hasKey("visibility")) { QWindow::Visibility visibility(QWindow::Visibility(window.readEntry("visibility", QWindow::Windowed))); rootObject()->setVisibility(qMax(visibility, QQuickView::AutomaticVisibility)); } object->installEventFilter(this); connect(object, &QObject::destroyed, qGuiApp, &QCoreApplication::quit); object->setParent(m_engine); connect(qGuiApp, &QGuiApplication::commitDataRequest, this, [this](QSessionManager &sessionManager) { if (ResourcesModel::global()->isBusy()) { Q_EMIT preventedClose(); sessionManager.cancel(); } }); } bool DiscoverObject::eventFilter(QObject * object, QEvent * event) { if (object!=rootObject()) return false; if (event->type() == QEvent::Close) { if (ResourcesModel::global()->isBusy()) { qCWarning(DISCOVER_LOG) << "not closing because there's still pending tasks"; Q_EMIT preventedClose(); return true; } KConfigGroup window(KSharedConfig::openConfig(), "Window"); window.writeEntry("geometry", rootObject()->geometry()); window.writeEntry("visibility", rootObject()->visibility()); // } else if (event->type() == QEvent::ShortcutOverride) { // qCWarning(DISCOVER_LOG) << "Action conflict" << event; } return false; } void DiscoverObject::setupActions() { if (KAuthorized::authorizeAction(QStringLiteral("help_report_bug")) && !KAboutData::applicationData().bugAddress().isEmpty()) { auto mReportBugAction = KStandardAction::reportBug(this, &DiscoverObject::reportBug, this); m_collection[mReportBugAction->objectName()] = mReportBugAction; } if (KAuthorized::authorizeAction(QStringLiteral("help_about_app"))) { auto mAboutAppAction = KStandardAction::aboutApp(this, &DiscoverObject::aboutApplication, this); m_collection[mAboutAppAction->objectName()] = mAboutAppAction; } } QAction * DiscoverObject::action(const QString& name) const { return m_collection.value(name); } QString DiscoverObject::iconName(const QIcon& icon) { return icon.name(); } void DiscoverObject::aboutApplication() { static QPointer dialog; if (!dialog) { dialog = new KAboutApplicationDialog(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); } void DiscoverObject::reportBug() { static QPointer dialog; if (!dialog) { dialog = new KBugReport(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); } void DiscoverObject::switchApplicationLanguage() { // auto langDialog = new KSwitchLanguageDialog(nullptr); // connect(langDialog, SIGNAL(finished(int)), this, SLOT(dialogFinished())); // langDialog->show(); } void DiscoverObject::setCompactMode(DiscoverObject::CompactMode mode) { if (m_mode != mode) { m_mode = mode; Q_EMIT compactModeChanged(m_mode); } } class DiscoverTestExecutor : public QObject { public: DiscoverTestExecutor(QObject* rootObject, QQmlEngine* engine, const QUrl &url) : QObject(engine) { connect(engine, &QQmlEngine::quit, this, &DiscoverTestExecutor::finish, Qt::QueuedConnection); QQmlComponent* component = new QQmlComponent(engine, url, engine); m_testObject = component->create(engine->rootContext()); if (!m_testObject) { qCWarning(DISCOVER_LOG) << "error loading test" << url << m_testObject << component->errors(); Q_ASSERT(false); } m_testObject->setProperty("appRoot", QVariant::fromValue(rootObject)); connect(engine, &QQmlEngine::warnings, this, &DiscoverTestExecutor::processWarnings); } void processWarnings(const QList &warnings) { foreach(const QQmlError &warning, warnings) { if (warning.url().path().endsWith(QLatin1String("DiscoverTest.qml"))) { qCWarning(DISCOVER_LOG) << "Test failed!" << warnings; qGuiApp->exit(1); } } m_warnings << warnings; } void finish() { //The CI doesn't seem to have icons, remove when it's not an issue anymore m_warnings.erase(std::remove_if(m_warnings.begin(), m_warnings.end(), [](const QQmlError& err) -> bool { return err.description().contains(QLatin1String("QML Image: Failed to get image from provider: image://icon/")); })); if (m_warnings.isEmpty()) qCDebug(DISCOVER_LOG) << "cool no warnings!"; else qCDebug(DISCOVER_LOG) << "test finished successfully despite" << m_warnings; qGuiApp->exit(m_warnings.count()); } private: QObject* m_testObject; QList m_warnings; }; void DiscoverObject::loadTest(const QUrl& url) { new DiscoverTestExecutor(rootObject(), engine(), url); } QWindow* DiscoverObject::rootObject() const { return qobject_cast(m_engine->rootObjects().at(0)); } void DiscoverObject::setRootObjectProperty(const char* name, const QVariant& value) { auto ro = rootObject(); if (!ro) { qCWarning(DISCOVER_LOG) << "please check your installation"; return; } rootObject()->setProperty(name, value); } void DiscoverObject::showPassiveNotification(const QString& msg) { QTimer::singleShot(100, this, [this, msg](){ QMetaObject::invokeMethod(rootObject(), "showPassiveNotification", Qt::QueuedConnection, Q_ARG(QVariant, msg), Q_ARG(QVariant, {}), Q_ARG(QVariant, {}), Q_ARG(QVariant, {})); }); } void DiscoverObject::reboot() { QDBusInterface interface(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QStringLiteral("org.kde.KSMServerInterface"), QDBusConnection::sessionBus()); interface.asyncCall(QStringLiteral("logout"), 0, 1, 2); // Options: do not ask again | reboot | force } QRect DiscoverObject::initialGeometry() const { KConfigGroup window(KSharedConfig::openConfig(), "Window"); return window.readEntry("geometry", QRect()); } #include "DiscoverObject.moc" diff --git a/discover/DiscoverObject.h b/discover/DiscoverObject.h index 6e7ace08..80ddd24c 100644 --- a/discover/DiscoverObject.h +++ b/discover/DiscoverObject.h @@ -1,102 +1,102 @@ /* * Copyright (C) 2012 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser General Public License * version 2, or (at your option) any later version, as published by the * Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library/Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DISCOVEROBJECT_H #define DISCOVEROBJECT_H #include #include class AbstractResource; class Category; class QWindow; class QQmlApplicationEngine; class CachedNetworkAccessManagerFactory; class DiscoverObject : public QObject { Q_OBJECT Q_PROPERTY(CompactMode compactMode READ compactMode WRITE setCompactMode NOTIFY compactModeChanged) Q_PROPERTY(bool isRoot READ isRoot CONSTANT) Q_PROPERTY(QRect initialGeometry READ initialGeometry CONSTANT) public: enum CompactMode { Auto, Compact, Full }; Q_ENUM(CompactMode) - explicit DiscoverObject(CompactMode mode); + explicit DiscoverObject(CompactMode mode, const QVariantMap &initialProperties); ~DiscoverObject() override; QStringList modes() const; void setupActions(); CompactMode compactMode() const { return m_mode; } void setCompactMode(CompactMode mode); bool eventFilter(QObject * object, QEvent * event) override; Q_SCRIPTABLE QAction * action(const QString& name) const; Q_SCRIPTABLE static QString iconName(const QIcon& icon); void loadTest(const QUrl& url); static bool isRoot(); QWindow* rootObject() const; void showPassiveNotification(const QString &msg); QRect initialGeometry() const; public Q_SLOTS: void openApplication(const QUrl& app); void openMimeType(const QString& mime); void openCategory(const QString& category); void openMode(const QString& mode); void openLocalPackage(const QUrl &localfile); void reboot(); private Q_SLOTS: void reportBug(); void switchApplicationLanguage(); void aboutApplication(); Q_SIGNALS: void openSearch(const QString &search); void openApplicationInternal(AbstractResource* app); void listMimeInternal(const QString& mime); void listCategoryInternal(Category* cat); void compactModeChanged(DiscoverObject::CompactMode compactMode); void preventedClose(); void unableToFind(const QString &resid); void openErrorPage(const QString &errorMessage); private: void setRootObjectProperty(const char *name, const QVariant &value); void integrateObject(QObject* object); QQmlApplicationEngine* engine() const { return m_engine; } QMap m_collection; QQmlApplicationEngine * const m_engine; CompactMode m_mode; QScopedPointer m_networkAccessManagerFactory; }; #endif // DISCOVEROBJECT_H diff --git a/discover/main.cpp b/discover/main.cpp index 91886bb6..1f10369f 100644 --- a/discover/main.cpp +++ b/discover/main.cpp @@ -1,167 +1,173 @@ /* * Copyright (C) 2012 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser General Public License * version 2, or (at your option) any later version, as published by the * Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library/Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // #define QT_QML_DEBUG #include #include #include #include #include #include #include #include #include "DiscoverObject.h" #include #include "DiscoverVersion.h" #include #include typedef QHash StringCompactMode; Q_GLOBAL_STATIC_WITH_ARGS(StringCompactMode, s_decodeCompactMode, (StringCompactMode { { QLatin1String("auto"), DiscoverObject::Auto }, { QLatin1String("compact"), DiscoverObject::Compact }, { QLatin1String("full"), DiscoverObject::Full } })) QCommandLineParser* createParser() { QCommandLineParser* parser = new QCommandLineParser; parser->addOption(QCommandLineOption(QStringLiteral("application"), i18n("Directly open the specified application by its package name."), QStringLiteral("name"))); parser->addOption(QCommandLineOption(QStringLiteral("mime"), i18n("Open with a program that can deal with the given mimetype."), QStringLiteral("name"))); parser->addOption(QCommandLineOption(QStringLiteral("category"), i18n("Display a list of entries with a category."), QStringLiteral("name"))); parser->addOption(QCommandLineOption(QStringLiteral("mode"), i18n("Open Discover in a said mode. Modes correspond to the toolbar buttons."), QStringLiteral("name"))); parser->addOption(QCommandLineOption(QStringLiteral("listmodes"), i18n("List all the available modes."))); parser->addOption(QCommandLineOption(QStringLiteral("compact"), i18n("Compact Mode (auto/compact/full)."), QStringLiteral("mode"), QStringLiteral("auto"))); parser->addOption(QCommandLineOption(QStringLiteral("local-filename"), i18n("Local package file to install"), QStringLiteral("package"))); parser->addOption(QCommandLineOption(QStringLiteral("listbackends"), i18n("List all the available backends."))); parser->addOption(QCommandLineOption(QStringLiteral("search"), i18n("Search string."), QStringLiteral("text"))); parser->addOption(QCommandLineOption(QStringLiteral("test"), QStringLiteral("Test file"), QStringLiteral("file.qml"))); parser->addPositionalArgument(QStringLiteral("urls"), i18n("Supports appstream: url scheme")); DiscoverBackendsFactory::setupCommandLine(parser); KAboutData::applicationData().setupCommandLine(parser); return parser; } void processArgs(QCommandLineParser* parser, DiscoverObject* mainWindow) { if(parser->isSet(QStringLiteral("application"))) mainWindow->openApplication(QUrl(parser->value(QStringLiteral("application")))); else if(parser->isSet(QStringLiteral("mime"))) mainWindow->openMimeType(parser->value(QStringLiteral("mime"))); else if(parser->isSet(QStringLiteral("category"))) mainWindow->openCategory(parser->value(QStringLiteral("category"))); if(parser->isSet(QStringLiteral("mode"))) mainWindow->openMode(parser->value(QStringLiteral("mode"))); if(parser->isSet(QStringLiteral("search"))) Q_EMIT mainWindow->openSearch(parser->value(QStringLiteral("search"))); if(parser->isSet(QStringLiteral("local-filename"))) mainWindow->openLocalPackage(QUrl::fromUserInput(parser->value(QStringLiteral("local-filename")), {}, QUrl::AssumeLocalFile)); foreach(const QString &arg, parser->positionalArguments()) { const QUrl url = QUrl::fromUserInput(arg, {}, QUrl::AssumeLocalFile); if (url.isLocalFile()) mainWindow->openLocalPackage(url); else if (url.scheme() == QLatin1String("apt")) Q_EMIT mainWindow->openSearch(url.host()); else mainWindow->openApplication(url); } } int main(int argc, char** argv) { QApplication app(argc, argv); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("plasmadiscover"))); app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KCrash::initialize(); KQuickAddons::QtQuickSettings::init(); KLocalizedString::setApplicationDomain("plasma-discover"); KAboutData about(QStringLiteral("discover"), i18n("Discover"), version, i18n("An application explorer"), KAboutLicense::GPL, i18n("© 2010-2019 Plasma Development Team")); about.addAuthor(i18n("Aleix Pol Gonzalez"), QString(), QStringLiteral("aleixpol@kde.org")); about.addAuthor(i18n("Jonathan Thomas"), QString(), QStringLiteral("echidnaman@kubuntu.org")); about.setProductName("discover/discover"); about.setProgramLogo(app.windowIcon()); about.setTranslator( i18ndc(nullptr, "NAME OF TRANSLATORS", "Your names"), i18ndc(nullptr, "EMAIL OF TRANSLATORS", "Your emails")); KAboutData::setApplicationData(about); DiscoverObject *mainWindow = nullptr; { QScopedPointer parser(createParser()); parser->process(app); about.processCommandLine(parser.data()); DiscoverBackendsFactory::processCommandLine(parser.data(), parser->isSet(QStringLiteral("test"))); if(parser->isSet(QStringLiteral("listbackends"))) { QTextStream(stdout) << i18n("Available backends:\n"); DiscoverBackendsFactory f; foreach(const QString& name, f.allBackendNames(false, true)) QTextStream(stdout) << " * " << name << '\n'; return 0; } if (parser->isSet(QStringLiteral("test"))) { QStandardPaths::setTestModeEnabled(true); } KDBusService* service = new KDBusService(KDBusService::Unique, &app); - mainWindow = new DiscoverObject(s_decodeCompactMode->value(parser->value(QStringLiteral("compact")), DiscoverObject::Full)); + { + auto options = parser->optionNames(); + options.removeAll(QStringLiteral("backends")); + options.removeAll(QStringLiteral("test")); + bool hasOptions = !options.isEmpty() || !parser->positionalArguments().isEmpty(); + mainWindow = new DiscoverObject(s_decodeCompactMode->value(parser->value(QStringLiteral("compact")), DiscoverObject::Full), {{QStringLiteral("defaultStartup"), !hasOptions}}); + } QObject::connect(&app, &QCoreApplication::aboutToQuit, mainWindow, &DiscoverObject::deleteLater); QObject::connect(service, &KDBusService::activateRequested, mainWindow, [mainWindow](const QStringList &arguments, const QString &/*workingDirectory*/){ if (!mainWindow->rootObject()) QCoreApplication::instance()->quit(); mainWindow->rootObject()->raise(); if (arguments.isEmpty()) return; QScopedPointer parser(createParser()); parser->parse(arguments); processArgs(parser.data(), mainWindow); }); processArgs(parser.data(), mainWindow); if(parser->isSet(QStringLiteral("listmodes"))) { QTextStream(stdout) << i18n("Available modes:\n"); foreach(const QString& mode, mainWindow->modes()) QTextStream(stdout) << " * " << mode << '\n'; delete mainWindow; return 0; } if (parser->isSet(QStringLiteral("test"))) { const QUrl testFile = QUrl::fromUserInput(parser->value(QStringLiteral("test")), {}, QUrl::AssumeLocalFile); Q_ASSERT(!testFile.isEmpty() && testFile.isLocalFile()); mainWindow->loadTest(testFile); } } return app.exec(); }