diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2444faa..f9e562df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(keepassx_SOURCES core/AutoTypeMatch.cpp core/Config.cpp core/CsvParser.cpp + core/CustomData.cpp core/Database.cpp core/DatabaseIcons.cpp core/Entry.cpp diff --git a/src/core/CustomData.cpp b/src/core/CustomData.cpp new file mode 100644 index 00000000..cb783f3a --- /dev/null +++ b/src/core/CustomData.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2017 KeePassXC Team + * + * 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 "CustomData.h" + +CustomData::CustomData(QObject* parent) + : QObject(parent) +{ +} + +QList CustomData::keys() const +{ + return m_data.keys(); +} + +bool CustomData::hasKey(const QString& key) const +{ + return m_data.contains(key); +} + +QString CustomData::value(const QString& key) const +{ + return m_data.value(key); +} + +bool CustomData::contains(const QString& key) const +{ + return m_data.contains(key); +} + +bool CustomData::containsValue(const QString& value) const +{ + return m_data.values().contains(value); +} + +void CustomData::set(const QString& key, const QString& value) +{ + bool emitModified = false; + + bool addAttribute = !m_data.contains(key); + bool changeValue = !addAttribute && (m_data.value(key) != value); + + if (addAttribute ) { + emit aboutToBeAdded(key); + } + + if (addAttribute || changeValue) { + m_data.insert(key, value); + emitModified = true; + } + + if (emitModified) { + emit modified(); + } + + if (addAttribute) { + emit added(key); + } +} + +void CustomData::remove(const QString& key) +{ + emit aboutToBeRemoved(key); + + m_data.remove(key); + + emit removed(key); + emit modified(); +} + +void CustomData::rename(const QString& oldKey, const QString& newKey) +{ + if (!m_data.contains(oldKey)) { + Q_ASSERT(false); + return; + } + + if (m_data.contains(newKey)) { + Q_ASSERT(false); + return; + } + + QString data = value(oldKey); + + emit aboutToRename(oldKey, newKey); + + m_data.remove(oldKey); + m_data.insert(newKey, data); + + emit modified(); + emit renamed(oldKey, newKey); +} + +void CustomData::copyDataFrom(const CustomData* other) +{ + if (*this != *other) { + emit aboutToBeReset(); + + m_data = other->m_data; + + emit reset(); + emit modified(); + } +} + +bool CustomData::operator==(const CustomData& other) const +{ + return (m_data == other.m_data); +} + +bool CustomData::operator!=(const CustomData& other) const +{ + return (m_data != other.m_data); +} + +void CustomData::clear() +{ + emit aboutToBeReset(); + + m_data.clear(); + + emit reset(); + emit modified(); +} + +bool CustomData::isEmpty() const +{ + return m_data.isEmpty(); +} + +int CustomData::dataSize() +{ + int size = 0; + + QHashIterator i(m_data); + while (i.hasNext()) { + i.next(); + size += i.key().toUtf8().size() + i.value().toUtf8().size(); + } + return size; +} diff --git a/src/core/CustomData.h b/src/core/CustomData.h new file mode 100644 index 00000000..722d9bd2 --- /dev/null +++ b/src/core/CustomData.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2017 KeePassXC Team + * + * 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_CUSTOMDATA_H +#define KEEPASSX_CUSTOMDATA_H + +#include +#include +#include +#include + +class CustomData : public QObject +{ + Q_OBJECT + +public: + explicit CustomData(QObject* parent = nullptr); + QList keys() const; + bool hasKey(const QString& key) const; + QString value(const QString& key) const; + bool contains(const QString& key) const; + bool containsValue(const QString& value) const; + void set(const QString& key, const QString& value); + void remove(const QString& key); + void rename(const QString& oldKey, const QString& newKey); + void clear(); + bool isEmpty() const; + int dataSize(); + void copyDataFrom(const CustomData* other); + bool operator==(const CustomData& other) const; + bool operator!=(const CustomData& other) const; + + +signals: + void modified(); + void aboutToBeAdded(const QString& key); + void added(const QString& key); + void aboutToBeRemoved(const QString& key); + void removed(const QString& key); + void aboutToRename(const QString& oldKey, const QString& newKey); + void renamed(const QString& oldKey, const QString& newKey); + void aboutToBeReset(); + void reset(); + +private: + QHash m_data; +}; + +#endif // KEEPASSX_CUSTOMDATA_H diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 1dfc614e..721891d1 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -37,6 +37,7 @@ Entry::Entry() : m_attributes(new EntryAttributes(this)) , m_attachments(new EntryAttachments(this)) , m_autoTypeAssociations(new AutoTypeAssociations(this)) + , m_customData(new CustomData(this)) , m_tmpHistoryItem(nullptr) , m_modifiedSinceBegin(false) , m_updateTimeinfo(true) @@ -52,6 +53,7 @@ Entry::Entry() connect(m_attributes, SIGNAL(defaultKeyModified()), SLOT(emitDataChanged())); connect(m_attachments, SIGNAL(modified()), this, SIGNAL(modified())); connect(m_autoTypeAssociations, SIGNAL(modified()), SIGNAL(modified())); + connect(m_customData, SIGNAL(modified()), this, SIGNAL(modified())); connect(this, SIGNAL(modified()), SLOT(updateTimeinfo())); connect(this, SIGNAL(modified()), SLOT(updateModifiedSinceBegin())); @@ -340,6 +342,16 @@ const EntryAttachments* Entry::attachments() const return m_attachments; } +CustomData *Entry::customData() +{ + return m_customData; +} + +const CustomData *Entry::customData() const +{ + return m_customData; +} + bool Entry::hasTotp() const { return m_attributes->hasKey("TOTP Seed") || m_attributes->hasKey("otp"); @@ -606,6 +618,7 @@ void Entry::truncateHistory() size += historyItem->attributes()->attributesSize(); size += historyItem->autoTypeAssociations()->associationsSize(); size += historyItem->attachments()->attachmentsSize(); + size += customData()->dataSize(); const QStringList tags = historyItem->tags().split(delimiter, QString::SkipEmptyParts); for (const QString& tag : tags) { size += tag.toUtf8().size(); @@ -632,6 +645,7 @@ Entry* Entry::clone(CloneFlags flags) const entry->m_uuid = m_uuid; } entry->m_data = m_data; + entry->m_customData->copyDataFrom(m_customData); entry->m_attributes->copyDataFrom(m_attributes); entry->m_attachments->copyDataFrom(m_attachments); @@ -676,6 +690,7 @@ void Entry::copyDataFrom(const Entry* other) { setUpdateTimeinfo(false); m_data = other->m_data; + m_customData->copyDataFrom(other->m_customData); m_attributes->copyDataFrom(other->m_attributes); m_attachments->copyDataFrom(other->m_attachments); m_autoTypeAssociations->copyDataFrom(other->m_autoTypeAssociations); diff --git a/src/core/Entry.h b/src/core/Entry.h index 8579f953..ba8c4edd 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -28,6 +28,7 @@ #include #include "core/AutoTypeAssociations.h" +#include "core/CustomData.h" #include "core/EntryAttachments.h" #include "core/EntryAttributes.h" #include "core/TimeInfo.h" @@ -107,6 +108,8 @@ public: const EntryAttributes* attributes() const; EntryAttachments* attachments(); const EntryAttachments* attachments() const; + CustomData *customData(); + const CustomData *customData() const; static const int DefaultIconNumber; static const int ResolveMaximumDepth; @@ -232,6 +235,8 @@ private: EntryAttachments* const m_attachments; AutoTypeAssociations* const m_autoTypeAssociations; + CustomData* const m_customData; + QList m_history; Entry* m_tmpHistoryItem; bool m_modifiedSinceBegin; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 51b24c19..61a955b8 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -33,13 +33,17 @@ Entry::CloneFlags Group::DefaultEntryCloneFlags = static_cast Entry::CloneNewUuid | Entry::CloneResetTimeInfo); Group::Group() - : m_updateTimeinfo(true) + : m_customData(new CustomData(this)) + , m_updateTimeinfo(true) { m_data.iconNumber = DefaultIconNumber; m_data.isExpanded = true; m_data.autoTypeEnabled = Inherit; m_data.searchingEnabled = Inherit; m_data.mergeMode = ModeInherit; + + connect(m_customData, SIGNAL(modified()), this, SIGNAL(modified())); + connect(this, SIGNAL(modified()), SLOT(updateTimeinfo())); } Group::~Group() @@ -80,7 +84,6 @@ Group* Group::createRecycleBin() template inline bool Group::set(P& property, const V& value) { if (property != value) { property = value; - updateTimeinfo(); emit modified(); return true; } else { @@ -251,6 +254,16 @@ bool Group::isExpired() const return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc(); } +CustomData *Group::customData() +{ + return m_customData; +} + +const CustomData *Group::customData() const +{ + return m_customData; +} + void Group::setUuid(const Uuid& uuid) { set(m_uuid, uuid); @@ -275,8 +288,6 @@ void Group::setIcon(int iconNumber) if (m_data.iconNumber != iconNumber || !m_data.customIcon.isNull()) { m_data.iconNumber = iconNumber; m_data.customIcon = Uuid(); - - updateTimeinfo(); emit modified(); emit dataChanged(this); } @@ -289,8 +300,6 @@ void Group::setIcon(const Uuid& uuid) if (m_data.customIcon != uuid) { m_data.customIcon = uuid; m_data.iconNumber = 0; - - updateTimeinfo(); emit modified(); emit dataChanged(this); } @@ -305,8 +314,8 @@ void Group::setExpanded(bool expanded) { if (m_data.isExpanded != expanded) { m_data.isExpanded = expanded; - updateTimeinfo(); if (config()->get("IgnoreGroupExpansion").toBool()) { + updateTimeinfo(); return; } emit modified(); @@ -337,7 +346,6 @@ void Group::setExpires(bool value) { if (m_data.timeInfo.expires() != value) { m_data.timeInfo.setExpires(value); - updateTimeinfo(); emit modified(); } } @@ -346,7 +354,6 @@ void Group::setExpiryTime(const QDateTime& dateTime) { if (m_data.timeInfo.expiryTime() != dateTime) { m_data.timeInfo.setExpiryTime(dateTime); - updateTimeinfo(); emit modified(); } } @@ -768,6 +775,7 @@ Group* Group::clone(Entry::CloneFlags entryFlags, Group::CloneFlags groupFlags) } clonedGroup->m_data = m_data; + clonedGroup->m_customData->copyDataFrom(m_customData); if (groupFlags & Group::CloneIncludeEntries) { const QList entryList = entries(); @@ -799,6 +807,7 @@ Group* Group::clone(Entry::CloneFlags entryFlags, Group::CloneFlags groupFlags) void Group::copyDataFrom(const Group* other) { m_data = other->m_data; + m_customData->copyDataFrom(other->m_customData); m_lastTopVisibleEntry = other->m_lastTopVisibleEntry; } diff --git a/src/core/Group.h b/src/core/Group.h index b1654a23..f49b7721 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -26,6 +26,7 @@ #include "core/Database.h" #include "core/Entry.h" +#include "core/CustomData.h" #include "core/TimeInfo.h" #include "core/Uuid.h" @@ -83,6 +84,8 @@ public: bool resolveAutoTypeEnabled() const; Entry* lastTopVisibleEntry() const; bool isExpired() const; + CustomData *customData(); + const CustomData *customData() const; static const int DefaultIconNumber; static const int RecycleBinIconNumber; @@ -164,6 +167,9 @@ signals: void modified(); +private slots: + void updateTimeinfo(); + private: template bool set(P& property, const V& value); @@ -177,7 +183,6 @@ private: void recSetDatabase(Database* db); void cleanupParent(); void recCreateDelObjects(); - void updateTimeinfo(); QPointer m_db; Uuid m_uuid; @@ -186,6 +191,8 @@ private: QList m_children; QList m_entries; + CustomData *const m_customData; + QPointer m_parent; bool m_updateTimeinfo; diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index ab56dab7..4c41c02a 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -27,6 +27,7 @@ const int Metadata::DefaultHistoryMaxSize = 6 * 1024 * 1024; Metadata::Metadata(QObject* parent) : QObject(parent) + , m_customData(new CustomData(this)) , m_updateDatetime(true) { m_data.generator = "KeePassXC"; @@ -50,6 +51,8 @@ Metadata::Metadata(QObject* parent) m_entryTemplatesGroupChanged = now; m_masterKeyChanged = now; m_settingsChanged = now; + + connect(m_customData, SIGNAL(modified()), this, SIGNAL(modified())); } template bool Metadata::set(P& property, const V& value) @@ -291,9 +294,14 @@ int Metadata::historyMaxSize() const return m_data.historyMaxSize; } -QHash Metadata::customFields() const +CustomData *Metadata::customData() { - return m_customFields; + return m_customData; +} + +const CustomData *Metadata::customData() const +{ + return m_customData; } void Metadata::setGenerator(const QString& value) @@ -511,27 +519,13 @@ void Metadata::setHistoryMaxSize(int value) set(m_data.historyMaxSize, value); } -void Metadata::addCustomField(const QString& key, const QString& value) +QDateTime Metadata::settingsChanged() const { - Q_ASSERT(!m_customFields.contains(key)); - - m_customFields.insert(key, value); - emit modified(); -} - -void Metadata::removeCustomField(const QString& key) -{ - Q_ASSERT(m_customFields.contains(key)); - - m_customFields.remove(key); - emit modified(); -} - -QDateTime Metadata::settingsChanged() const { return m_settingsChanged; } -void Metadata::setSettingsChanged(const QDateTime& value) { +void Metadata::setSettingsChanged(const QDateTime& value) +{ Q_ASSERT(value.timeSpec() == Qt::UTC); m_settingsChanged = value; } diff --git a/src/core/Metadata.h b/src/core/Metadata.h index 7791b038..a6387dfb 100644 --- a/src/core/Metadata.h +++ b/src/core/Metadata.h @@ -27,6 +27,7 @@ #include #include "core/Uuid.h" +#include "core/CustomData.h" class Database; class Group; @@ -97,7 +98,8 @@ public: int masterKeyChangeForce() const; int historyMaxItems() const; int historyMaxSize() const; - QHash customFields() const; + CustomData *customData(); + const CustomData *customData() const; static const int DefaultHistoryMaxItems; static const int DefaultHistoryMaxSize; @@ -134,8 +136,6 @@ public: void setMasterKeyChangeForce(int value); void setHistoryMaxItems(int value); void setHistoryMaxSize(int value); - void addCustomField(const QString& key, const QString& value); - void removeCustomField(const QString& key); void setUpdateDatetime(bool value); /* * Copy all attributes from other except: @@ -175,7 +175,7 @@ private: QDateTime m_masterKeyChanged; QDateTime m_settingsChanged; - QHash m_customFields; + CustomData *const m_customData; bool m_updateDatetime; }; diff --git a/src/format/KdbxXmlReader.cpp b/src/format/KdbxXmlReader.cpp index f30dc64b..7aed4014 100644 --- a/src/format/KdbxXmlReader.cpp +++ b/src/format/KdbxXmlReader.cpp @@ -295,7 +295,7 @@ void KdbxXmlReader::parseMeta() } else if (m_xml.name() == "Binaries") { parseBinaries(); } else if (m_xml.name() == "CustomData") { - parseCustomData(); + parseCustomData(m_meta->customData()); } else if (m_xml.name() == "SettingsChanged") { m_meta->setSettingsChanged(readDateTime()); } else { @@ -397,20 +397,20 @@ void KdbxXmlReader::parseBinaries() } } -void KdbxXmlReader::parseCustomData() +void KdbxXmlReader::parseCustomData(CustomData *customData) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { if (m_xml.name() == "Item") { - parseCustomDataItem(); + parseCustomDataItem(customData); continue; } skipCurrentElement(); } } -void KdbxXmlReader::parseCustomDataItem() +void KdbxXmlReader::parseCustomDataItem(CustomData *customData) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Item"); @@ -432,7 +432,7 @@ void KdbxXmlReader::parseCustomDataItem() } if (keySet && valueSet) { - m_meta->addCustomField(key, value); + customData->set(key, value); return; } @@ -583,6 +583,10 @@ Group* KdbxXmlReader::parseGroup() } continue; } + if (m_xml.name() == "CustomData") { + parseCustomData(group->customData()); + continue; + } skipCurrentElement(); } @@ -744,7 +748,10 @@ Entry* KdbxXmlReader::parseEntry(bool history) } continue; } - + if (m_xml.name() == "CustomData" ){ + parseCustomData(entry->customData()); + continue; + } skipCurrentElement(); } diff --git a/src/format/KdbxXmlReader.h b/src/format/KdbxXmlReader.h index 7ec592eb..e94bfd4d 100644 --- a/src/format/KdbxXmlReader.h +++ b/src/format/KdbxXmlReader.h @@ -66,8 +66,8 @@ protected: virtual void parseCustomIcons(); virtual void parseIcon(); virtual void parseBinaries(); - virtual void parseCustomData(); - virtual void parseCustomDataItem(); + virtual void parseCustomData(CustomData *customData); + virtual void parseCustomDataItem(CustomData *customData); virtual bool parseRoot(); virtual Group* parseGroup(); virtual void parseDeletedObjects(); diff --git a/src/format/KdbxXmlWriter.cpp b/src/format/KdbxXmlWriter.cpp index 4fe202a9..07953af3 100644 --- a/src/format/KdbxXmlWriter.cpp +++ b/src/format/KdbxXmlWriter.cpp @@ -129,7 +129,7 @@ void KdbxXmlWriter::writeMetadata() if (m_kdbxVersion < KeePass2::FILE_VERSION_4) { writeBinaries(); } - writeCustomData(); + writeCustomData(m_meta->customData()); m_xml.writeEndElement(); } @@ -218,14 +218,13 @@ void KdbxXmlWriter::writeBinaries() m_xml.writeEndElement(); } -void KdbxXmlWriter::writeCustomData() +void KdbxXmlWriter::writeCustomData(const CustomData *customData) { m_xml.writeStartElement("CustomData"); - QHash customFields = m_meta->customFields(); - const QList keyList = customFields.keys(); + const QList keyList = customData->keys(); for (const QString& key : keyList) { - writeCustomDataItem(key, customFields.value(key)); + writeCustomDataItem(key, customData->value(key)); } m_xml.writeEndElement(); @@ -277,6 +276,10 @@ void KdbxXmlWriter::writeGroup(const Group* group) writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry()); + if (!group->customData()->isEmpty()){ + writeCustomData(group->customData()); + } + const QList& entryList = group->entries(); for (const Entry* entry : entryList) { writeEntry(entry); @@ -401,6 +404,11 @@ void KdbxXmlWriter::writeEntry(const Entry* entry) } writeAutoType(entry); + + if (!entry->customData()->isEmpty()){ + writeCustomData(entry->customData()); + } + // write history only for entries that are not history items if (entry->parent()) { writeEntryHistory(entry); diff --git a/src/format/KdbxXmlWriter.h b/src/format/KdbxXmlWriter.h index 6c1bd1d0..ef77ffd9 100644 --- a/src/format/KdbxXmlWriter.h +++ b/src/format/KdbxXmlWriter.h @@ -51,7 +51,7 @@ private: void writeCustomIcons(); void writeIcon(const Uuid& uuid, const QImage& icon); void writeBinaries(); - void writeCustomData(); + void writeCustomData(const CustomData *customData); void writeCustomDataItem(const QString& key, const QString& value); void writeRoot(); void writeGroup(const Group* group); diff --git a/src/gui/EditWidgetProperties.cpp b/src/gui/EditWidgetProperties.cpp index a278d6cb..d59f17b3 100644 --- a/src/gui/EditWidgetProperties.cpp +++ b/src/gui/EditWidgetProperties.cpp @@ -18,20 +18,27 @@ #include "EditWidgetProperties.h" #include "ui_EditWidgetProperties.h" +#include + EditWidgetProperties::EditWidgetProperties(QWidget* parent) : QWidget(parent) , m_ui(new Ui::EditWidgetProperties()) + , m_customData(new CustomData(this)) + , m_customDataModel(new QStandardItemModel(this)) { m_ui->setupUi(this); + m_ui->customDataTable->setModel(m_customDataModel); + + this->connect( m_ui->removeCustomDataButton, SIGNAL(clicked()), SLOT(removeSelectedPluginData())); } EditWidgetProperties::~EditWidgetProperties() { } -void EditWidgetProperties::setFields(TimeInfo timeInfo, Uuid uuid) +void EditWidgetProperties::setFields(const TimeInfo &timeInfo, const Uuid &uuid) { - QString timeFormat("d MMM yyyy HH:mm:ss"); + static const QString timeFormat("d MMM yyyy HH:mm:ss"); m_ui->modifiedEdit->setText( timeInfo.lastModificationTime().toLocalTime().toString(timeFormat)); m_ui->createdEdit->setText( @@ -40,3 +47,36 @@ void EditWidgetProperties::setFields(TimeInfo timeInfo, Uuid uuid) timeInfo.lastAccessTime().toLocalTime().toString(timeFormat)); m_ui->uuidEdit->setText(uuid.toHex()); } + +void EditWidgetProperties::setCustomData(const CustomData *customData) +{ + Q_ASSERT(customData != nullptr); + m_customData->copyDataFrom(customData); + + this->updateModel(); +} + +const CustomData *EditWidgetProperties::customData() const +{ + return m_customData; +} + +void EditWidgetProperties::removeSelectedPluginData() +{ + const QItemSelectionModel *pSelectionModel = m_ui->customDataTable->selectionModel(); + if (pSelectionModel){ + for( const QModelIndex& index : pSelectionModel->selectedRows(0) ){ + const QString key = index.data().toString(); + m_customData->remove(key); + } + this->updateModel(); + } +} + +void EditWidgetProperties::updateModel() +{ + m_customDataModel->clear(); + for( const QString& key : m_customData->keys() ){ + m_customDataModel->appendRow(QList() << new QStandardItem( key ) << new QStandardItem( m_customData->value( key ) )); + } +} diff --git a/src/gui/EditWidgetProperties.h b/src/gui/EditWidgetProperties.h index 4a2c0591..dbcfac69 100644 --- a/src/gui/EditWidgetProperties.h +++ b/src/gui/EditWidgetProperties.h @@ -18,8 +18,11 @@ #ifndef KEEPASSX_EDITWIDGETPROPERTIES_H #define KEEPASSX_EDITWIDGETPROPERTIES_H +#include +#include #include +#include "core/CustomData.h" #include "core/TimeInfo.h" #include "core/Uuid.h" @@ -35,11 +38,21 @@ public: explicit EditWidgetProperties(QWidget* parent = nullptr); ~EditWidgetProperties(); - void setFields(TimeInfo timeInfo, Uuid uuid); + void setFields(const TimeInfo &timeInfo, const Uuid &uuid); + void setCustomData(const CustomData *customData); + + const CustomData *customData() const; + +private slots: + void removeSelectedPluginData(); private: + void updateModel(); + const QScopedPointer m_ui; + QPointer m_customData; + QPointer m_customDataModel; Q_DISABLE_COPY(EditWidgetProperties) }; diff --git a/src/gui/EditWidgetProperties.ui b/src/gui/EditWidgetProperties.ui index bf49cc92..269134f6 100644 --- a/src/gui/EditWidgetProperties.ui +++ b/src/gui/EditWidgetProperties.ui @@ -10,9 +10,12 @@ 328 - - - QFormLayout::ExpandingFieldsGrow + + + 5 + + + 0 0 @@ -23,72 +26,128 @@ 0 - - - - - 0 - 0 - - - - true - - + + + + + + Created: + + + + + + + + 0 + 0 + + + + true + + + + + + + Modified: + + + + + + + + 0 + 0 + + + + true + + + + + + + Accessed: + + + + + + + true + + + + + + + Uuid: + + + + + + + true + + + + - - - - - 0 - 0 - - - - true - - - - - - - Created: - - - - - - - Modified: - - - - - - - Accessed: - - - - - - - true - - - - - - - Uuid: - - - - - - - true + + + + Plugin Data + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + false + + + true + + + false + + + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index c3055757..ac968180 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -666,6 +666,7 @@ void EditEntryWidget::setForms(const Entry* entry, bool restore) #endif m_editWidgetProperties->setFields(entry->timeInfo(), entry->uuid()); + m_editWidgetProperties->setCustomData(entry->customData()); if (!m_history && !restore) { m_historyModel->setEntries(entry->historyItems()); @@ -771,7 +772,7 @@ void EditEntryWidget::updateEntryData(Entry* entry) const { entry->attributes()->copyCustomKeysFrom(m_entryAttributes); entry->attachments()->copyDataFrom(m_advancedUi->attachmentsWidget->entryAttachments()); - + entry->customData()->copyDataFrom(m_editWidgetProperties->customData()); entry->setTitle(m_mainUi->titleEdit->text()); entry->setUsername(m_mainUi->usernameEdit->text()); entry->setUrl(m_mainUi->urlEdit->text()); diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index da9875fb..9ffd31a5 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -95,6 +95,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, Database* database) m_editGroupWidgetIcons->load(group->uuid(), database, iconStruct); m_editWidgetProperties->setFields(group->timeInfo(), group->uuid()); + m_editWidgetProperties->setCustomData(group->customData()); setCurrentPage(0); @@ -118,6 +119,8 @@ void EditGroupWidget::apply() m_group->setSearchingEnabled(triStateFromIndex(m_mainUi->searchComboBox->currentIndex())); m_group->setAutoTypeEnabled(triStateFromIndex(m_mainUi->autotypeComboBox->currentIndex())); + m_group->customData()->copyDataFrom(m_editWidgetProperties->customData()); + if (m_mainUi->autoTypeSequenceInherit->isChecked()) { m_group->setDefaultAutoTypeSequence(QString()); }