Add optional delete from disk in collection and playlist

Fixes #284
This commit is contained in:
Jonas Kvinge
2020-08-19 22:02:35 +02:00
parent 9b14df6b27
commit 653a35496d
19 changed files with 411 additions and 87 deletions

View File

@@ -34,10 +34,11 @@
const int DeleteFiles::kBatchSize = 50;
DeleteFiles::DeleteFiles(TaskManager *task_manager, std::shared_ptr<MusicStorage> storage)
DeleteFiles::DeleteFiles(TaskManager *task_manager, std::shared_ptr<MusicStorage> storage, const bool use_trash)
: thread_(nullptr),
task_manager_(task_manager),
storage_(storage),
use_trash_(use_trash),
started_(false),
task_id_(0),
progress_(0) {
@@ -112,6 +113,7 @@ void DeleteFiles::ProcessSomeFiles() {
MusicStorage::DeleteJob job;
job.metadata_ = song;
job.use_trash_ = use_trash_;
if (!storage_->DeleteFromStorage(job)) {
songs_with_errors_ << song;

View File

@@ -38,7 +38,7 @@ class DeleteFiles : public QObject {
Q_OBJECT
public:
explicit DeleteFiles(TaskManager *task_manager, std::shared_ptr<MusicStorage> storage);
explicit DeleteFiles(TaskManager *task_manager, std::shared_ptr<MusicStorage> storage, const bool use_trash);
~DeleteFiles() override;
static const int kBatchSize;
@@ -59,6 +59,7 @@ signals:
std::shared_ptr<MusicStorage> storage_;
SongList songs_;
bool use_trash_;
bool started_;

View File

@@ -108,6 +108,17 @@ bool FilesystemMusicStorage::DeleteFromStorage(const DeleteJob &job) {
QString path = job.metadata_.url().toLocalFile();
QFileInfo fileInfo(path);
if (job.use_trash_) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
if (fileInfo.isDir())
return Utilities::MoveToTrashRecursive(path);
else
return QFile::moveToTrash(path);
#else
return false;
#endif
}
if (fileInfo.isDir())
return Utilities::RemoveRecursive(path);
else

View File

@@ -91,6 +91,8 @@
#include "database.h"
#include "player.h"
#include "appearance.h"
#include "filesystemmusicstorage.h"
#include "deletefiles.h"
#include "engine/enginetype.h"
#include "engine/enginebase.h"
#include "engine/engine_fwd.h"
@@ -100,6 +102,7 @@
#include "dialogs/trackselectiondialog.h"
#include "dialogs/edittagdialog.h"
#include "dialogs/addstreamdialog.h"
#include "dialogs/deleteconfirmationdialog.h"
#include "organize/organizedialog.h"
#include "widgets/fancytabwidget.h"
#include "widgets/playingwidget.h"
@@ -261,15 +264,16 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd
playlist_play_pause_(nullptr),
playlist_stop_after_(nullptr),
playlist_undoredo_(nullptr),
playlist_organize_(nullptr),
playlist_copy_url_(nullptr),
playlist_show_in_collection_(nullptr),
playlist_copy_to_collection_(nullptr),
playlist_move_to_collection_(nullptr),
playlist_open_in_browser_(nullptr),
playlist_organize_(nullptr),
#ifndef Q_OS_WIN
playlist_copy_to_device_(nullptr),
#endif
playlist_open_in_browser_(nullptr),
playlist_copy_url_(nullptr),
playlist_delete_(nullptr),
playlist_queue_(nullptr),
playlist_queue_play_next_(nullptr),
playlist_skip_(nullptr),
@@ -286,7 +290,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd
doubleclick_addmode_(BehaviourSettingsPage::AddBehaviour_Append),
doubleclick_playmode_(BehaviourSettingsPage::PlayBehaviour_Never),
menu_playmode_(BehaviourSettingsPage::PlayBehaviour_Never),
exit_count_(0)
exit_count_(0),
delete_files_(false)
{
qLog(Debug) << "Starting";
@@ -659,16 +664,16 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd
playlist_menu_->addAction(ui_->action_add_files_to_transcoder);
#endif
playlist_menu_->addSeparator();
playlist_copy_url_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy URL(s)..."), this, SLOT(PlaylistCopyUrl()));
playlist_show_in_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-find"), tr("Show in collection..."), this, SLOT(ShowInCollection()));
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser()));
playlist_organize_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, SLOT(PlaylistMoveToCollection()));
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, SLOT(PlaylistCopyToCollection()));
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, SLOT(PlaylistMoveToCollection()));
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
playlist_copy_to_device_ = playlist_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(PlaylistCopyToDevice()));
#endif
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, SLOT(PlaylistCopyToCollection()));
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, SLOT(PlaylistMoveToCollection()));
playlist_organize_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, SLOT(PlaylistMoveToCollection()));
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser()));
playlist_open_in_browser_->setVisible(false);
playlist_show_in_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-find"), tr("Show in collection..."), this, SLOT(ShowInCollection()));
playlist_copy_url_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy URL(s)..."), this, SLOT(PlaylistCopyUrl()));
playlist_delete_ = playlist_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(PlaylistDelete()));
playlist_menu_->addSeparator();
playlistitem_actions_separator_ = playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_->action_clear_playlist);
@@ -990,6 +995,10 @@ void MainWindow::ReloadSettings() {
}
}
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
delete_files_ = s.value("delete_files", false).toBool();
s.endGroup();
osd_->ReloadSettings();
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings_.value("search_for_cover_auto", true).toBool());
@@ -1733,6 +1742,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
playlist_copy_to_device_->setVisible(false);
#endif
playlist_organize_->setVisible(false);
playlist_delete_->setVisible(false);
playlist_copy_url_->setVisible(selected > 0);
@@ -1805,6 +1815,10 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
playlist_copy_to_device_->setVisible(editable > 0);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
playlist_delete_->setVisible(delete_files_ && editable > 0);
#endif
// Remove old item actions, if any.
for (QAction *action : playlistitem_actions_) {
playlist_menu_->removeAction(action);
@@ -2850,3 +2864,39 @@ void MainWindow::Love() {
if (tray_icon_) tray_icon_->LoveStateChanged(false);
}
void MainWindow::PlaylistDelete() {
if (!delete_files_) return;
SongList selected_songs;
QStringList files;
bool is_current_item = false;
for (const QModelIndex &proxy_idx : ui_->playlist->view()->selectionModel()->selectedRows()) {
QModelIndex source_idx = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_idx);
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
if (!item || !item->Metadata().url().isLocalFile()) continue;
selected_songs << item->Metadata();
files << item->Metadata().url().toLocalFile();
if (item == app_->player()->GetCurrentItem()) is_current_item = true;
}
if (selected_songs.isEmpty()) return;
if (DeleteConfirmationDialog::warning(files) != QDialogButtonBox::Yes) return;
if (app_->player()->GetState() == Engine::Playing && app_->playlist_manager()->current()->rowCount() == selected_songs.count()) {
app_->player()->Stop();
}
ui_->playlist->view()->RemoveSelected();
if (app_->player()->GetState() == Engine::Playing && is_current_item) {
app_->player()->Next();
}
std::shared_ptr<MusicStorage> storage(new FilesystemMusicStorage("/"));
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage, true);
connect(delete_files, SIGNAL(Finished(SongList)), SLOT(DeleteFinished(SongList)));
delete_files->Start(selected_songs);
}

