2010-06-26 00:01:47 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-06-26 00:01:47 +02:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-07-04 22:52:45 +02:00
|
|
|
#include "config.h"
|
2010-07-04 01:00:07 +02:00
|
|
|
#include "devicedatabasebackend.h"
|
2010-06-26 00:36:21 +02:00
|
|
|
#include "devicekitlister.h"
|
2010-07-24 20:31:05 +02:00
|
|
|
#include "devicemanager.h"
|
|
|
|
#include "devicestatefiltermodel.h"
|
2010-07-17 16:22:07 +02:00
|
|
|
#include "filesystemdevice.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/application.h"
|
2012-06-29 16:56:17 +02:00
|
|
|
#include "core/concurrentrun.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/database.h"
|
2011-04-22 18:50:29 +02:00
|
|
|
#include "core/logging.h"
|
2010-07-19 23:16:22 +02:00
|
|
|
#include "core/musicstorage.h"
|
2010-07-04 17:56:08 +02:00
|
|
|
#include "core/taskmanager.h"
|
2010-07-03 23:05:55 +02:00
|
|
|
#include "core/utilities.h"
|
|
|
|
#include "ui/iconloader.h"
|
2010-06-26 00:01:47 +02:00
|
|
|
|
2011-08-10 17:23:32 +02:00
|
|
|
#ifdef HAVE_AUDIOCD
|
|
|
|
# include "cddalister.h"
|
|
|
|
# include "cddadevice.h"
|
|
|
|
#endif
|
2011-08-05 02:15:16 +02:00
|
|
|
|
2010-07-23 15:46:30 +02:00
|
|
|
#ifdef Q_OS_DARWIN
|
2010-07-24 19:53:40 +02:00
|
|
|
# include "macdevicelister.h"
|
|
|
|
#endif
|
2010-08-15 00:43:19 +02:00
|
|
|
#ifdef Q_OS_WIN32
|
2012-01-15 16:32:04 +01:00
|
|
|
# ifdef HAVE_SAC
|
|
|
|
# include "wmdmlister.h"
|
|
|
|
# include "wmdmdevice.h"
|
|
|
|
# endif
|
2010-08-15 00:43:19 +02:00
|
|
|
#endif
|
2010-07-24 19:53:40 +02:00
|
|
|
#ifdef HAVE_LIBGPOD
|
|
|
|
# include "gpoddevice.h"
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_GIO
|
|
|
|
# include "giolister.h"
|
2010-07-23 15:46:30 +02:00
|
|
|
#endif
|
2010-07-30 23:10:34 +02:00
|
|
|
#ifdef HAVE_IMOBILEDEVICE
|
2010-08-01 16:13:27 +02:00
|
|
|
# include "afcdevice.h"
|
2010-07-30 23:10:34 +02:00
|
|
|
# include "ilister.h"
|
|
|
|
#endif
|
2010-08-14 17:57:05 +02:00
|
|
|
#ifdef HAVE_LIBMTP
|
|
|
|
# include "mtpdevice.h"
|
|
|
|
#endif
|
2010-07-23 15:46:30 +02:00
|
|
|
|
2012-06-29 17:06:47 +02:00
|
|
|
#include <QApplication>
|
2010-08-28 21:07:23 +02:00
|
|
|
#include <QDir>
|
2010-07-03 23:05:55 +02:00
|
|
|
#include <QIcon>
|
2010-08-14 14:30:51 +02:00
|
|
|
#include <QMessageBox>
|
2010-07-04 13:34:25 +02:00
|
|
|
#include <QPainter>
|
2010-08-14 14:30:51 +02:00
|
|
|
#include <QPushButton>
|
2010-07-19 21:56:29 +02:00
|
|
|
#include <QSortFilterProxyModel>
|
2010-07-17 16:22:07 +02:00
|
|
|
#include <QUrl>
|
2010-07-03 23:05:55 +02:00
|
|
|
|
2012-06-29 16:56:17 +02:00
|
|
|
#include <tr1/functional>
|
|
|
|
using std::tr1::bind;
|
|
|
|
|
2010-07-04 13:34:25 +02:00
|
|
|
const int DeviceManager::kDeviceIconSize = 32;
|
|
|
|
const int DeviceManager::kDeviceIconOverlaySize = 16;
|
2010-07-03 23:05:55 +02:00
|
|
|
|
2010-07-19 21:56:29 +02:00
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
DeviceManager::DeviceInfo::DeviceInfo()
|
|
|
|
: database_id_(-1),
|
2010-08-29 21:22:21 +02:00
|
|
|
transcode_mode_(MusicStorage::Transcode_Unsupported),
|
2010-08-29 18:12:55 +02:00
|
|
|
transcode_format_(Song::Type_Unknown),
|
2010-07-04 17:56:08 +02:00
|
|
|
task_percentage_(-1)
|
2010-07-03 23:05:55 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-07-04 01:00:07 +02:00
|
|
|
DeviceDatabaseBackend::Device DeviceManager::DeviceInfo::SaveToDb() const {
|
|
|
|
DeviceDatabaseBackend::Device ret;
|
|
|
|
ret.friendly_name_ = friendly_name_;
|
|
|
|
ret.size_ = size_;
|
|
|
|
ret.id_ = database_id_;
|
2010-07-17 19:18:02 +02:00
|
|
|
ret.icon_name_ = icon_name_;
|
2010-08-29 17:32:36 +02:00
|
|
|
ret.transcode_mode_ = transcode_mode_;
|
|
|
|
ret.transcode_format_ = transcode_format_;
|
2010-07-04 01:00:07 +02:00
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
QStringList unique_ids;
|
|
|
|
foreach (const Backend& backend, backends_) {
|
|
|
|
unique_ids << backend.unique_id_;
|
|
|
|
}
|
|
|
|
ret.unique_id_ = unique_ids.join(",");
|
2010-07-04 01:00:07 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:32:36 +02:00
|
|
|
void DeviceManager::DeviceInfo::InitFromDb(const DeviceDatabaseBackend::Device& dev) {
|
2010-07-04 01:00:07 +02:00
|
|
|
database_id_ = dev.id_;
|
|
|
|
friendly_name_ = dev.friendly_name_;
|
|
|
|
size_ = dev.size_;
|
2010-08-29 17:32:36 +02:00
|
|
|
transcode_mode_ = dev.transcode_mode_;
|
|
|
|
transcode_format_ = dev.transcode_format_;
|
2010-08-16 01:26:04 +02:00
|
|
|
|
|
|
|
QStringList icon_names = dev.icon_name_.split(',');
|
|
|
|
QVariantList icons;
|
|
|
|
foreach (const QString& icon_name, icon_names) {
|
|
|
|
icons << icon_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoadIcon(icons, friendly_name_);
|
2010-07-17 19:18:02 +02:00
|
|
|
|
|
|
|
QStringList unique_ids = dev.unique_id_.split(',');
|
|
|
|
foreach (const QString& id, unique_ids) {
|
|
|
|
backends_ << Backend(NULL, id);
|
|
|
|
}
|
2010-07-04 01:00:07 +02:00
|
|
|
}
|
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
void DeviceManager::DeviceInfo::LoadIcon(const QVariantList& icons, const QString& name_hint) {
|
2010-07-17 19:18:02 +02:00
|
|
|
if (icons.isEmpty()) {
|
|
|
|
icon_name_ = "drive-removable-media-usb-pendrive";
|
|
|
|
icon_ = IconLoader::Load(icon_name_);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-04 01:00:07 +02:00
|
|
|
// Try to load the icon with that exact name first
|
2010-08-16 01:26:04 +02:00
|
|
|
foreach (const QVariant& icon, icons) {
|
|
|
|
if (!icon.value<QPixmap>().isNull()) {
|
|
|
|
icon_ = QIcon(icon.value<QPixmap>());
|
2010-07-17 19:18:02 +02:00
|
|
|
return;
|
2010-08-16 01:26:04 +02:00
|
|
|
} else {
|
|
|
|
icon_ = IconLoader::Load(icon.toString());
|
|
|
|
if (!icon_.isNull()) {
|
|
|
|
icon_name_ = icon.toString();
|
|
|
|
return;
|
|
|
|
}
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
QString hint = QString(icons.first().toString() + name_hint).toLower();
|
2010-07-04 01:00:07 +02:00
|
|
|
|
|
|
|
// If that failed than try to guess if it's a phone or ipod. Fall back on
|
|
|
|
// a usb memory stick icon.
|
2010-07-17 23:48:09 +02:00
|
|
|
if (hint.contains("phone"))
|
2010-07-17 19:18:02 +02:00
|
|
|
icon_name_ = "phone";
|
2010-07-17 23:48:09 +02:00
|
|
|
else if (hint.contains("ipod") || hint.contains("apple"))
|
2010-07-17 19:18:02 +02:00
|
|
|
icon_name_ = "multimedia-player-ipod-standard-monochrome";
|
|
|
|
else
|
|
|
|
icon_name_ = "drive-removable-media-usb-pendrive";
|
|
|
|
icon_ = IconLoader::Load(icon_name_);
|
|
|
|
}
|
|
|
|
|
|
|
|
const DeviceManager::DeviceInfo::Backend* DeviceManager::DeviceInfo::BestBackend() const {
|
|
|
|
int best_priority = -1;
|
|
|
|
const Backend* ret = NULL;
|
|
|
|
|
|
|
|
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]);
|
|
|
|
}
|
2010-07-04 01:00:07 +02:00
|
|
|
}
|
2010-07-17 19:18:02 +02:00
|
|
|
|
|
|
|
if (!ret && !backends_.isEmpty())
|
|
|
|
return &(backends_[0]);
|
|
|
|
return ret;
|
2010-07-04 01:00:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
DeviceManager::DeviceManager(Application* app, QObject *parent)
|
2010-07-03 23:05:55 +02:00
|
|
|
: QAbstractListModel(parent),
|
2012-02-12 14:41:50 +01:00
|
|
|
app_(app),
|
2010-07-04 13:34:25 +02:00
|
|
|
not_connected_overlay_(IconLoader::Load("edit-delete"))
|
2010-06-26 00:01:47 +02:00
|
|
|
{
|
2012-06-29 16:58:30 +02:00
|
|
|
thread_pool_.setMaxThreadCount(1);
|
2012-02-12 14:41:50 +01:00
|
|
|
connect(app_->task_manager(), SIGNAL(TasksChanged()), SLOT(TasksChanged()));
|
2010-07-04 17:56:08 +02:00
|
|
|
|
2010-07-04 01:00:07 +02:00
|
|
|
// Create the backend in the database thread
|
2010-08-27 20:36:57 +02:00
|
|
|
backend_ = new DeviceDatabaseBackend;
|
2012-02-12 14:41:50 +01:00
|
|
|
backend_->moveToThread(app_->database()->thread());
|
|
|
|
backend_->Init(app_->database());
|
2010-07-04 01:00:07 +02:00
|
|
|
|
2012-06-29 16:56:17 +02:00
|
|
|
// This reads from the database and contends on the database mutex, which can
|
|
|
|
// be very slow on startup.
|
2012-07-16 00:06:55 +02:00
|
|
|
ConcurrentRun::Run<void>(&thread_pool_, bind(&DeviceManager::LoadAllDevices, this));
|
2010-07-04 01:00:07 +02:00
|
|
|
|
2010-07-19 21:56:29 +02:00
|
|
|
// This proxy model only shows connected devices
|
|
|
|
connected_devices_model_ = new DeviceStateFilterModel(this);
|
|
|
|
connected_devices_model_->setSourceModel(this);
|
|
|
|
|
2011-08-11 21:37:09 +02:00
|
|
|
// CD devices are detected via the DiskArbitration framework instead on Darwin.
|
2011-08-11 21:46:48 +02:00
|
|
|
#if defined(HAVE_AUDIOCD) && !defined(Q_OS_DARWIN)
|
2011-08-05 02:15:16 +02:00
|
|
|
AddLister(new CddaLister);
|
2011-08-11 21:37:09 +02:00
|
|
|
#endif
|
2010-12-26 14:38:35 +01:00
|
|
|
#ifdef HAVE_DEVICEKIT
|
2010-06-26 14:41:18 +02:00
|
|
|
AddLister(new DeviceKitLister);
|
2010-06-26 14:57:00 +02:00
|
|
|
#endif
|
2010-07-17 16:22:07 +02:00
|
|
|
#ifdef HAVE_GIO
|
|
|
|
AddLister(new GioLister);
|
|
|
|
#endif
|
2010-07-23 15:46:30 +02:00
|
|
|
#ifdef Q_OS_DARWIN
|
|
|
|
AddLister(new MacDeviceLister);
|
|
|
|
#endif
|
2012-01-15 16:32:04 +01:00
|
|
|
#if defined(Q_OS_WIN32) && defined(HAVE_SAC)
|
2010-08-15 20:08:09 +02:00
|
|
|
AddLister(new WmdmLister);
|
2010-08-22 21:18:22 +02:00
|
|
|
AddDeviceClass<WmdmDevice>();
|
2010-08-15 00:43:19 +02:00
|
|
|
#endif
|
2010-07-30 23:10:34 +02:00
|
|
|
#ifdef HAVE_IMOBILEDEVICE
|
|
|
|
AddLister(new iLister);
|
2010-08-01 16:13:27 +02:00
|
|
|
AddDeviceClass<AfcDevice>();
|
2010-07-30 23:10:34 +02:00
|
|
|
#endif
|
2010-07-17 16:22:07 +02:00
|
|
|
|
|
|
|
AddDeviceClass<FilesystemDevice>();
|
|
|
|
|
2011-08-10 17:23:32 +02:00
|
|
|
#ifdef HAVE_AUDIOCD
|
|
|
|
AddDeviceClass<CddaDevice>();
|
|
|
|
#endif
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
#ifdef HAVE_LIBGPOD
|
|
|
|
AddDeviceClass<GPodDevice>();
|
|
|
|
#endif
|
2010-08-14 17:57:05 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_LIBMTP
|
|
|
|
AddDeviceClass<MtpDevice>();
|
|
|
|
#endif
|
2010-06-26 14:41:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DeviceManager::~DeviceManager() {
|
2010-08-22 17:42:21 +02:00
|
|
|
foreach (DeviceLister* lister, listers_) {
|
2010-08-23 12:26:00 +02:00
|
|
|
lister->ShutDown();
|
2010-08-22 17:42:21 +02:00
|
|
|
delete lister;
|
|
|
|
}
|
|
|
|
|
2010-07-04 01:00:07 +02:00
|
|
|
backend_->deleteLater();
|
2010-06-26 14:41:18 +02:00
|
|
|
}
|
|
|
|
|
2012-06-29 16:56:17 +02:00
|
|
|
void DeviceManager::LoadAllDevices() {
|
|
|
|
Q_ASSERT(QThread::currentThread() != qApp->thread());
|
|
|
|
DeviceDatabaseBackend::DeviceList devices = backend_->GetAllDevices();
|
|
|
|
foreach (const DeviceDatabaseBackend::Device& device, devices) {
|
|
|
|
DeviceInfo info;
|
|
|
|
info.InitFromDb(device);
|
|
|
|
devices_ << info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
int DeviceManager::rowCount(const QModelIndex&) const {
|
|
|
|
return devices_.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant DeviceManager::data(const QModelIndex& index, int role) const {
|
|
|
|
if (!index.isValid() || index.column() != 0)
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[index.row()];
|
|
|
|
|
|
|
|
switch (role) {
|
2010-07-04 13:34:25 +02:00
|
|
|
case Qt::DisplayRole: {
|
2010-07-17 19:18:02 +02:00
|
|
|
QString text;
|
|
|
|
if (!info.friendly_name_.isEmpty())
|
|
|
|
text = info.friendly_name_;
|
|
|
|
else
|
|
|
|
text = info.BestBackend()->unique_id_;
|
|
|
|
|
2010-07-04 13:34:25 +02:00
|
|
|
if (info.size_)
|
|
|
|
text = text + QString(" (%1)").arg(Utilities::PrettySize(info.size_));
|
2011-08-05 02:15:16 +02:00
|
|
|
if (info.device_.get())
|
|
|
|
info.device_->Refresh();
|
2010-07-04 13:34:25 +02:00
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Qt::DecorationRole: {
|
|
|
|
QPixmap pixmap = info.icon_.pixmap(kDeviceIconSize);
|
|
|
|
|
2011-08-05 09:20:04 +02:00
|
|
|
if (info.backends_.isEmpty() || !info.BestBackend()->lister_) {
|
2010-07-04 13:34:25 +02:00
|
|
|
// Disconnected but remembered
|
|
|
|
QPainter p(&pixmap);
|
|
|
|
p.drawPixmap(kDeviceIconSize - kDeviceIconOverlaySize,
|
|
|
|
kDeviceIconSize - kDeviceIconOverlaySize,
|
|
|
|
not_connected_overlay_.pixmap(kDeviceIconOverlaySize));
|
|
|
|
}
|
|
|
|
|
|
|
|
return pixmap;
|
|
|
|
}
|
|
|
|
|
2010-07-04 17:01:24 +02:00
|
|
|
case Role_FriendlyName:
|
|
|
|
return info.friendly_name_;
|
2010-07-04 13:34:25 +02:00
|
|
|
|
|
|
|
case Role_UniqueId:
|
2010-07-17 19:18:02 +02:00
|
|
|
return info.BestBackend()->unique_id_;
|
2010-07-04 13:34:25 +02:00
|
|
|
|
2010-07-04 17:01:24 +02:00
|
|
|
case Role_IconName:
|
|
|
|
return info.icon_name_;
|
|
|
|
|
|
|
|
case Role_Capacity:
|
2010-07-30 00:16:12 +02:00
|
|
|
case MusicStorage::Role_Capacity:
|
2010-07-04 17:01:24 +02:00
|
|
|
return info.size_;
|
|
|
|
|
2010-07-18 00:06:19 +02:00
|
|
|
case Role_FreeSpace:
|
2010-07-30 00:16:12 +02:00
|
|
|
case MusicStorage::Role_FreeSpace:
|
2010-07-18 00:06:19 +02:00
|
|
|
return info.BestBackend()->lister_ ?
|
|
|
|
info.BestBackend()->lister_->DeviceFreeSpace(info.BestBackend()->unique_id_) :
|
|
|
|
QVariant();
|
|
|
|
|
2010-07-04 13:34:25 +02:00
|
|
|
case Role_State:
|
|
|
|
if (info.device_)
|
|
|
|
return State_Connected;
|
2010-09-11 14:29:44 +02:00
|
|
|
if (info.BestBackend()->lister_) {
|
|
|
|
if (info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_))
|
|
|
|
return State_NotMounted;
|
2010-07-04 13:34:25 +02:00
|
|
|
return State_NotConnected;
|
2010-09-11 14:29:44 +02:00
|
|
|
}
|
2010-07-04 13:34:25 +02:00
|
|
|
return State_Remembered;
|
|
|
|
|
2010-07-04 17:56:08 +02:00
|
|
|
case Role_UpdatingPercentage:
|
|
|
|
if (info.task_percentage_ == -1)
|
|
|
|
return QVariant();
|
|
|
|
return info.task_percentage_;
|
|
|
|
|
2010-07-30 00:16:12 +02:00
|
|
|
case MusicStorage::Role_Storage:
|
2010-08-14 14:30:51 +02:00
|
|
|
if (!info.device_ && info.database_id_ != -1)
|
|
|
|
const_cast<DeviceManager*>(this)->Connect(index.row());
|
2010-07-25 11:27:41 +02:00
|
|
|
if (!info.device_)
|
2010-08-14 14:30:51 +02:00
|
|
|
return QVariant();
|
|
|
|
return QVariant::fromValue<boost::shared_ptr<MusicStorage> >(info.device_);
|
|
|
|
|
|
|
|
case MusicStorage::Role_StorageForceConnect:
|
|
|
|
if (!info.device_) {
|
2010-09-11 14:29:44 +02:00
|
|
|
if (info.database_id_ == -1 &&
|
|
|
|
!info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) {
|
2011-08-10 17:23:32 +02:00
|
|
|
|
2011-08-11 22:10:14 +02:00
|
|
|
if (info.BestBackend()->lister_->AskForScan(info.BestBackend()->unique_id_)) {
|
2011-08-05 02:15:16 +02:00
|
|
|
boost::scoped_ptr<QMessageBox> dialog(new QMessageBox(
|
|
|
|
QMessageBox::Information, tr("Connect device"),
|
|
|
|
tr("This is the first time you have connected this device. Clementine 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);
|
|
|
|
dialog->exec();
|
|
|
|
|
|
|
|
if (dialog->clickedButton() != connect)
|
|
|
|
return QVariant();
|
|
|
|
}
|
2010-08-14 14:30:51 +02:00
|
|
|
}
|
|
|
|
|
2010-07-25 11:27:41 +02:00
|
|
|
const_cast<DeviceManager*>(this)->Connect(index.row());
|
2010-08-14 14:30:51 +02:00
|
|
|
}
|
2010-07-25 11:27:41 +02:00
|
|
|
if (!info.device_)
|
|
|
|
return QVariant();
|
2010-08-09 23:50:46 +02:00
|
|
|
return QVariant::fromValue<boost::shared_ptr<MusicStorage> >(info.device_);
|
2010-07-19 23:16:22 +02:00
|
|
|
|
2010-08-28 21:07:23 +02:00
|
|
|
case Role_MountPath: {
|
2010-07-25 11:27:41 +02:00
|
|
|
if (!info.device_)
|
|
|
|
return QVariant();
|
2010-08-28 21:07:23 +02:00
|
|
|
|
|
|
|
QString ret = info.device_->url().path();
|
|
|
|
# ifdef Q_OS_WIN32
|
|
|
|
if (ret.startsWith('/'))
|
|
|
|
ret.remove(0, 1);
|
|
|
|
# endif
|
|
|
|
return QDir::toNativeSeparators(ret);
|
|
|
|
}
|
2010-07-25 01:20:34 +02:00
|
|
|
|
2010-08-29 17:32:36 +02:00
|
|
|
case Role_TranscodeMode:
|
|
|
|
return info.transcode_mode_;
|
|
|
|
|
|
|
|
case Role_TranscodeFormat:
|
|
|
|
return info.transcode_format_;
|
|
|
|
|
2010-08-30 16:45:27 +02:00
|
|
|
case Role_SongCount:
|
|
|
|
if (!info.device_)
|
|
|
|
return QVariant();
|
|
|
|
return info.device_->song_count();
|
|
|
|
|
2010-07-04 13:34:25 +02:00
|
|
|
default:
|
|
|
|
return QVariant();
|
2010-07-03 23:05:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-26 14:41:18 +02:00
|
|
|
void DeviceManager::AddLister(DeviceLister *lister) {
|
2010-06-26 00:36:21 +02:00
|
|
|
listers_ << lister;
|
2010-07-03 23:05:55 +02:00
|
|
|
connect(lister, SIGNAL(DeviceAdded(QString)), SLOT(PhysicalDeviceAdded(QString)));
|
|
|
|
connect(lister, SIGNAL(DeviceRemoved(QString)), SLOT(PhysicalDeviceRemoved(QString)));
|
|
|
|
connect(lister, SIGNAL(DeviceChanged(QString)), SLOT(PhysicalDeviceChanged(QString)));
|
2010-06-26 00:01:47 +02:00
|
|
|
|
2010-06-26 00:36:21 +02:00
|
|
|
lister->Start();
|
2010-06-26 00:01:47 +02:00
|
|
|
}
|
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
int DeviceManager::FindDeviceById(const QString &id) const {
|
|
|
|
for (int i=0 ; i<devices_.count() ; ++i) {
|
2010-07-17 19:18:02 +02:00
|
|
|
foreach (const DeviceInfo::Backend& backend, devices_[i].backends_) {
|
|
|
|
if (backend.unique_id_ == id)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-08-01 13:55:01 +02:00
|
|
|
int DeviceManager::FindDeviceByUrl(const QList<QUrl>& urls) const {
|
|
|
|
if (urls.isEmpty())
|
2010-07-17 19:18:02 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (int i=0 ; i<devices_.count() ; ++i) {
|
|
|
|
foreach (const DeviceInfo::Backend& backend, devices_[i].backends_) {
|
2010-08-01 13:55:01 +02:00
|
|
|
if (!backend.lister_)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QList<QUrl> device_urls = backend.lister_->MakeDeviceUrls(backend.unique_id_);
|
|
|
|
foreach (const QUrl& url, device_urls) {
|
|
|
|
if (urls.contains(url))
|
|
|
|
return i;
|
|
|
|
}
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
2010-07-03 23:05:55 +02:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceManager::PhysicalDeviceAdded(const QString &id) {
|
2010-06-26 14:41:18 +02:00
|
|
|
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
|
2010-06-26 00:01:47 +02:00
|
|
|
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Info) << "Device added:" << id;
|
2010-06-26 14:41:18 +02:00
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
// Do we have this device already?
|
|
|
|
int i = FindDeviceById(id);
|
2010-07-17 19:18:02 +02:00
|
|
|
if (i != -1) {
|
2010-07-03 23:05:55 +02:00
|
|
|
DeviceInfo& info = devices_[i];
|
2010-07-17 19:18:02 +02:00
|
|
|
for (int backend_index = 0 ; backend_index < info.backends_.count() ; ++backend_index) {
|
|
|
|
if (info.backends_[backend_index].unique_id_ == id) {
|
|
|
|
info.backends_[backend_index].lister_ = lister;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-07-03 23:05:55 +02:00
|
|
|
|
2010-07-04 13:43:17 +02:00
|
|
|
emit dataChanged(index(i, 0), index(i, 0));
|
2010-07-17 19:18:02 +02:00
|
|
|
} else {
|
|
|
|
// Check if we have another device with the same URL
|
2010-08-01 13:55:01 +02:00
|
|
|
i = FindDeviceByUrl(lister->MakeDeviceUrls(id));
|
2010-07-17 19:18:02 +02:00
|
|
|
if (i != -1) {
|
|
|
|
// Add this device's lister to the existing device
|
|
|
|
DeviceInfo& info = devices_[i];
|
|
|
|
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 (info.database_id_ == -1 && info.BestBackend()->lister_ == lister) {
|
|
|
|
info.friendly_name_ = lister->MakeFriendlyName(id);
|
|
|
|
info.size_ = lister->DeviceCapacity(id);
|
2010-07-17 23:48:09 +02:00
|
|
|
info.LoadIcon(lister->DeviceIcons(id), info.friendly_name_);
|
2010-07-17 19:18:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
emit dataChanged(index(i, 0), index(i, 0));
|
|
|
|
} else {
|
|
|
|
// It's a completely new device
|
|
|
|
DeviceInfo info;
|
|
|
|
info.backends_ << DeviceInfo::Backend(lister, id);
|
|
|
|
info.friendly_name_ = lister->MakeFriendlyName(id);
|
|
|
|
info.size_ = lister->DeviceCapacity(id);
|
2010-07-17 23:48:09 +02:00
|
|
|
info.LoadIcon(lister->DeviceIcons(id), info.friendly_name_);
|
2010-07-17 19:18:02 +02:00
|
|
|
|
|
|
|
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
|
|
|
devices_ << info;
|
|
|
|
endInsertRows();
|
|
|
|
}
|
2010-07-03 23:05:55 +02:00
|
|
|
}
|
2010-06-26 00:01:47 +02:00
|
|
|
}
|
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
void DeviceManager::PhysicalDeviceRemoved(const QString &id) {
|
2010-07-17 19:18:02 +02:00
|
|
|
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
|
|
|
|
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Info) << "Device removed:" << id;
|
2010-07-03 23:05:55 +02:00
|
|
|
|
|
|
|
int i = FindDeviceById(id);
|
|
|
|
if (i == -1) {
|
|
|
|
// Shouldn't happen
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceInfo& info = devices_[i];
|
|
|
|
|
|
|
|
if (info.database_id_ != -1) {
|
|
|
|
// Keep the structure around, but just "disconnect" it
|
2010-07-24 21:41:30 +02:00
|
|
|
for (int backend_index = 0 ; backend_index < info.backends_.count() ; ++backend_index) {
|
|
|
|
if (info.backends_[backend_index].unique_id_ == id) {
|
|
|
|
info.backends_[backend_index].lister_ = NULL;
|
2010-07-17 19:18:02 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.device_ && info.device_->lister() == lister)
|
|
|
|
info.device_.reset();
|
2010-07-03 23:05:55 +02:00
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
if (!info.device_)
|
|
|
|
emit DeviceDisconnected(i);
|
2010-09-18 15:54:23 +02:00
|
|
|
|
|
|
|
emit dataChanged(index(i, 0), index(i, 0));
|
2010-07-17 19:18:02 +02:00
|
|
|
} else {
|
|
|
|
// 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) {
|
|
|
|
if (info.backends_[backend_index].unique_id_ == id) {
|
|
|
|
info.backends_.removeAt(backend_index);
|
|
|
|
break;
|
|
|
|
}
|
2010-07-04 17:01:24 +02:00
|
|
|
}
|
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
if (info.backends_.isEmpty()) {
|
|
|
|
beginRemoveRows(QModelIndex(), i, i);
|
|
|
|
devices_.removeAt(i);
|
|
|
|
|
|
|
|
foreach (const QModelIndex& idx, persistentIndexList()) {
|
|
|
|
if (idx.row() == i)
|
|
|
|
changePersistentIndex(idx, QModelIndex());
|
|
|
|
else if (idx.row() > i)
|
|
|
|
changePersistentIndex(idx, index(idx.row()-1, idx.column()));
|
|
|
|
}
|
|
|
|
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
2010-06-26 14:41:18 +02:00
|
|
|
}
|
2010-06-26 00:01:47 +02:00
|
|
|
}
|
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
void DeviceManager::PhysicalDeviceChanged(const QString &id) {
|
2010-06-26 14:41:18 +02:00
|
|
|
DeviceLister* lister = qobject_cast<DeviceLister*>(sender());
|
2010-07-04 13:46:42 +02:00
|
|
|
Q_UNUSED(lister);
|
2010-06-26 00:01:47 +02:00
|
|
|
|
2010-07-03 23:05:55 +02:00
|
|
|
int i = FindDeviceById(id);
|
|
|
|
if (i == -1) {
|
|
|
|
// Shouldn't happen
|
|
|
|
return;
|
2010-06-26 00:01:47 +02:00
|
|
|
}
|
2010-07-03 23:05:55 +02:00
|
|
|
|
|
|
|
// TODO
|
2010-06-26 00:01:47 +02:00
|
|
|
}
|
2010-07-04 01:00:07 +02:00
|
|
|
|
|
|
|
boost::shared_ptr<ConnectedDevice> DeviceManager::Connect(int row) {
|
|
|
|
DeviceInfo& info = devices_[row];
|
|
|
|
if (info.device_) // Already connected
|
|
|
|
return info.device_;
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
boost::shared_ptr<ConnectedDevice> ret;
|
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
if (!info.BestBackend()->lister_) // Not physically connected
|
2010-07-17 16:22:07 +02:00
|
|
|
return ret;
|
2010-07-04 01:00:07 +02:00
|
|
|
|
2010-09-11 14:29:44 +02:00
|
|
|
if (info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) {
|
|
|
|
// Mount the device
|
|
|
|
info.BestBackend()->lister_->MountDevice(info.BestBackend()->unique_id_);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-07-04 01:00:07 +02:00
|
|
|
bool first_time = (info.database_id_ == -1);
|
|
|
|
if (first_time) {
|
|
|
|
// We haven't stored this device in the database before
|
|
|
|
info.database_id_ = backend_->AddDevice(info.SaveToDb());
|
|
|
|
}
|
|
|
|
|
2010-08-01 13:55:01 +02:00
|
|
|
// Get the device URLs
|
|
|
|
QList<QUrl> urls = info.BestBackend()->lister_->MakeDeviceUrls(
|
|
|
|
info.BestBackend()->unique_id_);
|
|
|
|
if (urls.isEmpty())
|
2010-07-17 16:22:07 +02:00
|
|
|
return ret;
|
|
|
|
|
2010-08-01 13:55:01 +02:00
|
|
|
// Take the first URL that we have a handler for
|
|
|
|
QUrl device_url;
|
|
|
|
foreach (const QUrl& url, urls) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Info) << "Connecting" << url;
|
2010-08-01 13:55:01 +02:00
|
|
|
|
|
|
|
// Find a device class for this URL's scheme
|
|
|
|
if (device_classes_.contains(url.scheme())) {
|
|
|
|
device_url = url;
|
2010-08-14 17:57:05 +02:00
|
|
|
break;
|
2010-08-01 13:55:01 +02:00
|
|
|
}
|
2010-09-04 14:57:34 +02:00
|
|
|
|
|
|
|
// If we get here it means that this URL scheme wasn't supported. If it
|
|
|
|
// was "ipod" or "mtp" then the user compiled out support and the device
|
|
|
|
// won't work properly.
|
|
|
|
if (url.scheme() == "mtp" || url.scheme() == "gphoto2") {
|
|
|
|
if (QMessageBox::critical(NULL, tr("This device will not work properly"),
|
|
|
|
tr("This is an MTP device, but you compiled Clementine without libmtp support.") + " " +
|
|
|
|
tr("If you continue, this device will work slowly and songs copied to it may not work."),
|
|
|
|
QMessageBox::Abort, QMessageBox::Ignore) == QMessageBox::Abort)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (url.scheme() == "ipod") {
|
|
|
|
if (QMessageBox::critical(NULL, tr("This device will not work properly"),
|
|
|
|
tr("This is an iPod, but you compiled Clementine without libgpod support.") + " " +
|
|
|
|
tr("If you continue, this device will work slowly and songs copied to it may not work."),
|
|
|
|
QMessageBox::Abort, QMessageBox::Ignore) == QMessageBox::Abort)
|
|
|
|
return ret;
|
|
|
|
}
|
2010-08-01 13:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (device_url.isEmpty()) {
|
|
|
|
// Munge the URL list into a string list
|
|
|
|
QStringList url_strings;
|
|
|
|
foreach (const QUrl& url, urls) { url_strings << url.toString(); }
|
2010-07-17 19:18:02 +02:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->AddError(tr("This type of device is not supported: %1").arg(url_strings.join(", ")));
|
2010-07-17 16:22:07 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-01 13:55:01 +02:00
|
|
|
QMetaObject meta_object = device_classes_.value(device_url.scheme());
|
2010-07-17 16:22:07 +02:00
|
|
|
QObject* instance = meta_object.newInstance(
|
2010-08-01 13:55:01 +02:00
|
|
|
Q_ARG(QUrl, device_url), Q_ARG(DeviceLister*, info.BestBackend()->lister_),
|
2010-07-17 19:18:02 +02:00
|
|
|
Q_ARG(QString, info.BestBackend()->unique_id_), Q_ARG(DeviceManager*, this),
|
2012-02-26 16:59:39 +01:00
|
|
|
Q_ARG(Application*, app_),
|
2010-07-17 16:22:07 +02:00
|
|
|
Q_ARG(int, info.database_id_), Q_ARG(bool, first_time));
|
|
|
|
ret.reset(static_cast<ConnectedDevice*>(instance));
|
|
|
|
|
|
|
|
if (!ret) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << "Could not create device for" << device_url.toString();
|
2010-07-17 16:22:07 +02:00
|
|
|
} else {
|
2010-08-08 19:41:06 +02:00
|
|
|
ret->Init();
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
info.device_ = ret;
|
2010-07-19 23:16:22 +02:00
|
|
|
emit dataChanged(index(row), index(row));
|
2010-07-17 16:22:07 +02:00
|
|
|
connect(info.device_.get(), SIGNAL(TaskStarted(int)), SLOT(DeviceTaskStarted(int)));
|
2010-08-30 16:45:27 +02:00
|
|
|
connect(info.device_.get(), SIGNAL(SongCountUpdated(int)), SLOT(DeviceSongCountUpdated(int)));
|
2010-07-17 16:22:07 +02:00
|
|
|
}
|
2010-07-04 17:56:08 +02:00
|
|
|
|
2010-07-25 11:27:41 +02:00
|
|
|
emit DeviceConnected(row);
|
|
|
|
|
2010-07-17 16:22:07 +02:00
|
|
|
return ret;
|
2010-07-04 01:00:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<ConnectedDevice> DeviceManager::GetConnectedDevice(int row) const {
|
|
|
|
return devices_[row].device_;
|
|
|
|
}
|
2010-07-04 02:33:34 +02:00
|
|
|
|
2010-07-04 14:56:49 +02:00
|
|
|
int DeviceManager::GetDatabaseId(int row) const {
|
|
|
|
return devices_[row].database_id_;
|
|
|
|
}
|
|
|
|
|
2010-07-04 17:01:24 +02:00
|
|
|
DeviceLister* DeviceManager::GetLister(int row) const {
|
2010-07-17 19:18:02 +02:00
|
|
|
return devices_[row].BestBackend()->lister_;
|
2010-07-04 17:01:24 +02:00
|
|
|
}
|
|
|
|
|
2010-07-04 02:33:34 +02:00
|
|
|
void DeviceManager::Disconnect(int row) {
|
|
|
|
DeviceInfo& info = devices_[row];
|
|
|
|
if (!info.device_) // Already disconnected
|
|
|
|
return;
|
|
|
|
|
|
|
|
info.device_.reset();
|
|
|
|
emit DeviceDisconnected(row);
|
2010-07-24 22:31:09 +02:00
|
|
|
emit dataChanged(index(row), index(row));
|
2010-07-04 02:33:34 +02:00
|
|
|
}
|
2010-07-04 14:56:49 +02:00
|
|
|
|
|
|
|
void DeviceManager::Forget(int row) {
|
|
|
|
DeviceInfo& info = devices_[row];
|
|
|
|
if (info.database_id_ == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (info.device_)
|
|
|
|
Disconnect(row);
|
|
|
|
|
|
|
|
backend_->RemoveDevice(info.database_id_);
|
|
|
|
info.database_id_ = -1;
|
|
|
|
|
2010-07-17 19:18:02 +02:00
|
|
|
if (!info.BestBackend()->lister_) {
|
2010-07-04 14:56:49 +02:00
|
|
|
// It's not attached any more so remove it from the list
|
|
|
|
beginRemoveRows(QModelIndex(), row, row);
|
|
|
|
devices_.removeAt(row);
|
2010-07-04 17:01:24 +02:00
|
|
|
|
|
|
|
foreach (const QModelIndex& idx, persistentIndexList()) {
|
|
|
|
if (idx.row() == row)
|
|
|
|
changePersistentIndex(idx, QModelIndex());
|
|
|
|
else if (idx.row() > row)
|
|
|
|
changePersistentIndex(idx, index(idx.row()-1, idx.column()));
|
|
|
|
}
|
|
|
|
|
2010-07-04 14:56:49 +02:00
|
|
|
endRemoveRows();
|
|
|
|
} else {
|
2010-07-04 17:18:37 +02:00
|
|
|
// It's still attached, set the name and icon back to what they were
|
|
|
|
// originally
|
2010-07-17 23:48:09 +02:00
|
|
|
const QString id = info.BestBackend()->unique_id_;
|
|
|
|
|
|
|
|
info.friendly_name_ = info.BestBackend()->lister_->MakeFriendlyName(id);
|
|
|
|
info.LoadIcon(info.BestBackend()->lister_->DeviceIcons(id), info.friendly_name_);
|
2010-07-04 17:18:37 +02:00
|
|
|
|
2010-07-04 14:56:49 +02:00
|
|
|
dataChanged(index(row, 0), index(row, 0));
|
|
|
|
}
|
|
|
|
}
|
2010-07-04 17:18:37 +02:00
|
|
|
|
2010-08-29 17:32:36 +02:00
|
|
|
void DeviceManager::SetDeviceOptions(int row,
|
|
|
|
const QString& friendly_name, const QString& icon_name,
|
2010-08-29 21:22:21 +02:00
|
|
|
MusicStorage::TranscodeMode mode, Song::FileType format) {
|
2010-07-04 17:18:37 +02:00
|
|
|
DeviceInfo& info = devices_[row];
|
|
|
|
info.friendly_name_ = friendly_name;
|
2010-08-16 01:26:04 +02:00
|
|
|
info.LoadIcon(QVariantList() << icon_name, friendly_name);
|
2010-08-29 17:32:36 +02:00
|
|
|
info.transcode_mode_ = mode;
|
|
|
|
info.transcode_format_ = format;
|
2010-07-04 17:18:37 +02:00
|
|
|
|
|
|
|
emit dataChanged(index(row, 0), index(row, 0));
|
|
|
|
|
|
|
|
if (info.database_id_ != -1)
|
2010-08-29 17:32:36 +02:00
|
|
|
backend_->SetDeviceOptions(info.database_id_, friendly_name, icon_name,
|
|
|
|
mode, format);
|
2010-07-04 17:18:37 +02:00
|
|
|
}
|
2010-07-04 17:56:08 +02:00
|
|
|
|
|
|
|
void DeviceManager::DeviceTaskStarted(int id) {
|
|
|
|
ConnectedDevice* device = qobject_cast<ConnectedDevice*>(sender());
|
|
|
|
if (!device)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i=0 ; i<devices_.count() ; ++i) {
|
|
|
|
DeviceInfo& info = devices_[i];
|
|
|
|
if (info.device_.get() == device) {
|
|
|
|
active_tasks_[id] = index(i);
|
|
|
|
info.task_percentage_ = 0;
|
|
|
|
emit dataChanged(index(i), index(i));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceManager::TasksChanged() {
|
2012-02-12 14:41:50 +01:00
|
|
|
QList<TaskManager::Task> tasks = app_->task_manager()->GetTasks();
|
2010-07-04 17:56:08 +02:00
|
|
|
QList<QPersistentModelIndex> finished_tasks = active_tasks_.values();
|
|
|
|
|
2011-07-21 01:22:20 +02:00
|
|
|
foreach (const TaskManager::Task& task, tasks) {
|
2010-07-04 17:56:08 +02:00
|
|
|
if (!active_tasks_.contains(task.id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QPersistentModelIndex index = active_tasks_[task.id];
|
|
|
|
if (!index.isValid())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DeviceInfo& info = devices_[index.row()];
|
|
|
|
if (task.progress_max)
|
|
|
|
info.task_percentage_ = float(task.progress) / task.progress_max * 100;
|
|
|
|
else
|
|
|
|
info.task_percentage_ = 0;
|
|
|
|
emit dataChanged(index, index);
|
|
|
|
finished_tasks.removeAll(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const QPersistentModelIndex& index, finished_tasks) {
|
|
|
|
if (!index.isValid())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DeviceInfo& info = devices_[index.row()];
|
|
|
|
info.task_percentage_ = -1;
|
|
|
|
emit dataChanged(index, index);
|
2010-08-29 21:22:21 +02:00
|
|
|
|
|
|
|
active_tasks_.remove(active_tasks_.key(index));
|
2010-07-04 17:56:08 +02:00
|
|
|
}
|
|
|
|
}
|
2010-07-25 03:07:51 +02:00
|
|
|
|
2010-08-01 13:01:07 +02:00
|
|
|
void DeviceManager::UnmountAsync(int row) {
|
|
|
|
Q_ASSERT(QMetaObject::invokeMethod(this, "Unmount", Q_ARG(int, row)));
|
|
|
|
}
|
|
|
|
|
2010-07-25 03:07:51 +02:00
|
|
|
void DeviceManager::Unmount(int row) {
|
|
|
|
DeviceInfo& info = devices_[row];
|
2010-08-14 14:42:16 +02:00
|
|
|
if (info.database_id_ != -1 && !info.device_)
|
2010-07-25 03:07:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (info.device_)
|
|
|
|
Disconnect(row);
|
|
|
|
|
|
|
|
if (info.BestBackend()->lister_)
|
|
|
|
info.BestBackend()->lister_->UnmountDevice(info.BestBackend()->unique_id_);
|
|
|
|
}
|
2010-08-30 16:45:27 +02:00
|
|
|
|
|
|
|
void DeviceManager::DeviceSongCountUpdated(int count) {
|
|
|
|
ConnectedDevice* device = qobject_cast<ConnectedDevice*>(sender());
|
|
|
|
if (!device)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int row = FindDeviceById(device->unique_id());
|
|
|
|
if (row == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
emit dataChanged(index(row), index(row));
|
|
|
|
}
|