Add a DeviceManager which holds all the listers and connected devices. Make FilesystemDevices use their own LibraryWatcher.

This commit is contained in:
David Sansome 2010-06-26 12:41:18 +00:00
parent 28ea240eb8
commit 2deca7fd61
20 changed files with 169 additions and 57 deletions

View File

@ -55,7 +55,7 @@ set(SOURCES
devices/connecteddevice.cpp devices/connecteddevice.cpp
devices/devicekitlister.cpp devices/devicekitlister.cpp
devices/devicelister.cpp devices/devicelister.cpp
devices/devicetest.cpp devices/devicemanager.cpp
devices/filesystemdevice.cpp devices/filesystemdevice.cpp
engines/enginebase.cpp engines/enginebase.cpp
@ -177,7 +177,7 @@ set(HEADERS
devices/connecteddevice.h devices/connecteddevice.h
devices/devicekitlister.h devices/devicekitlister.h
devices/devicelister.h devices/devicelister.h
devices/devicetest.h devices/devicemanager.h
devices/filesystemdevice.h devices/filesystemdevice.h
engines/enginebase.h engines/enginebase.h

View File

@ -29,6 +29,9 @@
const char* Database::kDatabaseFilename = "clementine.db"; const char* Database::kDatabaseFilename = "clementine.db";
const int Database::kSchemaVersion = 13; const int Database::kSchemaVersion = 13;
int Database::sNextConnectionId = 1;
QMutex Database::sNextConnectionIdMutex;
Database::Token::Token(const QString& token, int start, int end) Database::Token::Token(const QString& token, int start, int end)
: token(token), : token(token),
start_offset(start), start_offset(start),
@ -320,6 +323,11 @@ Database::Database(QObject* parent, const QString& database_name)
injected_database_name_(database_name), injected_database_name_(database_name),
query_hash_(0) query_hash_(0)
{ {
{
QMutexLocker l(&sNextConnectionIdMutex);
connection_id_ = sNextConnectionId ++;
}
directory_ = QDir::toNativeSeparators( directory_ = QDir::toNativeSeparators(
QDir::homePath() + "/.config/" + QCoreApplication::organizationName()); QDir::homePath() + "/.config/" + QCoreApplication::organizationName());
@ -337,8 +345,9 @@ QSqlDatabase Database::Connect() {
} }
} }
const QString connection_id("thread_" + QString::number( const QString connection_id =
reinterpret_cast<quint64>(QThread::currentThread()))); QString("%1_thread_%2").arg(connection_id_).arg(
reinterpret_cast<quint64>(QThread::currentThread()));
// Try to find an existing connection for this thread // Try to find an existing connection for this thread
QSqlDatabase db = QSqlDatabase::database(connection_id); QSqlDatabase db = QSqlDatabase::database(connection_id);

View File

@ -60,6 +60,13 @@ class Database : public QObject {
QMutex connect_mutex_; QMutex connect_mutex_;
QMutex mutex_; QMutex mutex_;
// This ID makes the QSqlDatabase name unique to the object as well as the
// thread
int connection_id_;
static QMutex sNextConnectionIdMutex;
static int sNextConnectionId;
// Used by tests // Used by tests
QString injected_database_name_; QString injected_database_name_;

View File

@ -15,18 +15,25 @@
*/ */
#include "connecteddevice.h" #include "connecteddevice.h"
#include "devicemanager.h"
#include "core/database.h" #include "core/database.h"
#include "library/library.h" #include "library/library.h"
#include "library/librarybackend.h" #include "library/librarybackend.h"
#include "library/librarymodel.h" #include "library/librarymodel.h"
ConnectedDevice::ConnectedDevice(QObject *parent) #include <QtDebug>
: QObject(parent),
lister_(NULL), ConnectedDevice::ConnectedDevice(DeviceLister* lister, const QString& id,
DeviceManager* manager)
: QObject(manager),
lister_(lister),
unique_id_(id),
manager_(manager),
database_(new BackgroundThreadImplementation<Database, MemoryDatabase>(this)), database_(new BackgroundThreadImplementation<Database, MemoryDatabase>(this)),
backend_(NULL), backend_(NULL),
model_(NULL) model_(NULL)
{ {
qDebug() << __PRETTY_FUNCTION__;
// Wait for the database thread to start // Wait for the database thread to start
database_->Start(true); database_->Start(true);
@ -39,8 +46,3 @@ ConnectedDevice::ConnectedDevice(QObject *parent)
// Create the model // Create the model
model_ = new LibraryModel(backend_, this); model_ = new LibraryModel(backend_, this);
} }
void ConnectedDevice::set_lister(DeviceLister *lister, const QString &id) {
lister_ = lister;
unique_id_ = id;
}

View File

@ -23,6 +23,7 @@
class Database; class Database;
class DeviceLister; class DeviceLister;
class DeviceManager;
class LibraryBackend; class LibraryBackend;
class LibraryModel; class LibraryModel;
@ -30,9 +31,8 @@ class ConnectedDevice : public QObject {
Q_OBJECT Q_OBJECT
public: public:
ConnectedDevice(QObject *parent = 0); ConnectedDevice(DeviceLister* lister, const QString& id, DeviceManager* manager);
void set_lister(DeviceLister* lister, const QString& id);
DeviceLister* lister() const { return lister_; } DeviceLister* lister() const { return lister_; }
QString unique_id() const { return unique_id_; } QString unique_id() const { return unique_id_; }
@ -41,6 +41,7 @@ public:
protected: protected:
DeviceLister* lister_; DeviceLister* lister_;
QString unique_id_; QString unique_id_;
DeviceManager* manager_;
BackgroundThread<Database>* database_; BackgroundThread<Database>* database_;
LibraryBackend* backend_; LibraryBackend* backend_;

View File

@ -217,6 +217,8 @@ QString DeviceKitLister::FindUniqueIdByPath(const QDBusObjectPath &path) const {
return QString(); return QString();
} }
ConnectedDevice* DeviceKitLister::Connect(const QString &id, QObject *parent) { ConnectedDevice* DeviceKitLister::Connect(const QString &id, DeviceManager* manager) {
return new FilesystemDevice(DeviceInfo(id, Field_MountPath).toString(), parent); return new FilesystemDevice(
DeviceInfo(id, Field_MountPath).toString(),
this, id, manager);
} }

View File

@ -45,7 +45,7 @@ public:
QStringList DeviceUniqueIDs(); QStringList DeviceUniqueIDs();
QVariant DeviceInfo(const QString& id, int field); QVariant DeviceInfo(const QString& id, int field);
ConnectedDevice* Connect(const QString &id, QObject *parent); ConnectedDevice* Connect(const QString &id, DeviceManager* manager);
protected: protected:
void Init(); void Init();

View File

@ -20,6 +20,7 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
class ConnectedDevice; class ConnectedDevice;
class DeviceManager;
class DeviceLister : public QObject { class DeviceLister : public QObject {
Q_OBJECT Q_OBJECT
@ -49,7 +50,7 @@ public:
// Create a new ConnectedDevice instance for the given device. Must be // Create a new ConnectedDevice instance for the given device. Must be
// thread-safe. // thread-safe.
virtual ConnectedDevice* Connect(const QString& id, QObject* parent) = 0; virtual ConnectedDevice* Connect(const QString& id, DeviceManager* manager) = 0;
signals: signals:
void DeviceAdded(const QString& id); void DeviceAdded(const QString& id);

View File

@ -14,15 +14,22 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>. along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "devicetest.h" #include "connecteddevice.h"
#include "devicemanager.h"
#include "devicekitlister.h" #include "devicekitlister.h"
#include <QtDebug> DeviceManager::DeviceManager(TaskManager* task_manager, QObject *parent)
: QObject(parent),
DeviceTest::DeviceTest(QObject *parent) task_manager_(task_manager)
: QObject(parent)
{ {
DeviceLister* lister = new DeviceKitLister; AddLister(new DeviceKitLister);
}
DeviceManager::~DeviceManager() {
qDeleteAll(listers_);
}
void DeviceManager::AddLister(DeviceLister *lister) {
listers_ << lister; listers_ << lister;
connect(lister, SIGNAL(DeviceAdded(QString)), SLOT(DeviceAdded(QString))); connect(lister, SIGNAL(DeviceAdded(QString)), SLOT(DeviceAdded(QString)));
connect(lister, SIGNAL(DeviceRemoved(QString)), SLOT(DeviceRemoved(QString))); connect(lister, SIGNAL(DeviceRemoved(QString)), SLOT(DeviceRemoved(QString)));
@ -31,28 +38,36 @@ DeviceTest::DeviceTest(QObject *parent)
lister->Start(); lister->Start();
} }
DeviceTest::~DeviceTest() { void DeviceManager::DeviceAdded(const QString &id) {
qDeleteAll(listers_); DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
}
void DeviceTest::DeviceAdded(const QString &id) {
DeviceLister* engine = qobject_cast<DeviceLister*>(sender());
qDebug() << "Device added:" << id; qDebug() << "Device added:" << id;
for (int i=0 ; i<DeviceKitLister::LastField ; ++i) { for (int i=0 ; i<DeviceKitLister::LastField ; ++i) {
qDebug() << i << engine->DeviceInfo(id, i); qDebug() << i << lister->DeviceInfo(id, i);
}
ConnectedDevice* device = lister->Connect(id, this);
devices_ << device;
}
void DeviceManager::DeviceRemoved(const QString &id) {
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
qDebug() << "Device removed:" << id;
foreach (ConnectedDevice* device, devices_) {
if (device->lister() == lister && device->unique_id() == id) {
delete device;
devices_.removeAll(device);
break;
}
} }
} }
void DeviceTest::DeviceRemoved(const QString &id) { void DeviceManager::DeviceChanged(const QString &id) {
qDebug() << "Device removed:" << id; DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
}
void DeviceTest::DeviceChanged(const QString &id) {
DeviceLister* engine = qobject_cast<DeviceLister*>(sender());
qDebug() << "Device changed:" << id; qDebug() << "Device changed:" << id;
for (int i=0 ; i<DeviceKitLister::LastField ; ++i) { for (int i=0 ; i<DeviceKitLister::LastField ; ++i) {
qDebug() << i << engine->DeviceInfo(id, i); qDebug() << i << lister->DeviceInfo(id, i);
} }
} }

View File

@ -14,27 +14,37 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>. along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef DEVICETEST_H #ifndef DEVICEMANAGER_H
#define DEVICETEST_H #define DEVICEMANAGER_H
#include <QObject> #include <QObject>
class ConnectedDevice;
class DeviceLister; class DeviceLister;
class TaskManager;
class DeviceTest : public QObject { class DeviceManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
DeviceTest(QObject* parent = 0); DeviceManager(TaskManager* task_manager, QObject* parent = 0);
~DeviceTest(); ~DeviceManager();
public slots: TaskManager* task_manager() const { return task_manager_; }
private slots:
void DeviceAdded(const QString& id); void DeviceAdded(const QString& id);
void DeviceRemoved(const QString& id); void DeviceRemoved(const QString& id);
void DeviceChanged(const QString& id); void DeviceChanged(const QString& id);
private: private:
void AddLister(DeviceLister* lister);
private:
TaskManager* task_manager_;
QList<DeviceLister*> listers_; QList<DeviceLister*> listers_;
QList<ConnectedDevice*> devices_;
}; };
#endif // DEVICETEST_H #endif // DEVICEMANAGER_H

View File

@ -14,11 +14,50 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>. along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "devicelister.h"
#include "devicemanager.h"
#include "filesystemdevice.h" #include "filesystemdevice.h"
#include "library/librarybackend.h" #include "library/librarybackend.h"
#include "library/librarywatcher.h"
FilesystemDevice::FilesystemDevice(const QString& mount_point, QObject* parent) #include <QtDebug>
: ConnectedDevice(parent)
FilesystemDevice::FilesystemDevice(
const QString& mount_point, DeviceLister* lister, const QString& id,
DeviceManager* manager)
: ConnectedDevice(lister, id, manager),
watcher_(new BackgroundThreadImplementation<LibraryWatcher, LibraryWatcher>(this))
{ {
// Create the library watcher
watcher_->Start(true);
watcher_->Worker()->set_device_name(lister_->DeviceInfo(
unique_id_, DeviceLister::Field_FriendlyName).toString());
watcher_->Worker()->set_backend(backend_);
watcher_->Worker()->set_task_manager(manager_->task_manager());
// To make the connections below less verbose
LibraryWatcher* watcher = watcher_->Worker().get();
connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)),
watcher, SLOT(AddDirectory(Directory,SubdirectoryList)));
connect(backend_, SIGNAL(DirectoryDeleted(Directory)),
watcher, SLOT(RemoveDirectory(Directory)));
connect(watcher, SIGNAL(NewOrUpdatedSongs(SongList)),
backend_, SLOT(AddOrUpdateSongs(SongList)));
connect(watcher, SIGNAL(SongsMTimeUpdated(SongList)),
backend_, SLOT(UpdateMTimesOnly(SongList)));
connect(watcher, SIGNAL(SongsDeleted(SongList)),
backend_, SLOT(DeleteSongs(SongList)));
connect(watcher, SIGNAL(SubdirsDiscovered(SubdirectoryList)),
backend_, SLOT(AddOrUpdateSubdirs(SubdirectoryList)));
connect(watcher, SIGNAL(SubdirsMTimeUpdated(SubdirectoryList)),
backend_, SLOT(AddOrUpdateSubdirs(SubdirectoryList)));
connect(watcher, SIGNAL(CompilationsNeedUpdating()),
backend_, SLOT(UpdateCompilations()));
backend_->AddDirectory(mount_point); backend_->AddDirectory(mount_point);
} }
FilesystemDevice::~FilesystemDevice() {
qDebug() << __PRETTY_FUNCTION__;
}

