Move attributes and attachments handking from Entry into own classes.

This commit is contained in:
Felix Geyer 2012-04-14 15:38:20 +02:00
parent dabb1800c6
commit d4a94a8996
12 changed files with 477 additions and 226 deletions

View File

@ -24,6 +24,8 @@ set(keepassx_SOURCES
core/DataPath.cpp
core/Endian.cpp
core/Entry.cpp
core/EntryAttachments.cpp
core/EntryAttributes.cpp
core/Group.cpp
core/Metadata.cpp
core/TimeInfo.cpp
@ -72,6 +74,8 @@ set(keepassx_SOURCES
set(keepassx_MOC
core/Database.h
core/Entry.h
core/EntryAttachments.h
core/EntryAttributes.h
core/Group.h
core/Metadata.h
gui/ChangeMasterKeyWidget.h

View File

@ -22,8 +22,6 @@
#include "core/Group.h"
#include "core/Metadata.h"
const QStringList Entry::m_defaultAttibutes(QStringList() << "Title" << "URL" << "UserName" << "Password" << "Notes");
Entry::Entry()
{
m_group = 0;
@ -34,9 +32,12 @@ Entry::Entry()
m_autoTypeEnabled = true;
m_autoTypeObfuscation = 0;
Q_FOREACH (const QString& key, m_defaultAttibutes) {
setAttribute(key, "");
}
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()));
}
Entry::~Entry()
@ -155,59 +156,49 @@ const QList<AutoTypeAssociation>& Entry::autoTypeAssociations() const
return m_autoTypeAssociations;
}
const QList<QString> Entry::attributes() const
{
return m_attributes.keys();
}
QString Entry::attributeValue(const QString& key) const
{
return m_attributes.value(key);
}
const QList<QString> Entry::attachments() const
{
return m_binaries.keys();
}
QByteArray Entry::attachmentValue(const QString& key) const
{
return m_binaries.value(key);
}
bool Entry::isAttributeProtected(const QString& key) const
{
return m_protectedAttributes.contains(key);
}
bool Entry::isAttachmentProtected(const QString& key) const
{
return m_protectedAttachments.contains(key);
}
QString Entry::title() const
{
return m_attributes.value("Title");
return m_attributes->value("Title");
}
QString Entry::url() const
{
return m_attributes.value("URL");
return m_attributes->value("URL");
}
QString Entry::username() const
{
return m_attributes.value("UserName");
return m_attributes->value("UserName");
}
QString Entry::password() const
{
return m_attributes.value("Password");
return m_attributes->value("Password");
}
QString Entry::notes() const
{
return m_attributes.value("Notes");
return m_attributes->value("Notes");
}
EntryAttributes* Entry::attributes()
{
return m_attributes;
}
const EntryAttributes* Entry::attributes() const
{
return m_attributes;
}
EntryAttachments* Entry::attachments()
{
return m_attachments;
}
const EntryAttachments* Entry::attachments() const
{
return m_attachments;
}
void Entry::setUuid(const Uuid& uuid)
@ -290,137 +281,29 @@ void Entry::addAutoTypeAssociation(const AutoTypeAssociation& assoc)
Q_EMIT modified();
}
void Entry::setAttribute(const QString& key, const QString& value, bool protect)
{
bool emitModified = false;
bool addAttribute = !m_attributes.contains(key);
bool defaultAttribute = isDefaultAttribute(key);
if (addAttribute && !defaultAttribute) {
Q_EMIT attributeAboutToBeAdded(key);
}
if (addAttribute || m_attributes.value(key) != value) {
m_attributes.insert(key, value);
emitModified = true;
}
if (protect) {
if (!m_protectedAttributes.contains(key)) {
emitModified = true;
}
m_protectedAttributes.insert(key);
}
else if (m_protectedAttributes.remove(key)) {
emitModified = true;
}
if (emitModified) {
Q_EMIT modified();
}
if (defaultAttribute) {
Q_EMIT dataChanged(this);
}
else if (addAttribute) {
Q_EMIT attributeAdded(key);
}
else {
Q_EMIT attributeChanged(key);
}
}
void Entry::removeAttribute(const QString& key)
{
Q_ASSERT(!isDefaultAttribute(key));
if (!m_attributes.contains(key)) {
Q_ASSERT(false);
return;
}
Q_EMIT attributeAboutToBeRemoved(key);
m_attributes.remove(key);
m_protectedAttributes.remove(key);
Q_EMIT attributeRemoved(key);
Q_EMIT modified();
}
void Entry::setAttachment(const QString& key, const QByteArray& value, bool protect)
{
bool emitModified = false;
bool addAttachment = !m_binaries.contains(key);
if (addAttachment || m_binaries.value(key) != value) {
Q_EMIT attachmentAboutToBeAdded(key);
m_binaries.insert(key, value);
emitModified = true;
}
if (protect) {
if (!m_protectedAttachments.contains(key)) {
emitModified = true;
}
m_protectedAttachments.insert(key);
}
else if (m_protectedAttachments.remove(key)) {
emitModified = true;
}
if (addAttachment) {
Q_EMIT attachmentAdded(key);
}
else {
Q_EMIT attachmentChanged(key);
}
if (emitModified) {
Q_EMIT modified();
}
}
void Entry::removeAttachment(const QString& key)
{
if (!m_binaries.contains(key)) {
Q_ASSERT(false);
return;
}
Q_EMIT attachmentAboutToBeRemoved(key);
m_binaries.remove(key);
m_protectedAttachments.remove(key);
Q_EMIT attachmentRemoved(key);
Q_EMIT modified();
}
void Entry::setTitle(const QString& title)
{
setAttribute("Title", title);
m_attributes->set("Title", title);
}
void Entry::setUrl(const QString& url)
{
setAttribute("URL", url);
m_attributes->set("URL", url);
}
void Entry::setUsername(const QString& username)
{
setAttribute("UserName", username);
m_attributes->set("UserName", username);
}
void Entry::setPassword(const QString& password)
{
setAttribute("Password", password);
m_attributes->set("Password", password);
}
void Entry::setNotes(const QString& notes)
{
setAttribute("Notes", notes);
m_attributes->set("Notes", notes);
}
QList<Entry*> Entry::historyItems()
@ -457,7 +340,7 @@ void Entry::setGroup(Group* group)
QObject::setParent(group);
}
bool Entry::isDefaultAttribute(const QString& key)
void Entry::emitDataChanged()
{
return m_defaultAttibutes.contains(key);
Q_EMIT dataChanged(this);
}

