mirror of
https://invent.kde.org/system/dolphin
synced 2024-10-28 03:21:56 +00:00
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
This commit is contained in:
parent
8e97c4981c
commit
405dd624fb
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -374,6 +374,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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -206,6 +206,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
|
||||
|
|
Loading…
Reference in a new issue