View File

@ -19,11 +19,19 @@
#include "connecteddevice.h" #include "connecteddevice.h"
class DeviceManager;
class LibraryWatcher;
class FilesystemDevice : public ConnectedDevice { class FilesystemDevice : public ConnectedDevice {
Q_OBJECT Q_OBJECT
public: public:
FilesystemDevice(const QString& mount_point, QObject* parent = 0); FilesystemDevice(const QString& mount_point, DeviceLister* lister,
const QString& id, DeviceManager* manager);
~FilesystemDevice();
private:
BackgroundThread<LibraryWatcher>* watcher_;
}; };
#endif // FILESYSTEMDEVICE_H #endif // FILESYSTEMDEVICE_H

View File

@ -61,8 +61,8 @@ void Library::StartThreads() {
void Library::WatcherInitialised() { void Library::WatcherInitialised() {
LibraryWatcher* watcher = watcher_->Worker().get(); LibraryWatcher* watcher = watcher_->Worker().get();
watcher->SetBackend(backend_); watcher->set_backend(backend_);
watcher->SetTaskManager(task_manager_); watcher->set_task_manager(task_manager_);
connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)), connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)),
watcher, SLOT(AddDirectory(Directory,SubdirectoryList))); watcher, SLOT(AddDirectory(Directory,SubdirectoryList)));