View File

@ -27,6 +27,8 @@
#include <QtGui/QPixmap>
#include <QtGui/QPixmapCache>
#include "core/EntryAttachments.h"
#include "core/EntryAttributes.h"
#include "core/TimeInfo.h"
#include "core/Uuid.h"
@ -60,17 +62,15 @@ public:
int autoTypeObfuscation() const;
QString defaultAutoTypeSequence() const;
const QList<AutoTypeAssociation>& autoTypeAssociations() const;
const QList<QString> attributes() const;
QString attributeValue(const QString& key) const;
const QList<QString> attachments() const;
QByteArray attachmentValue(const QString& key) const;
bool isAttributeProtected(const QString& key) const;
bool isAttachmentProtected(const QString& key) const;
QString title() const;
QString url() const;
QString username() const;
QString password() const;
QString notes() const;
EntryAttributes* attributes();
const EntryAttributes* attributes() const;
EntryAttachments* attachments();
const EntryAttachments* attachments() const;
void setUuid(const Uuid& uuid);
void setIcon(int iconNumber);
@ -84,10 +84,6 @@ public:
void setAutoTypeObfuscation(int obfuscation);
void setDefaultAutoTypeSequence(const QString& sequence);
void addAutoTypeAssociation(const AutoTypeAssociation& assoc);
void setAttribute(const QString& key, const QString& value, bool protect = false);
void removeAttribute(const QString& key);
void setAttachment(const QString& key, const QByteArray& value, bool protect = false);
void removeAttachment(const QString& key);
void setTitle(const QString& title);
void setUrl(const QString& url);
void setUsername(const QString& username);
@ -103,28 +99,17 @@ public:
void setUpdateTimeinfo(bool value);
static bool isDefaultAttribute(const QString& key);
Q_SIGNALS:
/**
* Emitted when a default attribute has been changed.
*/
void dataChanged(Entry* entry);
void attributeChanged(QString key);
void attributeAboutToBeAdded(QString key);
void attributeAdded(QString key);
void attributeAboutToBeRemoved(QString key);
void attributeRemoved(QString key);
void attachmentChanged(QString key);
void attachmentAboutToBeAdded(QString key);
void attachmentAdded(QString key);
void attachmentAboutToBeRemoved(QString key);
void attachmentRemoved(QString key);
void modified();
private Q_SLOTS:
void emitDataChanged();
private:
Uuid m_uuid;
int m_iconNumber;
@ -138,16 +123,13 @@ private:
int m_autoTypeObfuscation;
QString m_defaultAutoTypeSequence;
QList<AutoTypeAssociation> m_autoTypeAssociations;
QMap<QString, QString> m_attributes;
QMap<QString, QByteArray> m_binaries;
QSet<QString> m_protectedAttributes;
QSet<QString> m_protectedAttachments;
EntryAttributes* m_attributes;
EntryAttachments* m_attachments;
QList<Entry*> m_history;
QPointer<Group> m_group;
const Database* m_db;
QPixmapCache::Key m_pixmapCacheKey;
const static QStringList m_defaultAttibutes;
bool m_updateTimeinfo;
template <class T> inline bool set(T& property, const T& value);

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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 "EntryAttachments.h"
EntryAttachments::EntryAttachments(QObject* parent)
: QObject(parent)
{
}
QList<QString> EntryAttachments::keys() const
{
return m_attachments.keys();
}
QByteArray EntryAttachments::value(const QString& key) const
{
return m_attachments.value(key);
}
bool EntryAttachments::isProtected(const QString& key) const
{
return m_protectedAttachments.contains(key);
}
void EntryAttachments::set(const QString& key, const QByteArray& value, bool protect)
{
bool emitModified = false;
bool addAttachment = !m_attachments.contains(key);
if (addAttachment) {
Q_EMIT aboutToBeAdded(key);
}
if (addAttachment || m_attachments.value(key) != value) {
m_attachments.insert(key, value);
emitModified = true;
}
if (protect != m_protectedAttachments.contains(key)) {
if (protect) {
m_protectedAttachments.insert(key);
}
else {
m_protectedAttachments.remove(key);
}
emitModified = true;
}
if (addAttachment) {
Q_EMIT added(key);
}
else {
Q_EMIT keyModified(key);
}
if (emitModified) {
Q_EMIT modified();
}
}
void EntryAttachments::remove(const QString& key)
{
if (!m_attachments.contains(key)) {
Q_ASSERT(false);
return;
}
Q_EMIT aboutToBeRemoved(key);
m_attachments.remove(key);
m_protectedAttachments.remove(key);
Q_EMIT removed(key);
Q_EMIT modified();
}
void EntryAttachments::copyFrom(const EntryAttachments* other)
{
if (*this != *other) {
Q_EMIT aboutToBeReset();
m_attachments.clear();
m_protectedAttachments.clear();
Q_FOREACH (const QString& key, other->keys()) {
m_attachments.insert(key, other->value(key));
if (other->isProtected(key)) {
m_protectedAttachments.insert(key);
}
}
Q_EMIT reset();
Q_EMIT modified();
}
}
void EntryAttachments::clear()
{
Q_EMIT aboutToBeReset();
m_attachments.clear();
m_protectedAttachments.clear();
Q_EMIT reset();
Q_EMIT modified();
}
bool EntryAttachments::operator!=(const EntryAttachments& other) const
{
return m_attachments != other.m_attachments || m_protectedAttachments != other.m_protectedAttachments;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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_ENTRYATTACHMENTS_H
#define KEEPASSX_ENTRYATTACHMENTS_H
#include <QtCore/QMap>
#include <QtCore/QSet>
class EntryAttachments : public QObject
{
Q_OBJECT
public:
explicit EntryAttachments(QObject* parent = 0);
QList<QString> keys() const;
QByteArray value(const QString& key) const;
bool isProtected(const QString& key) const;
void set(const QString& key, const QByteArray& value, bool protect = false);
void remove(const QString& key);
void copyFrom(const EntryAttachments* other);
void clear();
bool operator!=(const EntryAttachments& other) const;
Q_SIGNALS:
void modified();
void keyModified(QString key);
void aboutToBeAdded(QString key);
void added(QString key);
void aboutToBeRemoved(QString key);
void removed(QString key);
void aboutToBeReset();
void reset();
private:
QMap<QString, QByteArray> m_attachments;
QSet<QString> m_protectedAttachments;
};
#endif // KEEPASSX_ENTRYATTACHMENTS_H

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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 "EntryAttributes.h"
const QStringList EntryAttributes::m_defaultAttibutes(QStringList() << "Title" << "URL" << "UserName" << "Password" << "Notes");
EntryAttributes::EntryAttributes(QObject* parent)
: QObject(parent)
{
Q_FOREACH (const QString& key, m_defaultAttibutes) {
set(key, "");
}
}
QList<QString> EntryAttributes::keys() const
{
return m_attributes.keys();
}
QString EntryAttributes::value(const QString& key) const
{
return m_attributes.value(key);
}
bool EntryAttributes::isProtected(const QString& key) const
{
return m_protectedAttributes.contains(key);
}
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
{
bool emitModified = false;
bool addAttribute = !m_attributes.contains(key);
bool defaultAttribute = isDefaultAttribute(key);
if (addAttribute && !defaultAttribute) {
Q_EMIT aboutToBeAdded(key);
}
if (addAttribute || m_attributes.value(key) != value) {
m_attributes.insert(key, value);
emitModified = true;
}
if (protect) {
if (!m_protectedAttributes.contains(key)) {
emitModified = true;
}
m_protectedAttributes.insert(key);
}
else if (m_protectedAttributes.remove(key)) {
emitModified = true;
}
if (emitModified) {
Q_EMIT modified();
}
if (defaultAttribute) {
Q_EMIT defaultKeyModified();
}
else if (addAttribute) {
Q_EMIT added(key);
}
else if (emitModified) {
Q_EMIT customKeyModified(key);
}
}
void EntryAttributes::remove(const QString& key)
{
Q_ASSERT(!isDefaultAttribute(key));
if (!m_attributes.contains(key)) {
Q_ASSERT(false);
return;
}
Q_EMIT aboutToBeRemoved(key);
m_attributes.remove(key);
m_protectedAttributes.remove(key);
Q_EMIT removed(key);
Q_EMIT modified();
}
void EntryAttributes::copyFrom(const EntryAttributes* other)
{
if (*this != *other) {
Q_EMIT aboutToBeReset();
m_attributes.clear();
m_protectedAttributes.clear();
Q_FOREACH (const QString& key, other->keys()) {
m_attributes.insert(key, other->value(key));
if (other->isProtected(key)) {
m_protectedAttributes.insert(key);
}
}
Q_EMIT reset();
Q_EMIT modified();
}
}
void EntryAttributes::clear()
{
Q_EMIT aboutToBeReset();
m_attributes.clear();
m_protectedAttributes.clear();
Q_EMIT reset();
Q_EMIT modified();
}
bool EntryAttributes::operator!=(const EntryAttributes& other) const
{
return m_attributes != other.m_attributes || m_protectedAttributes != other.m_protectedAttributes;
}
bool EntryAttributes::isDefaultAttribute(const QString& key)
{
return m_defaultAttibutes.contains(key);
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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_ENTRYATTRIBUTES_H
#define KEEPASSX_ENTRYATTRIBUTES_H
#include <QtCore/QMap>
#include <QtCore/QSet>
#include <QtCore/QObject>
#include <QtCore/QStringList>
class EntryAttributes : public QObject
{
Q_OBJECT
public:
explicit EntryAttributes(QObject* parent = 0);
QList<QString> keys() const;
QString value(const QString& key) const;
bool isProtected(const QString& key) const;
void set(const QString& key, const QString& value, bool protect = false);
void remove(const QString& key);
void copyFrom(const EntryAttributes* other);
void clear();
bool operator!=(const EntryAttributes& other) const;
static bool isDefaultAttribute(const QString& key);
Q_SIGNALS:
void modified();
void defaultKeyModified();
void customKeyModified(QString key);
void aboutToBeAdded(QString key);
void added(QString key);
void aboutToBeRemoved(QString key);
void removed(QString key);
void aboutToBeReset();
void reset();
private:
QMap<QString, QString> m_attributes;
QSet<QString> m_protectedAttributes;
const static QStringList m_defaultAttibutes;
};
#endif // KEEPASSX_ENTRYATTRIBUTES_H

View File

@ -555,7 +555,7 @@ void KeePass2XmlReader::parseEntryString(Entry *entry)
}
}
entry->setAttribute(key, value, isProtected);
entry->attributes()->set(key, value, isProtected);
}
else {
skipCurrentElement();
@ -582,7 +582,7 @@ void KeePass2XmlReader::parseEntryBinary(Entry *entry)
m_randomStream->processInPlace(value);
}
entry->setAttachment(key, value, isProtected);
entry->attachments()->set(key, value, isProtected);
}
else {
skipCurrentElement();

View File

@ -254,7 +254,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
writeString("Tags", entry->tags());
writeTimes(entry->timeInfo());
Q_FOREACH (const QString& key, entry->attributes()) {
Q_FOREACH (const QString& key, entry->attributes()->keys()) {
m_xml.writeStartElement("String");
bool protect = ( ((key == "Title") && m_meta->protectTitle()) ||
@ -262,7 +262,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
((key == "Password") && m_meta->protectPassword()) ||
((key == "URL") && m_meta->protectUrl()) ||
((key == "Notes") && m_meta->protectNotes()) ||
entry->isAttributeProtected(key) ) &&
entry->attributes()->isProtected(key) ) &&
m_randomStream;
writeString("Key", key);
@ -272,11 +272,11 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
if (protect) {
m_xml.writeAttribute("Protected", "True");
QByteArray rawData = m_randomStream->process(entry->attributeValue(key).toUtf8());
QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8());
value = QString::fromAscii(rawData.toBase64());
}
else {
value = entry->attributeValue(key);
value = entry->attributes()->value(key);
}
m_xml.writeCharacters(value);
@ -285,10 +285,10 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
m_xml.writeEndElement();
}
Q_FOREACH (const QString& key, entry->attachments()) {
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
m_xml.writeStartElement("Binary");
bool protect = entry->isAttachmentProtected(key) && m_randomStream;
bool protect = entry->attachments()->isProtected(key) && m_randomStream;
writeString("Key", key);
@ -297,11 +297,11 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
if (protect) {
m_xml.writeAttribute("Protected", "True");
QByteArray rawData = m_randomStream->process(entry->attachmentValue(key));
QByteArray rawData = m_randomStream->process(entry->attachments()->value(key));
value = QString::fromAscii(rawData.toBase64());
}
else {
value = entry->attachmentValue(key);
value = entry->attachments()->value(key);
}
m_xml.writeCharacters(value);

View File

@ -79,14 +79,14 @@ void TestKeePass2Reader::testProtectedStrings()
QCOMPARE(entry->title(), QString("Sample Entry"));
QCOMPARE(entry->username(), QString("Protected User Name"));
QCOMPARE(entry->password(), QString("ProtectedPassword"));
QCOMPARE(entry->attributeValue("TestProtected"), QString("ABC"));
QCOMPARE(entry->attributeValue("TestUnprotected"), QString("DEF"));
QCOMPARE(entry->attributes()->value("TestProtected"), QString("ABC"));
QCOMPARE(entry->attributes()->value("TestUnprotected"), QString("DEF"));
QVERIFY(!db->metadata()->protectTitle());
QVERIFY(db->metadata()->protectUsername());
QVERIFY(db->metadata()->protectPassword());
QVERIFY(entry->isAttributeProtected("TestProtected"));
QVERIFY(!entry->isAttributeProtected("TestUnprotected"));
QVERIFY(entry->attributes()->isProtected("TestProtected"));
QVERIFY(!entry->attributes()->isProtected("TestUnprotected"));
delete db;
delete reader;

View File

@ -44,8 +44,8 @@ void TestKeePass2Writer::initTestCase()
group->setNotes("I'm a note!");
Entry* entry = new Entry();
entry->setUuid(Uuid::random());
entry->setAttribute("test", "protectedTest", true);
QVERIFY(entry->isAttributeProtected("test"));
entry->attributes()->set("test", "protectedTest", true);
QVERIFY(entry->attributes()->isProtected("test"));
entry->setGroup(group);
Group* groupNew = new Group();
groupNew->setUuid(Uuid::random());
@ -79,8 +79,8 @@ void TestKeePass2Writer::testProtectedAttributes()
{
QCOMPARE(m_dbTest->rootGroup()->entries().size(), 1);
Entry* entry = m_dbTest->rootGroup()->entries().at(0);
QCOMPARE(entry->attributeValue("test"), QString("protectedTest"));
QCOMPARE(entry->isAttributeProtected("test"), true);
QCOMPARE(entry->attributes()->value("test"), QString("protectedTest"));
QCOMPARE(entry->attributes()->isProtected("test"), true);
}
KEEPASSX_QTEST_CORE_MAIN(TestKeePass2Writer)

View File

@ -214,26 +214,26 @@ void TestKeePass2XmlReader::testEntry1()
QCOMPARE(ti.usageCount(), 8);
QCOMPARE(ti.locationChanged(), genDT(2010, 8, 25, 16, 13, 54));
QList<QString> attrs = entry->attributes();
QCOMPARE(entry->attributeValue("Notes"), QString("Notes"));
QList<QString> attrs = entry->attributes()->keys();
QCOMPARE(entry->attributes()->value("Notes"), QString("Notes"));
QVERIFY(attrs.removeOne("Notes"));
QCOMPARE(entry->attributeValue("Password"), QString("Password"));
QCOMPARE(entry->attributes()->value("Password"), QString("Password"));
QVERIFY(attrs.removeOne("Password"));
QCOMPARE(entry->attributeValue("Title"), QString("Sample Entry 1"));
QCOMPARE(entry->attributes()->value("Title"), QString("Sample Entry 1"));
QVERIFY(attrs.removeOne("Title"));
QCOMPARE(entry->attributeValue("URL"), QString(""));
QCOMPARE(entry->attributes()->value("URL"), QString(""));
QVERIFY(attrs.removeOne("URL"));
QCOMPARE(entry->attributeValue("UserName"), QString("User Name"));
QCOMPARE(entry->attributes()->value("UserName"), QString("User Name"));
QVERIFY(attrs.removeOne("UserName"));
QVERIFY(attrs.isEmpty());
QCOMPARE(entry->title(), entry->attributeValue("Title"));
QCOMPARE(entry->url(), entry->attributeValue("URL"));
QCOMPARE(entry->username(), entry->attributeValue("UserName"));
QCOMPARE(entry->password(), entry->attributeValue("Password"));
QCOMPARE(entry->notes(), entry->attributeValue("Notes"));
QCOMPARE(entry->title(), entry->attributes()->value("Title"));
QCOMPARE(entry->url(), entry->attributes()->value("URL"));
QCOMPARE(entry->username(), entry->attributes()->value("UserName"));
QCOMPARE(entry->password(), entry->attributes()->value("Password"));
QCOMPARE(entry->notes(), entry->attributes()->value("Notes"));
QCOMPARE(entry->attachments().size(), 0);
QCOMPARE(entry->attachments()->keys().size(), 0);
QCOMPARE(entry->autoTypeEnabled(), false);
QCOMPARE(entry->autoTypeObfuscation(), 0);
QCOMPARE(entry->defaultAutoTypeSequence(), QString(""));
@ -258,25 +258,25 @@ void TestKeePass2XmlReader::testEntry2()
const TimeInfo ti = entry->timeInfo();
QCOMPARE(ti.usageCount(), 7);
QList<QString> attrs = entry->attributes();
QCOMPARE(entry->attributeValue("CustomString"), QString("isavalue"));
QList<QString> attrs = entry->attributes()->keys();
QCOMPARE(entry->attributes()->value("CustomString"), QString("isavalue"));
QVERIFY(attrs.removeOne("CustomString"));
QCOMPARE(entry->attributeValue("Notes"), QString(""));
QCOMPARE(entry->attributes()->value("Notes"), QString(""));
QVERIFY(attrs.removeOne("Notes"));
QCOMPARE(entry->attributeValue("Password"), QString("Jer60Hz8o9XHvxBGcRqT"));
QCOMPARE(entry->attributes()->value("Password"), QString("Jer60Hz8o9XHvxBGcRqT"));
QVERIFY(attrs.removeOne("Password"));
QCOMPARE(entry->attributeValue("Protected String"), QString("y")); // TODO should have a protection attribute
QCOMPARE(entry->attributes()->value("Protected String"), QString("y")); // TODO should have a protection attribute
QVERIFY(attrs.removeOne("Protected String"));
QCOMPARE(entry->attributeValue("Title"), QString("Sample Entry 2"));
QCOMPARE(entry->attributes()->value("Title"), QString("Sample Entry 2"));
QVERIFY(attrs.removeOne("Title"));
QCOMPARE(entry->attributeValue("URL"), QString("http://www.keepassx.org/"));
QCOMPARE(entry->attributes()->value("URL"), QString("http://www.keepassx.org/"));
QVERIFY(attrs.removeOne("URL"));
QCOMPARE(entry->attributeValue("UserName"), QString("notDEFUSERNAME"));
QCOMPARE(entry->attributes()->value("UserName"), QString("notDEFUSERNAME"));
QVERIFY(attrs.removeOne("UserName"));
QVERIFY(attrs.isEmpty());
QCOMPARE(entry->attachments().size(), 1);
QCOMPARE(QString(entry->attachmentValue("testattach.txt")), QString("42"));
QCOMPARE(entry->attachments()->keys().size(), 1);
QCOMPARE(QString(entry->attachments()->value("testattach.txt")), QString("42"));
QCOMPARE(entry->autoTypeEnabled(), true);
QCOMPARE(entry->autoTypeObfuscation(), 1);
@ -299,7 +299,6 @@ void TestKeePass2XmlReader::testEntryHistory()
const Entry* entry = entryMain->historyItems().at(0);
QCOMPARE(entry->uuid(), entryMain->uuid());
QVERIFY(!entry->parent());
QCOMPARE(entry->children().size(), 0);
QCOMPARE(entry->timeInfo().lastModificationTime(), genDT(2010, 8, 25, 16, 13, 54));
QCOMPARE(entry->timeInfo().usageCount(), 3);
QCOMPARE(entry->title(), QString("Sample Entry"));
@ -310,7 +309,6 @@ void TestKeePass2XmlReader::testEntryHistory()
const Entry* entry = entryMain->historyItems().at(1);
QCOMPARE(entry->uuid(), entryMain->uuid());
QVERIFY(!entry->parent());
QCOMPARE(entry->children().size(), 0);
QCOMPARE(entry->timeInfo().lastModificationTime(), genDT(2010, 8, 25, 16, 15, 43));
QCOMPARE(entry->timeInfo().usageCount(), 7);
QCOMPARE(entry->title(), QString("Sample Entry 1"));