File indexing completed on 2024-05-05 16:07:10

0001 /*
0002     SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <QApplication>
0008 
0009 #include <KLocalizedString>
0010 #include <QCommandLineOption>
0011 #include <QCommandLineParser>
0012 #include <QQuickItem>
0013 
0014 #include <KAboutData>
0015 #include <QQmlContext>
0016 #include <QQmlEngine>
0017 #include <QQmlExpression>
0018 #include <QQmlProperty>
0019 #include <QQuickWindow>
0020 #include <QStandardPaths>
0021 #include <kdeclarative/qmlobject.h>
0022 #include <kpackage/package.h>
0023 #include <kpackage/packageloader.h>
0024 
0025 int main(int argc, char **argv)
0026 {
0027     QCommandLineParser parser;
0028     QApplication app(argc, argv);
0029 
0030     const QString description = i18n("KPackage QML application shell");
0031 
0032     app.setApplicationVersion(QStringLiteral("0.1"));
0033     parser.addVersionOption();
0034     parser.addHelpOption();
0035     parser.setApplicationDescription(description);
0036 
0037     QCommandLineOption appPluginOption(QCommandLineOption(QStringList() << QStringLiteral("a") << QStringLiteral("app"),
0038                                                           i18n("The unique name of the application (mandatory)"),
0039                                                           QStringLiteral("app")));
0040 
0041     parser.addOption(appPluginOption);
0042 
0043     parser.process(app);
0044 
0045     QString packagePath;
0046     if (parser.isSet(appPluginOption)) {
0047         packagePath = parser.value(appPluginOption);
0048     } else {
0049         parser.showHelp(1);
0050     }
0051 
0052     // usually we have an ApplicationWindow here, so we do not need to create a window by ourselves
0053     KDeclarative::QmlObject obj;
0054     obj.setTranslationDomain(packagePath);
0055     obj.setInitializationDelayed(true);
0056     obj.loadPackage(packagePath);
0057     if (!obj.package().isValid()) {
0058         qWarning() << "The specified Application package is not valid.";
0059         return 1;
0060     }
0061     obj.engine()->rootContext()->setContextProperty(QStringLiteral("commandlineArguments"), parser.positionalArguments());
0062     QVariantMap paths;
0063     paths[QStringLiteral("desktop")] = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
0064     paths[QStringLiteral("documents")] = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
0065     paths[QStringLiteral("music")] = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
0066     paths[QStringLiteral("movies")] = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
0067     paths[QStringLiteral("pictures")] = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
0068     paths[QStringLiteral("home")] = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
0069     obj.engine()->rootContext()->setContextProperty(QStringLiteral("userPaths"), paths);
0070     obj.completeInitialization();
0071 
0072     if (!obj.package().metadata().isValid()) {
0073         return -1;
0074     }
0075 
0076     KPluginMetaData data = obj.package().metadata();
0077     // About data
0078     KAboutData aboutData(data.pluginId(), data.name(), data.version(), data.description(), KAboutLicense::byKeyword(data.license()).key());
0079 
0080     const auto authors = data.authors();
0081     for (auto &author : authors) {
0082         aboutData.addAuthor(author.name(), author.task(), author.emailAddress(), author.webAddress(), author.ocsUsername());
0083     }
0084     // We assume that desktop file in applications dir is named similar as
0085     // the pluginId, this is required to get icons working on wayland for example
0086     aboutData.setDesktopFileName(data.pluginId());
0087 
0088     KAboutData::setApplicationData(aboutData);
0089 
0090     // The root is not a window?
0091     // have to use a normal QQuickWindow since the root item is already created
0092     QQuickItem *item = qobject_cast<QQuickItem *>(obj.rootObject());
0093     QWindow *window = qobject_cast<QWindow *>(obj.rootObject());
0094     if (item) {
0095         QQuickWindow view;
0096         item->setParentItem(view.contentItem());
0097         if (item->implicitWidth() > 0 && item->implicitHeight() > 0) {
0098             view.resize(item->implicitWidth(), item->implicitHeight());
0099         } else {
0100             view.resize(item->width(), item->height());
0101         }
0102 
0103         // set anchors
0104         QQmlExpression expr(obj.engine()->rootContext(), obj.rootObject(), QStringLiteral("parent"));
0105         QQmlProperty prop(obj.rootObject(), QStringLiteral("anchors.fill"));
0106         prop.write(expr.evaluate());
0107         view.setTitle(obj.package().metadata().name());
0108         view.setIcon(QIcon::fromTheme(obj.package().metadata().iconName()));
0109 
0110         // Forward Qt.quit() in QML code to QApplication::quit()
0111         QObject::connect(obj.engine(), &QQmlEngine::quit, &app, &QCoreApplication::quit);
0112 
0113         view.show();
0114         return app.exec();
0115     } else if (window) {
0116         window->setTitle(obj.package().metadata().name());
0117         window->setIcon(QIcon::fromTheme(obj.package().metadata().iconName()));
0118     } else {
0119         qWarning() << "The root Qml Item should be either a kind of window or a QQuickItem";
0120         return 1;
0121     }
0122 
0123     return app.exec();
0124 }