Commit 10fab95e authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

List backends without sources in the Sources page

BUG: 388751
parent d3724cd8
......@@ -14,24 +14,6 @@ DiscoverPage {
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)
}
}
onObjectAdded: {
everySourceModel.addSourceModel(object.sourcesModel)
}
onObjectRemoved: {
everySourceModel.removeSourceModel(object.sourcesModel)
}
}
header: QQC2.ToolBar {
anchors {
right: parent.right
......@@ -66,15 +48,17 @@ DiscoverPage {
id: sourcesView
model: QSortFilterProxyModel{
filterRegExp: new RegExp(page.search, 'i')
sourceModel: KConcatenateRowsProxyModel {
id: everySourceModel
}
sourceModel: SourcesModel
}
currentIndex: -1
section {
property: "statusTip"
delegate: RowLayout {
Component {
id: sourceBackendDelegate
RowLayout {
id: backendItem
readonly property QtObject backend: sourcesBackend
readonly property bool isDefault: ResourcesModel.currentApplicationBackend == resourcesBackend
anchors {
right: parent.right
left: parent.left
......@@ -82,32 +66,44 @@ DiscoverPage {
Kirigami.Heading {
Layout.fillWidth: true
leftPadding: Kirigami.Units.largeSpacing
text: settingsButton.isDefault ? i18n("%1 (Default)", section) : section
text: backendItem.isDefault ? i18n("%1 (Default)", resourcesBackend.displayName) : resourcesBackend.displayName
}
Button {
id: settingsButton
Layout.rightMargin: Kirigami.Units.smallSpacing
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
Connections {
target: backend
onPassiveMessage: window.showPassiveNotification(message)
}
visible: resourcesBackend && resourcesBackend.hasApplications
Component {
id: dialogComponent
AddSourceDialog {
source: backendItem.backend
onVisibleChanged: if (!visible) {
destroy()
}
}
}
menu: Menu {
id: settingsMenu
MenuItem {
enabled: !settingsButton.isDefault
enabled: !backendItem.isDefault
text: i18n("Make default")
onTriggered: ResourcesModel.currentApplicationBackend = settingsButton.backend.resourcesBackend
onTriggered: ResourcesModel.currentApplicationBackend = backendItem.backend.resourcesBackend
}
MenuItem {
text: i18n("Add Source")
visible: backendItem.backend
onTriggered: addSourceDialog.open()
onTriggered: {
var addSourceDialog = dialogComponent.createObject()
addSourceDialog.open()
}
}
MenuSeparator {
......@@ -117,10 +113,10 @@ DiscoverPage {
Instantiator {
id: backendActionsInst
model: ActionsModel {
actions: settingsButton.backend ? settingsButton.backend.actions : null
actions: backendItem.backend ? backendItem.backend.actions : undefined
}
delegate: MenuItem {
action: ActionBridge { action: model.action }
action: ActionBridge { action: action }
}
onObjectAdded: {
settingsMenu.insertItem(index, object)
......@@ -134,49 +130,68 @@ DiscoverPage {
}
}
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))
delegate: ConditionalLoader {
anchors {
right: parent.right
left: parent.left
}
readonly property variant resourcesBackend: model.resourcesBackend
readonly property variant sourcesBackend: model.sourcesBackend
readonly property variant display: model.display
readonly property variant checked: model.checked
readonly property variant statusTip: model.statusTip
readonly property variant toolTip: model.toolTip
readonly property variant modelIndex: sourcesView.model.index(index, 0)
condition: resourcesBackend != null
componentTrue: sourceBackendDelegate
componentFalse: sourceDelegate
}
Component {
id: sourceDelegate
Kirigami.SwipeListItem {
Layout.fillWidth: true
enabled: display.length>0
highlighted: ListView.isCurrentItem
onClicked: Navigation.openApplicationListSource(display)
Keys.onReturnPressed: clicked()
actions: [
Kirigami.Action {
enabled: display.length>0
iconName: "view-filter"
tooltip: i18n("Browse the origin's resources")
onTriggered: Navigation.openApplicationListSource(display)
},
Kirigami.Action {
iconName: "edit-delete"
tooltip: i18n("Delete the origin")
onTriggered: {
var backend = sb
if (!backend.removeSource(display)) {
window.showPassiveNotification(i18n("Failed to remove the source '%1'", 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
RowLayout {
CheckBox {
id: enabledBox
readonly property variant modelChecked: sourcesView.model.data(modelIndex, Qt.CheckStateRole)
checked: modelChecked != Qt.Unchecked
enabled: modelChecked !== undefined
onClicked: {
sourcesView.model.setData(modelIndex, checkedState, Qt.CheckStateRole)
}
}
QQC2.Label {
text: display + " - <i>" + toolTip + "</i>"
elide: Text.ElideRight
Layout.fillWidth: true
}
}
QQC2.Label {
text: model.display + " - <i>" + model.toolTip + "</i>"
elide: Text.ElideRight
Layout.fillWidth: true
}
}
}
......@@ -200,7 +215,7 @@ DiscoverPage {
text: name
}
InstallApplicationButton {
application: model.application
application: application
}
}
}
......
......@@ -48,7 +48,7 @@ int ActionsModel::rowCount(const QModelIndex& parent) const
return parent.isValid() ? 0 : m_filteredActions.count();
}
void ActionsModel::setActions(const QList<QAction*>& actions)
void ActionsModel::setActions(const QVariant& actions)
{
if (m_actions == actions) {
return;
......@@ -61,7 +61,7 @@ void ActionsModel::setActions(const QList<QAction*>& actions)
void ActionsModel::reload()
{
QList<QAction*> actions = m_actions;
QList<QAction*> actions = m_actions.value<QList<QAction*>>();
if (m_priority>=0) {
actions = kFilter<QList<QAction*>>(actions, [this](QAction* action){ return action->priority() == m_priority; });
}
......
......@@ -30,7 +30,7 @@ class QAction;
class DISCOVERCOMMON_EXPORT ActionsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QList<QAction*> actions READ actions WRITE setActions NOTIFY actionsChanged)
Q_PROPERTY(QVariant actions READ actions WRITE setActions NOTIFY actionsChanged)
Q_PROPERTY(int filterPriority READ filterPriority WRITE setFilterPriority)
public:
explicit ActionsModel(QObject* parent = nullptr);
......@@ -42,16 +42,16 @@ class DISCOVERCOMMON_EXPORT ActionsModel : public QAbstractListModel
void setFilterPriority(int p);
int filterPriority() const;
void setActions(const QList<QAction*>& actions);
QList<QAction*> actions() const { return m_actions; }
void setActions(const QVariant& actions);
QVariant actions() const { return m_actions; }
Q_SIGNALS:
void actionsChanged(const QList<QAction*>& actions);
void actionsChanged(const QVariant& actions);
private:
void reload();
QList<QAction*> m_actions;
QVariant m_actions;
QList<QAction*> m_filteredActions;
int m_priority;
};
......
......@@ -51,6 +51,7 @@ LINK_PUBLIC
Qt5::Qml
Qt5::Widgets
KF5::I18n
KF5::ItemModels
LINK_PRIVATE
Qt5::Xml
Qt5::DBus
......
......@@ -27,15 +27,11 @@ DummySourcesBackend::DummySourcesBackend(AbstractResourcesBackend * parent)
, m_sources(new QStandardItemModel(this))
, m_testAction(new QAction(QIcon::fromTheme(QStringLiteral("kalgebra")), QStringLiteral("DummyAction"), this))
{
QHash<int, QByteArray> 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!"; });
connect(m_sources, &QStandardItemModel::itemChanged, this, [](QStandardItem* item) { qDebug() << "DummySource changed" << item << item->checkState(); });
}
QAbstractItemModel* DummySourcesBackend::sources()
......@@ -47,8 +43,9 @@ 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<QObject*>(this), AbstractSourcesBackend::SourcesBackend);
it->setCheckable(true);
it->setCheckState(Qt::Checked);
m_sources->appendRow(it);
return true;
}
......
......@@ -32,7 +32,6 @@ public:
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<QAction*> actions() const override;
......
......@@ -208,7 +208,6 @@ void FlatpakSourcesBackend::addRemote(FlatpakRemote *remote, FlatpakInstallation
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<QObject*>(this), AbstractSourcesBackend::SourcesBackend);
it->setFlatpakInstallation(installation);
......
......@@ -38,7 +38,6 @@ public:
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<QAction*> actions() const override;
......
......@@ -105,11 +105,6 @@ PackageKitSourcesBackend::PackageKitSourcesBackend(AbstractResourcesBackend* par
m_actions += createActionForService(service, this);
}
QString PackageKitSourcesBackend::name() const
{
return resourcesBackend()->displayName();
}
QString PackageKitSourcesBackend::idDescription()
{
return i18n("Repository URL:");
......@@ -134,8 +129,6 @@ void PackageKitSourcesBackend::addRepositoryDetails(const QString &id, const QSt
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)
......
......@@ -33,7 +33,6 @@ class PackageKitSourcesBackend : public AbstractSourcesBackend
public:
PackageKitSourcesBackend(AbstractResourcesBackend* parent);
QString name() const override;
QString idDescription() override;
bool addSource(const QString& id) override;
......
......@@ -77,6 +77,7 @@ class DISCOVERCOMMON_EXPORT AbstractResourcesBackend : public QObject
Q_PROPERTY(int updatesCount READ updatesCount NOTIFY updatesCountChanged)
Q_PROPERTY(bool hasSecurityUpdates READ hasSecurityUpdates NOTIFY updatesCountChanged)
Q_PROPERTY(bool isFetching READ isFetching NOTIFY fetchingChanged)
Q_PROPERTY(bool hasApplications READ hasApplications CONSTANT)
public:
/**
* Constructs an AbstractResourcesBackend
......
......@@ -33,7 +33,6 @@ 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<QAction*> actions READ actions CONSTANT)
public:
......@@ -41,12 +40,10 @@ class DISCOVERCOMMON_EXPORT AbstractSourcesBackend : public QObject
~AbstractSourcesBackend() override;
enum Roles {
SectionRole = Qt::StatusTipRole,
SourcesBackend
SourcesBackend = Qt::UserRole
};
Q_ENUM(Roles)
virtual QString name() const = 0;
virtual QString idDescription() = 0;
Q_SCRIPTABLE virtual bool addSource(const QString& id) = 0;
......
......@@ -22,30 +22,58 @@
#include <QtGlobal>
#include <QDebug>
#include <QAction>
#include "resources/AbstractResourcesBackend.h"
#include "resources/AbstractSourcesBackend.h"
Q_GLOBAL_STATIC(SourcesModel, s_sources)
class SourceBackendModel : public QAbstractListModel
{
Q_OBJECT
public:
SourceBackendModel(AbstractResourcesBackend* backend, QObject* parent)
: QAbstractListModel(parent), m_backend(backend)
{}
QVariant data(const QModelIndex & index, int role) const override {
if (!index.isValid()) return {};
switch(role) {
case SourcesModel::ResourcesBackend: return QVariant::fromValue<QObject*>(m_backend);
case SourcesModel::SourcesBackend: return QVariant::fromValue<QObject*>(m_sources);
}
return {};
}
int rowCount(const QModelIndex & parent) const override { return parent.isValid() ? 0 : 1; }
AbstractSourcesBackend* m_sources = nullptr;
private:
AbstractResourcesBackend* m_backend;
};
SourcesModel::SourcesModel(QObject* parent)
: QAbstractListModel(parent)
: KConcatenateRowsProxyModel(parent)
{}
SourcesModel::~SourcesModel() = default;
QHash<int, QByteArray> SourcesModel::roleNames() const
SourcesModel* SourcesModel::global()
{
return { {SourceBackend, "sourceBackend"} };
return s_sources;
}
SourcesModel* SourcesModel::global()
QHash<int, QByteArray> SourcesModel::roleNames() const
{
return s_sources;
QHash<int, QByteArray> roles = KConcatenateRowsProxyModel::roleNames();
roles.insert(SourcesBackend, "sourcesBackend");
roles.insert(ResourcesBackend, "resourcesBackend");
return roles;
}
static bool ensureModel(const QList<QByteArray> &roles)
{
static QList<QByteArray> required = {"sourcesBackend", "display", "checked"};
for (const auto &role: roles) {
static auto required = {"display", "checked"};
for (const auto &role: required) {
if (!roles.contains(role))
return false;
}
......@@ -54,43 +82,25 @@ static bool ensureModel(const QList<QByteArray> &roles)
void SourcesModel::addSourcesBackend(AbstractSourcesBackend* sources)
{
if (m_sources.contains(sources))
auto b = addBackend(qobject_cast<AbstractResourcesBackend*>(sources->parent()));
if (!b)
return;
b->m_sources = sources;
Q_ASSERT(ensureModel(sources->sources()->roleNames().values()));
beginInsertRows(QModelIndex(), m_sources.size(), m_sources.size());
m_sources += sources;
endInsertRows();
emit sourcesChanged();
addSourceModel(sources->sources());
}
QVariant SourcesModel::data(const QModelIndex& index, int role) const
SourceBackendModel* SourcesModel::addBackend(AbstractResourcesBackend* backend)
{
if(!index.isValid() || index.row()>=m_sources.count()) {
return QVariant();
}
switch(role) {
case SourceBackend:
return QVariant::fromValue<QObject*>(m_sources[index.row()]);
}
Q_ASSERT(backend);
if (backend->dynamicPropertyNames().contains("InSourcesModel"))
return nullptr;
backend->setProperty("InSourcesModel", 1);
return QVariant();
auto b = new SourceBackendModel(backend, this);
addSourceModel(b);
return b;
}
int SourcesModel::rowCount(const QModelIndex& parent) const
{
return parent.isValid() ? 0 : m_sources.count();
}
QObject * SourcesModel::backendForSection(const QString& status) const
{
AbstractSourcesBackend* ret = nullptr;
for(AbstractSourcesBackend* b: m_sources) {
if (b->name() == status) {
ret = b;
break;
}
}
return ret;
}
#include "SourcesModel.moc"
......@@ -23,37 +23,30 @@
#include <QAbstractListModel>
#include <QSet>
#include <QtQml/QQmlListProperty>
#include <KConcatenateRowsProxyModel>
#include "discovercommon_export.h"
class QAction;
class AbstractSourcesBackend;
class DISCOVERCOMMON_EXPORT SourcesModel : public QAbstractListModel
class AbstractResourcesBackend;
class SourceBackendModel;
class DISCOVERCOMMON_EXPORT SourcesModel : public KConcatenateRowsProxyModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY sourcesChanged)
public:
enum Roles {
SourceBackend = Qt::UserRole+1
SourcesBackend = Qt::UserRole+1,
ResourcesBackend
};
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<int, QByteArray> roleNames() const override;
public Q_SLOTS:
QObject* backendForSection(const QString &status) const;
Q_SIGNALS:
void sourcesChanged();
private:
QList<AbstractSourcesBackend*> m_sources;
SourceBackendModel* addBackend(AbstractResourcesBackend* backend);
void addSourcesBackend(AbstractSourcesBackend* sources);
};
#endif // SOURCESMODEL_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment