Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1,32 @@
ecm_add_qml_module(itemmodelsplugin
URI "org.kde.kitemmodels"
VERSION 1.0
GENERATE_PLUGIN_SOURCE
DEPENDENCIES
QtCore
)
target_sources(itemmodelsplugin PRIVATE
kdescendantsproxymodel_qml.cpp
kdescendantsproxymodel_qml.h
krolenames.cpp
krolenames.h
ksortfilterproxymodel.cpp
ksortfilterproxymodel.h
types.h
)
ecm_qt_declare_logging_category(itemmodelsplugin
HEADER kitemmodels_debug.h
IDENTIFIER KITEMMODELS_LOG
CATEGORY_NAME kf.itemmodels.quick
DESCRIPTION "KItemModels (QtQuick)"
EXPORT KITEMMODELS
)
target_link_libraries(itemmodelsplugin PRIVATE
Qt6::Qml
KF6::ItemModels
)
ecm_finalize_qml_module(itemmodelsplugin DESTINATION ${KDE_INSTALL_QMLDIR} EXPORT KF6ItemModelsTargets)
@@ -0,0 +1,46 @@
/*
SPDX-FileCopyrightText: 2020 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kdescendantsproxymodel_qml.h"
#include <QDebug>
KDescendantsProxyModelQml::KDescendantsProxyModelQml(QObject *parent)
: KDescendantsProxyModel(parent)
{
}
KDescendantsProxyModelQml::~KDescendantsProxyModelQml()
{
}
void KDescendantsProxyModelQml::expandChildren(int row)
{
QModelIndex idx = mapToSource(index(row, 0));
expandSourceIndex(idx);
}
void KDescendantsProxyModelQml::collapseChildren(int row)
{
QModelIndex idx = mapToSource(index(row, 0));
collapseSourceIndex(idx);
}
void KDescendantsProxyModelQml::toggleChildren(int row)
{
QModelIndex sourceIndex = mapToSource(index(row, 0));
if (!sourceModel()->hasChildren(sourceIndex)) {
return;
}
if (isSourceIndexExpanded(sourceIndex)) {
collapseSourceIndex(sourceIndex);
} else {
expandSourceIndex(sourceIndex);
}
}
#include "moc_kdescendantsproxymodel_qml.cpp"
@@ -0,0 +1,29 @@
/*
SPDX-FileCopyrightText: 2020 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
// This class exposes KDescendantsProxyModel in a more QML friendly way
#pragma once
#include <KDescendantsProxyModel>
#include <QObject>
#include <QPointer>
#include <qqmlregistration.h>
class KDescendantsProxyModelQml : public KDescendantsProxyModel
{
Q_OBJECT
QML_NAMED_ELEMENT(KDescendantsProxyModel)
public:
explicit KDescendantsProxyModelQml(QObject *parent = nullptr);
~KDescendantsProxyModelQml() override;
Q_INVOKABLE void expandChildren(int row);
Q_INVOKABLE void collapseChildren(int row);
Q_INVOKABLE void toggleChildren(int row);
};
@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "krolenames.h"
#include <QAbstractItemModel>
#include <QQmlInfo>
class KRoleNamesPrivate
{
KRoleNames *const q;
public:
explicit KRoleNamesPrivate(KRoleNames *qq)
: q(qq)
{
}
QHash<int, QByteArray> roleNames() const;
QAbstractItemModel *model() const;
};
KRoleNames::KRoleNames(QObject *parent)
: QObject(parent)
, d(new KRoleNamesPrivate(this))
{
Q_ASSERT(parent);
if (!d->model()) {
qmlWarning(parent) << "KRoleNames must be attached to a QAbstractItemModel";
return;
}
}
KRoleNames::~KRoleNames() = default;
QByteArray KRoleNames::roleName(int role) const
{
const auto map = d->roleNames();
return map.value(role, QByteArray());
}
int KRoleNames::role(const QByteArray &roleName) const
{
const auto map = d->roleNames();
return map.key(roleName, -1);
}
KRoleNames *KRoleNames::qmlAttachedProperties(QObject *object)
{
return new KRoleNames(object);
}
QHash<int, QByteArray> KRoleNamesPrivate::roleNames() const
{
if (const auto m = model()) {
return m->roleNames();
}
return {};
}
QAbstractItemModel *KRoleNamesPrivate::model() const
{
return qobject_cast<QAbstractItemModel *>(q->parent());
}
#include "moc_krolenames.cpp"
@@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KROLENAMES_H
#define KROLENAMES_H
#include <QObject>
#include <qqml.h>
#include <memory>
class QAbstractItemModel;
class KRoleNamesPrivate;
/**
* @class KRoleNames
*
* @brief A mapper between roles and role names of an attachee model.
*
* KRoleNames exposes runtime-invokable methods to map from roles to role names
* and vice-versa. It can be used to retrieve data from a model in an imperative
* fashion when enum with roles is not available at runtime (i.e. not exported
* via Q_ENUM macro) but role names are known; or just to maintain consistency
* with view delegates (which use role names as properties).
*
* @since 6.0
*/
class KRoleNames : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("KRoleNames can only be used as an attached property")
QML_ATTACHED(KRoleNames)
QML_ADDED_IN_MINOR_VERSION(1)
public:
explicit KRoleNames(QObject *parent = nullptr);
~KRoleNames() override;
/**
* Maps role number to role name.
*
* Returns an empty string if role is not found in attachee model's
* roleNames() hash map.
*
* @since 6.0
*/
Q_INVOKABLE QByteArray roleName(int role) const;
/**
* Maps role name to role number.
*
* Returns -1 if role name is not found in attachee model's
* roleNames() hash map.
*
* @since 6.0
*/
Q_INVOKABLE int role(const QByteArray &roleName) const;
static KRoleNames *qmlAttachedProperties(QObject *object);
private:
std::unique_ptr<KRoleNamesPrivate> const d;
};
QML_DECLARE_TYPEINFO(KRoleNames, QML_HAS_ATTACHED_PROPERTIES)
#endif
@@ -0,0 +1,314 @@
/*
* SPDX-FileCopyrightText: 2010 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "ksortfilterproxymodel.h"
#include <QQmlContext>
#include <QQmlEngine>
#include "kitemmodels_debug.h"
KSortFilterProxyModel::KSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
, m_componentCompleted(false)
, m_sortRoleSourceOfTruth(SourceOfTruthIsRoleID)
, m_filterRoleSourceOfTruth(SourceOfTruthIsRoleID)
, m_sortRoleGuard(false)
, m_filterRoleGuard(false)
{
setDynamicSortFilter(true);
connect(this, &KSortFilterProxyModel::modelReset, this, &KSortFilterProxyModel::rowCountChanged);
connect(this, &KSortFilterProxyModel::rowsInserted, this, &KSortFilterProxyModel::rowCountChanged);
connect(this, &KSortFilterProxyModel::rowsRemoved, this, &KSortFilterProxyModel::rowCountChanged);
connect(this, &KSortFilterProxyModel::sortRoleChanged, this, &KSortFilterProxyModel::syncSortRoleProperties);
connect(this, &KSortFilterProxyModel::filterRoleChanged, this, &KSortFilterProxyModel::syncFilterRoleProperties);
}
KSortFilterProxyModel::~KSortFilterProxyModel()
{
}
static void reverseStringIntHash(QHash<QString, int> &dst, const QHash<int, QByteArray> &src)
{
dst.clear();
dst.reserve(src.count());
for (auto i = src.constBegin(); i != src.constEnd(); ++i) {
dst[QString::fromUtf8(i.value())] = i.key();
}
}
void KSortFilterProxyModel::syncRoleNames()
{
if (!sourceModel()) {
return;
}
reverseStringIntHash(m_roleIds, roleNames());
m_sortRoleGuard = true;
syncSortRoleProperties();
m_sortRoleGuard = false;
m_filterRoleGuard = true;
syncFilterRoleProperties();
m_filterRoleGuard = false;
}
int KSortFilterProxyModel::roleNameToId(const QString &name) const
{
return m_roleIds.value(name, Qt::DisplayRole);
}
void KSortFilterProxyModel::setSourceModel(QAbstractItemModel *model)
{
const auto oldModel = sourceModel();
if (model == oldModel) {
return;
}
if (oldModel) {
for (const auto &connection : std::as_const(m_sourceModelConnections)) {
disconnect(connection);
}
}
QSortFilterProxyModel::setSourceModel(model);
// NOTE: some models actually fill their roleNames() only when they get some actual data, this works around the bad behavior
if (model) {
m_sourceModelConnections = {{
connect(model, &QAbstractItemModel::modelReset, this, &KSortFilterProxyModel::syncRoleNames),
connect(model, &QAbstractItemModel::rowsInserted, this, &KSortFilterProxyModel::syncRoleNames),
connect(model, &QAbstractItemModel::rowsRemoved, this, &KSortFilterProxyModel::syncRoleNames),
}};
}
if (m_componentCompleted) {
syncRoleNames();
}
}
bool KSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (m_filterRowCallback.isCallable()) {
QJSEngine *engine = qjsEngine(this);
QJSValueList args = {QJSValue(source_row), engine->toScriptValue(source_parent)};
QJSValue result = const_cast<KSortFilterProxyModel *>(this)->m_filterRowCallback.call(args);
if (result.isError()) {
qCWarning(KITEMMODELS_LOG) << "Row filter callback produced an error:";
qCWarning(KITEMMODELS_LOG) << result.toString();
return true;
} else {
return result.toBool();
}
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
bool KSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
{
if (m_filterColumnCallback.isCallable()) {
QJSEngine *engine = qjsEngine(this);
QJSValueList args = {QJSValue(source_column), engine->toScriptValue(source_parent)};
QJSValue result = const_cast<KSortFilterProxyModel *>(this)->m_filterColumnCallback.call(args);
if (result.isError()) {
qCWarning(KITEMMODELS_LOG) << "Row filter callback produced an error:";
qCWarning(KITEMMODELS_LOG) << result.toString();
return true;
} else {
return result.toBool();
}
}
return QSortFilterProxyModel::filterAcceptsColumn(source_column, source_parent);
}
void KSortFilterProxyModel::setFilterString(const QString &filterString)
{
if (filterString == m_filterString) {
return;
}
m_filterString = filterString;
QSortFilterProxyModel::setFilterFixedString(filterString);
Q_EMIT filterStringChanged();
}
QString KSortFilterProxyModel::filterString() const
{
return m_filterString;
}
QJSValue KSortFilterProxyModel::filterRowCallback() const
{
return m_filterRowCallback;
}
void KSortFilterProxyModel::setFilterRowCallback(const QJSValue &callback)
{
if (m_filterRowCallback.strictlyEquals(callback)) {
return;
}
if (!callback.isNull() && !callback.isCallable()) {
return;
}
m_filterRowCallback = callback;
invalidateFilter();
Q_EMIT filterRowCallbackChanged(callback);
}
void KSortFilterProxyModel::setFilterColumnCallback(const QJSValue &callback)
{
if (m_filterColumnCallback.strictlyEquals(callback)) {
return;
}
if (!callback.isNull() && !callback.isCallable()) {
return;
}
m_filterColumnCallback = callback;
invalidateFilter();
Q_EMIT filterColumnCallbackChanged(callback);
}
QJSValue KSortFilterProxyModel::filterColumnCallback() const
{
return m_filterColumnCallback;
}
void KSortFilterProxyModel::syncSortRoleProperties()
{
if (!sourceModel()) {
return;
}
if (!m_sortRoleGuard) {
m_sortRoleSourceOfTruth = SourceOfTruthIsRoleID;
}
if (m_sortRoleSourceOfTruth == SourceOfTruthIsRoleName) {
if (m_sortRoleName.isEmpty()) {
QSortFilterProxyModel::setSortRole(Qt::DisplayRole);
sort(-1, Qt::AscendingOrder);
} else {
const auto role = roleNameToId(m_sortRoleName);
QSortFilterProxyModel::setSortRole(role);
sort(std::max(sortColumn(), 0), sortOrder());
}
} else {
const QString roleName = QString::fromUtf8(roleNames().value(sortRole()));
if (m_sortRoleName != roleName) {
m_sortRoleName = roleName;
Q_EMIT sortRoleNameChanged();
}
}
}
void KSortFilterProxyModel::syncFilterRoleProperties()
{
if (!sourceModel()) {
return;
}
if (!m_filterRoleGuard) {
m_filterRoleSourceOfTruth = SourceOfTruthIsRoleID;
}
if (m_filterRoleSourceOfTruth == SourceOfTruthIsRoleName) {
const auto role = roleNameToId(m_filterRoleName);
QSortFilterProxyModel::setFilterRole(role);
} else {
const QString roleName = QString::fromUtf8(roleNames().value(filterRole()));
if (m_filterRoleName != roleName) {
m_filterRoleName = roleName;
Q_EMIT filterRoleNameChanged();
}
}
}
void KSortFilterProxyModel::setFilterRoleName(const QString &roleName)
{
if (m_filterRoleSourceOfTruth == SourceOfTruthIsRoleName && m_filterRoleName == roleName) {
return;
}
m_filterRoleSourceOfTruth = SourceOfTruthIsRoleName;
m_filterRoleName = roleName;
m_filterRoleGuard = true;
syncFilterRoleProperties();
m_filterRoleGuard = false;
Q_EMIT filterRoleNameChanged();
}
QString KSortFilterProxyModel::filterRoleName() const
{
return m_filterRoleName;
}
void KSortFilterProxyModel::setSortRoleName(const QString &roleName)
{
if (m_sortRoleSourceOfTruth == SourceOfTruthIsRoleName && m_sortRoleName == roleName) {
return;
}
m_sortRoleSourceOfTruth = SourceOfTruthIsRoleName;
m_sortRoleName = roleName;
m_sortRoleGuard = true;
syncSortRoleProperties();
m_sortRoleGuard = false;
Q_EMIT sortRoleNameChanged();
}
QString KSortFilterProxyModel::sortRoleName() const
{
return m_sortRoleName;
}
void KSortFilterProxyModel::setSortOrder(const Qt::SortOrder order)
{
sort(std::max(sortColumn(), 0), order);
Q_EMIT sortOrderChanged();
}
void KSortFilterProxyModel::setSortColumn(int column)
{
if (column == sortColumn()) {
return;
}
sort(column, sortOrder());
Q_EMIT sortColumnChanged();
}
void KSortFilterProxyModel::classBegin()
{
}
void KSortFilterProxyModel::componentComplete()
{
m_componentCompleted = true;
syncRoleNames();
}
void KSortFilterProxyModel::invalidateFilter()
{
QSortFilterProxyModel::invalidateFilter();
}
#include "moc_ksortfilterproxymodel.cpp"
@@ -0,0 +1,178 @@
/*
* SPDX-FileCopyrightText: 2010 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KSORTFILTERPROXYMODEL_H
#define KSORTFILTERPROXYMODEL_H
#include <QAbstractItemModel>
#include <QJSValue>
#include <QList>
#include <QQmlParserStatus>
#include <QSortFilterProxyModel>
#include <qqmlregistration.h>
#include <array>
/**
* @class KSortFilterProxyModel
* @short Filter and sort an existing QAbstractItemModel
*
* @since 5.67
*/
class KSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
QML_ELEMENT
Q_INTERFACES(QQmlParserStatus)
/**
* The string for the filter, only rows with their filterRole matching filterString will be displayed
*/
Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged)
/**
* A JavaScript callable that can be used to perform advanced filters on a given row.
* The callback is passed the source row, and source parent for a given row as arguments
*
* The callable's return value is evaluated as boolean to determine
* whether the row is accepted (true) or filtered out (false). It overrides the default implementation
* that uses filterRegExp or filterString; while filterCallback is set those two properties are
* ignored. Attempts to write a non-callable to this property are silently ignored, but you can set
* it to null.
*
* @code
* filterRowCallback: function(source_row, source_parent) {
* return sourceModel.data(sourceModel.index(source_row, 0, source_parent), Qt.DisplayRole) == "...";
* };
* @endcode
*/
Q_PROPERTY(QJSValue filterRowCallback READ filterRowCallback WRITE setFilterRowCallback NOTIFY filterRowCallbackChanged)
/**
* A JavaScript callable that can be used to perform advanced filters on a given column.
* The callback is passed the source column, and source parent for a given column as arguments.
*
* @see filterRowCallback
*/
Q_PROPERTY(QJSValue filterColumnCallback READ filterColumnCallback WRITE setFilterColumnCallback NOTIFY filterColumnCallbackChanged)
/**
* The role of the sourceModel on which the filter will be applied.
* This can either be the numerical role value or the role name as a string.
*/
Q_PROPERTY(QString filterRoleName READ filterRoleName WRITE setFilterRoleName NOTIFY filterRoleNameChanged)
/**
* The role of the sourceModel that will be used for sorting. if empty the order will be left unaltered
* This can either be the numerical role value or the role name as a string.
*/
Q_PROPERTY(QString sortRoleName READ sortRoleName WRITE setSortRoleName NOTIFY sortRoleNameChanged)
/**
* One of Qt.AscendingOrder or Qt.DescendingOrder
*/
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
/**
* Specify which column should be used for sorting
* The default value is -1.
* If \a sortRole is set, the default value is 0.
*/
Q_PROPERTY(int sortColumn READ sortColumn WRITE setSortColumn NOTIFY sortColumnChanged)
/**
* The number of top level rows.
*/
Q_PROPERTY(int count READ rowCount NOTIFY rowCountChanged)
public:
explicit KSortFilterProxyModel(QObject *parent = nullptr);
~KSortFilterProxyModel() override;
void setSourceModel(QAbstractItemModel *sourceModel) override;
void setFilterRowCallback(const QJSValue &callback);
QJSValue filterRowCallback() const;
void setFilterString(const QString &filterString);
QString filterString() const;
void setFilterColumnCallback(const QJSValue &callback);
QJSValue filterColumnCallback() const;
void setFilterRoleName(const QString &roleName);
QString filterRoleName() const;
void setSortRoleName(const QString &roleName);
QString sortRoleName() const;
void setSortOrder(const Qt::SortOrder order);
void setSortColumn(int column);
void classBegin() override;
void componentComplete() override;
public Q_SLOTS:
/**
* Invalidates the current filtering.
*
* This function should be called if you are implementing custom filtering through
* filterRowCallback or filterColumnCallback, and your filter parameters have changed.
*
* @since 5.70
*/
void invalidateFilter();
Q_SIGNALS:
void filterStringChanged();
void filterRoleNameChanged();
void sortRoleNameChanged();
void sortOrderChanged();
void sortColumnChanged();
void filterRowCallbackChanged(const QJSValue &);
void filterColumnCallbackChanged(const QJSValue &);
void rowCountChanged();
protected:
int roleNameToId(const QString &name) const;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override;
protected Q_SLOTS:
// This method is called whenever we suspect that role names mapping might have gone stale.
// It must not alter the source of truth for sort/filter properties.
void syncRoleNames();
// These methods are dealing with individual pairs of properties. They are
// called on various occasions, and need to check whether the invocation
// has been caused by a standalone base type's property change
// (switching source of truth to role ID) or as a side-effect of a sync.
void syncSortRoleProperties();
void syncFilterRoleProperties();
private:
// conveniently, role ID is the default source of truth, turning it into
// zero-initialization.
enum SourceOfTruthForRoleProperty : bool {
SourceOfTruthIsRoleID = false,
SourceOfTruthIsRoleName = true,
};
bool m_componentCompleted : 1;
SourceOfTruthForRoleProperty m_sortRoleSourceOfTruth : 1;
SourceOfTruthForRoleProperty m_filterRoleSourceOfTruth : 1;
bool m_sortRoleGuard : 1;
bool m_filterRoleGuard : 1;
// default role name corresponds to the standard mapping of the default Qt::DisplayRole in QAbstractItemModel::roleNames
QString m_sortRoleName{QStringLiteral("display")};
QString m_filterRoleName{QStringLiteral("display")};
QString m_filterString;
QJSValue m_filterRowCallback;
QJSValue m_filterColumnCallback;
QHash<QString, int> m_roleIds;
std::array<QMetaObject::Connection, 3> m_sourceModelConnections;
};
#endif
@@ -0,0 +1,24 @@
/*
SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <QQmlEngine>
#include <KColumnHeadersModel>
#include <KNumberModel>
struct KColumnHeadersModelForeign {
Q_GADGET
QML_NAMED_ELEMENT(KColumnHeadersModel)
QML_FOREIGN(KColumnHeadersModel)
};
struct KNumberModelForeign {
Q_GADGET
QML_NAMED_ELEMENT(KNumberModel)
QML_FOREIGN(KNumberModel)
};