File indexing completed on 2024-05-05 17:33:03
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 // #define QT_QML_DEBUG 0008 0009 #include "DiscoverObject.h" 0010 #include "DiscoverVersion.h" 0011 #include <DiscoverBackendsFactory.h> 0012 #include <KAboutData> 0013 #include <KCrash> 0014 #include <KDBusService> 0015 #include <KLocalizedString> 0016 #include <KWindowSystem> 0017 #include <QApplication> 0018 #include <QCommandLineParser> 0019 #include <QStandardPaths> 0020 #include <QSurfaceFormat> 0021 #include <QTextStream> 0022 #include <QWindow> 0023 #if WITH_QTWEBVIEW 0024 #include <QtWebView> 0025 #endif 0026 0027 #include <QProcessEnvironment> 0028 0029 typedef QHash<QString, DiscoverObject::CompactMode> StringCompactMode; 0030 Q_GLOBAL_STATIC_WITH_ARGS(StringCompactMode, 0031 s_decodeCompactMode, 0032 (StringCompactMode{ 0033 {QLatin1String("auto"), DiscoverObject::Auto}, 0034 {QLatin1String("compact"), DiscoverObject::Compact}, 0035 {QLatin1String("full"), DiscoverObject::Full}, 0036 })) 0037 0038 QCommandLineParser *createParser() 0039 { 0040 // clang-format off 0041 QCommandLineParser *parser = new QCommandLineParser; 0042 parser->addOption(QCommandLineOption(QStringLiteral("application"), i18n("Directly open the specified application by its appstream:// URI."), QStringLiteral("name"))); 0043 parser->addOption(QCommandLineOption(QStringLiteral("mime"), i18n("Open with a search for programs that can deal with the given mimetype."), QStringLiteral("name"))); 0044 parser->addOption(QCommandLineOption(QStringLiteral("category"), i18n("Display a list of entries with a category."), QStringLiteral("name"))); 0045 parser->addOption(QCommandLineOption(QStringLiteral("mode"), i18n("Open Discover in a said mode. Modes correspond to the toolbar buttons."), QStringLiteral("name"))); 0046 parser->addOption(QCommandLineOption(QStringLiteral("listmodes"), i18n("List all the available modes."))); 0047 parser->addOption(QCommandLineOption(QStringLiteral("compact"), i18n("Compact Mode (auto/compact/full)."), QStringLiteral("mode"), QStringLiteral("auto"))); 0048 parser->addOption(QCommandLineOption(QStringLiteral("local-filename"), i18n("Local package file to install"), QStringLiteral("package"))); 0049 parser->addOption(QCommandLineOption(QStringLiteral("listbackends"), i18n("List all the available backends."))); 0050 parser->addOption(QCommandLineOption(QStringLiteral("search"), i18n("Search string."), QStringLiteral("text"))); 0051 parser->addOption(QCommandLineOption(QStringLiteral("feedback"), i18n("Lists the available options for user feedback"))); 0052 parser->addOption(QCommandLineOption(QStringLiteral("test"), QStringLiteral("Test file"), QStringLiteral("file.qml"))); 0053 parser->addPositionalArgument(QStringLiteral("urls"), i18n("Supports appstream: url scheme")); 0054 // clang-format on 0055 DiscoverBackendsFactory::setupCommandLine(parser); 0056 KAboutData::applicationData().setupCommandLine(parser); 0057 return parser; 0058 } 0059 0060 void processArgs(QCommandLineParser *parser, DiscoverObject *mainWindow) 0061 { 0062 if (parser->isSet(QStringLiteral("application"))) 0063 mainWindow->openApplication(QUrl(parser->value(QStringLiteral("application")))); 0064 else if (parser->isSet(QStringLiteral("mime"))) 0065 mainWindow->openMimeType(parser->value(QStringLiteral("mime"))); 0066 else if (parser->isSet(QStringLiteral("category"))) 0067 mainWindow->openCategory(parser->value(QStringLiteral("category"))); 0068 else if (parser->isSet(QStringLiteral("mode"))) 0069 mainWindow->openMode(parser->value(QStringLiteral("mode"))); 0070 0071 if (parser->isSet(QStringLiteral("search"))) 0072 Q_EMIT mainWindow->openSearch(parser->value(QStringLiteral("search"))); 0073 0074 if (parser->isSet(QStringLiteral("local-filename"))) 0075 mainWindow->openLocalPackage(QUrl::fromUserInput(parser->value(QStringLiteral("local-filename")), {}, QUrl::AssumeLocalFile)); 0076 0077 const auto positionalArguments = parser->positionalArguments(); 0078 for (const QString &arg : positionalArguments) { 0079 const QUrl url = QUrl::fromUserInput(arg, {}, QUrl::AssumeLocalFile); 0080 if (url.isLocalFile()) 0081 mainWindow->openLocalPackage(url); 0082 else if (url.scheme() == QLatin1String("apt")) 0083 Q_EMIT mainWindow->openSearch(url.host()); 0084 else 0085 mainWindow->openApplication(url); 0086 } 0087 0088 if (mainWindow->rootObject()->property("pageStack").value<QObject *>()->property("depth").toInt() == 0) { 0089 mainWindow->openMode(QStringLiteral("Browsing")); 0090 } 0091 } 0092 0093 static void raiseWindow(QWindow *window) 0094 { 0095 KWindowSystem::updateStartupId(window); 0096 KWindowSystem::activateWindow(window); 0097 } 0098 0099 int main(int argc, char **argv) 0100 { 0101 // needs to be set before we create the QGuiApplication 0102 QCoreApplication::setAttribute(Qt::AA_DisableSessionManager, true); 0103 #if WITH_QTWEBVIEW 0104 QtWebView::initialize(); 0105 #endif 0106 0107 auto format = QSurfaceFormat::defaultFormat(); 0108 format.setOption(QSurfaceFormat::ResetNotification); 0109 QSurfaceFormat::setDefaultFormat(format); 0110 0111 QApplication app(argc, argv); 0112 app.setWindowIcon(QIcon::fromTheme(QStringLiteral("plasmadiscover"))); 0113 app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); 0114 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0115 app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); 0116 #endif 0117 KCrash::initialize(); 0118 KLocalizedString::setApplicationDomain("plasma-discover"); 0119 KAboutData about(QStringLiteral("discover"), 0120 i18n("Discover"), 0121 version, 0122 i18n("An application explorer"), 0123 KAboutLicense::GPL, 0124 i18n("© 2010-2022 Plasma Development Team")); 0125 about.addAuthor(i18n("Aleix Pol Gonzalez"), QString(), QStringLiteral("aleixpol@kde.org"), QStringLiteral("https://proli.net"), QStringLiteral("apol")); 0126 about.addAuthor(i18n("Nate Graham"), 0127 i18n("Quality Assurance, Design and Usability"), 0128 QStringLiteral("nate@kde.org"), 0129 QStringLiteral("https://pointieststick.com/"), 0130 QStringLiteral("ngraham")); 0131 about.addAuthor(i18n("Dan Leinir Turthra Jensen"), 0132 i18n("KNewStuff"), 0133 QStringLiteral("admin@leinir.dk"), 0134 QStringLiteral("https://leinir.dk/"), 0135 QStringLiteral("leinir")); 0136 about.setProductName("discover/discover"); 0137 about.setProgramLogo(app.windowIcon()); 0138 0139 about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); 0140 0141 KAboutData::setApplicationData(about); 0142 0143 DiscoverObject *mainWindow = nullptr; 0144 { 0145 QScopedPointer<QCommandLineParser> parser(createParser()); 0146 parser->process(app); 0147 about.processCommandLine(parser.data()); 0148 DiscoverBackendsFactory::processCommandLine(parser.data(), parser->isSet(QStringLiteral("test"))); 0149 const bool feedback = parser->isSet(QStringLiteral("feedback")); 0150 0151 if (parser->isSet(QStringLiteral("listbackends"))) { 0152 QTextStream(stdout) << i18n("Available backends:\n"); 0153 DiscoverBackendsFactory f; 0154 const auto backendNames = f.allBackendNames(false, true); 0155 for (const QString &name : backendNames) 0156 QTextStream(stdout) << " * " << name << '\n'; 0157 return 0; 0158 } 0159 0160 if (parser->isSet(QStringLiteral("test"))) { 0161 QStandardPaths::setTestModeEnabled(true); 0162 } 0163 0164 KDBusService *service = !feedback ? new KDBusService(KDBusService::Unique, &app) : nullptr; 0165 0166 { 0167 auto options = parser->optionNames(); 0168 options.removeAll(QStringLiteral("backends")); 0169 options.removeAll(QStringLiteral("test")); 0170 QVariantMap initialProperties; 0171 if (!options.isEmpty() || !parser->positionalArguments().isEmpty()) 0172 initialProperties = {{QStringLiteral("currentTopLevel"), QStringLiteral("qrc:/qml/LoadingPage.qml")}}; 0173 if (feedback) { 0174 initialProperties.insert("visible", false); 0175 } 0176 mainWindow = new DiscoverObject(s_decodeCompactMode->value(parser->value(QStringLiteral("compact")), DiscoverObject::Full), initialProperties); 0177 } 0178 if (feedback) { 0179 QTextStream(stdout) << mainWindow->describeSources() << '\n'; 0180 delete mainWindow; 0181 return 0; 0182 } else { 0183 auto onActivateRequested = [mainWindow](const QStringList &arguments, const QString & /*workingDirectory*/) { 0184 mainWindow->restore(); 0185 auto window = qobject_cast<QWindow *>(mainWindow->rootObject()); 0186 if (!window) { 0187 // Should never happen anyway 0188 QCoreApplication::instance()->quit(); 0189 return; 0190 } 0191 0192 raiseWindow(window); 0193 0194 if (arguments.isEmpty()) 0195 return; 0196 QScopedPointer<QCommandLineParser> parser(createParser()); 0197 parser->parse(arguments); 0198 processArgs(parser.data(), mainWindow); 0199 }; 0200 QObject::connect(service, &KDBusService::activateRequested, mainWindow, onActivateRequested); 0201 } 0202 0203 QObject::connect(&app, &QCoreApplication::aboutToQuit, mainWindow, &DiscoverObject::deleteLater); 0204 0205 processArgs(parser.data(), mainWindow); 0206 0207 if (parser->isSet(QStringLiteral("listmodes"))) { 0208 QTextStream(stdout) << i18n("Available modes:\n"); 0209 const auto modes = mainWindow->modes(); 0210 for (const QString &mode : modes) 0211 QTextStream(stdout) << " * " << mode << '\n'; 0212 delete mainWindow; 0213 return 0; 0214 } 0215 0216 if (parser->isSet(QStringLiteral("test"))) { 0217 const QUrl testFile = QUrl::fromUserInput(parser->value(QStringLiteral("test")), {}, QUrl::AssumeLocalFile); 0218 Q_ASSERT(!testFile.isEmpty() && testFile.isLocalFile()); 0219 0220 mainWindow->loadTest(testFile); 0221 } 0222 } 0223 0224 return app.exec(); 0225 }