Add error handling for mtp and gpod device
This commit is contained in:
@@ -99,6 +99,8 @@ void ConnectedDevice::InitBackendDirectory(const QString &mount_point, bool firs
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectedDevice::ConnectAsync() { emit ConnectFinished(unique_id_, true); }
|
||||||
|
|
||||||
void ConnectedDevice::Eject() {
|
void ConnectedDevice::Eject() {
|
||||||
|
|
||||||
DeviceInfo *info = manager_->FindDeviceById(unique_id_);
|
DeviceInfo *info = manager_->FindDeviceById(unique_id_);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class ConnectedDevice : public QObject,
|
|||||||
~ConnectedDevice();
|
~ConnectedDevice();
|
||||||
|
|
||||||
virtual bool Init() = 0;
|
virtual bool Init() = 0;
|
||||||
|
virtual void ConnectAsync();
|
||||||
// For some devices (e.g. CD devices) we don't have callbacks to be notified when something change:
|
// For some devices (e.g. CD devices) we don't have callbacks to be notified when something change:
|
||||||
// we can call this method to refresh device's state
|
// we can call this method to refresh device's state
|
||||||
virtual void Refresh() {}
|
virtual void Refresh() {}
|
||||||
@@ -71,6 +72,7 @@ class ConnectedDevice : public QObject,
|
|||||||
signals:
|
signals:
|
||||||
void TaskStarted(int id);
|
void TaskStarted(int id);
|
||||||
void SongCountUpdated(int count);
|
void SongCountUpdated(int count);
|
||||||
|
void ConnectFinished(const QString& id, bool success);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitBackendDirectory(const QString &mount_point, bool first_time, bool rewrite_path = true);
|
void InitBackendDirectory(const QString &mount_point, bool first_time, bool rewrite_path = true);
|
||||||
|
|||||||
@@ -548,12 +548,29 @@ std::shared_ptr<ConnectedDevice> DeviceManager::Connect(DeviceInfo *info) {
|
|||||||
|
|
||||||
connect(info->device_.get(), SIGNAL(TaskStarted(int)), SLOT(DeviceTaskStarted(int)));
|
connect(info->device_.get(), SIGNAL(TaskStarted(int)), SLOT(DeviceTaskStarted(int)));
|
||||||
connect(info->device_.get(), SIGNAL(SongCountUpdated(int)), SLOT(DeviceSongCountUpdated(int)));
|
connect(info->device_.get(), SIGNAL(SongCountUpdated(int)), SLOT(DeviceSongCountUpdated(int)));
|
||||||
|
connect(info->device_.get(), SIGNAL(ConnectFinished(const QString&, bool)), SLOT(DeviceConnectFinished(const QString&, bool)));
|
||||||
emit DeviceConnected(idx);
|
ret->ConnectAsync();
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceManager::DeviceConnectFinished(const QString &id, bool success) {
|
||||||
|
|
||||||
|
DeviceInfo *info = FindDeviceById(id);
|
||||||
|
if (!info) return;
|
||||||
|
|
||||||
|
QModelIndex idx = ItemToIndex(info);
|
||||||
|
if (!idx.isValid()) return;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
emit DeviceConnected(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
info->device_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
DeviceInfo *DeviceManager::GetDevice(QModelIndex idx) const {
|
DeviceInfo *DeviceManager::GetDevice(QModelIndex idx) const {
|
||||||
|
|
||||||
DeviceInfo *info = IndexToItem(idx);
|
DeviceInfo *info = IndexToItem(idx);
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ class DeviceManager : public SimpleTreeModel<DeviceInfo> {
|
|||||||
void TasksChanged();
|
void TasksChanged();
|
||||||
void DeviceSongCountUpdated(int count);
|
void DeviceSongCountUpdated(int count);
|
||||||
void LoadAllDevices();
|
void LoadAllDevices();
|
||||||
|
void DeviceConnectFinished(const QString &id, bool success);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void LazyPopulate(DeviceInfo *item) { LazyPopulate(item, true); }
|
void LazyPopulate(DeviceInfo *item) { LazyPopulate(item, true); }
|
||||||
|
|||||||
@@ -59,11 +59,10 @@ bool GPodDevice::Init() {
|
|||||||
loader_ = new GPodLoader(url_.path(), app_->task_manager(), backend_, shared_from_this());
|
loader_ = new GPodLoader(url_.path(), app_->task_manager(), backend_, shared_from_this());
|
||||||
loader_->moveToThread(loader_thread_);
|
loader_->moveToThread(loader_thread_);
|
||||||
|
|
||||||
connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString)));
|
||||||
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
||||||
connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*)), SLOT(LoadFinished(Itdb_iTunesDB*)));
|
connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*, bool)), SLOT(LoadFinished(Itdb_iTunesDB*, bool)));
|
||||||
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
||||||
loader_thread_->start();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -71,7 +70,13 @@ bool GPodDevice::Init() {
|
|||||||
|
|
||||||
GPodDevice::~GPodDevice() {}
|
GPodDevice::~GPodDevice() {}
|
||||||
|
|
||||||
void GPodDevice::LoadFinished(Itdb_iTunesDB *db) {
|
void GPodDevice::ConnectAsync() {
|
||||||
|
|
||||||
|
loader_thread_->start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPodDevice::LoadFinished(Itdb_iTunesDB *db, bool success) {
|
||||||
|
|
||||||
QMutexLocker l(&db_mutex_);
|
QMutexLocker l(&db_mutex_);
|
||||||
db_ = db;
|
db_ = db;
|
||||||
@@ -87,8 +92,12 @@ void GPodDevice::LoadFinished(Itdb_iTunesDB *db) {
|
|||||||
loader_->deleteLater();
|
loader_->deleteLater();
|
||||||
loader_ = nullptr;
|
loader_ = nullptr;
|
||||||
|
|
||||||
|
emit ConnectFinished(unique_id_, success);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPodDevice::LoaderError(const QString &message) { app_->AddError(message); }
|
||||||
|
|
||||||
bool GPodDevice::StartCopy(QList<Song::FileType> *supported_filetypes) {
|
bool GPodDevice::StartCopy(QList<Song::FileType> *supported_filetypes) {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,19 +46,19 @@ class GPodLoader;
|
|||||||
|
|
||||||
class GPodDevice : public ConnectedDevice, public virtual MusicStorage {
|
class GPodDevice : public ConnectedDevice, public virtual MusicStorage {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
signals:
|
|
||||||
void Error(const QString &message);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE GPodDevice(
|
Q_INVOKABLE GPodDevice(
|
||||||
const QUrl &url, DeviceLister *lister,
|
const QUrl &url, DeviceLister *lister,
|
||||||
const QString &unique_id, DeviceManager *manager,
|
const QString &unique_id,
|
||||||
|
DeviceManager *manager,
|
||||||
Application *app,
|
Application *app,
|
||||||
int database_id, bool first_time);
|
int database_id,
|
||||||
|
bool first_time);
|
||||||
~GPodDevice();
|
~GPodDevice();
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
void ConnectAsync();
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "ipod"; }
|
static QStringList url_schemes() { return QStringList() << "ipod"; }
|
||||||
|
|
||||||
@@ -73,7 +73,8 @@ class GPodDevice : public ConnectedDevice, public virtual MusicStorage {
|
|||||||
void FinishDelete(bool success);
|
void FinishDelete(bool success);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void LoadFinished(Itdb_iTunesDB *db);
|
void LoadFinished(Itdb_iTunesDB *db, bool success);
|
||||||
|
void LoaderError(const QString& message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Itdb_Track *AddTrackToITunesDb(const Song &metadata);
|
Itdb_Track *AddTrackToITunesDb(const Song &metadata);
|
||||||
|
|||||||
@@ -52,6 +52,17 @@ void GPodLoader::LoadDatabase() {
|
|||||||
int task_id = task_manager_->StartTask(tr("Loading iPod database"));
|
int task_id = task_manager_->StartTask(tr("Loading iPod database"));
|
||||||
emit TaskStarted(task_id);
|
emit TaskStarted(task_id);
|
||||||
|
|
||||||
|
Itdb_iTunesDB *db = TryLoad();
|
||||||
|
|
||||||
|
moveToThread(original_thread_);
|
||||||
|
|
||||||
|
task_manager_->SetTaskFinished(task_id);
|
||||||
|
emit LoadFinished(db, db);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Itdb_iTunesDB *GPodLoader::TryLoad() {
|
||||||
|
|
||||||
// Load the iTunes database
|
// Load the iTunes database
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
Itdb_iTunesDB *db = itdb_parse(QDir::toNativeSeparators(mount_point_).toLocal8Bit(), &error);
|
Itdb_iTunesDB *db = itdb_parse(QDir::toNativeSeparators(mount_point_).toLocal8Bit(), &error);
|
||||||
@@ -62,12 +73,12 @@ void GPodLoader::LoadDatabase() {
|
|||||||
qLog(Error) << "loading database failed:" << error->message;
|
qLog(Error) << "loading database failed:" << error->message;
|
||||||
emit Error(QString::fromUtf8(error->message));
|
emit Error(QString::fromUtf8(error->message));
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
emit Error(tr("An error occurred loading the iTunes database"));
|
emit Error(tr("An error occurred loading the iTunes database"));
|
||||||
}
|
}
|
||||||
|
|
||||||
task_manager_->SetTaskFinished(task_id);
|
return db;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert all the tracks from libgpod structs into Song classes
|
// Convert all the tracks from libgpod structs into Song classes
|
||||||
@@ -91,10 +102,6 @@ void GPodLoader::LoadDatabase() {
|
|||||||
// Add the songs we've just loaded
|
// Add the songs we've just loaded
|
||||||
backend_->AddOrUpdateSongs(songs);
|
backend_->AddOrUpdateSongs(songs);
|
||||||
|
|
||||||
moveToThread(original_thread_);
|
return db;
|
||||||
|
|
||||||
task_manager_->SetTaskFinished(task_id);
|
|
||||||
emit LoadFinished(db);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ class GPodLoader : public QObject {
|
|||||||
signals:
|
signals:
|
||||||
void Error(const QString &message);
|
void Error(const QString &message);
|
||||||
void TaskStarted(int task_id);
|
void TaskStarted(int task_id);
|
||||||
void LoadFinished(Itdb_iTunesDB *db);
|
void LoadFinished(Itdb_iTunesDB *db, bool success);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Itdb_iTunesDB *TryLoad();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<ConnectedDevice> device_;
|
std::shared_ptr<ConnectedDevice> device_;
|
||||||
|
|||||||
@@ -64,36 +64,39 @@ MtpDevice::~MtpDevice() {}
|
|||||||
bool MtpDevice::Init() {
|
bool MtpDevice::Init() {
|
||||||
|
|
||||||
InitBackendDirectory("/", first_time_, false);
|
InitBackendDirectory("/", first_time_, false);
|
||||||
|
model_->Init();
|
||||||
|
|
||||||
loader_ = new MtpLoader(url_, app_->task_manager(), backend_, shared_from_this());
|
loader_ = new MtpLoader(url_, app_->task_manager(), backend_, shared_from_this());
|
||||||
if (!loader_->Init()) {
|
|
||||||
delete loader_;
|
|
||||||
loader_ = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
model_->Init();
|
|
||||||
loader_->moveToThread(loader_thread_);
|
loader_->moveToThread(loader_thread_);
|
||||||
|
|
||||||
connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString)));
|
||||||
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
||||||
connect(loader_, SIGNAL(LoadFinished()), SLOT(LoadFinished()));
|
connect(loader_, SIGNAL(LoadFinished(bool)), SLOT(LoadFinished(bool)));
|
||||||
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
||||||
|
|
||||||
db_busy_.lock();
|
|
||||||
loader_thread_->start();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MtpDevice::LoadFinished() {
|
void MtpDevice::ConnectAsync() {
|
||||||
|
|
||||||
|
db_busy_.lock();
|
||||||
|
loader_thread_->start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MtpDevice::LoadFinished(bool success) {
|
||||||
|
|
||||||
loader_->deleteLater();
|
loader_->deleteLater();
|
||||||
loader_ = nullptr;
|
loader_ = nullptr;
|
||||||
db_busy_.unlock();
|
db_busy_.unlock();
|
||||||
|
emit ConnectFinished(unique_id_, success);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MtpDevice::LoaderError(const QString& message) { app_->AddError(message); }
|
||||||
|
|
||||||
bool MtpDevice::StartCopy(QList<Song::FileType> *supported_types) {
|
bool MtpDevice::StartCopy(QList<Song::FileType> *supported_types) {
|
||||||
|
|
||||||
// Ensure only one "organise files" can be active at any one time
|
// Ensure only one "organise files" can be active at any one time
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class MtpDevice : public ConnectedDevice {
|
|||||||
static QStringList url_schemes() { return QStringList() << "mtp" << "gphoto2"; }
|
static QStringList url_schemes() { return QStringList() << "mtp" << "gphoto2"; }
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
void ConnectAsync();
|
||||||
|
|
||||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
||||||
int GetFreeSpace();
|
int GetFreeSpace();
|
||||||
@@ -68,7 +69,8 @@ class MtpDevice : public ConnectedDevice {
|
|||||||
void FinishDelete(bool success);
|
void FinishDelete(bool success);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void LoadFinished();
|
void LoadFinished(bool success);
|
||||||
|
void LoaderError(const QString& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool GetSupportedFiletypes(QList<Song::FileType> *ret, LIBMTP_mtpdevice_struct *device);
|
bool GetSupportedFiletypes(QList<Song::FileType> *ret, LIBMTP_mtpdevice_struct *device);
|
||||||
|
|||||||
@@ -40,34 +40,35 @@ MtpLoader::MtpLoader(const QUrl &url, TaskManager *task_manager, CollectionBacke
|
|||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
MtpLoader::~MtpLoader() {
|
MtpLoader::~MtpLoader() {}
|
||||||
delete connection_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MtpLoader::Init() {
|
bool MtpLoader::Init() { return true; }
|
||||||
connection_ = new MtpConnection(url_);
|
|
||||||
return connection_->is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MtpLoader::LoadDatabase() {
|
void MtpLoader::LoadDatabase() {
|
||||||
|
|
||||||
int task_id = task_manager_->StartTask(tr("Loading MTP device"));
|
int task_id = task_manager_->StartTask(tr("Loading MTP device"));
|
||||||
emit TaskStarted(task_id);
|
emit TaskStarted(task_id);
|
||||||
|
|
||||||
TryLoad();
|
bool success = TryLoad();
|
||||||
|
|
||||||
moveToThread(original_thread_);
|
moveToThread(original_thread_);
|
||||||
|
|
||||||
task_manager_->SetTaskFinished(task_id);
|
task_manager_->SetTaskFinished(task_id);
|
||||||
emit LoadFinished();
|
emit LoadFinished(success);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MtpLoader::TryLoad() {
|
bool MtpLoader::TryLoad() {
|
||||||
|
|
||||||
|
MtpConnection dev(url_);
|
||||||
|
if (!dev.is_valid()) {
|
||||||
|
emit Error(tr("Error connecting MTP device"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Load the list of songs on the device
|
// Load the list of songs on the device
|
||||||
SongList songs;
|
SongList songs;
|
||||||
LIBMTP_track_t* tracks = LIBMTP_Get_Tracklisting_With_Callback(connection_->device(), nullptr, nullptr);
|
LIBMTP_track_t* tracks = LIBMTP_Get_Tracklisting_With_Callback(dev.device(), nullptr, nullptr);
|
||||||
while (tracks) {
|
while (tracks) {
|
||||||
LIBMTP_track_t *track = tracks;
|
LIBMTP_track_t *track = tracks;
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class MtpLoader : public QObject {
|
|||||||
signals:
|
signals:
|
||||||
void Error(const QString &message);
|
void Error(const QString &message);
|
||||||
void TaskStarted(int task_id);
|
void TaskStarted(int task_id);
|
||||||
void LoadFinished();
|
void LoadFinished(bool success);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool TryLoad();
|
bool TryLoad();
|
||||||
|
|||||||
Reference in New Issue
Block a user