diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a95527cbe..b6bd43001 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,11 +35,13 @@ set(SOURCES
core/backgroundthread.cpp
core/commandlineoptions.cpp
core/database.cpp
+ core/filesystemmusicstorage.cpp
core/fht.cpp
core/globalshortcutbackend.cpp
core/globalshortcuts.cpp
core/gnomeglobalshortcutbackend.cpp
core/mergedproxymodel.cpp
+ core/musicstorage.cpp
core/networkaccessmanager.cpp
core/organise.cpp
core/organiseformat.cpp
diff --git a/src/core/filesystemmusicstorage.cpp b/src/core/filesystemmusicstorage.cpp
new file mode 100644
index 000000000..8965013fb
--- /dev/null
+++ b/src/core/filesystemmusicstorage.cpp
@@ -0,0 +1,49 @@
+/* This file is part of Clementine.
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#include "filesystemmusicstorage.h"
+
+#include
+#include
+
+FilesystemMusicStorage::FilesystemMusicStorage(const QString& root)
+ : root_(root)
+{
+}
+
+bool FilesystemMusicStorage::CopyToStorage(
+ const QString& source, const QString& destination,
+ const Song&, bool overwrite, bool remove_original) {
+ const QString dest_filename = root_ + "/" + destination;
+
+ // Don't do anything if the destination is the same as the source
+ if (source == dest_filename)
+ return true;
+
+ // Create directories as required
+ QDir dir;
+ dir.mkpath(dest_filename.section('/', 0, -2));
+
+ // Remove the destination file if it exists and we want to overwrite
+ if (overwrite && QFile::exists(dest_filename))
+ QFile::remove(dest_filename);
+
+ // Copy or move
+ if (remove_original)
+ return QFile::rename(source, dest_filename);
+ else
+ return QFile::copy(source, dest_filename);
+}
diff --git a/src/core/filesystemmusicstorage.h b/src/core/filesystemmusicstorage.h
new file mode 100644
index 000000000..b9b6764f7
--- /dev/null
+++ b/src/core/filesystemmusicstorage.h
@@ -0,0 +1,35 @@
+/* This file is part of Clementine.
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#ifndef FILESYSTEMMUSICSTORAGE_H
+#define FILESYSTEMMUSICSTORAGE_H
+
+#include "musicstorage.h"
+
+class FilesystemMusicStorage : public MusicStorage {
+public:
+ FilesystemMusicStorage(const QString& root);
+
+ QString LocalPath() const { return root_; }
+
+ bool CopyToStorage(const QString &source, const QString &destination,
+ const Song &metadata, bool overwrite, bool remove_original);
+
+private:
+ QString root_;
+};
+
+#endif // FILESYSTEMMUSICSTORAGE_H
diff --git a/src/core/musicstorage.cpp b/src/core/musicstorage.cpp
new file mode 100644
index 000000000..1e2f3f12c
--- /dev/null
+++ b/src/core/musicstorage.cpp
@@ -0,0 +1,21 @@
+/* This file is part of Clementine.
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#include "musicstorage.h"
+
+MusicStorage::MusicStorage()
+{
+}
diff --git a/src/core/musicstorage.h b/src/core/musicstorage.h
new file mode 100644
index 000000000..f40eeb9ca
--- /dev/null
+++ b/src/core/musicstorage.h
@@ -0,0 +1,40 @@
+/* This file is part of Clementine.
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#ifndef MUSICSTORAGE_H
+#define MUSICSTORAGE_H
+
+#include "song.h"
+
+#include
+
+class MusicStorage {
+public:
+ MusicStorage();
+ virtual ~MusicStorage() {}
+
+ static const int kStorageRole = Qt::UserRole + 100;
+
+ virtual QString LocalPath() const { return QString(); }
+
+ virtual bool CopyToStorage(const QString& source, const QString& destination,
+ const Song& metadata, bool overwrite,
+ bool remove_original) = 0;
+};
+
+Q_DECLARE_METATYPE(MusicStorage*);
+
+#endif // MUSICSTORAGE_H
diff --git a/src/core/organise.cpp b/src/core/organise.cpp
index d2e179a82..0606fd602 100644
--- a/src/core/organise.cpp
+++ b/src/core/organise.cpp
@@ -14,6 +14,7 @@
along with Clementine. If not, see .
*/
+#include "musicstorage.h"
#include "organise.h"
#include "taskmanager.h"
@@ -24,7 +25,7 @@
const int Organise::kBatchSize = 10;
-Organise::Organise(TaskManager* task_manager, const QString &destination,
+Organise::Organise(TaskManager* task_manager, MusicStorage* destination,
const OrganiseFormat &format, bool copy, bool overwrite,
const QStringList& files)
: thread_(NULL),
@@ -95,25 +96,8 @@ void Organise::ProcessSomeFiles() {
if (!song.is_valid())
continue;
- // Get the destination filename
- QString dest_filename = destination_ + "/" + format_.GetFilenameForSong(song);
-
- // Don't do anything if the destination is the same as the source
- if (filename == dest_filename)
- continue;
-
- // Create directories as required
- dir.mkpath(dest_filename.section('/', 0, -2));
-
- // Remove the destination file if it exists and we want to overwrite
- if (overwrite_ && QFile::exists(dest_filename))
- QFile::remove(dest_filename);
-
- // Copy or move
- if (copy_)
- QFile::copy(filename, dest_filename);
- else
- QFile::rename(filename, dest_filename);
+ destination_->CopyToStorage(filename, format_.GetFilenameForSong(song),
+ song, overwrite_, !copy_);
}
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
diff --git a/src/core/organise.h b/src/core/organise.h
index aa76bc72d..2d9b78245 100644
--- a/src/core/organise.h
+++ b/src/core/organise.h
@@ -21,13 +21,14 @@
#include "organiseformat.h"
+class MusicStorage;
class TaskManager;
class Organise : public QObject {
Q_OBJECT
public:
- Organise(TaskManager* task_manager, const QString& destination,
+ Organise(TaskManager* task_manager, MusicStorage* destination,
const OrganiseFormat& format, bool copy, bool overwrite,
const QStringList& files);
@@ -42,8 +43,8 @@ private:
QThread* thread_;
QThread* original_thread_;
TaskManager* task_manager_;
+ MusicStorage* destination_;
- const QString destination_;
const OrganiseFormat format_;
const bool copy_;
const bool overwrite_;
diff --git a/src/devices/connecteddevice.h b/src/devices/connecteddevice.h
index 329afc5bc..4ccf33ed1 100644
--- a/src/devices/connecteddevice.h
+++ b/src/devices/connecteddevice.h
@@ -26,6 +26,7 @@ class DeviceLister;
class DeviceManager;
class LibraryBackend;
class LibraryModel;
+class MusicStorage;
class ConnectedDevice : public QObject {
Q_OBJECT
@@ -40,6 +41,8 @@ public:
QString unique_id() const { return unique_id_; }
LibraryModel* model() const { return model_; }
+ virtual MusicStorage* storage() = 0;
+
signals:
void TaskStarted(int id);
void Error(const QString& message);
diff --git a/src/devices/devicemanager.cpp b/src/devices/devicemanager.cpp
index 4b87a5244..c220860b5 100644
--- a/src/devices/devicemanager.cpp
+++ b/src/devices/devicemanager.cpp
@@ -27,11 +27,25 @@
#include
#include
+#include
#include
const int DeviceManager::kDeviceIconSize = 32;
const int DeviceManager::kDeviceIconOverlaySize = 16;
+DeviceStateFilterModel::DeviceStateFilterModel(QObject *parent,
+ DeviceManager::State state)
+ : QSortFilterProxyModel(parent),
+ state_(state)
+{
+}
+
+bool DeviceStateFilterModel::filterAcceptsRow(int row, const QModelIndex&) const {
+ return sourceModel()->index(row, 0).data(DeviceManager::Role_State).toInt()
+ == state_;
+}
+
+
DeviceManager::DeviceInfo::DeviceInfo()
: database_id_(-1),
task_percentage_(-1)
@@ -132,6 +146,10 @@ DeviceManager::DeviceManager(BackgroundThread* database,
devices_ << info;
}
+ // This proxy model only shows connected devices
+ connected_devices_model_ = new DeviceStateFilterModel(this);
+ connected_devices_model_->setSourceModel(this);
+
#ifdef Q_WS_X11
AddLister(new DeviceKitLister);
#endif
diff --git a/src/devices/devicemanager.h b/src/devices/devicemanager.h
index 77076ee63..6b53fbef4 100644
--- a/src/devices/devicemanager.h
+++ b/src/devices/devicemanager.h
@@ -23,6 +23,7 @@
#include
#include
+#include
#include
@@ -47,6 +48,8 @@ public:
Role_FreeSpace,
Role_IconName,
Role_UpdatingPercentage,
+
+ LastRole,
};
enum State {
@@ -61,6 +64,8 @@ public:
BackgroundThread* database() const { return database_; }
TaskManager* task_manager() const { return task_manager_; }
+ QAbstractItemModel* connected_devices_model() const { return connected_devices_model_; }
+
// Get info about devices
int GetDatabaseId(int row) const;
DeviceLister* GetLister(int row) const;
@@ -150,6 +155,8 @@ private:
DeviceDatabaseBackend* backend_;
TaskManager* task_manager_;
+ QSortFilterProxyModel* connected_devices_model_;
+
QIcon not_connected_overlay_;
QList listers_;
@@ -161,6 +168,20 @@ private:
QMap active_tasks_;
};
+class DeviceStateFilterModel : public QSortFilterProxyModel {
+public:
+ DeviceStateFilterModel(QObject* parent, DeviceManager::State state =
+ DeviceManager::State_Connected);
+
+protected:
+ bool filterAcceptsRow(int row, const QModelIndex& parent) const;
+
+private:
+ DeviceManager::State state_;
+};
+
+
+
template
void DeviceManager::AddDeviceClass() {
QStringList schemes = T::url_schemes();
diff --git a/src/devices/deviceview.cpp b/src/devices/deviceview.cpp
index a8c6e8709..18fcc872d 100644
--- a/src/devices/deviceview.cpp
+++ b/src/devices/deviceview.cpp
@@ -177,7 +177,7 @@ void DeviceView::SetLibrary(LibraryModel* library) {
library_ = library;
organise_dialog_.reset(new OrganiseDialog(manager_->task_manager()));
- organise_dialog_->AddDirectoryModel(library_->directory_model());
+ organise_dialog_->SetDestinationModel(library_->directory_model());
}
void DeviceView::contextMenuEvent(QContextMenuEvent* e) {
diff --git a/src/devices/filesystemdevice.cpp b/src/devices/filesystemdevice.cpp
index a55ac0267..cb1051bdf 100644
--- a/src/devices/filesystemdevice.cpp
+++ b/src/devices/filesystemdevice.cpp
@@ -28,6 +28,7 @@ FilesystemDevice::FilesystemDevice(
const QString& unique_id, DeviceManager* manager,
int database_id, bool first_time)
: ConnectedDevice(url, lister, unique_id, manager, database_id, first_time),
+ FilesystemMusicStorage(url.toLocalFile()),
watcher_(new BackgroundThreadImplementation(this))
{
// Create the library watcher
diff --git a/src/devices/filesystemdevice.h b/src/devices/filesystemdevice.h
index ba2868a1c..09779f708 100644
--- a/src/devices/filesystemdevice.h
+++ b/src/devices/filesystemdevice.h
@@ -19,11 +19,12 @@
#include "connecteddevice.h"
#include "core/backgroundthread.h"
+#include "core/filesystemmusicstorage.h"
class DeviceManager;
class LibraryWatcher;
-class FilesystemDevice : public ConnectedDevice {
+class FilesystemDevice : public ConnectedDevice, public FilesystemMusicStorage {
Q_OBJECT
public:
@@ -35,6 +36,8 @@ public:
static QStringList url_schemes() { return QStringList() << "file"; }
+ MusicStorage* storage() { return this; }
+
private:
BackgroundThread* watcher_;
};
diff --git a/src/devices/gpoddevice.cpp b/src/devices/gpoddevice.cpp
index 6ab44e071..619d49c7b 100644
--- a/src/devices/gpoddevice.cpp
+++ b/src/devices/gpoddevice.cpp
@@ -47,3 +47,10 @@ GPodDevice::~GPodDevice() {
}
+bool GPodDevice::CopyToStorage(
+ const QString &source, const QString &destination,
+ const Song &metadata, bool overwrite, bool remove_original)
+{
+ return true;
+}
+
diff --git a/src/devices/gpoddevice.h b/src/devices/gpoddevice.h
index d4d7a06ff..0df5d0aa3 100644
--- a/src/devices/gpoddevice.h
+++ b/src/devices/gpoddevice.h
@@ -18,10 +18,11 @@
#define GPODDEVICE_H
#include "connecteddevice.h"
+#include "core/musicstorage.h"
class GPodLoader;
-class GPodDevice : public ConnectedDevice {
+class GPodDevice : public ConnectedDevice, public MusicStorage {
Q_OBJECT
public:
@@ -33,6 +34,11 @@ public:
static QStringList url_schemes() { return QStringList() << "ipod"; }
+ MusicStorage* storage() { return this; }
+
+ bool CopyToStorage(const QString &source, const QString &destination,
+ const Song &metadata, bool overwrite, bool remove_original);
+
private:
QThread* loader_thread_;
GPodLoader* loader_;
diff --git a/src/library/librarydirectorymodel.cpp b/src/library/librarydirectorymodel.cpp
index 2033ee044..60cdf5be4 100644
--- a/src/library/librarydirectorymodel.cpp
+++ b/src/library/librarydirectorymodel.cpp
@@ -16,6 +16,8 @@
#include "librarydirectorymodel.h"
#include "librarybackend.h"
+#include "core/filesystemmusicstorage.h"
+#include "core/musicstorage.h"
#include "ui/iconloader.h"
LibraryDirectoryModel::LibraryDirectoryModel(LibraryBackend* backend, QObject* parent)
@@ -27,10 +29,15 @@ LibraryDirectoryModel::LibraryDirectoryModel(LibraryBackend* backend, QObject* p
connect(backend_, SIGNAL(DirectoryDeleted(Directory)), SLOT(DirectoryDeleted(Directory)));
}
+LibraryDirectoryModel::~LibraryDirectoryModel() {
+ qDeleteAll(storage_);
+}
+
void LibraryDirectoryModel::DirectoryDiscovered(const Directory &dir) {
QStandardItem* item = new QStandardItem(dir.path);
item->setData(dir.id, kIdRole);
item->setIcon(dir_icon_);
+ storage_ << new FilesystemMusicStorage(dir.path);
appendRow(item);
}
@@ -38,6 +45,7 @@ void LibraryDirectoryModel::DirectoryDeleted(const Directory &dir) {
for (int i=0 ; idata(kIdRole).toInt() == dir.id) {
removeRow(i);
+ delete storage_.takeAt(i);
break;
}
}
@@ -60,3 +68,11 @@ void LibraryDirectoryModel::RemoveDirectory(const QModelIndex& index) {
backend_->RemoveDirectory(dir);
}
+
+QVariant LibraryDirectoryModel::data(const QModelIndex &index, int role) const {
+ if (role == MusicStorage::kStorageRole) {
+ return QVariant::fromValue(storage_[index.row()]);
+ }
+
+ return QStandardItemModel::data(index, role);
+}
diff --git a/src/library/librarydirectorymodel.h b/src/library/librarydirectorymodel.h
index cd7a6de8e..47669b494 100644
--- a/src/library/librarydirectorymodel.h
+++ b/src/library/librarydirectorymodel.h
@@ -23,17 +23,21 @@
#include "directory.h"
class LibraryBackend;
+class MusicStorage;
class LibraryDirectoryModel : public QStandardItemModel {
Q_OBJECT
public:
LibraryDirectoryModel(LibraryBackend* backend, QObject* parent = 0);
+ ~LibraryDirectoryModel();
// To be called by GUIs
void AddDirectory(const QString& path);
void RemoveDirectory(const QModelIndex& index);
+ QVariant data(const QModelIndex &index, int role) const;
+
private slots:
// To be called by the backend
void DirectoryDiscovered(const Directory& directories);
@@ -44,6 +48,7 @@ class LibraryDirectoryModel : public QStandardItemModel {
QIcon dir_icon_;
LibraryBackend* backend_;
+ QList storage_;
};
#endif // LIBRARYDIRECTORYMODEL_H
diff --git a/src/library/librarymodel.h b/src/library/librarymodel.h
index d87ad1c7f..76f14a647 100644
--- a/src/library/librarymodel.h
+++ b/src/library/librarymodel.h
@@ -41,7 +41,7 @@ class LibraryModel : public SimpleTreeModel {
LibraryModel(LibraryBackend* backend, QObject* parent = 0);
~LibraryModel();
- enum {
+ enum Role {
Role_Type = Qt::UserRole + 1,
Role_ContainerType,
Role_SortText,
diff --git a/src/library/libraryview.cpp b/src/library/libraryview.cpp
index d3966049b..d94042991 100644
--- a/src/library/libraryview.cpp
+++ b/src/library/libraryview.cpp
@@ -118,7 +118,7 @@ void LibraryView::ReloadSettings() {
void LibraryView::SetTaskManager(TaskManager *task_manager) {
organise_dialog_.reset(new OrganiseDialog(task_manager));
- organise_dialog_->AddDirectoryModel(library_->directory_model());
+ organise_dialog_->SetDestinationModel(library_->directory_model());
}
void LibraryView::SetLibrary(LibraryModel *library) {
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp
index 312f15b40..3f696beed 100644
--- a/src/ui/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -203,7 +203,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
ui_->devices_view->SetDeviceManager(devices_);
ui_->devices_view->SetLibrary(library_->model());
- organise_dialog_->AddDirectoryModel(library_->model()->directory_model());
+ organise_dialog_->SetDestinationModel(library_->model()->directory_model());
cover_manager_->Init();
diff --git a/src/ui/organisedialog.cpp b/src/ui/organisedialog.cpp
index 62ad7a6fb..48261720a 100644
--- a/src/ui/organisedialog.cpp
+++ b/src/ui/organisedialog.cpp
@@ -16,6 +16,7 @@
#include "organisedialog.h"
#include "ui_organisedialog.h"
+#include "core/musicstorage.h"
#include "core/organise.h"
#include
@@ -87,9 +88,7 @@ OrganiseDialog::~OrganiseDialog() {
delete ui_;
}
-void OrganiseDialog::AddDirectoryModel(QAbstractItemModel *model) {
- // TODO: Add this model to a proxy model that merges different models
- // together, eg. from the local library and also removable devices.
+void OrganiseDialog::SetDestinationModel(QAbstractItemModel *model) {
ui_->destination->setModel(model);
}
@@ -148,6 +147,15 @@ void OrganiseDialog::InsertTag(const QString &tag) {
}
void OrganiseDialog::UpdatePreviews() {
+ const QModelIndex destination = ui_->destination->model()->index(
+ ui_->destination->currentIndex(), 0);
+ if (!destination.isValid())
+ return;
+ const MusicStorage* storage =
+ destination.data(MusicStorage::kStorageRole).value();
+
+ const bool has_local_destination = !storage->LocalPath().isEmpty();
+
// Update the format object
format_.set_format(ui_->naming->toPlainText());
format_.set_replace_non_ascii(ui_->replace_ascii->isChecked());
@@ -155,16 +163,19 @@ void OrganiseDialog::UpdatePreviews() {
format_.set_replace_the(ui_->replace_the->isChecked());
const bool format_valid = format_.IsValid();
- ui_->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
- format_valid && !ui_->destination->currentText().isEmpty());
+ ui_->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(format_valid);
if (!format_valid)
return;
+ // Update the previews
ui_->preview->clear();
- foreach (const Song& song, preview_songs_) {
- QString filename = ui_->destination->currentText() + "/" +
- format_.GetFilenameForSong(song);
- ui_->preview->addItem(QDir::toNativeSeparators(filename));
+ ui_->preview->setVisible(has_local_destination);
+ if (has_local_destination) {
+ foreach (const Song& song, preview_songs_) {
+ QString filename = storage->LocalPath() + "/" +
+ format_.GetFilenameForSong(song);
+ ui_->preview->addItem(QDir::toNativeSeparators(filename));
+ }
}
}
@@ -202,9 +213,14 @@ void OrganiseDialog::accept() {
s.setValue("overwrite", ui_->overwrite->isChecked());
s.setValue("destination", ui_->destination->currentText());
+ const QModelIndex destination = ui_->destination->model()->index(
+ ui_->destination->currentIndex(), 0);
+ MusicStorage* storage =
+ destination.data(MusicStorage::kStorageRole).value();
+
// It deletes itself when it's finished.
Organise* organise = new Organise(
- task_manager_, ui_->destination->currentText(), format_,
+ task_manager_, storage, format_,
!ui_->move->isChecked(), ui_->overwrite->isChecked(), filenames_);
organise->Start();
diff --git a/src/ui/organisedialog.h b/src/ui/organisedialog.h
index 6e55b0f16..bf1757e48 100644
--- a/src/ui/organisedialog.h
+++ b/src/ui/organisedialog.h
@@ -43,7 +43,7 @@ public:
static const char* kDefaultFormat;
static const char* kSettingsGroup;
- void AddDirectoryModel(QAbstractItemModel* model);
+ void SetDestinationModel(QAbstractItemModel* model);
void SetUrls(const QList& urls);
void SetFilenames(const QStringList& filenames);