diff --git a/.clang-tidy b/.clang-tidy index 002c444..c83ed8f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -20,6 +20,7 @@ Checks: > -cppcoreguidelines-avoid-do-while, -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-use-enum-class, google-global-names-in-headers, google-readability-casting, google-runtime-int, @@ -63,6 +64,8 @@ CheckOptions: readability-identifier-naming.ParameterCase: camelBack readability-identifier-naming.VariableCase: camelBack + misc-const-correctness.WarnPointersAsPointers: false + # does not appear to work readability-operators-representation.BinaryOperators: '&&;&=;&;|;~;!;!=;||;|=;^;^=' readability-operators-representation.OverloadedOperators: '&&;&=;&;|;~;!;!=;||;|=;^;^=' diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6029b42..472ae04 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -24,7 +24,6 @@ qt_add_library(quickshell-core STATIC elapsedtimer.cpp desktopentry.cpp desktopentrymonitor.cpp - objectrepeater.cpp platformmenu.cpp qsmenu.cpp retainable.cpp diff --git a/src/core/logging.cpp b/src/core/logging.cpp index 034a14d..3e3abca 100644 --- a/src/core/logging.cpp +++ b/src/core/logging.cpp @@ -746,11 +746,11 @@ bool EncodedLogReader::readVarInt(quint32* slot) { if (!this->reader.skip(1)) return false; *slot = qFromLittleEndian(n); } else if ((bytes[1] != 0xff || bytes[2] != 0xff) && readLength >= 3) { - auto n = *reinterpret_cast(bytes.data() + 1); + auto n = *reinterpret_cast(bytes.data() + 1); // NOLINT if (!this->reader.skip(3)) return false; *slot = qFromLittleEndian(n); } else if (readLength == 7) { - auto n = *reinterpret_cast(bytes.data() + 3); + auto n = *reinterpret_cast(bytes.data() + 3); // NOLINT if (!this->reader.skip(7)) return false; *slot = qFromLittleEndian(n); } else return false; diff --git a/src/core/model.cpp b/src/core/model.cpp index 165c606..c2b5d78 100644 --- a/src/core/model.cpp +++ b/src/core/model.cpp @@ -1,81 +1,13 @@ #include "model.hpp" -#include #include +#include #include -#include -#include -#include -#include -#include - -qint32 UntypedObjectModel::rowCount(const QModelIndex& parent) const { - if (parent != QModelIndex()) return 0; - return static_cast(this->valuesList.length()); -} - -QVariant UntypedObjectModel::data(const QModelIndex& index, qint32 role) const { - if (role != Qt::UserRole) return QVariant(); - return QVariant::fromValue(this->valuesList.at(index.row())); -} QHash UntypedObjectModel::roleNames() const { return {{Qt::UserRole, "modelData"}}; } -void UntypedObjectModel::insertObject(QObject* object, qsizetype index) { - auto iindex = index == -1 ? this->valuesList.length() : index; - emit this->objectInsertedPre(object, iindex); - - auto intIndex = static_cast(iindex); - this->beginInsertRows(QModelIndex(), intIndex, intIndex); - this->valuesList.insert(iindex, object); - this->endInsertRows(); - - emit this->valuesChanged(); - emit this->objectInsertedPost(object, iindex); -} - -void UntypedObjectModel::removeAt(qsizetype index) { - auto* object = this->valuesList.at(index); - emit this->objectRemovedPre(object, index); - - auto intIndex = static_cast(index); - this->beginRemoveRows(QModelIndex(), intIndex, intIndex); - this->valuesList.removeAt(index); - this->endRemoveRows(); - - emit this->valuesChanged(); - emit this->objectRemovedPost(object, index); -} - -bool UntypedObjectModel::removeObject(const QObject* object) { - auto index = this->valuesList.indexOf(object); - if (index == -1) return false; - - this->removeAt(index); - return true; -} - -void UntypedObjectModel::diffUpdate(const QVector& newValues) { - for (qsizetype i = 0; i < this->valuesList.length();) { - if (newValues.contains(this->valuesList.at(i))) i++; - else this->removeAt(i); - } - - qsizetype oi = 0; - for (auto* object: newValues) { - if (this->valuesList.length() == oi || this->valuesList.at(oi) != object) { - this->insertObject(object, oi); - } - - oi++; - } -} - -qsizetype UntypedObjectModel::indexOf(QObject* object) { return this->valuesList.indexOf(object); } - UntypedObjectModel* UntypedObjectModel::emptyInstance() { - static auto* instance = new UntypedObjectModel(nullptr); // NOLINT - return instance; + return ObjectModel::emptyInstance(); } diff --git a/src/core/model.hpp b/src/core/model.hpp index 3c5822a..0e88025 100644 --- a/src/core/model.hpp +++ b/src/core/model.hpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include #include @@ -49,14 +49,11 @@ class UntypedObjectModel: public QAbstractListModel { public: explicit UntypedObjectModel(QObject* parent): QAbstractListModel(parent) {} - [[nodiscard]] qint32 rowCount(const QModelIndex& parent) const override; - [[nodiscard]] QVariant data(const QModelIndex& index, qint32 role) const override; [[nodiscard]] QHash roleNames() const override; - [[nodiscard]] QList values() const { return this->valuesList; } - void removeAt(qsizetype index); + [[nodiscard]] virtual QList values() = 0; - Q_INVOKABLE qsizetype indexOf(QObject* object); + Q_INVOKABLE virtual qsizetype indexOf(QObject* object) const = 0; static UntypedObjectModel* emptyInstance(); @@ -71,15 +68,6 @@ signals: /// Sent immediately after an object is removed from the list. void objectRemovedPost(QObject* object, qsizetype index); -protected: - void insertObject(QObject* object, qsizetype index = -1); - bool removeObject(const QObject* object); - - // Assumes only one instance of a specific value - void diffUpdate(const QVector& newValues); - - QVector valuesList; - private: static qsizetype valuesCount(QQmlListProperty* property); static QObject* valueAt(QQmlListProperty* property, qsizetype index); @@ -90,14 +78,20 @@ class ObjectModel: public UntypedObjectModel { public: explicit ObjectModel(QObject* parent): UntypedObjectModel(parent) {} - [[nodiscard]] QVector& valueList() { return *std::bit_cast*>(&this->valuesList); } - - [[nodiscard]] const QVector& valueList() const { - return *std::bit_cast*>(&this->valuesList); - } + [[nodiscard]] const QList& valueList() const { return this->mValuesList; } + [[nodiscard]] QList& valueList() { return this->mValuesList; } void insertObject(T* object, qsizetype index = -1) { - this->UntypedObjectModel::insertObject(object, index); + auto iindex = index == -1 ? this->mValuesList.length() : index; + emit this->objectInsertedPre(object, iindex); + + auto intIndex = static_cast(iindex); + this->beginInsertRows(QModelIndex(), intIndex, intIndex); + this->mValuesList.insert(iindex, object); + this->endInsertRows(); + + emit this->valuesChanged(); + emit this->objectInsertedPost(object, iindex); } void insertObjectSorted(T* object, const std::function& compare) { @@ -110,17 +104,71 @@ public: } auto idx = iter - list.begin(); - this->UntypedObjectModel::insertObject(object, idx); + this->insertObject(object, idx); } - void removeObject(const T* object) { this->UntypedObjectModel::removeObject(object); } + bool removeObject(const T* object) { + auto index = this->mValuesList.indexOf(object); + if (index == -1) return false; + + this->removeAt(index); + return true; + } + + void removeAt(qsizetype index) { + auto* object = this->mValuesList.at(index); + emit this->objectRemovedPre(object, index); + + auto intIndex = static_cast(index); + this->beginRemoveRows(QModelIndex(), intIndex, intIndex); + this->mValuesList.removeAt(index); + this->endRemoveRows(); + + emit this->valuesChanged(); + emit this->objectRemovedPost(object, index); + } // Assumes only one instance of a specific value - void diffUpdate(const QVector& newValues) { - this->UntypedObjectModel::diffUpdate(*std::bit_cast*>(&newValues)); + void diffUpdate(const QList& newValues) { + for (qsizetype i = 0; i < this->mValuesList.length();) { + if (newValues.contains(this->mValuesList.at(i))) i++; + else this->removeAt(i); + } + + qsizetype oi = 0; + for (auto* object: newValues) { + if (this->mValuesList.length() == oi || this->mValuesList.at(oi) != object) { + this->insertObject(object, oi); + } + + oi++; + } } static ObjectModel* emptyInstance() { return static_cast*>(UntypedObjectModel::emptyInstance()); } + + [[nodiscard]] qint32 rowCount(const QModelIndex& parent) const override { + if (parent != QModelIndex()) return 0; + return static_cast(this->mValuesList.length()); + } + + [[nodiscard]] QVariant data(const QModelIndex& index, qint32 role) const override { + if (role != Qt::UserRole) return QVariant(); + // Values must be QObject derived, but we can't assert that here without breaking forward decls, + // so no static_cast. + return QVariant::fromValue(reinterpret_cast(this->mValuesList.at(index.row()))); + } + + qsizetype indexOf(QObject* object) const override { + return this->mValuesList.indexOf(reinterpret_cast(object)); + } + + [[nodiscard]] QList values() override { + return *reinterpret_cast*>(&this->mValuesList); + } + +private: + QList mValuesList; }; diff --git a/src/core/module.md b/src/core/module.md index b9404ea..41f065d 100644 --- a/src/core/module.md +++ b/src/core/module.md @@ -21,7 +21,6 @@ headers = [ "model.hpp", "elapsedtimer.hpp", "desktopentry.hpp", - "objectrepeater.hpp", "qsmenu.hpp", "retainable.hpp", "popupanchor.hpp", diff --git a/src/core/objectrepeater.cpp b/src/core/objectrepeater.cpp deleted file mode 100644 index 7971952..0000000 --- a/src/core/objectrepeater.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "objectrepeater.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QVariant ObjectRepeater::model() const { return this->mModel; } - -void ObjectRepeater::setModel(QVariant model) { - if (model == this->mModel) return; - - if (this->itemModel != nullptr) { - QObject::disconnect(this->itemModel, nullptr, this, nullptr); - } - - this->mModel = std::move(model); - emit this->modelChanged(); - this->reloadElements(); -} - -void ObjectRepeater::onModelDestroyed() { - this->mModel.clear(); - this->itemModel = nullptr; - emit this->modelChanged(); - this->reloadElements(); -} - -QQmlComponent* ObjectRepeater::delegate() const { return this->mDelegate; } - -void ObjectRepeater::setDelegate(QQmlComponent* delegate) { - if (delegate == this->mDelegate) return; - - if (this->mDelegate != nullptr) { - QObject::disconnect(this->mDelegate, nullptr, this, nullptr); - } - - this->mDelegate = delegate; - - if (delegate != nullptr) { - QObject::connect( - this->mDelegate, - &QObject::destroyed, - this, - &ObjectRepeater::onDelegateDestroyed - ); - } - - emit this->delegateChanged(); - this->reloadElements(); -} - -void ObjectRepeater::onDelegateDestroyed() { - this->mDelegate = nullptr; - emit this->delegateChanged(); - this->reloadElements(); -} - -void ObjectRepeater::reloadElements() { - for (auto i = this->valuesList.length() - 1; i >= 0; i--) { - this->removeComponent(i); - } - - if (this->mDelegate == nullptr || !this->mModel.isValid()) return; - - if (this->mModel.canConvert()) { - auto* model = this->mModel.value(); - this->itemModel = model; - - this->insertModelElements(model, 0, model->rowCount() - 1); // -1 is fine - - // clang-format off - QObject::connect(model, &QObject::destroyed, this, &ObjectRepeater::onModelDestroyed); - QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &ObjectRepeater::onModelRowsInserted); - QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &ObjectRepeater::onModelRowsRemoved); - QObject::connect(model, &QAbstractItemModel::rowsMoved, this, &ObjectRepeater::onModelRowsMoved); - QObject::connect(model, &QAbstractItemModel::modelAboutToBeReset, this, &ObjectRepeater::onModelAboutToBeReset); - // clang-format on - } else if (this->mModel.canConvert()) { - auto values = this->mModel.value(); - auto len = values.count(); - - for (auto i = 0; i != len; i++) { - this->insertComponent(i, {{"modelData", QVariant::fromValue(values.at(i))}}); - } - } else if (this->mModel.canConvert>()) { - auto values = this->mModel.value>(); - - for (auto& value: values) { - this->insertComponent(this->valuesList.length(), {{"modelData", value}}); - } - } else { - qCritical() << this - << "Cannot create components as the model is not compatible:" << this->mModel; - } -} - -void ObjectRepeater::insertModelElements(QAbstractItemModel* model, int first, int last) { - auto roles = model->roleNames(); - auto roleDataVec = QVector(); - for (auto id: roles.keys()) { - roleDataVec.push_back(QModelRoleData(id)); - } - - auto values = QModelRoleDataSpan(roleDataVec); - auto props = QVariantMap(); - - for (auto i = first; i != last + 1; i++) { - auto index = model->index(i, 0); - model->multiData(index, values); - - for (auto [id, name]: roles.asKeyValueRange()) { - props.insert(name, *values.dataForRole(id)); - } - - this->insertComponent(i, props); - - props.clear(); - } -} - -void ObjectRepeater::onModelRowsInserted(const QModelIndex& parent, int first, int last) { - if (parent != QModelIndex()) return; - - this->insertModelElements(this->itemModel, first, last); -} - -void ObjectRepeater::onModelRowsRemoved(const QModelIndex& parent, int first, int last) { - if (parent != QModelIndex()) return; - - for (auto i = last; i != first - 1; i--) { - this->removeComponent(i); - } -} - -void ObjectRepeater::onModelRowsMoved( - const QModelIndex& sourceParent, - int sourceStart, - int sourceEnd, - const QModelIndex& destParent, - int destStart -) { - auto hasSource = sourceParent != QModelIndex(); - auto hasDest = destParent != QModelIndex(); - - if (!hasSource && !hasDest) return; - - if (hasSource) { - this->onModelRowsRemoved(sourceParent, sourceStart, sourceEnd); - } - - if (hasDest) { - this->onModelRowsInserted(destParent, destStart, destStart + (sourceEnd - sourceStart)); - } -} - -void ObjectRepeater::onModelAboutToBeReset() { - auto last = static_cast(this->valuesList.length() - 1); - this->onModelRowsRemoved(QModelIndex(), 0, last); // -1 is fine -} - -void ObjectRepeater::insertComponent(qsizetype index, const QVariantMap& properties) { - auto* context = QQmlEngine::contextForObject(this); - auto* instance = this->mDelegate->createWithInitialProperties(properties, context); - - if (instance == nullptr) { - qWarning().noquote() << this->mDelegate->errorString(); - qWarning() << this << "failed to create object for model data" << properties; - } else { - QQmlEngine::setObjectOwnership(instance, QQmlEngine::CppOwnership); - instance->setParent(this); - } - - this->insertObject(instance, index); -} - -void ObjectRepeater::removeComponent(qsizetype index) { - auto* instance = this->valuesList.at(index); - this->removeAt(index); - delete instance; -} diff --git a/src/core/objectrepeater.hpp b/src/core/objectrepeater.hpp deleted file mode 100644 index 409b12d..0000000 --- a/src/core/objectrepeater.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "model.hpp" - -///! A Repeater / for loop / map for non Item derived objects. -/// > [!ERROR] Removed in favor of @@QtQml.Models.Instantiator -/// -/// The ObjectRepeater creates instances of the provided delegate for every entry in the -/// given model, similarly to a @@QtQuick.Repeater but for non visual types. -class ObjectRepeater: public ObjectModel { - Q_OBJECT; - /// The model providing data to the ObjectRepeater. - /// - /// Currently accepted model types are `list` lists, javascript arrays, - /// and [QAbstractListModel] derived models, though only one column will be repeated - /// from the latter. - /// - /// Note: @@ObjectModel is a [QAbstractListModel] with a single column. - /// - /// [QAbstractListModel]: https://doc.qt.io/qt-6/qabstractlistmodel.html - Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged); - /// The delegate component to repeat. - /// - /// The delegate is given the same properties as in a Repeater, except `index` which - /// is not currently implemented. - /// - /// If the model is a `list` or javascript array, a `modelData` property will be - /// exposed containing the entry from the model. If the model is a [QAbstractListModel], - /// the roles from the model will be exposed. - /// - /// Note: @@ObjectModel has a single role named `modelData` for compatibility with normal lists. - /// - /// [QAbstractListModel]: https://doc.qt.io/qt-6/qabstractlistmodel.html - Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged); - Q_CLASSINFO("DefaultProperty", "delegate"); - QML_ELEMENT; - QML_UNCREATABLE("ObjectRepeater has been removed in favor of QtQml.Models.Instantiator."); - -public: - explicit ObjectRepeater(QObject* parent = nullptr): ObjectModel(parent) {} - - [[nodiscard]] QVariant model() const; - void setModel(QVariant model); - - [[nodiscard]] QQmlComponent* delegate() const; - void setDelegate(QQmlComponent* delegate); - -signals: - void modelChanged(); - void delegateChanged(); - -private slots: - void onDelegateDestroyed(); - void onModelDestroyed(); - void onModelRowsInserted(const QModelIndex& parent, int first, int last); - void onModelRowsRemoved(const QModelIndex& parent, int first, int last); - - void onModelRowsMoved( - const QModelIndex& sourceParent, - int sourceStart, - int sourceEnd, - const QModelIndex& destParent, - int destStart - ); - - void onModelAboutToBeReset(); - -private: - void reloadElements(); - void insertModelElements(QAbstractItemModel* model, int first, int last); - void insertComponent(qsizetype index, const QVariantMap& properties); - void removeComponent(qsizetype index); - - QVariant mModel; - QAbstractItemModel* itemModel = nullptr; - QQmlComponent* mDelegate = nullptr; -}; diff --git a/src/core/util.hpp b/src/core/util.hpp index 88583d0..3b86d28 100644 --- a/src/core/util.hpp +++ b/src/core/util.hpp @@ -29,7 +29,7 @@ struct StringLiteral16 { } [[nodiscard]] constexpr const QChar* qCharPtr() const noexcept { - return std::bit_cast(&this->value); + return std::bit_cast(&this->value); // NOLINT } [[nodiscard]] Q_ALWAYS_INLINE operator QString() const noexcept { diff --git a/src/dbus/properties.hpp b/src/dbus/properties.hpp index f6a6330..1596cb7 100644 --- a/src/dbus/properties.hpp +++ b/src/dbus/properties.hpp @@ -217,7 +217,7 @@ protected: private: [[nodiscard]] constexpr Owner* owner() const { - auto* self = std::bit_cast(this); + auto* self = std::bit_cast(this); // NOLINT return std::bit_cast(self - offset()); // NOLINT } diff --git a/src/services/pipewire/device.cpp b/src/services/pipewire/device.cpp index 314fd63..e3bc967 100644 --- a/src/services/pipewire/device.cpp +++ b/src/services/pipewire/device.cpp @@ -107,7 +107,7 @@ void PwDevice::addDeviceIndexPairs(const spa_pod* param) { qint32 device = 0; qint32 index = 0; - spa_pod* props = nullptr; + const spa_pod* props = nullptr; // clang-format off quint32 id = SPA_PARAM_Route; diff --git a/src/services/polkit/listener.cpp b/src/services/polkit/listener.cpp index 643292c..875cff6 100644 --- a/src/services/polkit/listener.cpp +++ b/src/services/polkit/listener.cpp @@ -231,4 +231,4 @@ void AuthRequest::cancel(const QString& reason) { // NOLINTEND(readability-make-member-function-const) } // namespace qs::service::polkit -// NOLINTEND(readability-identifier-naming,misc-use-anonymous-namespace) \ No newline at end of file +// NOLINTEND(readability-identifier-naming,misc-use-anonymous-namespace)