context menu to trust or distrust keys

This commit is contained in:
Blue 2023-01-15 21:17:38 +03:00
parent b72a837754
commit 73d83f55af
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
5 changed files with 144 additions and 18 deletions

View File

@ -43,6 +43,12 @@ void UI::KeyDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
painter->save(); painter->save();
painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::Antialiasing, true);
QRect r;
int maxRight = 0;
int leftOrigin = option.rect.left() + margin;
QColor q = painter->pen().color();
q.setAlpha(180);
QRect rect = option.rect;
bool hover = option.state & QStyle::State_MouseOver; bool hover = option.state & QStyle::State_MouseOver;
if (hover) { if (hover) {
painter->save(); painter->save();
@ -50,13 +56,15 @@ void UI::KeyDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
painter->restore(); painter->restore();
} }
QRect r; QVariant dirtyV = index.data(UI::KeysModel::Dirty);
int maxRight = 0; if (dirtyV.isValid() && dirtyV.toBool()) {
int leftOrigin = option.rect.left() + margin; painter->save();
QColor q = painter->pen().color(); rect.setWidth(margin / 2);
q.setAlpha(180); painter->fillRect(rect, option.palette.brush(QPalette::Active, QPalette::Highlight));
rect.setWidth(option.rect.width());
painter->restore();
}
QRect rect = option.rect;
rect.adjust(margin, margin, -margin, -margin); rect.adjust(margin, margin, -margin, -margin);
QVariant labelV = index.data(UI::KeysModel::Label); QVariant labelV = index.data(UI::KeysModel::Label);
if (labelV.isValid()) { if (labelV.isValid()) {
@ -167,6 +175,7 @@ QSize UI::KeyDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
firstLine = parts; firstLine = parts;
width = std::max(width, firstLine * fingerPrintMetrics.horizontalAdvance(hex, partSize) + (firstLine - 1) * spaceWidth); width = std::max(width, firstLine * fingerPrintMetrics.horizontalAdvance(hex, partSize) + (firstLine - 1) * spaceWidth);
width += 1; //there is a mistake somewhere, this the cheapest way to compensate it
} }
QVariant lastV = index.data(UI::KeysModel::LastInteraction); QVariant lastV = index.data(UI::KeysModel::LastInteraction);
if (lastV.isValid()) { if (lastV.isValid()) {
@ -186,6 +195,7 @@ QSize UI::KeyDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
width += margin; width += margin;
width += defaultMetrics.horizontalAdvance(levelName); width += defaultMetrics.horizontalAdvance(levelName);
width += 1; //there is a mistake somewhere, this the cheapest way to compensate it
} }
mw += width; mw += width;

View File

