diff --git a/discover/DiscoverDeclarativePlugin.cpp b/discover/DiscoverDeclarativePlugin.cpp index cade5a21..206861d0 100644 --- a/discover/DiscoverDeclarativePlugin.cpp +++ b/discover/DiscoverDeclarativePlugin.cpp @@ -1,76 +1,77 @@ /* * 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 "DiscoverDeclarativePlugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include void DiscoverDeclarativePlugin::initializeEngine(QQmlEngine* engine, const char* uri) { engine->rootContext()->setContextProperty(QStringLiteral("ResourcesModel"), ResourcesModel::global()); engine->rootContext()->setContextProperty(QStringLiteral("TransactionModel"), TransactionModel::global()); engine->rootContext()->setContextProperty(QStringLiteral("SourcesModel"), SourcesModel::global()); engine->rootContext()->setContextProperty(QStringLiteral("CategoryModel"), CategoryModel::global()); QQmlExtensionPlugin::initializeEngine(engine, uri); } void DiscoverDeclarativePlugin::registerTypes(const char* /*uri*/) { qmlRegisterType("org.kde.discover", 2, 0, "TransactionListener"); qmlRegisterType(); qmlRegisterType("org.kde.discover", 2, 0, "ResourcesUpdatesModel"); qmlRegisterType("org.kde.discover", 2, 0, "ResourcesProxyModel"); qmlRegisterType("org.kde.discover", 2, 0, "ReviewsModel"); qmlRegisterType("org.kde.discover", 2, 0, "ApplicationAddonsModel"); qmlRegisterType("org.kde.discover", 2, 0, "ScreenshotsModel"); - qmlRegisterType("org.kde.discover", 2, 0, "MessageActionsModel"); + qmlRegisterType("org.kde.discover", 2, 0, "ActionsModel"); qmlRegisterType("org.kde.discover", 2, 0, "UpdateModel"); qmlRegisterUncreatableType("org.kde.discover", 2, 0, "QAction", QStringLiteral("Use QQC Action")); qmlRegisterUncreatableType("org.kde.discover", 2, 0, "AbstractResource", QStringLiteral("should come from the ResourcesModel")); qmlRegisterUncreatableType("org.kde.discover", 2, 0, "AbstractSourcesBackend", QStringLiteral("should come from the SourcesModel")); qmlRegisterUncreatableType("org.kde.discover", 2, 0, "Transaction", QStringLiteral("should come from the backends")); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlProtectModule("org.kde.discover", 2); + qRegisterMetaType>(); } diff --git a/discover/qml/SourcesPage.qml b/discover/qml/SourcesPage.qml index 1e97e275..4650fbe9 100644 --- a/discover/qml/SourcesPage.qml +++ b/discover/qml/SourcesPage.qml @@ -1,230 +1,222 @@ import QtQuick 2.4 import QtQuick.Controls 1.1 import QtQuick.Controls 2.1 as QQC2 import QtQuick.Layouts 1.1 import org.kde.discover 2.0 import org.kde.discover.app 1.0 import org.kde.kquickcontrolsaddons 2.0 import org.kde.kirigami 2.1 as Kirigami import "navigation.js" as Navigation DiscoverPage { id: page clip: true title: i18n("Settings") property string search: "" readonly property var fu: Instantiator { model: SourcesModel delegate: QtObject { readonly property var sourcesModel: sourceBackend.sources readonly property var a: Connections { target: sourceBackend onPassiveMessage: window.showPassiveNotification(message) } - readonly property var b: AddSourceDialog { - id: addSourceDialog - source: sourceBackend - } - - readonly property var c: MenuItem { - id: menuItem - text: sourceBackend.name - onTriggered: { - try { - addSourceDialog.open() - addSourceDialog.visible = true - } catch (e) { - console.log("error loading dialog:", e) - } - } - } - - Component.onCompleted: { - sourcesMenu.insertItem(0, menuItem) - } } onObjectAdded: { everySourceModel.addSourceModel(object.sourcesModel) } onObjectRemoved: { everySourceModel.removeSourceModel(object.sourcesModel) } } mainItem: ListView { id: sourcesView model: QSortFilterProxyModel{ filterRegExp: new RegExp(page.search) sourceModel: KConcatenateRowsProxyModel { id: everySourceModel } } currentIndex: -1 - Menu { id: sourcesMenu } - section { property: "statusTip" - delegate: Kirigami.Heading { - leftPadding: Kirigami.Units.largeSpacing - text: section + delegate: RowLayout { + anchors { + right: parent.right + left: parent.left + } + Kirigami.Heading { + Layout.fillWidth: true + leftPadding: Kirigami.Units.largeSpacing + text: settingsButton.isDefault ? i18n("%1 (Default)", section) : section + } + ToolButton { + id: settingsButton + iconName: "preferences-other" + readonly property QtObject backend: SourcesModel.backendForSection(section) + readonly property bool isDefault: ResourcesModel.currentApplicationBackend == settingsButton.backend.resourcesBackend + visible: backend + AddSourceDialog { + id: addSourceDialog + source: settingsButton.backend + } + + menu: Menu { + id: settingsMenu + MenuItem { + enabled: !settingsButton.isDefault + text: i18n("Make default") + onTriggered: ResourcesModel.currentApplicationBackend = settingsButton.backend.resourcesBackend + } + + MenuItem { + text: i18n("Add Source") + + onTriggered: addSourceDialog.open() + } + + MenuSeparator { + visible: messageActionsInst.count>0 + } + + Instantiator { + id: messageActionsInst + model: ActionsModel { + actions: settingsButton.backend ? settingsButton.backend.resourcesBackend.messageActions : null + } + delegate: MenuItem { + action: ActionBridge { action: model.action } + } + onObjectAdded: { + settingsMenu.insertItem(index, object) + } + onObjectRemoved: { + object.destroy() + } + } + + MenuSeparator { + visible: backendActionsInst.count>0 + } + + Instantiator { + id: backendActionsInst + model: ActionsModel { + actions: settingsButton.backend ? settingsButton.backend.actions : null + } + delegate: MenuItem { + action: ActionBridge { action: model.action } + } + onObjectAdded: { + settingsMenu.insertItem(index, object) + } + onObjectRemoved: { + object.destroy() + } + } + } + } } } headerPositioning: ListView.OverlayHeader header: QQC2.ToolBar { anchors { right: parent.right left: parent.left } contentItem: RowLayout { anchors { topMargin: Kirigami.Units.smallSpacing bottomMargin: Kirigami.Units.smallSpacing } Item { Layout.fillWidth: true } - ToolButton { - text: i18n("Application Sources") - tooltip: i18n("Allows to choose the source that will be used for browsing applications") - menu: Menu { - id: backendsMenu - } - enabled: menu.items.length>0 - - ExclusiveGroup { - id: select - } - - Instantiator { - model: ResourcesModel.applicationBackends - delegate: MenuItem { - text: modelData.displayName - checkable: true - checked: ResourcesModel.currentApplicationBackend == modelData - onTriggered: ResourcesModel.currentApplicationBackend = modelData - exclusiveGroup: select - } - onObjectAdded: { - backendsMenu.insertItem(index, object) - } - onObjectRemoved: { - object.destroy() - } - } - } - - ToolButton { -// iconName: "list-add" - text: i18n("Add Source") - - tooltip: text - menu: sourcesMenu - } Repeater { model: SourcesModel.actions delegate: RowLayout { Kirigami.Icon { source: modelData.icon } visible: theAction.action && theAction.action.visible ToolButton { height: parent.height action: Action { id: theAction readonly property QtObject action: modelData text: action.text onTriggered: action.trigger() enabled: action.enabled } } } } - ToolButton { - text: i18n("More...") - menu: Menu { - id: actionsMenu - } - enabled: menu.items.length>0 - - Instantiator { - model: MessageActionsModel {} - delegate: MenuItem { - action: ActionBridge { action: model.action } - } - onObjectAdded: { - actionsMenu.insertItem(index, object) - } - onObjectRemoved: { - object.destroy() - } - } - } - ToolButton { text: i18n("Help...") menu: Menu { MenuItem { action: ActionBridge { action: app.action("help_about_app") } } MenuItem { action: ActionBridge { action: app.action("help_report_bug") } } } } } } delegate: Kirigami.SwipeListItem { Layout.fillWidth: true enabled: display.length>0 highlighted: ListView.isCurrentItem onClicked: Navigation.openApplicationListSource(model.display) readonly property string backendName: model.statusTip readonly property variant modelIndex: sourcesView.model.index(model.index, 0) Keys.onReturnPressed: clicked() actions: [ Kirigami.Action { enabled: display.length>0 iconName: "view-filter" tooltip: i18n("Browse the origin's resources") onTriggered: Navigation.openApplicationListSource(model.display) }, Kirigami.Action { iconName: "edit-delete" tooltip: i18n("Delete the origin") onTriggered: { var backend = sourcesView.model.data(modelIndex, AbstractSourcesBackend.SourcesBackend) if (!backend.removeSource(model.display)) { window.showPassiveNotification(i18n("Failed to remove the source '%1'", model.display)) } } } ] RowLayout { CheckBox { id: enabledBox readonly property variant modelChecked: sourcesView.model.data(modelIndex, Qt.CheckStateRole) checked: modelChecked != Qt.Unchecked enabled: modelChecked !== undefined onClicked: { model.checked = checkedState } } QQC2.Label { text: model.display + " - " + model.toolTip + "" elide: Text.ElideRight Layout.fillWidth: true } } } } } diff --git a/libdiscover/MessageActionsModel.cpp b/libdiscover/ActionsModel.cpp similarity index 76% rename from libdiscover/MessageActionsModel.cpp rename to libdiscover/ActionsModel.cpp index aff3441b..fbca0ada 100644 --- a/libdiscover/MessageActionsModel.cpp +++ b/libdiscover/ActionsModel.cpp @@ -1,80 +1,86 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 "MessageActionsModel.h" +#include "ActionsModel.h" #include "resources/ResourcesModel.h" #include "utils.h" #include -MessageActionsModel::MessageActionsModel(QObject* parent) +ActionsModel::ActionsModel(QObject* parent) : QAbstractListModel(parent) , m_priority(-1) { - connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, this, &MessageActionsModel::reload); + connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, this, &ActionsModel::reload); } -QHash< int, QByteArray > MessageActionsModel::roleNames() const +QHash< int, QByteArray > ActionsModel::roleNames() const { return { { Qt::UserRole, "action" }}; } -QVariant MessageActionsModel::data(const QModelIndex& index, int role) const +QVariant ActionsModel::data(const QModelIndex& index, int role) const { if(!index.isValid() || role!=Qt::UserRole) return QVariant(); return QVariant::fromValue(m_actions[index.row()]); } -int MessageActionsModel::rowCount(const QModelIndex& parent) const +int ActionsModel::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : m_actions.count(); } -void MessageActionsModel::reload() +void ActionsModel::setActions(const QList& actions) { - auto actions = ResourcesModel::global()->messageActions(); + if (m_actions == actions) { + return; + } + + reload(); + Q_EMIT actionsChanged(m_actions); +} + +void ActionsModel::reload() +{ + auto actions = m_filteredActions; if (m_priority>=0) { actions = kFilter>(actions, [this](QAction* action){ return action->priority() == m_priority; }); } + actions = kFilter>(actions, [](QAction* action){ return action->isVisible(); }); if (actions == m_actions) return; beginResetModel(); m_actions = actions; endResetModel(); } -int MessageActionsModel::filterPriority() const +int ActionsModel::filterPriority() const { return m_priority; } -void MessageActionsModel::setFilterPriority(int p) +void ActionsModel::setFilterPriority(int p) { if (m_priority != p) { m_priority = p; reload(); } } - -void MessageActionsModel::componentComplete() -{ - reload(); -} diff --git a/libdiscover/MessageActionsModel.h b/libdiscover/ActionsModel.h similarity index 80% rename from libdiscover/MessageActionsModel.h rename to libdiscover/ActionsModel.h index 8d420b8d..8377c0f2 100644 --- a/libdiscover/MessageActionsModel.h +++ b/libdiscover/ActionsModel.h @@ -1,55 +1,59 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ -#ifndef MESSAGEACTIONSMODEL_H -#define MESSAGEACTIONSMODEL_H +#ifndef ACTIONSMODEL_H +#define ACTIONSMODEL_H #include #include #include "discovercommon_export.h" class QAction; -class DISCOVERCOMMON_EXPORT MessageActionsModel : public QAbstractListModel, public QQmlParserStatus +class DISCOVERCOMMON_EXPORT ActionsModel : public QAbstractListModel { Q_OBJECT - Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QList actions READ actions WRITE setActions NOTIFY actionsChanged) Q_PROPERTY(int filterPriority READ filterPriority WRITE setFilterPriority) public: - explicit MessageActionsModel(QObject* parent = nullptr); + explicit ActionsModel(QObject* parent = nullptr); QHash roleNames() const override; QVariant data(const QModelIndex& index, int role) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; void setFilterPriority(int p); int filterPriority() const; - void classBegin() override {} - void componentComplete() override; + void setActions(const QList& actions); + QList actions() const { return m_actions; } + + Q_SIGNALS: + void actionsChanged(const QList& actions); private: void reload(); QList m_actions; + QList m_filteredActions; int m_priority; }; #endif diff --git a/libdiscover/CMakeLists.txt b/libdiscover/CMakeLists.txt index 910ba629..f5227a45 100644 --- a/libdiscover/CMakeLists.txt +++ b/libdiscover/CMakeLists.txt @@ -1,67 +1,67 @@ add_definitions(-DTRANSLATION_DOMAIN=\"libdiscover\") add_subdirectory(backends) add_subdirectory(notifiers) add_subdirectory(tests) set(discovercommon_SRCS Category/Category.cpp Category/CategoryModel.cpp Category/CategoriesReader.cpp ReviewsBackend/AbstractReviewsBackend.cpp ReviewsBackend/Rating.cpp ReviewsBackend/Review.cpp ReviewsBackend/ReviewsModel.cpp Transaction/AddonList.cpp Transaction/Transaction.cpp Transaction/TransactionListener.cpp Transaction/TransactionModel.cpp UpdateModel/UpdateItem.cpp UpdateModel/UpdateModel.cpp resources/ResourcesModel.cpp resources/ResourcesProxyModel.cpp resources/PackageState.cpp resources/ResourcesUpdatesModel.cpp resources/StandardBackendUpdater.cpp resources/SourcesModel.cpp resources/AbstractResourcesBackend.cpp resources/AbstractResource.cpp resources/AbstractBackendUpdater.cpp resources/AbstractSourcesBackend.cpp resources/StoredResultsStream.cpp CachedNetworkAccessManager.cpp - MessageActionsModel + ActionsModel.cpp DiscoverBackendsFactory.cpp ScreenshotsModel.cpp ApplicationAddonsModel.cpp ) if(AppStreamQt_FOUND) set(discovercommon_SRCS ${discovercommon_SRCS} appstream/OdrsReviewsBackend.cpp appstream/AppStreamIntegration.cpp ) endif() add_library(DiscoverCommon ${discovercommon_SRCS}) target_link_libraries(DiscoverCommon LINK_PUBLIC Qt5::Core Qt5::Qml Qt5::Widgets KF5::I18n LINK_PRIVATE Qt5::Xml Qt5::DBus KF5::KIOCore KF5::CoreAddons ) add_library(Discover::Common ALIAS DiscoverCommon) generate_export_header(DiscoverCommon) target_include_directories(DiscoverCommon PRIVATE ${PHONON_INCLUDES} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) install(TARGETS DiscoverCommon DESTINATION ${CMAKE_INSTALL_LIBDIR}/plasma-discover) install(FILES resources/discoverabstractnotifier.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) diff --git a/libdiscover/backends/DummyBackend/DummySourcesBackend.cpp b/libdiscover/backends/DummyBackend/DummySourcesBackend.cpp index 7dbbe12d..a8d877da 100644 --- a/libdiscover/backends/DummyBackend/DummySourcesBackend.cpp +++ b/libdiscover/backends/DummyBackend/DummySourcesBackend.cpp @@ -1,71 +1,71 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 "DummySourcesBackend.h" #include #include -DummySourcesBackend::DummySourcesBackend(QObject* parent) +DummySourcesBackend::DummySourcesBackend(AbstractResourcesBackend * parent) : AbstractSourcesBackend(parent) , m_sources(new QStandardItemModel(this)) , m_testAction(new QAction(QIcon::fromTheme(QStringLiteral("kalgebra")), QStringLiteral("DummyAction"), this)) { QHash roles = m_sources->roleNames(); roles.insert(AbstractSourcesBackend::SourcesBackend, "sourcesBackend"); roles.insert(Qt::CheckStateRole, "checked"); m_sources->setItemRoleNames(roles); for (int i = 0; i<10; ++i) addSource(QStringLiteral("DummySource%1").arg(i)); connect(m_testAction, &QAction::triggered, [](){ qDebug() << "action triggered!"; }); } QAbstractItemModel* DummySourcesBackend::sources() { return m_sources; } bool DummySourcesBackend::addSource(const QString& id) { QStandardItem* it = new QStandardItem(id); it->setData(QVariant(id + QLatin1Char(' ') + id), Qt::ToolTipRole); it->setData(name(), AbstractSourcesBackend::SectionRole); it->setData(QVariant::fromValue(this), AbstractSourcesBackend::SourcesBackend); m_sources->appendRow(it); return true; } bool DummySourcesBackend::removeSource(const QString& id) { QList items = m_sources->findItems(id); if (items.count()==1) { m_sources->removeRow(items.first()->row()); } else { qWarning() << "couldn't find " << id << items; } return items.count()==1; } QList DummySourcesBackend::actions() const { return QList() << m_testAction; } diff --git a/libdiscover/backends/DummyBackend/DummySourcesBackend.h b/libdiscover/backends/DummyBackend/DummySourcesBackend.h index 8ee16635..b538150a 100644 --- a/libdiscover/backends/DummyBackend/DummySourcesBackend.h +++ b/libdiscover/backends/DummyBackend/DummySourcesBackend.h @@ -1,44 +1,44 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ #ifndef DUMMYSOURCESBACKEND_H #define DUMMYSOURCESBACKEND_H #include #include class DummySourcesBackend : public AbstractSourcesBackend { public: - explicit DummySourcesBackend(QObject* parent); + explicit DummySourcesBackend(AbstractResourcesBackend * parent); QAbstractItemModel* sources() override; bool addSource(const QString& id) override; bool removeSource(const QString& id) override; QString name() const override { return QStringLiteral("Dummy"); } QString idDescription() override { return QStringLiteral("Random weird text"); } QList actions() const override; private: QStandardItemModel* m_sources; QAction* m_testAction; }; #endif // DUMMYSOURCESBACKEND_H diff --git a/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.cpp b/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.cpp index 5bbfe762..85b0946f 100644 --- a/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.cpp +++ b/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.cpp @@ -1,224 +1,224 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * Copyright © 2017 Jan Grulich * * * * 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 "FlatpakSourcesBackend.h" #include "FlatpakResource.h" #include "FlatpakBackend.h" #include #include #include #include #include #include #include #include #include class FlatpakSourceItem : public QStandardItem { public: FlatpakSourceItem(const QString &text) : QStandardItem(text) { } void setFlatpakInstallation(FlatpakInstallation *installation) { m_installation = installation; } FlatpakInstallation *flatpakInstallation() const { return m_installation; } private: FlatpakInstallation *m_installation; }; -FlatpakSourcesBackend::FlatpakSourcesBackend(const QVector &installations, QObject* parent) +FlatpakSourcesBackend::FlatpakSourcesBackend(const QVector &installations, AbstractResourcesBackend * parent) : AbstractSourcesBackend(parent) , m_preferredInstallation(installations.constFirst()) , m_sources(new QStandardItemModel(this)) , m_flathubAction(new QAction(i18n("Add Flathub"), this)) { QHash roles = m_sources->roleNames(); roles.insert(Qt::CheckStateRole, "checked"); roles.insert(Qt::UserRole, "flatpakInstallation"); m_sources->setItemRoleNames(roles); m_flathubAction->setToolTip(QStringLiteral("flathub")); connect(m_flathubAction, &QAction::triggered, this, [this](){ addSource(QStringLiteral("https://flathub.org/repo/flathub.flatpakrepo")); }); for (auto installation : installations) { if (!listRepositories(installation)) { qWarning() << "Failed to list repositories from installation" << installation; } } } QAbstractItemModel* FlatpakSourcesBackend::sources() { return m_sources; } bool FlatpakSourcesBackend::addSource(const QString &id) { FlatpakBackend* backend = qobject_cast(parent()); const QUrl flatpakrepoUrl = QUrl::fromUserInput(id); if (flatpakrepoUrl.isLocalFile()) { auto res = backend->addSourceFromFlatpakRepo(flatpakrepoUrl); if (res) backend->installApplication(res); else backend->passiveMessage(i18n("Could not add the source %1", flatpakrepoUrl.toDisplayString())); } else { AbstractResourcesBackend::Filters filter; filter.resourceUrl = flatpakrepoUrl; auto stream = new StoredResultsStream ({backend->search(filter)}); connect(stream, &StoredResultsStream::finished, this, [backend, stream, flatpakrepoUrl]() { const auto res = stream->resources(); if (!res.isEmpty()) { Q_ASSERT(res.count() == 1); backend->installApplication(res.first()); } else { backend->passiveMessage(i18n("Could not add the source %1", flatpakrepoUrl.toDisplayString())); } }); } return true; } bool FlatpakSourcesBackend::removeSource(const QString &id) { QList items = m_sources->findItems(id); if (items.count() == 1) { FlatpakSourceItem *sourceItem = static_cast(items.first()); g_autoptr(GCancellable) cancellable = g_cancellable_new(); if (flatpak_installation_remove_remote(sourceItem->flatpakInstallation(), id.toUtf8().constData(), cancellable, nullptr)) { m_sources->removeRow(sourceItem->row()); return true; } else { qWarning() << "Failed to remove " << id << " remote repository"; return false; } } else { qWarning() << "couldn't find " << id << items; return false; } return false; } QList FlatpakSourcesBackend::actions() const { return { m_flathubAction }; } bool FlatpakSourcesBackend::listRepositories(FlatpakInstallation* installation) { Q_ASSERT(installation); g_autoptr(GCancellable) cancellable = g_cancellable_new(); g_autoptr(GPtrArray) remotes = flatpak_installation_list_remotes(installation, cancellable, nullptr); if (!remotes) { return false; } const auto actions = this->actions(); for (uint i = 0; i < remotes->len; i++) { FlatpakRemote *remote = FLATPAK_REMOTE(g_ptr_array_index(remotes, i)); if (flatpak_remote_get_noenumerate(remote)) { continue; } const QString id = QString::fromUtf8(flatpak_remote_get_name(remote)); const QString remoteUrl = QString::fromUtf8(flatpak_remote_get_url(remote)); const QString title = i18nc("description (url)", "%1 (%2)", QString::fromUtf8(flatpak_remote_get_title(remote)), remoteUrl); for(QAction *action: actions) { if (action->toolTip() == id) { action->setEnabled(false); action->setVisible(false); } } FlatpakSourceItem *it = new FlatpakSourceItem(id); it->setCheckState(flatpak_remote_get_disabled(remote) ? Qt::Unchecked : Qt::Checked); it->setData(title.isEmpty() ? id : title, Qt::ToolTipRole); it->setData(name(), AbstractSourcesBackend::SectionRole); it->setData(QVariant::fromValue(this), AbstractSourcesBackend::SourcesBackend); it->setFlatpakInstallation(installation); m_sources->appendRow(it); } return true; } FlatpakRemote * FlatpakSourcesBackend::installSource(FlatpakResource *resource) { g_autoptr(GCancellable) cancellable = g_cancellable_new(); auto remote = flatpak_installation_get_remote_by_name(m_preferredInstallation, resource->flatpakName().toUtf8().constData(), cancellable, nullptr); if (remote) { qWarning() << "Source " << resource->flatpakName() << " already exists"; return nullptr; } remote = flatpak_remote_new(resource->flatpakName().toUtf8().constData()); flatpak_remote_set_url(remote, resource->getMetadata(QStringLiteral("repo-url")).toString().toUtf8().constData()); flatpak_remote_set_noenumerate(remote, false); flatpak_remote_set_title(remote, resource->comment().toUtf8().constData()); const QString gpgKey = resource->getMetadata(QStringLiteral("gpg-key")).toString(); if (!gpgKey.isEmpty()) { gsize dataLen = 0; g_autofree guchar *data = nullptr; g_autoptr(GBytes) bytes = nullptr; data = g_base64_decode(gpgKey.toUtf8().constData(), &dataLen); bytes = g_bytes_new(data, dataLen); flatpak_remote_set_gpg_verify(remote, true); flatpak_remote_set_gpg_key(remote, bytes); } else { flatpak_remote_set_gpg_verify(remote, false); } if (!resource->branch().isEmpty()) { flatpak_remote_set_default_branch(remote, resource->branch().toUtf8().constData()); } if (!flatpak_installation_modify_remote(m_preferredInstallation, remote, cancellable, nullptr)) { qWarning() << "Failed to add source " << resource->flatpakName(); return nullptr; } FlatpakSourceItem *it = new FlatpakSourceItem(resource->flatpakName()); it->setCheckState(flatpak_remote_get_disabled(remote) ? Qt::Unchecked : Qt::Checked); it->setData(resource->comment().isEmpty() ? resource->flatpakName() : resource->comment(), Qt::ToolTipRole); it->setData(name(), AbstractSourcesBackend::SectionRole); it->setData(QVariant::fromValue(this), AbstractSourcesBackend::SourcesBackend); it->setFlatpakInstallation(m_preferredInstallation); m_sources->appendRow(it); return remote; } QString FlatpakSourcesBackend::idDescription() { return i18n("Flatpak repository URI (*.flatpakrepo)"); } diff --git a/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.h b/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.h index d6bfc7a4..a4bc883c 100644 --- a/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.h +++ b/libdiscover/backends/FlatpakBackend/FlatpakSourcesBackend.h @@ -1,54 +1,54 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * Copyright © 2017 Jan Grulich * * * * 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 . * ***************************************************************************/ #ifndef FLATPAKSOURCESBACKEND_H #define FLATPAKSOURCESBACKEND_H #include #include extern "C" { #include } class FlatpakResource; class FlatpakSourcesBackend : public AbstractSourcesBackend { public: - explicit FlatpakSourcesBackend(const QVector& installations, QObject *parent); + explicit FlatpakSourcesBackend(const QVector& installations, AbstractResourcesBackend *parent); QAbstractItemModel* sources() override; bool addSource(const QString &id) override; bool removeSource(const QString &id) override; QString name() const override { return QStringLiteral("Flatpak"); } QString idDescription() override; QList actions() const override; FlatpakRemote * installSource(FlatpakResource *resource); private: bool listRepositories(FlatpakInstallation *installation); FlatpakInstallation *m_preferredInstallation; QStandardItemModel* m_sources; QAction* const m_flathubAction; }; #endif // FLATPAKSOURCESBACKEND_H diff --git a/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.cpp b/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.cpp index 0a11c80b..c2147358 100644 --- a/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.cpp +++ b/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.cpp @@ -1,149 +1,150 @@ /*************************************************************************** * Copyright © 2016 Aleix Pol Gonzalez * * * * 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 "PackageKitSourcesBackend.h" #include #include #include #include #include +#include class PKSourcesModel : public QStandardItemModel { public: PKSourcesModel(PackageKitSourcesBackend* backend) : QStandardItemModel(backend) , m_backend(backend) {} QHash roleNames() const override { auto roles = QStandardItemModel::roleNames(); roles[AbstractSourcesBackend::SourcesBackend] = "sourcesBackend"; roles[Qt::CheckStateRole] = "checked"; return roles; } QVariant data(const QModelIndex & index, int role) const override { if (role == AbstractSourcesBackend::SourcesBackend) return QVariant::fromValue(m_backend); else return QStandardItemModel::data(index, role); } bool setData(const QModelIndex & index, const QVariant & value, int role) override { auto item = itemFromIndex(index); if (!item) return false; switch(role) { case Qt::CheckStateRole: { auto transaction = PackageKit::Daemon::global()->repoEnable(item->text(), value.toInt() == Qt::Checked); connect(transaction, &PackageKit::Transaction::errorCode, m_backend, &PackageKitSourcesBackend::transactionError); return true; } } item->setData(value, role); return true; } private: PackageKitSourcesBackend* m_backend; }; -PackageKitSourcesBackend::PackageKitSourcesBackend(QObject* parent) +PackageKitSourcesBackend::PackageKitSourcesBackend(AbstractResourcesBackend* parent) : AbstractSourcesBackend(parent) , m_sources(new PKSourcesModel(this)) { connect(PackageKit::Daemon::global(), &PackageKit::Daemon::repoListChanged, this, &PackageKitSourcesBackend::resetSources); resetSources(); } QString PackageKitSourcesBackend::name() const { - return i18n("Software Management"); + return resourcesBackend()->displayName(); } QString PackageKitSourcesBackend::idDescription() { return i18n("Repository URL:"); } QStandardItem* PackageKitSourcesBackend::findItemForId(const QString &id) const { for(int i=0, c=m_sources->rowCount(); iitem(i); if (it->text() == id) return it; } return nullptr; } void PackageKitSourcesBackend::addRepositoryDetails(const QString &id, const QString &description, bool enabled) { bool add = false; QStandardItem* item = findItemForId(id); if (!item) { item = new QStandardItem(id); add = true; } item->setData(description, Qt::ToolTipRole); item->setData(name(), AbstractSourcesBackend::SectionRole); item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); if (add) m_sources->appendRow(item); } QAbstractItemModel * PackageKitSourcesBackend::sources() { return m_sources; } bool PackageKitSourcesBackend::addSource(const QString& /*id*/) { return false; } bool PackageKitSourcesBackend::removeSource(const QString& id) { auto transaction = PackageKit::Daemon::global()->repoRemove(id, false); connect(transaction, &PackageKit::Transaction::errorCode, this, &PackageKitSourcesBackend::transactionError); return false; } QList PackageKitSourcesBackend::actions() const { return {}; } void PackageKitSourcesBackend::resetSources() { m_sources->clear(); auto transaction = PackageKit::Daemon::global()->getRepoList(); connect(transaction, &PackageKit::Transaction::repoDetail, this, &PackageKitSourcesBackend::addRepositoryDetails); connect(transaction, &PackageKit::Transaction::errorCode, this, &PackageKitSourcesBackend::transactionError); } void PackageKitSourcesBackend::transactionError(PackageKit::Transaction::Error error, const QString& message) { Q_EMIT passiveMessage(message); qWarning() << "Transaction error: " << error << message << sender(); } diff --git a/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.h b/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.h index 72b67b9d..b9769487 100644 --- a/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.h +++ b/libdiscover/backends/PackageKitBackend/PackageKitSourcesBackend.h @@ -1,55 +1,55 @@ /*************************************************************************** * Copyright © 2016 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ #ifndef PACKAGEKITSOURCESBACKEND_H #define PACKAGEKITSOURCESBACKEND_H #include #include class QStandardItem; class PKSourcesModel; class PackageKitSourcesBackend : public AbstractSourcesBackend { Q_OBJECT public: - PackageKitSourcesBackend(QObject* parent); + PackageKitSourcesBackend(AbstractResourcesBackend* parent); QString name() const override; QString idDescription() override; bool addSource(const QString& id) override; bool removeSource(const QString& id) override; QAbstractItemModel* sources() override; QList actions() const override; void transactionError(PackageKit::Transaction::Error, const QString& message); private: void resetSources(); void addRepositoryDetails(const QString &id, const QString &description, bool enabled); QStandardItem* findItemForId(const QString &id) const; PKSourcesModel* m_sources; }; #endif // PACKAGEKITSOURCESBACKEND_H diff --git a/libdiscover/resources/AbstractResourcesBackend.h b/libdiscover/resources/AbstractResourcesBackend.h index 8cf6bcab..13ec3263 100644 --- a/libdiscover/resources/AbstractResourcesBackend.h +++ b/libdiscover/resources/AbstractResourcesBackend.h @@ -1,270 +1,271 @@ /*************************************************************************** * Copyright ?? 2012 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ #ifndef ABSTRACTRESOURCESBACKEND_H #define ABSTRACTRESOURCESBACKEND_H #include #include #include #include "AbstractResource.h" #include "Transaction/AddonList.h" #include "discovercommon_export.h" class QAction; class Transaction; class Category; class AbstractReviewsBackend; class AbstractBackendUpdater; class DISCOVERCOMMON_EXPORT ResultsStream : public QObject { Q_OBJECT public: ResultsStream(const QString &objectName); /// assumes all the information is in @p resources ResultsStream(const QString &objectName, const QVector& resources); ~ResultsStream() override; void finish(); Q_SIGNALS: void resourcesFound(const QVector& resources); }; /** * \class AbstractResourcesBackend AbstractResourcesBackend.h "AbstractResourcesBackend.h" * * \brief This is the base class of all resource backends. * * For writing basic new resource backends, we need to implement two classes: this and the * AbstractResource one. Basic questions on how to build your plugin with those classes * can be answered by looking at the dummy plugin. * * As this is the base class of a backend, we save all the created resources here and also * accept calls to install and remove applications or to cancel transactions. * * To show resources in Muon, we need to initialize all resources we want to show beforehand, * we should not create resources in the search function. When we reload the resources * (e.g. when initializing), the backend needs change the fetching property throughout the * processs. */ class DISCOVERCOMMON_EXPORT AbstractResourcesBackend : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString displayName READ displayName CONSTANT) Q_PROPERTY(AbstractReviewsBackend* reviewsBackend READ reviewsBackend CONSTANT) Q_PROPERTY(int updatesCount READ updatesCount NOTIFY updatesCountChanged) Q_PROPERTY(bool isFetching READ isFetching NOTIFY fetchingChanged) + Q_PROPERTY(QList messageActions READ messageActions CONSTANT) public: /** * Constructs an AbstractResourcesBackend * @param parent the parent of the class (the object will be deleted when the parent gets deleted) */ explicit AbstractResourcesBackend(QObject* parent = nullptr); /** * @returns true when the backend is in a valid state, which means it is able to work * You must return true here if you want the backend to be loaded. */ virtual bool isValid() const = 0; struct Filters { Category* category = nullptr; AbstractResource::State state = AbstractResource::Broken; QString mimetype; QString search; QString extends; QUrl resourceUrl; QHash roles; bool allBackends = false; bool shouldFilter(AbstractResource* res) const; void filterJustInCase(QVector& input) const; }; /** * @returns a stream that will provide elements that match the search */ virtual ResultsStream* search(const Filters &search) = 0;//FIXME: Probably provide a standard implementation?! virtual ResultsStream* findResourceByPackageName(const QUrl &search) = 0;//FIXME: Probably provide a standard implementation?! /** * @returns the reviews backend of this AbstractResourcesBackend (which handles all ratings and reviews of resources) */ virtual AbstractReviewsBackend* reviewsBackend() const = 0;//FIXME: Have a standard impl which returns 0? /** * @returns the class which is used by muon to update the users system, if you are unsure what to do * just return the StandardBackendUpdater */ virtual AbstractBackendUpdater* backendUpdater() const = 0;//FIXME: Standard impl returning the standard updater? /** * @returns the number of resources for which an update is available, it should only count technical packages */ virtual int updatesCount() const = 0;//FIXME: Probably provide a standard implementation?! /** * Tells whether the backend is fetching resources */ virtual bool isFetching() const = 0; /** * This method is used to integrate advanced functions into the Muon GUI. * * In plasma-discover-updater, actions with HighPriority will be shown in a KMessageWidget, * normal priority will go right on top of the more menu, low priority will go * to the advanced menu. */ virtual QList messageActions() const = 0; /** * @returns the appstream ids that this backend extends */ virtual QStringList extends() const; /** @returns the plugin's name */ QString name() const; /** @internal only to be used by the factory */ void setName(const QString& name); virtual QString displayName() const = 0; /** * emits a change for all rating properties */ void emitRatingsReady(); virtual AbstractResource* resourceForFile(const QUrl &/*url*/) { return nullptr; } /** * @returns the root category tree */ virtual QVector category() const { return {}; } virtual bool hasApplications() const { return false; } public Q_SLOTS: /** * This gets called when the backend should install an application. * The AbstractResourcesBackend should create a Transaction object, is returned and * will be included in the TransactionModel * @param app the application to be installed * @param addons the addons which should be installed with the application * @returns the Transaction that keeps track of the installation process */ virtual Transaction* installApplication(AbstractResource *app, const AddonList& addons) = 0; /** * Overloaded function, which simply does the same, except not installing any addons. */ virtual Transaction* installApplication(AbstractResource *app); /** * This gets called when the backend should remove an application. * Like in the installApplication() method, we'll return the Transaction * responsible for the removal. * * @see installApplication * @param app the application to be removed * @returns the Transaction that keeps track of the removal process */ virtual Transaction* removeApplication(AbstractResource *app) = 0; /** * Notifies the backend that the user wants the information to be up to date */ virtual void checkForUpdates() = 0; Q_SIGNALS: /** * Notify of a change in the backend */ void fetchingChanged(); /** * This should be emitted when the number of upgradeable packages changed. */ void updatesCountChanged(); /** * This should be emitted when all data of the backends resources changed. Internally it will emit * a signal in the model to show the view that all data of a certain backend changed. */ void allDataChanged(const QVector &propertyNames); /** * Allows to notify some @p properties in @p resource have changed */ void resourcesChanged(AbstractResource* resource, const QVector &properties); void resourceRemoved(AbstractResource* resource); void passiveMessage(const QString &message); private: QString m_name; }; template static T containerValues(const W& container) { T ret; ret.reserve(container.size()); for(auto a : container) { ret.push_back(a); } return ret; } DISCOVERCOMMON_EXPORT QDebug operator<<(QDebug dbg, const AbstractResourcesBackend::Filters& filters); /** * @internal Workaround because QPluginLoader enforces 1 instance per plugin */ class DISCOVERCOMMON_EXPORT AbstractResourcesBackendFactory : public QObject { Q_OBJECT public: virtual QVector newInstance(QObject* parent, const QString &name) const = 0; }; #define MUON_BACKEND_PLUGIN(ClassName)\ class ClassName##Factory : public AbstractResourcesBackendFactory {\ Q_OBJECT\ Q_PLUGIN_METADATA(IID "org.kde.muon.AbstractResourcesBackendFactory")\ Q_INTERFACES(AbstractResourcesBackendFactory)\ public:\ QVector newInstance(QObject* parent, const QString &name) const override {\ auto c = new ClassName(parent);\ c->setName(name);\ return {c};\ }\ }; Q_DECLARE_INTERFACE( AbstractResourcesBackendFactory, "org.kde.muon.AbstractResourcesBackendFactory" ) #endif // ABSTRACTRESOURCESBACKEND_H diff --git a/libdiscover/resources/AbstractSourcesBackend.cpp b/libdiscover/resources/AbstractSourcesBackend.cpp index 5e1f41ae..f494a86d 100644 --- a/libdiscover/resources/AbstractSourcesBackend.cpp +++ b/libdiscover/resources/AbstractSourcesBackend.cpp @@ -1,27 +1,34 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 "AbstractSourcesBackend.h" +#include "AbstractResourcesBackend.h" -AbstractSourcesBackend::AbstractSourcesBackend(QObject* parent) +AbstractSourcesBackend::AbstractSourcesBackend(AbstractResourcesBackend* parent) : QObject(parent) {} AbstractSourcesBackend::~AbstractSourcesBackend() = default; + +AbstractResourcesBackend * AbstractSourcesBackend::resourcesBackend() const +{ + return dynamic_cast(parent()); +} + diff --git a/libdiscover/resources/AbstractSourcesBackend.h b/libdiscover/resources/AbstractSourcesBackend.h index bf5fce45..50768425 100644 --- a/libdiscover/resources/AbstractSourcesBackend.h +++ b/libdiscover/resources/AbstractSourcesBackend.h @@ -1,58 +1,64 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ #ifndef ABSTRACTSOURCESMANAGER_H #define ABSTRACTSOURCESMANAGER_H #include #include "discovercommon_export.h" class QAction; class QAbstractItemModel; +class AbstractResourcesBackend; + class DISCOVERCOMMON_EXPORT AbstractSourcesBackend : public QObject { Q_OBJECT + Q_PROPERTY(AbstractResourcesBackend* resourcesBackend READ resourcesBackend CONSTANT) Q_PROPERTY(QAbstractItemModel* sources READ sources CONSTANT) Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString idDescription READ idDescription CONSTANT) + Q_PROPERTY(QList actions READ actions CONSTANT) public: - explicit AbstractSourcesBackend(QObject* parent); + explicit AbstractSourcesBackend(AbstractResourcesBackend* parent); ~AbstractSourcesBackend() override; enum Roles { SectionRole = Qt::StatusTipRole, SourcesBackend }; Q_ENUM(Roles) virtual QString name() const = 0; virtual QString idDescription() = 0; Q_SCRIPTABLE virtual bool addSource(const QString& id) = 0; Q_SCRIPTABLE virtual bool removeSource(const QString& id) = 0; virtual QAbstractItemModel* sources() = 0; virtual QList actions() const = 0; + AbstractResourcesBackend* resourcesBackend() const; + Q_SIGNALS: void passiveMessage(const QString &message); }; #endif // ABSTRACTRESOURCESBACKEND_H diff --git a/libdiscover/resources/SourcesModel.cpp b/libdiscover/resources/SourcesModel.cpp index 9e47f212..31af9fbf 100644 --- a/libdiscover/resources/SourcesModel.cpp +++ b/libdiscover/resources/SourcesModel.cpp @@ -1,94 +1,96 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 "SourcesModel.h" #include #include #include #include "resources/AbstractSourcesBackend.h" Q_GLOBAL_STATIC(SourcesModel, s_sources) SourcesModel::SourcesModel(QObject* parent) : QAbstractListModel(parent) {} SourcesModel::~SourcesModel() = default; QHash SourcesModel::roleNames() const { return { {SourceBackend, "sourceBackend"} }; } SourcesModel* SourcesModel::global() { return s_sources; } static bool ensureModel(const QList &roles) { static QList required = {"sourcesBackend", "display", "checked"}; for (const auto &role: roles) { if (!roles.contains(role)) return false; } return true; } void SourcesModel::addSourcesBackend(AbstractSourcesBackend* sources) { if (m_sources.contains(sources)) return; Q_ASSERT(ensureModel(sources->sources()->roleNames().values())); beginInsertRows(QModelIndex(), m_sources.size(), m_sources.size()); m_sources += sources; endInsertRows(); emit sourcesChanged(); } QVariant SourcesModel::data(const QModelIndex& index, int role) const { if(!index.isValid() || index.row()>=m_sources.count()) { return QVariant(); } switch(role) { case SourceBackend: return QVariant::fromValue(m_sources[index.row()]); } return QVariant(); } int SourcesModel::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : m_sources.count(); } -QList SourcesModel::actions() const +QObject * SourcesModel::backendForSection(const QString& status) const { - QList ret; + AbstractSourcesBackend* ret = nullptr; for(AbstractSourcesBackend* b: m_sources) { - foreach(QAction* action, b->actions()) - ret.append(action); + if (b->name() == status) { + ret = b; + break; + } } return ret; } diff --git a/libdiscover/resources/SourcesModel.h b/libdiscover/resources/SourcesModel.h index 3d831485..cc512dfc 100644 --- a/libdiscover/resources/SourcesModel.h +++ b/libdiscover/resources/SourcesModel.h @@ -1,59 +1,59 @@ /*************************************************************************** * Copyright © 2014 Aleix Pol Gonzalez * * * * 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 . * ***************************************************************************/ #ifndef SOURCESMODEL_H #define SOURCESMODEL_H #include #include #include #include "discovercommon_export.h" class QAction; class AbstractSourcesBackend; class DISCOVERCOMMON_EXPORT SourcesModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int count READ rowCount NOTIFY sourcesChanged) - Q_PROPERTY(QList actions READ actions NOTIFY sourcesChanged) public: enum Roles { SourceBackend = Qt::UserRole+1 }; explicit SourcesModel(QObject* parent = nullptr); ~SourcesModel() override; static SourcesModel* global(); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; void addSourcesBackend(AbstractSourcesBackend* sources); QHash roleNames() const override; - QList actions() const; + public Q_SLOTS: + QObject* backendForSection(const QString &status) const; Q_SIGNALS: void sourcesChanged(); private: QList m_sources; }; #endif // SOURCESMODEL_H