aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2024-06-28 21:05:25 +0000
committersaturneric <[email protected]>2024-06-28 21:05:25 +0000
commitd0333031c1f593998a501eff866f091ff2f036be (patch)
tree707a597c25b488955572601e87ba9e379df0a6ed
parentfeat: rewrite key list structure and logic (diff)
downloadGpgFrontend-d0333031c1f593998a501eff866f091ff2f036be.tar.gz
GpgFrontend-d0333031c1f593998a501eff866f091ff2f036be.zip
feat: user can select shown columns at key table
-rw-r--r--gpgfrontend.qrc1
-rw-r--r--resource/lfs/icons/filter.pngbin0 -> 4328 bytes
-rw-r--r--src/core/model/GpgKeyTableModel.cpp25
-rw-r--r--src/core/model/GpgKeyTableModel.h67
-rw-r--r--src/core/model/GpgKeyTableProxyModel.cpp44
-rw-r--r--src/core/model/GpgKeyTableProxyModel.h12
-rw-r--r--src/ui/dialog/SignersPicker.cpp22
-rw-r--r--src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp9
-rw-r--r--src/ui/main_window/KeyMgmt.cpp40
-rw-r--r--src/ui/main_window/MainWindow.cpp11
-rw-r--r--src/ui/main_window/MainWindowUI.cpp26
-rw-r--r--src/ui/widgets/HelpPage.cpp7
-rw-r--r--src/ui/widgets/KeyList.cpp226
-rw-r--r--src/ui/widgets/KeyList.h183
-rw-r--r--src/ui/widgets/KeyTable.cpp136
-rw-r--r--src/ui/widgets/KeyTable.h176
-rw-r--r--ui/KeyList.ui17
17 files changed, 640 insertions, 362 deletions
diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc
index e311ed6a..a04c1819 100644
--- a/gpgfrontend.qrc
+++ b/gpgfrontend.qrc
@@ -97,6 +97,7 @@
<file alias="key.png">resource/lfs/icons/key.png</file>
<file alias="stairs.png">resource/lfs/icons/stairs.png</file>
<file alias="detail.png">resource/lfs/icons/detail.png</file>
+ <file alias="filter.png">resource/lfs/icons/filter.png</file>
</qresource>
<qresource prefix="/test/key">
<file alias="pv1.key">resource/lfs/test/data/pv1.key</file>
diff --git a/resource/lfs/icons/filter.png b/resource/lfs/icons/filter.png
new file mode 100644
index 00000000..a8480b48
--- /dev/null
+++ b/resource/lfs/icons/filter.png
Binary files differ
diff --git a/src/core/model/GpgKeyTableModel.cpp b/src/core/model/GpgKeyTableModel.cpp
index cff619cd..4d542c3f 100644
--- a/src/core/model/GpgKeyTableModel.cpp
+++ b/src/core/model/GpgKeyTableModel.cpp
@@ -36,9 +36,18 @@ namespace GpgFrontend {
GpgKeyTableModel::GpgKeyTableModel(GpgKeyList keys, QObject *parent)
: QAbstractTableModel(parent),
buffered_keys_(keys),
- column_headers_({tr("Select"), tr("Type"), tr("Name"),
- tr("Email Address"), tr("Usage"), tr("Trust"),
- tr("Key ID"), tr("Finger Print")}),
+ column_headers_({
+ tr("Select"),
+ tr("Type"),
+ tr("Name"),
+ tr("Email Address"),
+ tr("Usage"),
+ tr("Trust"),
+ tr("Key ID"),
+ tr("Create Date"),
+ tr("Algorithm"),
+ tr("Subkey(s)"),
+ }),
key_check_state_(buffered_keys_.size()) {}
auto GpgKeyTableModel::rowCount(const QModelIndex & /*parent*/) const -> int {
@@ -47,7 +56,7 @@ auto GpgKeyTableModel::rowCount(const QModelIndex & /*parent*/) const -> int {
auto GpgKeyTableModel::columnCount(const QModelIndex & /*parent*/) const
-> int {
- return 8;
+ return 10;
}
auto GpgKeyTableModel::data(const QModelIndex &index, int role) const
@@ -99,7 +108,13 @@ auto GpgKeyTableModel::data(const QModelIndex &index, int role) const
return key.GetId();
}
case 7: {
- return key.GetFingerprint();
+ return key.GetCreateTime();
+ }
+ case 8: {
+ return key.GetKeyAlgo();
+ }
+ case 9: {
+ return static_cast<int>(key.GetSubKeys()->size());
}
default:
return {};
diff --git a/src/core/model/GpgKeyTableModel.h b/src/core/model/GpgKeyTableModel.h
index 047820a5..78289b41 100644
--- a/src/core/model/GpgKeyTableModel.h
+++ b/src/core/model/GpgKeyTableModel.h
@@ -38,58 +38,73 @@
namespace GpgFrontend {
enum class GpgKeyTableColumn : unsigned int {
- kNone = 0,
- kType = 1 << 0,
- kName = 1 << 1,
- kEmailAddress = 1 << 2,
- kUsage = 1 << 3,
- kValidity = 1 << 4,
- kFingerPrint = 1 << 5,
- kKeyId = 1 << 6,
- kOwnerTrust = 1 << 7,
- kAll = ~0u
+ kNONE = 0,
+ kTYPE = 1 << 0,
+ kNAME = 1 << 1,
+ kEMAIL_ADDRESS = 1 << 2,
+ kUSAGE = 1 << 3,
+ kKEY_ID = 1 << 4,
+ kOWNER_TRUST = 1 << 5,
+ kCREATE_DATE = 1 << 6,
+ kALGO = 1 << 7,
+ kSUBKEYS_NUMBER = 1 << 8,
+ kALL = ~0U
};
-inline GpgKeyTableColumn operator|(GpgKeyTableColumn lhs,
- GpgKeyTableColumn rhs) {
+inline auto operator|(GpgKeyTableColumn lhs, GpgKeyTableColumn rhs)
+ -> GpgKeyTableColumn {
using T = std::underlying_type_t<GpgKeyTableColumn>;
return static_cast<GpgKeyTableColumn>(static_cast<T>(lhs) |
static_cast<T>(rhs));
}
-inline GpgKeyTableColumn &operator|=(GpgKeyTableColumn &lhs,
- GpgKeyTableColumn rhs) {
+inline auto operator|=(GpgKeyTableColumn &lhs, GpgKeyTableColumn rhs)
+ -> GpgKeyTableColumn & {
lhs = lhs | rhs;
return lhs;
}
-inline bool operator&(GpgKeyTableColumn lhs, GpgKeyTableColumn rhs) {
+inline auto operator&(GpgKeyTableColumn lhs, GpgKeyTableColumn rhs)
+ -> GpgKeyTableColumn {
using T = std::underlying_type_t<GpgKeyTableColumn>;
- return (static_cast<T>(lhs) & static_cast<T>(rhs)) != 0;
+ return static_cast<GpgKeyTableColumn>(static_cast<T>(lhs) &
+ static_cast<T>(rhs));
+}
+
+inline auto operator&=(GpgKeyTableColumn &lhs, GpgKeyTableColumn rhs)
+ -> GpgKeyTableColumn & {
+ lhs = lhs & rhs;
+ return lhs;
+}
+
+inline auto operator~(GpgKeyTableColumn hs) -> GpgKeyTableColumn {
+ using T = std::underlying_type_t<GpgKeyTableColumn>;
+ return static_cast<GpgKeyTableColumn>(~static_cast<T>(hs));
}
enum class GpgKeyTableDisplayMode : unsigned int {
- kNone = 0,
- kPublicKey = 1 << 0,
- kPrivateKey = 1 << 1,
- kFavorites = 1 << 2,
- kAll = ~0u
+ kNONE = 0,
+ kPUBLIC_KEY = 1 << 0,
+ kPRIVATE_KEY = 1 << 1,
+ kFAVORITES = 1 << 2,
+ kALL = ~0U
};
-inline GpgKeyTableDisplayMode operator|(GpgKeyTableDisplayMode lhs,
- GpgKeyTableDisplayMode rhs) {
+inline auto operator|(GpgKeyTableDisplayMode lhs, GpgKeyTableDisplayMode rhs)
+ -> GpgKeyTableDisplayMode {
using T = std::underlying_type_t<GpgKeyTableDisplayMode>;
return static_cast<GpgKeyTableDisplayMode>(static_cast<T>(lhs) |
static_cast<T>(rhs));
}
-inline GpgKeyTableDisplayMode &operator|=(GpgKeyTableDisplayMode &lhs,
- GpgKeyTableDisplayMode rhs) {
+inline auto operator|=(GpgKeyTableDisplayMode &lhs, GpgKeyTableDisplayMode rhs)
+ -> GpgKeyTableDisplayMode & {
lhs = lhs | rhs;
return lhs;
}
-inline bool operator&(GpgKeyTableDisplayMode lhs, GpgKeyTableDisplayMode rhs) {
+inline auto operator&(GpgKeyTableDisplayMode lhs, GpgKeyTableDisplayMode rhs)
+ -> bool {
using T = std::underlying_type_t<GpgKeyTableDisplayMode>;
return (static_cast<T>(lhs) & static_cast<T>(rhs)) != 0;
}
diff --git a/src/core/model/GpgKeyTableProxyModel.cpp b/src/core/model/GpgKeyTableProxyModel.cpp
index 7fdedff5..0ecd000f 100644
--- a/src/core/model/GpgKeyTableProxyModel.cpp
+++ b/src/core/model/GpgKeyTableProxyModel.cpp
@@ -48,6 +48,8 @@ GpgKeyTableProxyModel::GpgKeyTableProxyModel(
connect(this, &GpgKeyTableProxyModel::SignalFavoritesChanged, this,
&GpgKeyTableProxyModel::slot_update_favorites);
+ connect(this, &GpgKeyTableProxyModel::SignalColumnTypeChange, this,
+ &GpgKeyTableProxyModel::slot_update_column_type);
emit SignalFavoritesChanged();
}
@@ -58,19 +60,19 @@ auto GpgKeyTableProxyModel::filterAcceptsRow(
auto key_id = sourceModel()->data(index).toString();
auto key = GpgKeyGetter::GetInstance().GetKey(key_id);
- if (!(display_mode_ & GpgKeyTableDisplayMode::kPrivateKey) &&
+ if (!(display_mode_ & GpgKeyTableDisplayMode::kPRIVATE_KEY) &&
key.IsPrivateKey()) {
return false;
}
- if (!(display_mode_ & GpgKeyTableDisplayMode::kPublicKey) &&
+ if (!(display_mode_ & GpgKeyTableDisplayMode::kPUBLIC_KEY) &&
!key.IsPrivateKey()) {
return false;
}
if (!custom_filter_(key)) return false;
- if (display_mode_ & GpgKeyTableDisplayMode::kFavorites &&
+ if (display_mode_ & GpgKeyTableDisplayMode::kFAVORITES &&
!favorite_fingerprints_.contains(key.GetFingerprint())) {
return false;
}
@@ -97,25 +99,40 @@ auto GpgKeyTableProxyModel::filterAcceptsColumn(
return true;
}
case 1: {
- return filter_columns_ & GpgKeyTableColumn::kType;
+ return (filter_columns_ & GpgKeyTableColumn::kTYPE) !=
+ GpgKeyTableColumn::kNONE;
}
case 2: {
- return filter_columns_ & GpgKeyTableColumn::kName;
+ return (filter_columns_ & GpgKeyTableColumn::kNAME) !=
+ GpgKeyTableColumn::kNONE;
}
case 3: {
- return filter_columns_ & GpgKeyTableColumn::kEmailAddress;
+ return (filter_columns_ & GpgKeyTableColumn::kEMAIL_ADDRESS) !=
+ GpgKeyTableColumn::kNONE;
}
case 4: {
- return filter_columns_ & GpgKeyTableColumn::kUsage;
+ return (filter_columns_ & GpgKeyTableColumn::kUSAGE) !=
+ GpgKeyTableColumn::kNONE;
}
case 5: {
- return filter_columns_ & GpgKeyTableColumn::kOwnerTrust;
+ return (filter_columns_ & GpgKeyTableColumn::kOWNER_TRUST) !=
+ GpgKeyTableColumn::kNONE;
}
case 6: {
- return filter_columns_ & GpgKeyTableColumn::kKeyId;
+ return (filter_columns_ & GpgKeyTableColumn::kKEY_ID) !=
+ GpgKeyTableColumn::kNONE;
}
case 7: {
- return filter_columns_ & GpgKeyTableColumn::kFingerPrint;
+ 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;
}
default:
return false;
@@ -139,4 +156,11 @@ void GpgKeyTableProxyModel::slot_update_favorites() {
invalidateFilter();
}
+
+void GpgKeyTableProxyModel::slot_update_column_type(
+ GpgKeyTableColumn filter_columns) {
+ filter_columns_ = filter_columns;
+ invalidateColumnsFilter();
+}
+
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/core/model/GpgKeyTableProxyModel.h b/src/core/model/GpgKeyTableProxyModel.h
index 004fc87b..657b40cf 100644
--- a/src/core/model/GpgKeyTableProxyModel.h
+++ b/src/core/model/GpgKeyTableProxyModel.h
@@ -62,6 +62,12 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyTableProxyModel
*/
void SignalFavoritesChanged();
+ /**
+ * @brief
+ *
+ */
+ void SignalColumnTypeChange(GpgKeyTableColumn);
+
private slots:
/**
@@ -70,6 +76,12 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyTableProxyModel
*/
void slot_update_favorites();
+ /**
+ * @brief
+ *
+ */
+ void slot_update_column_type(GpgKeyTableColumn);
+
private:
QSharedPointer<GpgKeyTableModel> model_;
GpgKeyTableDisplayMode display_mode_;
diff --git a/src/ui/dialog/SignersPicker.cpp b/src/ui/dialog/SignersPicker.cpp
index 5ab33425..c6bbbbe7 100644
--- a/src/ui/dialog/SignersPicker.cpp
+++ b/src/ui/dialog/SignersPicker.cpp
@@ -44,23 +44,23 @@ SignersPicker::SignersPicker(QWidget* parent)
connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject);
/*Setup KeyList*/
- key_list_ = new KeyList(0U, this);
- key_list_->AddListGroupTab(
- tr("Signers"), "signers", GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kName | GpgKeyTableColumn::kEmailAddress |
- GpgKeyTableColumn::kUsage,
- [](const GpgKey& key) -> bool {
- return key.IsHasActualSigningCapability();
- });
+ key_list_ =
+ new KeyList(KeyMenuAbility::SEARCH_BAR,
+ GpgKeyTableColumn::kNAME | GpgKeyTableColumn::kEMAIL_ADDRESS |
+ GpgKeyTableColumn::kKEY_ID | GpgKeyTableColumn::kUSAGE,
+ this);
+ key_list_->AddListGroupTab(tr("Signers"), "signers",
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
+ [](const GpgKey& key) -> bool {
+ return key.IsHasActualSigningCapability();
+ });
key_list_->SlotRefresh();
auto* vbox2 = new QVBoxLayout();
vbox2->addWidget(new QLabel(tr("Select Signer(s)") + ": "));
vbox2->addWidget(key_list_);
vbox2->addWidget(new QLabel(
- QString(
- tr("Please select one or more private keys you use for signing.")) +
- "\n" +
+ tr("Please select one or more private keys you use for signing.") + "\n" +
tr("If no key is selected, the default key will be used for signing.")));
vbox2->addWidget(confirm_button);
vbox2->addWidget(cancel_button);
diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
index f8d3d44b..4d96a945 100644
--- a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
@@ -41,10 +41,13 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
m_uids_(std::move(uid)),
m_key_(key) {
const auto key_id = m_key_.GetId();
- m_key_list_ = new KeyList(KeyMenuAbility::NONE, this);
+ m_key_list_ =
+ new KeyList(KeyMenuAbility::SEARCH_BAR,
+ GpgKeyTableColumn::kNAME | GpgKeyTableColumn::kEMAIL_ADDRESS |
+ GpgKeyTableColumn::kKEY_ID,
+ this);
m_key_list_->AddListGroupTab(
- tr("Signers"), "signers", GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kName | GpgKeyTableColumn::kEmailAddress,
+ tr("Signers"), "signers", GpgKeyTableDisplayMode::kPRIVATE_KEY,
[key_id](const GpgKey& key) -> bool {
return !(key.IsDisabled() || !key.IsHasCertificationCapability() ||
!key.IsHasMasterKey() || key.IsExpired() || key.IsRevoked() ||
diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp
index 85671ab2..c45fd46f 100644
--- a/src/ui/main_window/KeyMgmt.cpp
+++ b/src/ui/main_window/KeyMgmt.cpp
@@ -52,40 +52,30 @@ namespace GpgFrontend::UI {
KeyMgmt::KeyMgmt(QWidget* parent)
: GeneralMainWindow("key_management", parent) {
/* the list of Keys available*/
- key_list_ = new KeyList(KeyMenuAbility::ALL, this);
+ key_list_ = new KeyList(KeyMenuAbility::ALL, GpgKeyTableColumn::kALL, this);
- key_list_->AddListGroupTab(
- tr("All"), "all",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey);
+ key_list_->AddListGroupTab(tr("All"), "all",
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY);
key_list_->AddListGroupTab(
tr("Only Public Key"), "only_public_key",
- GpgKeyTableDisplayMode::kPublicKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
- [](const GpgKey& key) -> bool {
+ GpgKeyTableDisplayMode::kPUBLIC_KEY, [](const GpgKey& key) -> bool {
return !key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
key_list_->AddListGroupTab(
tr("Has Private Key"), "has_private_key",
- GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
- [](const GpgKey& key) -> bool {
+ GpgKeyTableDisplayMode::kPRIVATE_KEY, [](const GpgKey& key) -> bool {
return key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
key_list_->AddListGroupTab(
tr("No Primary Key"), "no_primary_key",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
[](const GpgKey& key) -> bool {
return !key.IsHasMasterKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
@@ -93,18 +83,16 @@ KeyMgmt::KeyMgmt(QWidget* parent)
key_list_->AddListGroupTab(
tr("Revoked"), "revoked",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
+
[](const GpgKey& key) -> bool { return key.IsRevoked(); });
key_list_->AddListGroupTab(
tr("Expired"), "expired",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
+
[](const GpgKey& key) -> bool { return key.IsExpired(); });
setCentralWidget(key_list_);
diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp
index c50cfc5e..7e2bbe85 100644
--- a/src/ui/main_window/MainWindow.cpp
+++ b/src/ui/main_window/MainWindow.cpp
@@ -61,10 +61,13 @@ void MainWindow::Init() noexcept {
setCentralWidget(edit_);
/* the list of Keys available*/
- m_key_list_ =
- new KeyList(KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL |
- KeyMenuAbility::SEARCH_BAR,
- this);
+ m_key_list_ = new KeyList(
+ KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL |
+ KeyMenuAbility::SEARCH_BAR,
+ GpgKeyTableColumn::kTYPE | GpgKeyTableColumn::kNAME |
+ GpgKeyTableColumn::kKEY_ID | GpgKeyTableColumn::kEMAIL_ADDRESS |
+ GpgKeyTableColumn::kUSAGE | GpgKeyTableColumn::kOWNER_TRUST,
+ this);
info_board_ = new InfoBoardWidget(this);
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index f96cf595..c1189fa2 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -708,43 +708,31 @@ void MainWindow::create_dock_windows() {
m_key_list_->AddListGroupTab(
tr("Default"), "default",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
[](const GpgKey& key) -> bool {
return !(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
m_key_list_->AddListGroupTab(
tr("Favourite"), "favourite",
- GpgKeyTableDisplayMode::kPublicKey | GpgKeyTableDisplayMode::kPrivateKey |
- GpgKeyTableDisplayMode::kFavorites,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
+ GpgKeyTableDisplayMode::kPUBLIC_KEY |
+ GpgKeyTableDisplayMode::kPRIVATE_KEY |
+ GpgKeyTableDisplayMode::kFAVORITES,
[](const GpgKey& key) -> bool {
return CommonUtils::GetInstance()->KeyExistsinFavouriteList(key);
});
m_key_list_->AddListGroupTab(
tr("Only Public Key"), "only_public_key",
- GpgKeyTableDisplayMode::kPublicKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
- [](const GpgKey& key) -> bool {
+ GpgKeyTableDisplayMode::kPUBLIC_KEY, [](const GpgKey& key) -> bool {
return !key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
m_key_list_->AddListGroupTab(
tr("Has Private Key"), "has_private_key",
- GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn::kType | GpgKeyTableColumn::kName |
- GpgKeyTableColumn::kEmailAddress | GpgKeyTableColumn::kUsage |
- GpgKeyTableColumn::kValidity,
- [](const GpgKey& key) -> bool {
+ GpgKeyTableDisplayMode::kPRIVATE_KEY, [](const GpgKey& key) -> bool {
return key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp
index 78169944..cf56564c 100644
--- a/src/ui/widgets/HelpPage.cpp
+++ b/src/ui/widgets/HelpPage.cpp
@@ -28,6 +28,8 @@
#include "ui/widgets/HelpPage.h"
+#include "core/function/GlobalSettingStation.h"
+
namespace GpgFrontend::UI {
HelpPage::HelpPage(const QString& path, QWidget* parent) : QWidget(parent) {
@@ -64,7 +66,10 @@ auto HelpPage::localized_help(const QUrl& url) -> QUrl {
QStringList fileparts = filename.split(".");
// QSettings settings;
- QString lang = QSettings().value("int/lang", QLocale().name()).toString();
+ QString lang = GlobalSettingStation::GetInstance()
+ .GetSettings()
+ .value("int/lang", QLocale().name())
+ .toString();
if (lang.isEmpty()) {
lang = QLocale().name();
}
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 4229a35f..5ebddbb5 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -29,7 +29,6 @@
#include "ui/widgets/KeyList.h"
#include <cstddef>
-#include <mutex>
#include <utility>
#include "core/function/GlobalSettingStation.h"
@@ -41,11 +40,19 @@
namespace GpgFrontend::UI {
-KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability, QWidget* parent)
+KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability,
+ GpgKeyTableColumn fixed_columns_filter, QWidget* parent)
: QWidget(parent),
ui_(GpgFrontend::SecureCreateSharedObject<Ui_KeyList>()),
menu_ability_(menu_ability),
- model_(GpgKeyGetter::GetInstance().GetGpgKeyTableModel()) {
+ model_(GpgKeyGetter::GetInstance().GetGpgKeyTableModel()),
+ fixed_columns_filter_(fixed_columns_filter),
+ global_column_filter_(static_cast<GpgKeyTableColumn>(
+ GlobalSettingStation::GetInstance()
+ .GetSettings()
+ .value("keys/global_columns_filter",
+ static_cast<unsigned int>(GpgKeyTableColumn::kALL))
+ .toUInt())) {
init();
}
@@ -59,6 +66,94 @@ void KeyList::init() {
ui_->uncheckButton->setHidden(~menu_ability_ & KeyMenuAbility::UNCHECK_ALL);
ui_->searchBarEdit->setHidden(~menu_ability_ & KeyMenuAbility::SEARCH_BAR);
+ auto* column_type_menu = new QMenu();
+
+ key_id_column_action_ = new QAction(tr("Key ID"));
+ key_id_column_action_->setCheckable(true);
+ key_id_column_action_->setChecked(
+ (global_column_filter_ & GpgKeyTableColumn::kKEY_ID) !=
+ GpgKeyTableColumn::kNONE);
+ connect(key_id_column_action_, &QAction::toggled, this, [=](bool checked) {
+ UpdateKeyTableColumnType(
+ checked ? global_column_filter_ | GpgKeyTableColumn::kKEY_ID
+ : global_column_filter_ & ~GpgKeyTableColumn::kKEY_ID);
+ });
+
+ algo_column_action_ = new QAction(tr("Algorithm"));
+ algo_column_action_->setCheckable(true);
+ algo_column_action_->setChecked(
+ (global_column_filter_ & GpgKeyTableColumn::kALGO) !=
+ GpgKeyTableColumn::kNONE);
+ connect(algo_column_action_, &QAction::toggled, this, [=](bool checked) {
+ UpdateKeyTableColumnType(
+ checked ? global_column_filter_ | GpgKeyTableColumn::kALGO
+ : global_column_filter_ & ~GpgKeyTableColumn::kALGO);
+ });
+
+ owner_trust_column_action_ = new QAction(tr("Owner Trust"));
+ owner_trust_column_action_->setCheckable(true);
+ owner_trust_column_action_->setChecked(
+ (global_column_filter_ & GpgKeyTableColumn::kOWNER_TRUST) !=
+ GpgKeyTableColumn::kNONE);
+ connect(
+ owner_trust_column_action_, &QAction::toggled, this, [=](bool checked) {
+ UpdateKeyTableColumnType(
+ checked ? global_column_filter_ | GpgKeyTableColumn::kOWNER_TRUST
+ : global_column_filter_ & ~GpgKeyTableColumn::kOWNER_TRUST);
+ });
+
+ create_date_column_action_ = new QAction(tr("Create Date"));
+ create_date_column_action_->setCheckable(true);
+ create_date_column_action_->setChecked(
+ (global_column_filter_ & GpgKeyTableColumn::kCREATE_DATE) !=
+ GpgKeyTableColumn::kNONE);
+ connect(
+ create_date_column_action_, &QAction::toggled, this, [=](bool checked) {
+ UpdateKeyTableColumnType(
+ checked ? global_column_filter_ | GpgKeyTableColumn::kCREATE_DATE
+ : global_column_filter_ & ~GpgKeyTableColumn::kCREATE_DATE);
+ });
+
+ subkeys_number_column_action_ = new QAction("Subkey(s)");
+ subkeys_number_column_action_->setCheckable(true);
+ subkeys_number_column_action_->setChecked(
+ (global_column_filter_ & GpgKeyTableColumn::kSUBKEYS_NUMBER) !=
+ GpgKeyTableColumn::kNONE);
+ connect(
+ subkeys_number_column_action_, &QAction::toggled, this,
+ [=](bool checked) {
+ UpdateKeyTableColumnType(
+ checked
+ ? global_column_filter_ | GpgKeyTableColumn::kSUBKEYS_NUMBER
+ : global_column_filter_ & ~GpgKeyTableColumn::kSUBKEYS_NUMBER);
+ });
+
+ if ((fixed_columns_filter_ & GpgKeyTableColumn::kKEY_ID) !=
+ GpgKeyTableColumn::kNONE) {
+ column_type_menu->addAction(key_id_column_action_);
+ }
+
+ if ((fixed_columns_filter_ & GpgKeyTableColumn::kALGO) !=
+ GpgKeyTableColumn::kNONE) {
+ column_type_menu->addAction(algo_column_action_);
+ }
+ if ((fixed_columns_filter_ & GpgKeyTableColumn::kCREATE_DATE) !=
+ GpgKeyTableColumn::kNONE) {
+ column_type_menu->addAction(create_date_column_action_);
+ }
+
+ if ((fixed_columns_filter_ & GpgKeyTableColumn::kOWNER_TRUST) !=
+ GpgKeyTableColumn::kNONE) {
+ column_type_menu->addAction(owner_trust_column_action_);
+ }
+
+ if ((fixed_columns_filter_ & GpgKeyTableColumn::kSUBKEYS_NUMBER) !=
+ GpgKeyTableColumn::kNONE) {
+ column_type_menu->addAction(subkeys_number_column_action_);
+ }
+
+ ui_->columnTypeButton->setMenu(column_type_menu);
+
ui_->keyGroupTab->clear();
popup_menu_ = new QMenu(this);
@@ -95,6 +190,11 @@ void KeyList::init() {
connect(this, &KeyList::SignalRefreshStatusBar,
UISignalStation::GetInstance(),
&UISignalStation::SignalRefreshStatusBar);
+ connect(this, &KeyList::SignalColumnTypeChange, this, [=]() {
+ GlobalSettingStation::GetInstance().GetSettings().setValue(
+ "keys/global_columns_filter",
+ static_cast<unsigned int>(global_column_filter_));
+ });
setAcceptDrops(true);
@@ -114,14 +214,20 @@ void KeyList::init() {
}
void KeyList::AddListGroupTab(const QString& name, const QString& id,
- GpgKeyTableDisplayMode select_type,
- GpgKeyTableColumn info_type,
- GpgKeyTableProxyModel::KeyFilter filter) {
+ GpgKeyTableDisplayMode display_mode,
+ GpgKeyTableProxyModel::KeyFilter search_filter,
+ GpgKeyTableColumn custom_columns_filter) {
auto* key_table =
- new KeyTable(this, model_, select_type, info_type, std::move(filter));
+ new KeyTable(this, model_, display_mode, custom_columns_filter,
+ std::move(search_filter));
key_table->setObjectName(id);
ui_->keyGroupTab->addTab(key_table, name);
+
+ connect(this, &KeyList::SignalColumnTypeChange, key_table,
+ &KeyTable::SignalColumnTypeChange);
+
+ UpdateKeyTableColumnType(global_column_filter_);
}
void KeyList::SlotRefresh() {
@@ -347,12 +453,12 @@ void KeyList::dropEvent(QDropEvent* event) {
if (!file.open(QIODevice::ReadOnly)) {
GF_UI_LOG_ERROR("couldn't open file: {}", tmp.toString());
}
- QByteArray in_buffer = file.readAll();
+ auto in_buffer = file.readAll();
this->import_keys(in_buffer);
file.close();
}
} else {
- QByteArray in_buffer(event->mimeData()->text().toUtf8());
+ auto in_buffer(event->mimeData()->text().toUtf8());
this->import_keys(in_buffer);
}
}
@@ -458,7 +564,6 @@ void KeyList::filter_by_keyword() {
auto* key_table = qobject_cast<KeyTable*>(ui_->keyGroupTab->widget(i));
// refresh arguments
key_table->SetFilterKeyword(keyword.toLower());
- key_table->SetMenuAbility(menu_ability_);
}
// refresh ui
@@ -477,104 +582,9 @@ void KeyList::check_all() {
key_table->CheckAll();
}
-auto KeyTable::GetChecked() -> KeyIdArgsListPtr {
- auto ret = std::make_unique<KeyIdArgsList>();
- for (size_t i = 0; i < GetRowCount(); i++) {
- if (IsRowChecked(i)) ret->push_back(GetKeyIdByRow(i));
- }
- return ret;
-}
-
-KeyTable::KeyTable(QWidget* parent, QSharedPointer<GpgKeyTableModel> model,
- GpgKeyTableDisplayMode select_type,
- GpgKeyTableColumn info_type,
- GpgKeyTableProxyModel::KeyFilter filter)
- : QTableView(parent),
- model_(std::move(model)),
- proxy_model_(model_, select_type, info_type, std::move(filter), this) {
- setModel(&proxy_model_);
-
- verticalHeader()->hide();
- horizontalHeader()->setStretchLastSection(false);
- setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-
- setShowGrid(false);
- sortByColumn(2, Qt::AscendingOrder);
- setSelectionBehavior(QAbstractItemView::SelectRows);
- setSelectionMode(QAbstractItemView::SingleSelection);
-
- // table items not editable
- setEditTriggers(QAbstractItemView::NoEditTriggers);
-
- setFocusPolicy(Qt::NoFocus);
- setAlternatingRowColors(true);
-
- connect(CommonUtils::GetInstance(), &CommonUtils::SignalFavoritesChanged,
- &proxy_model_, &GpgKeyTableProxyModel::SignalFavoritesChanged);
-}
-
-void KeyTable::SetMenuAbility(KeyMenuAbility::AbilityType ability) {
- this->ability_ = ability;
-}
-
-void KeyTable::SetFilterKeyword(const QString& keyword) {
- proxy_model_.SetSearchKeywords(keyword);
-}
-
-void KeyTable::RefreshModel(QSharedPointer<GpgKeyTableModel> model) {
- model_ = std::move(model);
- proxy_model_.setSourceModel(model_.get());
-}
-
-auto KeyTable::IsRowChecked(int row) const -> bool {
- auto index = model()->index(row, 0);
- return index.data(Qt::CheckStateRole).toInt() == Qt::Checked;
-}
-
-auto KeyTable::GetRowCount() const -> int { return model()->rowCount(); }
-
-auto KeyTable::GetKeyIdByRow(int row) const -> QString {
- if (row < 0 || row >= model()->rowCount()) return {};
- auto origin_row = model()->index(row, 0).data().toInt();
- return model_->GetKeyIDByRow(origin_row);
-}
-
-auto KeyTable::IsPrivateKeyByRow(int row) const -> bool {
- if (row < 0 || row >= model()->rowCount()) return false;
- auto origin_row = model()->index(row, 0).data().toInt();
- return model_->IsPrivateKeyByRow(origin_row);
-}
-
-auto KeyTable::IsPublicKeyByRow(int row) const -> bool {
- if (row < 0 || row >= model()->rowCount()) return false;
- auto origin_row = model()->index(row, 0).data().toInt();
- return !model_->IsPrivateKeyByRow(origin_row);
-}
-
-void KeyTable::SetRowChecked(int row) const {
- if (row < 0 || row >= model()->rowCount()) return;
- model()->setData(model()->index(row, 0), Qt::Checked, Qt::CheckStateRole);
-}
-
-void KeyTable::CheckAll() {
- for (int row = 0; row < model()->rowCount(); ++row) {
- auto index = model()->index(row, 0);
- model()->setData(index, Qt::Checked, Qt::CheckStateRole);
- }
-}
-
-void KeyTable::UncheckAll() {
- for (int row = 0; row < model()->rowCount(); ++row) {
- auto index = model()->index(row, 0);
- model()->setData(index, Qt::Unchecked, Qt::CheckStateRole);
- }
-}
-
-[[nodiscard]] auto KeyTable::GetRowSelected() const -> int {
- auto selected_indexes = selectedIndexes();
- if (selected_indexes.empty()) return -1;
-
- return selected_indexes.first().row();
+void KeyList::UpdateKeyTableColumnType(GpgKeyTableColumn column_type) {
+ global_column_filter_ = column_type;
+ emit SignalColumnTypeChange(fixed_columns_filter_ & global_column_filter_);
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h
index 70320519..1893a98a 100644
--- a/src/ui/widgets/KeyList.h
+++ b/src/ui/widgets/KeyList.h
@@ -28,9 +28,7 @@
#pragma once
-#include "core/model/GpgKey.h"
-#include "core/model/GpgKeyTableModel.h"
-#include "core/model/GpgKeyTableProxyModel.h"
+#include "ui/widgets/KeyTable.h"
class Ui_KeyList;
@@ -56,143 +54,6 @@ struct KeyMenuAbility {
* @brief
*
*/
-struct KeyTable : public QTableView {
- Q_OBJECT
- public:
- using KeyTableFilter = std::function<bool(const GpgKey&, const KeyTable&)>;
-
- /**
- * @brief Construct a new Key Table object
- *
- * @param _key_list
- * @param _select_type
- * @param _info_type
- * @param _filter
- */
- KeyTable(
- QWidget* parent, QSharedPointer<GpgKeyTableModel> model,
- GpgKeyTableDisplayMode _select_type, GpgKeyTableColumn _info_type,
- GpgKeyTableProxyModel::KeyFilter _filter = [](const GpgKey&) -> bool {
- return true;
- });
-
- /**
- * @brief
- *
- * @param model
- */
- void RefreshModel(QSharedPointer<GpgKeyTableModel> model);
-
- /**
- * @brief Get the Checked object
- *
- * @return KeyIdArgsListPtr&
- */
- auto GetChecked() -> KeyIdArgsListPtr;
-
- /**
- * @brief
- *
- */
- void UncheckALL() const;
-
- /**
- * @brief
- *
- */
- void CheckALL() const;
-
- /**
- * @brief
- *
- */
- void SetMenuAbility(KeyMenuAbility::AbilityType ability);
-
- /**
- * @brief
- *
- */
- void SetFilterKeyword(const QString& keyword);
-
- /**
- * @brief
- *
- * @param row
- * @return true
- * @return false
- */
- [[nodiscard]] auto IsRowChecked(int row) const -> bool;
-
- /**
- * @brief Set the Row Checked object
- *
- * @param row
- */
- void SetRowChecked(int row) const;
-
- /**
- * @brief Set the Row Checked object
- *
- * @param row
- */
- [[nodiscard]] auto GetRowSelected() const -> int;
-
- /**
- * @brief Get the Row Count object
- *
- * @return auto
- */
- [[nodiscard]] auto GetRowCount() const -> int;
-
- /**
- * @brief Get the Key Id By Row object
- *
- * @param row
- * @return QString
- */
- [[nodiscard]] auto GetKeyIdByRow(int row) const -> QString;
-
- /**
- * @brief
- *
- * @param row
- * @return true
- * @return false
- */
- [[nodiscard]] auto IsPublicKeyByRow(int row) const -> bool;
-
- /**
- * @brief
- *
- * @param row
- * @return true
- * @return false
- */
- [[nodiscard]] auto IsPrivateKeyByRow(int row) const -> bool;
-
- /**
- * @brief
- *
- */
- void CheckAll();
-
- /**
- * @brief
- *
- */
- void UncheckAll();
-
- private:
- KeyMenuAbility::AbilityType ability_; ///<
-
- QSharedPointer<GpgKeyTableModel> model_;
- GpgKeyTableProxyModel proxy_model_;
-};
-
-/**
- * @brief
- *
- */
class KeyList : public QWidget {
Q_OBJECT
@@ -203,8 +64,10 @@ class KeyList : public QWidget {
* @param menu_ability
* @param parent
*/
- explicit KeyList(KeyMenuAbility::AbilityType menu_ability,
- QWidget* parent = nullptr);
+ explicit KeyList(
+ KeyMenuAbility::AbilityType menu_ability,
+ GpgKeyTableColumn fixed_column_filter = GpgKeyTableColumn::kALL,
+ QWidget* parent = nullptr);
/**
* @brief
@@ -216,11 +79,11 @@ class KeyList : public QWidget {
*/
void AddListGroupTab(
const QString& name, const QString& id,
- GpgKeyTableDisplayMode selectType = GpgKeyTableDisplayMode::kPrivateKey,
- GpgKeyTableColumn infoType = GpgKeyTableColumn::kAll,
- GpgKeyTableProxyModel::KeyFilter filter = [](const GpgKey&) -> bool {
- return true;
- });
+ GpgKeyTableDisplayMode display_mode =
+ GpgKeyTableDisplayMode::kPRIVATE_KEY,
+ GpgKeyTableProxyModel::KeyFilter search_filter =
+ [](const GpgKey&) -> bool { return true; },
+ GpgKeyTableColumn custom_columns_filter = GpgKeyTableColumn::kALL);
/**
* @brief Set the Double Clicked Action object
@@ -293,7 +156,7 @@ class KeyList : public QWidget {
* @param keyIds
* @param key_table
*/
- static void SetChecked(const KeyIdArgsListPtr& keyIds,
+ static void SetChecked(const KeyIdArgsListPtr& key_ids,
const KeyTable& key_table);
/**
@@ -318,6 +181,12 @@ class KeyList : public QWidget {
*/
[[maybe_unused]] auto ContainsPrivateKeys() -> bool;
+ /**
+ * @brief
+ *
+ */
+ void UpdateKeyTableColumnType(GpgKeyTableColumn);
+
signals:
/**
* @brief
@@ -333,6 +202,14 @@ class KeyList : public QWidget {
*/
void SignalRefreshDatabase();
+ signals:
+
+ /**
+ * @brief
+ *
+ */
+ void SignalColumnTypeChange(GpgKeyTableColumn);
+
public slots:
/**
@@ -359,7 +236,7 @@ class KeyList : public QWidget {
*
* @param inBuffer
*/
- void import_keys(const QByteArray& inBuffer);
+ void import_keys(const QByteArray& in_buffer);
/**
* @brief
@@ -384,6 +261,14 @@ class KeyList : public QWidget {
std::function<void(const GpgKey&, QWidget*)> m_action_ = nullptr; ///<
KeyMenuAbility::AbilityType menu_ability_ = KeyMenuAbility::ALL; ///<
QSharedPointer<GpgKeyTableModel> model_;
+ GpgKeyTableColumn fixed_columns_filter_;
+ GpgKeyTableColumn global_column_filter_;
+
+ QAction* key_id_column_action_;
+ QAction* algo_column_action_;
+ QAction* create_date_column_action_;
+ QAction* owner_trust_column_action_;
+ QAction* subkeys_number_column_action_;
private slots:
diff --git a/src/ui/widgets/KeyTable.cpp b/src/ui/widgets/KeyTable.cpp
new file mode 100644
index 00000000..fc6d083f
--- /dev/null
+++ b/src/ui/widgets/KeyTable.cpp
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) 2021 Saturneric <[email protected]>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "ui/widgets/KeyTable.h"
+
+#include "ui/UserInterfaceUtils.h"
+
+namespace GpgFrontend::UI {
+
+auto KeyTable::GetChecked() const -> KeyIdArgsListPtr {
+ auto ret = std::make_unique<KeyIdArgsList>();
+ for (size_t i = 0; i < GetRowCount(); i++) {
+ if (IsRowChecked(i)) ret->push_back(GetKeyIdByRow(i));
+ }
+ return ret;
+}
+
+KeyTable::KeyTable(QWidget* parent, QSharedPointer<GpgKeyTableModel> model,
+ GpgKeyTableDisplayMode select_type,
+ GpgKeyTableColumn column_filter,
+ GpgKeyTableProxyModel::KeyFilter filter)
+ : QTableView(parent),
+ model_(std::move(model)),
+ proxy_model_(model_, select_type, column_filter, std::move(filter), this),
+ column_filter_(column_filter) {
+ setModel(&proxy_model_);
+
+ verticalHeader()->hide();
+ horizontalHeader()->setStretchLastSection(false);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+
+ setShowGrid(false);
+ sortByColumn(2, Qt::AscendingOrder);
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // table items not editable
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ setFocusPolicy(Qt::NoFocus);
+ setAlternatingRowColors(true);
+
+ connect(CommonUtils::GetInstance(), &CommonUtils::SignalFavoritesChanged,
+ &proxy_model_, &GpgKeyTableProxyModel::SignalFavoritesChanged);
+ connect(this, &KeyTable::SignalColumnTypeChange, this,
+ [=](GpgKeyTableColumn global_column_filter) {
+ emit(&proxy_model_)
+ ->SignalColumnTypeChange(column_filter_ & global_column_filter);
+ });
+}
+
+void KeyTable::SetFilterKeyword(const QString& keyword) {
+ proxy_model_.SetSearchKeywords(keyword);
+}
+
+void KeyTable::RefreshModel(QSharedPointer<GpgKeyTableModel> model) {
+ model_ = std::move(model);
+ proxy_model_.setSourceModel(model_.get());
+}
+
+auto KeyTable::IsRowChecked(int row) const -> bool {
+ auto index = model()->index(row, 0);
+ return index.data(Qt::CheckStateRole).toInt() == Qt::Checked;
+}
+
+auto KeyTable::GetRowCount() const -> int { return model()->rowCount(); }
+
+auto KeyTable::GetKeyIdByRow(int row) const -> QString {
+ if (row < 0 || row >= model()->rowCount()) return {};
+ auto origin_row = model()->index(row, 0).data().toInt();
+ return model_->GetKeyIDByRow(origin_row);
+}
+
+auto KeyTable::IsPrivateKeyByRow(int row) const -> bool {
+ if (row < 0 || row >= model()->rowCount()) return false;
+ auto origin_row = model()->index(row, 0).data().toInt();
+ return model_->IsPrivateKeyByRow(origin_row);
+}
+
+auto KeyTable::IsPublicKeyByRow(int row) const -> bool {
+ if (row < 0 || row >= model()->rowCount()) return false;
+ auto origin_row = model()->index(row, 0).data().toInt();
+ return !model_->IsPrivateKeyByRow(origin_row);
+}
+
+void KeyTable::SetRowChecked(int row) const {
+ if (row < 0 || row >= model()->rowCount()) return;
+ model()->setData(model()->index(row, 0), Qt::Checked, Qt::CheckStateRole);
+}
+
+void KeyTable::CheckAll() {
+ for (int row = 0; row < model()->rowCount(); ++row) {
+ auto index = model()->index(row, 0);
+ model()->setData(index, Qt::Checked, Qt::CheckStateRole);
+ }
+}
+
+void KeyTable::UncheckAll() {
+ for (int row = 0; row < model()->rowCount(); ++row) {
+ auto index = model()->index(row, 0);
+ model()->setData(index, Qt::Unchecked, Qt::CheckStateRole);
+ }
+}
+
+[[nodiscard]] auto KeyTable::GetRowSelected() const -> int {
+ auto selected_indexes = selectedIndexes();
+ if (selected_indexes.empty()) return -1;
+
+ return selected_indexes.first().row();
+}
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/widgets/KeyTable.h b/src/ui/widgets/KeyTable.h
new file mode 100644
index 00000000..4ec8f687
--- /dev/null
+++ b/src/ui/widgets/KeyTable.h
@@ -0,0 +1,176 @@
+/**
+ * Copyright (C) 2021 Saturneric <[email protected]>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include "core/model/GpgKey.h"
+#include "core/model/GpgKeyTableModel.h"
+#include "core/model/GpgKeyTableProxyModel.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+struct KeyTable : public QTableView {
+ Q_OBJECT
+ public:
+ using KeyTableFilter = std::function<bool(const GpgKey&, const KeyTable&)>;
+
+ /**
+ * @brief Construct a new Key Table object
+ *
+ * @param _key_list
+ * @param _select_type
+ * @param _info_type
+ * @param _filter
+ */
+ KeyTable(
+ QWidget* parent, QSharedPointer<GpgKeyTableModel> model,
+ GpgKeyTableDisplayMode _select_type, GpgKeyTableColumn _info_type,
+ GpgKeyTableProxyModel::KeyFilter _filter = [](const GpgKey&) -> bool {
+ return true;
+ });
+
+ /**
+ * @brief
+ *
+ * @param model
+ */
+ void RefreshModel(QSharedPointer<GpgKeyTableModel> model);
+
+ /**
+ * @brief Get the Checked object
+ *
+ * @return KeyIdArgsListPtr&
+ */
+ [[nodiscard]] auto GetChecked() const -> KeyIdArgsListPtr;
+
+ /**
+ * @brief
+ *
+ */
+ void UncheckALL() const;
+
+ /**
+ * @brief
+ *
+ */
+ void CheckALL() const;
+
+ /**
+ * @brief
+ *
+ */
+ void SetFilterKeyword(const QString& keyword);
+
+ /**
+ * @brief
+ *
+ * @param row
+ * @return true
+ * @return false
+ */
+ [[nodiscard]] auto IsRowChecked(int row) const -> bool;
+
+ /**
+ * @brief Set the Row Checked object
+ *
+ * @param row
+ */
+ void SetRowChecked(int row) const;
+
+ /**
+ * @brief Set the Row Checked object
+ *
+ * @param row
+ */
+ [[nodiscard]] auto GetRowSelected() const -> int;
+
+ /**
+ * @brief Get the Row Count object
+ *
+ * @return auto
+ */
+ [[nodiscard]] auto GetRowCount() const -> int;
+
+ /**
+ * @brief Get the Key Id By Row object
+ *
+ * @param row
+ * @return QString
+ */
+ [[nodiscard]] auto GetKeyIdByRow(int row) const -> QString;
+
+ /**
+ * @brief
+ *
+ * @param row
+ * @return true
+ * @return false
+ */
+ [[nodiscard]] auto IsPublicKeyByRow(int row) const -> bool;
+
+ /**
+ * @brief
+ *
+ * @param row
+ * @return true
+ * @return false
+ */
+ [[nodiscard]] auto IsPrivateKeyByRow(int row) const -> bool;
+
+ /**
+ * @brief
+ *
+ */
+ void CheckAll();
+
+ /**
+ * @brief
+ *
+ */
+ void UncheckAll();
+
+ signals:
+
+ /**
+ * @brief
+ *
+ */
+ void SignalColumnTypeChange(GpgKeyTableColumn);
+
+ private:
+ QSharedPointer<GpgKeyTableModel> model_;
+ GpgKeyTableProxyModel proxy_model_;
+
+ GpgKeyTableColumn column_filter_;
+};
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/ui/KeyList.ui b/ui/KeyList.ui
index afccdcf6..618b44fd 100644
--- a/ui/KeyList.ui
+++ b/ui/KeyList.ui
@@ -93,6 +93,23 @@
</widget>
</item>
<item>
+ <widget class="QToolButton" name="columnTypeButton">
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="../gpgfrontend.qrc">
+ <normaloff>:/icons/filter.png</normaloff>:/icons/filter.png</iconset>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>