Convert devicemanager to QAbstractItemModel
This commit is contained in:
@@ -684,6 +684,7 @@ optional_source(UNIX
|
|||||||
device/deviceviewcontainer.cpp
|
device/deviceviewcontainer.cpp
|
||||||
device/deviceview.cpp
|
device/deviceview.cpp
|
||||||
device/deviceproperties.cpp
|
device/deviceproperties.cpp
|
||||||
|
device/deviceinfo.cpp
|
||||||
HEADERS
|
HEADERS
|
||||||
device/connecteddevice.h
|
device/connecteddevice.h
|
||||||
device/devicedatabasebackend.h
|
device/devicedatabasebackend.h
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ AfcDevice::~AfcDevice() {
|
|||||||
Utilities::RemoveRecursive(local_path_);
|
Utilities::RemoveRecursive(local_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AfcDevice::Init() {
|
bool AfcDevice::Init() {
|
||||||
|
|
||||||
// Make a new temporary directory for the iTunesDB. We copy it off the iPod so that libgpod can have a local directory to use.
|
// Make a new temporary directory for the iTunesDB. We copy it off the iPod so that libgpod can have a local directory to use.
|
||||||
local_path_ = Utilities::MakeTempDir();
|
local_path_ = Utilities::MakeTempDir();
|
||||||
@@ -59,6 +59,8 @@ void AfcDevice::Init() {
|
|||||||
connect(loader_thread_, SIGNAL(started()), transfer_, SLOT(CopyFromDevice()));
|
connect(loader_thread_, SIGNAL(started()), transfer_, SLOT(CopyFromDevice()));
|
||||||
loader_thread_->start();
|
loader_thread_->start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AfcDevice::CopyFinished(bool success) {
|
void AfcDevice::CopyFinished(bool success) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
Q_INVOKABLE AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
Q_INVOKABLE AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
||||||
~AfcDevice();
|
~AfcDevice();
|
||||||
|
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "afc"; }
|
static QStringList url_schemes() { return QStringList() << "afc"; }
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,11 @@ CddaDevice::CddaDevice(const QUrl &url, DeviceLister *lister, const QString &uni
|
|||||||
|
|
||||||
CddaDevice::~CddaDevice() {}
|
CddaDevice::~CddaDevice() {}
|
||||||
|
|
||||||
void CddaDevice::Init() {
|
bool CddaDevice::Init() {
|
||||||
|
|
||||||
song_count_ = 0; // Reset song count, in case it was already set
|
song_count_ = 0; // Reset song count, in case it was already set
|
||||||
cdda_song_loader_.LoadSongs();
|
cdda_song_loader_.LoadSongs();
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class CddaDevice : public ConnectedDevice {
|
|||||||
Q_INVOKABLE CddaDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
Q_INVOKABLE CddaDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
||||||
~CddaDevice();
|
~CddaDevice();
|
||||||
|
|
||||||
void Init();
|
bool Init();
|
||||||
void Refresh();
|
void Refresh();
|
||||||
bool CopyToStorage(const MusicStorage::CopyJob&) { return false; }
|
bool CopyToStorage(const MusicStorage::CopyJob&) { return false; }
|
||||||
bool DeleteFromStorage(const MusicStorage::DeleteJob&) { return false; }
|
bool DeleteFromStorage(const MusicStorage::DeleteJob&) { return false; }
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ void CddaLister::UnmountDevice(const QString &id) {
|
|||||||
|
|
||||||
void CddaLister::UpdateDeviceFreeSpace(const QString&) {}
|
void CddaLister::UpdateDeviceFreeSpace(const QString&) {}
|
||||||
|
|
||||||
void CddaLister::Init() {
|
bool CddaLister::Init() {
|
||||||
|
|
||||||
cdio_init();
|
cdio_init();
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@@ -113,7 +113,7 @@ void CddaLister::Init() {
|
|||||||
char** devices = cdio_get_devices(DRIVER_DEVICE);
|
char** devices = cdio_get_devices(DRIVER_DEVICE);
|
||||||
if (!devices) {
|
if (!devices) {
|
||||||
qLog(Debug) << "No CD devices found";
|
qLog(Debug) << "No CD devices found";
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
for (; *devices != nullptr; ++devices) {
|
for (; *devices != nullptr; ++devices) {
|
||||||
QString device(*devices);
|
QString device(*devices);
|
||||||
@@ -133,4 +133,6 @@ void CddaLister::Init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class CddaLister : public DeviceLister {
|
|||||||
QList<QUrl> MakeDeviceUrls(const QString&);
|
QList<QUrl> MakeDeviceUrls(const QString&);
|
||||||
void UnmountDevice(const QString&);
|
void UnmountDevice(const QString&);
|
||||||
void UpdateDeviceFreeSpace(const QString&);
|
void UpdateDeviceFreeSpace(const QString&);
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList devices_list_;
|
QStringList devices_list_;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -110,12 +111,12 @@ void ConnectedDevice::FinishDelete(bool) {
|
|||||||
|
|
||||||
MusicStorage::TranscodeMode ConnectedDevice::GetTranscodeMode() const {
|
MusicStorage::TranscodeMode ConnectedDevice::GetTranscodeMode() const {
|
||||||
int index = manager_->FindDeviceById(unique_id_);
|
int index = manager_->FindDeviceById(unique_id_);
|
||||||
return MusicStorage::TranscodeMode(manager_->index(index).data(DeviceManager::Role_TranscodeMode).toInt());
|
return MusicStorage::TranscodeMode(manager_->index(index, 0, QModelIndex()).data(DeviceManager::Role_TranscodeMode).toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
Song::FileType ConnectedDevice::GetTranscodeFormat() const {
|
Song::FileType ConnectedDevice::GetTranscodeFormat() const {
|
||||||
int index = manager_->FindDeviceById(unique_id_);
|
int index = manager_->FindDeviceById(unique_id_);
|
||||||
return Song::FileType(manager_->index(index).data(DeviceManager::Role_TranscodeFormat).toInt());
|
return Song::FileType(manager_->index(index, 0, QModelIndex()).data(DeviceManager::Role_TranscodeFormat).toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectedDevice::BackendTotalSongCountUpdated(int count) {
|
void ConnectedDevice::BackendTotalSongCountUpdated(int count) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -48,7 +49,7 @@ class ConnectedDevice : public QObject,
|
|||||||
ConnectedDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
ConnectedDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time);
|
||||||
~ConnectedDevice();
|
~ConnectedDevice();
|
||||||
|
|
||||||
virtual void Init() = 0;
|
virtual bool Init() = 0;
|
||||||
// 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() {}
|
||||||
@@ -67,7 +68,7 @@ class ConnectedDevice : public QObject,
|
|||||||
|
|
||||||
virtual void Eject();
|
virtual void Eject();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void TaskStarted(int id);
|
void TaskStarted(int id);
|
||||||
void SongCountUpdated(int count);
|
void SongCountUpdated(int count);
|
||||||
|
|
||||||
|
|||||||
141
src/device/deviceinfo.cpp
Normal file
141
src/device/deviceinfo.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* This code was part of Clementine.
|
||||||
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
|
#include "core/iconloader.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/simpletreemodel.h"
|
||||||
|
|
||||||
|
#include "deviceinfo.h"
|
||||||
|
#include "devicedatabasebackend.h"
|
||||||
|
|
||||||
|
DeviceDatabaseBackend::Device DeviceInfo::SaveToDb() const {
|
||||||
|
|
||||||
|
DeviceDatabaseBackend::Device ret;
|
||||||
|
ret.friendly_name_ = friendly_name_;
|
||||||
|
ret.size_ = size_;
|
||||||
|
ret.id_ = database_id_;
|
||||||
|
ret.icon_name_ = icon_name_;
|
||||||
|
ret.transcode_mode_ = transcode_mode_;
|
||||||
|
ret.transcode_format_ = transcode_format_;
|
||||||
|
|
||||||
|
QStringList unique_ids;
|
||||||
|
for (const Backend &backend : backends_) {
|
||||||
|
unique_ids << backend.unique_id_;
|
||||||
|
}
|
||||||
|
ret.unique_id_ = unique_ids.join(",");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInfo::InitFromDb(const DeviceDatabaseBackend::Device &dev) {
|
||||||
|
|
||||||
|
database_id_ = dev.id_;
|
||||||
|
friendly_name_ = dev.friendly_name_;
|
||||||
|
size_ = dev.size_;
|
||||||
|
transcode_mode_ = dev.transcode_mode_;
|
||||||
|
transcode_format_ = dev.transcode_format_;
|
||||||
|
|
||||||
|
QStringList icon_names = dev.icon_name_.split(',');
|
||||||
|
QVariantList icons;
|
||||||
|
for (const QString &icon_name : icon_names) {
|
||||||
|
icons << icon_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadIcon(icons, friendly_name_);
|
||||||
|
|
||||||
|
QStringList unique_ids = dev.unique_id_.split(',');
|
||||||
|
for (const QString &id : unique_ids) {
|
||||||
|
backends_ << Backend(nullptr, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeviceInfo::Backend *DeviceInfo::BestBackend() const {
|
||||||
|
|
||||||
|
int best_priority = -1;
|
||||||
|
const Backend *ret = nullptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < backends_.count(); ++i) {
|
||||||
|
if (backends_[i].lister_ && backends_[i].lister_->priority() > best_priority) {
|
||||||
|
best_priority = backends_[i].lister_->priority();
|
||||||
|
ret = &(backends_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret && !backends_.isEmpty()) return &(backends_[0]);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInfo::LoadIcon(const QVariantList &icons, const QString &name_hint) {
|
||||||
|
|
||||||
|
icon_name_ = "device";
|
||||||
|
|
||||||
|
if (icons.isEmpty()) {
|
||||||
|
icon_ = IconLoader::Load(icon_name_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load the icon with that exact name first
|
||||||
|
for (const QVariant &icon : icons) {
|
||||||
|
if (!icon.value<QPixmap>().isNull()) {
|
||||||
|
icon_ = QIcon(icon.value<QPixmap>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!icon.toString().isEmpty()) icon_ = IconLoader::Load(icon.toString());
|
||||||
|
if (!icon_.isNull()) {
|
||||||
|
icon_name_ = icon.toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString hint = QString(icons.first().toString() + name_hint).toLower();
|
||||||
|
|
||||||
|
if (hint.contains("phone"))
|
||||||
|
icon_name_ = "device-phone";
|
||||||
|
else if (hint.contains("ipod") || hint.contains("apple"))
|
||||||
|
icon_name_ = "device-ipod";
|
||||||
|
else if ((hint.contains("usb")) && (hint.contains("reader")))
|
||||||
|
icon_name_ = "device-usb-flash";
|
||||||
|
else if (hint.contains("usb"))
|
||||||
|
icon_name_ = "device-usb-drive";
|
||||||
|
else
|
||||||
|
icon_name_ = "device";
|
||||||
|
|
||||||
|
icon_ = IconLoader::Load(icon_name_);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
121
src/device/deviceinfo.h
Normal file
121
src/device/deviceinfo.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* This code was part of Clementine.
|
||||||
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEVICEINFO_H
|
||||||
|
#define DEVICEINFO_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "core/song.h"
|
||||||
|
#include "core/musicstorage.h"
|
||||||
|
#include "core/simpletreemodel.h"
|
||||||
|
#include "core/simpletreeitem.h"
|
||||||
|
#include "collection/collectionmodel.h"
|
||||||
|
#include "devicedatabasebackend.h"
|
||||||
|
#include "devicelister.h"
|
||||||
|
|
||||||
|
class Application;
|
||||||
|
class ConnectedDevice;
|
||||||
|
class DeviceLister;
|
||||||
|
class DeviceStateFilterModel;
|
||||||
|
|
||||||
|
// Devices can be in three different states:
|
||||||
|
// 1) Remembered in the database but not physically connected at the moment.
|
||||||
|
// database_id valid, lister null, device null
|
||||||
|
// 2) Physically connected but the user hasn't "connected" it to Strawberry
|
||||||
|
// yet.
|
||||||
|
// database_id == -1, lister valid, device null
|
||||||
|
// 3) Physically connected and connected to Strawberry
|
||||||
|
// database_id valid, lister valid, device valid
|
||||||
|
// Devices in all states will have a unique_id.
|
||||||
|
|
||||||
|
class DeviceInfo : public SimpleTreeItem<DeviceInfo> {
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
Type_Root,
|
||||||
|
Type_Device,
|
||||||
|
};
|
||||||
|
|
||||||
|
DeviceInfo(SimpleTreeModel<DeviceInfo> *model)
|
||||||
|
: SimpleTreeItem<DeviceInfo>(Type_Root, model),
|
||||||
|
database_id_(-1),
|
||||||
|
size_(0),
|
||||||
|
transcode_mode_(MusicStorage::Transcode_Unsupported),
|
||||||
|
transcode_format_(Song::FileType_Unknown),
|
||||||
|
task_percentage_(-1) {}
|
||||||
|
|
||||||
|
DeviceInfo(Type type, DeviceInfo *parent = nullptr)
|
||||||
|
: SimpleTreeItem<DeviceInfo>(type, parent),
|
||||||
|
database_id_(-1),
|
||||||
|
size_(0),
|
||||||
|
transcode_mode_(MusicStorage::Transcode_Unsupported),
|
||||||
|
transcode_format_(Song::FileType_Unknown),
|
||||||
|
task_percentage_(-1) {}
|
||||||
|
|
||||||
|
// A device can be discovered in different ways (devicekit, gio, etc.)
|
||||||
|
// Sometimes the same device is discovered more than once. In this case the device will have multiple "backends".
|
||||||
|
struct Backend {
|
||||||
|
Backend(DeviceLister *lister = nullptr, const QString &id = QString())
|
||||||
|
: lister_(lister), unique_id_(id) {}
|
||||||
|
|
||||||
|
DeviceLister *lister_; // nullptr if not physically connected
|
||||||
|
QString unique_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialising to the database
|
||||||
|
void InitFromDb(const DeviceDatabaseBackend::Device &dev);
|
||||||
|
DeviceDatabaseBackend::Device SaveToDb() const;
|
||||||
|
|
||||||
|
// Tries to load a good icon for the device. Sets icon_name_ and icon_.
|
||||||
|
void LoadIcon(const QVariantList &icons, const QString &name_hint);
|
||||||
|
|
||||||
|
// Gets the best backend available (the one with the highest priority)
|
||||||
|
const Backend *BestBackend() const;
|
||||||
|
|
||||||
|
int database_id_; // -1 if not remembered in the database
|
||||||
|
std::shared_ptr<ConnectedDevice> device_; // nullptr if not connected
|
||||||
|
QList<Backend> backends_;
|
||||||
|
|
||||||
|
QString friendly_name_;
|
||||||
|
quint64 size_;
|
||||||
|
|
||||||
|
QString icon_name_;
|
||||||
|
QIcon icon_;
|
||||||
|
|
||||||
|
MusicStorage::TranscodeMode transcode_mode_;
|
||||||
|
Song::FileType transcode_format_;
|
||||||
|
|
||||||
|
int task_percentage_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICEINFO_H
|
||||||
@@ -48,7 +48,7 @@ QString DeviceKitLister::DeviceData::unique_id() const {
|
|||||||
return QString("DeviceKit/%1/%2/%3/%4").arg(drive_serial, drive_vendor, drive_model).arg(device_size);
|
return QString("DeviceKit/%1/%2/%3/%4").arg(drive_serial, drive_vendor, drive_model).arg(device_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceKitLister::Init() {
|
bool DeviceKitLister::Init() {
|
||||||
|
|
||||||
interface_.reset(new OrgFreedesktopUDisksInterface(OrgFreedesktopUDisksInterface::staticInterfaceName(), "/org/freedesktop/UDisks", QDBusConnection::systemBus()));
|
interface_.reset(new OrgFreedesktopUDisksInterface(OrgFreedesktopUDisksInterface::staticInterfaceName(), "/org/freedesktop/UDisks", QDBusConnection::systemBus()));
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ void DeviceKitLister::Init() {
|
|||||||
if (!reply.isValid()) {
|
if (!reply.isValid()) {
|
||||||
qLog(Warning) << "Error enumerating DeviceKit-disks devices:" << reply.error().name() << reply.error().message();
|
qLog(Warning) << "Error enumerating DeviceKit-disks devices:" << reply.error().name() << reply.error().message();
|
||||||
interface_.reset();
|
interface_.reset();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for changes
|
// Listen for changes
|
||||||
@@ -85,6 +85,8 @@ void DeviceKitLister::Init() {
|
|||||||
emit DeviceAdded(id);
|
emit DeviceAdded(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DeviceKitLister::DeviceUniqueIDs() {
|
QStringList DeviceKitLister::DeviceUniqueIDs() {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class DeviceKitLister : public DeviceLister {
|
|||||||
void UpdateDeviceFreeSpace(const QString &id);
|
void UpdateDeviceFreeSpace(const QString &id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void DBusDeviceAdded(const QDBusObjectPath &path);
|
void DBusDeviceAdded(const QDBusObjectPath &path);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ signals:
|
|||||||
void DeviceMounted(const QString &id, int request_id, bool success);
|
void DeviceMounted(const QString &id, int request_id, bool success);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Init() = 0;
|
virtual bool Init() = 0;
|
||||||
QUrl MakeUrlFromLocalPath(const QString &path) const;
|
QUrl MakeUrlFromLocalPath(const QString &path) const;
|
||||||
bool IsIpod(const QString &path) const;
|
bool IsIpod(const QString &path) const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,9 +29,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QPersistentModelIndex>
|
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
@@ -39,9 +38,7 @@
|
|||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QIcon>
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
@@ -56,33 +53,18 @@
|
|||||||
#include "core/musicstorage.h"
|
#include "core/musicstorage.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
|
#include "core/simpletreemodel.h"
|
||||||
#include "filesystemdevice.h"
|
#include "filesystemdevice.h"
|
||||||
#include "connecteddevice.h"
|
#include "connecteddevice.h"
|
||||||
#include "devicelister.h"
|
#include "devicelister.h"
|
||||||
#include "devicedatabasebackend.h"
|
#include "devicedatabasebackend.h"
|
||||||
#include "devicestatefiltermodel.h"
|
#include "devicestatefiltermodel.h"
|
||||||
|
#include "deviceinfo.h"
|
||||||
|
|
||||||
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
|
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
|
||||||
# include "cddalister.h"
|
# include "cddalister.h"
|
||||||
# include "cddadevice.h"
|
# include "cddadevice.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
|
||||||
# include "macdevicelister.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBGPOD
|
|
||||||
# include "gpoddevice.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_GIO
|
|
||||||
# include "giolister.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_IMOBILEDEVICE
|
|
||||||
# include "afcdevice.h"
|
|
||||||
# include "ilister.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBMTP
|
|
||||||
# include "mtpdevice.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
# ifdef HAVE_DEVICEKIT
|
# ifdef HAVE_DEVICEKIT
|
||||||
# include "devicekitlister.h"
|
# include "devicekitlister.h"
|
||||||
@@ -91,123 +73,33 @@
|
|||||||
# include "udisks2lister.h"
|
# include "udisks2lister.h"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBMTP
|
||||||
|
# include "mtpdevice.h"
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_IMOBILEDEVICE
|
||||||
|
# include "afcdevice.h"
|
||||||
|
# include "ilister.h"
|
||||||
|
#endif
|
||||||
|
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
||||||
|
# include "macdevicelister.h"
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LIBGPOD
|
||||||
|
# include "gpoddevice.h"
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_GIO
|
||||||
|
# include "giolister.h" // Needs to be last because of #undef signals.
|
||||||
|
#endif
|
||||||
|
|
||||||
using std::bind;
|
using std::bind;
|
||||||
|
|
||||||
const int DeviceManager::kDeviceIconSize = 32;
|
const int DeviceManager::kDeviceIconSize = 32;
|
||||||
const int DeviceManager::kDeviceIconOverlaySize = 16;
|
const int DeviceManager::kDeviceIconOverlaySize = 16;
|
||||||
|
|
||||||
DeviceManager::DeviceInfo::DeviceInfo()
|
|
||||||
: database_id_(-1),
|
|
||||||
transcode_mode_(MusicStorage::Transcode_Unsupported),
|
|
||||||
transcode_format_(Song::FileType_Unknown),
|
|
||||||
task_percentage_(-1) {}
|
|
||||||
|
|
||||||
DeviceDatabaseBackend::Device DeviceManager::DeviceInfo::SaveToDb() const {
|
|
||||||
|
|
||||||
DeviceDatabaseBackend::Device ret;
|
|
||||||
ret.friendly_name_ = friendly_name_;
|
|
||||||
ret.size_ = size_;
|
|
||||||
ret.id_ = database_id_;
|
|
||||||
ret.icon_name_ = icon_name_;
|
|
||||||
ret.transcode_mode_ = transcode_mode_;
|
|
||||||
ret.transcode_format_ = transcode_format_;
|
|
||||||
|
|
||||||
QStringList unique_ids;
|
|
||||||
for (const Backend &backend : backends_) {
|
|
||||||
unique_ids << backend.unique_id_;
|
|
||||||
}
|
|
||||||
ret.unique_id_ = unique_ids.join(",");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::DeviceInfo::InitFromDb(const DeviceDatabaseBackend::Device &dev) {
|
|
||||||
|
|
||||||
database_id_ = dev.id_;
|
|
||||||
friendly_name_ = dev.friendly_name_;
|
|
||||||
size_ = dev.size_;
|
|
||||||
transcode_mode_ = dev.transcode_mode_;
|
|
||||||
transcode_format_ = dev.transcode_format_;
|
|
||||||
|
|
||||||
QStringList icon_names = dev.icon_name_.split(',');
|
|
||||||
QVariantList icons;
|
|
||||||
for (const QString &icon_name : icon_names) {
|
|
||||||
icons << icon_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadIcon(icons, friendly_name_);
|
|
||||||
|
|
||||||
QStringList unique_ids = dev.unique_id_.split(',');
|
|
||||||
for (const QString &id : unique_ids) {
|
|
||||||
backends_ << Backend(nullptr, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::DeviceInfo::LoadIcon(const QVariantList &icons, const QString &name_hint) {
|
|
||||||
|
|
||||||
icon_name_ = "device";
|
|
||||||
|
|
||||||
if (icons.isEmpty()) {
|
|
||||||
icon_ = IconLoader::Load(icon_name_);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the icon with that exact name first
|
|
||||||
for (const QVariant &icon : icons) {
|
|
||||||
if (!icon.value<QPixmap>().isNull()) {
|
|
||||||
icon_ = QIcon(icon.value<QPixmap>());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!icon.toString().isEmpty()) icon_ = IconLoader::Load(icon.toString());
|
|
||||||
if (!icon_.isNull()) {
|
|
||||||
icon_name_ = icon.toString();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString hint = QString(icons.first().toString() + name_hint).toLower();
|
|
||||||
|
|
||||||
if (hint.contains("phone"))
|
|
||||||
icon_name_ = "device-phone";
|
|
||||||
else if (hint.contains("ipod") || hint.contains("apple"))
|
|
||||||
icon_name_ = "device-ipod";
|
|
||||||
else if ((hint.contains("usb")) && (hint.contains("reader")))
|
|
||||||
icon_name_ = "device-usb-flash";
|
|
||||||
else if (hint.contains("usb"))
|
|
||||||
icon_name_ = "device-usb-drive";
|
|
||||||
else
|
|
||||||
icon_name_ = "device";
|
|
||||||
|
|
||||||
icon_ = IconLoader::Load(icon_name_);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const DeviceManager::DeviceInfo::Backend *DeviceManager::DeviceInfo::BestBackend() const {
|
|
||||||
|
|
||||||
int best_priority = -1;
|
|
||||||
const Backend *ret = nullptr;
|
|
||||||
|
|
||||||
for (int i = 0; i < backends_.count(); ++i) {
|
|
||||||
if (backends_[i].lister_ && backends_[i].lister_->priority() > best_priority) {
|
|
||||||
best_priority = backends_[i].lister_->priority();
|
|
||||||
ret = &(backends_[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ret && !backends_.isEmpty()) return &(backends_[0]);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceManager::DeviceManager(Application *app, QObject *parent)
|
DeviceManager::DeviceManager(Application *app, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: SimpleTreeModel<DeviceInfo>(new DeviceInfo(this), parent),
|
||||||
app_(app),
|
app_(app),
|
||||||
not_connected_overlay_(IconLoader::Load("edit-delete"))
|
not_connected_overlay_(IconLoader::Load("edit-delete")) {
|
||||||
{
|
|
||||||
thread_pool_.setMaxThreadCount(1);
|
thread_pool_.setMaxThreadCount(1);
|
||||||
connect(app_->task_manager(), SIGNAL(TasksChanged()), SLOT(TasksChanged()));
|
connect(app_->task_manager(), SIGNAL(TasksChanged()), SLOT(TasksChanged()));
|
||||||
|
|
||||||
@@ -270,11 +162,11 @@ DeviceManager::~DeviceManager() {
|
|||||||
void DeviceManager::LoadAllDevices() {
|
void DeviceManager::LoadAllDevices() {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() != qApp->thread());
|
Q_ASSERT(QThread::currentThread() != qApp->thread());
|
||||||
|
|
||||||
DeviceDatabaseBackend::DeviceList devices = backend_->GetAllDevices();
|
DeviceDatabaseBackend::DeviceList devices = backend_->GetAllDevices();
|
||||||
for (const DeviceDatabaseBackend::Device &device : devices) {
|
for (const DeviceDatabaseBackend::Device &device : devices) {
|
||||||
DeviceInfo info;
|
DeviceInfo *info = new DeviceInfo(DeviceInfo::Type_Root, root_);
|
||||||
info.InitFromDb(device);
|
info->InitFromDb(device);
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
||||||
devices_ << info;
|
devices_ << info;
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
@@ -282,34 +174,30 @@ void DeviceManager::LoadAllDevices() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int DeviceManager::rowCount(const QModelIndex&) const {
|
|
||||||
return devices_.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant DeviceManager::data(const QModelIndex &index, int role) const {
|
QVariant DeviceManager::data(const QModelIndex &index, int role) const {
|
||||||
|
|
||||||
if (!index.isValid() || index.column() != 0) return QVariant();
|
if (!index.isValid() || index.column() != 0) return QVariant();
|
||||||
|
|
||||||
const DeviceInfo &info = devices_[index.row()];
|
const DeviceInfo *info = IndexToItem(index);
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
QString text;
|
QString text;
|
||||||
if (!info.friendly_name_.isEmpty())
|
if (!info->friendly_name_.isEmpty())
|
||||||
text = info.friendly_name_;
|
text = info->friendly_name_;
|
||||||
else
|
else
|
||||||
text = info.BestBackend()->unique_id_;
|
text = info->BestBackend()->unique_id_;
|
||||||
|
|
||||||
if (info.size_)
|
if (info->size_)
|
||||||
text = text + QString(" (%1)").arg(Utilities::PrettySize(info.size_));
|
text = text + QString(" (%1)").arg(Utilities::PrettySize(info->size_));
|
||||||
if (info.device_.get()) info.device_->Refresh();
|
if (info->device_.get()) info->device_->Refresh();
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Qt::DecorationRole: {
|
case Qt::DecorationRole: {
|
||||||
QPixmap pixmap = info.icon_.pixmap(kDeviceIconSize);
|
QPixmap pixmap = info->icon_.pixmap(kDeviceIconSize);
|
||||||
|
|
||||||
if (info.backends_.isEmpty() || !info.BestBackend()->lister_) {
|
if (info->backends_.isEmpty() || !info->BestBackend()->lister_) {
|
||||||
// Disconnected but remembered
|
// Disconnected but remembered
|
||||||
QPainter p(&pixmap);
|
QPainter p(&pixmap);
|
||||||
p.drawPixmap(kDeviceIconSize - kDeviceIconOverlaySize, kDeviceIconSize - kDeviceIconOverlaySize, not_connected_overlay_.pixmap(kDeviceIconOverlaySize));
|
p.drawPixmap(kDeviceIconSize - kDeviceIconOverlaySize, kDeviceIconSize - kDeviceIconOverlaySize, not_connected_overlay_.pixmap(kDeviceIconOverlaySize));
|
||||||
@@ -319,45 +207,45 @@ QVariant DeviceManager::data(const QModelIndex &index, int role) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Role_FriendlyName:
|
case Role_FriendlyName:
|
||||||
return info.friendly_name_;
|
return info->friendly_name_;
|
||||||
|
|
||||||
case Role_UniqueId:
|
case Role_UniqueId:
|
||||||
return info.BestBackend()->unique_id_;
|
return info->BestBackend()->unique_id_;
|
||||||
|
|
||||||
case Role_IconName:
|
case Role_IconName:
|
||||||
return info.icon_name_;
|
return info->icon_name_;
|
||||||
|
|
||||||
case Role_Capacity:
|
case Role_Capacity:
|
||||||
case MusicStorage::Role_Capacity:
|
case MusicStorage::Role_Capacity:
|
||||||
return info.size_;
|
return info->size_;
|
||||||
|
|
||||||
case Role_FreeSpace:
|
case Role_FreeSpace:
|
||||||
case MusicStorage::Role_FreeSpace:
|
case MusicStorage::Role_FreeSpace:
|
||||||
return info.BestBackend()->lister_ ? info.BestBackend()->lister_->DeviceFreeSpace(info.BestBackend()->unique_id_) : QVariant();
|
return info->BestBackend()->lister_ ? info->BestBackend()->lister_->DeviceFreeSpace(info->BestBackend()->unique_id_) : QVariant();
|
||||||
|
|
||||||
case Role_State:
|
case Role_State:
|
||||||
if (info.device_) return State_Connected;
|
if (info->device_) return State_Connected;
|
||||||
if (info.BestBackend()->lister_) {
|
if (info->BestBackend()->lister_) {
|
||||||
if (info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) return State_NotMounted;
|
if (info->BestBackend()->lister_->DeviceNeedsMount(info->BestBackend()->unique_id_)) return State_NotMounted;
|
||||||
return State_NotConnected;
|
return State_NotConnected;
|
||||||
}
|
}
|
||||||
return State_Remembered;
|
return State_Remembered;
|
||||||
|
|
||||||
case Role_UpdatingPercentage:
|
case Role_UpdatingPercentage:
|
||||||
if (info.task_percentage_ == -1) return QVariant();
|
if (info->task_percentage_ == -1) return QVariant();
|
||||||
return info.task_percentage_;
|
return info->task_percentage_;
|
||||||
|
|
||||||
case MusicStorage::Role_Storage:
|
case MusicStorage::Role_Storage:
|
||||||
if (!info.device_ && info.database_id_ != -1)
|
if (!info->device_ && info->database_id_ != -1)
|
||||||
const_cast<DeviceManager*>(this)->Connect(index.row());
|
const_cast<DeviceManager*>(this)->Connect(index.row());
|
||||||
if (!info.device_) return QVariant();
|
if (!info->device_) return QVariant();
|
||||||
return QVariant::fromValue<std::shared_ptr<MusicStorage>>(info.device_);
|
return QVariant::fromValue<std::shared_ptr<MusicStorage>>(info->device_);
|
||||||
|
|
||||||
case MusicStorage::Role_StorageForceConnect:
|
case MusicStorage::Role_StorageForceConnect:
|
||||||
if (!info.device_) {
|
if (!info->device_) {
|
||||||
if (info.database_id_ == -1 && !info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) {
|
if (info->database_id_ == -1 && !info->BestBackend()->lister_->DeviceNeedsMount(info->BestBackend()->unique_id_)) {
|
||||||
|
|
||||||
if (info.BestBackend()->lister_->AskForScan(info.BestBackend()->unique_id_)) {
|
if (info->BestBackend()->lister_->AskForScan(info->BestBackend()->unique_id_)) {
|
||||||
std::unique_ptr<QMessageBox> dialog(new QMessageBox(QMessageBox::Information, tr("Connect device"), tr("This is the first time you have connected this device. Strawberry will now scan the device to find music files - this may take some time."), QMessageBox::Cancel));
|
std::unique_ptr<QMessageBox> dialog(new QMessageBox(QMessageBox::Information, tr("Connect device"), tr("This is the first time you have connected this device. Strawberry will now scan the device to find music files - this may take some time."), QMessageBox::Cancel));
|
||||||
QPushButton *connect = dialog->addButton(tr("Connect device"), QMessageBox::AcceptRole);
|
QPushButton *connect = dialog->addButton(tr("Connect device"), QMessageBox::AcceptRole);
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
@@ -368,13 +256,13 @@ QVariant DeviceManager::data(const QModelIndex &index, int role) const {
|
|||||||
|
|
||||||
const_cast<DeviceManager*>(this)->Connect(index.row());
|
const_cast<DeviceManager*>(this)->Connect(index.row());
|
||||||
}
|
}
|
||||||
if (!info.device_) return QVariant();
|
if (!info->device_) return QVariant();
|
||||||
return QVariant::fromValue<std::shared_ptr<MusicStorage>>(info.device_);
|
return QVariant::fromValue<std::shared_ptr<MusicStorage>>(info->device_);
|
||||||
|
|
||||||
case Role_MountPath: {
|
case Role_MountPath: {
|
||||||
if (!info.device_) return QVariant();
|
if (!info->device_) return QVariant();
|
||||||
|
|
||||||
QString ret = info.device_->url().path();
|
QString ret = info->device_->url().path();
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
if (ret.startsWith('/')) ret.remove(0, 1);
|
if (ret.startsWith('/')) ret.remove(0, 1);
|
||||||
#endif
|
#endif
|
||||||
@@ -382,14 +270,14 @@ QVariant DeviceManager::data(const QModelIndex &index, int role) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Role_TranscodeMode:
|
case Role_TranscodeMode:
|
||||||
return info.transcode_mode_;
|
return info->transcode_mode_;
|
||||||
|
|
||||||
case Role_TranscodeFormat:
|
case Role_TranscodeFormat:
|
||||||
return info.transcode_format_;
|
return info->transcode_format_;
|
||||||
|
|
||||||
case Role_SongCount:
|
case Role_SongCount:
|
||||||
if (!info.device_) return QVariant();
|
if (!info->device_) return QVariant();
|
||||||
return info.device_->song_count();
|
return info->device_->song_count();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@@ -410,7 +298,7 @@ void DeviceManager::AddLister(DeviceLister *lister) {
|
|||||||
int DeviceManager::FindDeviceById(const QString &id) const {
|
int DeviceManager::FindDeviceById(const QString &id) const {
|
||||||
|
|
||||||
for (int i = 0; i < devices_.count(); ++i) {
|
for (int i = 0; i < devices_.count(); ++i) {
|
||||||
for (const DeviceInfo::Backend &backend : devices_[i].backends_) {
|
for (const DeviceInfo::Backend &backend : devices_[i]->backends_) {
|
||||||
if (backend.unique_id_ == id) return i;
|
if (backend.unique_id_ == id) return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,7 +312,7 @@ int DeviceManager::FindDeviceByUrl(const QList<QUrl> &urls) const {
|
|||||||
if (urls.isEmpty()) return -1;
|
if (urls.isEmpty()) return -1;
|
||||||
|
|
||||||
for (int i = 0; i < devices_.count(); ++i) {
|
for (int i = 0; i < devices_.count(); ++i) {
|
||||||
for (const DeviceInfo::Backend &backend : devices_[i].backends_) {
|
for (const DeviceInfo::Backend &backend : devices_[i]->backends_) {
|
||||||
if (!backend.lister_) continue;
|
if (!backend.lister_) continue;
|
||||||
|
|
||||||
QList<QUrl> device_urls = backend.lister_->MakeDeviceUrls(backend.unique_id_);
|
QList<QUrl> device_urls = backend.lister_->MakeDeviceUrls(backend.unique_id_);
|
||||||
@@ -447,10 +335,10 @@ void DeviceManager::PhysicalDeviceAdded(const QString &id) {
|
|||||||
// Do we have this device already?
|
// Do we have this device already?
|
||||||
int i = FindDeviceById(id);
|
int i = FindDeviceById(id);
|
||||||
if (i != -1) {
|
if (i != -1) {
|
||||||
DeviceInfo &info = devices_[i];
|
DeviceInfo *info = devices_[i];
|
||||||
for (int backend_index = 0 ; backend_index < info.backends_.count() ; ++backend_index) {
|
for (int backend_index = 0 ; backend_index < info->backends_.count() ; ++backend_index) {
|
||||||
if (info.backends_[backend_index].unique_id_ == id) {
|
if (info->backends_[backend_index].unique_id_ == id) {
|
||||||
info.backends_[backend_index].lister_ = lister;
|
info->backends_[backend_index].lister_ = lister;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,25 +350,25 @@ void DeviceManager::PhysicalDeviceAdded(const QString &id) {
|
|||||||
i = FindDeviceByUrl(lister->MakeDeviceUrls(id));
|
i = FindDeviceByUrl(lister->MakeDeviceUrls(id));
|
||||||
if (i != -1) {
|
if (i != -1) {
|
||||||
// Add this device's lister to the existing device
|
// Add this device's lister to the existing device
|
||||||
DeviceInfo &info = devices_[i];
|
DeviceInfo *info = devices_[i];
|
||||||
info.backends_ << DeviceInfo::Backend(lister, id);
|
info->backends_ << DeviceInfo::Backend(lister, id);
|
||||||
|
|
||||||
// If the user hasn't saved the device in the DB yet then overwrite the device's name and icon etc.
|
// If the user hasn't saved the device in the DB yet then overwrite the device's name and icon etc.
|
||||||
if (info.database_id_ == -1 && info.BestBackend()->lister_ == lister) {
|
if (info->database_id_ == -1 && info->BestBackend()->lister_ == lister) {
|
||||||
info.friendly_name_ = lister->MakeFriendlyName(id);
|
info->friendly_name_ = lister->MakeFriendlyName(id);
|
||||||
info.size_ = lister->DeviceCapacity(id);
|
info->size_ = lister->DeviceCapacity(id);
|
||||||
info.LoadIcon(lister->DeviceIcons(id), info.friendly_name_);
|
info->LoadIcon(lister->DeviceIcons(id), info->friendly_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit dataChanged(index(i, 0), index(i, 0));
|
emit dataChanged(index(i, 0), index(i, 0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// It's a completely new device
|
// It's a completely new device
|
||||||
DeviceInfo info;
|
DeviceInfo *info = new DeviceInfo(DeviceInfo::Type_Root, root_);
|
||||||
info.backends_ << DeviceInfo::Backend(lister, id);
|
info->backends_ << DeviceInfo::Backend(lister, id);
|
||||||
info.friendly_name_ = lister->MakeFriendlyName(id);
|
info->friendly_name_ = lister->MakeFriendlyName(id);
|
||||||
info.size_ = lister->DeviceCapacity(id);
|
info->size_ = lister->DeviceCapacity(id);
|
||||||
info.LoadIcon(lister->DeviceIcons(id), info.friendly_name_);
|
info->LoadIcon(lister->DeviceIcons(id), info->friendly_name_);
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
||||||
devices_ << info;
|
devices_ << info;
|
||||||
@@ -502,33 +390,33 @@ void DeviceManager::PhysicalDeviceRemoved(const QString &id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInfo &info = devices_[i];
|
DeviceInfo *info = devices_[i];
|
||||||
|
|
||||||
if (info.database_id_ != -1) {
|
if (info->database_id_ != -1) {
|
||||||
// Keep the structure around, but just "disconnect" it
|
// Keep the structure around, but just "disconnect" it
|
||||||
for (int backend_index = 0 ; backend_index < info.backends_.count() ; ++backend_index) {
|
for (int backend_index = 0 ; backend_index < info->backends_.count() ; ++backend_index) {
|
||||||
if (info.backends_[backend_index].unique_id_ == id) {
|
if (info->backends_[backend_index].unique_id_ == id) {
|
||||||
info.backends_[backend_index].lister_ = nullptr;
|
info->backends_[backend_index].lister_ = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.device_ && info.device_->lister() == lister) info.device_.reset();
|
if (info->device_ && info->device_->lister() == lister) info->device_.reset();
|
||||||
|
|
||||||
if (!info.device_) emit DeviceDisconnected(i);
|
if (!info->device_) emit DeviceDisconnected(i);
|
||||||
|
|
||||||
emit dataChanged(index(i, 0), index(i, 0));
|
emit dataChanged(index(i, 0), index(i, 0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If this was the last lister for the device then remove it from the model
|
// If this was the last lister for the device then remove it from the model
|
||||||
for (int backend_index = 0 ; backend_index < info.backends_.count() ; ++backend_index) {
|
for (int backend_index = 0 ; backend_index < info->backends_.count() ; ++backend_index) {
|
||||||
if (info.backends_[backend_index].unique_id_ == id) {
|
if (info->backends_[backend_index].unique_id_ == id) {
|
||||||
info.backends_.removeAt(backend_index);
|
info->backends_.removeAt(backend_index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.backends_.isEmpty()) {
|
if (info->backends_.isEmpty()) {
|
||||||
beginRemoveRows(QModelIndex(), i, i);
|
beginRemoveRows(QModelIndex(), i, i);
|
||||||
devices_.removeAt(i);
|
devices_.removeAt(i);
|
||||||
|
|
||||||
@@ -557,33 +445,34 @@ void DeviceManager::PhysicalDeviceChanged(const QString &id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ConnectedDevice> DeviceManager::Connect(int row) {
|
std::shared_ptr<ConnectedDevice> DeviceManager::Connect(int row) {
|
||||||
|
|
||||||
DeviceInfo &info = devices_[row];
|
DeviceInfo *info = devices_[row];
|
||||||
if (info.device_) // Already connected
|
if (info->device_) // Already connected
|
||||||
return info.device_;
|
return info->device_;
|
||||||
|
|
||||||
std::shared_ptr<ConnectedDevice> ret;
|
std::shared_ptr<ConnectedDevice> ret;
|
||||||
|
|
||||||
if (!info.BestBackend()->lister_) // Not physically connected
|
if (!info->BestBackend()->lister_) // Not physically connected
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) {
|
if (info->BestBackend()->lister_->DeviceNeedsMount(info->BestBackend()->unique_id_)) {
|
||||||
// Mount the device
|
// Mount the device
|
||||||
info.BestBackend()->lister_->MountDevice(info.BestBackend()->unique_id_);
|
info->BestBackend()->lister_->MountDevice(info->BestBackend()->unique_id_);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool first_time = (info.database_id_ == -1);
|
bool first_time = (info->database_id_ == -1);
|
||||||
if (first_time) {
|
if (first_time) {
|
||||||
// We haven't stored this device in the database before
|
// We haven't stored this device in the database before
|
||||||
info.database_id_ = backend_->AddDevice(info.SaveToDb());
|
info->database_id_ = backend_->AddDevice(info->SaveToDb());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device URLs
|
// Get the device URLs
|
||||||
QList<QUrl> urls = info.BestBackend()->lister_->MakeDeviceUrls(info.BestBackend()->unique_id_);
|
QList<QUrl> urls = info->BestBackend()->lister_->MakeDeviceUrls(info->BestBackend()->unique_id_);
|
||||||
if (urls.isEmpty()) return ret;
|
if (urls.isEmpty()) return ret;
|
||||||
|
|
||||||
// Take the first URL that we have a handler for
|
// Take the first URL that we have a handler for
|
||||||
@@ -630,65 +519,70 @@ std::shared_ptr<ConnectedDevice> DeviceManager::Connect(int row) {
|
|||||||
QMetaObject meta_object = device_classes_.value(device_url.scheme());
|
QMetaObject meta_object = device_classes_.value(device_url.scheme());
|
||||||
QObject *instance = meta_object.newInstance(
|
QObject *instance = meta_object.newInstance(
|
||||||
Q_ARG(QUrl, device_url),
|
Q_ARG(QUrl, device_url),
|
||||||
Q_ARG(DeviceLister*, info.BestBackend()->lister_),
|
Q_ARG(DeviceLister*, info->BestBackend()->lister_),
|
||||||
Q_ARG(QString, info.BestBackend()->unique_id_),
|
Q_ARG(QString, info->BestBackend()->unique_id_),
|
||||||
Q_ARG(DeviceManager*, this), Q_ARG(Application*, app_),
|
Q_ARG(DeviceManager*, this), Q_ARG(Application*, app_),
|
||||||
Q_ARG(int, info.database_id_), Q_ARG(bool, first_time));
|
Q_ARG(int, info->database_id_), Q_ARG(bool, first_time));
|
||||||
|
|
||||||
ret.reset(static_cast<ConnectedDevice*>(instance));
|
ret.reset(static_cast<ConnectedDevice*>(instance));
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
qLog(Warning) << "Could not create device for" << device_url.toString();
|
qLog(Warning) << "Could not create device for" << device_url.toString();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ret->Init();
|
|
||||||
|
|
||||||
info.device_ = ret;
|
bool result = ret->Init();
|
||||||
emit dataChanged(index(row), index(row));
|
if (!result) {
|
||||||
connect(info.device_.get(), SIGNAL(TaskStarted(int)), SLOT(DeviceTaskStarted(int)));
|
qLog(Warning) << "Could not connect to device" << device_url.toString();
|
||||||
connect(info.device_.get(), SIGNAL(SongCountUpdated(int)), SLOT(DeviceSongCountUpdated(int)));
|
return ret;
|
||||||
}
|
}
|
||||||
|
info->device_ = ret;
|
||||||
|
QModelIndex index = ItemToIndex(info);
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
connect(info->device_.get(), SIGNAL(TaskStarted(int)), SLOT(DeviceTaskStarted(int)));
|
||||||
|
connect(info->device_.get(), SIGNAL(SongCountUpdated(int)), SLOT(DeviceSongCountUpdated(int)));
|
||||||
|
|
||||||
emit DeviceConnected(row);
|
emit DeviceConnected(row);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ConnectedDevice> DeviceManager::GetConnectedDevice(int row) const {
|
std::shared_ptr<ConnectedDevice> DeviceManager::GetConnectedDevice(int row) const {
|
||||||
return devices_[row].device_;
|
return devices_[row]->device_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DeviceManager::GetDatabaseId(int row) const {
|
int DeviceManager::GetDatabaseId(int row) const {
|
||||||
return devices_[row].database_id_;
|
return devices_[row]->database_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceLister *DeviceManager::GetLister(int row) const {
|
DeviceLister *DeviceManager::GetLister(int row) const {
|
||||||
return devices_[row].BestBackend()->lister_;
|
return devices_[row]->BestBackend()->lister_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::Disconnect(int row) {
|
void DeviceManager::Disconnect(int row) {
|
||||||
|
|
||||||
DeviceInfo &info = devices_[row];
|
DeviceInfo *info = devices_[row];
|
||||||
if (!info.device_) // Already disconnected
|
if (!info->device_) // Already disconnected
|
||||||
return;
|
return;
|
||||||
|
|
||||||
info.device_.reset();
|
info->device_.reset();
|
||||||
emit DeviceDisconnected(row);
|
emit DeviceDisconnected(row);
|
||||||
emit dataChanged(index(row), index(row));
|
QModelIndex index = ItemToIndex(info);
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::Forget(int row) {
|
void DeviceManager::Forget(int row) {
|
||||||
|
|
||||||
DeviceInfo &info = devices_[row];
|
DeviceInfo *info = devices_[row];
|
||||||
if (info.database_id_ == -1) return;
|
if (info->database_id_ == -1) return;
|
||||||
|
|
||||||
if (info.device_) Disconnect(row);
|
if (info->device_) Disconnect(row);
|
||||||
|
|
||||||
backend_->RemoveDevice(info.database_id_);
|
backend_->RemoveDevice(info->database_id_);
|
||||||
info.database_id_ = -1;
|
info->database_id_ = -1;
|
||||||
|
|
||||||
if (!info.BestBackend()->lister_) {
|
if (!info->BestBackend()->lister_) {
|
||||||
// It's not attached any more so remove it from the list
|
// It's not attached any more so remove it from the list
|
||||||
beginRemoveRows(QModelIndex(), row, row);
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
devices_.removeAt(row);
|
devices_.removeAt(row);
|
||||||
@@ -704,10 +598,10 @@ void DeviceManager::Forget(int row) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// It's still attached, set the name and icon back to what they were originally
|
// It's still attached, set the name and icon back to what they were originally
|
||||||
const QString id = info.BestBackend()->unique_id_;
|
const QString id = info->BestBackend()->unique_id_;
|
||||||
|
|
||||||
info.friendly_name_ = info.BestBackend()->lister_->MakeFriendlyName(id);
|
info->friendly_name_ = info->BestBackend()->lister_->MakeFriendlyName(id);
|
||||||
info.LoadIcon(info.BestBackend()->lister_->DeviceIcons(id), info.friendly_name_);
|
info->LoadIcon(info->BestBackend()->lister_->DeviceIcons(id), info->friendly_name_);
|
||||||
|
|
||||||
dataChanged(index(row, 0), index(row, 0));
|
dataChanged(index(row, 0), index(row, 0));
|
||||||
}
|
}
|
||||||
@@ -716,16 +610,16 @@ void DeviceManager::Forget(int row) {
|
|||||||
|
|
||||||
void DeviceManager::SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format) {
|
void DeviceManager::SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format) {
|
||||||
|
|
||||||
DeviceInfo &info = devices_[row];
|
DeviceInfo *info = devices_[row];
|
||||||
info.friendly_name_ = friendly_name;
|
info->friendly_name_ = friendly_name;
|
||||||
info.LoadIcon(QVariantList() << icon_name, friendly_name);
|
info->LoadIcon(QVariantList() << icon_name, friendly_name);
|
||||||
info.transcode_mode_ = mode;
|
info->transcode_mode_ = mode;
|
||||||
info.transcode_format_ = format;
|
info->transcode_format_ = format;
|
||||||
|
|
||||||
emit dataChanged(index(row, 0), index(row, 0));
|
emit dataChanged(index(row, 0), index(row, 0));
|
||||||
|
|
||||||
if (info.database_id_ != -1)
|
if (info->database_id_ != -1)
|
||||||
backend_->SetDeviceOptions(info.database_id_, friendly_name, icon_name, mode, format);
|
backend_->SetDeviceOptions(info->database_id_, friendly_name, icon_name, mode, format);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,11 +629,12 @@ void DeviceManager::DeviceTaskStarted(int id) {
|
|||||||
if (!device) return;
|
if (!device) return;
|
||||||
|
|
||||||
for (int i = 0; i < devices_.count(); ++i) {
|
for (int i = 0; i < devices_.count(); ++i) {
|
||||||
DeviceInfo &info = devices_[i];
|
DeviceInfo *info = devices_[i];
|
||||||
if (info.device_.get() == device) {
|
if (info->device_.get() == device) {
|
||||||
active_tasks_[id] = index(i);
|
QModelIndex index = ItemToIndex(info);
|
||||||
info.task_percentage_ = 0;
|
active_tasks_[id] = index;
|
||||||
emit dataChanged(index(i), index(i));
|
info->task_percentage_ = 0;
|
||||||
|
emit dataChanged(index, index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -757,20 +652,22 @@ void DeviceManager::TasksChanged() {
|
|||||||
QPersistentModelIndex index = active_tasks_[task.id];
|
QPersistentModelIndex index = active_tasks_[task.id];
|
||||||
if (!index.isValid()) continue;
|
if (!index.isValid()) continue;
|
||||||
|
|
||||||
DeviceInfo &info = devices_[index.row()];
|
DeviceInfo *info = IndexToItem(index);
|
||||||
if (task.progress_max)
|
if (task.progress_max)
|
||||||
info.task_percentage_ = float(task.progress) / task.progress_max * 100;
|
info->task_percentage_ = float(task.progress) / task.progress_max * 100;
|
||||||
else
|
else
|
||||||
info.task_percentage_ = 0;
|
info->task_percentage_ = 0;
|
||||||
|
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
finished_tasks.removeAll(index);
|
finished_tasks.removeAll(index);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QPersistentModelIndex &index : finished_tasks) {
|
for (const QPersistentModelIndex &index : finished_tasks) {
|
||||||
if (!index.isValid()) continue;
|
if (!index.isValid()) continue;
|
||||||
|
|
||||||
DeviceInfo &info = devices_[index.row()];
|
DeviceInfo *info = devices_[index.row()];
|
||||||
info.task_percentage_ = -1;
|
info->task_percentage_ = -1;
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
active_tasks_.remove(active_tasks_.key(index));
|
active_tasks_.remove(active_tasks_.key(index));
|
||||||
@@ -784,13 +681,13 @@ void DeviceManager::UnmountAsync(int row) {
|
|||||||
|
|
||||||
void DeviceManager::Unmount(int row) {
|
void DeviceManager::Unmount(int row) {
|
||||||
|
|
||||||
DeviceInfo &info = devices_[row];
|
DeviceInfo *info = devices_[row];
|
||||||
if (info.database_id_ != -1 && !info.device_) return;
|
if (info->database_id_ != -1 && !info->device_) return;
|
||||||
|
|
||||||
if (info.device_) Disconnect(row);
|
if (info->device_) Disconnect(row);
|
||||||
|
|
||||||
if (info.BestBackend()->lister_)
|
if (info->BestBackend()->lister_)
|
||||||
info.BestBackend()->lister_->UnmountDevice(info.BestBackend()->unique_id_);
|
info->BestBackend()->lister_->UnmountDevice(info->BestBackend()->unique_id_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,7 +699,25 @@ void DeviceManager::DeviceSongCountUpdated(int count) {
|
|||||||
int row = FindDeviceById(device->unique_id());
|
int row = FindDeviceById(device->unique_id());
|
||||||
if (row == -1) return;
|
if (row == -1) return;
|
||||||
|
|
||||||
emit dataChanged(index(row), index(row));
|
QModelIndex index = ItemToIndex(devices_[row]);
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceManager::LazyPopulate(DeviceInfo *parent, bool signal) {
|
||||||
|
if (parent->lazy_loaded) return;
|
||||||
|
parent->lazy_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceInfo *DeviceManager::ItemFromRow(int row) {
|
||||||
|
return devices_[row];
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DeviceManager::DeviceNameByID(QString unique_id) {
|
||||||
|
|
||||||
|
int row = FindDeviceById(unique_id);
|
||||||
|
DeviceInfo *info = devices_[row];
|
||||||
|
QModelIndex index = ItemToIndex(info);
|
||||||
|
return data(index, DeviceManager::Role_FriendlyName).toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -30,28 +31,29 @@
|
|||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMultiMap>
|
#include <QMultiMap>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QUrl>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/musicstorage.h"
|
#include "core/musicstorage.h"
|
||||||
|
#include "core/simpletreemodel.h"
|
||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
#include "devicedatabasebackend.h"
|
#include "devicedatabasebackend.h"
|
||||||
|
#include "deviceinfo.h"
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
class ConnectedDevice;
|
class ConnectedDevice;
|
||||||
class DeviceLister;
|
class DeviceLister;
|
||||||
class DeviceStateFilterModel;
|
class DeviceStateFilterModel;
|
||||||
|
|
||||||
class DeviceManager : public QAbstractListModel {
|
class DeviceManager : public SimpleTreeModel<DeviceInfo> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -90,8 +92,10 @@ class DeviceManager : public QAbstractListModel {
|
|||||||
DeviceLister *GetLister(int row) const;
|
DeviceLister *GetLister(int row) const;
|
||||||
std::shared_ptr<ConnectedDevice> GetConnectedDevice(int row) const;
|
std::shared_ptr<ConnectedDevice> GetConnectedDevice(int row) const;
|
||||||
|
|
||||||
|
DeviceInfo *ItemFromRow(int row);
|
||||||
int FindDeviceById(const QString &id) const;
|
int FindDeviceById(const QString &id) const;
|
||||||
int FindDeviceByUrl(const QList<QUrl> &url) const;
|
int FindDeviceByUrl(const QList<QUrl> &url) const;
|
||||||
|
QString DeviceNameByID(QString unique_id);
|
||||||
|
|
||||||
// Actions on devices
|
// Actions on devices
|
||||||
std::shared_ptr<ConnectedDevice> Connect(int row);
|
std::shared_ptr<ConnectedDevice> Connect(int row);
|
||||||
@@ -101,14 +105,13 @@ class DeviceManager : public QAbstractListModel {
|
|||||||
|
|
||||||
void SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format);
|
void SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format);
|
||||||
|
|
||||||
// QAbstractListModel
|
// QAbstractItemModel
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void Unmount(int row);
|
void Unmount(int row);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void DeviceConnected(int row);
|
void DeviceConnected(int row);
|
||||||
void DeviceDisconnected(int row);
|
void DeviceDisconnected(int row);
|
||||||
|
|
||||||
@@ -121,55 +124,11 @@ signals:
|
|||||||
void DeviceSongCountUpdated(int count);
|
void DeviceSongCountUpdated(int count);
|
||||||
void LoadAllDevices();
|
void LoadAllDevices();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void LazyPopulate(DeviceInfo *item) { LazyPopulate(item, true); }
|
||||||
|
void LazyPopulate(DeviceInfo *item, bool signal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Devices can be in three different states:
|
|
||||||
// 1) Remembered in the database but not physically connected at the moment.
|
|
||||||
// database_id valid, lister null, device null
|
|
||||||
// 2) Physically connected but the user hasn't "connected" it to Strawberry
|
|
||||||
// yet.
|
|
||||||
// database_id == -1, lister valid, device null
|
|
||||||
// 3) Physically connected and connected to Strawberry
|
|
||||||
// database_id valid, lister valid, device valid
|
|
||||||
// Devices in all states will have a unique_id.
|
|
||||||
struct DeviceInfo {
|
|
||||||
DeviceInfo();
|
|
||||||
|
|
||||||
// A device can be discovered in different ways (devicekit, gio, etc.)
|
|
||||||
// Sometimes the same device is discovered more than once. In this case the device will have multiple "backends".
|
|
||||||
struct Backend {
|
|
||||||
Backend(DeviceLister *lister = nullptr, const QString &id = QString())
|
|
||||||
: lister_(lister), unique_id_(id) {}
|
|
||||||
|
|
||||||
DeviceLister *lister_; // nullptr if not physically connected
|
|
||||||
QString unique_id_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Serialising to the database
|
|
||||||
void InitFromDb(const DeviceDatabaseBackend::Device &dev);
|
|
||||||
DeviceDatabaseBackend::Device SaveToDb() const;
|
|
||||||
|
|
||||||
// Tries to load a good icon for the device. Sets icon_name_ and icon_.
|
|
||||||
void LoadIcon(const QVariantList &icons, const QString &name_hint);
|
|
||||||
|
|
||||||
// Gets the best backend available (the one with the highest priority)
|
|
||||||
const Backend *BestBackend() const;
|
|
||||||
|
|
||||||
int database_id_; // -1 if not remembered in the database
|
|
||||||
std::shared_ptr<ConnectedDevice>
|
|
||||||
device_; // nullptr if not connected
|
|
||||||
QList<Backend> backends_;
|
|
||||||
|
|
||||||
QString friendly_name_;
|
|
||||||
quint64 size_;
|
|
||||||
|
|
||||||
QString icon_name_;
|
|
||||||
QIcon icon_;
|
|
||||||
|
|
||||||
MusicStorage::TranscodeMode transcode_mode_;
|
|
||||||
Song::FileType transcode_format_;
|
|
||||||
|
|
||||||
int task_percentage_;
|
|
||||||
};
|
|
||||||
|
|
||||||
void AddLister(DeviceLister *lister);
|
void AddLister(DeviceLister *lister);
|
||||||
template <typename T> void AddDeviceClass();
|
template <typename T> void AddDeviceClass();
|
||||||
@@ -185,7 +144,7 @@ signals:
|
|||||||
QIcon not_connected_overlay_;
|
QIcon not_connected_overlay_;
|
||||||
|
|
||||||
QList<DeviceLister*> listers_;
|
QList<DeviceLister*> listers_;
|
||||||
QList<DeviceInfo> devices_;
|
QList<DeviceInfo*> devices_;
|
||||||
|
|
||||||
QMultiMap<QString, QMetaObject> device_classes_;
|
QMultiMap<QString, QMetaObject> device_classes_;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +27,6 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
@@ -56,6 +55,7 @@
|
|||||||
#include "connecteddevice.h"
|
#include "connecteddevice.h"
|
||||||
#include "devicelister.h"
|
#include "devicelister.h"
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
#include "deviceinfo.h"
|
||||||
#include "deviceproperties.h"
|
#include "deviceproperties.h"
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
# include "transcoder/transcoder.h"
|
# include "transcoder/transcoder.h"
|
||||||
@@ -117,7 +117,7 @@ void DeviceProperties::ShowDevice(int row) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
index_ = manager_->index(row);
|
index_ = manager_->index(row, 0, QModelIndex());
|
||||||
|
|
||||||
// Basic information
|
// Basic information
|
||||||
ui_->name->setText(index_.data(DeviceManager::Role_FriendlyName).toString());
|
ui_->name->setText(index_.data(DeviceManager::Role_FriendlyName).toString());
|
||||||
@@ -321,4 +321,3 @@ void DeviceProperties::UpdateFormatsFinished(QFuture<bool> future) {
|
|||||||
ui_->formats_stack->setCurrentWidget(ui_->formats_page);
|
ui_->formats_stack->setCurrentWidget(ui_->formats_page);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
#include "connecteddevice.h"
|
#include "connecteddevice.h"
|
||||||
#include "devicelister.h"
|
#include "devicelister.h"
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
#include "deviceinfo.h"
|
||||||
#include "deviceproperties.h"
|
#include "deviceproperties.h"
|
||||||
#include "deviceview.h"
|
#include "deviceview.h"
|
||||||
|
|
||||||
@@ -259,7 +261,6 @@ void DeviceView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
bool is_filesystem_device = false;
|
bool is_filesystem_device = false;
|
||||||
if (parent_device_index.isValid()) {
|
if (parent_device_index.isValid()) {
|
||||||
std::shared_ptr<ConnectedDevice> device = app_->device_manager()->GetConnectedDevice(parent_device_index.row());
|
std::shared_ptr<ConnectedDevice> device = app_->device_manager()->GetConnectedDevice(parent_device_index.row());
|
||||||
qLog(Debug) << device->LocalPath();
|
|
||||||
if (device && !device->LocalPath().isEmpty()) is_filesystem_device = true;
|
if (device && !device->LocalPath().isEmpty()) is_filesystem_device = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +307,9 @@ void DeviceView::DeviceConnected(int row) {
|
|||||||
std::shared_ptr<ConnectedDevice> device = app_->device_manager()->GetConnectedDevice(row);
|
std::shared_ptr<ConnectedDevice> device = app_->device_manager()->GetConnectedDevice(row);
|
||||||
if (!device) return;
|
if (!device) return;
|
||||||
|
|
||||||
QModelIndex sort_idx = sort_model_->mapFromSource(app_->device_manager()->index(row));
|
DeviceInfo *info = app_->device_manager()->ItemFromRow(row);
|
||||||
|
QModelIndex index = app_->device_manager()->ItemToIndex(info);
|
||||||
|
QModelIndex sort_idx = sort_model_->mapFromSource(index);
|
||||||
|
|
||||||
QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(device->model());
|
QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(device->model());
|
||||||
sort_model->setSourceModel(device->model());
|
sort_model->setSourceModel(device->model());
|
||||||
@@ -320,7 +323,9 @@ void DeviceView::DeviceConnected(int row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceView::DeviceDisconnected(int row) {
|
void DeviceView::DeviceDisconnected(int row) {
|
||||||
merged_model_->RemoveSubModel(sort_model_->mapFromSource(app_->device_manager()->index(row)));
|
DeviceInfo *info = app_->device_manager()->ItemFromRow(row);
|
||||||
|
QModelIndex index = app_->device_manager()->ItemToIndex(info);
|
||||||
|
merged_model_->RemoveSubModel(sort_model_->mapFromSource(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceView::Forget() {
|
void DeviceView::Forget() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,7 +30,6 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
#include <QStyleOptionViewItem>
|
#include <QStyleOptionViewItem>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ FilesystemDevice::FilesystemDevice(const QUrl &url, DeviceLister *lister, const
|
|||||||
watcher_->moveToThread(watcher_thread_);
|
watcher_->moveToThread(watcher_thread_);
|
||||||
watcher_thread_->start(QThread::IdlePriority);
|
watcher_thread_->start(QThread::IdlePriority);
|
||||||
|
|
||||||
watcher_->set_device_name(manager->data(manager->index(manager->FindDeviceById(unique_id)), DeviceManager::Role_FriendlyName).toString());
|
watcher_->set_device_name(manager->DeviceNameByID(unique_id));
|
||||||
watcher_->set_backend(backend_);
|
watcher_->set_backend(backend_);
|
||||||
watcher_->set_task_manager(app_->task_manager());
|
watcher_->set_task_manager(app_->task_manager());
|
||||||
|
|
||||||
@@ -58,9 +58,10 @@ FilesystemDevice::FilesystemDevice(const QUrl &url, DeviceLister *lister, const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilesystemDevice::Init() {
|
bool FilesystemDevice::Init() {
|
||||||
InitBackendDirectory(url_.toLocalFile(), first_time_);
|
InitBackendDirectory(url_.toLocalFile(), first_time_);
|
||||||
model_->Init();
|
model_->Init();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilesystemDevice::~FilesystemDevice() {
|
FilesystemDevice::~FilesystemDevice() {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
int database_id, bool first_time);
|
int database_id, bool first_time);
|
||||||
~FilesystemDevice();
|
~FilesystemDevice();
|
||||||
|
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "file"; }
|
static QStringList url_schemes() { return QStringList() << "file"; }
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,16 @@
|
|||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/signalchecker.h"
|
#include "core/signalchecker.h"
|
||||||
@@ -85,7 +89,7 @@ void GioLister::VolumeMountFinished(GObject *object, GAsyncResult *result, gpoin
|
|||||||
OperationFinished<GVolume>(std::bind(g_volume_mount_finish, _1, _2, _3), object, result);
|
OperationFinished<GVolume>(std::bind(g_volume_mount_finish, _1, _2, _3), object, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GioLister::Init() {
|
bool GioLister::Init() {
|
||||||
|
|
||||||
monitor_.reset_without_add(g_volume_monitor_get());
|
monitor_.reset_without_add(g_volume_monitor_get());
|
||||||
|
|
||||||
@@ -116,6 +120,8 @@ void GioLister::Init() {
|
|||||||
signals_.append(CHECKED_GCONNECT(monitor_, "mount-changed", &MountChangedCallback, this));
|
signals_.append(CHECKED_GCONNECT(monitor_, "mount-changed", &MountChangedCallback, this));
|
||||||
signals_.append(CHECKED_GCONNECT(monitor_, "mount-removed", &MountRemovedCallback, this));
|
signals_.append(CHECKED_GCONNECT(monitor_, "mount-removed", &MountRemovedCallback, this));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GioLister::~GioLister() {
|
GioLister::~GioLister() {
|
||||||
@@ -191,10 +197,13 @@ QList<QUrl> GioLister::MakeDeviceUrls(const QString &id) {
|
|||||||
|
|
||||||
QString mount_point;
|
QString mount_point;
|
||||||
QString uri;
|
QString uri;
|
||||||
|
QString unix_device;
|
||||||
|
|
||||||
{
|
{
|
||||||
QMutexLocker l(&mutex_);
|
QMutexLocker l(&mutex_);
|
||||||
mount_point = devices_[id].mount_path;
|
mount_point = devices_[id].mount_path;
|
||||||
uri = devices_[id].mount_uri;
|
uri = devices_[id].mount_uri;
|
||||||
|
unix_device = devices_[id].volume_unix_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gphoto2 gives invalid hostnames with []:, characters in
|
// gphoto2 gives invalid hostnames with []:, characters in
|
||||||
@@ -204,12 +213,22 @@ QList<QUrl> GioLister::MakeDeviceUrls(const QString &id) {
|
|||||||
|
|
||||||
QList<QUrl> ret;
|
QList<QUrl> ret;
|
||||||
|
|
||||||
// Special case for file:// GIO URIs - we have to check whether they point to an ipod.
|
if (url.isValid()) {
|
||||||
if (url.isValid() && url.scheme() == "file") {
|
QRegExp device_re("usb/(\\d+)/(\\d+)");
|
||||||
ret << MakeUrlFromLocalPath(url.path());
|
if (device_re.indexIn(unix_device) >= 0) {
|
||||||
}
|
QUrlQuery url_query(url);
|
||||||
else {
|
url_query.addQueryItem("busnum", device_re.cap(1));
|
||||||
ret << url;
|
url_query.addQueryItem("devnum", device_re.cap(2));
|
||||||
|
url.setQuery(url_query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for file:// GIO URIs - we have to check whether they point to an ipod.
|
||||||
|
if (url.scheme() == "file") {
|
||||||
|
ret << MakeUrlFromLocalPath(url.path());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret << url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret << MakeUrlFromLocalPath(mount_point);
|
ret << MakeUrlFromLocalPath(mount_point);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
// Work around compile issue with glib >= 2.25
|
// Work around compile issue with glib >= 2.25
|
||||||
#ifdef signals
|
#ifdef signals
|
||||||
#undef signals
|
# undef signals
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QMutex>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
@@ -74,7 +74,7 @@ class GioLister : public DeviceLister {
|
|||||||
void UpdateDeviceFreeSpace(const QString &id);
|
void UpdateDeviceFreeSpace(const QString &id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct DeviceInfo {
|
struct DeviceInfo {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ GPodDevice::GPodDevice(const QUrl &url, DeviceLister *lister, const QString &uni
|
|||||||
loader_(nullptr),
|
loader_(nullptr),
|
||||||
db_(nullptr) {}
|
db_(nullptr) {}
|
||||||
|
|
||||||
void GPodDevice::Init() {
|
bool GPodDevice::Init() {
|
||||||
|
|
||||||
InitBackendDirectory(url_.path(), first_time_);
|
InitBackendDirectory(url_.path(), first_time_);
|
||||||
model_->Init();
|
model_->Init();
|
||||||
@@ -65,6 +65,8 @@ void GPodDevice::Init() {
|
|||||||
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
||||||
loader_thread_->start();
|
loader_thread_->start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPodDevice::~GPodDevice() {}
|
GPodDevice::~GPodDevice() {}
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ class GPodLoader;
|
|||||||
class GPodDevice : public ConnectedDevice, public virtual MusicStorage {
|
class GPodDevice : public ConnectedDevice, public virtual MusicStorage {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
signals:
|
||||||
|
void Error(const QString &message);
|
||||||
|
|
||||||
|
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,
|
||||||
@@ -55,7 +58,7 @@ public:
|
|||||||
int database_id, bool first_time);
|
int database_id, bool first_time);
|
||||||
~GPodDevice();
|
~GPodDevice();
|
||||||
|
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "ipod"; }
|
static QStringList url_schemes() { return QStringList() << "ipod"; }
|
||||||
|
|
||||||
@@ -69,9 +72,6 @@ public:
|
|||||||
bool DeleteFromStorage(const DeleteJob &job);
|
bool DeleteFromStorage(const DeleteJob &job);
|
||||||
void FinishDelete(bool success);
|
void FinishDelete(bool success);
|
||||||
|
|
||||||
signals:
|
|
||||||
void Error(const QString &message);
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void LoadFinished(Itdb_iTunesDB *db);
|
void LoadFinished(Itdb_iTunesDB *db);
|
||||||
|
|
||||||
@@ -98,4 +98,3 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // GPODDEVICE_H
|
#endif // GPODDEVICE_H
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ iLister::iLister() {
|
|||||||
iLister::~iLister() {
|
iLister::~iLister() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void iLister::Init() {
|
bool iLister::Init() {
|
||||||
idevice_event_subscribe(&EventCallback, reinterpret_cast<void*>(this));
|
idevice_event_subscribe(&EventCallback, reinterpret_cast<void*>(this));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iLister::EventCallback(const idevice_event_t *event, void *context) {
|
void iLister::EventCallback(const idevice_event_t *event, void *context) {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class iLister : public DeviceLister {
|
|||||||
QString bt_mac;
|
QString bt_mac;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void Init();
|
virtual bool Init();
|
||||||
|
|
||||||
static void EventCallback(const idevice_event_t *event, void *context);
|
static void EventCallback(const idevice_event_t *event, void *context);
|
||||||
|
|
||||||
|
|||||||
@@ -38,15 +38,24 @@ MtpConnection::MtpConnection(const QUrl &url) : device_(nullptr) {
|
|||||||
// Parse the URL
|
// Parse the URL
|
||||||
QRegExp host_re("^usb-(\\d+)-(\\d+)$");
|
QRegExp host_re("^usb-(\\d+)-(\\d+)$");
|
||||||
|
|
||||||
if (host_re.indexIn(hostname) == -1) {
|
unsigned int bus_location = 0;
|
||||||
|
unsigned int device_num = 0;
|
||||||
|
|
||||||
|
QUrlQuery url_query(url);
|
||||||
|
|
||||||
|
if (host_re.indexIn(hostname) >= 0) {
|
||||||
|
bus_location = host_re.cap(1).toUInt();
|
||||||
|
device_num = host_re.cap(2).toUInt();
|
||||||
|
}
|
||||||
|
else if (url_query.hasQueryItem("busnum")) {
|
||||||
|
bus_location = url_query.queryItemValue("busnum").toUInt();
|
||||||
|
device_num = url_query.queryItemValue("devnum").toUInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
qLog(Warning) << "Invalid MTP device:" << hostname;
|
qLog(Warning) << "Invalid MTP device:" << hostname;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned int bus_location = host_re.cap(1).toInt();
|
|
||||||
const unsigned int device_num = host_re.cap(2).toInt();
|
|
||||||
|
|
||||||
QUrlQuery url_query(url);
|
|
||||||
if (url_query.hasQueryItem("vendor")) {
|
if (url_query.hasQueryItem("vendor")) {
|
||||||
LIBMTP_raw_device_t *raw_device = (LIBMTP_raw_device_t*)malloc(sizeof(LIBMTP_raw_device_t));
|
LIBMTP_raw_device_t *raw_device = (LIBMTP_raw_device_t*)malloc(sizeof(LIBMTP_raw_device_t));
|
||||||
raw_device->device_entry.vendor = url_query.queryItemValue("vendor").toLatin1().data();
|
raw_device->device_entry.vendor = url_query.queryItemValue("vendor").toLatin1().data();
|
||||||
|
|||||||
@@ -61,12 +61,17 @@ MtpDevice::MtpDevice(const QUrl &url, DeviceLister *lister, const QString &uniqu
|
|||||||
|
|
||||||
MtpDevice::~MtpDevice() {}
|
MtpDevice::~MtpDevice() {}
|
||||||
|
|
||||||
void 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)), SIGNAL(Error(QString)));
|
||||||
@@ -77,6 +82,8 @@ void MtpDevice::Init() {
|
|||||||
db_busy_.lock();
|
db_busy_.lock();
|
||||||
loader_thread_->start();
|
loader_thread_->start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MtpDevice::LoadFinished() {
|
void MtpDevice::LoadFinished() {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class MtpDevice : public ConnectedDevice {
|
|||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "mtp" << "gphoto2"; }
|
static QStringList url_schemes() { return QStringList() << "mtp" << "gphoto2"; }
|
||||||
|
|
||||||
void Init();
|
bool Init();
|
||||||
|
|
||||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
||||||
int GetFreeSpace();
|
int GetFreeSpace();
|
||||||
|
|||||||
@@ -40,7 +40,14 @@ MtpLoader::MtpLoader(const QUrl &url, TaskManager *task_manager, CollectionBacke
|
|||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
MtpLoader::~MtpLoader() {}
|
MtpLoader::~MtpLoader() {
|
||||||
|
delete connection_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MtpLoader::Init() {
|
||||||
|
connection_ = new MtpConnection(url_);
|
||||||
|
return connection_->is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
void MtpLoader::LoadDatabase() {
|
void MtpLoader::LoadDatabase() {
|
||||||
|
|
||||||
@@ -58,15 +65,9 @@ void MtpLoader::LoadDatabase() {
|
|||||||
|
|
||||||
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(dev.device(), nullptr, nullptr);
|
LIBMTP_track_t* tracks = LIBMTP_Get_Tracklisting_With_Callback(connection_->device(), nullptr, nullptr);
|
||||||
while (tracks) {
|
while (tracks) {
|
||||||
LIBMTP_track_t *track = tracks;
|
LIBMTP_track_t *track = tracks;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
class TaskManager;
|
class TaskManager;
|
||||||
class CollectionBackend;
|
class CollectionBackend;
|
||||||
class ConnectedDevice;
|
class ConnectedDevice;
|
||||||
|
class MtpConnection;
|
||||||
|
|
||||||
class MtpLoader : public QObject {
|
class MtpLoader : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -42,10 +43,12 @@ class MtpLoader : public QObject {
|
|||||||
MtpLoader(const QUrl &url, TaskManager *task_manager, CollectionBackend *backend, std::shared_ptr<ConnectedDevice> device);
|
MtpLoader(const QUrl &url, TaskManager *task_manager, CollectionBackend *backend, std::shared_ptr<ConnectedDevice> device);
|
||||||
~MtpLoader();
|
~MtpLoader();
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void LoadDatabase();
|
void LoadDatabase();
|
||||||
|
|
||||||
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();
|
||||||
@@ -60,7 +63,7 @@ signals:
|
|||||||
QUrl url_;
|
QUrl url_;
|
||||||
TaskManager *task_manager_;
|
TaskManager *task_manager_;
|
||||||
CollectionBackend *backend_;
|
CollectionBackend *backend_;
|
||||||
|
MtpConnection *connection_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MTPLOADER_H
|
#endif // MTPLOADER_H
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ void Udisks2Lister::UpdateDeviceFreeSpace(const QString &id) {
|
|||||||
emit DeviceChanged(id);
|
emit DeviceChanged(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Udisks2Lister::Init() {
|
bool Udisks2Lister::Init() {
|
||||||
|
|
||||||
udisks2_interface_.reset(new OrgFreedesktopDBusObjectManagerInterface(udisks2_service_, "/org/freedesktop/UDisks2", QDBusConnection::systemBus()));
|
udisks2_interface_.reset(new OrgFreedesktopDBusObjectManagerInterface(udisks2_service_, "/org/freedesktop/UDisks2", QDBusConnection::systemBus()));
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ void Udisks2Lister::Init() {
|
|||||||
if (!reply.isValid()) {
|
if (!reply.isValid()) {
|
||||||
qLog(Warning) << "Error enumerating udisks2 devices:" << reply.error().name() << reply.error().message();
|
qLog(Warning) << "Error enumerating udisks2 devices:" << reply.error().name() << reply.error().message();
|
||||||
udisks2_interface_.reset();
|
udisks2_interface_.reset();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QDBusObjectPath &path : reply.value().keys()) {
|
for (const QDBusObjectPath &path : reply.value().keys()) {
|
||||||
@@ -191,6 +191,8 @@ void Udisks2Lister::Init() {
|
|||||||
connect(udisks2_interface_.get(), SIGNAL(InterfacesAdded(QDBusObjectPath, InterfacesAndProperties)), SLOT(DBusInterfaceAdded(QDBusObjectPath, InterfacesAndProperties)));
|
connect(udisks2_interface_.get(), SIGNAL(InterfacesAdded(QDBusObjectPath, InterfacesAndProperties)), SLOT(DBusInterfaceAdded(QDBusObjectPath, InterfacesAndProperties)));
|
||||||
connect(udisks2_interface_.get(), SIGNAL(InterfacesRemoved(QDBusObjectPath, QStringList)), SLOT(DBusInterfaceRemoved(QDBusObjectPath, QStringList)));
|
connect(udisks2_interface_.get(), SIGNAL(InterfacesRemoved(QDBusObjectPath, QStringList)), SLOT(DBusInterfaceRemoved(QDBusObjectPath, QStringList)));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Udisks2Lister::DBusInterfaceAdded(const QDBusObjectPath &path, const InterfacesAndProperties &interfaces) {
|
void Udisks2Lister::DBusInterfaceAdded(const QDBusObjectPath &path, const InterfacesAndProperties &interfaces) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Udisks2Lister : public DeviceLister {
|
|||||||
void UpdateDeviceFreeSpace(const QString &id) override;
|
void UpdateDeviceFreeSpace(const QString &id) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init() override;
|
bool Init() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void DBusInterfaceAdded(const QDBusObjectPath &path, const InterfacesAndProperties &ifaces);
|
void DBusInterfaceAdded(const QDBusObjectPath &path, const InterfacesAndProperties &ifaces);
|
||||||
|
|||||||
Reference in New Issue
Block a user