View File

@ -67,7 +67,13 @@ LibraryWatcher::ScanTransaction::ScanTransaction(LibraryWatcher* watcher,
cached_songs_dirty_(true), cached_songs_dirty_(true),
known_subdirs_dirty_(true) known_subdirs_dirty_(true)
{ {
task_id_ = watcher_->task_manager_->StartTask(tr("Updating library")); QString description;
if (watcher_->device_name_.isEmpty())
description = tr("Updating library");
else
description = tr("Updating %1").arg(watcher_->device_name_);
task_id_ = watcher_->task_manager_->StartTask(description);
} }
LibraryWatcher::ScanTransaction::~ScanTransaction() { LibraryWatcher::ScanTransaction::~ScanTransaction() {

View File

@ -38,8 +38,10 @@ class LibraryWatcher : public QObject {
static const char* kSettingsGroup; static const char* kSettingsGroup;
void SetBackend(LibraryBackend* backend) { backend_ = backend; } void set_backend(LibraryBackend* backend) { backend_ = backend; }
void SetTaskManager(TaskManager* task_manager) { task_manager_ = task_manager; } void set_task_manager(TaskManager* task_manager) { task_manager_ = task_manager; }
void set_device_name(const QString& device_name) { device_name_ = device_name; }
void IncrementalScanAsync(); void IncrementalScanAsync();
void SetRescanPausedAsync(bool pause); void SetRescanPausedAsync(bool pause);
@ -135,6 +137,7 @@ class LibraryWatcher : public QObject {
LibraryBackend* backend_; LibraryBackend* backend_;
TaskManager* task_manager_; TaskManager* task_manager_;
QString device_name_;
bool stop_requested_; bool stop_requested_;
bool scan_on_startup_; bool scan_on_startup_;

View File

@ -34,8 +34,6 @@
#include "ui/iconloader.h" #include "ui/iconloader.h"
#include "ui/mainwindow.h" #include "ui/mainwindow.h"
#include "devices/devicetest.h" // TODO: Remove me
#include <QtSingleApplication> #include <QtSingleApplication>
#include <QtDebug> #include <QtDebug>
#include <QLibraryInfo> #include <QLibraryInfo>
@ -166,8 +164,6 @@ int main(int argc, char *argv[]) {
MPRIS mpris; MPRIS mpris;
#endif #endif
DeviceTest device_test; // TODO: Remove me (and the header)
// Window // Window
MainWindow w(&network, options.engine()); MainWindow w(&network, options.engine());

View File

@ -1476,6 +1476,10 @@ msgstr "Обновить коллекцию"
msgid "Update the library when Clementine starts" msgid "Update the library when Clementine starts"
msgstr "Обновить коллекцию при старте Clementine" msgstr "Обновить коллекцию при старте Clementine"
#, qt-format
msgid "Updating %1"
msgstr ""
msgid "Updating library" msgid "Updating library"
msgstr "Обновление библиотеки" msgstr "Обновление библиотеки"

View File

@ -1460,6 +1460,10 @@ msgstr ""
msgid "Update the library when Clementine starts" msgid "Update the library when Clementine starts"
msgstr "" msgstr ""
#, qt-format
msgid "Updating %1"
msgstr ""
msgid "Updating library" msgid "Updating library"
msgstr "" msgstr ""

View File

@ -25,6 +25,7 @@
#include "core/songloader.h" #include "core/songloader.h"
#include "core/stylesheetloader.h" #include "core/stylesheetloader.h"
#include "core/taskmanager.h" #include "core/taskmanager.h"
#include "devices/devicemanager.h"
#include "engines/enginebase.h" #include "engines/enginebase.h"
#include "library/groupbydialog.h" #include "library/groupbydialog.h"
#include "library/libraryconfig.h" #include "library/libraryconfig.h"
@ -117,6 +118,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
player_(NULL), player_(NULL),
library_(NULL), library_(NULL),
global_shortcuts_(new GlobalShortcuts(this)), global_shortcuts_(new GlobalShortcuts(this)),
devices_(new DeviceManager(task_manager_, this)),
settings_dialog_(NULL), settings_dialog_(NULL),
add_stream_dialog_(new AddStreamDialog), add_stream_dialog_(new AddStreamDialog),
cover_manager_(NULL), cover_manager_(NULL),

View File

@ -34,6 +34,7 @@ class AddStreamDialog;
class AlbumCoverManager; class AlbumCoverManager;
class CommandlineOptions; class CommandlineOptions;
class Database; class Database;
class DeviceManager;
class EditTagDialog; class EditTagDialog;
class Equalizer; class Equalizer;
class ErrorDialog; class ErrorDialog;
@ -184,6 +185,8 @@ class MainWindow : public QMainWindow, public PlatformInterface {
Library* library_; Library* library_;
GlobalShortcuts* global_shortcuts_; GlobalShortcuts* global_shortcuts_;
DeviceManager* devices_;
boost::scoped_ptr<SettingsDialog> settings_dialog_; boost::scoped_ptr<SettingsDialog> settings_dialog_;
boost::scoped_ptr<AddStreamDialog> add_stream_dialog_; boost::scoped_ptr<AddStreamDialog> add_stream_dialog_;
boost::scoped_ptr<AlbumCoverManager> cover_manager_; boost::scoped_ptr<AlbumCoverManager> cover_manager_;