mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-02-18 13:24:10 -05:00
Properly block modified signal during Database destruction (#6438)
fixes #6393
This commit is contained in:
parent
66c3026cf5
commit
81a66c439c
@ -52,6 +52,7 @@ set(keepassx_SOURCES
|
|||||||
core/InactivityTimer.cpp
|
core/InactivityTimer.cpp
|
||||||
core/Merger.cpp
|
core/Merger.cpp
|
||||||
core/Metadata.cpp
|
core/Metadata.cpp
|
||||||
|
core/ModifiableObject.cpp
|
||||||
core/PasswordGenerator.cpp
|
core/PasswordGenerator.cpp
|
||||||
core/PasswordHealth.cpp
|
core/PasswordHealth.cpp
|
||||||
core/PassphraseGenerator.cpp
|
core/PassphraseGenerator.cpp
|
||||||
|
@ -28,7 +28,7 @@ bool AutoTypeAssociations::Association::operator!=(const AutoTypeAssociations::A
|
|||||||
}
|
}
|
||||||
|
|
||||||
AutoTypeAssociations::AutoTypeAssociations(QObject* parent)
|
AutoTypeAssociations::AutoTypeAssociations(QObject* parent)
|
||||||
: QObject(parent)
|
: ModifiableObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ void AutoTypeAssociations::copyDataFrom(const AutoTypeAssociations* other)
|
|||||||
emit aboutToReset();
|
emit aboutToReset();
|
||||||
m_associations = other->m_associations;
|
m_associations = other->m_associations;
|
||||||
emit reset();
|
emit reset();
|
||||||
emit modified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoTypeAssociations::add(const AutoTypeAssociations::Association& association)
|
void AutoTypeAssociations::add(const AutoTypeAssociations::Association& association)
|
||||||
@ -50,7 +50,7 @@ void AutoTypeAssociations::add(const AutoTypeAssociations::Association& associat
|
|||||||
emit aboutToAdd(index);
|
emit aboutToAdd(index);
|
||||||
m_associations.append(association);
|
m_associations.append(association);
|
||||||
emit added(index);
|
emit added(index);
|
||||||
emit modified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoTypeAssociations::remove(int index)
|
void AutoTypeAssociations::remove(int index)
|
||||||
@ -60,7 +60,7 @@ void AutoTypeAssociations::remove(int index)
|
|||||||
emit aboutToRemove(index);
|
emit aboutToRemove(index);
|
||||||
m_associations.removeAt(index);
|
m_associations.removeAt(index);
|
||||||
emit removed(index);
|
emit removed(index);
|
||||||
emit modified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoTypeAssociations::removeEmpty()
|
void AutoTypeAssociations::removeEmpty()
|
||||||
@ -81,7 +81,7 @@ void AutoTypeAssociations::update(int index, const AutoTypeAssociations::Associa
|
|||||||
if (m_associations.at(index) != association) {
|
if (m_associations.at(index) != association) {
|
||||||
m_associations[index] = association;
|
m_associations[index] = association;
|
||||||
emit dataChanged(index);
|
emit dataChanged(index);
|
||||||
emit modified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
#ifndef KEEPASSX_AUTOTYPEASSOCIATIONS_H
|
#ifndef KEEPASSX_AUTOTYPEASSOCIATIONS_H
|
||||||
#define KEEPASSX_AUTOTYPEASSOCIATIONS_H
|
#define KEEPASSX_AUTOTYPEASSOCIATIONS_H
|
||||||
|
|
||||||
#include <QObject>
|
#include "core/ModifiableObject.h"
|
||||||
|
|
||||||
class AutoTypeAssociations : public QObject
|
class AutoTypeAssociations : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -53,7 +53,6 @@ private:
|
|||||||
QList<AutoTypeAssociations::Association> m_associations;
|
QList<AutoTypeAssociations::Association> m_associations;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void modified();
|
|
||||||
void dataChanged(int index);
|
void dataChanged(int index);
|
||||||
void aboutToAdd(int index);
|
void aboutToAdd(int index);
|
||||||
void added(int index);
|
void added(int index);
|
||||||
|
@ -27,7 +27,7 @@ const QString CustomData::BrowserLegacyKeyPrefix = QStringLiteral("Public Key: "
|
|||||||
const QString CustomData::ExcludeFromReports = QStringLiteral("KnownBad");
|
const QString CustomData::ExcludeFromReports = QStringLiteral("KnownBad");
|
||||||
|
|
||||||
CustomData::CustomData(QObject* parent)
|
CustomData::CustomData(QObject* parent)
|
||||||
: QObject(parent)
|
: ModifiableObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ void CustomData::set(const QString& key, const QString& value)
|
|||||||
if (addAttribute || changeValue) {
|
if (addAttribute || changeValue) {
|
||||||
m_data.insert(key, value);
|
m_data.insert(key, value);
|
||||||
updateLastModified();
|
updateLastModified();
|
||||||
emit customDataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addAttribute) {
|
if (addAttribute) {
|
||||||
@ -84,7 +84,7 @@ void CustomData::remove(const QString& key)
|
|||||||
|
|
||||||
updateLastModified();
|
updateLastModified();
|
||||||
emit removed(key);
|
emit removed(key);
|
||||||
emit customDataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomData::rename(const QString& oldKey, const QString& newKey)
|
void CustomData::rename(const QString& oldKey, const QString& newKey)
|
||||||
@ -104,7 +104,7 @@ void CustomData::rename(const QString& oldKey, const QString& newKey)
|
|||||||
m_data.insert(newKey, data);
|
m_data.insert(newKey, data);
|
||||||
|
|
||||||
updateLastModified();
|
updateLastModified();
|
||||||
emit customDataModified();
|
emitModified();
|
||||||
emit renamed(oldKey, newKey);
|
emit renamed(oldKey, newKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ void CustomData::copyDataFrom(const CustomData* other)
|
|||||||
|
|
||||||
updateLastModified();
|
updateLastModified();
|
||||||
emit reset();
|
emit reset();
|
||||||
emit customDataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime CustomData::getLastModified() const
|
QDateTime CustomData::getLastModified() const
|
||||||
@ -153,7 +153,7 @@ void CustomData::clear()
|
|||||||
m_data.clear();
|
m_data.clear();
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit customDataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CustomData::isEmpty() const
|
bool CustomData::isEmpty() const
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class CustomData : public QObject
|
#include "core/ModifiableObject.h"
|
||||||
|
|
||||||
|
class CustomData : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -54,7 +56,6 @@ public:
|
|||||||
static const QString ExcludeFromReports;
|
static const QString ExcludeFromReports;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void customDataModified();
|
|
||||||
void aboutToBeAdded(const QString& key);
|
void aboutToBeAdded(const QString& key);
|
||||||
void added(const QString& key);
|
void added(const QString& key);
|
||||||
void aboutToBeRemoved(const QString& key);
|
void aboutToBeRemoved(const QString& key);
|
||||||
@ -63,7 +64,6 @@ signals:
|
|||||||
void renamed(const QString& oldKey, const QString& newKey);
|
void renamed(const QString& oldKey, const QString& newKey);
|
||||||
void aboutToBeReset();
|
void aboutToBeReset();
|
||||||
void reset();
|
void reset();
|
||||||
void lastModified();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateLastModified();
|
void updateLastModified();
|
||||||
|
@ -44,24 +44,35 @@ Database::Database()
|
|||||||
, m_data()
|
, m_data()
|
||||||
, m_rootGroup(nullptr)
|
, m_rootGroup(nullptr)
|
||||||
, m_fileWatcher(new FileWatcher(this))
|
, m_fileWatcher(new FileWatcher(this))
|
||||||
, m_emitModified(false)
|
|
||||||
, m_uuid(QUuid::createUuid())
|
, m_uuid(QUuid::createUuid())
|
||||||
{
|
{
|
||||||
|
// setup modified timer
|
||||||
|
m_modifiedTimer.setSingleShot(true);
|
||||||
|
connect(this, &Database::emitModifiedChanged, this, [this](bool value) {
|
||||||
|
if (!value) {
|
||||||
|
stopModifiedTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(&m_modifiedTimer, &QTimer::timeout, this, &Database::emitModified);
|
||||||
|
|
||||||
|
// other signals
|
||||||
|
connect(m_metadata, &Metadata::modified, this, &Database::markAsModified);
|
||||||
|
connect(this, &Database::databaseOpened, this, [this]() { updateCommonUsernames(); });
|
||||||
|
connect(this, &Database::databaseSaved, this, [this]() { updateCommonUsernames(); });
|
||||||
|
connect(m_fileWatcher, &FileWatcher::fileChanged, this, &Database::databaseFileChanged);
|
||||||
|
|
||||||
|
// static uuid map
|
||||||
|
s_uuidMap.insert(m_uuid, this);
|
||||||
|
|
||||||
|
// block modified signal and set root group
|
||||||
|
setEmitModified(false);
|
||||||
|
|
||||||
setRootGroup(new Group());
|
setRootGroup(new Group());
|
||||||
rootGroup()->setUuid(QUuid::createUuid());
|
rootGroup()->setUuid(QUuid::createUuid());
|
||||||
rootGroup()->setName(tr("Passwords", "Root group name"));
|
rootGroup()->setName(tr("Passwords", "Root group name"));
|
||||||
m_modifiedTimer.setSingleShot(true);
|
|
||||||
|
|
||||||
s_uuidMap.insert(m_uuid, this);
|
|
||||||
|
|
||||||
connect(m_metadata, SIGNAL(metadataModified()), SLOT(markAsModified()));
|
|
||||||
connect(&m_modifiedTimer, SIGNAL(timeout()), SIGNAL(databaseModified()));
|
|
||||||
connect(this, SIGNAL(databaseOpened()), SLOT(updateCommonUsernames()));
|
|
||||||
connect(this, SIGNAL(databaseSaved()), SLOT(updateCommonUsernames()));
|
|
||||||
connect(m_fileWatcher, &FileWatcher::fileChanged, this, &Database::databaseFileChanged);
|
|
||||||
|
|
||||||
m_modified = false;
|
m_modified = false;
|
||||||
m_emitModified = true;
|
setEmitModified(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Database(const QString& filePath)
|
Database::Database(const QString& filePath)
|
||||||
@ -431,7 +442,6 @@ void Database::releaseData()
|
|||||||
|
|
||||||
setEmitModified(false);
|
setEmitModified(false);
|
||||||
m_modified = false;
|
m_modified = false;
|
||||||
stopModifiedTimer();
|
|
||||||
|
|
||||||
s_uuidMap.remove(m_uuid);
|
s_uuidMap.remove(m_uuid);
|
||||||
m_uuid = QUuid();
|
m_uuid = QUuid();
|
||||||
@ -439,7 +449,10 @@ void Database::releaseData()
|
|||||||
m_data.clear();
|
m_data.clear();
|
||||||
m_metadata->clear();
|
m_metadata->clear();
|
||||||
|
|
||||||
|
auto oldGroup = rootGroup();
|
||||||
setRootGroup(new Group());
|
setRootGroup(new Group());
|
||||||
|
// explicitly delete old group, otherwise it is only deleted when the database object is destructed
|
||||||
|
delete oldGroup;
|
||||||
|
|
||||||
m_fileWatcher->stop();
|
m_fileWatcher->stop();
|
||||||
|
|
||||||
@ -840,15 +853,6 @@ void Database::emptyRecycleBin()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::setEmitModified(bool value)
|
|
||||||
{
|
|
||||||
if (m_emitModified && !value) {
|
|
||||||
stopModifiedTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_emitModified = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Database::isModified() const
|
bool Database::isModified() const
|
||||||
{
|
{
|
||||||
return m_modified;
|
return m_modified;
|
||||||
@ -862,7 +866,7 @@ bool Database::hasNonDataChanges() const
|
|||||||
void Database::markAsModified()
|
void Database::markAsModified()
|
||||||
{
|
{
|
||||||
m_modified = true;
|
m_modified = true;
|
||||||
if (m_emitModified && !m_modifiedTimer.isActive()) {
|
if (!m_modifiedTimer.isActive()) {
|
||||||
// Small time delay prevents numerous consecutive saves due to repeated signals
|
// Small time delay prevents numerous consecutive saves due to repeated signals
|
||||||
startModifiedTimer();
|
startModifiedTimer();
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
|
#include "core/ModifiableObject.h"
|
||||||
#include "crypto/kdf/AesKdf.h"
|
#include "crypto/kdf/AesKdf.h"
|
||||||
#include "crypto/kdf/Kdf.h"
|
#include "crypto/kdf/Kdf.h"
|
||||||
#include "format/KeePass2.h"
|
#include "format/KeePass2.h"
|
||||||
@ -52,7 +53,7 @@ struct DeletedObject
|
|||||||
|
|
||||||
Q_DECLARE_TYPEINFO(DeletedObject, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(DeletedObject, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
class Database : public QObject
|
class Database : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -83,7 +84,6 @@ public:
|
|||||||
bool isInitialized() const;
|
bool isInitialized() const;
|
||||||
bool isModified() const;
|
bool isModified() const;
|
||||||
bool hasNonDataChanges() const;
|
bool hasNonDataChanges() const;
|
||||||
void setEmitModified(bool value);
|
|
||||||
bool isReadOnly() const;
|
bool isReadOnly() const;
|
||||||
void setReadOnly(bool readOnly);
|
void setReadOnly(bool readOnly);
|
||||||
bool isSaving();
|
bool isSaving();
|
||||||
@ -151,7 +151,6 @@ signals:
|
|||||||
void groupAboutToMove(Group* group, Group* toGroup, int index);
|
void groupAboutToMove(Group* group, Group* toGroup, int index);
|
||||||
void groupMoved();
|
void groupMoved();
|
||||||
void databaseOpened();
|
void databaseOpened();
|
||||||
void databaseModified();
|
|
||||||
void databaseSaved();
|
void databaseSaved();
|
||||||
void databaseDiscarded();
|
void databaseDiscarded();
|
||||||
void databaseFileChanged();
|
void databaseFileChanged();
|
||||||
@ -213,7 +212,6 @@ private:
|
|||||||
QMutex m_saveMutex;
|
QMutex m_saveMutex;
|
||||||
QPointer<FileWatcher> m_fileWatcher;
|
QPointer<FileWatcher> m_fileWatcher;
|
||||||
bool m_modified = false;
|
bool m_modified = false;
|
||||||
bool m_emitModified;
|
|
||||||
bool m_hasNonDataChange = false;
|
bool m_hasNonDataChange = false;
|
||||||
QString m_keyError;
|
QString m_keyError;
|
||||||
|
|
||||||
|
@ -47,15 +47,15 @@ Entry::Entry()
|
|||||||
m_data.autoTypeEnabled = true;
|
m_data.autoTypeEnabled = true;
|
||||||
m_data.autoTypeObfuscation = 0;
|
m_data.autoTypeObfuscation = 0;
|
||||||
|
|
||||||
connect(m_attributes, SIGNAL(entryAttributesModified()), SLOT(updateTotp()));
|
connect(m_attributes, &EntryAttributes::modified, this, &Entry::updateTotp);
|
||||||
connect(m_attributes, SIGNAL(entryAttributesModified()), this, SIGNAL(entryModified()));
|
connect(m_attributes, &EntryAttributes::modified, this, &Entry::modified);
|
||||||
connect(m_attributes, SIGNAL(defaultKeyModified()), SLOT(emitDataChanged()));
|
connect(m_attributes, &EntryAttributes::defaultKeyModified, this, &Entry::emitDataChanged);
|
||||||
connect(m_attachments, SIGNAL(entryAttachmentsModified()), this, SIGNAL(entryModified()));
|
connect(m_attachments, &EntryAttachments::modified, this, &Entry::modified);
|
||||||
connect(m_autoTypeAssociations, SIGNAL(modified()), SIGNAL(entryModified()));
|
connect(m_autoTypeAssociations, &AutoTypeAssociations::modified, this, &Entry::modified);
|
||||||
connect(m_customData, SIGNAL(customDataModified()), this, SIGNAL(entryModified()));
|
connect(m_customData, &CustomData::modified, this, &Entry::modified);
|
||||||
|
|
||||||
connect(this, SIGNAL(entryModified()), SLOT(updateTimeinfo()));
|
connect(this, &Entry::modified, this, &Entry::updateTimeinfo);
|
||||||
connect(this, SIGNAL(entryModified()), SLOT(updateModifiedSinceBegin()));
|
connect(this, &Entry::modified, this, &Entry::updateModifiedSinceBegin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry::~Entry()
|
Entry::~Entry()
|
||||||
@ -76,7 +76,7 @@ template <class T> inline bool Entry::set(T& property, const T& value)
|
|||||||
{
|
{
|
||||||
if (property != value) {
|
if (property != value) {
|
||||||
property = value;
|
property = value;
|
||||||
emit entryModified();
|
emitModified();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -609,7 +609,7 @@ void Entry::setIcon(int iconNumber)
|
|||||||
m_data.iconNumber = iconNumber;
|
m_data.iconNumber = iconNumber;
|
||||||
m_data.customIcon = QUuid();
|
m_data.customIcon = QUuid();
|
||||||
|
|
||||||
emit entryModified();
|
emitModified();
|
||||||
emitDataChanged();
|
emitDataChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,7 +622,7 @@ void Entry::setIcon(const QUuid& uuid)
|
|||||||
m_data.customIcon = uuid;
|
m_data.customIcon = uuid;
|
||||||
m_data.iconNumber = 0;
|
m_data.iconNumber = 0;
|
||||||
|
|
||||||
emit entryModified();
|
emitModified();
|
||||||
emitDataChanged();
|
emitDataChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -715,7 +715,7 @@ void Entry::setExpires(const bool& value)
|
|||||||
{
|
{
|
||||||
if (m_data.timeInfo.expires() != value) {
|
if (m_data.timeInfo.expires() != value) {
|
||||||
m_data.timeInfo.setExpires(value);
|
m_data.timeInfo.setExpires(value);
|
||||||
emit entryModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -723,7 +723,7 @@ void Entry::setExpiryTime(const QDateTime& dateTime)
|
|||||||
{
|
{
|
||||||
if (m_data.timeInfo.expiryTime() != dateTime) {
|
if (m_data.timeInfo.expiryTime() != dateTime) {
|
||||||
m_data.timeInfo.setExpiryTime(dateTime);
|
m_data.timeInfo.setExpiryTime(dateTime);
|
||||||
emit entryModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +742,7 @@ void Entry::addHistoryItem(Entry* entry)
|
|||||||
Q_ASSERT(!entry->parent());
|
Q_ASSERT(!entry->parent());
|
||||||
|
|
||||||
m_history.append(entry);
|
m_history.append(entry);
|
||||||
emit entryModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
||||||
@ -760,7 +760,7 @@ void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
|||||||
delete entry;
|
delete entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit entryModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::truncateHistory()
|
void Entry::truncateHistory()
|
||||||
@ -813,7 +813,7 @@ void Entry::truncateHistory()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
emit entryModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "core/EntryAttachments.h"
|
#include "core/EntryAttachments.h"
|
||||||
#include "core/EntryAttributes.h"
|
#include "core/EntryAttributes.h"
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
|
#include "core/ModifiableObject.h"
|
||||||
#include "core/TimeInfo.h"
|
#include "core/TimeInfo.h"
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
@ -75,7 +76,7 @@ struct EntryData
|
|||||||
bool equals(const EntryData& other, CompareItemOptions options) const;
|
bool equals(const EntryData& other, CompareItemOptions options) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entry : public QObject
|
class Entry : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -260,7 +261,6 @@ signals:
|
|||||||
* Emitted when a default attribute has been changed.
|
* Emitted when a default attribute has been changed.
|
||||||
*/
|
*/
|
||||||
void entryDataChanged(Entry* entry);
|
void entryDataChanged(Entry* entry);
|
||||||
void entryModified();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void emitDataChanged();
|
void emitDataChanged();
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
EntryAttachments::EntryAttachments(QObject* parent)
|
EntryAttachments::EntryAttachments(QObject* parent)
|
||||||
: QObject(parent)
|
: ModifiableObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ QByteArray EntryAttachments::value(const QString& key) const
|
|||||||
|
|
||||||
void EntryAttachments::set(const QString& key, const QByteArray& value)
|
void EntryAttachments::set(const QString& key, const QByteArray& value)
|
||||||
{
|
{
|
||||||
bool emitModified = false;
|
bool shouldEmitModified = false;
|
||||||
bool addAttachment = !m_attachments.contains(key);
|
bool addAttachment = !m_attachments.contains(key);
|
||||||
|
|
||||||
if (addAttachment) {
|
if (addAttachment) {
|
||||||
@ -58,7 +58,7 @@ void EntryAttachments::set(const QString& key, const QByteArray& value)
|
|||||||
|
|
||||||
if (addAttachment || m_attachments.value(key) != value) {
|
if (addAttachment || m_attachments.value(key) != value) {
|
||||||
m_attachments.insert(key, value);
|
m_attachments.insert(key, value);
|
||||||
emitModified = true;
|
shouldEmitModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addAttachment) {
|
if (addAttachment) {
|
||||||
@ -67,8 +67,8 @@ void EntryAttachments::set(const QString& key, const QByteArray& value)
|
|||||||
emit keyModified(key);
|
emit keyModified(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emitModified) {
|
if (shouldEmitModified) {
|
||||||
emit entryAttachmentsModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ void EntryAttachments::remove(const QString& key)
|
|||||||
m_attachments.remove(key);
|
m_attachments.remove(key);
|
||||||
|
|
||||||
emit removed(key);
|
emit removed(key);
|
||||||
emit entryAttachmentsModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryAttachments::remove(const QStringList& keys)
|
void EntryAttachments::remove(const QStringList& keys)
|
||||||
@ -108,7 +108,7 @@ void EntryAttachments::remove(const QStringList& keys)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isModified) {
|
if (isModified) {
|
||||||
emit entryAttachmentsModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ void EntryAttachments::clear()
|
|||||||
m_attachments.clear();
|
m_attachments.clear();
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit entryAttachmentsModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryAttachments::copyDataFrom(const EntryAttachments* other)
|
void EntryAttachments::copyDataFrom(const EntryAttachments* other)
|
||||||
@ -146,7 +146,7 @@ void EntryAttachments::copyDataFrom(const EntryAttachments* other)
|
|||||||
m_attachments = other->m_attachments;
|
m_attachments = other->m_attachments;
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit entryAttachmentsModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "core/ModifiableObject.h"
|
||||||
|
|
||||||
class QStringList;
|
class QStringList;
|
||||||
|
|
||||||
class EntryAttachments : public QObject
|
class EntryAttachments : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -45,7 +47,6 @@ public:
|
|||||||
int attachmentsSize() const;
|
int attachmentsSize() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void entryAttachmentsModified();
|
|
||||||
void keyModified(const QString& key);
|
void keyModified(const QString& key);
|
||||||
void aboutToBeAdded(const QString& key);
|
void aboutToBeAdded(const QString& key);
|
||||||
void added(const QString& key);
|
void added(const QString& key);
|
||||||
|
@ -35,7 +35,7 @@ const QString EntryAttributes::SearchTextGroupName = "SearchText";
|
|||||||
const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
|
const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
|
||||||
|
|
||||||
EntryAttributes::EntryAttributes(QObject* parent)
|
EntryAttributes::EntryAttributes(QObject* parent)
|
||||||
: QObject(parent)
|
: ModifiableObject(parent)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ bool EntryAttributes::isReference(const QString& key) const
|
|||||||
|
|
||||||
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
|
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
|
||||||
{
|
{
|
||||||
bool emitModified = false;
|
bool shouldEmitModified = false;
|
||||||
|
|
||||||
bool addAttribute = !m_attributes.contains(key);
|
bool addAttribute = !m_attributes.contains(key);
|
||||||
bool changeValue = !addAttribute && (m_attributes.value(key) != value);
|
bool changeValue = !addAttribute && (m_attributes.value(key) != value);
|
||||||
@ -116,27 +116,27 @@ void EntryAttributes::set(const QString& key, const QString& value, bool protect
|
|||||||
|
|
||||||
if (addAttribute || changeValue) {
|
if (addAttribute || changeValue) {
|
||||||
m_attributes.insert(key, value);
|
m_attributes.insert(key, value);
|
||||||
emitModified = true;
|
shouldEmitModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protect) {
|
if (protect) {
|
||||||
if (!m_protectedAttributes.contains(key)) {
|
if (!m_protectedAttributes.contains(key)) {
|
||||||
emitModified = true;
|
shouldEmitModified = true;
|
||||||
}
|
}
|
||||||
m_protectedAttributes.insert(key);
|
m_protectedAttributes.insert(key);
|
||||||
} else if (m_protectedAttributes.remove(key)) {
|
} else if (m_protectedAttributes.remove(key)) {
|
||||||
emitModified = true;
|
shouldEmitModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emitModified) {
|
if (shouldEmitModified) {
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultAttribute && changeValue) {
|
if (defaultAttribute && changeValue) {
|
||||||
emit defaultKeyModified();
|
emit defaultKeyModified();
|
||||||
} else if (addAttribute) {
|
} else if (addAttribute) {
|
||||||
emit added(key);
|
emit added(key);
|
||||||
} else if (emitModified) {
|
} else if (shouldEmitModified) {
|
||||||
emit customKeyModified(key);
|
emit customKeyModified(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ void EntryAttributes::remove(const QString& key)
|
|||||||
m_protectedAttributes.remove(key);
|
m_protectedAttributes.remove(key);
|
||||||
|
|
||||||
emit removed(key);
|
emit removed(key);
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
||||||
@ -185,7 +185,7 @@ void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
|||||||
m_protectedAttributes.insert(newKey);
|
m_protectedAttributes.insert(newKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
emit renamed(oldKey, newKey);
|
emit renamed(oldKey, newKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
|
bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
|
||||||
@ -250,7 +250,7 @@ void EntryAttributes::copyDataFrom(const EntryAttributes* other)
|
|||||||
m_protectedAttributes = other->m_protectedAttributes;
|
m_protectedAttributes = other->m_protectedAttributes;
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ void EntryAttributes::clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit reset();
|
emit reset();
|
||||||
emit entryAttributesModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
int EntryAttributes::attributesSize() const
|
int EntryAttributes::attributesSize() const
|
||||||
|
@ -26,7 +26,9 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
class EntryAttributes : public QObject
|
#include "core/ModifiableObject.h"
|
||||||
|
|
||||||
|
class EntryAttributes : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -69,7 +71,6 @@ public:
|
|||||||
static const QString SearchTextGroupName;
|
static const QString SearchTextGroupName;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void entryAttributesModified();
|
|
||||||
void defaultKeyModified();
|
void defaultKeyModified();
|
||||||
void customKeyModified(const QString& key);
|
void customKeyModified(const QString& key);
|
||||||
void aboutToBeAdded(const QString& key);
|
void aboutToBeAdded(const QString& key);
|
||||||
|
@ -46,9 +46,9 @@ Group::Group()
|
|||||||
m_data.searchingEnabled = Inherit;
|
m_data.searchingEnabled = Inherit;
|
||||||
m_data.mergeMode = Default;
|
m_data.mergeMode = Default;
|
||||||
|
|
||||||
connect(m_customData, SIGNAL(customDataModified()), this, SIGNAL(groupModified()));
|
connect(m_customData, &CustomData::modified, this, &Group::modified);
|
||||||
connect(this, SIGNAL(groupModified()), SLOT(updateTimeinfo()));
|
connect(this, &Group::modified, this, &Group::updateTimeinfo);
|
||||||
connect(this, SIGNAL(groupNonDataChange()), SLOT(updateTimeinfo()));
|
connect(this, &Group::groupNonDataChange, this, &Group::updateTimeinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::~Group()
|
Group::~Group()
|
||||||
@ -80,7 +80,7 @@ template <class P, class V> inline bool Group::set(P& property, const V& value)
|
|||||||
{
|
{
|
||||||
if (property != value) {
|
if (property != value) {
|
||||||
property = value;
|
property = value;
|
||||||
emit groupModified();
|
emitModified();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -333,7 +333,7 @@ void Group::setIcon(int iconNumber)
|
|||||||
if (iconNumber >= 0 && (m_data.iconNumber != iconNumber || !m_data.customIcon.isNull())) {
|
if (iconNumber >= 0 && (m_data.iconNumber != iconNumber || !m_data.customIcon.isNull())) {
|
||||||
m_data.iconNumber = iconNumber;
|
m_data.iconNumber = iconNumber;
|
||||||
m_data.customIcon = QUuid();
|
m_data.customIcon = QUuid();
|
||||||
emit groupModified();
|
emitModified();
|
||||||
emit groupDataChanged(this);
|
emit groupDataChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,7 +343,7 @@ void Group::setIcon(const QUuid& uuid)
|
|||||||
if (!uuid.isNull() && m_data.customIcon != uuid) {
|
if (!uuid.isNull() && m_data.customIcon != uuid) {
|
||||||
m_data.customIcon = uuid;
|
m_data.customIcon = uuid;
|
||||||
m_data.iconNumber = 0;
|
m_data.iconNumber = 0;
|
||||||
emit groupModified();
|
emitModified();
|
||||||
emit groupDataChanged(this);
|
emit groupDataChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,7 +385,7 @@ void Group::setExpires(bool value)
|
|||||||
{
|
{
|
||||||
if (m_data.timeInfo.expires() != value) {
|
if (m_data.timeInfo.expires() != value) {
|
||||||
m_data.timeInfo.setExpires(value);
|
m_data.timeInfo.setExpires(value);
|
||||||
emit groupModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +393,7 @@ void Group::setExpiryTime(const QDateTime& dateTime)
|
|||||||
{
|
{
|
||||||
if (m_data.timeInfo.expiryTime() != dateTime) {
|
if (m_data.timeInfo.expiryTime() != dateTime) {
|
||||||
m_data.timeInfo.setExpiryTime(dateTime);
|
m_data.timeInfo.setExpiryTime(dateTime);
|
||||||
emit groupModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +465,7 @@ void Group::setParent(Group* parent, int index)
|
|||||||
m_data.timeInfo.setLocationChanged(Clock::currentDateTimeUtc());
|
m_data.timeInfo.setLocationChanged(Clock::currentDateTimeUtc());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit groupModified();
|
emitModified();
|
||||||
|
|
||||||
if (!moveWithinDatabase) {
|
if (!moveWithinDatabase) {
|
||||||
emit groupAdded();
|
emit groupAdded();
|
||||||
@ -927,12 +927,12 @@ void Group::addEntry(Entry* entry)
|
|||||||
emit entryAboutToAdd(entry);
|
emit entryAboutToAdd(entry);
|
||||||
|
|
||||||
m_entries << entry;
|
m_entries << entry;
|
||||||
connect(entry, SIGNAL(entryDataChanged(Entry*)), SIGNAL(entryDataChanged(Entry*)));
|
connect(entry, &Entry::entryDataChanged, this, &Group::entryDataChanged);
|
||||||
if (m_db) {
|
if (m_db) {
|
||||||
connect(entry, SIGNAL(entryModified()), m_db, SLOT(markAsModified()));
|
connect(entry, &Entry::modified, m_db, &Database::markAsModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit groupModified();
|
emitModified();
|
||||||
emit entryAdded(entry);
|
emit entryAdded(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,7 +949,7 @@ void Group::removeEntry(Entry* entry)
|
|||||||
entry->disconnect(m_db);
|
entry->disconnect(m_db);
|
||||||
}
|
}
|
||||||
m_entries.removeAll(entry);
|
m_entries.removeAll(entry);
|
||||||
emit groupModified();
|
emitModified();
|
||||||
emit entryRemoved(entry);
|
emit entryRemoved(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -990,21 +990,21 @@ void Group::connectDatabaseSignalsRecursive(Database* db)
|
|||||||
entry->disconnect(m_db);
|
entry->disconnect(m_db);
|
||||||
}
|
}
|
||||||
if (db) {
|
if (db) {
|
||||||
connect(entry, SIGNAL(entryModified()), db, SLOT(markAsModified()));
|
connect(entry, &Entry::modified, db, &Database::markAsModified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
connect(this, SIGNAL(groupDataChanged(Group*)), db, SIGNAL(groupDataChanged(Group*)));
|
connect(this, &Group::groupDataChanged, db, &Database::groupDataChanged);
|
||||||
connect(this, SIGNAL(groupAboutToRemove(Group*)), db, SIGNAL(groupAboutToRemove(Group*)));
|
connect(this, &Group::groupAboutToRemove, db, &Database::groupAboutToRemove);
|
||||||
connect(this, SIGNAL(groupRemoved()), db, SIGNAL(groupRemoved()));
|
connect(this, &Group::groupRemoved, db, &Database::groupRemoved);
|
||||||
connect(this, SIGNAL(groupAboutToAdd(Group*, int)), db, SIGNAL(groupAboutToAdd(Group*,int)));
|
connect(this, &Group::groupAboutToAdd, db, &Database::groupAboutToAdd);
|
||||||
connect(this, SIGNAL(groupAdded()), db, SIGNAL(groupAdded()));
|
connect(this, &Group::groupAdded, db, &Database::groupAdded);
|
||||||
connect(this, SIGNAL(aboutToMove(Group*,Group*,int)), db, SIGNAL(groupAboutToMove(Group*,Group*,int)));
|
connect(this, &Group::aboutToMove, db, &Database::groupAboutToMove);
|
||||||
connect(this, SIGNAL(groupMoved()), db, SIGNAL(groupMoved()));
|
connect(this, &Group::groupMoved, db, &Database::groupMoved);
|
||||||
connect(this, SIGNAL(groupModified()), db, SLOT(markAsModified()));
|
connect(this, &Group::groupNonDataChange, db, &Database::markNonDataChange);
|
||||||
connect(this, SIGNAL(groupNonDataChange()), db, SLOT(markNonDataChange()));
|
connect(this, &Group::modified, db, &Database::markAsModified);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,7 +1020,7 @@ void Group::cleanupParent()
|
|||||||
if (m_parent) {
|
if (m_parent) {
|
||||||
emit groupAboutToRemove(this);
|
emit groupAboutToRemove(this);
|
||||||
m_parent->m_children.removeAll(this);
|
m_parent->m_children.removeAll(this);
|
||||||
emit groupModified();
|
emitModified();
|
||||||
emit groupRemoved();
|
emit groupRemoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1189,7 +1189,7 @@ void Group::sortChildrenRecursively(bool reverse)
|
|||||||
child->sortChildrenRecursively(reverse);
|
child->sortChildrenRecursively(reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit groupModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Group::GroupData::operator==(const Group::GroupData& other) const
|
bool Group::GroupData::operator==(const Group::GroupData& other) const
|
||||||
|
@ -27,9 +27,10 @@
|
|||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
|
#include "core/ModifiableObject.h"
|
||||||
#include "core/TimeInfo.h"
|
#include "core/TimeInfo.h"
|
||||||
|
|
||||||
class Group : public QObject
|
class Group : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -184,7 +185,6 @@ signals:
|
|||||||
void groupRemoved();
|
void groupRemoved();
|
||||||
void aboutToMove(Group* group, Group* toGroup, int index);
|
void aboutToMove(Group* group, Group* toGroup, int index);
|
||||||
void groupMoved();
|
void groupMoved();
|
||||||
void groupModified();
|
|
||||||
void groupNonDataChange();
|
void groupNonDataChange();
|
||||||
void entryAboutToAdd(Entry* entry);
|
void entryAboutToAdd(Entry* entry);
|
||||||
void entryAdded(Entry* entry);
|
void entryAdded(Entry* entry);
|
||||||
|
@ -29,12 +29,12 @@ const int Metadata::DefaultHistoryMaxItems = 10;
|
|||||||
const int Metadata::DefaultHistoryMaxSize = 6 * 1024 * 1024;
|
const int Metadata::DefaultHistoryMaxSize = 6 * 1024 * 1024;
|
||||||
|
|
||||||
Metadata::Metadata(QObject* parent)
|
Metadata::Metadata(QObject* parent)
|
||||||
: QObject(parent)
|
: ModifiableObject(parent)
|
||||||
, m_customData(new CustomData(this))
|
, m_customData(new CustomData(this))
|
||||||
, m_updateDatetime(true)
|
, m_updateDatetime(true)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
connect(m_customData, SIGNAL(customDataModified()), SIGNAL(metadataModified()));
|
connect(m_customData, &CustomData::modified, this, &Metadata::modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metadata::init()
|
void Metadata::init()
|
||||||
@ -76,7 +76,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value)
|
|||||||
{
|
{
|
||||||
if (property != value) {
|
if (property != value) {
|
||||||
property = value;
|
property = value;
|
||||||
emit metadataModified();
|
emitModified();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -90,7 +90,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value, QDat
|
|||||||
if (m_updateDatetime) {
|
if (m_updateDatetime) {
|
||||||
dateTime = Clock::currentDateTimeUtc();
|
dateTime = Clock::currentDateTimeUtc();
|
||||||
}
|
}
|
||||||
emit metadataModified();
|
emitModified();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -386,7 +386,7 @@ void Metadata::addCustomIcon(const QUuid& uuid, const QImage& image)
|
|||||||
m_customIcons.insert(uuid, QIcon());
|
m_customIcons.insert(uuid, QIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit metadataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metadata::removeCustomIcon(const QUuid& uuid)
|
void Metadata::removeCustomIcon(const QUuid& uuid)
|
||||||
@ -404,7 +404,7 @@ void Metadata::removeCustomIcon(const QUuid& uuid)
|
|||||||
m_customIconsRaw.remove(uuid);
|
m_customIconsRaw.remove(uuid);
|
||||||
m_customIconsOrder.removeAll(uuid);
|
m_customIconsOrder.removeAll(uuid);
|
||||||
Q_ASSERT(m_customIconsRaw.count() == m_customIconsOrder.count());
|
Q_ASSERT(m_customIconsRaw.count() == m_customIconsOrder.count());
|
||||||
emit metadataModified();
|
emitModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Metadata::findCustomIcon(const QImage& candidate)
|
QUuid Metadata::findCustomIcon(const QImage& candidate)
|
||||||
|
@ -30,11 +30,12 @@
|
|||||||
|
|
||||||
#include "core/CustomData.h"
|
#include "core/CustomData.h"
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
|
#include "core/ModifiableObject.h"
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
class Group;
|
class Group;
|
||||||
|
|
||||||
class Metadata : public QObject
|
class Metadata : public ModifiableObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -149,9 +150,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void copyAttributesFrom(const Metadata* other);
|
void copyAttributesFrom(const Metadata* other);
|
||||||
|
|
||||||
signals:
|
|
||||||
void metadataModified();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class P, class V> bool set(P& property, const V& value);
|
template <class P, class V> bool set(P& property, const V& value);
|
||||||
template <class P, class V> bool set(P& property, const V& value, QDateTime& dateTime);
|
template <class P, class V> bool set(P& property, const V& value, QDateTime& dateTime);
|
||||||
|
65
src/core/ModifiableObject.cpp
Normal file
65
src/core/ModifiableObject.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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 "ModifiableObject.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <typename T> T findParent(const QObject* obj)
|
||||||
|
{
|
||||||
|
if (!obj) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = obj->parent();
|
||||||
|
while (p) {
|
||||||
|
auto casted = qobject_cast<T>(p);
|
||||||
|
if (casted) {
|
||||||
|
return casted;
|
||||||
|
}
|
||||||
|
p = p->parent();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ModifiableObject::modifiedSignalEnabled() const
|
||||||
|
{
|
||||||
|
auto p = this;
|
||||||
|
while (p) {
|
||||||
|
if (!p->m_emitModified) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p = findParent<ModifiableObject*>(p);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModifiableObject::setEmitModified(bool value)
|
||||||
|
{
|
||||||
|
if (m_emitModified != value) {
|
||||||
|
m_emitModified = value;
|
||||||
|
emit emitModifiedChanged(m_emitModified);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModifiableObject::emitModified()
|
||||||
|
{
|
||||||
|
if (modifiedSignalEnabled()) {
|
||||||
|
emit modified();
|
||||||
|
}
|
||||||
|
}
|
59
src/core/ModifiableObject.h
Normal file
59
src/core/ModifiableObject.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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 KEEPASSXC_MODIFIABLEOBJECT_H
|
||||||
|
#define KEEPASSXC_MODIFIABLEOBJECT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class ModifiableObject : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
using QObject::QObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief check if the modified signal is enabled.
|
||||||
|
* Note that this is NOT the same as m_emitModified.
|
||||||
|
* The signal is enabled if neither the current object nor any of its parents disabled the signal.
|
||||||
|
*/
|
||||||
|
bool modifiedSignalEnabled() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* @brief set whether the modified signal should be emitted from this object and all its children.
|
||||||
|
*
|
||||||
|
* This means that even after calling `setEmitModified(true)` on this object,
|
||||||
|
* the signal may still be blocked in one of its parents.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
void setEmitModified(bool value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void emitModified();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void modified();
|
||||||
|
void emitModifiedChanged(bool value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_emitModified{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSXC_MODIFIABLEOBJECT_H
|
@ -475,7 +475,7 @@ namespace FdoSecrets
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Another possibility is the group being moved to recycle bin.
|
// Another possibility is the group being moved to recycle bin.
|
||||||
connect(m_exposedGroup.data(), &Group::groupModified, this, [this]() {
|
connect(m_exposedGroup.data(), &Group::modified, this, [this]() {
|
||||||
if (inRecycleBin(m_exposedGroup->parentGroup())) {
|
if (inRecycleBin(m_exposedGroup->parentGroup())) {
|
||||||
// reset the exposed group to none
|
// reset the exposed group to none
|
||||||
FdoSecrets::settings()->setExposedGroup(m_backend->database().data(), {});
|
FdoSecrets::settings()->setExposedGroup(m_backend->database().data(), {});
|
||||||
@ -483,7 +483,7 @@ namespace FdoSecrets
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Monitor exposed group settings
|
// Monitor exposed group settings
|
||||||
connect(m_backend->database()->metadata()->customData(), &CustomData::customDataModified, this, [this]() {
|
connect(m_backend->database()->metadata()->customData(), &CustomData::modified, this, [this]() {
|
||||||
if (!m_exposedGroup || backendLocked()) {
|
if (!m_exposedGroup || backendLocked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -500,8 +500,8 @@ namespace FdoSecrets
|
|||||||
onEntryAdded(entry, false);
|
onEntryAdded(entry, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not connect to databaseModified signal because we only want signals for the subset under m_exposedGroup
|
// Do not connect to Database::modified signal because we only want signals for the subset under m_exposedGroup
|
||||||
connect(m_backend->database()->metadata(), &Metadata::metadataModified, this, &Collection::collectionChanged);
|
connect(m_backend->database()->metadata(), &Metadata::modified, this, &Collection::collectionChanged);
|
||||||
connectGroupSignalRecursive(m_exposedGroup);
|
connectGroupSignalRecursive(m_exposedGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +556,7 @@ namespace FdoSecrets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(group, &Group::groupModified, this, &Collection::collectionChanged);
|
connect(group, &Group::modified, this, &Collection::collectionChanged);
|
||||||
connect(group, &Group::entryAdded, this, [this](Entry* entry) { onEntryAdded(entry, true); });
|
connect(group, &Group::entryAdded, this, [this](Entry* entry) { onEntryAdded(entry, true); });
|
||||||
|
|
||||||
const auto children = group->children();
|
const auto children = group->children();
|
||||||
|
@ -63,7 +63,7 @@ namespace FdoSecrets
|
|||||||
: DBusObject(parent)
|
: DBusObject(parent)
|
||||||
, m_backend(backend)
|
, m_backend(backend)
|
||||||
{
|
{
|
||||||
connect(m_backend.data(), &Entry::entryModified, this, &Item::itemChanged);
|
connect(m_backend, &Entry::modified, this, &Item::itemChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBusResult Item::locked(const DBusClientPtr& client, bool& locked) const
|
DBusResult Item::locked(const DBusClientPtr& client, bool& locked) const
|
||||||
|
@ -157,12 +157,11 @@ namespace FdoSecrets
|
|||||||
void Service::monitorDatabaseExposedGroup(DatabaseWidget* dbWidget)
|
void Service::monitorDatabaseExposedGroup(DatabaseWidget* dbWidget)
|
||||||
{
|
{
|
||||||
Q_ASSERT(dbWidget);
|
Q_ASSERT(dbWidget);
|
||||||
connect(
|
connect(dbWidget->database()->metadata()->customData(), &CustomData::modified, this, [this, dbWidget]() {
|
||||||
dbWidget->database()->metadata()->customData(), &CustomData::customDataModified, this, [this, dbWidget]() {
|
if (!FdoSecrets::settings()->exposedGroup(dbWidget->database()).isNull() && !findCollection(dbWidget)) {
|
||||||
if (!FdoSecrets::settings()->exposedGroup(dbWidget->database()).isNull() && !findCollection(dbWidget)) {
|
onDatabaseTabOpened(dbWidget, true);
|
||||||
onDatabaseTabOpened(dbWidget, true);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::ensureDefaultAlias()
|
void Service::ensureDefaultAlias()
|
||||||
|
@ -99,6 +99,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
|||||||
, m_opVaultOpenWidget(new OpVaultOpenWidget(this))
|
, m_opVaultOpenWidget(new OpVaultOpenWidget(this))
|
||||||
, m_groupView(new GroupView(m_db.data(), m_mainSplitter))
|
, m_groupView(new GroupView(m_db.data(), m_mainSplitter))
|
||||||
, m_saveAttempts(0)
|
, m_saveAttempts(0)
|
||||||
|
, m_entrySearcher(new EntrySearcher(false))
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_db);
|
Q_ASSERT(m_db);
|
||||||
|
|
||||||
@ -211,7 +212,6 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
|||||||
|
|
||||||
m_blockAutoSave = false;
|
m_blockAutoSave = false;
|
||||||
|
|
||||||
m_EntrySearcher = new EntrySearcher(false);
|
|
||||||
m_searchLimitGroup = config()->get(Config::SearchLimitGroup).toBool();
|
m_searchLimitGroup = config()->get(Config::SearchLimitGroup).toBool();
|
||||||
|
|
||||||
#ifdef WITH_XC_KEESHARE
|
#ifdef WITH_XC_KEESHARE
|
||||||
@ -234,7 +234,13 @@ DatabaseWidget::DatabaseWidget(const QString& filePath, QWidget* parent)
|
|||||||
|
|
||||||
DatabaseWidget::~DatabaseWidget()
|
DatabaseWidget::~DatabaseWidget()
|
||||||
{
|
{
|
||||||
delete m_EntrySearcher;
|
// Trigger any Database deletion related signals manually by
|
||||||
|
// explicitly clearing the Database pointer, instead of leaving it to ~QSharedPointer.
|
||||||
|
// QSharedPointer may behave differently depending on whether it is cleared by the `clear` method
|
||||||
|
// or by its destructor. In the latter case, the ref counter may not be correctly maintained
|
||||||
|
// if a copy of the QSharedPointer is created in any slots activated by the Database destructor.
|
||||||
|
// More details: https://github.com/keepassxreboot/keepassxc/issues/6393.
|
||||||
|
m_db.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Database> DatabaseWidget::database() const
|
QSharedPointer<Database> DatabaseWidget::database() const
|
||||||
@ -1061,10 +1067,10 @@ void DatabaseWidget::connectDatabaseSignals()
|
|||||||
SIGNAL(filePathChanged(QString, QString)),
|
SIGNAL(filePathChanged(QString, QString)),
|
||||||
|
|
||||||
SIGNAL(databaseFilePathChanged(QString, QString)));
|
SIGNAL(databaseFilePathChanged(QString, QString)));
|
||||||
connect(m_db.data(), SIGNAL(databaseModified()), SIGNAL(databaseModified()));
|
connect(m_db.data(), &Database::modified, this, &DatabaseWidget::databaseModified);
|
||||||
connect(m_db.data(), SIGNAL(databaseModified()), SLOT(onDatabaseModified()));
|
connect(m_db.data(), &Database::modified, this, &DatabaseWidget::onDatabaseModified);
|
||||||
connect(m_db.data(), SIGNAL(databaseSaved()), SIGNAL(databaseSaved()));
|
connect(m_db.data(), &Database::databaseSaved, this, &DatabaseWidget::databaseSaved);
|
||||||
connect(m_db.data(), SIGNAL(databaseFileChanged()), this, SLOT(reloadDatabaseFile()));
|
connect(m_db.data(), &Database::databaseFileChanged, this, &DatabaseWidget::reloadDatabaseFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseWidget::loadDatabase(bool accepted)
|
void DatabaseWidget::loadDatabase(bool accepted)
|
||||||
@ -1366,7 +1372,7 @@ void DatabaseWidget::search(const QString& searchtext)
|
|||||||
|
|
||||||
Group* searchGroup = m_searchLimitGroup ? currentGroup() : m_db->rootGroup();
|
Group* searchGroup = m_searchLimitGroup ? currentGroup() : m_db->rootGroup();
|
||||||
|
|
||||||
QList<Entry*> searchResult = m_EntrySearcher->search(searchtext, searchGroup);
|
QList<Entry*> searchResult = m_entrySearcher->search(searchtext, searchGroup);
|
||||||
|
|
||||||
m_entryView->displaySearch(searchResult);
|
m_entryView->displaySearch(searchResult);
|
||||||
m_lastSearchText = searchtext;
|
m_lastSearchText = searchtext;
|
||||||
@ -1388,7 +1394,7 @@ void DatabaseWidget::search(const QString& searchtext)
|
|||||||
|
|
||||||
void DatabaseWidget::setSearchCaseSensitive(bool state)
|
void DatabaseWidget::setSearchCaseSensitive(bool state)
|
||||||
{
|
{
|
||||||
m_EntrySearcher->setCaseSensitive(state);
|
m_entrySearcher->setCaseSensitive(state);
|
||||||
refreshSearch();
|
refreshSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ private:
|
|||||||
int m_saveAttempts;
|
int m_saveAttempts;
|
||||||
|
|
||||||
// Search state
|
// Search state
|
||||||
EntrySearcher* m_EntrySearcher;
|
QScopedPointer<EntrySearcher> m_entrySearcher;
|
||||||
QString m_lastSearchText;
|
QString m_lastSearchText;
|
||||||
bool m_searchLimitGroup;
|
bool m_searchLimitGroup;
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ void EditWidgetProperties::setCustomData(CustomData* customData)
|
|||||||
m_customData = customData;
|
m_customData = customData;
|
||||||
|
|
||||||
if (m_customData) {
|
if (m_customData) {
|
||||||
connect(m_customData, SIGNAL(customDataModified()), SLOT(update()));
|
connect(m_customData, &CustomData::modified, this, &EditWidgetProperties::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
@ -532,19 +532,23 @@ void EditEntryWidget::setupSSHAgent()
|
|||||||
m_sshAgentUi->commentTextLabel->setFont(fixedFont);
|
m_sshAgentUi->commentTextLabel->setFont(fixedFont);
|
||||||
m_sshAgentUi->publicKeyEdit->setFont(fixedFont);
|
m_sshAgentUi->publicKeyEdit->setFont(fixedFont);
|
||||||
|
|
||||||
connect(m_sshAgentUi->attachmentRadioButton, SIGNAL(clicked(bool)), SLOT(updateSSHAgentKeyInfo()));
|
// clang-format off
|
||||||
connect(m_sshAgentUi->attachmentComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateSSHAgentAttachment()));
|
connect(m_sshAgentUi->attachmentRadioButton, &QRadioButton::clicked,
|
||||||
connect(m_sshAgentUi->externalFileRadioButton, SIGNAL(clicked(bool)), SLOT(updateSSHAgentKeyInfo()));
|
this, &EditEntryWidget::updateSSHAgentKeyInfo);
|
||||||
connect(m_sshAgentUi->externalFileEdit, SIGNAL(textChanged(QString)), SLOT(updateSSHAgentKeyInfo()));
|
connect(m_sshAgentUi->attachmentComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
connect(m_sshAgentUi->browseButton, SIGNAL(clicked()), SLOT(browsePrivateKey()));
|
this, &EditEntryWidget::updateSSHAgentAttachment);
|
||||||
connect(m_sshAgentUi->addToAgentButton, SIGNAL(clicked()), SLOT(addKeyToAgent()));
|
connect(m_sshAgentUi->externalFileRadioButton, &QRadioButton::clicked,
|
||||||
connect(m_sshAgentUi->removeFromAgentButton, SIGNAL(clicked()), SLOT(removeKeyFromAgent()));
|
this, &EditEntryWidget::updateSSHAgentKeyInfo);
|
||||||
connect(m_sshAgentUi->decryptButton, SIGNAL(clicked()), SLOT(decryptPrivateKey()));
|
connect(m_sshAgentUi->externalFileEdit, &QLineEdit::textChanged, this, &EditEntryWidget::updateSSHAgentKeyInfo);
|
||||||
connect(m_sshAgentUi->copyToClipboardButton, SIGNAL(clicked()), SLOT(copyPublicKey()));
|
connect(m_sshAgentUi->browseButton, &QPushButton::clicked, this, &EditEntryWidget::browsePrivateKey);
|
||||||
|
connect(m_sshAgentUi->addToAgentButton, &QPushButton::clicked, this, &EditEntryWidget::addKeyToAgent);
|
||||||
|
connect(m_sshAgentUi->removeFromAgentButton, &QPushButton::clicked, this, &EditEntryWidget::removeKeyFromAgent);
|
||||||
|
connect(m_sshAgentUi->decryptButton, &QPushButton::clicked, this, &EditEntryWidget::decryptPrivateKey);
|
||||||
|
connect(m_sshAgentUi->copyToClipboardButton, &QPushButton::clicked, this, &EditEntryWidget::copyPublicKey);
|
||||||
|
|
||||||
connect(m_advancedUi->attachmentsWidget->entryAttachments(),
|
connect(m_advancedUi->attachmentsWidget->entryAttachments(), &EntryAttachments::modified,
|
||||||
SIGNAL(entryAttachmentsModified()),
|
this, &EditEntryWidget::updateSSHAgentAttachments);
|
||||||
SLOT(updateSSHAgentAttachments()));
|
// clang-format on
|
||||||
|
|
||||||
addPage(tr("SSH Agent"), icons()->icon("utilities-terminal"), m_sshAgentWidget);
|
addPage(tr("SSH Agent"), icons()->icon("utilities-terminal"), m_sshAgentWidget);
|
||||||
}
|
}
|
||||||
@ -803,7 +807,7 @@ void EditEntryWidget::loadEntry(Entry* entry,
|
|||||||
m_create = create;
|
m_create = create;
|
||||||
m_history = history;
|
m_history = history;
|
||||||
|
|
||||||
connect(m_entry, &Entry::entryModified, this, [this] { m_entryModifiedTimer.start(); });
|
connect(m_entry, &Entry::modified, this, [this] { m_entryModifiedTimer.start(); });
|
||||||
|
|
||||||
if (history) {
|
if (history) {
|
||||||
setHeadline(QString("%1 \u2022 %2").arg(parentName, tr("Entry history")));
|
setHeadline(QString("%1 \u2022 %2").arg(parentName, tr("Entry history")));
|
||||||
|
@ -124,7 +124,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer<
|
|||||||
m_db = database;
|
m_db = database;
|
||||||
|
|
||||||
m_temporaryGroup.reset(group->clone(Entry::CloneNoFlags, Group::CloneNoFlags));
|
m_temporaryGroup.reset(group->clone(Entry::CloneNoFlags, Group::CloneNoFlags));
|
||||||
connect(m_temporaryGroup->customData(), SIGNAL(customDataModified()), SLOT(setModified()));
|
connect(m_temporaryGroup->customData(), &CustomData::modified, this, [this]() { setModified(true); });
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
setHeadline(tr("Add group"));
|
setHeadline(tr("Add group"));
|
||||||
|
@ -43,14 +43,14 @@ ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent)
|
|||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_db(std::move(db))
|
, m_db(std::move(db))
|
||||||
{
|
{
|
||||||
connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(handleDatabaseChanged()));
|
connect(KeeShare::instance(), &KeeShare::activeChanged, this, &ShareObserver::handleDatabaseChanged);
|
||||||
|
|
||||||
connect(m_db.data(), SIGNAL(groupDataChanged(Group*)), SLOT(handleDatabaseChanged()));
|
connect(m_db.data(), &Database::groupDataChanged, this, &ShareObserver::handleDatabaseChanged);
|
||||||
connect(m_db.data(), SIGNAL(groupAdded()), SLOT(handleDatabaseChanged()));
|
connect(m_db.data(), &Database::groupAdded, this, &ShareObserver::handleDatabaseChanged);
|
||||||
connect(m_db.data(), SIGNAL(groupRemoved()), SLOT(handleDatabaseChanged()));
|
connect(m_db.data(), &Database::groupRemoved, this, &ShareObserver::handleDatabaseChanged);
|
||||||
|
|
||||||
connect(m_db.data(), SIGNAL(databaseModified()), SLOT(handleDatabaseChanged()));
|
connect(m_db.data(), &Database::modified, this, &ShareObserver::handleDatabaseChanged);
|
||||||
connect(m_db.data(), SIGNAL(databaseSaved()), SLOT(handleDatabaseSaved()));
|
connect(m_db.data(), &Database::databaseSaved, this, &ShareObserver::handleDatabaseSaved);
|
||||||
|
|
||||||
handleDatabaseChanged();
|
handleDatabaseChanged();
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ void EditGroupWidgetKeeShare::setGroup(Group* temporaryGroup, QSharedPointer<Dat
|
|||||||
m_temporaryGroup = temporaryGroup;
|
m_temporaryGroup = temporaryGroup;
|
||||||
|
|
||||||
if (m_temporaryGroup) {
|
if (m_temporaryGroup) {
|
||||||
connect(m_temporaryGroup, SIGNAL(groupModified()), SLOT(update()));
|
connect(m_temporaryGroup, &Group::modified, this, &EditGroupWidgetKeeShare::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
@ -110,7 +110,7 @@ void TestDatabase::testSignals()
|
|||||||
QVERIFY(ok);
|
QVERIFY(ok);
|
||||||
QCOMPARE(spyFilePathChanged.count(), 1);
|
QCOMPARE(spyFilePathChanged.count(), 1);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
db->metadata()->setName("test1");
|
db->metadata()->setName("test1");
|
||||||
QTRY_COMPARE(spyModified.count(), 1);
|
QTRY_COMPARE(spyModified.count(), 1);
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ void TestDatabase::testEmptyRecycleBinOnDisabled()
|
|||||||
// Prevents assertion failures on CI systems when the data dir is not writable
|
// Prevents assertion failures on CI systems when the data dir is not writable
|
||||||
db->setReadOnly(false);
|
db->setReadOnly(false);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
db->emptyRecycleBin();
|
db->emptyRecycleBin();
|
||||||
// The database must be unmodified in this test after emptying the recycle bin.
|
// The database must be unmodified in this test after emptying the recycle bin.
|
||||||
@ -159,7 +159,7 @@ void TestDatabase::testEmptyRecycleBinOnNotCreated()
|
|||||||
QVERIFY(db->open(filename, key, nullptr, false));
|
QVERIFY(db->open(filename, key, nullptr, false));
|
||||||
db->setReadOnly(false);
|
db->setReadOnly(false);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
db->emptyRecycleBin();
|
db->emptyRecycleBin();
|
||||||
// The database must be unmodified in this test after emptying the recycle bin.
|
// The database must be unmodified in this test after emptying the recycle bin.
|
||||||
@ -175,7 +175,7 @@ void TestDatabase::testEmptyRecycleBinOnEmpty()
|
|||||||
QVERIFY(db->open(filename, key, nullptr, false));
|
QVERIFY(db->open(filename, key, nullptr, false));
|
||||||
db->setReadOnly(false);
|
db->setReadOnly(false);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
db->emptyRecycleBin();
|
db->emptyRecycleBin();
|
||||||
// The database must be unmodified in this test after emptying the recycle bin.
|
// The database must be unmodified in this test after emptying the recycle bin.
|
||||||
|
@ -841,7 +841,7 @@ void TestGroup::testCopyDataFrom()
|
|||||||
group3->setName("TestGroup3");
|
group3->setName("TestGroup3");
|
||||||
group3->customData()->set("testKey", "value");
|
group3->customData()->set("testKey", "value");
|
||||||
|
|
||||||
QSignalSpy spyGroupModified(group.data(), SIGNAL(groupModified()));
|
QSignalSpy spyGroupModified(group.data(), SIGNAL(modified()));
|
||||||
QSignalSpy spyGroupDataChanged(group.data(), SIGNAL(groupDataChanged(Group*)));
|
QSignalSpy spyGroupDataChanged(group.data(), SIGNAL(groupDataChanged(Group*)));
|
||||||
|
|
||||||
group->copyDataFrom(group2.data());
|
group->copyDataFrom(group2.data());
|
||||||
|
@ -1479,7 +1479,7 @@ void TestMerge::testMergeNotModified()
|
|||||||
QScopedPointer<Database> dbSource(
|
QScopedPointer<Database> dbSource(
|
||||||
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
|
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
|
||||||
|
|
||||||
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(databaseModified()));
|
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(modified()));
|
||||||
Merger merger(dbSource.data(), dbDestination.data());
|
Merger merger(dbSource.data(), dbDestination.data());
|
||||||
merger.merge();
|
merger.merge();
|
||||||
QTRY_VERIFY(modifiedSignalSpy.empty());
|
QTRY_VERIFY(modifiedSignalSpy.empty());
|
||||||
@ -1491,7 +1491,7 @@ void TestMerge::testMergeModified()
|
|||||||
QScopedPointer<Database> dbSource(
|
QScopedPointer<Database> dbSource(
|
||||||
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
|
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
|
||||||
|
|
||||||
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(databaseModified()));
|
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(modified()));
|
||||||
// Make sure the two changes have a different timestamp.
|
// Make sure the two changes have a different timestamp.
|
||||||
QTest::qSleep(1);
|
QTest::qSleep(1);
|
||||||
Entry* entry = dbSource->rootGroup()->findEntryByPath("entry1");
|
Entry* entry = dbSource->rootGroup()->findEntryByPath("entry1");
|
||||||
|
@ -61,7 +61,7 @@ void TestModified::testSignals()
|
|||||||
|
|
||||||
QScopedPointer<Database> db(new Database());
|
QScopedPointer<Database> db(new Database());
|
||||||
auto* root = db->rootGroup();
|
auto* root = db->rootGroup();
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
db->setKey(compositeKey);
|
db->setKey(compositeKey);
|
||||||
++spyCount;
|
++spyCount;
|
||||||
@ -88,7 +88,7 @@ void TestModified::testSignals()
|
|||||||
|
|
||||||
QScopedPointer<Database> db2(new Database());
|
QScopedPointer<Database> db2(new Database());
|
||||||
auto* root2 = db2->rootGroup();
|
auto* root2 = db2->rootGroup();
|
||||||
QSignalSpy spyModified2(db2.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified2(db2.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
group1->setParent(root2);
|
group1->setParent(root2);
|
||||||
++spyCount;
|
++spyCount;
|
||||||
@ -149,7 +149,7 @@ void TestModified::testGroupSets()
|
|||||||
auto* group = new Group();
|
auto* group = new Group();
|
||||||
group->setParent(root);
|
group->setParent(root);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
root->setUuid(QUuid::createUuid());
|
root->setUuid(QUuid::createUuid());
|
||||||
++spyCount;
|
++spyCount;
|
||||||
@ -223,7 +223,7 @@ void TestModified::testEntrySets()
|
|||||||
auto* entry = new Entry();
|
auto* entry = new Entry();
|
||||||
entry->setGroup(group);
|
entry->setGroup(group);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
entry->setUuid(QUuid::createUuid());
|
entry->setUuid(QUuid::createUuid());
|
||||||
++spyCount;
|
++spyCount;
|
||||||
@ -647,7 +647,7 @@ void TestModified::testCustomData()
|
|||||||
auto* entry = new Entry();
|
auto* entry = new Entry();
|
||||||
entry->setGroup(group);
|
entry->setGroup(group);
|
||||||
|
|
||||||
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
|
QSignalSpy spyModified(db.data(), SIGNAL(modified()));
|
||||||
|
|
||||||
db->metadata()->customData()->set("Key", "Value");
|
db->metadata()->customData()->set("Key", "Value");
|
||||||
++spyCount;
|
++spyCount;
|
||||||
@ -667,3 +667,58 @@ void TestModified::testCustomData()
|
|||||||
group->customData()->set("Key", "Value");
|
group->customData()->set("Key", "Value");
|
||||||
QTRY_COMPARE(spyModified.count(), spyCount);
|
QTRY_COMPARE(spyModified.count(), spyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestModified::testBlockModifiedSignal()
|
||||||
|
{
|
||||||
|
QScopedPointer<Database> db(new Database());
|
||||||
|
auto entry = db->rootGroup()->addEntryWithPath("/abc");
|
||||||
|
|
||||||
|
QSignalSpy spyDbModified(db.data(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyMetadataModified(db->metadata(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyCustomDataModified(db->metadata()->customData(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyGroupModified(db->rootGroup(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyGroupCustomDataModified(db->rootGroup()->customData(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyEntryModified(entry, SIGNAL(modified()));
|
||||||
|
QSignalSpy spyEntryCustomDataModified(entry->customData(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyEntryAttributesModified(entry->attributes(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyEntryAttachmentModified(entry->attachments(), SIGNAL(modified()));
|
||||||
|
QSignalSpy spyEntryAutoTypeAssociationsModified(entry->autoTypeAssociations(), SIGNAL(modified()));
|
||||||
|
|
||||||
|
QVERIFY(spyDbModified.isValid());
|
||||||
|
QVERIFY(spyMetadataModified.isValid());
|
||||||
|
QVERIFY(spyCustomDataModified.isValid());
|
||||||
|
QVERIFY(spyGroupModified.isValid());
|
||||||
|
QVERIFY(spyGroupCustomDataModified.isValid());
|
||||||
|
QVERIFY(spyEntryModified.isValid());
|
||||||
|
QVERIFY(spyEntryCustomDataModified.isValid());
|
||||||
|
QVERIFY(spyEntryAttributesModified.isValid());
|
||||||
|
QVERIFY(spyEntryAttachmentModified.isValid());
|
||||||
|
QVERIFY(spyEntryAutoTypeAssociationsModified.isValid());
|
||||||
|
|
||||||
|
db->setEmitModified(false);
|
||||||
|
|
||||||
|
auto* group1 = new Group();
|
||||||
|
group1->setParent(db->rootGroup());
|
||||||
|
db->metadata()->setName("Modified Database");
|
||||||
|
db->metadata()->customData()->set("Key", "Value");
|
||||||
|
|
||||||
|
group1->customData()->set("abc", "dd");
|
||||||
|
entry->setTitle("Another Title");
|
||||||
|
entry->customData()->set("entryabc", "dd");
|
||||||
|
entry->attributes()->set("aaa", "dd");
|
||||||
|
entry->attachments()->set("aaa", {});
|
||||||
|
entry->autoTypeAssociations()->add({"", ""});
|
||||||
|
|
||||||
|
db.reset();
|
||||||
|
|
||||||
|
QCOMPARE(spyDbModified.count(), 0);
|
||||||
|
QCOMPARE(spyMetadataModified.count(), 0);
|
||||||
|
QCOMPARE(spyCustomDataModified.count(), 0);
|
||||||
|
QCOMPARE(spyGroupModified.count(), 0);
|
||||||
|
QCOMPARE(spyGroupCustomDataModified.count(), 0);
|
||||||
|
QCOMPARE(spyEntryModified.count(), 0);
|
||||||
|
QCOMPARE(spyEntryCustomDataModified.count(), 0);
|
||||||
|
QCOMPARE(spyEntryAttributesModified.count(), 0);
|
||||||
|
QCOMPARE(spyEntryAttachmentModified.count(), 0);
|
||||||
|
QCOMPARE(spyEntryAutoTypeAssociationsModified.count(), 0);
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ private slots:
|
|||||||
void testHistoryItems();
|
void testHistoryItems();
|
||||||
void testHistoryMaxSize();
|
void testHistoryMaxSize();
|
||||||
void testCustomData();
|
void testCustomData();
|
||||||
|
void testBlockModifiedSignal();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_TESTMODIFIED_H
|
#endif // KEEPASSX_TESTMODIFIED_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user