diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7dbe3db6..fc41ad3ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,10 @@ set(SOURCES core/taskmanager.cpp core/utilities.cpp + devices/device.cpp + devices/deviceengine.cpp + devices/filesystemdeviceengine.cpp + engines/enginebase.cpp library/groupbydialog.cpp @@ -168,6 +172,10 @@ set(HEADERS core/songloader.h core/taskmanager.h + devices/device.h + devices/deviceengine.h + devices/filesystemdeviceengine.h + engines/enginebase.h library/groupbydialog.h @@ -398,6 +406,11 @@ list(APPEND OTHER_SOURCES if(NOT APPLE AND NOT WIN32) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus) + # Hack to get it to generate interfaces without namespaces - required + # because otherwise org::freedesktop::UDisks and + # org::freedesktop::UDisks::Device conflict. + list(APPEND QT_DBUSXML2CPP_EXECUTABLE -N) + # MPRIS DBUS interfaces qt4_add_dbus_adaptor(SOURCES dbus/org.freedesktop.MediaPlayer.player.xml diff --git a/src/devices/device.cpp b/src/devices/device.cpp new file mode 100644 index 000000000..cdbbf852d --- /dev/null +++ b/src/devices/device.cpp @@ -0,0 +1,22 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#include "device.h" + +Device::Device(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/devices/device.h b/src/devices/device.h new file mode 100644 index 000000000..5e0ab69f9 --- /dev/null +++ b/src/devices/device.h @@ -0,0 +1,29 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#ifndef DEVICE_H +#define DEVICE_H + +#include + +class Device : public QObject { + Q_OBJECT + +public: + Device(QObject *parent = 0); +}; + +#endif // DEVICE_H diff --git a/src/devices/deviceengine.cpp b/src/devices/deviceengine.cpp new file mode 100644 index 000000000..c948866a1 --- /dev/null +++ b/src/devices/deviceengine.cpp @@ -0,0 +1,22 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#include "deviceengine.h" + +DeviceEngine::DeviceEngine(QObject *parent) + : QAbstractItemModel(parent) +{ +} diff --git a/src/devices/deviceengine.h b/src/devices/deviceengine.h new file mode 100644 index 000000000..a66aa5c12 --- /dev/null +++ b/src/devices/deviceengine.h @@ -0,0 +1,42 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#ifndef DEVICEENGINE_H +#define DEVICEENGINE_H + +#include + +class DeviceEngine : public QAbstractItemModel { + Q_OBJECT + +public: + DeviceEngine(QObject* parent = 0); + + enum Column { + Column_UniqueID = 0, + Column_FriendlyName, + Column_Manufacturer, + Column_Model, + Column_Capacity, + Column_FreeSpace, + + LastDeviceEngineColumn + }; + + virtual bool Init() = 0; +}; + +#endif // DEVICEENGINE_H diff --git a/src/devices/filesystemdeviceengine.cpp b/src/devices/filesystemdeviceengine.cpp new file mode 100644 index 000000000..b4e40e994 --- /dev/null +++ b/src/devices/filesystemdeviceengine.cpp @@ -0,0 +1,191 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#include "filesystemdeviceengine.h" +#include "dbus/udisks.h" +#include "dbus/udisksdevice.h" + +FilesystemDeviceEngine::FilesystemDeviceEngine(QObject *parent) + : DeviceEngine(parent) +{ +} + +FilesystemDeviceEngine::~FilesystemDeviceEngine() { +} + +bool FilesystemDeviceEngine::Init() { + interface_.reset(new OrgFreedesktopUDisksInterface( + OrgFreedesktopUDisksInterface::staticInterfaceName(), + "/org/freedesktop/UDisks", QDBusConnection::systemBus())); + + if (!interface_->isValid()) { + qWarning() << "Error connecting to the DeviceKit-disks DBUS service"; + interface_.reset(); + return false; + } + + connect(interface_.get(), SIGNAL(DeviceAdded(QDBusObjectPath)), SLOT(DeviceAdded(QDBusObjectPath))); + connect(interface_.get(), SIGNAL(DeviceRemoved(QDBusObjectPath)), SLOT(DeviceRemoved(QDBusObjectPath))); + connect(interface_.get(), SIGNAL(DeviceChanged(QDBusObjectPath)), SLOT(DeviceChanged(QDBusObjectPath))); + + Reset(); + return true; +} + +QModelIndex FilesystemDeviceEngine::index(int row, int column, const QModelIndex &parent) const { + if (parent.isValid()) + return QModelIndex(); + return createIndex(row, column); +} + +int FilesystemDeviceEngine::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return device_info_.count(); +} + +int FilesystemDeviceEngine::columnCount(const QModelIndex &parent) const { + return LastFilesystemDeviceEngineColumn; +} + +QVariant FilesystemDeviceEngine::data(const QModelIndex &index, int role) const { + const DeviceInfo& info = device_info_[index.row()]; + + switch (index.column()) { + case Column_UniqueID: + return info.unique_id(); + + case Column_FriendlyName: + if (!info.device_presentation_name.isEmpty()) + return info.device_presentation_name; + if (!info.drive_model.isEmpty() || !info.drive_vendor.isEmpty()) + return QString("%1 %2").arg(info.drive_vendor, info.drive_model); + return info.drive_serial; + + case Column_Manufacturer: + return info.drive_vendor; + + case Column_Model: + return info.drive_model; + + case Column_Capacity: + return info.device_size; + + case Column_FreeSpace: + return QVariant(); + + case Column_DbusPath: + return info.dbus_path; + + case Column_MountPath: + return info.device_mount_paths.isEmpty() ? QVariant() : info.device_mount_paths[0]; + + default: + return QVariant(); + } +} + +void FilesystemDeviceEngine::Reset() { + QDBusPendingReply > reply = interface_->EnumerateDevices(); + reply.waitForFinished(); + + if (!reply.isValid()) { + qWarning() << "Error enumerating DeviceKit-disks devices:" << reply.error(); + return; + } + +#if QT_VERSION >= 0x040600 + emit beginResetModel(); +#endif + + device_info_.clear(); + foreach (const QDBusObjectPath& path, reply.value()) { + DeviceInfo info = ReadDeviceInfo(path); + if (info.suitable) + device_info_ << info; + } + +#if QT_VERSION >= 0x040600 + emit endResetModel(); +#else + reset(); +#endif +} + +FilesystemDeviceEngine::DeviceInfo FilesystemDeviceEngine::ReadDeviceInfo( + const QDBusObjectPath &path) const { + DeviceInfo ret; + + OrgFreedesktopUDisksDeviceInterface device( + OrgFreedesktopUDisksDeviceInterface::staticInterfaceName(), + path.path(), QDBusConnection::systemBus()); + if (!device.isValid()) { + qWarning() << "Error connecting to the device interface on" << path.path(); + return ret; + } + + // Don't do anything with internal drives, hidden drives, or things that + // aren't partitions + if (device.deviceIsSystemInternal() || + device.devicePresentationHide() || + !device.deviceIsPartition()) { + return ret; + } + + ret.suitable = true; + ret.dbus_path = path.path(); + ret.drive_serial = device.driveSerial(); + ret.drive_model = device.driveModel(); + ret.drive_vendor = device.driveVendor(); + ret.device_presentation_name = device.devicePresentationName(); + ret.device_presentation_icon_name = device.devicePresentationIconName(); + ret.device_size = device.deviceSize(); + return ret; +} + +void FilesystemDeviceEngine::DeviceAdded(const QDBusObjectPath &path) { + DeviceInfo info = ReadDeviceInfo(path); + if (!info.suitable) + return; + + emit beginInsertRows(QModelIndex(), device_info_.count(), device_info_.count()); + device_info_ << info; + emit endInsertRows(); +} + +void FilesystemDeviceEngine::DeviceRemoved(const QDBusObjectPath &path) { + QModelIndex index = FindDevice(path); + if (!index.isValid()) + return; + + emit beginRemoveRows(QModelIndex(), index.row(), index.row()); + device_info_.removeAt(index.row()); + emit endRemoveRows(); +} + +void FilesystemDeviceEngine::DeviceChanged(const QDBusObjectPath &path) { + QModelIndex index = FindDevice(path); + DeviceInfo info = ReadDeviceInfo(path); + + if (index.isValid() && !info.suitable) + DeviceRemoved(path); + else if (!index.isValid() && info.suitable) + DeviceAdded(path); + else if (index.isValid() && info.suitable) { + device_info_[index.row()] = info; + emit dataChanged(index, index.sibling(index.row(), columnCount())); + } +} diff --git a/src/devices/filesystemdeviceengine.h b/src/devices/filesystemdeviceengine.h new file mode 100644 index 000000000..762834719 --- /dev/null +++ b/src/devices/filesystemdeviceengine.h @@ -0,0 +1,84 @@ +/* This file is part of Clementine. + + 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 . +*/ + +#ifndef FILESYSTEMDEVICEENGINE_H +#define FILESYSTEMDEVICEENGINE_H + +#include "deviceengine.h" + +#include + +#include + +class OrgFreedesktopUDisksInterface; + +class QDBusObjectPath; + +class FilesystemDeviceEngine : public DeviceEngine { + Q_OBJECT + +public: + FilesystemDeviceEngine(QObject *parent = 0); + ~FilesystemDeviceEngine(); + + enum Column { + Column_MountPath = LastDeviceEngineColumn, + Column_DbusPath, + + LastFilesystemDeviceEngineColumn + }; + + bool Init(); + + QModelIndex index(int row, int column, const QModelIndex &parent) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + +private slots: + void DeviceAdded(const QDBusObjectPath& path); + void DeviceRemoved(const QDBusObjectPath& path); + void DeviceChanged(const QDBusObjectPath& path); + +private: + struct DeviceInfo { + DeviceInfo() : suitable(false), device_size(0) {} + + bool suitable; + QString dbus_path; + QString drive_serial; + QString drive_model; + QString drive_vendor; + QString device_presentation_name; + QString device_presentation_icon_name; + QStringList device_mount_paths; + quint64 device_size; + + QString unique_id() const; + }; + + void Reset(); + DeviceInfo ReadDeviceInfo(const QDBusObjectPath& path) const; + + QModelIndex FindDevice(const QDBusObjectPath& path) const; + +private: + boost::scoped_ptr interface_; + + QList device_info_; +}; + +#endif // FILESYSTEMDEVICEENGINE_H diff --git a/src/widgets/osd.cpp b/src/widgets/osd.cpp index 8f61a5208..64fa7b079 100644 --- a/src/widgets/osd.cpp +++ b/src/widgets/osd.cpp @@ -18,6 +18,10 @@ #include "osdpretty.h" #include "ui/systemtrayicon.h" +#ifdef Q_WS_X11 +# include "dbus/notification.h" +#endif + #include #include #include diff --git a/src/widgets/osd.h b/src/widgets/osd.h index 9647d3ca5..36b0860be 100644 --- a/src/widgets/osd.h +++ b/src/widgets/osd.h @@ -17,6 +17,7 @@ #ifndef OSD_H #define OSD_H +#include #include #include @@ -26,6 +27,7 @@ #include "core/song.h" class NetworkAccessManager; +class OrgFreedesktopNotificationsInterface; class OSDPretty; class SystemTrayIcon; @@ -34,7 +36,6 @@ class QDBusPendingCallWatcher; #ifdef Q_WS_X11 # include # include -# include "dbus/notification.h" QDBusArgument& operator<< (QDBusArgument& arg, const QImage& image); const QDBusArgument& operator>> (const QDBusArgument& arg, QImage& image); @@ -118,7 +119,7 @@ class OSD : public QObject { #endif // Q_OS_DARWIN #ifdef Q_WS_X11 - boost::scoped_ptr interface_; + boost::scoped_ptr interface_; uint notification_id_; QDateTime last_notification_time_; #endif diff --git a/src/widgets/osd_x11.cpp b/src/widgets/osd_x11.cpp index e704b969d..21425e257 100644 --- a/src/widgets/osd_x11.cpp +++ b/src/widgets/osd_x11.cpp @@ -15,6 +15,7 @@ */ #include "osd.h" +#include "dbus/notification.h" #include #include @@ -52,8 +53,8 @@ const QDBusArgument& operator>> (const QDBusArgument& arg, QImage& image) { } void OSD::Init() { - interface_.reset(new org::freedesktop::Notifications( - "org.freedesktop.Notifications", + interface_.reset(new OrgFreedesktopNotificationsInterface( + OrgFreedesktopNotificationsInterface::staticInterfaceName(), "/org/freedesktop/Notifications", QDBusConnection::sessionBus())); if (!interface_->isValid()) {