diff --git a/QtClient/JoplinQtClient/FolderList.qml b/QtClient/JoplinQtClient/FolderList.qml index eeceecca3..176029012 100755 --- a/QtClient/JoplinQtClient/FolderList.qml +++ b/QtClient/JoplinQtClient/FolderList.qml @@ -21,6 +21,13 @@ Item { currentItem.stopEditing(); } + function selectItemById(id) { + currentItemId = id + var newIndex = listView.model.idToIndex(currentItemId); + currentIndex = newIndex + if (newIndex < 0) currentItemId = ""; + } + Rectangle { color: "#eeeeff" border.color: "#ff0000" @@ -33,9 +40,7 @@ Item { target: model onDataChanged: { if (currentItemId !== "") { - var newIndex = model.idToIndex(currentItemId); - currentIndex = newIndex - if (newIndex < 0) currentItemId = ""; + selectItemById(currentItemId); } } } diff --git a/QtClient/JoplinQtClient/JoplinQtClient.pro b/QtClient/JoplinQtClient/JoplinQtClient.pro index a9b892f99..8cc7f1dd9 100755 --- a/QtClient/JoplinQtClient/JoplinQtClient.pro +++ b/QtClient/JoplinQtClient/JoplinQtClient.pro @@ -16,7 +16,6 @@ SOURCES += \ webapi.cpp \ synchronizer.cpp \ settings.cpp \ - models/foldercollection.cpp \ uuid.cpp \ dispatcher.cpp @@ -46,7 +45,6 @@ HEADERS += \ webapi.h \ synchronizer.h \ settings.h \ - models/foldercollection.h \ simpletypes.h \ uuid.h \ dispatcher.h diff --git a/QtClient/JoplinQtClient/application.h b/QtClient/JoplinQtClient/application.h index aa8fd42ed..54d8a183d 100755 --- a/QtClient/JoplinQtClient/application.h +++ b/QtClient/JoplinQtClient/application.h @@ -6,7 +6,6 @@ #include "database.h" #include "models/foldermodel.h" #include "models/notecollection.h" -#include "models/foldercollection.h" #include "models/notemodel.h" #include "models/qmlnote.h" #include "webapi.h" diff --git a/QtClient/JoplinQtClient/database.cpp b/QtClient/JoplinQtClient/database.cpp index 1b7481a76..ea2295f1d 100755 --- a/QtClient/JoplinQtClient/database.cpp +++ b/QtClient/JoplinQtClient/database.cpp @@ -95,6 +95,20 @@ QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &table return query; } +bool Database::errorCheck(const QSqlQuery& query) { + if (query.lastError().isValid()) { + qCritical().noquote() << "SQL query error: " << query.lastError().text().trimmed() << ". Query was: " << query.lastQuery(); + QMapIterator i(query.boundValues()); + while (i.hasNext()) { + i.next(); + qCritical() << i.key() << "=" << i.value().toString(); + } + return false; + } + return true; +} + + int Database::version() const { if (version_ >= 0) return version_; diff --git a/QtClient/JoplinQtClient/database.h b/QtClient/JoplinQtClient/database.h index cabdedf53..05b369186 100755 --- a/QtClient/JoplinQtClient/database.h +++ b/QtClient/JoplinQtClient/database.h @@ -17,6 +17,7 @@ public: QSqlQuery query(const QString& sql) const; QSqlDatabase& database(); QSqlQuery buildSqlQuery(Database::QueryType type, const QString& tableName, const QStringList& fields, const VariantVector& values, const QString& whereCondition = ""); + bool errorCheck(const QSqlQuery& query); private: diff --git a/QtClient/JoplinQtClient/main.qml b/QtClient/JoplinQtClient/main.qml index 26fa340cb..1a0211879 100755 --- a/QtClient/JoplinQtClient/main.qml +++ b/QtClient/JoplinQtClient/main.qml @@ -35,7 +35,9 @@ Item { onEditingAccepted: function(index, text) { if (folderList.model.virtualItemShown()) { + folderList.model.hideVirtualItem(); folderList.model.addData(text) + folderList.selectItemById(folderList.model.lastInsertId()); } else { folderList.model.setData(index, text) } diff --git a/QtClient/JoplinQtClient/models/foldercollection.cpp b/QtClient/JoplinQtClient/models/foldercollection.cpp index 888dc5514..41a02bf1a 100755 --- a/QtClient/JoplinQtClient/models/foldercollection.cpp +++ b/QtClient/JoplinQtClient/models/foldercollection.cpp @@ -16,7 +16,7 @@ FolderCollection::FolderCollection(Database& db, const QString& parentId, const Folder FolderCollection::at(int index) const { if (cache_.size()) { - if (index < 0 || index >= count()) { + if (index < 0 || index >= cache_.size()) { qWarning() << "Invalid folder index:" << index; return Folder(); } diff --git a/QtClient/JoplinQtClient/models/foldermodel.cpp b/QtClient/JoplinQtClient/models/foldermodel.cpp index c7e433fc0..d856c46da 100755 --- a/QtClient/JoplinQtClient/models/foldermodel.cpp +++ b/QtClient/JoplinQtClient/models/foldermodel.cpp @@ -1,15 +1,18 @@ #include "foldermodel.h" +#include "uuid.h" using namespace jop; -FolderModel::FolderModel(Database &database) : QAbstractListModel(), folderCollection_(database, 0, "title"), db_(database), orderBy_("title") { +FolderModel::FolderModel(Database &database) : QAbstractListModel(), db_(database), orderBy_("title") { virtualItemShown_ = false; - connect(&folderCollection_, SIGNAL(changed(int,int,const QStringList&)), this, SLOT(folderCollection_changed(int,int,const QStringList&))); } int FolderModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent); - return folderCollection_.count() + (virtualItemShown_ ? 1 : 0); + QSqlQuery q = db_.query("SELECT count(*) as row_count FROM folders"); + q.exec(); + q.next(); + return q.value(0).toInt() + (virtualItemShown_ ? 1 : 0); } // NOTE: to lazy load - send back "Loading..." if item not currently loaded @@ -21,7 +24,7 @@ QVariant FolderModel::data(const QModelIndex & index, int role) const { if (virtualItemShown_ && index.row() == rowCount() - 1) { folder.setTitle("Untitled"); } else { - folder = folderCollection_.at(index.row()); + folder = atIndex(index.row()); } if (role == Qt::DisplayRole) { @@ -36,16 +39,25 @@ QVariant FolderModel::data(const QModelIndex & index, int role) const { } bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role) { - Folder folder = folderCollection_.at(index.row()); + Folder folder = atIndex(index.row()); if (role == Qt::EditRole) { emit dataChanging(); QStringList fields; - fields << "title"; VariantVector values; - values << value; - folderCollection_.update(folder.id(), fields, values); + fields << "title" << "synced"; + values << value << QVariant(0); + + QSqlQuery q = db_.buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + folder.id() + "\""); + q.exec(); + if (!db_.errorCheck(q)) return false; + + cache_.clear(); + + QVector roles; + roles << Qt::DisplayRole; + emit dataChanged(this->index(0), this->index(rowCount() - 1), roles); return true; } @@ -53,6 +65,39 @@ bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int r return false; } +Folder FolderModel::atIndex(int index) const { + if (cache_.size()) { + if (index < 0 || index >= cache_.size()) { + qWarning() << "Invalid folder index:" << index; + return Folder(); + } + + return cache_[index]; + } + + cache_.clear(); + + QSqlQuery q = db_.query("SELECT " + Folder::dbFields().join(",") + " FROM folders ORDER BY " + orderBy_); + q.exec(); + + while (q.next()) { + Folder folder; + folder.fromSqlQuery(q); + cache_.push_back(folder); + } + + if (!cache_.size()) { + qWarning() << "Invalid folder index:" << index; + return Folder(); + } else { + return atIndex(index); + } +} + +Folder FolderModel::atIndex(const QModelIndex &index) const { + return atIndex(index.row()); +} + void FolderModel::showVirtualItem() { virtualItemShown_ = true; beginInsertRows(QModelIndex(), this->rowCount() - 1, this->rowCount() - 1); @@ -70,7 +115,16 @@ QString FolderModel::idAtIndex(int index) const { } int FolderModel::idToIndex(const QString &id) const { - return folderCollection_.idToIndex(id); + int count = this->rowCount(); + for (int i = 0; i < count; i++) { + Folder folder = atIndex(i); + if (folder.id() == id) return i; + } + return -1; +} + +QString FolderModel::lastInsertId() const { + return lastInsertId_; } bool FolderModel::virtualItemShown() const { @@ -90,25 +144,49 @@ QHash FolderModel::roleNames() const { } void FolderModel::addData(const QString &title) { - emit dataChanging(); - QStringList fields; - fields << "title"; VariantVector values; - values << QVariant(title); - folderCollection_.add(fields, values); + QString folderId = uuid::createUuid(); + fields << "id" << "title" << "synced"; + values << folderId << QVariant(title) << QVariant(0); + + QSqlQuery q = db_.buildSqlQuery(Database::Insert, "folders", fields, values); + q.exec(); + if (!db_.errorCheck(q)) return; + + cache_.clear(); + + lastInsertId_ = folderId; + + QVector roles; + roles << Qt::DisplayRole; + + int from = 0; + int to = rowCount() - 1; + + // Necessary to make sure a new item is added to the view, even + // though it might not be positioned there due to sorting + beginInsertRows(QModelIndex(), to, to); + endInsertRows(); + + emit dataChanged(this->index(from), this->index(to), roles); } void FolderModel::deleteData(const int index) { - QString id = folderCollection_.indexToId(index); - folderCollection_.remove(id); -} + QString folderId = idAtIndex(index); + + QSqlQuery q(db_.database()); + q.prepare("DELETE FROM folders WHERE id = :id"); + q.bindValue(":id", folderId); + q.exec(); + if (!db_.errorCheck(q)) return; + + cache_.clear(); + + beginRemoveRows(QModelIndex(), index, index); + endRemoveRows(); -void FolderModel::folderCollection_changed(int from, int to, const QStringList& fields) { - beginRemoveRows(QModelIndex(), from, to); QVector roles; roles << Qt::DisplayRole; - qDebug() << "update" << from << to; - emit dataChanged(this->index(from), this->index(to), roles); - endRemoveRows(); + emit dataChanged(this->index(0), this->index(rowCount() - 1), roles); } diff --git a/QtClient/JoplinQtClient/models/foldermodel.h b/QtClient/JoplinQtClient/models/foldermodel.h index 762407850..b253c53e7 100755 --- a/QtClient/JoplinQtClient/models/foldermodel.h +++ b/QtClient/JoplinQtClient/models/foldermodel.h @@ -3,8 +3,8 @@ #include +#include "models/folder.h" #include "database.h" -#include "models/foldercollection.h" namespace jop { @@ -26,6 +26,8 @@ public: int rowCount(const QModelIndex & parent = QModelIndex()) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + Folder atIndex(int index) const; + Folder atIndex(const QModelIndex &index) const; protected: @@ -34,22 +36,23 @@ protected: private: QList folders_; - FolderCollection folderCollection_; bool virtualItemShown_; QString orderBy_; Database& db_; + mutable QVector cache_; + QString lastInsertId_; public slots: void addData(const QString& title); void deleteData(const int index); bool setData(int index, const QVariant &value, int role = Qt::EditRole); - void folderCollection_changed(int from, int to, const QStringList &fields); void showVirtualItem(); bool virtualItemShown() const; void hideVirtualItem(); QString idAtIndex(int index) const; int idToIndex(const QString& id) const; + QString lastInsertId() const; signals: diff --git a/QtClient/JoplinQtClient/stable.h b/QtClient/JoplinQtClient/stable.h index 16bdb1779..b21e4ccf0 100755 --- a/QtClient/JoplinQtClient/stable.h +++ b/QtClient/JoplinQtClient/stable.h @@ -26,6 +26,10 @@ #include #include + + +#include + #endif // __cplusplus #endif // STABLE_H