/** * Copyright (C) 2021-2024 Saturneric * * This file is part of GpgFrontend. * * GpgFrontend 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 3 of the License, or * (at your option) any later version. * * GpgFrontend 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 GpgFrontend. If not, see . * * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by * Saturneric starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GlobalRegisterTable.h" #include #include #include #include #include "GlobalRegisterTableTreeModel.h" #include "function/SecureMemoryAllocator.h" #include "utils/MemoryUtils.h" namespace GpgFrontend::Module { class GlobalRegisterTable::Impl { public: struct RTNode { QString name; QString type = tr("NODE"); int version = 0; const std::type_info* value_type = nullptr; std::optional value = std::nullopt; QMap> children; QWeakPointer parent; explicit RTNode(QString name, const QSharedPointer& parent) : name(std::move(name)), parent(parent) {} }; using RTNodePtr = QSharedPointer; explicit Impl(GlobalRegisterTable* parent) : parent_(parent), root_node_(SecureCreateSharedObject("", nullptr)) {} auto PublishKV(const Namespace& n, const Key& k, std::any v) -> bool { QStringList const segments = (n + "." + k).split('.'); int version = 0; { std::unique_lock lock(lock_); auto current = root_node_; for (const QString& segment : segments) { auto it = current->children.find(segment); if (it == current->children.end()) { it = current->children.insert( segment, SecureCreateSharedObject(segment, current)); } current = it.value(); } current->name = segments.back(); current->type = tr("LEAF"); current->value = v; current->value_type = &v.type(); version = ++current->version; } emit parent_->SignalPublish(n, k, version, v); return true; } auto LookupKV(const Namespace& n, const Key& k) -> std::optional { QStringList const segments = (n + "." + k).split('.'); std::optional rtn = std::nullopt; { std::shared_lock const lock(lock_); auto current = root_node_; for (const QString& segment : segments) { auto it = current->children.find(segment); if (it == current->children.end()) return std::nullopt; current = it.value(); } rtn = current->value; } return rtn; } auto ListChildKeys(const Namespace& n, const Key& k) -> QContainer { QStringList const segments = (n + "." + k).split('.'); QContainer rtn; { std::shared_lock lock(lock_); auto current = root_node_; for (const QString& segment : segments) { auto it = current->children.find(segment); if (it == current->children.end()) return {}; current = it.value(); } for (auto& key : current->children.keys()) rtn.push_back(key); } return rtn; } auto ListenPublish(QObject* o, const Namespace& n, const Key& k, LPCallback c) -> bool { if (o == nullptr) return false; return QObject::connect(parent_, &GlobalRegisterTable::SignalPublish, o, [n, k, c](const Namespace& pn, const Key& pk, int ver, std::any value) { if (pn == n && pk == k) { c(pn, pk, ver, std::move(value)); } }) == nullptr; } auto RootRTNode() -> RTNodePtr { return root_node_; } private: std::shared_mutex lock_; GlobalRegisterTable* parent_; RTNodePtr root_node_; }; class GlobalRegisterTableTreeModel::Impl { public: using RTNode = GlobalRegisterTable::Impl::RTNode; Impl(GlobalRegisterTableTreeModel* parent, GlobalRegisterTable::Impl* grt) : parent_(parent), root_node_(grt->RootRTNode()) {} [[nodiscard]] auto RowCount(const QModelIndex& parent) const -> int { auto* parent_node = !parent.isValid() ? root_node_.get() : static_cast(parent.internalPointer()); return parent_node->children.size(); } [[nodiscard]] auto ColumnCount(const QModelIndex& parent) const -> int { return 4; } [[nodiscard]] auto Data(const QModelIndex& index, int role) const -> QVariant { if (!index.isValid()) return {}; if (role == Qt::DisplayRole) { auto* node = static_cast(index.internalPointer()); switch (index.column()) { case 0: return node->name; case 1: return node->type; case 2: return QString(node->value && node->value.has_value() ? node->value->type().name() : ""); case 3: return Any2QVariant(node->value); default: return {}; } } return {}; } static auto Any2QVariant(std::optional op) -> QVariant { if (!op) return tr(""); auto& o = op.value(); if (o.type() == typeid(QString)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(std::string)) { return QVariant::fromValue( QString::fromStdString(std::any_cast(o))); } if (o.type() == typeid(int)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(long)) { return QVariant::fromValue( static_cast(std::any_cast(o))); } if (o.type() == typeid(long long)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(unsigned)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(unsigned long)) { return QVariant::fromValue( static_cast(std::any_cast(o))); } if (o.type() == typeid(unsigned long long)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(float)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(double)) { return QVariant::fromValue(std::any_cast(o)); } if (o.type() == typeid(bool)) { return QVariant::fromValue(std::any_cast(o)); } return tr(""); } [[nodiscard]] auto Index(int row, int column, const QModelIndex& parent) const -> QModelIndex { if (!parent_->hasIndex(row, column, parent)) return {}; auto* parent_node = !parent.isValid() ? root_node_.get() : static_cast(parent.internalPointer()); auto key = parent_node->children.keys().at(row); auto child_node = parent_node->children.value(key); return parent_->createIndex(row, column, child_node.get()); } [[nodiscard]] auto Parent(const QModelIndex& index) const -> QModelIndex { if (!index.isValid()) return {}; auto* child_node = static_cast(index.internalPointer()); auto parent_node = child_node->parent.lock(); if (!parent_node || parent_node == root_node_) return {}; int const row = static_cast( parent_node->parent.lock()->children.keys().indexOf(parent_node->name)); return parent_->createIndex(row, 0, parent_node.data()); } [[nodiscard]] static auto HeaderData(int section, Qt::Orientation orientation, int role) -> QVariant { if (role != Qt::DisplayRole) return {}; if (orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Key"); case 1: return tr("Type"); case 2: return tr("Value Type"); case 3: return tr("Value"); default: return {}; } } return {}; } private: GlobalRegisterTableTreeModel* parent_; GlobalRegisterTable::Impl::RTNodePtr root_node_; }; GlobalRegisterTable::GlobalRegisterTable() : p_(SecureCreateUniqueObject(this)) {} GlobalRegisterTable::~GlobalRegisterTable() = default; auto GlobalRegisterTable::PublishKV(Namespace n, Key k, std::any v) -> bool { return p_->PublishKV(n, k, v); } auto GlobalRegisterTable::LookupKV(Namespace n, Key v) -> std::optional { return p_->LookupKV(n, v); } auto GlobalRegisterTable::ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) -> bool { return p_->ListenPublish(o, n, k, c); } auto GlobalRegisterTable::ListChildKeys(Namespace n, Key k) -> QContainer { return p_->ListChildKeys(n, k); } GlobalRegisterTableTreeModel::GlobalRegisterTableTreeModel( GlobalRegisterTable* grt, QObject* parent) : QAbstractItemModel(parent), p_(SecureCreateUniqueObject(this, grt->p_.get())) {} auto GlobalRegisterTableTreeModel::rowCount(const QModelIndex& parent) const -> int { return p_->RowCount(parent); } auto GlobalRegisterTableTreeModel::columnCount(const QModelIndex& parent) const -> int { return p_->ColumnCount(parent); } auto GlobalRegisterTableTreeModel::data(const QModelIndex& index, int role) const -> QVariant { return p_->Data(index, role); } auto GlobalRegisterTableTreeModel::index( int row, int column, const QModelIndex& parent) const -> QModelIndex { return p_->Index(row, column, parent); } auto GlobalRegisterTableTreeModel::parent(const QModelIndex& index) const -> QModelIndex { return p_->Parent(index); } auto GlobalRegisterTableTreeModel::headerData(int section, Qt::Orientation orientation, int role) const -> QVariant { return p_->HeaderData(section, orientation, role); } } // namespace GpgFrontend::Module