@ -24,12 +24,32 @@ const QHash<int, QByteArray> UI::KeysModel::roles = {
UI::KeysModel::KeysModel(QObject* parent): UI::KeysModel::KeysModel(QObject* parent):
QAbstractListModel(parent), QAbstractListModel(parent),
keys() keys(),
modified()
{ {
} }
UI::KeysModel::~KeysModel() { UI::KeysModel::~KeysModel() {
for (Shared::KeyInfo* key : keys) {
delete key;
}
for (std::pair<const int, Shared::KeyInfo*>& pair: modified) {
delete pair.second;
}
}
std::deque<Shared::KeyInfo> UI::KeysModel::modifiedKeys() const {
std::deque<Shared::KeyInfo> response(modified.size());
int i = 0;
for (const std::pair<const int, Shared::KeyInfo*>& pair: modified) {
response[i] = *(pair.second);
++i;
}
return response;
} }
void UI::KeysModel::addKey(const Shared::KeyInfo& info) { void UI::KeysModel::addKey(const Shared::KeyInfo& info) {
@ -40,24 +60,34 @@ void UI::KeysModel::addKey(const Shared::KeyInfo& info) {
QVariant UI::KeysModel::data(const QModelIndex& index, int role) const { QVariant UI::KeysModel::data(const QModelIndex& index, int role) const {
int i = index.row(); int i = index.row();
const Shared::KeyInfo* info;
bool dirty;
std::map<int, Shared::KeyInfo*>::const_iterator itr = modified.find(i);
if (itr != modified.end()) {
info = itr->second;
dirty = true;
} else {
dirty = false;
info = keys[i];
}
QVariant answer; QVariant answer;
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
case Label: case Label:
answer = keys[i]->label; answer = info->label;
break; break;
case FingerPrint: case FingerPrint:
answer = keys[i]->fingerPrint; answer = info->fingerPrint;
break; break;
case TrustLevel: case TrustLevel:
answer = static_cast<uint8_t>(keys[i]->trustLevel); answer = static_cast<uint8_t>(info->trustLevel);
break; break;
case LastInteraction: case LastInteraction:
answer = keys[i]->lastInteraction; answer = info->lastInteraction;
break; break;
case Dirty: case Dirty:
answer = false; answer = dirty;
break; break;
} }
@ -78,7 +108,34 @@ QModelIndex UI::KeysModel::index(int row, int column, const QModelIndex& parent)
return createIndex(row, column, keys[row]); return createIndex(row, column, keys[row]);
} }
void UI::KeysModel::revertKey(int row) {
std::map<int, Shared::KeyInfo*>::const_iterator itr = modified.find(row);
if (itr != modified.end()) {
modified.erase(itr);
QModelIndex index = createIndex(row, 0, keys[row]);
dataChanged(index, index);
}
}
void UI::KeysModel::setTrustLevel(int row, Shared::TrustLevel level) {
std::map<int, Shared::KeyInfo*>::const_iterator itr = modified.find(row);
Shared::KeyInfo* info;
if (itr == modified.end()) {
if (row < rowCount()) {
info = new Shared::KeyInfo(*(keys[row]));
modified.insert(std::make_pair(row, info));
} else {
return;
}
} else {
info = itr->second;
}
info->trustLevel = level;
QModelIndex index = createIndex(row, 0, info);
dataChanged(index, index, {KeysModel::Dirty});
}

View File

@ -40,6 +40,8 @@ public:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column, const QModelIndex & parent) const override; QModelIndex index(int row, int column, const QModelIndex & parent) const override;
std::deque<Shared::KeyInfo> modifiedKeys() const;
enum Roles { enum Roles {
Label = Qt::UserRole + 1, Label = Qt::UserRole + 1,
FingerPrint, FingerPrint,
@ -48,8 +50,13 @@ public:
Dirty Dirty
}; };
public slots:
void revertKey(int index);
void setTrustLevel(int index, Shared::TrustLevel level);
private: private:
std::deque<Shared::KeyInfo*> keys; std::deque<Shared::KeyInfo*> keys;
std::map<int, Shared::KeyInfo*> modified;
private: private:
static const QHash<int, QByteArray> roles; static const QHash<int, QByteArray> roles;

View File

@ -26,7 +26,8 @@ Omemo::Omemo(QWidget* parent):
keysDelegate(), keysDelegate(),
unusedKeysDelegate(), unusedKeysDelegate(),
keysModel(), keysModel(),
unusedKeysModel() unusedKeysModel(),
contextMenu(new QMenu())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@ -36,15 +37,17 @@ Omemo::Omemo(QWidget* parent):
m_ui->keysView->setModel(&keysModel); m_ui->keysView->setModel(&keysModel);
m_ui->unusedKeysView->setItemDelegate(&unusedKeysDelegate); m_ui->unusedKeysView->setItemDelegate(&unusedKeysDelegate);
m_ui->unusedKeysView->setModel(&unusedKeysModel); m_ui->unusedKeysView->setModel(&unusedKeysModel);
m_ui->keysView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_ui->keysView, &QWidget::customContextMenuRequested, this, &Omemo::onActiveKeysContextMenu);
} }
Omemo::~Omemo() Omemo::~Omemo()
{ {
contextMenu->deleteLater();
} }
void Omemo::generateMockData() void Omemo::generateMockData() {
{
std::random_device rd; std::random_device rd;
std::uniform_int_distribution<char> dist(CHAR_MIN, CHAR_MAX); std::uniform_int_distribution<char> dist(CHAR_MIN, CHAR_MAX);
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
@ -63,3 +66,46 @@ void Omemo::generateMockData()
keysModel.addKey(info); keysModel.addKey(info);
} }
} }
void Omemo::onActiveKeysContextMenu(const QPoint& pos) {
contextMenu->clear();
QModelIndex index = m_ui->keysView->indexAt(pos);
if (index.isValid()) {
QVariant dirtyV = index.data(UI::KeysModel::Dirty);
if (dirtyV.isValid() && dirtyV.toBool()) {
QAction* rev = contextMenu->addAction(Shared::icon("clean"), tr("Revert changes"));
connect(rev, &QAction::triggered, std::bind(&UI::KeysModel::revertKey, &keysModel, index.row()));
}
QVariant levelV = index.data(UI::KeysModel::TrustLevel);
if (levelV.isValid()) {
Shared::TrustLevel level = static_cast<Shared::TrustLevel>(levelV.toUInt());
if (level == Shared::TrustLevel::undecided ||
level == Shared::TrustLevel::automaticallyDistrusted ||
level == Shared::TrustLevel::manuallyDistrusted
) {
QAction* rev = contextMenu->addAction(Shared::icon("favorite"), tr("Trust"));
connect(rev, &QAction::triggered,
std::bind(&UI::KeysModel::setTrustLevel, &keysModel,
index.row(), Shared::TrustLevel::manuallyTrusted
)
);
}
if (level == Shared::TrustLevel::undecided ||
level == Shared::TrustLevel::automaticallyTrusted ||
level == Shared::TrustLevel::manuallyTrusted ||
level == Shared::TrustLevel::authenticated
) {
QAction* rev = contextMenu->addAction(Shared::icon("unfavorite"), tr("Distrust"));
connect(rev, &QAction::triggered,
std::bind(&UI::KeysModel::setTrustLevel, &keysModel,
index.row(), Shared::TrustLevel::manuallyDistrusted
)
);
}
}
}
contextMenu->popup(m_ui->keysView->viewport()->mapToGlobal(pos));
}

View File

@ -17,11 +17,13 @@
#ifndef VCARD_OMEMO_H #ifndef VCARD_OMEMO_H
#define VCARD_OMEMO_H #define VCARD_OMEMO_H
#include <qwidget.h> #include <QWidget>
#include <QScopedPointer> #include <QScopedPointer>
#include <QMenu>
#include "keysmodel.h" #include "keysmodel.h"
#include "keydelegate.h" #include "keydelegate.h"
#include "shared/icons.h"
namespace Ui namespace Ui
{ {
@ -34,6 +36,9 @@ public:
Omemo(QWidget* parent = nullptr); Omemo(QWidget* parent = nullptr);
~Omemo(); ~Omemo();
private slots:
void onActiveKeysContextMenu(const QPoint& pos);
private: private:
void generateMockData(); void generateMockData();
@ -43,6 +48,7 @@ private:
UI::KeyDelegate unusedKeysDelegate; UI::KeyDelegate unusedKeysDelegate;
UI::KeysModel keysModel; UI::KeysModel keysModel;
UI::KeysModel unusedKeysModel; UI::KeysModel unusedKeysModel;
QMenu* contextMenu;
}; };
#endif // VCARD_OMEMO_H #endif // VCARD_OMEMO_H