View File

@@ -264,6 +264,8 @@ class MainWindow : public QMainWindow, public PlatformInterface {
void ExitFinished();
void PlaylistDelete();
private:
void SaveSettings();
@@ -331,15 +333,16 @@ class MainWindow : public QMainWindow, public PlatformInterface {
QAction *playlist_play_pause_;
QAction *playlist_stop_after_;
QAction *playlist_undoredo_;
QAction *playlist_organize_;
QAction *playlist_copy_url_;
QAction *playlist_show_in_collection_;
QAction *playlist_copy_to_collection_;
QAction *playlist_move_to_collection_;
QAction *playlist_open_in_browser_;
QAction *playlist_organize_;
#ifndef Q_OS_WIN
QAction *playlist_copy_to_device_;
#endif
QAction *playlist_open_in_browser_;
QAction *playlist_copy_url_;
QAction *playlist_delete_;
QAction *playlist_queue_;
QAction* playlist_queue_play_next_;
QAction *playlist_skip_;
@@ -369,6 +372,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
Song song_playing_;
QImage image_original_;
int exit_count_;
bool delete_files_;
};

View File

@@ -56,6 +56,7 @@ class MusicStorage {
typedef std::function<void(float progress)> ProgressFunction;
struct CopyJob {
CopyJob() : overwrite_(false), mark_as_listened_(false), remove_original_(false), albumcover_(false) {}
QString source_;
QString destination_;
Song metadata_;
@@ -70,7 +71,9 @@ class MusicStorage {
};
struct DeleteJob {
DeleteJob() : use_trash_(false) {}
Song metadata_;
bool use_trash_;
};
virtual QString LocalPath() const { return QString(); }

View File

@@ -253,6 +253,30 @@ QString MakeTempDir(const QString template_name) {
}
bool MoveToTrashRecursive(const QString &path) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QDir dir(path);
for (const QString &child : dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Hidden)) {
if (!MoveToTrashRecursive(path + "/" + child))
return false;
}
for (const QString &child : dir.entryList(QDir::NoDotAndDotDot | QDir::Files | QDir::Hidden)) {
if (!QFile::moveToTrash(path + "/" + child))
return false;
}
return dir.rmdir(path);
#else
return false;
#endif
}
bool RemoveRecursive(const QString &path) {
QDir dir(path);

View File

@@ -64,6 +64,7 @@ quint64 FileSystemFreeSpace(const QString &path);
QString MakeTempDir(const QString template_name = QString());
bool MoveToTrashRecursive(const QString &path);
bool RemoveRecursive(const QString &path);
bool CopyRecursive(const QString &source, const QString &destination);
bool Copy(QIODevice *source, QIODevice *destination);