diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 48ae6c791..31f56c0bd 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3630,6 +3630,14 @@ Supported extensions are: %1.
Select import/export file
+
+ Maintain group structure with shared database
+
+
+
+ Keep Group Structure
+
+
EditGroupWidgetMain
diff --git a/src/keeshare/KeeShareSettings.cpp b/src/keeshare/KeeShareSettings.cpp
index fa500eb5d..61ab2bb8e 100644
--- a/src/keeshare/KeeShareSettings.cpp
+++ b/src/keeshare/KeeShareSettings.cpp
@@ -213,7 +213,7 @@ namespace KeeShareSettings
}
}
} else {
- qWarning("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString()));
+ qDebug("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString()));
reader.skipCurrentElement();
}
}
@@ -253,7 +253,7 @@ namespace KeeShareSettings
} else if (reader.name() == "PublicKey") {
own.certificate = Certificate::deserialize(reader);
} else {
- qWarning("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString()));
+ qDebug("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString()));
reader.skipCurrentElement();
}
}
@@ -262,8 +262,7 @@ namespace KeeShareSettings
}
Reference::Reference()
- : type(Inactive)
- , uuid(QUuid::createUuid())
+ : uuid(QUuid::createUuid())
{
}
@@ -320,12 +319,21 @@ namespace KeeShareSettings
writer.writeStartElement("Password");
writer.writeCharacters(reference.password.toUtf8().toBase64());
writer.writeEndElement();
+ writer.writeStartElement("KeepGroups");
+ writer.writeCharacters(reference.keepGroups ? "True" : "False");
+ writer.writeEndElement();
});
}
Reference Reference::deserialize(const QString& raw)
{
+ if (raw.isEmpty()) {
+ return {};
+ }
+
Reference reference;
+ // If KeepGroups is not present, default to false for backward compatibility
+ reference.keepGroups = false;
xmlDeserialize(raw, [&](QXmlStreamReader& reader) {
while (!reader.error() && reader.readNextStartElement()) {
if (reader.name() == "Type") {
@@ -346,8 +354,10 @@ namespace KeeShareSettings
reference.path = QString::fromUtf8(QByteArray::fromBase64(reader.readElementText().toLatin1()));
} else if (reader.name() == "Password") {
reference.password = QString::fromUtf8(QByteArray::fromBase64(reader.readElementText().toLatin1()));
+ } else if (reader.name() == "KeepGroups") {
+ reference.keepGroups = reader.readElementText().compare("True") == 0;
} else {
- qWarning("Unknown Reference element %s", qPrintable(reader.name().toString()));
+ qDebug("Unknown Reference element %s", qPrintable(reader.name().toString()));
reader.skipCurrentElement();
}
}
diff --git a/src/keeshare/KeeShareSettings.h b/src/keeshare/KeeShareSettings.h
index b81dc15af..667cb8a74 100644
--- a/src/keeshare/KeeShareSettings.h
+++ b/src/keeshare/KeeShareSettings.h
@@ -122,10 +122,11 @@ namespace KeeShareSettings
struct Reference
{
- Type type;
+ Type type = Inactive;
QUuid uuid;
QString path;
QString password;
+ bool keepGroups = true;
Reference();
bool isNull() const;
diff --git a/src/keeshare/ShareExport.cpp b/src/keeshare/ShareExport.cpp
index 85f60d970..ed3aa0f11 100644
--- a/src/keeshare/ShareExport.cpp
+++ b/src/keeshare/ShareExport.cpp
@@ -62,6 +62,39 @@ namespace
}
}
+ void cloneIcon(Metadata* targetMetadata, const Database* sourceDb, const QUuid& iconUuid)
+ {
+ if (!iconUuid.isNull() && !targetMetadata->hasCustomIcon(iconUuid)) {
+ targetMetadata->addCustomIcon(iconUuid, sourceDb->metadata()->customIcon(iconUuid));
+ }
+ }
+
+ void cloneEntries(Metadata* targetMetadata, const Group* sourceGroup, Group* targetGroup)
+ {
+ for (const Entry* sourceEntry : sourceGroup->entries()) {
+ auto* targetEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
+ const bool updateTimeinfoEntry = targetEntry->canUpdateTimeinfo();
+ targetEntry->setUpdateTimeinfo(false);
+ targetEntry->setGroup(targetGroup);
+ targetEntry->setUpdateTimeinfo(updateTimeinfoEntry);
+ cloneIcon(targetMetadata, sourceEntry->database(), targetEntry->iconUuid());
+ }
+ }
+
+ void cloneChildren(Metadata* targetMetadata, const Group* sourceRoot, Group* targetRoot)
+ {
+ for (const Group* sourceGroup : sourceRoot->children()) {
+ auto* targetGroup = sourceGroup->clone(Entry::CloneNoFlags, Group::CloneNoFlags);
+ const bool updateTimeinfo = targetGroup->canUpdateTimeinfo();
+ targetGroup->setUpdateTimeinfo(false);
+ targetGroup->setParent(targetRoot);
+ targetGroup->setUpdateTimeinfo(updateTimeinfo);
+ cloneIcon(targetMetadata, sourceRoot->database(), targetGroup->iconUuid());
+ cloneEntries(targetMetadata, sourceGroup, targetGroup);
+ cloneChildren(targetMetadata, sourceGroup, targetGroup);
+ }
+ }
+
Database* extractIntoDatabase(const KeeShareSettings::Reference& reference, const Group* sourceRoot)
{
const auto* sourceDb = sourceRoot->database();
@@ -75,17 +108,10 @@ namespace
targetRoot->setUpdateTimeinfo(false);
KeeShare::setReferenceTo(targetRoot, KeeShareSettings::Reference());
targetRoot->setUpdateTimeinfo(updateTimeinfo);
- const auto sourceEntries = sourceRoot->entriesRecursive(false);
- for (const Entry* sourceEntry : sourceEntries) {
- auto* targetEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
- const bool updateTimeinfoEntry = targetEntry->canUpdateTimeinfo();
- targetEntry->setUpdateTimeinfo(false);
- targetEntry->setGroup(targetRoot);
- targetEntry->setUpdateTimeinfo(updateTimeinfoEntry);
- const auto iconUuid = targetEntry->iconUuid();
- if (!iconUuid.isNull() && !targetMetadata->hasCustomIcon(iconUuid)) {
- targetMetadata->addCustomIcon(iconUuid, sourceEntry->database()->metadata()->customIcon(iconUuid));
- }
+ cloneIcon(targetMetadata, sourceRoot->database(), targetRoot->iconUuid());
+ cloneEntries(targetMetadata, sourceRoot, targetRoot);
+ if (reference.keepGroups) {
+ cloneChildren(targetMetadata, sourceRoot, targetRoot);
}
auto key = QSharedPointer::create();
diff --git a/src/keeshare/group/EditGroupWidgetKeeShare.cpp b/src/keeshare/group/EditGroupWidgetKeeShare.cpp
index 82f8dd1c0..bea495b0a 100644
--- a/src/keeshare/group/EditGroupWidgetKeeShare.cpp
+++ b/src/keeshare/group/EditGroupWidgetKeeShare.cpp
@@ -43,6 +43,7 @@ EditGroupWidgetKeeShare::EditGroupWidgetKeeShare(QWidget* parent)
connect(m_ui->pathEdit, SIGNAL(editingFinished()), SLOT(selectPath()));
connect(m_ui->pathSelectionButton, SIGNAL(pressed()), SLOT(launchPathSelectionDialog()));
connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(selectType()));
+ connect(m_ui->keepGroupsCheckbox, SIGNAL(toggled(bool)), SLOT(keepGroupsToggled(bool)));
connect(m_ui->clearButton, SIGNAL(clicked(bool)), SLOT(clearInputs()));
connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(updateSharingState()));
@@ -97,6 +98,7 @@ void EditGroupWidgetKeeShare::updateSharingState()
m_ui->pathEdit->setEnabled(isEnabled);
m_ui->pathSelectionButton->setEnabled(isEnabled);
m_ui->passwordEdit->setEnabled(isEnabled);
+ m_ui->keepGroupsCheckbox->setEnabled(isEnabled);
if (!m_temporaryGroup || !isEnabled) {
m_ui->messageWidget->hideMessage();
@@ -188,6 +190,7 @@ void EditGroupWidgetKeeShare::update()
m_ui->typeComboBox->setCurrentIndex(reference.type);
m_ui->passwordEdit->setText(reference.password);
m_ui->pathEdit->setText(reference.path);
+ m_ui->keepGroupsCheckbox->setChecked(reference.keepGroups);
}
updateSharingState();
@@ -291,3 +294,13 @@ void EditGroupWidgetKeeShare::selectType()
updateSharingState();
}
+
+void EditGroupWidgetKeeShare::keepGroupsToggled(bool toggled)
+{
+ if (!m_temporaryGroup) {
+ return;
+ }
+ auto reference = KeeShare::referenceOf(m_temporaryGroup);
+ reference.keepGroups = toggled;
+ KeeShare::setReferenceTo(m_temporaryGroup, reference);
+}
diff --git a/src/keeshare/group/EditGroupWidgetKeeShare.h b/src/keeshare/group/EditGroupWidgetKeeShare.h
index aaa3ebbd3..bd08366e3 100644
--- a/src/keeshare/group/EditGroupWidgetKeeShare.h
+++ b/src/keeshare/group/EditGroupWidgetKeeShare.h
@@ -48,6 +48,7 @@ private slots:
void selectPassword();
void launchPathSelectionDialog();
void selectPath();
+ void keepGroupsToggled(bool);
private:
QScopedPointer m_ui;
diff --git a/src/keeshare/group/EditGroupWidgetKeeShare.ui b/src/keeshare/group/EditGroupWidgetKeeShare.ui
index 857ba61c8..1e8e0e1a6 100644
--- a/src/keeshare/group/EditGroupWidgetKeeShare.ui
+++ b/src/keeshare/group/EditGroupWidgetKeeShare.ui
@@ -138,7 +138,7 @@
- -
+
-
-
@@ -171,7 +171,7 @@
- -
+
-
Qt::Vertical
@@ -184,6 +184,19 @@
+ -
+
+
+ Maintain group structure with shared database
+
+
+ Keep Group Structure
+
+
+ true
+
+
+