diff options
| author | Nathaniel Graham <[email protected]> | 2019-12-20 10:07:25 -0700 |
|---|---|---|
| committer | Nate Graham <[email protected]> | 2020-03-15 13:20:50 -0600 |
| commit | 158d12ac37d27023cabf86d165630ec0c9309d4b (patch) | |
| tree | bbe81f75440d9b612edd086c6c44e47b7cbc2927 /src | |
| parent | 9c3f9c4846e38c6b36737edf31a35a61c55f589a (diff) | |
Add Duplicate feature
Summary: Adds a Duplicate feature to Dolphin, showing up as a menu item in the File menu that appears when one or more items are selected and the directory is writable. Duplicated items receive the names of the original files with " copy" appended before the file extension, if any.
Test Plan:
{F5201386} {F5201393}
Test cases:
- Try to duplicate when nothing is selected: **PASS**: menu item is grayed out
- Try to duplicate anything on a read-only local volume: **PASS**: menu item is grayed out
- Try to duplicate anything on a read-only samba share: **PASS**: menu item is grayed out
- Duplicate single local file on R/W volume: **PASS**: item is duplicated and named correctly
- Duplicate multiple local files on R/W volume: **PASS**: 3 items are duplicated, named correctly, and selected
- Duplicate single local directory on R/W volume: **PASS**: item is duplicated and named correctly, but a rename operation is not initiated
- Duplicate multiple local directories on R/W volume: **PASS**: 3 items are duplicated, named correctly, and selected
- Duplicate single file on R/W samba share: **PASS**: item is duplicated and correctly
- Duplicate multiple files on R/W samba share: **PASS**: 3 items are duplicated, named correctly, and selected
- Duplicate single directory on R/W samba share: **PASS**: item is duplicated and named correctly
- Duplicate multiple directory on R/W samba share: **PASS**: 3 items are duplicated, named correctly, and selected
- Try to undo a successful duplication: **PASS**: operation is undone
This is my first attempt at a big change like this and I'm sure it's full of issues. I will accept any and all suggestions for improvement. :)
Reviewers: #dolphin, #kde_applications, elvisangelaccio, dfaure, broulik, davidedmundson
Subscribers: kfm-devel, meven, markg, fazevedo, cfeck, #dolphin
Tags: #dolphin
Differential Revision: https://phabricator.kde.org/D8208
Diffstat (limited to 'src')
| -rw-r--r-- | src/dolphincontextmenu.cpp | 1 | ||||
| -rw-r--r-- | src/dolphinmainwindow.cpp | 2 | ||||
| -rw-r--r-- | src/dolphinui.rc | 5 | ||||
| -rw-r--r-- | src/views/dolphinview.cpp | 45 | ||||
| -rw-r--r-- | src/views/dolphinview.h | 6 | ||||
| -rw-r--r-- | src/views/dolphinviewactionhandler.cpp | 13 | ||||
| -rw-r--r-- | src/views/dolphinviewactionhandler.h | 5 |
7 files changed, 76 insertions, 1 deletions
diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index 9f3967199..e80283c58 100644 --- a/src/dolphincontextmenu.cpp +++ b/src/dolphincontextmenu.cpp @@ -396,6 +396,7 @@ void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& addAction(collection->action(KStandardAction::name(KStandardAction::Cut))); addAction(collection->action(KStandardAction::name(KStandardAction::Copy))); addAction(createPasteAction()); + addAction(m_mainWindow->actionCollection()->action(QStringLiteral("duplicate"))); addSeparator(); diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 642c24e60..399901688 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1905,6 +1905,7 @@ void DolphinMainWindow::updateFileAndEditActions() QAction* cutAction = col->action(KStandardAction::name(KStandardAction::Cut)); QAction* deleteWithTrashShortcut = col->action(QStringLiteral("delete_shortcut")); // see DolphinViewActionHandler QAction* showTarget = col->action(QStringLiteral("show_target")); + QAction* duplicateAction = col->action(QStringLiteral("duplicate")); // see DolphinViewActionHandler if (list.length() == 1 && list.first().isDir()) { addToPlacesAction->setEnabled(true); @@ -1921,6 +1922,7 @@ void DolphinMainWindow::updateFileAndEditActions() deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); cutAction->setEnabled(capabilities.supportsMoving()); showTarget->setEnabled(list.length() == 1 && list.at(0).isLink()); + duplicateAction->setEnabled(capabilities.supportsWriting()); } } diff --git a/src/dolphinui.rc b/src/dolphinui.rc index e1bb9ee58..e717b67ae 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -1,5 +1,5 @@ <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> -<kpartgui name="dolphin" version="29"> +<kpartgui name="dolphin" version="30"> <MenuBar> <Menu name="file"> <Action name="new_menu" /> @@ -11,6 +11,7 @@ <Action name="add_to_places" /> <Separator/> <Action name="renamefile" /> + <Action name="duplicate" /> <Action name="movetotrash" /> <Action name="deletefile" /> <Separator/> @@ -81,6 +82,7 @@ <Action name="edit_cut" /> <Action name="edit_copy" /> <Action name="renamefile" /> + <Action name="duplicate" /> <Action name="movetotrash" /> <Action name="deletefile" /> <Action name="invert_selection" /> @@ -91,6 +93,7 @@ <Action name="edit_cut" /> <Action name="edit_copy" /> <Action name="renamefile" /> + <Action name="duplicate" /> <Action name="movetotrash" /> <Action name="deletefile" /> <Action name="delete_shortcut" /> diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index cfece0fe6..776436032 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -63,6 +63,7 @@ #include <QDropEvent> #include <QGraphicsSceneDragDropEvent> #include <QMenu> +#include <QMimeDatabase> #include <QPixmapCache> #include <QPointer> #include <QScrollBar> @@ -704,6 +705,50 @@ void DolphinView::pasteIntoFolder() } } +void DolphinView::duplicateSelectedItems() +{ + const KFileItemList itemList = selectedItems(); + if (itemList.isEmpty()) { + return; + } + + const QMimeDatabase db; + + // Duplicate all selected items and append "copy" to the end of the file name + // but before the filename extension, if present + QList<QUrl> newSelection; + for (const auto &item : itemList) { + const QUrl originalURL = item.url(); + const QString originalFileName = item.name(); + QString extension = db.suffixForFileName(originalFileName); + + QUrl duplicateURL = originalURL; + + // No extension; new filename is "<oldfilename> copy" + if (extension.isEmpty()) { + duplicateURL.setPath(i18nc("<file path> copy", "%1 copy", originalURL.path())); + // There's an extension; new filename is "<oldfilename> copy.<extension>" + } else { + // Need to add a dot since QMimeDatabase::suffixForFileName() doesn't include it + extension = QLatin1String(".") + extension; + const QString directoryPath = originalURL.adjusted(QUrl::RemoveFilename).path(); + const QString originalFilenameWithoutExtension = originalFileName.chopped(extension.size()); + // Preserve file's original filename extension in case the casing differs + // from what QMimeDatabase::suffixForFileName() returned + const QString originalExtension = originalFileName.right(extension.size()); + duplicateURL.setPath(i18nc("<file path><filename> copy.<extension>", "%1%2 copy%3", directoryPath, originalFilenameWithoutExtension, originalExtension)); + } + + KIO::CopyJob* job = KIO::copyAs(originalURL, duplicateURL, KIO::HideProgressInfo); + KJobWidgets::setWindow(job, this); + + if (job) { + newSelection << duplicateURL; + KIO::FileUndoManager::self()->recordCopyJob(job); + } + } +} + void DolphinView::stopLoading() { m_model->cancelDirectoryLoading(); diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 60ecb2a95..83c5f92a4 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -375,6 +375,12 @@ public slots: void pasteIntoFolder(); /** + * Creates duplicates of selected items, appending "copy" + * to the end. + */ + void duplicateSelectedItems(); + + /** * Handles a drop of @p dropEvent onto widget @p dropWidget and destination @p destUrl */ void dropUrls(const QUrl &destUrl, QDropEvent *dropEvent, QWidget *dropWidget); diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index ef9f317ee..c61e1aaa9 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -136,6 +136,13 @@ void DolphinViewActionHandler::createActions() deleteWithTrashShortcut->setEnabled(false); connect(deleteWithTrashShortcut, &QAction::triggered, this, &DolphinViewActionHandler::slotDeleteItems); + QAction* duplicateAction = m_actionCollection->addAction(QStringLiteral("duplicate")); + duplicateAction->setText(i18nc("@action:inmenu File", "Duplicate Here")); + duplicateAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-duplicate"))); + m_actionCollection->setDefaultShortcut(duplicateAction, Qt::CTRL | Qt::Key_D); + duplicateAction->setEnabled(false); + connect(duplicateAction, &QAction::triggered, this, &DolphinViewActionHandler::slotDuplicate); + QAction *propertiesAction = m_actionCollection->addAction( QStringLiteral("properties") ); // Well, it's the File menu in dolphinmainwindow and the Edit menu in dolphinpart... :) propertiesAction->setText( i18nc("@action:inmenu File", "Properties") ); @@ -680,6 +687,12 @@ void DolphinViewActionHandler::slotAdjustViewProperties() delete dialog; } +void DolphinViewActionHandler::slotDuplicate() +{ + emit actionBeingHandled(); + m_currentView->duplicateSelectedItems(); +} + void DolphinViewActionHandler::slotProperties() { KPropertiesDialog* dialog = nullptr; diff --git a/src/views/dolphinviewactionhandler.h b/src/views/dolphinviewactionhandler.h index f931b3b9c..3228e7364 100644 --- a/src/views/dolphinviewactionhandler.h +++ b/src/views/dolphinviewactionhandler.h @@ -207,6 +207,11 @@ private Q_SLOTS: void slotAdjustViewProperties(); /** + * Begins a duplicate operation on the selected files + */ + void slotDuplicate(); + + /** * Connected to the "properties" action. * Opens the properties dialog for the selected items of the * active view. The properties dialog shows information |
