diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 313241245..146bc1957 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,7 @@ set(keepassx_SOURCES autotype/AutoType.cpp autotype/AutoTypeAction.cpp autotype/ShortcutWidget.cpp + core/AutoTypeAssociations.cpp core/Config.cpp core/Database.cpp core/DatabaseIcons.cpp @@ -97,6 +98,7 @@ set(keepassx_SOURCES set(keepassx_MOC autotype/AutoType.h autotype/ShortcutWidget.h + core/AutoTypeAssociations.h core/Config.h core/Database.h core/Entry.h diff --git a/src/core/AutoTypeAssociations.cpp b/src/core/AutoTypeAssociations.cpp new file mode 100644 index 000000000..d96901294 --- /dev/null +++ b/src/core/AutoTypeAssociations.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * 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 . + */ + +#include "AutoTypeAssociations.h" + +bool AutoTypeAssociations::Association::operator==(const AutoTypeAssociations::Association& other) const +{ + return window == other.window && sequence == other.sequence; +} + +bool AutoTypeAssociations::Association::operator!=(const AutoTypeAssociations::Association& other) const +{ + return window != other.window || sequence != other.sequence; +} + + +AutoTypeAssociations::AutoTypeAssociations(QObject* parent) + : QObject(parent) +{ +} + +void AutoTypeAssociations::copyDataFrom(const AutoTypeAssociations* other) +{ + if (m_associations == other->m_associations) { + return; + } + + Q_EMIT aboutToReset(); + m_associations = other->m_associations; + Q_EMIT reset(); + Q_EMIT modified(); +} + +void AutoTypeAssociations::add(const AutoTypeAssociations::Association& association) +{ + int index = m_associations.size(); + Q_EMIT aboutToAdd(index); + m_associations.append(association); + Q_EMIT added(index); + Q_EMIT modified(); +} + +void AutoTypeAssociations::remove(int index) +{ + Q_ASSERT(index >= 0 && index < m_associations.size()); + + Q_EMIT aboutToRemove(index); + m_associations.removeAt(index); + Q_EMIT removed(index); + Q_EMIT modified(); +} + +void AutoTypeAssociations::update(int index, const AutoTypeAssociations::Association& association) +{ + Q_ASSERT(index >= 0 && index < m_associations.size()); + + if (m_associations.at(index) != association) { + m_associations[index] = association; + Q_EMIT dataChanged(index); + Q_EMIT modified(); + } +} + +AutoTypeAssociations::Association AutoTypeAssociations::get(int index) const +{ + Q_ASSERT(index >= 0 && index < m_associations.size()); + + return m_associations.at(index); +} + +QList AutoTypeAssociations::getAll() const +{ + return m_associations; +} + +int AutoTypeAssociations::size() const +{ + return m_associations.size(); +} + +void AutoTypeAssociations::clear() +{ + m_associations.clear(); +} diff --git a/src/core/AutoTypeAssociations.h b/src/core/AutoTypeAssociations.h new file mode 100644 index 000000000..dd7ddf782 --- /dev/null +++ b/src/core/AutoTypeAssociations.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * 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 . + */ + +#ifndef KEEPASSX_AUTOTYPEASSOCIATIONS_H +#define KEEPASSX_AUTOTYPEASSOCIATIONS_H + +#include + +#include "core/Global.h" + +class AutoTypeAssociations : public QObject +{ + Q_OBJECT + +public: + struct Association + { + QString window; + QString sequence; + + bool operator==(const AutoTypeAssociations::Association& other) const; + bool operator!=(const AutoTypeAssociations::Association& other) const; + }; + + explicit AutoTypeAssociations(QObject* parent = Q_NULLPTR); + void copyDataFrom(const AutoTypeAssociations* other); + void add(const AutoTypeAssociations::Association& association); + void remove(int index); + void update(int index, const AutoTypeAssociations::Association& association); + AutoTypeAssociations::Association get(int index) const; + QList getAll() const; + int size() const; + void clear(); + +private: + QList m_associations; + +Q_SIGNALS: + void modified(); + void dataChanged(int index); + void aboutToAdd(int index); + void added(int index); + void aboutToRemove(int index); + void removed(int index); + void aboutToReset(); + void reset(); +}; + +Q_DECLARE_TYPEINFO(AutoTypeAssociations::Association, Q_MOVABLE_TYPE); + +#endif // KEEPASSX_AUTOTYPEASSOCIATIONS_H diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 58fe6e3b1..07faa9c1f 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -26,6 +26,9 @@ const int Entry::DefaultIconNumber = 0; Entry::Entry() + : m_attributes(new EntryAttributes(this)) + , m_attachments(new EntryAttachments(this)) + , m_autoTypeAssociations(new AutoTypeAssociations(this)) { m_updateTimeinfo = true; m_tmpHistoryItem = Q_NULLPTR; @@ -34,14 +37,12 @@ Entry::Entry() m_data.autoTypeEnabled = true; m_data.autoTypeObfuscation = 0; - m_attributes = new EntryAttributes(this); connect(m_attributes, SIGNAL(modified()), this, SIGNAL(modified())); connect(m_attributes, SIGNAL(defaultKeyModified()), SLOT(emitDataChanged())); - - m_attachments = new EntryAttachments(this); connect(m_attachments, SIGNAL(modified()), this, SIGNAL(modified())); - connect(this, SIGNAL(modified()), this, SLOT(updateTimeinfo())); + connect(m_autoTypeAssociations, SIGNAL(modified()), SIGNAL(modified())); + connect(this, SIGNAL(modified()), SLOT(updateTimeinfo())); connect(this, SIGNAL(modified()), SLOT(updateModifiedSinceBegin())); } @@ -166,9 +167,14 @@ QString Entry::defaultAutoTypeSequence() const return m_data.defaultAutoTypeSequence; } -const QList& Entry::autoTypeAssociations() const +AutoTypeAssociations* Entry::autoTypeAssociations() { - return m_data.autoTypeAssociations; + return m_autoTypeAssociations; +} + +const AutoTypeAssociations* Entry::autoTypeAssociations() const +{ + return m_autoTypeAssociations; } QString Entry::autoTypeSequence(const QString& windowTitle) const @@ -180,9 +186,9 @@ QString Entry::autoTypeSequence(const QString& windowTitle) const bool enableSet = false; QString sequence; if (!windowTitle.isEmpty()) { - Q_FOREACH (const AutoTypeAssociation& autoTypeAssoc, m_data.autoTypeAssociations) { - if (windowMatches(windowTitle, autoTypeAssoc.window)) { - sequence = autoTypeAssoc.sequence; + Q_FOREACH (const AutoTypeAssociations::Association& assoc, m_autoTypeAssociations->getAll()) { + if (windowMatches(windowTitle, assoc.window)) { + sequence = assoc.sequence; break; } } @@ -354,12 +360,6 @@ void Entry::setDefaultAutoTypeSequence(const QString& sequence) set(m_data.defaultAutoTypeSequence, sequence); } -void Entry::addAutoTypeAssociation(const AutoTypeAssociation& assoc) -{ - m_data.autoTypeAssociations << assoc; - Q_EMIT modified(); -} - void Entry::setTitle(const QString& title) { m_attributes->set("Title", title, m_attributes->isProtected("Title")); @@ -495,6 +495,7 @@ Entry* Entry::clone() const entry->m_data = m_data; *entry->m_attributes = *m_attributes; *entry->m_attachments = *m_attachments; + entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations); entry->setUpdateTimeinfo(true); return entry; diff --git a/src/core/Entry.h b/src/core/Entry.h index 599d35926..f3536fa9e 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -27,6 +27,7 @@ #include #include +#include "core/AutoTypeAssociations.h" #include "core/EntryAttachments.h" #include "core/EntryAttributes.h" #include "core/Global.h" @@ -36,14 +37,6 @@ class Database; class Group; -struct AutoTypeAssociation -{ - QString window; - QString sequence; -}; - -Q_DECLARE_TYPEINFO(AutoTypeAssociation, Q_MOVABLE_TYPE); - struct EntryData { int iconNumber; @@ -55,7 +48,6 @@ struct EntryData bool autoTypeEnabled; int autoTypeObfuscation; QString defaultAutoTypeSequence; - QList autoTypeAssociations; TimeInfo timeInfo; }; @@ -79,7 +71,8 @@ public: bool autoTypeEnabled() const; int autoTypeObfuscation() const; QString defaultAutoTypeSequence() const; - const QList& autoTypeAssociations() const; + AutoTypeAssociations* autoTypeAssociations(); + const AutoTypeAssociations* autoTypeAssociations() const; QString autoTypeSequence(const QString& windowTitle = QString()) const; QString title() const; QString url() const; @@ -105,7 +98,6 @@ public: void setAutoTypeEnabled(bool enable); void setAutoTypeObfuscation(int obfuscation); void setDefaultAutoTypeSequence(const QString& sequence); - void addAutoTypeAssociation(const AutoTypeAssociation& assoc); void setTitle(const QString& title); void setUrl(const QString& url); void setUsername(const QString& username); @@ -156,8 +148,9 @@ private: Uuid m_uuid; EntryData m_data; - EntryAttributes* m_attributes; - EntryAttachments* m_attachments; + EntryAttributes* const m_attributes; + EntryAttachments* const m_attachments; + AutoTypeAssociations* const m_autoTypeAssociations; QList m_history; Entry* m_tmpHistoryItem; diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index 14f6ef330..1ddbca49d 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -712,14 +712,14 @@ void KeePass2XmlReader::parseAutoTypeAssoc(Entry* entry) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association"); - AutoTypeAssociation assoc; + AutoTypeAssociations::Association assoc; while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Window") { assoc.window = readString(); } else if (m_xml.name() == "KeystrokeSequence") { assoc.sequence = readString(); - entry->addAutoTypeAssociation(assoc); + entry->autoTypeAssociations()->add(assoc); } else { skipCurrentElement(); diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index d18f6d563..8bd4649b8 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -384,14 +384,14 @@ void KeePass2XmlWriter::writeAutoType(const Entry* entry) writeNumber("DataTransferObfuscation", entry->autoTypeObfuscation()); writeString("DefaultSequence", entry->defaultAutoTypeSequence()); - Q_FOREACH (const AutoTypeAssociation& assoc, entry->autoTypeAssociations()) { + Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) { writeAutoTypeAssoc(assoc); } m_xml.writeEndElement(); } -void KeePass2XmlWriter::writeAutoTypeAssoc(const AutoTypeAssociation& assoc) +void KeePass2XmlWriter::writeAutoTypeAssoc(const AutoTypeAssociations::Association& assoc) { m_xml.writeStartElement("Association"); diff --git a/src/format/KeePass2XmlWriter.h b/src/format/KeePass2XmlWriter.h index 35666f0b0..7706c2625 100644 --- a/src/format/KeePass2XmlWriter.h +++ b/src/format/KeePass2XmlWriter.h @@ -58,7 +58,7 @@ private: void writeDeletedObject(const DeletedObject& delObj); void writeEntry(const Entry* entry); void writeAutoType(const Entry* entry); - void writeAutoTypeAssoc(const AutoTypeAssociation& assoc); + void writeAutoTypeAssoc(const AutoTypeAssociations::Association& assoc); void writeEntryHistory(const Entry* entry); void writeString(const QString& qualifiedName, const QString& string); diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index d730696b7..d7e531853 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -255,8 +255,8 @@ void TestKeePass2XmlReader::testEntry1() QCOMPARE(entry->autoTypeEnabled(), false); QCOMPARE(entry->autoTypeObfuscation(), 0); QCOMPARE(entry->defaultAutoTypeSequence(), QString("")); - QCOMPARE(entry->autoTypeAssociations().size(), 1); - const AutoTypeAssociation assoc1 = entry->autoTypeAssociations().at(0); + QCOMPARE(entry->autoTypeAssociations()->size(), 1); + const AutoTypeAssociations::Association assoc1 = entry->autoTypeAssociations()->get(0); QCOMPARE(assoc1.window, QString("Target Window")); QCOMPARE(assoc1.sequence, QString("")); } @@ -300,11 +300,11 @@ void TestKeePass2XmlReader::testEntry2() QCOMPARE(entry->autoTypeEnabled(), true); QCOMPARE(entry->autoTypeObfuscation(), 1); QCOMPARE(entry->defaultAutoTypeSequence(), QString("{USERNAME}{TAB}{PASSWORD}{ENTER}")); - QCOMPARE(entry->autoTypeAssociations().size(), 2); - const AutoTypeAssociation assoc1 = entry->autoTypeAssociations().at(0); + QCOMPARE(entry->autoTypeAssociations()->size(), 2); + const AutoTypeAssociations::Association assoc1 = entry->autoTypeAssociations()->get(0); QCOMPARE(assoc1.window, QString("Target Window")); QCOMPARE(assoc1.sequence, QString("{Title}{UserName}")); - const AutoTypeAssociation assoc2 = entry->autoTypeAssociations().at(1); + const AutoTypeAssociations::Association assoc2 = entry->autoTypeAssociations()->get(1); QCOMPARE(assoc2.window, QString("Target Window 2")); QCOMPARE(assoc2.sequence, QString("{Title}{UserName} test")); }