diff --git a/app/qml/BooksShelfTitle.qml b/app/qml/BooksShelfTitle.qml index ea1ff7c..8f9d54f 100644 --- a/app/qml/BooksShelfTitle.qml +++ b/app/qml/BooksShelfTitle.qml @@ -38,24 +38,16 @@ MouseArea { property alias text: label.text property bool currentFolder property bool editable - property bool _editing property bool _highlighted: pressed property color _highlightedColor: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) property bool _showPress: !currentFolder && (_highlighted || pressTimer.running) signal rename(var to) - - function editName() { - if (editable && !_editing) { - editor.text = text - _editing = true - } - } + signal startEdit() onEditableChanged: { - if (!editable && _editing) { - _editing = false - } + // Sync edit field and the label + if (editable) editor.text = text } Column { @@ -94,13 +86,14 @@ MouseArea { verticalCenter: parent.verticalCenter } onTextChanged: { - if (!_editing) { + if (!editable) { editor.text = text } } color: (currentFolder || pressed) ? Theme.highlightColor : Theme.primaryColor - opacity: _editing ? 0 : 1 visible: opacity > 0 + opacity: editable ? 0 : 1 + Behavior on opacity { FadeAnimation {} } Behavior on color { ColorAnimation { duration: 100 } } } @@ -115,17 +108,17 @@ MouseArea { textLeftMargin: 0 textRightMargin: 0 textTopMargin: 0 - opacity: _editing ? 1 : 0 visible: opacity > 0 + opacity: editable ? 1 : 0 + Behavior on opacity { FadeAnimation {} } //% "Enter folder name" placeholderText: qsTrId("shelf-title-placeholder") EnterKey.enabled: text.length > 0 && text !== "." && text !== ".." && text.indexOf("/") < 0 EnterKey.onClicked: { - if (_editing) { + if (editable) { if (text) { root.rename(text) } - _editing = false parent.focus = true } } @@ -141,6 +134,15 @@ MouseArea { onPressed: pressTimer.start() onCanceled: pressTimer.stop() + onPressAndHold: { + if (currentFolder && !editable) { + root.startEdit() + if (editable) { + editor.forceActiveFocus() + } + } + } + Rectangle { anchors.fill: parent color: _showPress ? _highlightedColor : "transparent" diff --git a/app/qml/BooksShelfView.qml b/app/qml/BooksShelfView.qml index 7e35adf..3ddf383 100644 --- a/app/qml/BooksShelfView.qml +++ b/app/qml/BooksShelfView.qml @@ -70,12 +70,12 @@ SilicaFlickable { onNeedDummyItemChanged: if (needDummyItem) hasDummyItem = true editMode: shelfView.editMode onRelativePathChanged: longStartTimer.restart() + onPathChanged: globalSettings.currentFolder = path } BooksPathModel { id: pathModel path: shelfModel.relativePath - storage: shelfModel.storage } onEditModeChanged: { @@ -176,15 +176,10 @@ SilicaFlickable { BooksShelfTitle { width: grid.width text: model.name - editable: editMode + editable: editMode && currentFolder currentFolder: model.index === (pathModel.count-1) onClicked: { - if (currentFolder) { - if (editMode) { - console.log("editing", model.name) - editName() - } - } else { + if (!currentFolder) { console.log("switching to", model.path) shelfView.stopEditing() shelfModel.relativePath = model.path @@ -192,8 +187,9 @@ SilicaFlickable { } onRename: { console.log(to) - model.name = to + shelfModel.name = to } + onStartEdit: shelfView.startEditing() } } } diff --git a/app/src/BooksPathModel.cpp b/app/src/BooksPathModel.cpp index a675884..f0f0aa5 100644 --- a/app/src/BooksPathModel.cpp +++ b/app/src/BooksPathModel.cpp @@ -63,9 +63,7 @@ void BooksPathModel::setPath(QString aPath) int i; QString path; QStringList pathList; - QStringList parentList; for (i=0; i(aStorage); - if (newStorage) storage.set(*newStorage); - } - if (!iStorage.equal(storage)) { - HDEBUG(storage.booksDir()); - iStorage.set(storage); - Q_EMIT storageChanged(); - } -} - QHash BooksPathModel::roleNames() const { QHash roles; @@ -142,30 +126,3 @@ QVariant BooksPathModel::data(const QModelIndex& aIndex, int aRole) const } return QVariant(); } - -bool BooksPathModel::setData(const QModelIndex& aIndex, const QVariant& aValue, int aRole) -{ - const int i = aIndex.row(); - if (validIndex(i) && aRole == BooksPathModelName && iStorage.isPresent()) { - QString newName(aValue.toString()); - if (iList.at(i).iName != newName) { - const Data& data = iList.at(i); - QString oldPath = iStorage.fullPath(data.iPath); - QString newPath = iStorage.fullPath(data.iParentPath); - newPath += "/"; - newPath += newName; - - HDEBUG("renaming" << qPrintable(oldPath) << "->" << qPrintable(newPath)); - if (rename(qPrintable(oldPath), qPrintable(newPath)) == 0) { - iList[i].iName = newName; - iList[i].iPath = newPath; - QModelIndex index = createIndex(i, 0); - Q_EMIT dataChanged(index, index); - return true; - } else { - HDEBUG(strerror(errno)); - } - } - } - return false; -} diff --git a/app/src/BooksPathModel.h b/app/src/BooksPathModel.h index 18ea5fb..191433d 100644 --- a/app/src/BooksPathModel.h +++ b/app/src/BooksPathModel.h @@ -35,7 +35,6 @@ #define BOOKS_PATH_MODEL_H #include "BooksTypes.h" -#include "BooksStorage.h" #include #include @@ -48,7 +47,6 @@ class BooksPathModel: public QAbstractListModel Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) - Q_PROPERTY(QObject* storage READ storage WRITE setStorage NOTIFY storageChanged) public: explicit BooksPathModel(QObject* aParent = NULL); @@ -56,19 +54,15 @@ public: int count() const { return iList.count(); } QString path() const { return iPath; } void setPath(QString aPath); - QObject* storage() { return &iStorage; } - void setStorage(QObject* aStorage); // QAbstractListModel virtual QHash roleNames() const; virtual int rowCount(const QModelIndex& aParent) const; virtual QVariant data(const QModelIndex& aIndex, int aRole) const; - virtual bool setData(const QModelIndex& aIndex, const QVariant& aValue, int aRole); Q_SIGNALS: void countChanged(); void pathChanged(); - void storageChanged(); private: bool validIndex(int aIndex) const; @@ -76,14 +70,11 @@ private: private: class Data { public: - QString iParentPath; QString iPath; QString iName; - Data(QString aParentPath, QString aPath, QString aName) : - iParentPath(aParentPath), iPath(aPath), iName(aName) {} + Data(QString aPath, QString aName) : iPath(aPath), iName(aName) {} }; - BooksStorage iStorage; QList iList; QString iPath; }; diff --git a/app/src/BooksShelf.cpp b/app/src/BooksShelf.cpp index b672901..9afcff3 100644 --- a/app/src/BooksShelf.cpp +++ b/app/src/BooksShelf.cpp @@ -547,10 +547,6 @@ BooksShelf::BooksShelf(BooksStorage aStorage, QString aRelativePath) : // They also don't need to read the content of the directory - // only the objects allocated by QML do that. QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - int slashPos = aRelativePath.lastIndexOf('/'); - iFileName = (slashPos >= 0) ? - aRelativePath.right(aRelativePath.length() - slashPos - 1) : - aRelativePath; updatePath(); } @@ -590,6 +586,60 @@ void BooksShelf::setDevice(QString aDevice) } } +void BooksShelf::setName(QString aName) +{ + if (iStorage.isValid() && + BooksUtil::isValidFileName(aName) && + iFileName != aName) { + QString parentDir; + const int lastSlash = iRelativePath.lastIndexOf('/'); + if (lastSlash > 0) { + parentDir = iRelativePath.left(lastSlash); + } + + QString newRelativePath; + if (!parentDir.isEmpty()) { + newRelativePath = parentDir; + newRelativePath += '/'; + } + newRelativePath += aName; + + QString oldPath = iStorage.fullPath(iRelativePath); + QString newPath = iStorage.fullPath(newRelativePath); + + HDEBUG("renaming" << qPrintable(oldPath) << "->" << qPrintable(newPath)); + if (rename(qPrintable(oldPath), qPrintable(newPath)) == 0) { + const QString oldFileName(iFileName); + iRelativePath = newRelativePath; + iPath = iStorage.fullPath(iRelativePath); + updateFileName(); + Q_EMIT pathChanged(); + Q_EMIT relativePathChanged(); + + // Since this directiry has been renamed, we need to update the + // order of objects in the parent directory. + QVariantMap state; + const QString stateFile = stateFileName(parentDir); + if (HarbourJson::load(stateFile, state)) { + QVariantList order = state.value(SHELF_STATE_ORDER).toList(); + int i, n = order.count(); + for (i=0; i= 0) ? + iRelativePath.right(iRelativePath.length() - slashPos - 1) : + iRelativePath; + if (iFileName != fileName) { + iFileName = fileName; + Q_EMIT nameChanged(); + } +} + void BooksShelf::onLoadTaskDone() { HASSERT(iLoadTask); @@ -680,7 +743,7 @@ void BooksShelf::saveState() QVariantMap state; state.insert(SHELF_STATE_ORDER, order); if (HarbourJson::save(stateFileName(), state)) { - HDEBUG("wrote" << stateFileName()); + HDEBUG("wrote" << qPrintable(stateFileName())); } } @@ -691,10 +754,10 @@ void BooksShelf::queueStateSave() } } -QString BooksShelf::stateFileName() const +QString BooksShelf::stateFileName(QString aRelativePath) const { return iStorage.isValid() ? - iStorage.configDir().path() + "/" + iRelativePath + ("/" SHELF_STATE_FILE) : + iStorage.configDir().path() + "/" + aRelativePath + ("/" SHELF_STATE_FILE) : QString(); } @@ -745,8 +808,7 @@ void BooksShelf::setEditMode(bool aEditMode) iEditMode = aEditMode; HDEBUG(iEditMode); if (iSaveTimer && iSaveTimer->saveRequested()) { - iSaveTimer->cancelSave(); - saveState(); + iSaveTimer->saveNow(); } setHasDummyItem(false); Q_EMIT editModeChanged(); diff --git a/app/src/BooksShelf.h b/app/src/BooksShelf.h index d1b09c7..0852f87 100644 --- a/app/src/BooksShelf.h +++ b/app/src/BooksShelf.h @@ -56,7 +56,7 @@ class BooksShelf: public QAbstractListModel, public BooksItem, public BooksLoadi Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged) Q_PROPERTY(bool accessible READ accessible CONSTANT) Q_PROPERTY(QString path READ path NOTIFY pathChanged) - Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged) Q_PROPERTY(QString relativePath READ relativePath WRITE setRelativePath NOTIFY relativePathChanged) Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged) @@ -90,6 +90,7 @@ public: void setRelativePath(QString aPath); BooksBook* bookAt(int aIndex) const; QObject* storage() { return &iStorage; } + void setName(QString aName); bool editMode() const { return iEditMode; } void setEditMode(bool aEditMode); @@ -147,6 +148,7 @@ private Q_SLOTS: private: void init(); QString stateFileName() const; + QString stateFileName(QString aRelativePath) const; int bookIndex(BooksBook* aBook) const; int itemIndex(QString aFileName, int aStartIndex = 0) const; bool validIndex(int aIndex) const; @@ -154,6 +156,7 @@ private: void queueStateSave(); void loadBookList(); void updatePath(); + void updateFileName(); void submitDeleteTask(int aIndex); private: @@ -184,5 +187,7 @@ QML_DECLARE_TYPE(BooksShelf) inline bool BooksShelf::validIndex(int aIndex) const { return aIndex >= 0 && aIndex < iList.count(); } +inline QString BooksShelf::stateFileName() const + { return stateFileName(iRelativePath); } #endif // BOOKS_SHELF_MODEL_H diff --git a/app/src/BooksUtil.cpp b/app/src/BooksUtil.cpp index 4b500c5..d20723d 100644 --- a/app/src/BooksUtil.cpp +++ b/app/src/BooksUtil.cpp @@ -77,3 +77,11 @@ shared_ptr BooksUtil::bookFromFile(std::string aPath) } return book; } + +bool BooksUtil::isValidFileName(QString aName) +{ + return !aName.isEmpty() && + aName != QStringLiteral(".") && + aName != QStringLiteral("..") && + !aName.contains('/'); +} diff --git a/app/src/BooksUtil.h b/app/src/BooksUtil.h index 597c1c8..9fa801b 100644 --- a/app/src/BooksUtil.h +++ b/app/src/BooksUtil.h @@ -43,6 +43,7 @@ namespace BooksUtil { shared_ptr bookFromFile(std::string aPath); shared_ptr bookFromFile(QString aPath); + bool isValidFileName(QString aName); } inline shared_ptr BooksUtil::bookFromFile(QString aPath)