diff --git a/src/lib/vehiclesupportpluginmodel.cpp b/src/lib/vehiclesupportpluginmodel.cpp index 17e3987..7a5f6b6 100644 --- a/src/lib/vehiclesupportpluginmodel.cpp +++ b/src/lib/vehiclesupportpluginmodel.cpp @@ -1,236 +1,239 @@ /* * Copyright 2019 Eike Hein * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "vehiclesupportpluginmodel.h" #include "debug.h" #include "vehiclesupportplugin.h" #include #include #include +#include #include namespace Kirogi { class Q_DECL_HIDDEN VehicleSupportPluginModel::Private { public: Private(VehicleSupportPluginModel *q); ~Private(); QVector plugins; // This is QMap so `VehicleSupportPluginModel::loadedPlugins` returns a stable sort. QMap loadedPlugins; void findPlugins(); private: VehicleSupportPluginModel *q; }; VehicleSupportPluginModel::Private::Private(VehicleSupportPluginModel *q) : q(q) { } VehicleSupportPluginModel::Private::~Private() { } void VehicleSupportPluginModel::Private::findPlugins() { auto filter = [](const KPluginMetaData &metaData) { return metaData.serviceTypes().contains(QStringLiteral("Kirogi/VehicleSupport")); }; - plugins = KPluginLoader::findPlugins(QStringLiteral("kirogi/vehiclesupport"), filter); + // Looking for the relative path when the application is not installed in the system + plugins = KPluginLoader::findPlugins(QCoreApplication::applicationDirPath() + QStringLiteral("/../lib/plugins/kirogi/vehiclesupport"), filter); + plugins += KPluginLoader::findPlugins(QStringLiteral("kirogi/vehiclesupport"), filter); // Unload plugins that apparently got uninstalled at runtime. for (const QString &id : loadedPlugins.keys()) { bool found = false; for (const KPluginMetaData &md : plugins) { if (md.pluginId() == id) { found = true; break; } } if (!found) { delete loadedPlugins.take(id); } } } VehicleSupportPluginModel::VehicleSupportPluginModel(QObject *parent) : QAbstractListModel(parent) , d(new Private(this)) { // FIXME TODO: Watch KSycoca and reload when new plugins are installed at runtime. d->findPlugins(); } VehicleSupportPluginModel::~VehicleSupportPluginModel() { } QHash VehicleSupportPluginModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); for (int i = 0; i < e.keyCount(); ++i) { roles.insert(e.value(i), e.key(i)); } return roles; } int VehicleSupportPluginModel::rowCount(const QModelIndex &parent) const { if (!checkIndex(parent, CheckIndexOption::ParentIsInvalid)) { return 0; } return d->plugins.count(); } QVariant VehicleSupportPluginModel::data(const QModelIndex &index, int role) const { if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { return QVariant(); } switch (role) { case Qt::DisplayRole: { return d->plugins.at(index.row()).name(); } case Id: { return d->plugins.at(index.row()).pluginId(); } case Status: { const QString &id = d->plugins.at(index.row()).pluginId(); if (d->loadedPlugins.contains(id)) { return PluginLoaded; } else { return PluginNotLoaded; } } case Plugin: { const QString &id = d->plugins.at(index.row()).pluginId(); return QVariant::fromValue(d->loadedPlugins.value(id)); } } return QVariant(); } bool VehicleSupportPluginModel::loadPlugin(int row) { const KPluginMetaData &md = d->plugins.at(row); if (d->loadedPlugins.contains(md.pluginId())) { return false; } KPluginLoader loader(md.fileName(), this); KPluginFactory *factory = loader.factory(); if (!factory) { qCWarning(KIROGI_CORE) << "Error loading plugin:" << md.pluginId() << "-" << loader.errorString(); } else { VehicleSupportPlugin *vehicleSupportPlugin = factory->create(this); if (!vehicleSupportPlugin) { qCWarning(KIROGI_CORE) << "Scheduling invalid plugin to be deleted:" << md.pluginId() << "/" << factory; factory->deleteLater(); } else { qCWarning(KIROGI_CORE) << "Loaded plugin with id:" << md.pluginId(); d->loadedPlugins[md.pluginId()] = vehicleSupportPlugin; emit pluginLoaded(md.pluginId(), md.name(), vehicleSupportPlugin); const QModelIndex &idx = index(row, 0); emit dataChanged(idx, idx, QVector{Status, Plugin}); } } return false; } bool VehicleSupportPluginModel::loadPluginById(const QString &id) { for (int i = 0; i < d->plugins.count(); ++i) { const KPluginMetaData &md = d->plugins.at(i); if (md.pluginId() == id) { return loadPlugin(i); } } return false; } bool VehicleSupportPluginModel::unloadPlugin(int row) { const QString &id = d->plugins.at(row).pluginId(); if (!d->loadedPlugins.contains(id)) { return false; } delete d->loadedPlugins.take(id); const QModelIndex &idx = index(row, 0); emit dataChanged(idx, idx, QVector{Status, Plugin}); return true; } bool VehicleSupportPluginModel::unloadAllPlugins() { if (!d->loadedPlugins.count()) { return false; } for (int i = 0; i < d->plugins.count(); ++i) { const KPluginMetaData &md = d->plugins.at(i); VehicleSupportPlugin *plugin = d->loadedPlugins.take(md.pluginId()); if (plugin) { delete plugin; const QModelIndex &idx = index(i, 0); emit dataChanged(idx, idx, QVector{Status, Plugin}); } } return true; } } diff --git a/src/main.cpp b/src/main.cpp index 470e5a0..1a66060 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,154 +1,158 @@ /* * Copyright 2019 Eike Hein * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 General Public License * along with this program. If not, see . */ #include "settings.h" #include "permissions.h" #include "gstreamer/gstreamerintegration.h" #include #ifndef Q_OS_ANDROID #include #endif #include #include #ifdef Q_OS_ANDROID #include #include #else #include #endif #include #include #include #include #include #include #ifdef Q_OS_ANDROID extern "C" gboolean gst_qt_android_init(GError ** error); Q_DECL_EXPORT #endif int main(int argc, char *argv[]) { int ret; #ifndef Q_OS_ANDROID gst_init(&argc, &argv); #else if (!gst_qt_android_init(NULL)) { return -1; } #endif QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #ifdef Q_OS_ANDROID QGuiApplication app(argc, argv); #else QApplication app(argc, argv); #endif KLocalizedString::setApplicationDomain("kirogi"); KAboutData aboutData(QStringLiteral("kirogi"), xi18nc("@title", "Kirogi"), QStringLiteral("0.1-dev"), xi18nc("@title", "A ground control application for drones."), KAboutLicense::GPL, xi18nc("@info:credit", "(c) 2019 The Kirogi Team"), QString(), QStringLiteral("https://www.kirogi.org/")); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setProductName(QByteArray("kirogi")); aboutData.addAuthor(xi18nc("@info:credit", "Eike Hein"), xi18nc("@info:credit", "Founder, Lead Developer"), QStringLiteral("hein@kde.org")); aboutData.addAuthor(xi18nc("@info:credit", "Rafael Brandmaier"), xi18nc("@info:credit", "Application icon"), QStringLiteral("rafael.brandmaier@kdemail.net")); aboutData.addAuthor(xi18nc("@info:credit", "L. 'AsmoArael' C."), xi18nc("@info:credit", "Mascot artwork"), QStringLiteral("lc.jarryh99@outlook.fr")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); app.setApplicationName(aboutData.componentName()); app.setApplicationDisplayName(aboutData.displayName()); app.setOrganizationDomain(aboutData.organizationDomain()); app.setApplicationVersion(aboutData.version()); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("kirogi"))); #ifndef Q_OS_ANDROID KCrash::initialize(); #endif QQmlApplicationEngine engine(&app); + /* Help our kind developers to test kirogi without further configuration + * Making it possible to install Kirogi in generic installation folder + */ + engine.addImportPath(QCoreApplication::applicationDirPath() + "/../lib/qml"); // For i18n. engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); engine.rootContext()->setContextProperty(QStringLiteral("kirogiAboutData"), QVariant::fromValue(aboutData)); engine.rootContext()->setContextProperty(QStringLiteral("kirogiSettings"), Settings::self()); // Initialize video stack. GStreamerIntegration *videoPlayer = new GStreamerIntegration(&app); engine.rootContext()->setContextProperty(QStringLiteral("videoPlayer"), QVariant::fromValue(videoPlayer)); engine.rootContext()->setContextProperty(QStringLiteral("locationPermissions"), QVariant::fromValue(new Permissions(QStringList() << QStringLiteral("android.permission.ACCESS_COARSE_LOCATION") << QStringLiteral("android.permission.ACCESS_FINE_LOCATION"), &app))); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); if( engine.rootObjects().isEmpty()) { qCritical() << "Application failed to load."; gst_deinit(); return -1; } videoPlayer->setWindow(qobject_cast(engine.rootObjects().first())); #ifdef Q_OS_ANDROID QtAndroid::hideSplashScreen(); #endif ret = app.exec(); delete videoPlayer; gst_deinit(); return ret; }