diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c56d9e8..d6c44805 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,6 +55,8 @@ set(keepassx_SOURCES gui/DatabaseWidget.cpp gui/EditEntryWidget.cpp gui/EditGroupWidget.cpp + gui/EntryAttachmentsModel.cpp + gui/EntryAttributesModel.cpp gui/EntryModel.cpp gui/EntryView.cpp gui/FileDialog.cpp @@ -84,6 +86,8 @@ set(keepassx_MOC gui/DatabaseWidget.h gui/EditEntryWidget.h gui/EditGroupWidget.h + gui/EntryAttachmentsModel.h + gui/EntryAttributesModel.h gui/EntryModel.h gui/EntryView.h gui/GroupModel.h diff --git a/src/gui/EntryAttachmentsModel.cpp b/src/gui/EntryAttachmentsModel.cpp new file mode 100644 index 00000000..dc98328b --- /dev/null +++ b/src/gui/EntryAttachmentsModel.cpp @@ -0,0 +1,142 @@ +/* + * 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 "EntryAttachmentsModel.h" + +#include "core/Entry.h" +#include "core/Tools.h" + +EntryAttachmentsModel::EntryAttachmentsModel(QObject* parent) + : QAbstractTableModel(parent) + , m_entryAttachments(0) +{ +} + +void EntryAttachmentsModel::setEntryAttachments(EntryAttachments* entryAttachments) +{ + beginResetModel(); + + if (m_entryAttachments) { + m_entryAttachments->disconnect(this); + } + + m_entryAttachments = entryAttachments; + + if (m_entryAttachments) { + connect(m_entryAttachments, SIGNAL(keyModified(QString)), SLOT(attachmentChange(QString))); + connect(m_entryAttachments, SIGNAL(aboutToBeAdded(QString)), SLOT(attachmentAboutToAdd(QString))); + connect(m_entryAttachments, SIGNAL(added(QString)), SLOT(attachmentAdd())); + connect(m_entryAttachments, SIGNAL(aboutToBeRemoved(QString)), SLOT(attachmentAboutToRemove(QString))); + connect(m_entryAttachments, SIGNAL(removed(QString)), SLOT(attachmentRemove())); + connect(m_entryAttachments, SIGNAL(aboutToBeReset()), SLOT(aboutToReset())); + connect(m_entryAttachments, SIGNAL(reset()), SLOT(reset())); + } + + endResetModel(); +} + +int EntryAttachmentsModel::rowCount(const QModelIndex& parent) const +{ + if (!m_entryAttachments || parent.isValid()) { + return 0; + } + else { + return m_entryAttachments->keys().size(); + } +} + +int EntryAttachmentsModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + + return 2; +} + +QVariant EntryAttachmentsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) { + switch (section) { + case 0: + return tr("Name"); + case 1: + return tr("Size"); + } + } + + return QVariant(); +} + +QVariant EntryAttachmentsModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + QString key = m_entryAttachments->keys().at(index.row()); + + if (index.column() == 0) { + return key; + } + else { + return Tools::humanReadableFileSize(m_entryAttachments->value(key).size()); + } + } + + return QVariant(); +} + +void EntryAttachmentsModel::attachmentChange(QString key) +{ + int row = m_entryAttachments->keys().indexOf(key); + Q_EMIT dataChanged(index(row, 0), index(row, columnCount()-1)); +} + +void EntryAttachmentsModel::attachmentAboutToAdd(QString key) +{ + QList rows = m_entryAttachments->keys(); + rows.append(key); + qSort(rows); + int row = rows.indexOf(key); + beginInsertRows(QModelIndex(), row, row); +} + +void EntryAttachmentsModel::attachmentAdd() +{ + endInsertRows(); +} + +void EntryAttachmentsModel::attachmentAboutToRemove(QString key) +{ + int row = m_entryAttachments->keys().indexOf(key); + beginRemoveRows(QModelIndex(), row, row); +} + +void EntryAttachmentsModel::attachmentRemove() +{ + endRemoveRows(); +} + +void EntryAttachmentsModel::aboutToReset() +{ + beginResetModel(); +} + +void EntryAttachmentsModel::reset() +{ + endResetModel(); +} diff --git a/src/gui/EntryAttachmentsModel.h b/src/gui/EntryAttachmentsModel.h new file mode 100644 index 00000000..cff00abf --- /dev/null +++ b/src/gui/EntryAttachmentsModel.h @@ -0,0 +1,50 @@ +/* + * 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_ENTRYATTACHMENTSMODEL_H +#define KEEPASSX_ENTRYATTACHMENTSMODEL_H + +#include + +class EntryAttachments; + +class EntryAttachmentsModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit EntryAttachmentsModel(QObject* parent = 0); + void setEntryAttachments(EntryAttachments* entry); + int rowCount(const QModelIndex& parent = QModelIndex()) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + +private Q_SLOTS: + void attachmentChange(QString key); + void attachmentAboutToAdd(QString key); + void attachmentAdd(); + void attachmentAboutToRemove(QString key); + void attachmentRemove(); + void aboutToReset(); + void reset(); + +private: + EntryAttachments* m_entryAttachments; +}; + +#endif // KEEPASSX_ENTRYATTACHMENTSMODEL_H diff --git a/src/gui/EntryAttributesModel.cpp b/src/gui/EntryAttributesModel.cpp new file mode 100644 index 00000000..957d8a6a --- /dev/null +++ b/src/gui/EntryAttributesModel.cpp @@ -0,0 +1,157 @@ +/* + * 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 "EntryAttributesModel.h" + +#include "core/Entry.h" +#include "core/Tools.h" + +EntryAttributesModel::EntryAttributesModel(QObject* parent) + : QAbstractTableModel(parent) + , m_entryAttributes(0) +{ +} + +void EntryAttributesModel::setEntryAttributes(EntryAttributes* entryAttributes) +{ + beginResetModel(); + + if (m_entryAttributes) { + m_entryAttributes->disconnect(this); + } + + m_entryAttributes = entryAttributes; + + if (m_entryAttributes) { + updateAttributes(); + connect(m_entryAttributes, SIGNAL(customKeyModified(QString)), SLOT(attributeChange(QString))); + connect(m_entryAttributes, SIGNAL(aboutToBeAdded(QString)), SLOT(attributeAboutToAdd(QString))); + connect(m_entryAttributes, SIGNAL(added(QString)), SLOT(attributeAdd())); + connect(m_entryAttributes, SIGNAL(aboutToBeRemoved(QString)), SLOT(attributeAboutToRemove(QString))); + connect(m_entryAttributes, SIGNAL(removed(QString)), SLOT(attributeRemove())); + connect(m_entryAttributes, SIGNAL(aboutToBeReset()), SLOT(aboutToReset())); + connect(m_entryAttributes, SIGNAL(reset()), SLOT(reset())); + } + + endResetModel(); +} + +int EntryAttributesModel::rowCount(const QModelIndex& parent) const +{ + if (!m_entryAttributes || parent.isValid()) { + return 0; + } + else { + return m_attributes.size(); + } +} + +int EntryAttributesModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + + return 2; +} + +QVariant EntryAttributesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) { + switch (section) { + case 0: + return tr("Name"); + case 1: + return tr("Value"); + } + } + + return QVariant(); +} + +QVariant EntryAttributesModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + QString key = m_attributes.at(index.row()); + + if (index.column() == 0) { + return key; + } + else { + return m_entryAttributes->value(key); + } + } + + return QVariant(); +} + +void EntryAttributesModel::attributeChange(QString key) +{ + int row = m_attributes.indexOf(key); + Q_ASSERT(row != -1); + Q_EMIT dataChanged(index(row, 0), index(row, columnCount()-1)); +} + +void EntryAttributesModel::attributeAboutToAdd(QString key) +{ + QList rows = m_attributes; + rows.append(key); + qSort(rows); + int row = rows.indexOf(key); + beginInsertRows(QModelIndex(), row, row); +} + +void EntryAttributesModel::attributeAdd() +{ + updateAttributes(); + endInsertRows(); +} + +void EntryAttributesModel::attributeAboutToRemove(QString key) +{ + int row = m_attributes.indexOf(key); + beginRemoveRows(QModelIndex(), row, row); +} + +void EntryAttributesModel::attributeRemove() +{ + updateAttributes(); + endRemoveRows(); +} + +void EntryAttributesModel::aboutToReset() +{ + beginResetModel(); +} + +void EntryAttributesModel::reset() +{ + endResetModel(); +} + +void EntryAttributesModel::updateAttributes() +{ + m_attributes.clear(); + + Q_FOREACH (const QString& key, m_entryAttributes->keys()) { + if (!EntryAttributes::isDefaultAttribute(key)) { + m_attributes.append(key); + } + } +} diff --git a/src/gui/EntryAttributesModel.h b/src/gui/EntryAttributesModel.h new file mode 100644 index 00000000..4e7f56f2 --- /dev/null +++ b/src/gui/EntryAttributesModel.h @@ -0,0 +1,53 @@ +/* + * 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_ENTRYATTRIBUTESMODEL_H +#define KEEPASSX_ENTRYATTRIBUTESMODEL_H + +#include + +class EntryAttributes; + +class EntryAttributesModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit EntryAttributesModel(QObject* parent = 0); + void setEntryAttributes(EntryAttributes* entryAttributes); + int rowCount(const QModelIndex& parent = QModelIndex()) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + +private Q_SLOTS: + void attributeChange(QString key); + void attributeAboutToAdd(QString key); + void attributeAdd(); + void attributeAboutToRemove(QString key); + void attributeRemove(); + void aboutToReset(); + void reset(); + +private: + void updateAttributes(); + + EntryAttributes* m_entryAttributes; + QList m_attributes; +}; + +#endif // KEEPASSX_ENTRYATTRIBUTESMODEL_H diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp index cd8cb3f6..07ba0a81 100644 --- a/tests/TestEntryModel.cpp +++ b/tests/TestEntryModel.cpp @@ -25,6 +25,8 @@ #include "core/Entry.h" #include "core/Group.h" #include "gui/EntryModel.h" +#include "gui/EntryAttachmentsModel.h" +#include "gui/EntryAttributesModel.h" void TestEntryModel::initTestCase() { @@ -93,4 +95,94 @@ void TestEntryModel::test() delete model; } +void TestEntryModel::testAttachmentsModel() +{ + EntryAttachments* entryAttachments = new EntryAttachments(this); + + EntryAttachmentsModel* model = new EntryAttachmentsModel(this); + ModelTest* modelTest = new ModelTest(model, this); + + QCOMPARE(model->rowCount(), 0); + model->setEntryAttachments(entryAttachments); + QCOMPARE(model->rowCount(), 0); + + QSignalSpy spyDataChanged(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + QSignalSpy spyAboutToAdd(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy spyAdded(model, SIGNAL(rowsInserted(QModelIndex,int,int))); + QSignalSpy spyAboutToRemove(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy spyRemoved(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + entryAttachments->set("first", QByteArray("123")); + + entryAttachments->set("2nd", QByteArray("456")); + entryAttachments->set("2nd", QByteArray("789")); + + QCOMPARE(model->data(model->index(0, 0)).toString(), QString("2nd")); + + entryAttachments->remove("first"); + + QCOMPARE(spyDataChanged.count(), 1); + QCOMPARE(spyAboutToAdd.count(), 2); + QCOMPARE(spyAdded.count(), 2); + QCOMPARE(spyAboutToRemove.count(), 1); + QCOMPARE(spyRemoved.count(), 1); + + QSignalSpy spyReset(model, SIGNAL(modelReset())); + entryAttachments->clear(); + model->setEntryAttachments(0); + QCOMPARE(spyReset.count(), 2); + QCOMPARE(model->rowCount(), 0); + + delete modelTest; + delete model; + delete entryAttachments; +} + +void TestEntryModel::testAttributesModel() +{ + EntryAttributes* entryAttributes = new EntryAttributes(this); + + EntryAttributesModel* model = new EntryAttributesModel(this); + ModelTest* modelTest = new ModelTest(model, this); + + QCOMPARE(model->rowCount(), 0); + model->setEntryAttributes(entryAttributes); + QCOMPARE(model->rowCount(), 0); + + QSignalSpy spyDataChanged(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + QSignalSpy spyAboutToAdd(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy spyAdded(model, SIGNAL(rowsInserted(QModelIndex,int,int))); + QSignalSpy spyAboutToRemove(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy spyRemoved(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + entryAttributes->set("first", "123"); + + entryAttributes->set("2nd", "456"); + entryAttributes->set("2nd", "789"); + + QCOMPARE(model->data(model->index(0, 0)).toString(), QString("2nd")); + QCOMPARE(model->data(model->index(0, 1)).toString(), QString("789")); + + entryAttributes->remove("first"); + + // make sure these don't generate messages + entryAttributes->set("Title", "test"); + entryAttributes->set("Notes", "test"); + + QCOMPARE(spyDataChanged.count(), 1); + QCOMPARE(spyAboutToAdd.count(), 2); + QCOMPARE(spyAdded.count(), 2); + QCOMPARE(spyAboutToRemove.count(), 1); + QCOMPARE(spyRemoved.count(), 1); + + QSignalSpy spyReset(model, SIGNAL(modelReset())); + entryAttributes->clear(); + model->setEntryAttributes(0); + QCOMPARE(spyReset.count(), 2); + QCOMPARE(model->rowCount(), 0); + + delete modelTest; + delete model; +} + KEEPASSX_QTEST_CORE_MAIN(TestEntryModel) diff --git a/tests/TestEntryModel.h b/tests/TestEntryModel.h index bd77f5ba..908cbea2 100644 --- a/tests/TestEntryModel.h +++ b/tests/TestEntryModel.h @@ -27,6 +27,8 @@ class TestEntryModel : public QObject private Q_SLOTS: void initTestCase(); void test(); + void testAttachmentsModel(); + void testAttributesModel(); }; #endif // KEEPASSX_TESTENTRYMODEL_H