Add cache for Solid devices to speed up KFilePlacesModel
This commit is contained in:
parent
601681bc18
commit
04893e481a
406
kdelibs-udisks2-kfileplacesdevicecache.patch
Normal file
406
kdelibs-udisks2-kfileplacesdevicecache.patch
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
diff --git a/kfile/CMakeLists.txt b/kfile/CMakeLists.txt
|
||||||
|
index ceae140..c7c4d3d 100644
|
||||||
|
--- a/kfile/CMakeLists.txt
|
||||||
|
+++ b/kfile/CMakeLists.txt
|
||||||
|
@@ -20,6 +20,7 @@ set(kfile_LIB_SRCS
|
||||||
|
kfilefiltercombo.cpp
|
||||||
|
kfiletreeview.cpp
|
||||||
|
kfilewidget.cpp
|
||||||
|
+ kfileplacesdevicecache.cpp
|
||||||
|
kfileplacesitem.cpp
|
||||||
|
kfileplacesmodel.cpp
|
||||||
|
kfileplacessharedbookmarks.cpp
|
||||||
|
@@ -63,6 +64,7 @@ install( FILES
|
||||||
|
kdirselectdialog.h
|
||||||
|
kdirsortfilterproxymodel.h
|
||||||
|
kfilefiltercombo.h
|
||||||
|
+ kfileplacesdevicecache.h
|
||||||
|
kfileplacesmodel.h
|
||||||
|
kfileplacesview.h
|
||||||
|
kfilepreviewgenerator.h
|
||||||
|
diff --git a/kfile/kfileplacesdevicecache.cpp b/kfile/kfileplacesdevicecache.cpp
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..40f7242
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/kfile/kfileplacesdevicecache.cpp
|
||||||
|
@@ -0,0 +1,174 @@
|
||||||
|
+/*
|
||||||
|
+ Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
|
||||||
|
+
|
||||||
|
+ This library is free software; you can redistribute it and/or
|
||||||
|
+ modify it under the terms of the GNU Library General Public
|
||||||
|
+ License version 2 as published by the Free Software Foundation.
|
||||||
|
+
|
||||||
|
+ This library 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
|
||||||
|
+ Library General Public License for more details.
|
||||||
|
+
|
||||||
|
+ You should have received a copy of the GNU Library General Public License
|
||||||
|
+ along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
+ Boston, MA 02110-1301, USA.
|
||||||
|
+*/
|
||||||
|
+
|
||||||
|
+#include "kfileplacesdevicecache.h"
|
||||||
|
+
|
||||||
|
+#include <QMutex>
|
||||||
|
+#include <QtConcurrentRun>
|
||||||
|
+#include <QFutureWatcher>
|
||||||
|
+#include <QTimer>
|
||||||
|
+
|
||||||
|
+#include <kprotocolinfo.h>
|
||||||
|
+#include <solid/predicate.h>
|
||||||
|
+#include <solid/device.h>
|
||||||
|
+#include <solid/devicenotifier.h>
|
||||||
|
+#include <solid/genericinterface.h>
|
||||||
|
+
|
||||||
|
+#include <kdebug.h>
|
||||||
|
+
|
||||||
|
+KFilePlacesDeviceCache* KFilePlacesDeviceCache::s_instance = 0;
|
||||||
|
+
|
||||||
|
+class KFilePlacesDeviceCache::Private
|
||||||
|
+{
|
||||||
|
+ public:
|
||||||
|
+ Private(KFilePlacesDeviceCache *parent):
|
||||||
|
+ queryRunning(false),
|
||||||
|
+ q(parent)
|
||||||
|
+ { }
|
||||||
|
+
|
||||||
|
+ ~Private()
|
||||||
|
+ { }
|
||||||
|
+
|
||||||
|
+ /* This method runs asynchronously in thread */
|
||||||
|
+ QSet<QString> listSolidDevicesAsync()
|
||||||
|
+ {
|
||||||
|
+ QSet<QString> udis;
|
||||||
|
+
|
||||||
|
+ kDebug() << "Querying Solid devices...";
|
||||||
|
+ const QList<Solid::Device>& deviceList = Solid::Device::listFromQuery(solidPredicate);
|
||||||
|
+ kDebug() << "Retrieved" << deviceList.count() << "devices";
|
||||||
|
+
|
||||||
|
+ Q_FOREACH (const Solid::Device& device, deviceList) {
|
||||||
|
+ if (solidPredicate.matches(device)) {
|
||||||
|
+ udis << device.udi();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return udis;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void _k_slotDeviceAdded(const QString &udi)
|
||||||
|
+ {
|
||||||
|
+ devicesCache << udi;
|
||||||
|
+
|
||||||
|
+ Q_EMIT q->deviceAdded(udi);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void _k_slotDeviceRemoved(const QString &udi)
|
||||||
|
+ {
|
||||||
|
+ if (!devicesCache.contains(udi)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ devicesCache.remove(udi);
|
||||||
|
+
|
||||||
|
+ Q_EMIT q->deviceRemoved(udi);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void _k_listSolidDevicesFinished()
|
||||||
|
+ {
|
||||||
|
+ Q_FOREACH (const QString& device, futureWatcher->result()) {
|
||||||
|
+ _k_slotDeviceAdded(device);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ delete futureWatcher;
|
||||||
|
+ futureWatcher = 0;
|
||||||
|
+
|
||||||
|
+ queryRunning = false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Solid::Predicate solidPredicate;
|
||||||
|
+
|
||||||
|
+ QFutureWatcher< QSet<QString> >* futureWatcher;
|
||||||
|
+
|
||||||
|
+ /* Static */
|
||||||
|
+ QSet<QString> devicesCache;
|
||||||
|
+ bool queryRunning;
|
||||||
|
+
|
||||||
|
+ KFilePlacesDeviceCache *q;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+KFilePlacesDeviceCache::KFilePlacesDeviceCache():
|
||||||
|
+ QObject(),
|
||||||
|
+ d(new Private(this))
|
||||||
|
+{
|
||||||
|
+ Solid::DeviceNotifier* notifier = Solid::DeviceNotifier::instance();
|
||||||
|
+ connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(_k_slotDeviceAdded(QString)));
|
||||||
|
+ connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(_k_slotDeviceRemoved(QString)));
|
||||||
|
+
|
||||||
|
+ QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]"
|
||||||
|
+ " OR "
|
||||||
|
+ "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]"
|
||||||
|
+ " OR "
|
||||||
|
+ "OpticalDisc.availableContent & 'Audio' ]"
|
||||||
|
+ " OR "
|
||||||
|
+ "StorageAccess.ignored == false ]");
|
||||||
|
+
|
||||||
|
+ if (KProtocolInfo::isKnownProtocol("mtp")) {
|
||||||
|
+ predicate.prepend("[");
|
||||||
|
+ predicate.append(" OR PortableMediaPlayer.supportedProtocols == 'mtp']");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ d->solidPredicate = Solid::Predicate::fromString(predicate);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+KFilePlacesDeviceCache* KFilePlacesDeviceCache::self()
|
||||||
|
+{
|
||||||
|
+ static QMutex mutex;
|
||||||
|
+
|
||||||
|
+ mutex.lock();
|
||||||
|
+ if (s_instance == 0) {
|
||||||
|
+ s_instance = new KFilePlacesDeviceCache();
|
||||||
|
+ }
|
||||||
|
+ mutex.unlock();
|
||||||
|
+
|
||||||
|
+ return s_instance;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+KFilePlacesDeviceCache::~KFilePlacesDeviceCache()
|
||||||
|
+{
|
||||||
|
+ Solid::DeviceNotifier* notifier = Solid::DeviceNotifier::instance();
|
||||||
|
+ disconnect(notifier, SIGNAL(deviceAdded(QString)));
|
||||||
|
+ disconnect(notifier, SIGNAL(deviceRemoved(QString)));
|
||||||
|
+
|
||||||
|
+ delete d;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const Solid::Predicate& KFilePlacesDeviceCache::predicate() const
|
||||||
|
+{
|
||||||
|
+ return d->solidPredicate;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const QSet<QString>& KFilePlacesDeviceCache::devices() const
|
||||||
|
+{
|
||||||
|
+ kDebug();
|
||||||
|
+ if (d->devicesCache.isEmpty() && !d->queryRunning) {
|
||||||
|
+ d->queryRunning = true;
|
||||||
|
+ d->futureWatcher = new QFutureWatcher< QSet<QString> >;
|
||||||
|
+ connect(d->futureWatcher, SIGNAL(finished()), this, SLOT(_k_listSolidDevicesFinished()));
|
||||||
|
+
|
||||||
|
+ QFuture< QSet<QString> > future = QtConcurrent::run(d, &Private::listSolidDevicesAsync);
|
||||||
|
+ d->futureWatcher->setFuture(future);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return d->devicesCache;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#include "kfileplacesdevicecache.moc"
|
||||||
|
diff --git a/kfile/kfileplacesdevicecache.h b/kfile/kfileplacesdevicecache.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..7293d03
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/kfile/kfileplacesdevicecache.h
|
||||||
|
@@ -0,0 +1,96 @@
|
||||||
|
+/*
|
||||||
|
+ Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
|
||||||
|
+
|
||||||
|
+ This library is free software; you can redistribute it and/or
|
||||||
|
+ modify it under the terms of the GNU Library General Public
|
||||||
|
+ License version 2 as published by the Free Software Foundation.
|
||||||
|
+
|
||||||
|
+ This library 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
|
||||||
|
+ Library General Public License for more details.
|
||||||
|
+
|
||||||
|
+ You should have received a copy of the GNU Library General Public License
|
||||||
|
+ along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
+ Boston, MA 02110-1301, USA.
|
||||||
|
+*/
|
||||||
|
+
|
||||||
|
+#ifndef KFILEPLACESDEVICECACHE_H
|
||||||
|
+#define KFILEPLACESDEVICECACHE_H
|
||||||
|
+
|
||||||
|
+#include <kfile_export.h>
|
||||||
|
+
|
||||||
|
+#include <QObject>
|
||||||
|
+#include <QSet>
|
||||||
|
+
|
||||||
|
+#include <solid/predicate.h>
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * @short Asynchronous cache for Solid devices
|
||||||
|
+ *
|
||||||
|
+ * Purpose of this cache is to load Solid devices asynchronously, because
|
||||||
|
+ * udisks2 backend can take quite a lot of time to enumerate devices, and
|
||||||
|
+ * since Solid does not have async API, the UI thread is blocked for too long.
|
||||||
|
+ *
|
||||||
|
+ * When libsolid2 with asynchronous API is available, this class can go away.
|
||||||
|
+ *
|
||||||
|
+ * The cache keeps itself up-to-date and notifies listeners when a
|
||||||
|
+ * new devices is added or removed.
|
||||||
|
+ */
|
||||||
|
+class KFILE_EXPORT KFilePlacesDeviceCache : public QObject
|
||||||
|
+{
|
||||||
|
+ Q_OBJECT
|
||||||
|
+
|
||||||
|
+public:
|
||||||
|
+ /**
|
||||||
|
+ * Returns a global instance of the cache
|
||||||
|
+ */
|
||||||
|
+ static KFilePlacesDeviceCache* self();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Returns list of Solid devices.
|
||||||
|
+ *
|
||||||
|
+ * This method always returns immediatelly. When there are no
|
||||||
|
+ * devices in the cache, it returns an empty list and will asynchronously
|
||||||
|
+ * query Solid for devices and will notify listeners by emitting
|
||||||
|
+ * deviceAdded() signal for each devices loaded.
|
||||||
|
+ */
|
||||||
|
+ const QSet<QString>& devices() const;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Returns Solid::Predicate used to obtain devices from Solid
|
||||||
|
+ */
|
||||||
|
+ const Solid::Predicate& predicate() const;
|
||||||
|
+
|
||||||
|
+Q_SIGNALS:
|
||||||
|
+ /**
|
||||||
|
+ * Emitted whenever a new device is discovered.
|
||||||
|
+ *
|
||||||
|
+ * @param udi UDI (Universal Device ID) of the newly discovered device
|
||||||
|
+ */
|
||||||
|
+ void deviceAdded(const QString& udi);
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Emitted whenever a device is removed from system
|
||||||
|
+ *
|
||||||
|
+ * @param udi UDI (Universal Device ID) of the removed device
|
||||||
|
+ */
|
||||||
|
+ void deviceRemoved(const QString& udi);
|
||||||
|
+
|
||||||
|
+private:
|
||||||
|
+ Q_PRIVATE_SLOT(d, void _k_listSolidDevicesFinished())
|
||||||
|
+ Q_PRIVATE_SLOT(d, void _k_slotDeviceAdded(const QString&))
|
||||||
|
+ Q_PRIVATE_SLOT(d, void _k_slotDeviceRemoved(const QString&))
|
||||||
|
+
|
||||||
|
+ class Private;
|
||||||
|
+ Private * const d;
|
||||||
|
+ friend class Private;
|
||||||
|
+
|
||||||
|
+ explicit KFilePlacesDeviceCache();
|
||||||
|
+ virtual ~KFilePlacesDeviceCache();
|
||||||
|
+
|
||||||
|
+ static KFilePlacesDeviceCache* s_instance;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#endif // KFILEPLACESDEVICECACHE_H
|
||||||
|
diff --git a/kfile/kfileplacesmodel.cpp b/kfile/kfileplacesmodel.cpp
|
||||||
|
index 0192926..e0b01c6 100644
|
||||||
|
--- a/kfile/kfileplacesmodel.cpp
|
||||||
|
+++ b/kfile/kfileplacesmodel.cpp
|
||||||
|
@@ -20,6 +20,7 @@
|
||||||
|
#include "kfileplacesmodel.h"
|
||||||
|
#include "kfileplacesitem_p.h"
|
||||||
|
#include "kfileplacessharedbookmarks_p.h"
|
||||||
|
+#include "kfileplacesdevicecache.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32_WCE
|
||||||
|
#include "Windows.h"
|
||||||
|
@@ -49,14 +50,12 @@
|
||||||
|
#include <kio/netaccess.h>
|
||||||
|
#include <kprotocolinfo.h>
|
||||||
|
|
||||||
|
-#include <solid/devicenotifier.h>
|
||||||
|
#include <solid/storageaccess.h>
|
||||||
|
#include <solid/storagedrive.h>
|
||||||
|
#include <solid/storagevolume.h>
|
||||||
|
#include <solid/opticaldrive.h>
|
||||||
|
#include <solid/opticaldisc.h>
|
||||||
|
#include <solid/portablemediaplayer.h>
|
||||||
|
-#include <solid/predicate.h>
|
||||||
|
|
||||||
|
class KFilePlacesModel::Private
|
||||||
|
{
|
||||||
|
@@ -74,7 +73,6 @@ public:
|
||||||
|
QSet<QString> availableDevices;
|
||||||
|
QMap<QObject*, QPersistentModelIndex> setupInProgress;
|
||||||
|
|
||||||
|
- Solid::Predicate predicate;
|
||||||
|
KBookmarkManager *bookmarkManager;
|
||||||
|
KFilePlacesSharedBookmarks * sharedBookmarks;
|
||||||
|
|
||||||
|
@@ -149,30 +147,12 @@ KFilePlacesModel::KFilePlacesModel(QObject *parent)
|
||||||
|
// create after, so if we have own places, they are added afterwards, in case of equal priorities
|
||||||
|
d->sharedBookmarks = new KFilePlacesSharedBookmarks(d->bookmarkManager);
|
||||||
|
|
||||||
|
- QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]"
|
||||||
|
- " OR "
|
||||||
|
- "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]"
|
||||||
|
- " OR "
|
||||||
|
- "OpticalDisc.availableContent & 'Audio' ]"
|
||||||
|
- " OR "
|
||||||
|
- "StorageAccess.ignored == false ]");
|
||||||
|
-
|
||||||
|
- if (KProtocolInfo::isKnownProtocol("mtp")) {
|
||||||
|
- predicate.prepend("[");
|
||||||
|
- predicate.append(" OR PortableMediaPlayer.supportedProtocols == 'mtp']");
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- d->predicate = Solid::Predicate::fromString(predicate);
|
||||||
|
-
|
||||||
|
- Q_ASSERT(d->predicate.isValid());
|
||||||
|
-
|
||||||
|
connect(d->bookmarkManager, SIGNAL(changed(QString,QString)),
|
||||||
|
this, SLOT(_k_reloadBookmarks()));
|
||||||
|
connect(d->bookmarkManager, SIGNAL(bookmarksChanged(QString)),
|
||||||
|
this, SLOT(_k_reloadBookmarks()));
|
||||||
|
|
||||||
|
- d->_k_reloadBookmarks();
|
||||||
|
- QTimer::singleShot(0, this, SLOT(_k_initDeviceList()));
|
||||||
|
+ d->_k_initDeviceList();
|
||||||
|
}
|
||||||
|
|
||||||
|
KFilePlacesModel::~KFilePlacesModel()
|
||||||
|
@@ -313,30 +293,21 @@ QModelIndex KFilePlacesModel::closestItem(const KUrl &url) const
|
||||||
|
|
||||||
|
void KFilePlacesModel::Private::_k_initDeviceList()
|
||||||
|
{
|
||||||
|
- Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
|
||||||
|
-
|
||||||
|
- connect(notifier, SIGNAL(deviceAdded(QString)),
|
||||||
|
+ KFilePlacesDeviceCache *cache = KFilePlacesDeviceCache::self();
|
||||||
|
+ connect(cache, SIGNAL(deviceAdded(QString)),
|
||||||
|
q, SLOT(_k_deviceAdded(QString)));
|
||||||
|
- connect(notifier, SIGNAL(deviceRemoved(QString)),
|
||||||
|
+ connect(cache, SIGNAL(deviceRemoved(QString)),
|
||||||
|
q, SLOT(_k_deviceRemoved(QString)));
|
||||||
|
|
||||||
|
- const QList<Solid::Device> &deviceList = Solid::Device::listFromQuery(predicate);
|
||||||
|
-
|
||||||
|
- foreach(const Solid::Device &device, deviceList) {
|
||||||
|
- availableDevices << device.udi();
|
||||||
|
- }
|
||||||
|
+ availableDevices = cache->devices();
|
||||||
|
|
||||||
|
_k_reloadBookmarks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KFilePlacesModel::Private::_k_deviceAdded(const QString &udi)
|
||||||
|
{
|
||||||
|
- Solid::Device d(udi);
|
||||||
|
-
|
||||||
|
- if (predicate.matches(d)) {
|
||||||
|
- availableDevices << udi;
|
||||||
|
- _k_reloadBookmarks();
|
||||||
|
- }
|
||||||
|
+ availableDevices << udi;
|
||||||
|
+ _k_reloadBookmarks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KFilePlacesModel::Private::_k_deviceRemoved(const QString &udi)
|
@ -124,6 +124,9 @@ Patch45: kdelibs-4.7.3-halectomy.patch
|
|||||||
# udisks2 Solid backend
|
# udisks2 Solid backend
|
||||||
Patch47: kdelibs-udisks2-backend.patch
|
Patch47: kdelibs-udisks2-backend.patch
|
||||||
|
|
||||||
|
# cache to improve performance of apps using Solid with udisks2 (#868530)
|
||||||
|
Patch48: kdelibs-udisks2-kfileplacesdevicecache.patch
|
||||||
|
|
||||||
## upstreamable
|
## upstreamable
|
||||||
# knewstuff2 variant of:
|
# knewstuff2 variant of:
|
||||||
# https://git.reviewboard.kde.org/r/102439/
|
# https://git.reviewboard.kde.org/r/102439/
|
||||||
@ -317,6 +320,7 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage
|
|||||||
|
|
||||||
%if "%{?udisks}" == "udisks2"
|
%if "%{?udisks}" == "udisks2"
|
||||||
%patch47 -p1 -b .udisks2backend
|
%patch47 -p1 -b .udisks2backend
|
||||||
|
%patch48 -p1 -b .kfileplacesdevicescache
|
||||||
%else
|
%else
|
||||||
%patch45 -p1 -b .halectomy
|
%patch45 -p1 -b .halectomy
|
||||||
%endif
|
%endif
|
||||||
|
Loading…
Reference in New Issue
Block a user