From ee3491860f86c65e6af1bc3549e6228c053e34f3 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 20 Dec 2024 20:44:31 +0100 Subject: fix: adjust the width of key list cell correctly --- src/ui/model/GpgKeyTableProxyModel.cpp | 277 +++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 src/ui/model/GpgKeyTableProxyModel.cpp (limited to 'src/ui/model/GpgKeyTableProxyModel.cpp') diff --git a/src/ui/model/GpgKeyTableProxyModel.cpp b/src/ui/model/GpgKeyTableProxyModel.cpp new file mode 100644 index 00000000..90ad2c6a --- /dev/null +++ b/src/ui/model/GpgKeyTableProxyModel.cpp @@ -0,0 +1,277 @@ +/** + * 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 "GpgKeyTableProxyModel.h" + +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/CacheObject.h" +#include "core/model/GpgKey.h" +#include "core/struct/cache_object/AllFavoriteKeyPairsCO.h" +#include "core/utils/GpgUtils.h" + +namespace GpgFrontend { + +GpgKeyTableProxyModel::GpgKeyTableProxyModel( + QSharedPointer model, GpgKeyTableDisplayMode display_mode, + GpgKeyTableColumn columns, KeyFilter filter, QObject *parent) + : QSortFilterProxyModel(parent), + model_(std::move(model)), + display_mode_(display_mode), + filter_columns_(columns), + custom_filter_(std::move(filter)), + default_font_("Arial", 14), + default_metrics_(default_font_) { + setSourceModel(model_.get()); + + connect(this, &GpgKeyTableProxyModel::SignalFavoritesChanged, this, + &GpgKeyTableProxyModel::slot_update_favorites); + connect(this, &GpgKeyTableProxyModel::SignalColumnTypeChange, this, + &GpgKeyTableProxyModel::slot_update_column_type); + + emit SignalFavoritesChanged(); +} + +auto GpgKeyTableProxyModel::filterAcceptsRow( + int source_row, const QModelIndex &sourceParent) const -> bool { + auto index = sourceModel()->index(source_row, 6, sourceParent); + auto key_id = sourceModel()->data(index).toString(); + + auto key = + GpgKeyGetter::GetInstance(model_->GetGpgContextChannel()).GetKey(key_id); + LOG_D() << "get key: " << key_id + << "from channel: " << model_->GetGpgContextChannel(); + assert(key.IsGood()); + + if (!(display_mode_ & GpgKeyTableDisplayMode::kPRIVATE_KEY) && + key.IsPrivateKey()) { + return false; + } + + if (!(display_mode_ & GpgKeyTableDisplayMode::kPUBLIC_KEY) && + !key.IsPrivateKey()) { + return false; + } + + if (!custom_filter_(key)) return false; + + if (display_mode_ & GpgKeyTableDisplayMode::kFAVORITES) { + LOG_D() << "kFAVORITES Mode" << "key id" << key_id << "favorite_key_ids_" + << favorite_key_ids_; + } + if (display_mode_ & GpgKeyTableDisplayMode::kFAVORITES && + !favorite_key_ids_.contains(key_id)) { + return false; + } + + if (filter_keywords_.isEmpty()) return true; + + QStringList infos; + for (int column = 0; column < sourceModel()->columnCount(); ++column) { + auto index = sourceModel()->index(source_row, column, sourceParent); + infos << sourceModel()->data(index).toString(); + + const auto uids = key.GetUIDs(); + for (const auto &uid : *uids) { + infos << uid.GetUID(); + } + } + + return std::any_of(infos.cbegin(), infos.cend(), [&](const QString &info) { + return info.contains(filter_keywords_, Qt::CaseInsensitive); + }); + + return false; +} + +auto GpgKeyTableProxyModel::filterAcceptsColumn( + int sourceColumn, const QModelIndex &sourceParent) const -> bool { + switch (sourceColumn) { + case 0: { + return true; + } + case 1: { + return (filter_columns_ & GpgKeyTableColumn::kTYPE) != + GpgKeyTableColumn::kNONE; + } + case 2: { + return (filter_columns_ & GpgKeyTableColumn::kNAME) != + GpgKeyTableColumn::kNONE; + } + case 3: { + return (filter_columns_ & GpgKeyTableColumn::kEMAIL_ADDRESS) != + GpgKeyTableColumn::kNONE; + } + case 4: { + return (filter_columns_ & GpgKeyTableColumn::kUSAGE) != + GpgKeyTableColumn::kNONE; + } + case 5: { + return (filter_columns_ & GpgKeyTableColumn::kOWNER_TRUST) != + GpgKeyTableColumn::kNONE; + } + case 6: { + return (filter_columns_ & GpgKeyTableColumn::kKEY_ID) != + GpgKeyTableColumn::kNONE; + } + case 7: { + return (filter_columns_ & GpgKeyTableColumn::kCREATE_DATE) != + GpgKeyTableColumn::kNONE; + } + case 8: { + return (filter_columns_ & GpgKeyTableColumn::kALGO) != + GpgKeyTableColumn::kNONE; + } + case 9: { + return (filter_columns_ & GpgKeyTableColumn::kSUBKEYS_NUMBER) != + GpgKeyTableColumn::kNONE; + } + case 10: { + return (filter_columns_ & GpgKeyTableColumn::kCOMMENT) != + GpgKeyTableColumn::kNONE; + } + default: + return false; + } +} + +void GpgKeyTableProxyModel::SetSearchKeywords(const QString &keywords) { + this->filter_keywords_ = keywords; + invalidateFilter(); +} + +void GpgKeyTableProxyModel::slot_update_favorites() { + slot_update_favorites_cache(); + invalidateFilter(); +} + +void GpgKeyTableProxyModel::slot_update_column_type( + GpgKeyTableColumn filter_columns) { + filter_columns_ = filter_columns; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 4) + invalidateColumnsFilter(); +#else + invalidateFilter(); +#endif +} + +void GpgKeyTableProxyModel::ResetGpgKeyTableModel( + QSharedPointer model) { + model_ = std::move(model); + slot_update_favorites_cache(); + setSourceModel(model_.get()); +} + +void GpgKeyTableProxyModel::slot_update_favorites_cache() { + auto json_data = CacheObject("all_favorite_key_pairs"); + auto cache_obj = AllFavoriteKeyPairsCO(json_data.object()); + + auto key_db_name = GetGpgKeyDatabaseName(model_->GetGpgContextChannel()); + + if (cache_obj.key_dbs.contains(key_db_name)) { + favorite_key_ids_ = cache_obj.key_dbs[key_db_name].key_ids; + } +} + +auto GpgKeyTableProxyModel::data(const QModelIndex &index, + int role) const -> QVariant { + if (role == Qt::FontRole) { + return default_font_; + } + + if (role == Qt::TextAlignmentRole) { + return Qt::AlignCenter; + } + + if (role == Qt::SizeHintRole) { + const QVariant display_data = model_->data(index, Qt::DisplayRole); + if (!display_data.isValid()) { + return {}; + } + + const QString text = display_data.toString(); + + QRect rect = default_metrics_.boundingRect(QRect{}, Qt::AlignCenter, text); + + const int horizontal_padding = 15; + const int vertical_padding = 2; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + const int raw_width = default_metrics_.horizontalAdvance(text); +#else + const int raw_width = rect.width(); +#endif + + const int width = + static_cast(raw_width * 1.15) + horizontal_padding * 2; + const int height = rect.height() + vertical_padding * 2; + + LOG_D() << "row text: " << text << "width: " << width; + + return QSize(width, height); + } + + return sourceModel()->data(index, role); +} + +auto GpgKeyTableProxyModel::headerData(int section, Qt::Orientation orientation, + int role) const -> QVariant { + if (role == Qt::FontRole) { + return default_font_; + } + + if (role == Qt::SizeHintRole) { + const QVariant display_data = + model_->headerData(section, orientation, Qt::DisplayRole); + if (!display_data.isValid()) { + return {}; + } + + const QString text = display_data.toString(); + + QRect rect = default_metrics_.boundingRect(QRect{}, Qt::AlignCenter, text); + + const int horizontal_padding = 15; + const int vertical_padding = 2; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + const int raw_width = default_metrics_.horizontalAdvance(text); +#else + const int raw_width = rect.width(); +#endif + + const int width = + static_cast(raw_width * 1.15) + horizontal_padding * 2; + const int height = rect.height() + vertical_padding * 2; + + return QSize(width, height); + } + + return sourceModel()->headerData(section, orientation, role); +} +} // namespace GpgFrontend \ No newline at end of file -- cgit v1.2.3