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... + +