[app] Made root directory configurable for removable storage
The dconf entry is /apps/harbour-books/removableRoot
This commit is contained in:
parent
1d4fdeaea9
commit
af9271dff5
12 changed files with 273 additions and 166 deletions
|
@ -39,9 +39,9 @@ ApplicationWindow {
|
|||
allowedOrientations: {
|
||||
switch (Settings.orientation) {
|
||||
default:
|
||||
case BooksSettings.OrientationAny: return Orientation.All
|
||||
case BooksSettings.OrientationPortrait: return Orientation.Portrait
|
||||
case BooksSettings.OrientationLandscape: return Orientation.Landscape
|
||||
case Settings.OrientationAny: return Orientation.All
|
||||
case Settings.OrientationPortrait: return Orientation.Portrait
|
||||
case Settings.OrientationLandscape: return Orientation.Landscape
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#define BOOKS_QML_FILE BOOKS_QML_DIR "/BooksMain.qml"
|
||||
|
||||
#define BOOKS_INTERNAL_ROOT "Documents/Books"
|
||||
#define BOOKS_REMOVABLE_ROOT "Books"
|
||||
|
||||
#define BOOKS_QML_PLUGIN "harbour.books"
|
||||
#define BOOKS_QML_PLUGIN_V1 1
|
||||
|
|
|
@ -47,12 +47,14 @@
|
|||
#define KEY_PAGE_DETAILS "pageDetails"
|
||||
#define KEY_CURRENT_BOOK "currentBook"
|
||||
#define KEY_CURRENT_FOLDER "currentFolder"
|
||||
#define KEY_REMOVABLE_ROOT "removableRoot"
|
||||
#define KEY_INVERT_COLORS "invertColors"
|
||||
#define KEY_ORIENTATION "orientation"
|
||||
#define DEFAULT_FONT_SIZE 0
|
||||
#define DEFAULT_PAGE_DETAILS 0
|
||||
#define DEFAULT_CURRENT_BOOK QString()
|
||||
#define DEFAULT_CURRENT_FOLDER QString()
|
||||
#define DEFAULT_REMOVABLE_ROOT "Books"
|
||||
#define DEFAULT_INVERT_COLORS false
|
||||
#define DEFAULT_ORIENTATION (BooksSettings::OrientationAny)
|
||||
|
||||
|
@ -227,6 +229,7 @@ public:
|
|||
MGConfItem* iCurrentFolderConf;
|
||||
MGConfItem* iCurrentBookPathConf;
|
||||
MGConfItem* iOrientationConf;
|
||||
MGConfItem* iRemovableRootConf;
|
||||
mutable shared_ptr<ZLTextStyle> iTextStyle[FontSizeSteps+1];
|
||||
BooksBook* iCurrentBook;
|
||||
QString iCurrentStorageDevice;
|
||||
|
@ -244,11 +247,10 @@ BooksSettings::Private::Private(BooksSettings* aParent) :
|
|||
iCurrentFolderConf(new MGConfItem(DCONF_PATH KEY_CURRENT_FOLDER, this)),
|
||||
iCurrentBookPathConf(new MGConfItem(DCONF_PATH KEY_CURRENT_BOOK, this)),
|
||||
iOrientationConf(new MGConfItem(DCONF_PATH KEY_ORIENTATION, this)),
|
||||
iRemovableRootConf(new MGConfItem(DCONF_PATH KEY_REMOVABLE_ROOT, this)),
|
||||
iCurrentBook(NULL)
|
||||
{
|
||||
iFontSize = currentFontSize();
|
||||
updateCurrentBook();
|
||||
updateCurrentStorage();
|
||||
connect(iFontSizeConf, SIGNAL(valueChanged()), SLOT(onFontSizeValueChanged()));
|
||||
connect(iCurrentFolderConf, SIGNAL(valueChanged()), SLOT(onCurrentFolderChanged()));
|
||||
connect(iCurrentBookPathConf, SIGNAL(valueChanged()), SLOT(onCurrentBookPathChanged()));
|
||||
|
@ -256,6 +258,7 @@ BooksSettings::Private::Private(BooksSettings* aParent) :
|
|||
connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(invertColorsChanged()));
|
||||
connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageBackgroundColorChanged()));
|
||||
connect(iOrientationConf, SIGNAL(valueChanged()), iParent, SIGNAL(orientationChanged()));
|
||||
connect(iRemovableRootConf, SIGNAL(valueChanged()), iParent, SIGNAL(removableRootChanged()));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -406,7 +409,7 @@ BooksSettings::Private::onCurrentBookPathChanged()
|
|||
// BooksSettings
|
||||
// ==========================================================================
|
||||
|
||||
BooksSettings::BooksSettings(QObject* aParent) : QObject(aParent),
|
||||
BooksSettings::BooksSettings() :
|
||||
iPrivate(new Private(this))
|
||||
{
|
||||
}
|
||||
|
@ -420,6 +423,15 @@ BooksSettings::sharedInstance()
|
|||
// recipient of the signal drops the last shared reference.
|
||||
instance = QSharedPointer<BooksSettings>(new BooksSettings, &QObject::deleteLater);
|
||||
Private::sSharedInstance = instance;
|
||||
// Finish initialization. These invoke BooksStorageManager::instance()
|
||||
// which in turn calls BooksSettings::sharedInstance() to call
|
||||
// removableRoot(). Now that Private::sSharedInstance is set, it
|
||||
// won't cause infinite recursion although the returned BooksSettings
|
||||
// object will be slightly under-initialized, so to speak. But that's
|
||||
// ok as long as BooksStorageManager::instance() doesn't need anything
|
||||
// from BooksSettings other than removableRoot()
|
||||
instance->iPrivate->updateCurrentBook();
|
||||
instance->iPrivate->updateCurrentStorage();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
@ -501,6 +513,12 @@ BooksSettings::setInvertColors(
|
|||
iPrivate->iInvertColorsConf->set(aValue);
|
||||
}
|
||||
|
||||
QString
|
||||
BooksSettings::removableRoot() const
|
||||
{
|
||||
return iPrivate->iRemovableRootConf->value(DEFAULT_REMOVABLE_ROOT).toString();
|
||||
}
|
||||
|
||||
QString
|
||||
BooksSettings::relativePath() const
|
||||
{
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
|
||||
#include "BooksTypes.h"
|
||||
#include "ZLTextStyle.h"
|
||||
#include <QObject>
|
||||
#include <QColor>
|
||||
#include <QtQml>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class BooksSettings : public QObject
|
||||
|
@ -52,12 +52,16 @@ class BooksSettings : public QObject
|
|||
Q_PROPERTY(QString currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged)
|
||||
Q_PROPERTY(QString currentStorage READ currentStorage NOTIFY currentStorageChanged)
|
||||
Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged)
|
||||
Q_PROPERTY(QString removableRoot READ removableRoot NOTIFY removableRootChanged)
|
||||
Q_PROPERTY(QColor primaryPageToolColor READ primaryPageToolColor CONSTANT)
|
||||
Q_PROPERTY(QColor highlightPageToolColor READ highlightPageToolColor NOTIFY invertColorsChanged)
|
||||
Q_PROPERTY(QColor pageBackgroundColor READ pageBackgroundColor NOTIFY pageBackgroundColorChanged)
|
||||
Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged)
|
||||
class TextStyle;
|
||||
|
||||
// Use sharedInstance() to instantiate this class
|
||||
BooksSettings();
|
||||
|
||||
public:
|
||||
enum FontSize {
|
||||
MinFontSize = -5,
|
||||
|
@ -72,8 +76,6 @@ public:
|
|||
OrientationLandscape
|
||||
};
|
||||
|
||||
explicit BooksSettings(QObject* aParent = NULL);
|
||||
|
||||
static QSharedPointer<BooksSettings> sharedInstance();
|
||||
|
||||
Q_INVOKABLE bool increaseFontSize();
|
||||
|
@ -94,6 +96,7 @@ public:
|
|||
void setCurrentBook(QObject* aBook);
|
||||
|
||||
QString relativePath() const;
|
||||
QString removableRoot() const;
|
||||
QString currentFolder() const;
|
||||
void setCurrentFolder(QString aValue);
|
||||
|
||||
|
@ -113,6 +116,7 @@ Q_SIGNALS:
|
|||
void currentFolderChanged();
|
||||
void currentStorageChanged();
|
||||
void relativePathChanged();
|
||||
void removableRootChanged();
|
||||
void pageBackgroundColorChanged();
|
||||
void orientationChanged();
|
||||
|
||||
|
@ -121,6 +125,4 @@ private:
|
|||
Private* iPrivate;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksSettings)
|
||||
|
||||
#endif // BOOKS_SETTINGS_H
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -516,7 +516,9 @@ void BooksShelf::init()
|
|||
#if QT_VERSION < 0x050000
|
||||
setRoleNames(roleNames());
|
||||
#endif
|
||||
QQmlEngine::setObjectOwnership(&iStorage, QQmlEngine::CppOwnership);
|
||||
connect(BooksStorageManager::instance(),
|
||||
SIGNAL(storageReplaced(BooksStorage,BooksStorage)),
|
||||
SLOT(onStorageReplaced(BooksStorage,BooksStorage)));
|
||||
}
|
||||
|
||||
void BooksShelf::setRelativePath(QString aPath)
|
||||
|
@ -537,6 +539,14 @@ void BooksShelf::setDevice(QString aDevice)
|
|||
}
|
||||
}
|
||||
|
||||
void BooksShelf::onStorageReplaced(BooksStorage aOld, BooksStorage aNew)
|
||||
{
|
||||
if (iStorage == aOld) {
|
||||
iStorage = aNew;
|
||||
updatePath();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksShelf::setName(QString aName)
|
||||
{
|
||||
if (iStorage.isValid() &&
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -147,6 +147,7 @@ private Q_SLOTS:
|
|||
void onCopyTaskProgressChanged();
|
||||
void onCopyTaskDone();
|
||||
void onDeleteTaskDone();
|
||||
void onStorageReplaced(BooksStorage aOldStorage, BooksStorage aNewStorage);
|
||||
void saveState();
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -32,6 +32,7 @@
|
|||
*/
|
||||
|
||||
#include "BooksStorage.h"
|
||||
#include "BooksSettings.h"
|
||||
#include "BooksDefs.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
@ -62,7 +63,8 @@ class BooksStorage::Private: public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Private(QString aDevice, QDir aBooksDir, bool aInternal);
|
||||
Private(QString aDevice, QString aMountPoint, QString aBooksDir,
|
||||
bool aInternal);
|
||||
|
||||
bool isRemoved() const;
|
||||
bool equal(const Private& aData) const;
|
||||
|
@ -76,14 +78,23 @@ Q_SIGNALS:
|
|||
public:
|
||||
QAtomicInt iRef;
|
||||
QString iDevice;
|
||||
QString iMountPoint;
|
||||
QDir iBooksDir;
|
||||
QDir iConfigDir;
|
||||
bool iInternal;
|
||||
bool iPresent;
|
||||
};
|
||||
|
||||
BooksStorage::Private::Private(QString aDevice, QDir aBooksDir, bool aInternal) :
|
||||
iRef(1), iDevice(aDevice), iBooksDir(aBooksDir), iInternal(aInternal),
|
||||
BooksStorage::Private::Private(
|
||||
QString aDevice,
|
||||
QString aMountPoint,
|
||||
QString aBooksDir,
|
||||
bool aInternal) :
|
||||
iRef(1),
|
||||
iDevice(aDevice),
|
||||
iMountPoint(aMountPoint),
|
||||
iBooksDir(aBooksDir),
|
||||
iInternal(aInternal),
|
||||
iPresent(true)
|
||||
{
|
||||
QString cfgDir;
|
||||
|
@ -97,7 +108,7 @@ BooksStorage::Private::Private(QString aDevice, QDir aBooksDir, bool aInternal)
|
|||
cfgDir += subDir;
|
||||
} else {
|
||||
cfgDir += REMOVABLE_STATE_DIR "/";
|
||||
QString label = QDir(Private::mountPoint(aBooksDir.path())).dirName();
|
||||
QString label = QDir(Private::mountPoint(aBooksDir)).dirName();
|
||||
if (label.isEmpty()) label = "sdcard";
|
||||
cfgDir += label;
|
||||
}
|
||||
|
@ -106,10 +117,12 @@ BooksStorage::Private::Private(QString aDevice, QDir aBooksDir, bool aInternal)
|
|||
|
||||
bool BooksStorage::Private::equal(const BooksStorage::Private& aData) const
|
||||
{
|
||||
return iInternal == iInternal &&
|
||||
iPresent == iPresent &&
|
||||
return iInternal == aData.iInternal &&
|
||||
iPresent == aData.iPresent &&
|
||||
iMountPoint == aData.iMountPoint &&
|
||||
iDevice == aData.iDevice &&
|
||||
iBooksDir == aData.iBooksDir;
|
||||
iBooksDir == aData.iBooksDir &&
|
||||
iConfigDir == aData.iConfigDir;
|
||||
}
|
||||
|
||||
bool BooksStorage::Private::isMountPoint(QString aPath)
|
||||
|
@ -153,9 +166,9 @@ BooksStorage::BooksStorage(const BooksStorage& aStorage) :
|
|||
if (iPrivate) iPrivate->iRef.ref();
|
||||
}
|
||||
|
||||
BooksStorage::BooksStorage(QString aDevice, QDir aBooksDir, bool aInternal) :
|
||||
QObject(NULL),
|
||||
iPrivate(new Private(aDevice, aBooksDir, aInternal)),
|
||||
BooksStorage::BooksStorage(QString aDevice, QString aMount, QString aBooksDir,
|
||||
bool aInternal) : QObject(NULL),
|
||||
iPrivate(new Private(aDevice, aMount, aBooksDir, aInternal)),
|
||||
iPassThrough(false)
|
||||
{
|
||||
HDEBUG("config dir" << qPrintable(configDir().path()));
|
||||
|
@ -253,17 +266,26 @@ void BooksStorage::set(const BooksStorage& aStorage)
|
|||
#define STORAGE_SCAN_INTERVAL 100
|
||||
#define STORAGE_SCAN_TIMEOUT 5000
|
||||
|
||||
class BooksStorageManager::Private {
|
||||
class BooksStorageManager::Private : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static BooksStorageManager* gInstance;
|
||||
|
||||
Private();
|
||||
Private(BooksStorageManager* aParent);
|
||||
~Private();
|
||||
|
||||
int findDevice(QString aDevice) const;
|
||||
int findPath(QString aPath, QString* aRelPath) const;
|
||||
bool scanMounts();
|
||||
|
||||
public Q_SLOTS:
|
||||
void onDeviceEvent(int);
|
||||
void onRemovableRootChanged();
|
||||
void onScanMounts();
|
||||
|
||||
public:
|
||||
BooksStorageManager* iParent;
|
||||
QSharedPointer<BooksSettings> iSettings;
|
||||
QList<BooksStorage> iStorageList;
|
||||
struct udev* iUdev;
|
||||
struct udev_monitor* iMonitor;
|
||||
|
@ -275,7 +297,10 @@ public:
|
|||
|
||||
BooksStorageManager* BooksStorageManager::Private::gInstance = NULL;
|
||||
|
||||
BooksStorageManager::Private::Private() :
|
||||
BooksStorageManager::Private::Private(BooksStorageManager* aParent) :
|
||||
QObject(aParent),
|
||||
iParent(aParent),
|
||||
iSettings(BooksSettings::sharedInstance()),
|
||||
iUdev(udev_new()),
|
||||
iMonitor(NULL),
|
||||
iDescriptor(-1),
|
||||
|
@ -303,21 +328,22 @@ BooksStorageManager::Private::Private() :
|
|||
QString mount(entries.at(1));
|
||||
if (mount == homeMount) {
|
||||
homeDevice = entries.at(0);
|
||||
HDEBUG("home device" << homeDevice);
|
||||
HDEBUG("internal" << homeDevice);
|
||||
} else if (mount.startsWith(mediaPrefix)) {
|
||||
QString dev = entries.at(0);
|
||||
QString path = mount;
|
||||
QString path(mount);
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += QLatin1String(BOOKS_REMOVABLE_ROOT);
|
||||
HDEBUG("removable device" << dev << path);
|
||||
iStorageList.append(BooksStorage(dev, path, false));
|
||||
path += iSettings->removableRoot();
|
||||
BooksStorage bs(dev, mount, path, false);
|
||||
HDEBUG("removable" << dev << bs.booksDir().path());
|
||||
iStorageList.append(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
mounts.close();
|
||||
}
|
||||
|
||||
iStorageList.insert(0, BooksStorage(homeDevice, homeBooks, true));
|
||||
iStorageList.insert(0, BooksStorage(homeDevice, homeMount, homeBooks, true));
|
||||
|
||||
if (iUdev) {
|
||||
iMonitor = udev_monitor_new_from_netlink(iUdev, "udev");
|
||||
|
@ -329,9 +355,28 @@ BooksStorageManager::Private::Private() :
|
|||
if (iDescriptor >= 0) {
|
||||
iNotifier = new QSocketNotifier(iDescriptor,
|
||||
QSocketNotifier::Read);
|
||||
connect(iNotifier, SIGNAL(activated(int)),
|
||||
SLOT(onDeviceEvent(int)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connect(iSettings.data(), SIGNAL(removableRootChanged()),
|
||||
SLOT(onRemovableRootChanged()));
|
||||
}
|
||||
|
||||
BooksStorageManager::Private::~Private()
|
||||
{
|
||||
if (iUdev) {
|
||||
if (iMonitor) {
|
||||
if (iDescriptor >= 0) {
|
||||
delete iNotifier;
|
||||
close(iDescriptor);
|
||||
}
|
||||
udev_monitor_unref(iMonitor);
|
||||
}
|
||||
udev_unref(iUdev);
|
||||
}
|
||||
}
|
||||
|
||||
int BooksStorageManager::Private::findDevice(QString aDevice) const
|
||||
|
@ -369,17 +414,127 @@ int BooksStorageManager::Private::findPath(QString aPath, QString* aRelPath) con
|
|||
return -1;
|
||||
}
|
||||
|
||||
BooksStorageManager::Private::~Private()
|
||||
bool BooksStorageManager::Private::scanMounts()
|
||||
{
|
||||
if (iUdev) {
|
||||
if (iMonitor) {
|
||||
if (iDescriptor >= 0) {
|
||||
delete iNotifier;
|
||||
close(iDescriptor);
|
||||
bool newStorageFound = false;
|
||||
QList<BooksStorage> newMounts;
|
||||
QFile mounts(STORAGE_MOUNTS_FILE);
|
||||
if (mounts.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// For some reason QTextStream can't read /proc/mounts line by line
|
||||
QByteArray contents = mounts.readAll();
|
||||
QTextStream in(&contents);
|
||||
QString mediaPrefix(STORAGE_MOUNT_PREFIX);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
QStringList entries = line.split(' ', QString::SkipEmptyParts);
|
||||
if (entries.count() > 2) {
|
||||
QString mount(entries.at(1));
|
||||
if (mount.startsWith(mediaPrefix)) {
|
||||
QString dev = entries.at(0);
|
||||
int index = findDevice(dev);
|
||||
if (index < 0) {
|
||||
QString path = mount;
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += iSettings->removableRoot();
|
||||
HDEBUG("new removable device" << dev << path);
|
||||
BooksStorage storage(dev, mount, path, false);
|
||||
iStorageList.append(storage);
|
||||
Q_EMIT iParent->storageAdded(storage);
|
||||
newStorageFound = true;
|
||||
}
|
||||
udev_monitor_unref(iMonitor);
|
||||
}
|
||||
udev_unref(iUdev);
|
||||
}
|
||||
}
|
||||
mounts.close();
|
||||
}
|
||||
return newStorageFound;
|
||||
}
|
||||
|
||||
void BooksStorageManager::Private::onScanMounts()
|
||||
{
|
||||
if (scanMounts()) {
|
||||
iScanMountsTimer->stop();
|
||||
} else {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
if (now > iScanDeadline) {
|
||||
HDEBUG("timeout waiting for new mount to appear");
|
||||
iScanMountsTimer->stop();
|
||||
} else {
|
||||
HDEBUG("no new mounts found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksStorageManager::Private::onDeviceEvent(int)
|
||||
{
|
||||
struct udev_device* dev = udev_monitor_receive_device(iMonitor);
|
||||
if (dev) {
|
||||
const char* devnode = udev_device_get_devnode(dev);
|
||||
const char* action = udev_device_get_action(dev);
|
||||
HDEBUG("got device");
|
||||
HDEBUG(" node:" << devnode);
|
||||
HDEBUG(" subsystem:" << udev_device_get_subsystem(dev));
|
||||
HDEBUG(" devtype:" << udev_device_get_devtype(dev));
|
||||
HDEBUG(" action:" << action);
|
||||
if (devnode && action) {
|
||||
if (!(strcmp(action, STORAGE_ACTION_ADD))) {
|
||||
// Mount list isn't updated yet when we receive this
|
||||
// notification. It takes hundreds of milliseconds until
|
||||
// it gets mounted and becomes accessible.
|
||||
if (!scanMounts()) {
|
||||
HDEBUG("no new mounts found");
|
||||
if (!iScanMountsTimer) {
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setSingleShot(false);
|
||||
timer->setInterval(STORAGE_SCAN_INTERVAL);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(onScanMounts()));
|
||||
iScanMountsTimer = timer;
|
||||
}
|
||||
iScanMountsTimer->start();
|
||||
iScanDeadline = QDateTime::currentDateTime().
|
||||
addMSecs(STORAGE_SCAN_TIMEOUT);
|
||||
}
|
||||
} else if (!(strcmp(action, STORAGE_ACTION_REMOVE))) {
|
||||
int pos = findDevice(devnode);
|
||||
if (pos >= 0) {
|
||||
HDEBUG("removable device is gone");
|
||||
BooksStorage storage = iStorageList.takeAt(pos);
|
||||
storage.iPrivate->iPresent = false;
|
||||
Q_EMIT storage.iPrivate->removed();
|
||||
Q_EMIT iParent->storageRemoved(storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
} else {
|
||||
HWARN("no device!");
|
||||
}
|
||||
}
|
||||
|
||||
void BooksStorageManager::Private::onRemovableRootChanged()
|
||||
{
|
||||
int i;
|
||||
HDEBUG(iSettings->removableRoot());
|
||||
QList<BooksStorage> replaced; // old-new pairs
|
||||
for (i=iStorageList.count()-1; i>=0; i--) {
|
||||
BooksStorage storage = iStorageList.at(i);
|
||||
if (!storage.isInternal()) {
|
||||
QString path(storage.iPrivate->iMountPoint);
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += iSettings->removableRoot();
|
||||
BooksStorage updated(storage.iPrivate->iDevice,
|
||||
storage.iPrivate->iMountPoint, path, false);
|
||||
if (!storage.equal(updated)) {
|
||||
replaced.append(storage);
|
||||
replaced.append(updated);
|
||||
iStorageList.replace(i, updated);
|
||||
} else {
|
||||
HWARN(storage.root() << "didn't change");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; (i+1)<replaced.count(); i+=2) {
|
||||
Q_EMIT iParent->storageReplaced(replaced.at(i), replaced.at(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,12 +557,8 @@ void BooksStorageManager::deleteInstance()
|
|||
}
|
||||
|
||||
BooksStorageManager::BooksStorageManager() :
|
||||
iPrivate(new Private)
|
||||
iPrivate(new Private(this))
|
||||
{
|
||||
if (iPrivate->iNotifier) {
|
||||
connect(iPrivate->iNotifier, SIGNAL(activated(int)),
|
||||
SLOT(onDeviceEvent(int)));
|
||||
}
|
||||
}
|
||||
|
||||
BooksStorageManager::~BooksStorageManager()
|
||||
|
@ -415,7 +566,6 @@ BooksStorageManager::~BooksStorageManager()
|
|||
if (Private::gInstance == this) {
|
||||
Private::gInstance = NULL;
|
||||
}
|
||||
delete iPrivate;
|
||||
}
|
||||
|
||||
int BooksStorageManager::count() const
|
||||
|
@ -440,100 +590,4 @@ BooksStorage BooksStorageManager::storageForPath(QString aPath, QString* aRelPat
|
|||
return (index >= 0) ? iPrivate->iStorageList.at(index) : BooksStorage();
|
||||
}
|
||||
|
||||
void BooksStorageManager::onDeviceEvent(int)
|
||||
{
|
||||
struct udev_device* dev = udev_monitor_receive_device(iPrivate->iMonitor);
|
||||
if (dev) {
|
||||
const char* devnode = udev_device_get_devnode(dev);
|
||||
const char* action = udev_device_get_action(dev);
|
||||
HDEBUG("got device");
|
||||
HDEBUG(" node:" << devnode);
|
||||
HDEBUG(" subsystem:" << udev_device_get_subsystem(dev));
|
||||
HDEBUG(" devtype:" << udev_device_get_devtype(dev));
|
||||
HDEBUG(" action:" << action);
|
||||
if (devnode && action) {
|
||||
if (!(strcmp(action, STORAGE_ACTION_ADD))) {
|
||||
// Mount list isn't updated yet when we receive this
|
||||
// notification. It takes hundreds of milliseconds until
|
||||
// it gets mounted and becomes accessible.
|
||||
if (!scanMounts()) {
|
||||
HDEBUG("no new mounts found");
|
||||
if (!iPrivate->iScanMountsTimer) {
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setSingleShot(false);
|
||||
timer->setInterval(STORAGE_SCAN_INTERVAL);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(onScanMounts()));
|
||||
iPrivate->iScanMountsTimer = timer;
|
||||
}
|
||||
iPrivate->iScanMountsTimer->start();
|
||||
iPrivate->iScanDeadline = QDateTime::currentDateTime().
|
||||
addMSecs(STORAGE_SCAN_TIMEOUT);
|
||||
}
|
||||
} else if (!(strcmp(action, STORAGE_ACTION_REMOVE))) {
|
||||
int pos = iPrivate->findDevice(devnode);
|
||||
if (pos >= 0) {
|
||||
HDEBUG("removable device is gone");
|
||||
BooksStorage storage = iPrivate->iStorageList.takeAt(pos);
|
||||
storage.iPrivate->iPresent = false;
|
||||
Q_EMIT storage.iPrivate->removed();
|
||||
Q_EMIT storageRemoved(storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
} else {
|
||||
HWARN("no device!");
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksStorageManager::scanMounts()
|
||||
{
|
||||
bool newStorageFound = false;
|
||||
QFile mounts(STORAGE_MOUNTS_FILE);
|
||||
if (mounts.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// For some reason QTextStream can't read /proc/mounts line by line
|
||||
QByteArray contents = mounts.readAll();
|
||||
QTextStream in(&contents);
|
||||
QString mediaPrefix(STORAGE_MOUNT_PREFIX);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
QStringList entries = line.split(' ', QString::SkipEmptyParts);
|
||||
if (entries.count() > 2) {
|
||||
QString mount(entries.at(1));
|
||||
if (mount.startsWith(mediaPrefix)) {
|
||||
QString dev = entries.at(0);
|
||||
int index = iPrivate->findDevice(dev);
|
||||
if (index < 0) {
|
||||
QString path = mount;
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += QLatin1String(BOOKS_REMOVABLE_ROOT);
|
||||
HDEBUG("new removable device" << dev << path);
|
||||
BooksStorage storage(dev, path, false);
|
||||
iPrivate->iStorageList.append(storage);
|
||||
Q_EMIT storageAdded(storage);
|
||||
newStorageFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mounts.close();
|
||||
}
|
||||
return newStorageFound;
|
||||
}
|
||||
|
||||
void BooksStorageManager::onScanMounts()
|
||||
{
|
||||
if (scanMounts()) {
|
||||
iPrivate->iScanMountsTimer->stop();
|
||||
} else {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
if (now > iPrivate->iScanDeadline) {
|
||||
HDEBUG("timeout waiting for new mount to appear");
|
||||
iPrivate->iScanMountsTimer->stop();
|
||||
} else {
|
||||
HDEBUG("no new mounts found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "BooksStorage.moc"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -38,6 +38,7 @@
|
|||
#include <QList>
|
||||
#include <QDir>
|
||||
|
||||
class BooksSettings;
|
||||
class BooksStorageManager;
|
||||
|
||||
class BooksStorage: public QObject
|
||||
|
@ -76,7 +77,7 @@ Q_SIGNALS:
|
|||
|
||||
private:
|
||||
friend class BooksStorageManager;
|
||||
BooksStorage(QString, QDir, bool);
|
||||
BooksStorage(QString, QString, QString, bool);
|
||||
void connectNotify(const QMetaMethod& aSignal);
|
||||
|
||||
private:
|
||||
|
@ -102,14 +103,10 @@ public:
|
|||
Q_SIGNALS:
|
||||
void storageAdded(BooksStorage aStorage);
|
||||
void storageRemoved(BooksStorage aStorage);
|
||||
void storageReplaced(BooksStorage aOldStorage, BooksStorage aNewStorage);
|
||||
|
||||
private:
|
||||
BooksStorageManager();
|
||||
bool scanMounts();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onDeviceEvent(int);
|
||||
void onScanMounts();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -90,6 +90,9 @@ BooksStorageModel::BooksStorageModel(QObject* aParent) :
|
|||
connect(mgr,
|
||||
SIGNAL(storageRemoved(BooksStorage)),
|
||||
SLOT(onStorageRemoved(BooksStorage)));
|
||||
connect(mgr,
|
||||
SIGNAL(storageReplaced(BooksStorage,BooksStorage)),
|
||||
SLOT(onStorageReplaced(BooksStorage,BooksStorage)));
|
||||
}
|
||||
|
||||
BooksStorageModel::~BooksStorageModel()
|
||||
|
@ -210,6 +213,24 @@ void BooksStorageModel::onStorageRemoved(BooksStorage aStorage)
|
|||
endRemoveRows();
|
||||
Q_EMIT countChanged();
|
||||
} else {
|
||||
HWARN("device not dfound on the list");
|
||||
HWARN("device not found on the list");
|
||||
}
|
||||
}
|
||||
|
||||
void BooksStorageModel::onStorageReplaced(BooksStorage aOld, BooksStorage aNew)
|
||||
{
|
||||
int index = find(aOld);
|
||||
if (index >=0) {
|
||||
QModelIndex modelIndex(createIndex(index, 0));
|
||||
QVector<int> roles(4);
|
||||
roles.append(BooksStorageRoot);
|
||||
roles.append(BooksStorageDevice);
|
||||
roles.append(BooksStorageRemovable);
|
||||
roles.append(BooksStorageDeleteAllRequest);
|
||||
HWARN(aOld.root() << "->" << aNew.root());
|
||||
iList.at(index)->iStorage = aNew;
|
||||
Q_EMIT dataChanged(modelIndex, modelIndex, roles);
|
||||
} else {
|
||||
HWARN("device not found on the list");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -72,6 +72,7 @@ Q_SIGNALS:
|
|||
private Q_SLOTS:
|
||||
void onStorageAdded(BooksStorage aStorage);
|
||||
void onStorageRemoved(BooksStorage aStorage);
|
||||
void onStorageReplaced(BooksStorage aOldStorage, BooksStorage aNewStorage);
|
||||
|
||||
private:
|
||||
bool validIndex(int aIndex) const;
|
||||
|
|
|
@ -171,7 +171,6 @@ bool ZLibrary::init(int& aArgc, char** &aArgv)
|
|||
}
|
||||
HDEBUG("screen" << booksPPI << "dpi");
|
||||
|
||||
BooksStorageManager::instance();
|
||||
ZLQtTimeManager::createInstance();
|
||||
ZLQtFSManager::createInstance();
|
||||
BooksDialogManager::createInstance();
|
||||
|
@ -179,6 +178,13 @@ bool ZLibrary::init(int& aArgc, char** &aArgv)
|
|||
ZLEncodingCollection::Instance().registerProvider(new IConvEncodingConverterProvider());
|
||||
ZLApplication::Instance();
|
||||
ZLFile::initCache();
|
||||
|
||||
// Due to the weird inter-dependency between BooksSettings and
|
||||
// BooksStorageManager, BooksSettings has to be created first.
|
||||
// Doing it the other way around will result in two instances of
|
||||
// BooksStorageManager being created :)
|
||||
QSharedPointer<BooksSettings> settings = BooksSettings::sharedInstance();
|
||||
BooksStorageManager::instance();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
|
@ -37,7 +37,6 @@
|
|||
#include "BooksBookModel.h"
|
||||
#include "BooksCoverModel.h"
|
||||
#include "BooksConfig.h"
|
||||
#include "BooksSettings.h"
|
||||
#include "BooksImportModel.h"
|
||||
#include "BooksPathModel.h"
|
||||
#include "BooksStorageModel.h"
|
||||
|
@ -79,7 +78,6 @@ Q_DECL_EXPORT int main(int argc, char **argv)
|
|||
BOOKS_QML_REGISTER(BooksPageWidget, "PageWidget");
|
||||
BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher");
|
||||
BOOKS_QML_REGISTER(BooksCoverWidget, "BookCover");
|
||||
BOOKS_QML_REGISTER(BooksSettings, "BooksSettings");
|
||||
BOOKS_QML_REGISTER(BooksHints, "BooksHints");
|
||||
HarbourLib::registerTypes(BOOKS_QML_PLUGIN,
|
||||
BOOKS_QML_PLUGIN_V1, BOOKS_QML_PLUGIN_V2);
|
||||
|
|
Loading…
Reference in a new issue