diff --git a/COPYING b/COPYING
index 1ec6980e1..c086a6236 100644
--- a/COPYING
+++ b/COPYING
@@ -164,6 +164,7 @@ Files: share/icons/application/scalable/actions/chevron-double-down.svg
share/icons/application/scalable/actions/entry-edit.svg
share/icons/application/scalable/actions/entry-new.svg
share/icons/application/scalable/actions/favicon-download.svg
+ share/icons/application/scalable/actions/group-clone.svg
share/icons/application/scalable/actions/group-delete.svg
share/icons/application/scalable/actions/group-edit.svg
share/icons/application/scalable/actions/group-empty-trash.svg
diff --git a/share/icons/application/scalable/actions/group-clone.svg b/share/icons/application/scalable/actions/group-clone.svg
new file mode 100644
index 000000000..90eb0eebc
--- /dev/null
+++ b/share/icons/application/scalable/actions/group-clone.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/share/icons/icons.qrc b/share/icons/icons.qrc
index b4aa3950f..776961e72 100644
--- a/share/icons/icons.qrc
+++ b/share/icons/icons.qrc
@@ -40,6 +40,7 @@
application/scalable/actions/getting-started.svg
application/scalable/actions/group-delete.svg
application/scalable/actions/group-edit.svg
+ application/scalable/actions/group-clone.svg
application/scalable/actions/group-empty-trash.svg
application/scalable/actions/group-new.svg
application/scalable/actions/hammer-wrench.svg
diff --git a/src/core/Group.cpp b/src/core/Group.cpp
index 5e77d4951..a6bb4173c 100644
--- a/src/core/Group.cpp
+++ b/src/core/Group.cpp
@@ -905,6 +905,10 @@ Group* Group::clone(Entry::CloneFlags entryFlags, Group::CloneFlags groupFlags)
clonedGroup->m_data.timeInfo.setLocationChanged(now);
}
+ if (groupFlags & Group::CloneRenameTitle) {
+ clonedGroup->setName(tr("%1 - Clone").arg(name()));
+ }
+
return clonedGroup;
}
diff --git a/src/core/Group.h b/src/core/Group.h
index 021126b3e..172bb6596 100644
--- a/src/core/Group.h
+++ b/src/core/Group.h
@@ -53,6 +53,7 @@ public:
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time
CloneIncludeEntries = 4, // clone the group entries
CloneDefault = CloneNewUuid | CloneResetTimeInfo | CloneIncludeEntries,
+ CloneRenameTitle = 8, // add "- Clone" after the original title
};
Q_DECLARE_FLAGS(CloneFlags, CloneFlag)
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 18437545d..a3a0ec103 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -826,6 +826,19 @@ void DatabaseWidget::createGroup()
switchToGroupEdit(m_newGroup.data(), true);
}
+void DatabaseWidget::cloneGroup()
+{
+ Group* currentGroup = m_groupView->currentGroup();
+ Q_ASSERT(currentGroup && canCloneCurrentGroup());
+ if (!currentGroup || !canCloneCurrentGroup()) {
+ return;
+ }
+
+ m_newGroup.reset(currentGroup->clone(Entry::CloneCopy, Group::CloneDefault | Group::CloneRenameTitle));
+ m_newParent = currentGroup->parentGroup();
+ switchToGroupEdit(m_newGroup.data(), true);
+}
+
void DatabaseWidget::deleteGroup()
{
Group* currentGroup = m_groupView->currentGroup();
@@ -1375,6 +1388,14 @@ void DatabaseWidget::onEntryChanged(Entry* entry)
emit entrySelectionChanged();
}
+bool DatabaseWidget::canCloneCurrentGroup() const
+{
+ bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup();
+ // bool isRecycleBin = isRecycleBinSelected();
+
+ return !isRootGroup;
+}
+
bool DatabaseWidget::canDeleteCurrentGroup() const
{
bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup();
diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h
index ee4a16cde..ae3fad675 100644
--- a/src/gui/DatabaseWidget.h
+++ b/src/gui/DatabaseWidget.h
@@ -94,6 +94,7 @@ public:
EntryView* entryView();
Group* currentGroup() const;
+ bool canCloneCurrentGroup() const;
bool canDeleteCurrentGroup() const;
bool isGroupSelected() const;
bool isRecycleBinSelected() const;
@@ -190,6 +191,7 @@ public slots:
void downloadAllFavicons();
void openUrlForEntry(Entry* entry);
void createGroup();
+ void cloneGroup();
void deleteGroup();
void switchToMainView(bool previousDialogAccepted = false);
void switchToEntryEdit();
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 2dd1becfc..8de29a804 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -390,6 +390,7 @@ MainWindow::MainWindow()
m_ui->actionGroupNew->setIcon(icons()->icon("group-new"));
m_ui->actionGroupEdit->setIcon(icons()->icon("group-edit"));
+ m_ui->actionGroupClone->setIcon(icons()->icon("group-clone"));
m_ui->actionGroupDelete->setIcon(icons()->icon("group-delete"));
m_ui->actionGroupEmptyRecycleBin->setIcon(icons()->icon("group-empty-trash"));
m_ui->actionEntryOpenUrl->setIcon(icons()->icon("web"));
@@ -490,6 +491,7 @@ MainWindow::MainWindow()
m_actionMultiplexer.connect(m_ui->actionGroupNew, SIGNAL(triggered()), SLOT(createGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupEdit, SIGNAL(triggered()), SLOT(switchToGroupEdit()));
+ m_actionMultiplexer.connect(m_ui->actionGroupClone, SIGNAL(triggered()), SLOT(cloneGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupDelete, SIGNAL(triggered()), SLOT(deleteGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupEmptyRecycleBin, SIGNAL(triggered()), SLOT(emptyRecycleBin()));
m_actionMultiplexer.connect(m_ui->actionGroupSortAsc, SIGNAL(triggered()), SLOT(sortGroupsAsc()));
@@ -830,6 +832,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|| (singleEntrySelected && dbWidget->currentEntryHasUrl()));
m_ui->actionGroupNew->setEnabled(groupSelected);
m_ui->actionGroupEdit->setEnabled(groupSelected);
+ m_ui->actionGroupClone->setEnabled(groupSelected && dbWidget->canCloneCurrentGroup());
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
m_ui->actionGroupSortAsc->setEnabled(groupSelected && currentGroupHasChildren);
m_ui->actionGroupSortDesc->setEnabled(groupSelected && currentGroupHasChildren);
diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui
index 8ea119d47..2dd852ca9 100644
--- a/src/gui/MainWindow.ui
+++ b/src/gui/MainWindow.ui
@@ -337,6 +337,7 @@
+
@@ -1045,6 +1046,14 @@
{USERNAME}{TAB}{PASSWORD}{ENTER}
+
+
+ false
+
+
+ Clone Group...
+
+