1 /* This file is part of Clementine.
2    Copyright 2010-2011, David Sansome <me@davidsansome.com>
3    Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
4    Copyright 2014, John Maguire <john.maguire@gmail.com>
5 
6    Clementine is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Clementine is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "deletefiles.h"
21 
22 #include <QStringList>
23 #include <QTimer>
24 #include <QThread>
25 #include <QUrl>
26 
27 #include "musicstorage.h"
28 #include "taskmanager.h"
29 
30 const int DeleteFiles::kBatchSize = 50;
31 
DeleteFiles(TaskManager * task_manager,std::shared_ptr<MusicStorage> storage)32 DeleteFiles::DeleteFiles(TaskManager* task_manager,
33                          std::shared_ptr<MusicStorage> storage)
34     : thread_(nullptr),
35       task_manager_(task_manager),
36       storage_(storage),
37       started_(false),
38       task_id_(0),
39       progress_(0) {
40   original_thread_ = thread();
41 }
42 
~DeleteFiles()43 DeleteFiles::~DeleteFiles() {}
44 
Start(const SongList & songs)45 void DeleteFiles::Start(const SongList& songs) {
46   if (thread_) return;
47 
48   songs_ = songs;
49 
50   task_id_ = task_manager_->StartTask(tr("Deleting files"));
51   task_manager_->SetTaskBlocksLibraryScans(true);
52 
53   thread_ = new QThread;
54   connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
55 
56   moveToThread(thread_);
57   thread_->start();
58 }
59 
Start(const QUrl & url)60 void DeleteFiles::Start(const QUrl& url) {
61   SongList songs;
62   Song song;
63   song.set_url(url);
64   songs << song;
65 
66   Start(songs);
67 }
68 
Start(const QStringList & filenames)69 void DeleteFiles::Start(const QStringList& filenames) {
70   SongList songs;
71   for (const QString& filename : filenames) {
72     Song song;
73     song.set_url(QUrl::fromLocalFile(filename));
74     songs << song;
75   }
76 
77   Start(songs);
78 }
79 
ProcessSomeFiles()80 void DeleteFiles::ProcessSomeFiles() {
81   if (!started_) {
82     storage_->StartDelete();
83     started_ = true;
84   }
85 
86   // None left?
87   if (progress_ >= songs_.count()) {
88     task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
89 
90     storage_->FinishCopy(songs_with_errors_.isEmpty());
91 
92     task_manager_->SetTaskFinished(task_id_);
93 
94     emit Finished(songs_with_errors_);
95 
96     // Move back to the original thread so deleteLater() can get called in
97     // the main thread's event loop
98     moveToThread(original_thread_);
99     deleteLater();
100 
101     // Stop this thread
102     thread_->quit();
103     return;
104   }
105 
106   // We process files in batches so we can be cancelled part-way through.
107 
108   const int n = qMin(songs_.count(), progress_ + kBatchSize);
109   for (; progress_ < n; ++progress_) {
110     task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
111 
112     const Song& song = songs_[progress_];
113 
114     MusicStorage::DeleteJob job;
115     job.metadata_ = song;
116 
117     if (!storage_->DeleteFromStorage(job)) {
118       songs_with_errors_ << song;
119     }
120   }
121 
122   QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
123 }
124