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/devicekitlister.cpp
devices/devicelister.cpp
devices/devicetest.cpp
devices/devicemanager.cpp
devices/filesystemdevice.cpp
engines/enginebase.cpp
@ -177,7 +177,7 @@ set(HEADERS
devices/connecteddevice.h
devices/devicekitlister.h
devices/devicelister.h
devices/devicetest.h
devices/devicemanager.h
devices/filesystemdevice.h
engines/enginebase.h

View File

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

View File

@ -60,6 +60,13 @@ class Database : public QObject {
QMutex connect_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
QString injected_database_name_;

View File

@ -15,18 +15,25 @@
*/
#include "connecteddevice.h"
#include "devicemanager.h"
#include "core/database.h"
#include "library/library.h"
#include "library/librarybackend.h"
#include "library/librarymodel.h"
ConnectedDevice::ConnectedDevice(QObject *parent)
: QObject(parent),
lister_(NULL),
#include <QtDebug>
ConnectedDevice::ConnectedDevice(DeviceLister* lister, const QString& id,
DeviceManager* manager)
: QObject(manager),
lister_(lister),
unique_id_(id),
manager_(manager),
database_(new BackgroundThreadImplementation<Database, MemoryDatabase>(this)),
backend_(NULL),
model_(NULL)
{
qDebug() << __PRETTY_FUNCTION__;
// Wait for the database thread to start
database_->Start(true);
@ -39,8 +46,3 @@ ConnectedDevice::ConnectedDevice(QObject *parent)
// Create the model
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 DeviceLister;
class DeviceManager;
class LibraryBackend;
class LibraryModel;
@ -30,9 +31,8 @@ class ConnectedDevice : public QObject {
Q_OBJECT
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_; }
QString unique_id() const { return unique_id_; }
@ -41,6 +41,7 @@ public:
protected:
DeviceLister* lister_;
QString unique_id_;
DeviceManager* manager_;
BackgroundThread<Database>* database_;
LibraryBackend* backend_;

View File

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

View File

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

View File

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

View File

@ -14,15 +14,22 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "devicetest.h"
#include "connecteddevice.h"
#include "devicemanager.h"
#include "devicekitlister.h"
#include <QtDebug>
DeviceTest::DeviceTest(QObject *parent)
: QObject(parent)
DeviceManager::DeviceManager(TaskManager* task_manager, QObject *parent)
: QObject(parent),
task_manager_(task_manager)
{
DeviceLister* lister = new DeviceKitLister;
AddLister(new DeviceKitLister);
}
DeviceManager::~DeviceManager() {
qDeleteAll(listers_);
}
void DeviceManager::AddLister(DeviceLister *lister) {
listers_ << lister;
connect(lister, SIGNAL(DeviceAdded(QString)), SLOT(DeviceAdded(QString)));
connect(lister, SIGNAL(DeviceRemoved(QString)), SLOT(DeviceRemoved(QString)));
@ -31,28 +38,36 @@ DeviceTest::DeviceTest(QObject *parent)
lister->Start();
}
DeviceTest::~DeviceTest() {
qDeleteAll(listers_);
}
void DeviceTest::DeviceAdded(const QString &id) {
DeviceLister* engine = qobject_cast<DeviceLister*>(sender());
void DeviceManager::DeviceAdded(const QString &id) {
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
qDebug() << "Device added:" << id;
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) {
qDebug() << "Device removed:" << id;
}
void DeviceTest::DeviceChanged(const QString &id) {
DeviceLister* engine = qobject_cast<DeviceLister*>(sender());
void DeviceManager::DeviceChanged(const QString &id) {
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
qDebug() << "Device changed:" << id;
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/>.
*/
#ifndef DEVICETEST_H
#define DEVICETEST_H
#ifndef DEVICEMANAGER_H
#define DEVICEMANAGER_H
#include <QObject>
class ConnectedDevice;
class DeviceLister;
class TaskManager;
class DeviceTest : public QObject {
class DeviceManager : public QObject {
Q_OBJECT
public:
DeviceTest(QObject* parent = 0);
~DeviceTest();
DeviceManager(TaskManager* task_manager, QObject* parent = 0);
~DeviceManager();
public slots:
TaskManager* task_manager() const { return task_manager_; }
private slots:
void DeviceAdded(const QString& id);
void DeviceRemoved(const QString& id);
void DeviceChanged(const QString& id);
private:
void AddLister(DeviceLister* lister);
private:
TaskManager* task_manager_;
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/>.
*/
#include "devicelister.h"
#include "devicemanager.h"
#include "filesystemdevice.h"
#include "library/librarybackend.h"
#include "library/librarywatcher.h"
FilesystemDevice::FilesystemDevice(const QString& mount_point, QObject* parent)
: ConnectedDevice(parent)
#include <QtDebug>
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);
}
FilesystemDevice::~FilesystemDevice() {
qDebug() << __PRETTY_FUNCTION__;
}

View File

@ -19,11 +19,19 @@
#include "connecteddevice.h"
class DeviceManager;
class LibraryWatcher;
class FilesystemDevice : public ConnectedDevice {
Q_OBJECT
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

View File

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

View File

@ -67,7 +67,13 @@ LibraryWatcher::ScanTransaction::ScanTransaction(LibraryWatcher* watcher,
cached_songs_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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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