mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Refactor DetailsWidget
This commit is contained in:
parent
3ba42ee32e
commit
6007e0de71
@ -48,7 +48,7 @@ bool EntryAttributes::hasKey(const QString& key) const
|
|||||||
return m_attributes.contains(key);
|
return m_attributes.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> EntryAttributes::customKeys()
|
QList<QString> EntryAttributes::customKeys() const
|
||||||
{
|
{
|
||||||
QList<QString> customKeys;
|
QList<QString> customKeys;
|
||||||
const QList<QString> keyList = keys();
|
const QList<QString> keyList = keys();
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
explicit EntryAttributes(QObject* parent = nullptr);
|
explicit EntryAttributes(QObject* parent = nullptr);
|
||||||
QList<QString> keys() const;
|
QList<QString> keys() const;
|
||||||
bool hasKey(const QString& key) const;
|
bool hasKey(const QString& key) const;
|
||||||
QList<QString> customKeys();
|
QList<QString> customKeys() const;
|
||||||
QString value(const QString& key) const;
|
QString value(const QString& key) const;
|
||||||
bool contains(const QString& key) const;
|
bool contains(const QString& key) const;
|
||||||
bool containsValue(const QString& value) const;
|
bool containsValue(const QString& value) const;
|
||||||
|
@ -439,11 +439,11 @@ void Group::setParent(Database* db)
|
|||||||
QObject::setParent(db);
|
QObject::setParent(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Group::hierarchy()
|
QStringList Group::hierarchy() const
|
||||||
{
|
{
|
||||||
QStringList hierarchy;
|
QStringList hierarchy;
|
||||||
Group* group = this;
|
const Group* group = this;
|
||||||
Group* parent = m_parent;
|
const Group* parent = m_parent;
|
||||||
hierarchy.prepend(group->name());
|
hierarchy.prepend(group->name());
|
||||||
|
|
||||||
while (parent) {
|
while (parent) {
|
||||||
|
@ -117,7 +117,7 @@ public:
|
|||||||
Group* parentGroup();
|
Group* parentGroup();
|
||||||
const Group* parentGroup() const;
|
const Group* parentGroup() const;
|
||||||
void setParent(Group* parent, int index = -1);
|
void setParent(Group* parent, int index = -1);
|
||||||
QStringList hierarchy();
|
QStringList hierarchy() const;
|
||||||
|
|
||||||
Database* database();
|
Database* database();
|
||||||
const Database* database() const;
|
const Database* database() const;
|
||||||
|
@ -111,9 +111,13 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
|||||||
"border-radius: 5px;");
|
"border-radius: 5px;");
|
||||||
|
|
||||||
m_detailsView = new DetailsWidget(this);
|
m_detailsView = new DetailsWidget(this);
|
||||||
connect(m_detailsView, &DetailsWidget::errorOccurred, this, [this](const QString& error) {
|
m_detailsView->hide();
|
||||||
showMessage(error, MessageWidget::MessageType::Error);
|
connect(this, SIGNAL(pressedEntry(Entry*)), m_detailsView, SLOT(setEntry(Entry*)));
|
||||||
});
|
connect(this, SIGNAL(pressedGroup(Group*)), m_detailsView, SLOT(setGroup(Group*)));
|
||||||
|
connect(this, SIGNAL(currentModeChanged(DatabaseWidget::Mode)),
|
||||||
|
m_detailsView, SLOT(setDatabaseMode(DatabaseWidget::Mode)));
|
||||||
|
connect(m_detailsView, SIGNAL(errorOccurred(QString)), this, SLOT(showErrorMessage(QString)));
|
||||||
|
|
||||||
|
|
||||||
QVBoxLayout* vLayout = new QVBoxLayout(rightHandSideWidget);
|
QVBoxLayout* vLayout = new QVBoxLayout(rightHandSideWidget);
|
||||||
vLayout->setMargin(0);
|
vLayout->setMargin(0);
|
||||||
@ -1488,6 +1492,11 @@ void DatabaseWidget::showMessage(const QString& text, MessageWidget::MessageType
|
|||||||
m_messageWidget->showMessage(text, type, autoHideTimeout);
|
m_messageWidget->showMessage(text, type, autoHideTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseWidget::showErrorMessage(const QString& errorMessage)
|
||||||
|
{
|
||||||
|
showMessage(errorMessage, MessageWidget::MessageType::Error);
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseWidget::hideMessage()
|
void DatabaseWidget::hideMessage()
|
||||||
{
|
{
|
||||||
if (m_messageWidget->isVisible()) {
|
if (m_messageWidget->isVisible()) {
|
||||||
|
@ -178,6 +178,7 @@ public slots:
|
|||||||
|
|
||||||
void showMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton = true,
|
void showMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton = true,
|
||||||
int autoHideTimeout = MessageWidget::DefaultAutoHideTimeout);
|
int autoHideTimeout = MessageWidget::DefaultAutoHideTimeout);
|
||||||
|
void showErrorMessage(const QString& errorMessage);
|
||||||
void hideMessage();
|
void hideMessage();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -28,105 +28,150 @@
|
|||||||
#include "gui/Clipboard.h"
|
#include "gui/Clipboard.h"
|
||||||
#include "entry/EntryAttachmentsModel.h"
|
#include "entry/EntryAttachmentsModel.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int GeneralTabIndex = 0;
|
||||||
|
const QString hierarchySeparator(" / ");
|
||||||
|
}
|
||||||
|
|
||||||
DetailsWidget::DetailsWidget(QWidget* parent)
|
DetailsWidget::DetailsWidget(QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_ui(new Ui::DetailsWidget())
|
, m_ui(new Ui::DetailsWidget())
|
||||||
, m_locked(false)
|
, m_locked(false)
|
||||||
, m_currentEntry(nullptr)
|
, m_currentEntry(nullptr)
|
||||||
, m_currentGroup(nullptr)
|
, m_currentGroup(nullptr)
|
||||||
, m_timer(nullptr)
|
, m_step(0)
|
||||||
, m_attributesTabWidget(nullptr)
|
, m_totpTimer(nullptr)
|
||||||
, m_attachmentsTabWidget(nullptr)
|
|
||||||
, m_autotypeTabWidget(nullptr)
|
|
||||||
, m_selectedTabEntry(0)
|
, m_selectedTabEntry(0)
|
||||||
, m_selectedTabGroup(0)
|
, m_selectedTabGroup(0)
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
connect(parent, SIGNAL(pressedEntry(Entry*)), SLOT(getSelectedEntry(Entry*)));
|
// Entry
|
||||||
connect(parent, SIGNAL(pressedGroup(Group*)), SLOT(getSelectedGroup(Group*)));
|
m_ui->entryTotpButton->setIcon(filePath()->icon("actions", "chronometer"));
|
||||||
connect(parent, SIGNAL(currentModeChanged(DatabaseWidget::Mode)), SLOT(setDatabaseMode(DatabaseWidget::Mode)));
|
m_ui->entryCloseButton->setIcon(filePath()->icon("actions", "dialog-close"));
|
||||||
|
|
||||||
m_ui->totpButton->setIcon(filePath()->icon("actions", "chronometer"));
|
m_ui->entryAttachmentsWidget->setReadOnly(true);
|
||||||
m_ui->closeButton->setIcon(filePath()->icon("actions", "dialog-close"));
|
m_ui->entryAttachmentsWidget->setButtonsVisible(false);
|
||||||
|
|
||||||
connect(m_ui->totpButton, SIGNAL(toggled(bool)), SLOT(showTotp(bool)));
|
connect(m_ui->entryTotpButton, SIGNAL(toggled(bool)), m_ui->entryTotpWidget, SLOT(setVisible(bool)));
|
||||||
connect(m_ui->closeButton, SIGNAL(toggled(bool)), SLOT(hideDetails()));
|
connect(m_ui->entryCloseButton, SIGNAL(toggled(bool)), SLOT(hide()));
|
||||||
connect(m_ui->tabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndex(int)));
|
connect(m_ui->entryTabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndexes()), Qt::QueuedConnection);
|
||||||
|
|
||||||
m_ui->attachmentsWidget->setReadOnly(true);
|
// Group
|
||||||
m_ui->attachmentsWidget->setButtonsVisible(false);
|
m_ui->groupCloseButton->setIcon(filePath()->icon("actions", "dialog-close"));
|
||||||
|
connect(m_ui->groupCloseButton, SIGNAL(toggled(bool)), SLOT(hide()));
|
||||||
m_attributesTabWidget = m_ui->tabWidget->widget(AttributesTab);
|
connect(m_ui->groupTabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndexes()), Qt::QueuedConnection);
|
||||||
m_attachmentsTabWidget = m_ui->tabWidget->widget(AttachmentsTab);
|
|
||||||
m_autotypeTabWidget = m_ui->tabWidget->widget(AutotypeTab);
|
|
||||||
|
|
||||||
this->hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailsWidget::~DetailsWidget()
|
DetailsWidget::~DetailsWidget()
|
||||||
{
|
{
|
||||||
if (m_timer) {
|
deleteTotpTimer();
|
||||||
delete m_timer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsWidget::getSelectedEntry(Entry* selectedEntry)
|
void DetailsWidget::setEntry(Entry* selectedEntry)
|
||||||
{
|
{
|
||||||
if (!selectedEntry) {
|
if (!selectedEntry) {
|
||||||
hideDetails();
|
hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_currentEntry = selectedEntry;
|
m_currentEntry = selectedEntry;
|
||||||
|
|
||||||
if (!config()->get("GUI/HideDetailsView").toBool()) {
|
updateEntryHeaderLine();
|
||||||
this->show();
|
updateEntryTotp();
|
||||||
|
updateEntryGeneralTab();
|
||||||
|
updateEntryNotesTab();
|
||||||
|
updateEntryAttributesTab();
|
||||||
|
updateEntryAttachmentsTab();
|
||||||
|
updateEntryAutotypeTab();
|
||||||
|
|
||||||
|
setVisible(!config()->get("GUI/HideDetailsView").toBool());
|
||||||
|
|
||||||
|
m_ui->stackedWidget->setCurrentWidget(m_ui->pageEntry);
|
||||||
|
const int tabIndex = m_ui->entryTabWidget->isTabEnabled(m_selectedTabEntry) ? m_selectedTabEntry
|
||||||
|
: GeneralTabIndex;
|
||||||
|
Q_ASSERT(m_ui->entryTabWidget->isTabEnabled(GeneralTabIndex));
|
||||||
|
m_ui->entryTabWidget->setCurrentIndex(tabIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::setGroup(Group* selectedGroup)
|
||||||
|
{
|
||||||
|
if (!selectedGroup) {
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->stackedWidget->setCurrentIndex(EntryPreview);
|
m_currentGroup = selectedGroup;
|
||||||
|
updateGroupHeaderLine();
|
||||||
|
updateGroupGeneralTab();
|
||||||
|
updateGroupNotesTab();
|
||||||
|
|
||||||
if (m_ui->tabWidget->count() < 5) {
|
setVisible(!config()->get("GUI/HideDetailsView").toBool());
|
||||||
m_ui->tabWidget->insertTab(static_cast<int>(AttributesTab), m_attributesTabWidget, tr("Attributes"));
|
|
||||||
m_ui->tabWidget->insertTab(static_cast<int>(AttachmentsTab), m_attachmentsTabWidget, tr("Attachments"));
|
m_ui->stackedWidget->setCurrentWidget(m_ui->pageGroup);
|
||||||
m_ui->tabWidget->insertTab(static_cast<int>(AutotypeTab), m_autotypeTabWidget, tr("Autotype"));
|
const int tabIndex = m_ui->groupTabWidget->isTabEnabled(m_selectedTabGroup) ? m_selectedTabGroup
|
||||||
|
: GeneralTabIndex;
|
||||||
|
Q_ASSERT(m_ui->groupTabWidget->isTabEnabled(GeneralTabIndex));
|
||||||
|
m_ui->groupTabWidget->setCurrentIndex(tabIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::setDatabaseMode(DatabaseWidget::Mode mode)
|
||||||
|
{
|
||||||
|
m_locked = mode == DatabaseWidget::LockedMode;
|
||||||
|
if (m_locked) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->tabWidget->setTabEnabled(AttributesTab, false);
|
if (mode == DatabaseWidget::ViewMode) {
|
||||||
m_ui->tabWidget->setTabEnabled(NotesTab, false);
|
if (m_ui->stackedWidget->currentWidget() == m_ui->pageGroup) {
|
||||||
m_ui->tabWidget->setTabEnabled(AutotypeTab, false);
|
setGroup(m_currentGroup);
|
||||||
|
} else {
|
||||||
m_ui->totpButton->hide();
|
setEntry(m_currentEntry);
|
||||||
m_ui->totpWidget->hide();
|
|
||||||
m_ui->totpButton->setChecked(false);
|
|
||||||
|
|
||||||
auto icon = m_currentEntry->iconPixmap();
|
|
||||||
if (icon.width() > 16 || icon.height() > 16) {
|
|
||||||
icon = icon.scaled(16, 16);
|
|
||||||
}
|
|
||||||
m_ui->entryIcon->setPixmap(icon);
|
|
||||||
|
|
||||||
QString title = QString(" / ");
|
|
||||||
Group* entry_group = m_currentEntry->group();
|
|
||||||
if (entry_group) {
|
|
||||||
QStringList hierarchy = entry_group->hierarchy();
|
|
||||||
hierarchy.removeFirst();
|
|
||||||
title += hierarchy.join(" / ");
|
|
||||||
if (hierarchy.size() > 0) {
|
|
||||||
title += " / ";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
title.append(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->title()));
|
}
|
||||||
m_ui->titleLabel->setText(title);
|
|
||||||
|
|
||||||
m_ui->usernameLabel->setText(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->username()));
|
void DetailsWidget::updateEntryHeaderLine()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
|
const QString title = m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->title());
|
||||||
|
m_ui->entryTitleLabel->setText(hierarchy(m_currentEntry->group(), title));
|
||||||
|
m_ui->entryIcon->setPixmap(preparePixmap(m_currentEntry->iconPixmap(), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateEntryTotp()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
|
const bool hasTotp = m_currentEntry->hasTotp();
|
||||||
|
m_ui->entryTotpButton->setVisible(hasTotp);
|
||||||
|
m_ui->entryTotpWidget->hide();
|
||||||
|
m_ui->entryTotpButton->setChecked(false);
|
||||||
|
|
||||||
|
if (hasTotp) {
|
||||||
|
deleteTotpTimer();
|
||||||
|
m_totpTimer = new QTimer(m_currentEntry);
|
||||||
|
connect(m_totpTimer, SIGNAL(timeout()), this, SLOT(updateTotpLabel()));
|
||||||
|
m_totpTimer->start(1000);
|
||||||
|
|
||||||
|
m_step = m_currentEntry->totpStep();
|
||||||
|
updateTotpLabel();
|
||||||
|
} else {
|
||||||
|
m_ui->entryTotpLabel->clear();
|
||||||
|
stopTotpTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateEntryGeneralTab()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
|
m_ui->entryUsernameLabel->setText(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->username()));
|
||||||
|
|
||||||
if (!config()->get("security/hidepassworddetails").toBool()) {
|
if (!config()->get("security/hidepassworddetails").toBool()) {
|
||||||
m_ui->passwordLabel->setText(
|
const QString password = m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password());
|
||||||
shortPassword(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password())));
|
m_ui->entryPasswordLabel->setText(shortPassword(password));
|
||||||
m_ui->passwordLabel->setToolTip(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password()));
|
m_ui->entryPasswordLabel->setToolTip(password);
|
||||||
} else {
|
} else {
|
||||||
m_ui->passwordLabel->setText(QString("\u25cf").repeated(6));
|
m_ui->entryPasswordLabel->setText(QString("\u25cf").repeated(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString url = m_currentEntry->webUrl();
|
QString url = m_currentEntry->webUrl();
|
||||||
@ -135,46 +180,38 @@ void DetailsWidget::getSelectedEntry(Entry* selectedEntry)
|
|||||||
// create a new display url that masks password placeholders
|
// create a new display url that masks password placeholders
|
||||||
// the actual link will use the password
|
// the actual link will use the password
|
||||||
url = QString("<a href=\"%1\">%2</a>").arg(url).arg(shortUrl(m_currentEntry->displayUrl()));
|
url = QString("<a href=\"%1\">%2</a>").arg(url).arg(shortUrl(m_currentEntry->displayUrl()));
|
||||||
m_ui->urlLabel->setOpenExternalLinks(true);
|
m_ui->entryUrlLabel->setOpenExternalLinks(true);
|
||||||
} else {
|
} else {
|
||||||
// Fallback to the raw url string
|
// Fallback to the raw url string
|
||||||
url = shortUrl(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->url()));
|
url = shortUrl(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->url()));
|
||||||
m_ui->urlLabel->setOpenExternalLinks(false);
|
m_ui->entryUrlLabel->setOpenExternalLinks(false);
|
||||||
}
|
}
|
||||||
m_ui->urlLabel->setText(url);
|
m_ui->entryUrlLabel->setText(url);
|
||||||
|
|
||||||
TimeInfo entryTime = m_currentEntry->timeInfo();
|
const TimeInfo entryTime = m_currentEntry->timeInfo();
|
||||||
if (entryTime.expires()) {
|
const QString expires = entryTime.expires() ? entryTime.expiryTime().toString(Qt::DefaultLocaleShortDate)
|
||||||
m_ui->expirationLabel->setText(entryTime.expiryTime().toString(Qt::DefaultLocaleShortDate));
|
: tr("Never");
|
||||||
} else {
|
m_ui->entryExpirationLabel->setText(expires);
|
||||||
m_ui->expirationLabel->setText(tr("Never"));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m_currentEntry->hasTotp()) {
|
void DetailsWidget::updateEntryNotesTab()
|
||||||
m_step = m_currentEntry->totpStep();
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
|
const QString notes = m_currentEntry->notes();
|
||||||
|
setTabEnabled(m_ui->entryTabWidget, m_ui->entryNotesTab, !notes.isEmpty());
|
||||||
|
m_ui->entryNotesEdit->setText(m_currentEntry->resolveMultiplePlaceholders(notes));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_timer) {
|
void DetailsWidget::updateEntryAttributesTab()
|
||||||
delete m_timer;
|
{
|
||||||
}
|
Q_ASSERT(m_currentEntry);
|
||||||
m_timer = new QTimer(selectedEntry);
|
m_ui->entryAttributesEdit->clear();
|
||||||
connect(m_timer, SIGNAL(timeout()), this, SLOT(updateTotp()));
|
const EntryAttributes* attributes = m_currentEntry->attributes();
|
||||||
updateTotp();
|
const QStringList customAttributes = attributes->customKeys();
|
||||||
m_timer->start(m_step * 1000);
|
const bool haveAttributes = customAttributes.size() > 0;
|
||||||
m_ui->totpButton->show();
|
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAttributesTab, haveAttributes);
|
||||||
}
|
if (haveAttributes) {
|
||||||
|
QString attributesText;
|
||||||
QString notes = m_currentEntry->notes();
|
|
||||||
if (!notes.isEmpty()) {
|
|
||||||
m_ui->tabWidget->setTabEnabled(NotesTab, true);
|
|
||||||
m_ui->notesEdit->setText(m_currentEntry->resolveMultiplePlaceholders(notes));
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList customAttributes = m_currentEntry->attributes()->customKeys();
|
|
||||||
if (customAttributes.size() > 0) {
|
|
||||||
m_ui->tabWidget->setTabEnabled(AttributesTab, true);
|
|
||||||
m_ui->attributesEdit->clear();
|
|
||||||
|
|
||||||
QString attributesText = QString();
|
|
||||||
for (const QString& key : customAttributes) {
|
for (const QString& key : customAttributes) {
|
||||||
QString value = m_currentEntry->attributes()->value(key);
|
QString value = m_currentEntry->attributes()->value(key);
|
||||||
if (m_currentEntry->attributes()->isProtected(key)) {
|
if (m_currentEntry->attributes()->isProtected(key)) {
|
||||||
@ -182,127 +219,117 @@ void DetailsWidget::getSelectedEntry(Entry* selectedEntry)
|
|||||||
}
|
}
|
||||||
attributesText.append(QString("<b>%1</b>: %2<br/>").arg(key, value));
|
attributesText.append(QString("<b>%1</b>: %2<br/>").arg(key, value));
|
||||||
}
|
}
|
||||||
m_ui->attributesEdit->setText(attributesText);
|
m_ui->entryAttributesEdit->setText(attributesText);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateEntryAttachmentsTab()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
const bool hasAttachments = !m_currentEntry->attachments()->isEmpty();
|
const bool hasAttachments = !m_currentEntry->attachments()->isEmpty();
|
||||||
m_ui->tabWidget->setTabEnabled(AttachmentsTab, hasAttachments);
|
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAttachmentsTab, hasAttachments);
|
||||||
m_ui->attachmentsWidget->setEntryAttachments(m_currentEntry->attachments());
|
m_ui->entryAttachmentsWidget->setEntryAttachments(m_currentEntry->attachments());
|
||||||
|
}
|
||||||
|
|
||||||
m_ui->autotypeTree->clear();
|
void DetailsWidget::updateEntryAutotypeTab()
|
||||||
AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations();
|
{
|
||||||
|
Q_ASSERT(m_currentEntry);
|
||||||
|
m_ui->entryAutotypeTree->clear();
|
||||||
QList<QTreeWidgetItem*> items;
|
QList<QTreeWidgetItem*> items;
|
||||||
for (auto assoc : autotypeAssociations->getAll()) {
|
const AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations();
|
||||||
QStringList association = QStringList() << assoc.window << assoc.sequence;
|
const auto associations = autotypeAssociations->getAll();
|
||||||
if (association.at(1).isEmpty()) {
|
for (const auto& assoc : associations) {
|
||||||
association.replace(1, m_currentEntry->effectiveAutoTypeSequence());
|
const QString sequence = assoc.sequence.isEmpty() ? m_currentEntry->effectiveAutoTypeSequence()
|
||||||
}
|
: assoc.sequence;
|
||||||
items.append(new QTreeWidgetItem(m_ui->autotypeTree, association));
|
items.append(new QTreeWidgetItem(m_ui->entryAutotypeTree, {assoc.window, sequence}));
|
||||||
}
|
|
||||||
if (items.count() > 0) {
|
|
||||||
m_ui->autotypeTree->addTopLevelItems(items);
|
|
||||||
m_ui->tabWidget->setTabEnabled(AutotypeTab, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ui->tabWidget->isTabEnabled(m_selectedTabEntry)) {
|
m_ui->entryAutotypeTree->addTopLevelItems(items);
|
||||||
m_ui->tabWidget->setCurrentIndex(m_selectedTabEntry);
|
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAutotypeTab, !items.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateGroupHeaderLine()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentGroup);
|
||||||
|
m_ui->groupTitleLabel->setText(hierarchy(m_currentGroup, QString()));
|
||||||
|
m_ui->groupIcon->setPixmap(preparePixmap(m_currentGroup->iconPixmap(), 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateGroupGeneralTab()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentGroup);
|
||||||
|
const QString searchingText = m_currentGroup->resolveSearchingEnabled() ? tr("Enabled") : tr("Disabled");
|
||||||
|
m_ui->groupSearchingLabel->setText(searchingText);
|
||||||
|
|
||||||
|
const QString autotypeText = m_currentGroup->resolveAutoTypeEnabled() ? tr("Enabled") : tr("Disabled");
|
||||||
|
m_ui->groupAutotypeLabel->setText(autotypeText);
|
||||||
|
|
||||||
|
const TimeInfo groupTime = m_currentGroup->timeInfo();
|
||||||
|
const QString expiresText = groupTime.expires() ? groupTime.expiryTime().toString(Qt::DefaultLocaleShortDate)
|
||||||
|
: tr("Never");
|
||||||
|
m_ui->groupExpirationLabel->setText(expiresText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateGroupNotesTab()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_currentGroup);
|
||||||
|
const QString notes = m_currentGroup->notes();
|
||||||
|
setTabEnabled(m_ui->groupTabWidget, m_ui->groupNotesTab, !notes.isEmpty());
|
||||||
|
m_ui->groupNotesEdit->setText(notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::stopTotpTimer()
|
||||||
|
{
|
||||||
|
if (m_totpTimer) {
|
||||||
|
m_totpTimer->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsWidget::getSelectedGroup(Group* selectedGroup)
|
void DetailsWidget::deleteTotpTimer()
|
||||||
{
|
{
|
||||||
if (!selectedGroup) {
|
if (m_totpTimer) {
|
||||||
hideDetails();
|
delete m_totpTimer;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_currentGroup = selectedGroup;
|
void DetailsWidget::updateTotpLabel()
|
||||||
|
{
|
||||||
if (!config()->get("GUI/HideDetailsView").toBool()) {
|
if (!m_locked && m_currentEntry) {
|
||||||
this->show();
|
const QString totpCode = m_currentEntry->totp();
|
||||||
}
|
const QString firstHalf = totpCode.left(totpCode.size() / 2);
|
||||||
|
const QString secondHalf = totpCode.mid(totpCode.size() / 2);
|
||||||
m_ui->stackedWidget->setCurrentIndex(GroupPreview);
|
m_ui->entryTotpLabel->setText(firstHalf + " " + secondHalf);
|
||||||
|
|
||||||
if (m_ui->tabWidget->count() > 2) {
|
|
||||||
m_ui->tabWidget->removeTab(AutotypeTab);
|
|
||||||
m_ui->tabWidget->removeTab(AttachmentsTab);
|
|
||||||
m_ui->tabWidget->removeTab(AttributesTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->tabWidget->setTabEnabled(GroupNotesTab, false);
|
|
||||||
|
|
||||||
m_ui->totpButton->hide();
|
|
||||||
m_ui->totpWidget->hide();
|
|
||||||
|
|
||||||
auto icon = m_currentGroup->iconPixmap();
|
|
||||||
if (icon.width() > 32 || icon.height() > 32) {
|
|
||||||
icon = icon.scaled(32, 32);
|
|
||||||
}
|
|
||||||
m_ui->entryIcon->setPixmap(icon);
|
|
||||||
|
|
||||||
QString title = " / ";
|
|
||||||
QStringList hierarchy = m_currentGroup->hierarchy();
|
|
||||||
hierarchy.removeFirst();
|
|
||||||
title += hierarchy.join(" / ");
|
|
||||||
if (hierarchy.size() > 0) {
|
|
||||||
title += " / ";
|
|
||||||
}
|
|
||||||
m_ui->titleLabel->setText(title);
|
|
||||||
|
|
||||||
QString notes = m_currentGroup->notes();
|
|
||||||
if (!notes.isEmpty()) {
|
|
||||||
m_ui->tabWidget->setTabEnabled(GroupNotesTab, true);
|
|
||||||
m_ui->notesEdit->setText(notes);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString searching = tr("Disabled");
|
|
||||||
if (m_currentGroup->resolveSearchingEnabled()) {
|
|
||||||
searching = tr("Enabled");
|
|
||||||
}
|
|
||||||
m_ui->searchingLabel->setText(searching);
|
|
||||||
|
|
||||||
QString autotype = tr("Disabled");
|
|
||||||
if (m_currentGroup->resolveAutoTypeEnabled()) {
|
|
||||||
autotype = tr("Enabled");
|
|
||||||
}
|
|
||||||
m_ui->autotypeLabel->setText(autotype);
|
|
||||||
|
|
||||||
TimeInfo groupTime = m_currentGroup->timeInfo();
|
|
||||||
if (groupTime.expires()) {
|
|
||||||
m_ui->groupExpirationLabel->setText(groupTime.expiryTime().toString(Qt::DefaultLocaleShortDate));
|
|
||||||
} else {
|
} else {
|
||||||
m_ui->groupExpirationLabel->setText(tr("Never"));
|
m_ui->entryTotpLabel->clear();
|
||||||
}
|
stopTotpTimer();
|
||||||
|
|
||||||
if (m_ui->tabWidget->isTabEnabled(m_selectedTabGroup)) {
|
|
||||||
m_ui->tabWidget->setCurrentIndex(m_selectedTabGroup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsWidget::updateTotp()
|
void DetailsWidget::updateTabIndexes()
|
||||||
{
|
{
|
||||||
if (!m_locked) {
|
m_selectedTabEntry = m_ui->entryTabWidget->currentIndex();
|
||||||
QString totpCode = m_currentEntry->totp();
|
m_selectedTabGroup = m_ui->groupTabWidget->currentIndex();
|
||||||
QString firstHalf = totpCode.left(totpCode.size() / 2);
|
|
||||||
QString secondHalf = totpCode.mid(totpCode.size() / 2);
|
|
||||||
m_ui->totpLabel->setText(firstHalf + " " + secondHalf);
|
|
||||||
} else if (m_timer) {
|
|
||||||
m_timer->stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsWidget::showTotp(bool visible)
|
void DetailsWidget::setTabEnabled(QTabWidget* tabWidget, QWidget* widget, bool enabled)
|
||||||
{
|
{
|
||||||
if (visible) {
|
const int tabIndex = tabWidget->indexOf(widget);
|
||||||
m_ui->totpWidget->show();
|
Q_ASSERT(tabIndex != -1);
|
||||||
} else {
|
tabWidget->setTabEnabled(tabIndex, enabled);
|
||||||
m_ui->totpWidget->hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DetailsWidget::shortUrl(QString url)
|
QPixmap DetailsWidget::preparePixmap(const QPixmap& pixmap, int size)
|
||||||
{
|
{
|
||||||
|
if (pixmap.width() > size || pixmap.height() > size) {
|
||||||
|
return pixmap.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString DetailsWidget::shortUrl(const QString& url)
|
||||||
|
{
|
||||||
|
// TODO: create elided text
|
||||||
QString newurl = "";
|
QString newurl = "";
|
||||||
if (url.length() > 60) {
|
if (url.length() > 60) {
|
||||||
newurl.append(url.left(20));
|
newurl.append(url.left(20));
|
||||||
@ -313,43 +340,19 @@ QString DetailsWidget::shortUrl(QString url)
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DetailsWidget::shortPassword(QString password)
|
QString DetailsWidget::shortPassword(const QString& password)
|
||||||
{
|
{
|
||||||
QString newpassword = "";
|
// TODO: create elided text
|
||||||
if (password.length() > 60) {
|
if (password.length() > 60) {
|
||||||
newpassword.append(password.left(50));
|
return QString("%1…").arg(password.left(60));
|
||||||
newpassword.append("…");
|
|
||||||
return newpassword;
|
|
||||||
}
|
}
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsWidget::hideDetails()
|
QString DetailsWidget::hierarchy(const Group* group, const QString& title)
|
||||||
{
|
{
|
||||||
this->hide();
|
QStringList hierarchy = group->hierarchy();
|
||||||
}
|
hierarchy.removeFirst();
|
||||||
|
hierarchy.append(title);
|
||||||
void DetailsWidget::setDatabaseMode(DatabaseWidget::Mode mode)
|
return QString("%1%2").arg(hierarchySeparator, hierarchy.join(hierarchySeparator));
|
||||||
{
|
|
||||||
m_locked = false;
|
|
||||||
if (mode == DatabaseWidget::LockedMode) {
|
|
||||||
m_locked = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mode == DatabaseWidget::ViewMode) {
|
|
||||||
if (m_ui->stackedWidget->currentIndex() == GroupPreview) {
|
|
||||||
getSelectedGroup(m_currentGroup);
|
|
||||||
} else {
|
|
||||||
getSelectedEntry(m_currentEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DetailsWidget::updateTabIndex(int index)
|
|
||||||
{
|
|
||||||
if (m_ui->stackedWidget->currentIndex() == GroupPreview) {
|
|
||||||
m_selectedTabGroup = index;
|
|
||||||
} else {
|
|
||||||
m_selectedTabEntry = index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
#define KEEPASSX_DETAILSWIDGET_H
|
#define KEEPASSX_DETAILSWIDGET_H
|
||||||
|
|
||||||
#include "gui/DatabaseWidget.h"
|
#include "gui/DatabaseWidget.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class DetailsWidget;
|
class DetailsWidget;
|
||||||
@ -34,48 +34,47 @@ public:
|
|||||||
explicit DetailsWidget(QWidget* parent = nullptr);
|
explicit DetailsWidget(QWidget* parent = nullptr);
|
||||||
~DetailsWidget();
|
~DetailsWidget();
|
||||||
|
|
||||||
enum StackedWidgetIndex
|
public slots:
|
||||||
{
|
void setEntry(Entry* selectedEntry);
|
||||||
EntryPreview = 0,
|
void setGroup(Group* selectedGroup);
|
||||||
GroupPreview = 1,
|
void setDatabaseMode(DatabaseWidget::Mode mode);
|
||||||
};
|
|
||||||
|
|
||||||
enum TabWidgetIndex
|
|
||||||
{
|
|
||||||
GeneralTab = 0,
|
|
||||||
AttributesTab = 1,
|
|
||||||
GroupNotesTab = 1,
|
|
||||||
AttachmentsTab = 2,
|
|
||||||
NotesTab = 3,
|
|
||||||
AutotypeTab = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccurred(const QString& error);
|
void errorOccurred(const QString& error);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void getSelectedEntry(Entry* selectedEntry);
|
void updateEntryHeaderLine();
|
||||||
void getSelectedGroup(Group* selectedGroup);
|
void updateEntryTotp();
|
||||||
void showTotp(bool visible);
|
void updateEntryGeneralTab();
|
||||||
void updateTotp();
|
void updateEntryNotesTab();
|
||||||
void hideDetails();
|
void updateEntryAttributesTab();
|
||||||
void setDatabaseMode(DatabaseWidget::Mode mode);
|
void updateEntryAttachmentsTab();
|
||||||
void updateTabIndex(int index);
|
void updateEntryAutotypeTab();
|
||||||
|
|
||||||
|
void updateGroupHeaderLine();
|
||||||
|
void updateGroupGeneralTab();
|
||||||
|
void updateGroupNotesTab();
|
||||||
|
|
||||||
|
void stopTotpTimer();
|
||||||
|
void deleteTotpTimer();
|
||||||
|
void updateTotpLabel();
|
||||||
|
void updateTabIndexes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setTabEnabled(QTabWidget *tabWidget, QWidget* widget, bool enabled);
|
||||||
|
static QPixmap preparePixmap(const QPixmap& pixmap, int size);
|
||||||
|
static QString shortUrl(const QString& url);
|
||||||
|
static QString shortPassword(const QString& password);
|
||||||
|
static QString hierarchy(const Group* group, const QString& title);
|
||||||
|
|
||||||
const QScopedPointer<Ui::DetailsWidget> m_ui;
|
const QScopedPointer<Ui::DetailsWidget> m_ui;
|
||||||
bool m_locked;
|
bool m_locked;
|
||||||
Entry* m_currentEntry;
|
Entry* m_currentEntry;
|
||||||
Group* m_currentGroup;
|
Group* m_currentGroup;
|
||||||
quint8 m_step;
|
quint8 m_step;
|
||||||
QPointer<QTimer> m_timer = nullptr;
|
QPointer<QTimer> m_totpTimer;
|
||||||
QWidget* m_attributesTabWidget;
|
|
||||||
QWidget* m_attachmentsTabWidget;
|
|
||||||
QWidget* m_autotypeTabWidget;
|
|
||||||
quint8 m_selectedTabEntry;
|
quint8 m_selectedTabEntry;
|
||||||
quint8 m_selectedTabGroup;
|
quint8 m_selectedTabGroup;
|
||||||
QString shortUrl(QString url);
|
|
||||||
QString shortPassword(QString password);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_DETAILSWIDGET_H
|
#endif // KEEPASSX_DETAILSWIDGET_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user