diff --git a/src/diskusage.cpp b/src/diskusage.cpp new file mode 100644 index 0000000..5dc3cc0 --- /dev/null +++ b/src/diskusage.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 Jolla Ltd. + * Contact: Thomas Perl + * + * You may use this file under the terms of the BSD license as follows: + * + * "Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Nemo Mobile nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + */ + +#include "diskusage.h" +#include "diskusage_p.h" + +#include +#include +#include +#include +#include + +DiskUsageWorker::DiskUsageWorker(QObject *parent) + : QObject(parent) + , m_quit(false) +{ +} + +DiskUsageWorker::~DiskUsageWorker() +{ +} + +static quint64 calculateSize(const QString &directory) +{ + QDir d(directory); + if (!d.exists() || !d.isReadable()) { + return 0L; + } + + QProcess du; + du.start("du", QStringList() << "-sb" << directory, QIODevice::ReadOnly); + du.waitForFinished(); + if (du.exitStatus() != QProcess::NormalExit) { + qWarning() << "Could not determine size of:" << directory; + return 0L; + } + QStringList size_directory = QString::fromUtf8(du.readAll()).split('\t'); + + if (size_directory.size() > 1) { + return size_directory[0].toULongLong(); + } + + return 0L; +} + +void DiskUsageWorker::submit(QStringList paths, QJSValue *callback) +{ + QVariantMap usage; + + foreach (const QString &path, paths) { + usage[path] = calculateSize(path); + + if (m_quit) { + break; + } + } + + for (QVariantMap::iterator it = usage.begin(); it != usage.end(); ++it) { + const QString &path = it.key(); + qlonglong bytes = it.value().toLongLong(); + + for (QVariantMap::const_iterator it2 = usage.cbegin(); it2 != usage.cend(); ++it2) { + const QString &subpath = it2.key(); + const qlonglong subbytes = it2.value().toLongLong(); + + if (subpath.length() > path.length() && subpath.indexOf(path) == 0) { + bytes -= subbytes; + } + } + + if (it.value() != bytes) { + it.value() = bytes; + } + } + + emit finished(usage, callback); +} + + +class DiskUsagePrivate +{ + Q_DISABLE_COPY(DiskUsagePrivate) + Q_DECLARE_PUBLIC(DiskUsage) + + DiskUsage * const q_ptr; + +public: + DiskUsagePrivate(DiskUsage *usage); + ~DiskUsagePrivate(); + +private: + QThread m_thread; + DiskUsageWorker *m_worker; +}; + +DiskUsagePrivate::DiskUsagePrivate(DiskUsage *usage) + : q_ptr(usage) + , m_thread() + , m_worker(new DiskUsageWorker()) +{ + m_worker->moveToThread(&m_thread); + + QObject::connect(usage, SIGNAL(submit(QStringList, QJSValue *)), + m_worker, SLOT(submit(QStringList, QJSValue *))); + + QObject::connect(m_worker, SIGNAL(finished(QVariantMap, QJSValue *)), + usage, SLOT(finished(QVariantMap, QJSValue *))); + + m_thread.start(); +} + +DiskUsagePrivate::~DiskUsagePrivate() +{ + // Make sure the worker quits as soon as possible + m_worker->scheduleQuit(); + + // Wait for thread to shut down + m_thread.quit(); + if (!m_thread.wait(10 * 1000)) { + qWarning("Worker thread did not quit in time"); + } + + m_worker->deleteLater(); +} + + +DiskUsage::DiskUsage(QObject *parent) + : QObject(parent) + , d_ptr(new DiskUsagePrivate(this)) + , m_working(false) +{ +} + +DiskUsage::~DiskUsage() +{ +} + +void DiskUsage::calculate(const QStringList &paths, QJSValue callback) +{ + QJSValue *cb = 0; + + if (!callback.isNull() && !callback.isUndefined() && callback.isCallable()) { + cb = new QJSValue(callback); + } + + setWorking(true); + emit submit(paths, cb); +} + +void DiskUsage::finished(QVariantMap usage, QJSValue *callback) +{ + if (callback) { + callback->call(QJSValueList() << callback->engine()->toScriptValue(usage)); + delete callback; + } + + setWorking(false); +} diff --git a/src/diskusage.h b/src/diskusage.h new file mode 100644 index 0000000..61aca4f --- /dev/null +++ b/src/diskusage.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Jolla Ltd. + * Contact: Thomas Perl + * + * You may use this file under the terms of the BSD license as follows: + * + * "Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Nemo Mobile nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + */ + +#ifndef DISKUSAGE_H +#define DISKUSAGE_H + +#include +#include +#include +#include + +class DiskUsagePrivate; + +class DiskUsage : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(DiskUsage) + + // True while calculation takes place + Q_PROPERTY(bool working + READ working + NOTIFY workingChanged) + +public: + explicit DiskUsage(QObject *parent=0); + virtual ~DiskUsage(); + + // Calculate the disk usage of the given paths, then call + // callback with a QVariantMap (mapping paths to usages in bytes) + Q_INVOKABLE void calculate(const QStringList &paths, QJSValue callback); + +signals: + void workingChanged(); + +signals: + void submit(QStringList paths, QJSValue *callback); + +private slots: + void finished(QVariantMap usage, QJSValue *callback); + +private: + bool working() const { return m_working; } + + void setWorking(bool working) { + if (m_working != working) { + m_working = working; + emit workingChanged(); + } + } + +private: + QScopedPointer const d_ptr; + bool m_working; +}; + +#endif /* DISKUSAGE_H */ diff --git a/src/diskusage_p.h b/src/diskusage_p.h new file mode 100644 index 0000000..324b07a --- /dev/null +++ b/src/diskusage_p.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Jolla Ltd. + * Contact: Thomas Perl + * + * You may use this file under the terms of the BSD license as follows: + * + * "Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Nemo Mobile nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + */ + +#ifndef DISKUSAGE_P_H +#define DISKUSAGE_P_H + +#include +#include +#include + +class DiskUsageWorker : public QObject +{ + Q_OBJECT + +public: + explicit DiskUsageWorker(QObject *parent=0); + virtual ~DiskUsageWorker(); + + void scheduleQuit() { m_quit = true; } + +public slots: + void submit(QStringList paths, QJSValue *callback); + +signals: + void finished(QVariantMap usage, QJSValue *callback); + +private: + bool m_quit; +}; + +#endif /* DISKUSAGE_P_H */ diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp index 94bd2de..e5f30d0 100644 --- a/src/plugin/plugin.cpp +++ b/src/plugin/plugin.cpp @@ -43,6 +43,7 @@ #include "aboutsettings.h" #include "devicelockiface.h" #include "developermodesettings.h" +#include "diskusage.h" class SystemSettingsPlugin : public QQmlExtensionPlugin { @@ -68,6 +69,7 @@ class SystemSettingsPlugin : public QQmlExtensionPlugin qmlRegisterType(uri, 1, 0, "DeviceLockInterface"); qmlRegisterType(uri, 1, 0, "DeveloperModeSettings"); qRegisterMetaType("DeveloperModeSettings::Status"); + qmlRegisterType(uri, 1, 0, "DiskUsage"); } }; diff --git a/src/src.pro b/src/src.pro index c578422..8631998 100644 --- a/src/src.pro +++ b/src/src.pro @@ -21,7 +21,8 @@ SOURCES += \ usbsettings.cpp \ aboutsettings.cpp \ devicelockiface.cpp \ - developermodesettings.cpp + developermodesettings.cpp \ + diskusage.cpp HEADERS += \ languagemodel.h \ @@ -33,7 +34,9 @@ HEADERS += \ usbsettings.h \ aboutsettings.h \ devicelockiface.h \ - developermodesettings.h + developermodesettings.h \ + diskusage.h \ + diskusage_p.h develheaders.path = /usr/include/systemsettings develheaders.files = $$HEADERS