Load songs in a background thread while initialising the Organise dialog
This commit is contained in:
parent
98a328cf97
commit
c7459b1b28
@ -22,12 +22,14 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QFutureWatcher>
|
||||
#include <QHash>
|
||||
#include <QMenu>
|
||||
#include <QPushButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QSettings>
|
||||
#include <QSignalMapper>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "iconloader.h"
|
||||
@ -48,7 +50,7 @@ OrganiseDialog::OrganiseDialog(TaskManager* task_manager, QWidget* parent)
|
||||
total_size_(0),
|
||||
resized_by_user_(false) {
|
||||
ui_->setupUi(this);
|
||||
connect(ui_->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
|
||||
connect(ui_->button_box->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
|
||||
SLOT(Reset()));
|
||||
|
||||
ui_->aftercopying->setItemIcon(1, IconLoader::Load("edit-delete"));
|
||||
@ -109,7 +111,7 @@ void OrganiseDialog::SetDestinationModel(QAbstractItemModel* model,
|
||||
ui_->eject_after->setVisible(devices);
|
||||
}
|
||||
|
||||
int OrganiseDialog::SetSongs(const SongList& songs) {
|
||||
bool OrganiseDialog::SetSongs(const SongList& songs) {
|
||||
total_size_ = 0;
|
||||
songs_.clear();
|
||||
|
||||
@ -125,11 +127,17 @@ int OrganiseDialog::SetSongs(const SongList& songs) {
|
||||
|
||||
ui_->free_space->set_additional_bytes(total_size_);
|
||||
UpdatePreviews();
|
||||
SetLoadingSongs(false);
|
||||
|
||||
if (songs_future_.isRunning()) {
|
||||
songs_future_.cancel();
|
||||
}
|
||||
songs_future_ = QFuture<SongList>();
|
||||
|
||||
return songs_.count();
|
||||
}
|
||||
|
||||
int OrganiseDialog::SetUrls(const QList<QUrl>& urls, quint64 total_size) {
|
||||
bool OrganiseDialog::SetUrls(const QList<QUrl>& urls) {
|
||||
QStringList filenames;
|
||||
|
||||
// Only add file:// URLs
|
||||
@ -142,8 +150,30 @@ int OrganiseDialog::SetUrls(const QList<QUrl>& urls, quint64 total_size) {
|
||||
return SetFilenames(filenames);
|
||||
}
|
||||
|
||||
int OrganiseDialog::SetFilenames(const QStringList& filenames,
|
||||
quint64 total_size) {
|
||||
bool OrganiseDialog::SetFilenames(const QStringList& filenames) {
|
||||
songs_future_ =
|
||||
QtConcurrent::run(this, &OrganiseDialog::LoadSongsBlocking, filenames);
|
||||
QFutureWatcher<SongList>* watcher = new QFutureWatcher<SongList>(this);
|
||||
watcher->setFuture(songs_future_);
|
||||
connect(watcher, SIGNAL(finished()), SLOT(LoadSongsFinished()));
|
||||
|
||||
SetLoadingSongs(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OrganiseDialog::SetLoadingSongs(bool loading) {
|
||||
if (loading) {
|
||||
ui_->preview_stack->setCurrentWidget(ui_->loading_page);
|
||||
ui_->button_box->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
} else {
|
||||
ui_->preview_stack->setCurrentWidget(ui_->preview_page);
|
||||
// The Ok button is enabled by UpdatePreviews
|
||||
}
|
||||
}
|
||||
|
||||
void OrganiseDialog::LoadSongsFinished() { SetSongs(songs_future_.result()); }
|
||||
|
||||
SongList OrganiseDialog::LoadSongsBlocking(const QStringList& filenames) {
|
||||
SongList songs;
|
||||
Song song;
|
||||
|
||||
@ -154,8 +184,9 @@ int OrganiseDialog::SetFilenames(const QStringList& filenames,
|
||||
// If it's a directory, add all the files inside.
|
||||
if (QFileInfo(filename).isDir()) {
|
||||
const QDir dir(filename);
|
||||
for (const QString& entry : dir.entryList(
|
||||
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)) {
|
||||
for (const QString& entry :
|
||||
dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot |
|
||||
QDir::Readable)) {
|
||||
filenames_copy << dir.filePath(entry);
|
||||
}
|
||||
continue;
|
||||
@ -164,7 +195,8 @@ int OrganiseDialog::SetFilenames(const QStringList& filenames,
|
||||
TagReaderClient::Instance()->ReadFileBlocking(filename, &song);
|
||||
if (song.is_valid()) songs << song;
|
||||
}
|
||||
return SetSongs(songs);
|
||||
|
||||
return songs;
|
||||
}
|
||||
|
||||
void OrganiseDialog::SetCopy(bool copy) {
|
||||
@ -177,7 +209,6 @@ void OrganiseDialog::InsertTag(const QString& tag) {
|
||||
|
||||
Organise::NewSongInfoList OrganiseDialog::ComputeNewSongsFilenames(
|
||||
const SongList& songs, const OrganiseFormat& format) {
|
||||
|
||||
// Check if we will have multiple files with the same name.
|
||||
// If so, they will erase each other if the overwrite flag is set.
|
||||
// Better to rename them: e.g. foo.bar -> foo(2).bar
|
||||
@ -199,6 +230,10 @@ Organise::NewSongInfoList OrganiseDialog::ComputeNewSongsFilenames(
|
||||
}
|
||||
|
||||
void OrganiseDialog::UpdatePreviews() {
|
||||
if (songs_future_.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndex destination =
|
||||
ui_->destination->model()->index(ui_->destination->currentIndex(), 0);
|
||||
std::shared_ptr<MusicStorage> storage;
|
||||
@ -236,7 +271,7 @@ void OrganiseDialog::UpdatePreviews() {
|
||||
bool ok = format_valid && !songs_.isEmpty();
|
||||
if (capacity != 0 && total_size_ > free) ok = false;
|
||||
|
||||
ui_->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
|
||||
ui_->button_box->button(QDialogButtonBox::Ok)->setEnabled(ok);
|
||||
if (!format_valid) return;
|
||||
|
||||
new_songs_info_ = ComputeNewSongsFilenames(songs_, format_);
|
||||
|
@ -51,9 +51,13 @@ class OrganiseDialog : public QDialog {
|
||||
|
||||
void SetDestinationModel(QAbstractItemModel* model, bool devices = false);
|
||||
|
||||
int SetSongs(const SongList& songs);
|
||||
int SetUrls(const QList<QUrl>& urls, quint64 total_size = 0);
|
||||
int SetFilenames(const QStringList& filenames, quint64 total_size = 0);
|
||||
// These functions return true if any songs were actually added to the dialog.
|
||||
// SetSongs returns immediately, SetUrls and SetFilenames load the songs in
|
||||
// the background.
|
||||
bool SetSongs(const SongList& songs);
|
||||
bool SetUrls(const QList<QUrl>& urls);
|
||||
bool SetFilenames(const QStringList& filenames);
|
||||
|
||||
void SetCopy(bool copy);
|
||||
|
||||
public slots:
|
||||
@ -69,9 +73,13 @@ class OrganiseDialog : public QDialog {
|
||||
void InsertTag(const QString& tag);
|
||||
void UpdatePreviews();
|
||||
|
||||
void LoadSongsFinished();
|
||||
void OrganiseFinished(const QStringList& files_with_errors);
|
||||
|
||||
private:
|
||||
SongList LoadSongsBlocking(const QStringList& filenames);
|
||||
void SetLoadingSongs(bool loading);
|
||||
|
||||
static Organise::NewSongInfoList ComputeNewSongsFilenames(
|
||||
const SongList& songs, const OrganiseFormat& format);
|
||||
|
||||
@ -80,6 +88,7 @@ class OrganiseDialog : public QDialog {
|
||||
|
||||
OrganiseFormat format_;
|
||||
|
||||
QFuture<SongList> songs_future_;
|
||||
SongList songs_;
|
||||
Organise::NewSongInfoList new_songs_info_;
|
||||
quint64 total_size_;
|
||||
|
@ -136,13 +136,73 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QListWidget" name="preview"/>
|
||||
<widget class="QStackedWidget" name="preview_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="preview_page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="preview"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="loading_page">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>264</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="BusyIndicator" name="loading_indicator" native="true">
|
||||
<property name="text" stdset="0">
|
||||
<string>Loading...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>264</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<widget class="QDialogButtonBox" name="button_box">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -165,6 +225,12 @@
|
||||
<extends>QTextEdit</extends>
|
||||
<header>widgets/linetextedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BusyIndicator</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/busyindicator.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>destination</tabstop>
|
||||
@ -176,15 +242,14 @@
|
||||
<tabstop>replace_spaces</tabstop>
|
||||
<tabstop>replace_ascii</tabstop>
|
||||
<tabstop>overwrite</tabstop>
|
||||
<tabstop>preview</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../data/data.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<sender>button_box</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>OrganiseDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
@ -200,7 +265,7 @@
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<sender>button_box</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>OrganiseDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
|
Loading…
x
Reference in New Issue
Block a user