mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-14 00:39:53 -05:00
Merge pull request #879 from keepassxreboot/feature/preview-panel
Add preview panel for entries and groups, closes #454 and #558
This commit is contained in:
commit
3b9ffa194d
1
COPYING
1
COPYING
@ -156,6 +156,7 @@ License: LGPL-2.1
|
|||||||
Comment: based on Nuvola icon theme
|
Comment: based on Nuvola icon theme
|
||||||
|
|
||||||
Files: share/icons/application/*/actions/application-exit.png
|
Files: share/icons/application/*/actions/application-exit.png
|
||||||
|
share/icons/application/*/actions/chronometer.png
|
||||||
share/icons/application/*/actions/configure.png
|
share/icons/application/*/actions/configure.png
|
||||||
share/icons/application/*/actions/dialog-close.png
|
share/icons/application/*/actions/dialog-close.png
|
||||||
share/icons/application/*/actions/dialog-ok.png
|
share/icons/application/*/actions/dialog-ok.png
|
||||||
|
BIN
share/icons/application/22x22/actions/chronometer.png
Normal file
BIN
share/icons/application/22x22/actions/chronometer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
@ -98,6 +98,7 @@ set(keepassx_SOURCES
|
|||||||
gui/DatabaseTabWidget.cpp
|
gui/DatabaseTabWidget.cpp
|
||||||
gui/DatabaseWidget.cpp
|
gui/DatabaseWidget.cpp
|
||||||
gui/DatabaseWidgetStateSync.cpp
|
gui/DatabaseWidgetStateSync.cpp
|
||||||
|
gui/DetailsWidget.cpp
|
||||||
gui/DialogyWidget.cpp
|
gui/DialogyWidget.cpp
|
||||||
gui/DragTabBar.cpp
|
gui/DragTabBar.cpp
|
||||||
gui/EditWidget.cpp
|
gui/EditWidget.cpp
|
||||||
|
@ -131,6 +131,7 @@ void Config::init(const QString& fileName)
|
|||||||
m_defaults.insert("security/lockdatabasescreenlock", true);
|
m_defaults.insert("security/lockdatabasescreenlock", true);
|
||||||
m_defaults.insert("security/passwordsrepeat", false);
|
m_defaults.insert("security/passwordsrepeat", false);
|
||||||
m_defaults.insert("security/passwordscleartext", false);
|
m_defaults.insert("security/passwordscleartext", false);
|
||||||
|
m_defaults.insert("security/hidepassworddetails", true);
|
||||||
m_defaults.insert("security/autotypeask", true);
|
m_defaults.insert("security/autotypeask", true);
|
||||||
m_defaults.insert("security/IconDownloadFallbackToGoogle", false);
|
m_defaults.insert("security/IconDownloadFallbackToGoogle", false);
|
||||||
m_defaults.insert("GUI/Language", "system");
|
m_defaults.insert("GUI/Language", "system");
|
||||||
|
@ -243,7 +243,15 @@ QString Entry::url() const
|
|||||||
|
|
||||||
QString Entry::webUrl() const
|
QString Entry::webUrl() const
|
||||||
{
|
{
|
||||||
return resolveUrl(m_attributes->value(EntryAttributes::URLKey));
|
QString url = resolveMultiplePlaceholders(m_attributes->value(EntryAttributes::URLKey));
|
||||||
|
return resolveUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Entry::displayUrl() const
|
||||||
|
{
|
||||||
|
QString url = maskPasswordPlaceholders(m_attributes->value(EntryAttributes::URLKey));
|
||||||
|
url = resolveMultiplePlaceholders(url);
|
||||||
|
return resolveUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Entry::username() const
|
QString Entry::username() const
|
||||||
|
@ -79,6 +79,7 @@ public:
|
|||||||
QString title() const;
|
QString title() const;
|
||||||
QString url() const;
|
QString url() const;
|
||||||
QString webUrl() const;
|
QString webUrl() const;
|
||||||
|
QString displayUrl() const;
|
||||||
QString username() const;
|
QString username() const;
|
||||||
QString password() const;
|
QString password() const;
|
||||||
QString notes() const;
|
QString notes() const;
|
||||||
|
@ -435,6 +435,23 @@ void Group::setParent(Database* db)
|
|||||||
QObject::setParent(db);
|
QObject::setParent(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList Group::hierarchy()
|
||||||
|
{
|
||||||
|
QStringList hierarchy;
|
||||||
|
Group* group = this;
|
||||||
|
Group* parent = m_parent;
|
||||||
|
hierarchy.prepend(group->name());
|
||||||
|
|
||||||
|
while (parent) {
|
||||||
|
group = group->parentGroup();
|
||||||
|
parent = group->parentGroup();
|
||||||
|
|
||||||
|
hierarchy.prepend(group->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
Database* Group::database()
|
Database* Group::database()
|
||||||
{
|
{
|
||||||
return m_db;
|
return m_db;
|
||||||
|
@ -106,6 +106,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();
|
||||||
|
|
||||||
Database* database();
|
Database* database();
|
||||||
const Database* database() const;
|
const Database* database() const;
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "gui/TotpDialog.h"
|
#include "gui/TotpDialog.h"
|
||||||
#include "gui/DatabaseOpenWidget.h"
|
#include "gui/DatabaseOpenWidget.h"
|
||||||
#include "gui/DatabaseSettingsWidget.h"
|
#include "gui/DatabaseSettingsWidget.h"
|
||||||
|
#include "gui/DetailsWidget.h"
|
||||||
#include "gui/KeePass1OpenWidget.h"
|
#include "gui/KeePass1OpenWidget.h"
|
||||||
#include "gui/MessageBox.h"
|
#include "gui/MessageBox.h"
|
||||||
#include "gui/UnlockDatabaseWidget.h"
|
#include "gui/UnlockDatabaseWidget.h"
|
||||||
@ -74,6 +75,9 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
|||||||
mainLayout->addLayout(layout);
|
mainLayout->addLayout(layout);
|
||||||
m_splitter = new QSplitter(m_mainWidget);
|
m_splitter = new QSplitter(m_mainWidget);
|
||||||
m_splitter->setChildrenCollapsible(false);
|
m_splitter->setChildrenCollapsible(false);
|
||||||
|
m_detailSplitter = new QSplitter(m_mainWidget);
|
||||||
|
m_detailSplitter->setOrientation(Qt::Vertical);
|
||||||
|
m_detailSplitter->setChildrenCollapsible(true);
|
||||||
|
|
||||||
QWidget* rightHandSideWidget = new QWidget(m_splitter);
|
QWidget* rightHandSideWidget = new QWidget(m_splitter);
|
||||||
|
|
||||||
@ -99,10 +103,18 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
|||||||
"border: 2px solid rgb(190, 190, 190);"
|
"border: 2px solid rgb(190, 190, 190);"
|
||||||
"border-radius: 5px;");
|
"border-radius: 5px;");
|
||||||
|
|
||||||
|
m_detailsView = new DetailsWidget(this);
|
||||||
|
|
||||||
QVBoxLayout* vLayout = new QVBoxLayout(rightHandSideWidget);
|
QVBoxLayout* vLayout = new QVBoxLayout(rightHandSideWidget);
|
||||||
vLayout->setMargin(0);
|
vLayout->setMargin(0);
|
||||||
vLayout->addWidget(m_searchingLabel);
|
vLayout->addWidget(m_searchingLabel);
|
||||||
vLayout->addWidget(m_entryView);
|
vLayout->addWidget(m_detailSplitter);
|
||||||
|
|
||||||
|
m_detailSplitter->addWidget(m_entryView);
|
||||||
|
m_detailSplitter->addWidget(m_detailsView);
|
||||||
|
|
||||||
|
m_detailSplitter->setStretchFactor(0, 80);
|
||||||
|
m_detailSplitter->setStretchFactor(1, 20);
|
||||||
|
|
||||||
m_searchingLabel->setVisible(false);
|
m_searchingLabel->setVisible(false);
|
||||||
|
|
||||||
@ -180,6 +192,12 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
|||||||
connect(&m_fileWatchUnblockTimer, SIGNAL(timeout()), this, SLOT(unblockAutoReload()));
|
connect(&m_fileWatchUnblockTimer, SIGNAL(timeout()), this, SLOT(unblockAutoReload()));
|
||||||
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
|
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
|
||||||
|
|
||||||
|
connect(m_groupView, SIGNAL(groupPressed(Group*)), SLOT(emitPressedGroup(Group*)));
|
||||||
|
connect(m_groupView, SIGNAL(groupChanged(Group*)), SLOT(emitPressedGroup(Group*)));
|
||||||
|
connect(m_entryView, SIGNAL(entryPressed(Entry*)), SLOT(emitPressedEntry(Entry*)));
|
||||||
|
connect(m_entryView, SIGNAL(entrySelectionChanged()), SLOT(emitPressedEntry()));
|
||||||
|
connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(emitPressedEntry()));
|
||||||
|
|
||||||
m_databaseModified = false;
|
m_databaseModified = false;
|
||||||
|
|
||||||
m_fileWatchTimer.setSingleShot(true);
|
m_fileWatchTimer.setSingleShot(true);
|
||||||
@ -1041,6 +1059,32 @@ void DatabaseWidget::emitEntryContextMenuRequested(const QPoint& pos)
|
|||||||
emit entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
|
emit entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseWidget::emitPressedEntry()
|
||||||
|
{
|
||||||
|
Entry* currentEntry = m_entryView->currentEntry();
|
||||||
|
emitPressedEntry(currentEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseWidget::emitPressedEntry(Entry* currentEntry)
|
||||||
|
{
|
||||||
|
if (!currentEntry) {
|
||||||
|
// if no entry is pressed, leave in details the last entry
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit pressedEntry(currentEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseWidget::emitPressedGroup(Group* currentGroup)
|
||||||
|
{
|
||||||
|
if (!currentGroup) {
|
||||||
|
// if no group is pressed, leave in details the last group
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit pressedGroup(currentGroup);
|
||||||
|
}
|
||||||
|
|
||||||
bool DatabaseWidget::dbHasKey() const
|
bool DatabaseWidget::dbHasKey() const
|
||||||
{
|
{
|
||||||
return m_db->hasKey();
|
return m_db->hasKey();
|
||||||
|
@ -47,6 +47,7 @@ class QSplitter;
|
|||||||
class QLabel;
|
class QLabel;
|
||||||
class UnlockDatabaseWidget;
|
class UnlockDatabaseWidget;
|
||||||
class MessageWidget;
|
class MessageWidget;
|
||||||
|
class DetailsWidget;
|
||||||
class UnlockDatabaseDialog;
|
class UnlockDatabaseDialog;
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
|
|
||||||
@ -115,6 +116,8 @@ signals:
|
|||||||
void databaseMerged(Database* mergedDb);
|
void databaseMerged(Database* mergedDb);
|
||||||
void groupContextMenuRequested(const QPoint& globalPos);
|
void groupContextMenuRequested(const QPoint& globalPos);
|
||||||
void entryContextMenuRequested(const QPoint& globalPos);
|
void entryContextMenuRequested(const QPoint& globalPos);
|
||||||
|
void pressedEntry(Entry* selectedEntry);
|
||||||
|
void pressedGroup(Group* selectedGroup);
|
||||||
void unlockedDatabase();
|
void unlockedDatabase();
|
||||||
void listModeAboutToActivate();
|
void listModeAboutToActivate();
|
||||||
void listModeActivated();
|
void listModeActivated();
|
||||||
@ -179,6 +182,9 @@ private slots:
|
|||||||
void switchToGroupEdit(Group* entry, bool create);
|
void switchToGroupEdit(Group* entry, bool create);
|
||||||
void emitGroupContextMenuRequested(const QPoint& pos);
|
void emitGroupContextMenuRequested(const QPoint& pos);
|
||||||
void emitEntryContextMenuRequested(const QPoint& pos);
|
void emitEntryContextMenuRequested(const QPoint& pos);
|
||||||
|
void emitPressedEntry();
|
||||||
|
void emitPressedEntry(Entry* currentEntry);
|
||||||
|
void emitPressedGroup(Group* currentGroup);
|
||||||
void updateMasterKey(bool accepted);
|
void updateMasterKey(bool accepted);
|
||||||
void openDatabase(bool accepted);
|
void openDatabase(bool accepted);
|
||||||
void mergeDatabase(bool accepted);
|
void mergeDatabase(bool accepted);
|
||||||
@ -209,6 +215,7 @@ private:
|
|||||||
UnlockDatabaseWidget* m_unlockDatabaseWidget;
|
UnlockDatabaseWidget* m_unlockDatabaseWidget;
|
||||||
UnlockDatabaseDialog* m_unlockDatabaseDialog;
|
UnlockDatabaseDialog* m_unlockDatabaseDialog;
|
||||||
QSplitter* m_splitter;
|
QSplitter* m_splitter;
|
||||||
|
QSplitter* m_detailSplitter;
|
||||||
GroupView* m_groupView;
|
GroupView* m_groupView;
|
||||||
EntryView* m_entryView;
|
EntryView* m_entryView;
|
||||||
QLabel* m_searchingLabel;
|
QLabel* m_searchingLabel;
|
||||||
@ -219,6 +226,7 @@ private:
|
|||||||
Uuid m_groupBeforeLock;
|
Uuid m_groupBeforeLock;
|
||||||
Uuid m_entryBeforeLock;
|
Uuid m_entryBeforeLock;
|
||||||
MessageWidget* m_messageWidget;
|
MessageWidget* m_messageWidget;
|
||||||
|
DetailsWidget* m_detailsView;
|
||||||
|
|
||||||
// Search state
|
// Search state
|
||||||
QString m_lastSearchText;
|
QString m_lastSearchText;
|
||||||
|
325
src/gui/DetailsWidget.cpp
Normal file
325
src/gui/DetailsWidget.cpp
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
|
||||||
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program 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 2 or (at your option)
|
||||||
|
* version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DetailsWidget.h"
|
||||||
|
#include "ui_DetailsWidget.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "core/Config.h"
|
||||||
|
#include "core/FilePath.h"
|
||||||
|
#include "core/TimeInfo.h"
|
||||||
|
#include "gui/Clipboard.h"
|
||||||
|
#include "gui/DatabaseWidget.h"
|
||||||
|
|
||||||
|
DetailsWidget::DetailsWidget(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_ui(new Ui::DetailsWidget())
|
||||||
|
, m_locked(false)
|
||||||
|
, m_currentEntry(nullptr)
|
||||||
|
, m_currentGroup(nullptr)
|
||||||
|
, m_attributesWidget(nullptr)
|
||||||
|
, m_autotypeWidget(nullptr)
|
||||||
|
, m_selectedTabEntry(0)
|
||||||
|
, m_selectedTabGroup(0)
|
||||||
|
{
|
||||||
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
|
connect(parent, SIGNAL(pressedEntry(Entry*)), SLOT(getSelectedEntry(Entry*)));
|
||||||
|
connect(parent, SIGNAL(pressedGroup(Group*)), SLOT(getSelectedGroup(Group*)));
|
||||||
|
connect(parent, SIGNAL(currentModeChanged(DatabaseWidget::Mode)), SLOT(setDatabaseMode(DatabaseWidget::Mode)));
|
||||||
|
|
||||||
|
m_ui->totpButton->setIcon(filePath()->icon("actions", "chronometer"));
|
||||||
|
m_ui->closeButton->setIcon(filePath()->icon("actions", "dialog-close"));
|
||||||
|
|
||||||
|
connect(m_ui->totpButton, SIGNAL(toggled(bool)), SLOT(showTotp(bool)));
|
||||||
|
connect(m_ui->closeButton, SIGNAL(toggled(bool)), SLOT(hideDetails()));
|
||||||
|
connect(m_ui->tabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndex(int)));
|
||||||
|
|
||||||
|
this->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
DetailsWidget::~DetailsWidget()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::getSelectedEntry(Entry* selectedEntry)
|
||||||
|
{
|
||||||
|
m_currentEntry = selectedEntry;
|
||||||
|
|
||||||
|
if (!config()->get("GUI/HideDetailsView").toBool()) {
|
||||||
|
this->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->stackedWidget->setCurrentIndex(EntryPreview);
|
||||||
|
|
||||||
|
if (m_ui->tabWidget->count() < 4) {
|
||||||
|
m_ui->tabWidget->insertTab(static_cast<int>(AttributesTab), m_attributesWidget, "Attributes");
|
||||||
|
m_ui->tabWidget->insertTab(static_cast<int>(AutotypeTab), m_autotypeWidget, "Autotype");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->tabWidget->setTabEnabled(AttributesTab, false);
|
||||||
|
m_ui->tabWidget->setTabEnabled(NotesTab, false);
|
||||||
|
m_ui->tabWidget->setTabEnabled(AutotypeTab, false);
|
||||||
|
|
||||||
|
m_ui->totpButton->hide();
|
||||||
|
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()));
|
||||||
|
|
||||||
|
if (!config()->get("security/hidepassworddetails").toBool()) {
|
||||||
|
m_ui->passwordLabel->setText(shortPassword(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password())));
|
||||||
|
m_ui->passwordLabel->setToolTip(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password()));
|
||||||
|
} else {
|
||||||
|
m_ui->passwordLabel->setText("****");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString url = m_currentEntry->webUrl();
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
// URL is well formed and can be opened in a browser
|
||||||
|
// create a new display url that masks password placeholders
|
||||||
|
// the actual link will use the password
|
||||||
|
url = QString("<a href=\"%1\">%2</a>").arg(url).arg(shortUrl(m_currentEntry->displayUrl()));
|
||||||
|
m_ui->urlLabel->setOpenExternalLinks(true);
|
||||||
|
} else {
|
||||||
|
// Fallback to the raw url string
|
||||||
|
url = shortUrl(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->url()));
|
||||||
|
m_ui->urlLabel->setOpenExternalLinks(false);
|
||||||
|
}
|
||||||
|
m_ui->urlLabel->setText(url);
|
||||||
|
|
||||||
|
TimeInfo entryTime = m_currentEntry->timeInfo();
|
||||||
|
if (entryTime.expires()) {
|
||||||
|
m_ui->expirationLabel->setText(entryTime.expiryTime().toString(Qt::DefaultLocaleShortDate));
|
||||||
|
} else {
|
||||||
|
m_ui->expirationLabel->setText(tr("Never"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentEntry->hasTotp()) {
|
||||||
|
m_ui->totpButton->show();
|
||||||
|
updateTotp();
|
||||||
|
|
||||||
|
m_step = m_currentEntry->totpStep();
|
||||||
|
|
||||||
|
m_timer = new QTimer(this);
|
||||||
|
connect(m_timer, SIGNAL(timeout()), this, SLOT(updateTotp()));
|
||||||
|
m_timer->start(m_step * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
QString value = m_currentEntry->attributes()->value(key);
|
||||||
|
if (m_currentEntry->attributes()->isProtected(key)) {
|
||||||
|
value = "<i>" + tr("[PROTECTED]") + "</i>";
|
||||||
|
}
|
||||||
|
attributesText.append(QString("<b>%1</b>: %2<br/>").arg(key, value));
|
||||||
|
}
|
||||||
|
m_ui->attributesEdit->setText(attributesText);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->autotypeTree->clear();
|
||||||
|
AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations();
|
||||||
|
QList<QTreeWidgetItem*> items;
|
||||||
|
for (auto assoc : autotypeAssociations->getAll()) {
|
||||||
|
QStringList association = QStringList() << assoc.window << assoc.sequence;
|
||||||
|
if (association.at(1).isEmpty()) {
|
||||||
|
association.replace(1, m_currentEntry->effectiveAutoTypeSequence());
|
||||||
|
}
|
||||||
|
items.append(new QTreeWidgetItem(m_ui->autotypeTree, association));
|
||||||
|
}
|
||||||
|
if (items.count() > 0) {
|
||||||
|
m_ui->autotypeTree->addTopLevelItems(items);
|
||||||
|
m_ui->tabWidget->setTabEnabled(AutotypeTab, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ui->tabWidget->isTabEnabled(m_selectedTabEntry)) {
|
||||||
|
m_ui->tabWidget->setCurrentIndex(m_selectedTabEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::getSelectedGroup(Group* selectedGroup)
|
||||||
|
{
|
||||||
|
m_currentGroup = selectedGroup;
|
||||||
|
|
||||||
|
if (!config()->get("GUI/HideDetailsView").toBool()) {
|
||||||
|
this->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->stackedWidget->setCurrentIndex(GroupPreview);
|
||||||
|
|
||||||
|
if (m_ui->tabWidget->count() > 2) {
|
||||||
|
m_autotypeWidget = m_ui->tabWidget->widget(AutotypeTab);
|
||||||
|
m_attributesWidget = m_ui->tabWidget->widget(AttributesTab);
|
||||||
|
m_ui->tabWidget->removeTab(AutotypeTab);
|
||||||
|
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 {
|
||||||
|
m_ui->groupExpirationLabel->setText(tr("Never"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ui->tabWidget->isTabEnabled(m_selectedTabGroup)) {
|
||||||
|
m_ui->tabWidget->setCurrentIndex(m_selectedTabGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::updateTotp()
|
||||||
|
{
|
||||||
|
if (m_locked) {
|
||||||
|
m_timer->stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString totpCode = m_currentEntry->totp();
|
||||||
|
QString firstHalf = totpCode.left(totpCode.size()/2);
|
||||||
|
QString secondHalf = totpCode.right(totpCode.size()/2);
|
||||||
|
m_ui->totpLabel->setText(firstHalf + " " + secondHalf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::showTotp(bool visible)
|
||||||
|
{
|
||||||
|
if (visible){
|
||||||
|
m_ui->totpWidget->show();
|
||||||
|
} else {
|
||||||
|
m_ui->totpWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DetailsWidget::shortUrl(QString url)
|
||||||
|
{
|
||||||
|
QString newurl = "";
|
||||||
|
if (url.length() > 60) {
|
||||||
|
newurl.append(url.left(20));
|
||||||
|
newurl.append("…");
|
||||||
|
newurl.append(url.right(20));
|
||||||
|
return newurl;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DetailsWidget::shortPassword(QString password)
|
||||||
|
{
|
||||||
|
QString newpassword = "";
|
||||||
|
if (password.length() > 60) {
|
||||||
|
newpassword.append(password.left(50));
|
||||||
|
newpassword.append("…");
|
||||||
|
return newpassword;
|
||||||
|
}
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::hideDetails()
|
||||||
|
{
|
||||||
|
this->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetailsWidget::setDatabaseMode(DatabaseWidget::Mode mode)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
76
src/gui/DetailsWidget.h
Normal file
76
src/gui/DetailsWidget.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program 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 2 or (at your option)
|
||||||
|
* version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEEPASSX_DETAILSWIDGET_H
|
||||||
|
#define KEEPASSX_DETAILSWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "gui/DatabaseWidget.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class DetailsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DetailsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DetailsWidget(QWidget* parent = nullptr);
|
||||||
|
~DetailsWidget();
|
||||||
|
|
||||||
|
enum StackedWidgetIndex
|
||||||
|
{
|
||||||
|
EntryPreview = 0,
|
||||||
|
GroupPreview = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TabWidgetIndex
|
||||||
|
{
|
||||||
|
GeneralTab = 0,
|
||||||
|
AttributesTab = 1,
|
||||||
|
GroupNotesTab = 1,
|
||||||
|
NotesTab = 2,
|
||||||
|
AutotypeTab = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void getSelectedEntry(Entry* selectedEntry);
|
||||||
|
void getSelectedGroup(Group* selectedGroup);
|
||||||
|
void showTotp(bool visible);
|
||||||
|
void updateTotp();
|
||||||
|
void hideDetails();
|
||||||
|
void setDatabaseMode(DatabaseWidget::Mode mode);
|
||||||
|
void updateTabIndex(int index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QScopedPointer<Ui::DetailsWidget> m_ui;
|
||||||
|
bool m_locked;
|
||||||
|
Entry* m_currentEntry;
|
||||||
|
Group* m_currentGroup;
|
||||||
|
quint8 m_step;
|
||||||
|
QTimer* m_timer;
|
||||||
|
QWidget* m_attributesWidget;
|
||||||
|
QWidget* m_autotypeWidget;
|
||||||
|
quint8 m_selectedTabEntry;
|
||||||
|
quint8 m_selectedTabGroup;
|
||||||
|
QString shortUrl(QString url);
|
||||||
|
QString shortPassword(QString password);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSX_DETAILSWIDGET_H
|
567
src/gui/DetailsWidget.ui
Normal file
567
src/gui/DetailsWidget.ui
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DetailsWidget</class>
|
||||||
|
<widget class="QWidget" name="DetailsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>630</width>
|
||||||
|
<height>200</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>200</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0,0">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="entryIcon">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="titleLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::AutoText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="totpWidget" native="true">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="totpLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="totpButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Generate TOTP Token</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="closeButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Generate TOTP Token</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="documentMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabsClosable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="generalTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="entryPage">
|
||||||
|
<layout class="QGridLayout" name="gridLayout" columnstretch="1,3">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="passwordLabel"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="urlLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="cursor">
|
||||||
|
<cursorShape>PointingHandCursor</cursorShape>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="expirationLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Expiration</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="urlLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>URL</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="expirationLabel"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="passwordLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Password</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="usernameLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Username</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="usernameLabel">
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="groupPage">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,3">
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="groupExpirationLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="autotypeLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Autotype</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="searchingLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="searchingLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Searching</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="autotypeLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="groupExpirationLabel_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Expiration</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="attributesTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Attributes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QTextEdit" name="attributesEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="notesTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Notes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QTextEdit" name="notesEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="autotypeTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Autotype</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QTreeWidget" name="autotypeTree">
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Sunken</enum>
|
||||||
|
</property>
|
||||||
|
<property name="showDropIndicator" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="rootIsDecorated">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerCascadingSectionResizes">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerDefaultSectionSize">
|
||||||
|
<number>250</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerMinimumSectionSize">
|
||||||
|
<number>50</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Window</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Sequence</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<action name="searchIcon">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="clearIcon">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -134,6 +134,7 @@ void SettingsWidget::loadSettings()
|
|||||||
m_generalUi->languageComboBox->setCurrentIndex(defaultIndex);
|
m_generalUi->languageComboBox->setCurrentIndex(defaultIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_generalUi->detailsHideCheckBox->setChecked(config()->get("GUI/HideDetailsView").toBool());
|
||||||
m_generalUi->systrayShowCheckBox->setChecked(config()->get("GUI/ShowTrayIcon").toBool());
|
m_generalUi->systrayShowCheckBox->setChecked(config()->get("GUI/ShowTrayIcon").toBool());
|
||||||
m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get("GUI/MinimizeToTray").toBool());
|
m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get("GUI/MinimizeToTray").toBool());
|
||||||
m_generalUi->systrayMinimizeOnCloseCheckBox->setChecked(config()->get("GUI/MinimizeOnClose").toBool());
|
m_generalUi->systrayMinimizeOnCloseCheckBox->setChecked(config()->get("GUI/MinimizeOnClose").toBool());
|
||||||
@ -160,6 +161,7 @@ void SettingsWidget::loadSettings()
|
|||||||
m_secUi->fallbackToGoogle->setChecked(config()->get("security/IconDownloadFallbackToGoogle").toBool());
|
m_secUi->fallbackToGoogle->setChecked(config()->get("security/IconDownloadFallbackToGoogle").toBool());
|
||||||
|
|
||||||
m_secUi->passwordCleartextCheckBox->setChecked(config()->get("security/passwordscleartext").toBool());
|
m_secUi->passwordCleartextCheckBox->setChecked(config()->get("security/passwordscleartext").toBool());
|
||||||
|
m_secUi->passwordDetailsCleartextCheckBox->setChecked(config()->get("security/hidepassworddetails").toBool());
|
||||||
m_secUi->passwordRepeatCheckBox->setChecked(config()->get("security/passwordsrepeat").toBool());
|
m_secUi->passwordRepeatCheckBox->setChecked(config()->get("security/passwordsrepeat").toBool());
|
||||||
|
|
||||||
|
|
||||||
@ -203,6 +205,7 @@ void SettingsWidget::saveSettings()
|
|||||||
|
|
||||||
config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString());
|
config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString());
|
||||||
|
|
||||||
|
config()->set("GUI/HideDetailsView", m_generalUi->detailsHideCheckBox->isChecked());
|
||||||
config()->set("GUI/ShowTrayIcon", m_generalUi->systrayShowCheckBox->isChecked());
|
config()->set("GUI/ShowTrayIcon", m_generalUi->systrayShowCheckBox->isChecked());
|
||||||
config()->set("GUI/MinimizeToTray", m_generalUi->systrayMinimizeToTrayCheckBox->isChecked());
|
config()->set("GUI/MinimizeToTray", m_generalUi->systrayMinimizeToTrayCheckBox->isChecked());
|
||||||
config()->set("GUI/MinimizeOnClose", m_generalUi->systrayMinimizeOnCloseCheckBox->isChecked());
|
config()->set("GUI/MinimizeOnClose", m_generalUi->systrayMinimizeOnCloseCheckBox->isChecked());
|
||||||
@ -226,6 +229,7 @@ void SettingsWidget::saveSettings()
|
|||||||
config()->set("security/IconDownloadFallbackToGoogle", m_secUi->fallbackToGoogle->isChecked());
|
config()->set("security/IconDownloadFallbackToGoogle", m_secUi->fallbackToGoogle->isChecked());
|
||||||
|
|
||||||
config()->set("security/passwordscleartext", m_secUi->passwordCleartextCheckBox->isChecked());
|
config()->set("security/passwordscleartext", m_secUi->passwordCleartextCheckBox->isChecked());
|
||||||
|
config()->set("security/hidepassworddetails", m_secUi->passwordDetailsCleartextCheckBox->isChecked());
|
||||||
config()->set("security/passwordsrepeat", m_secUi->passwordRepeatCheckBox->isChecked());
|
config()->set("security/passwordsrepeat", m_secUi->passwordRepeatCheckBox->isChecked());
|
||||||
|
|
||||||
// Security: clear storage if related settings are disabled
|
// Security: clear storage if related settings are disabled
|
||||||
|
@ -153,6 +153,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="detailsHideCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hide the Details view</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="systrayShowCheckBox">
|
<widget class="QCheckBox" name="systrayShowCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -136,6 +136,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="passwordDetailsCleartextCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hide passwords in the preview panel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -632,7 +632,7 @@ void EditEntryWidget::displayAttribute(QModelIndex index, bool showProtected)
|
|||||||
if (index.isValid()) {
|
if (index.isValid()) {
|
||||||
QString key = m_attributesModel->keyByIndex(index);
|
QString key = m_attributesModel->keyByIndex(index);
|
||||||
if (showProtected) {
|
if (showProtected) {
|
||||||
m_advancedUi->attributesEdit->setPlainText(tr("[PROTECTED] Press reveal to view or edit"));
|
m_advancedUi->attributesEdit->setPlainText(tr("[PROTECTED]") + " " + tr("Press reveal to view or edit"));
|
||||||
m_advancedUi->attributesEdit->setEnabled(false);
|
m_advancedUi->attributesEdit->setEnabled(false);
|
||||||
m_advancedUi->revealAttributeButton->setEnabled(true);
|
m_advancedUi->revealAttributeButton->setEnabled(true);
|
||||||
m_advancedUi->protectAttributeButton->setChecked(true);
|
m_advancedUi->protectAttributeButton->setChecked(true);
|
||||||
|
@ -151,8 +151,7 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
case Url:
|
case Url:
|
||||||
result = entry->maskPasswordPlaceholders(entry->url());
|
result = entry->displayUrl();
|
||||||
result = entry->resolveMultiplePlaceholders(result);
|
|
||||||
if (attr->isReference(EntryAttributes::URLKey)) {
|
if (attr->isReference(EntryAttributes::URLKey)) {
|
||||||
result.prepend(tr("Ref: ","Reference abbreviation"));
|
result.prepend(tr("Ref: ","Reference abbreviation"));
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ EntryView::EntryView(QWidget* parent)
|
|||||||
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
|
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
|
||||||
connect(m_model, SIGNAL(switchedToEntryListMode()), SLOT(switchToEntryListMode()));
|
connect(m_model, SIGNAL(switchedToEntryListMode()), SLOT(switchToEntryListMode()));
|
||||||
connect(m_model, SIGNAL(switchedToGroupMode()), SLOT(switchToGroupMode()));
|
connect(m_model, SIGNAL(switchedToGroupMode()), SLOT(switchToGroupMode()));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(clicked(QModelIndex)), SLOT(emitEntryPressed(QModelIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryView::keyPressEvent(QKeyEvent* event)
|
void EntryView::keyPressEvent(QKeyEvent* event)
|
||||||
@ -99,6 +101,11 @@ void EntryView::emitEntryActivated(const QModelIndex& index)
|
|||||||
emit entryActivated(entry, static_cast<EntryModel::ModelColumn>(m_sortModel->mapToSource(index).column()));
|
emit entryActivated(entry, static_cast<EntryModel::ModelColumn>(m_sortModel->mapToSource(index).column()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntryView::emitEntryPressed(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
emit entryPressed(entryFromIndex(index));
|
||||||
|
}
|
||||||
|
|
||||||
void EntryView::setModel(QAbstractItemModel* model)
|
void EntryView::setModel(QAbstractItemModel* model)
|
||||||
{
|
{
|
||||||
Q_UNUSED(model);
|
Q_UNUSED(model);
|
||||||
|
@ -47,6 +47,7 @@ public slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void entryActivated(Entry* entry, EntryModel::ModelColumn column);
|
void entryActivated(Entry* entry, EntryModel::ModelColumn column);
|
||||||
|
void entryPressed(Entry* entry);
|
||||||
void entrySelectionChanged();
|
void entrySelectionChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -54,6 +55,7 @@ protected:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void emitEntryActivated(const QModelIndex& index);
|
void emitEntryActivated(const QModelIndex& index);
|
||||||
|
void emitEntryPressed(const QModelIndex& index);
|
||||||
void switchToEntryListMode();
|
void switchToEntryListMode();
|
||||||
void switchToGroupMode();
|
void switchToGroupMode();
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ GroupView::GroupView(Database* db, QWidget* parent)
|
|||||||
|
|
||||||
connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(emitGroupChanged()));
|
connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(emitGroupChanged()));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(clicked(QModelIndex)), SLOT(emitGroupPressed(QModelIndex)));
|
||||||
|
|
||||||
modelReset();
|
modelReset();
|
||||||
|
|
||||||
setDragEnabled(true);
|
setDragEnabled(true);
|
||||||
@ -126,6 +128,11 @@ void GroupView::emitGroupChanged()
|
|||||||
emit groupChanged(currentGroup());
|
emit groupChanged(currentGroup());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GroupView::emitGroupPressed(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
emit groupPressed(m_model->groupFromIndex(index));
|
||||||
|
}
|
||||||
|
|
||||||
void GroupView::syncExpandedState(const QModelIndex& parent, int start, int end)
|
void GroupView::syncExpandedState(const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
for (int row = start; row <= end; row++) {
|
for (int row = start; row <= end; row++) {
|
||||||
|
@ -38,11 +38,13 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void groupChanged(Group* group);
|
void groupChanged(Group* group);
|
||||||
|
void groupPressed(Group* group);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void expandedChanged(const QModelIndex& index);
|
void expandedChanged(const QModelIndex& index);
|
||||||
void emitGroupChanged(const QModelIndex& index);
|
void emitGroupChanged(const QModelIndex& index);
|
||||||
void emitGroupChanged();
|
void emitGroupChanged();
|
||||||
|
void emitGroupPressed(const QModelIndex& index);
|
||||||
void syncExpandedState(const QModelIndex& parent, int start, int end);
|
void syncExpandedState(const QModelIndex& parent, int start, int end);
|
||||||
void modelReset();
|
void modelReset();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user