diff --git a/QtClient/JoplinQtClient/JoplinQtClient.pro b/QtClient/JoplinQtClient/JoplinQtClient.pro index 280862e0c..d0373b850 100755 --- a/QtClient/JoplinQtClient/JoplinQtClient.pro +++ b/QtClient/JoplinQtClient/JoplinQtClient.pro @@ -13,7 +13,9 @@ SOURCES += \ models/notemodel.cpp \ models/note.cpp \ services/noteservice.cpp \ - application.cpp + application.cpp \ + models/notecollection.cpp \ + services/notecache.cpp RESOURCES += qml.qrc @@ -36,7 +38,9 @@ HEADERS += \ models/notemodel.h \ models/note.h \ services/noteservice.h \ - application.h + application.h \ + models/notecollection.h \ + services/notecache.h DISTFILES += diff --git a/QtClient/JoplinQtClient/application.cpp b/QtClient/JoplinQtClient/application.cpp index 0ce0e0e2f..1c4790f55 100755 --- a/QtClient/JoplinQtClient/application.cpp +++ b/QtClient/JoplinQtClient/application.cpp @@ -12,9 +12,13 @@ Application::Application(int &argc, char **argv) : QGuiApplication(argc, argv) { folderService_ = FolderService(db_); folderModel_.setService(folderService_); + noteService_ = NoteService(db_); + noteModel_.setService(noteService_); + view_.setResizeMode(QQuickView::SizeRootObjectToView); QQmlContext *ctxt = view_.rootContext(); ctxt->setContextProperty("folderListModel", &folderModel_); + ctxt->setContextProperty("noteListModel", ¬eModel_); view_.setSource(QUrl("qrc:/main.qml")); @@ -25,14 +29,16 @@ Application::Application(int &argc, char **argv) : QGuiApplication(argc, argv) { view_.show(); } -QString Application::selectedFolderId() const { +int Application::selectedFolderId() const { QObject* rootObject = (QObject*)view_.rootObject(); int index = rootObject->property("currentFolderIndex").toInt(); QModelIndex modelIndex = folderModel_.index(index); - return folderModel_.data(modelIndex, FolderModel::IdRole).toString(); + return folderModel_.data(modelIndex, FolderModel::IdRole).toInt(); } void Application::view_currentFolderChanged() { - qDebug() << selectedFolderId(); + int folderId = selectedFolderId(); + noteCollection_ = NoteCollection(db_, noteCache_, folderId, "title ASC"); + noteModel_.setCollection(noteCollection_); } diff --git a/QtClient/JoplinQtClient/application.h b/QtClient/JoplinQtClient/application.h index cd5458f47..ef004a3da 100755 --- a/QtClient/JoplinQtClient/application.h +++ b/QtClient/JoplinQtClient/application.h @@ -5,7 +5,11 @@ #include "database.h" #include "services/folderservice.h" +#include "services/noteservice.h" #include "models/foldermodel.h" +#include "models/notecollection.h" +#include "services/notecache.h" +#include "models/notemodel.h" namespace jop { @@ -22,8 +26,12 @@ private: QQuickView view_; Database db_; FolderService folderService_; + NoteCollection noteCollection_; + NoteService noteService_; FolderModel folderModel_; - QString selectedFolderId() const; + NoteModel noteModel_; + int selectedFolderId() const; + NoteCache noteCache_; public slots: diff --git a/QtClient/JoplinQtClient/main.qml b/QtClient/JoplinQtClient/main.qml index af35fa7ac..c783dba04 100755 --- a/QtClient/JoplinQtClient/main.qml +++ b/QtClient/JoplinQtClient/main.qml @@ -32,6 +32,7 @@ Item { NoteList { id: noteList + model: noteListModel Layout.fillWidth: true Layout.fillHeight: true Layout.minimumWidth: 100 diff --git a/QtClient/JoplinQtClient/models/item.cpp b/QtClient/JoplinQtClient/models/item.cpp index 346391beb..05ad45f4a 100755 --- a/QtClient/JoplinQtClient/models/item.cpp +++ b/QtClient/JoplinQtClient/models/item.cpp @@ -12,12 +12,12 @@ void Item::fromSqlQuery(const QSqlQuery &q) { int i_title = q.record().indexOf("title"); int i_created_time = q.record().indexOf("created_time"); - id_ = q.value(i_id).toString(); + id_ = q.value(i_id).toInt(); title_ = q.value(i_title).toString(); createdTime_ = q.value(i_created_time).toInt(); } -QString Item::id() const { +int Item::id() const { return id_; } @@ -29,7 +29,7 @@ int Item::createdTime() const { return createdTime_; } -void Item::setId(const QString& v) { +void Item::setId(int v) { id_ = v; } diff --git a/QtClient/JoplinQtClient/models/item.h b/QtClient/JoplinQtClient/models/item.h index 885ef8ad6..fc7cc943c 100755 --- a/QtClient/JoplinQtClient/models/item.h +++ b/QtClient/JoplinQtClient/models/item.h @@ -11,12 +11,12 @@ public: Item(); - QString id() const; + int id() const; QString title() const; int createdTime() const; bool isPartial() const; - void setId(const QString& v); + void setId(int v); void setTitle(const QString& v); void setCreatedTime(int v); void setIsPartial(bool v); @@ -25,7 +25,7 @@ public: private: - QString id_; + int id_; QString title_; int createdTime_; bool isPartial_; diff --git a/QtClient/JoplinQtClient/models/notecollection.cpp b/QtClient/JoplinQtClient/models/notecollection.cpp new file mode 100755 index 000000000..cbc89a0d3 --- /dev/null +++ b/QtClient/JoplinQtClient/models/notecollection.cpp @@ -0,0 +1,89 @@ +#include "notecollection.h" + +using namespace jop; + +NoteCollection::NoteCollection() {} + +NoteCollection::NoteCollection(Database& db, NoteCache cache, int parentId, const QString& orderBy) { + db_ = db; + parentId_ = parentId; + orderBy_ = orderBy; + cache_ = cache; + cacheMinIndex_ = 0; + cacheMaxIndex_ = -1; +} + + +int NoteCollection::cacheMinIndex() const { + return cacheMinIndex_; +} + +int NoteCollection::cacheMaxIndex() const { + return cacheMaxIndex_; +} + +Note NoteCollection::itemAt(int index) const { + if (!parentId_) return Note(); + + qDebug() << "Note at" << index << "Min" << cacheMinIndex() << "Max" << cacheMaxIndex() << "Count" << count(); + + if (index >= cacheMinIndex() && index < cacheMaxIndex()) { + return notes_[index]; + } + + int buff = 16; + + int from = index - buff; + int to = from + (buff - 1); + + if (notes_.size()) { + if (from <= cacheMaxIndex()) { + from = cacheMaxIndex() + 1; + to = from + (buff - 1); + cacheMaxIndex_ = to; + } else if (to >= cacheMinIndex()) { + to = cacheMinIndex() - 1; + from = to - (buff - 1); + cacheMinIndex_ = from; + } + } else { + from = std::max(0, index - buff); + to = from + (buff - 1); + } + + if (from < 0) from = 0; + if (to >= count()) to = count() - 1; + + qDebug() << "Loading from" << from << "to" << to; + + QSqlQuery q = db_.query("SELECT id, title FROM notes WHERE parent_id = :parent_id ORDER BY " + orderBy_ + " LIMIT " + QString::number(to - from + 1) + " OFFSET " + QString::number(from)); + q.bindValue(":parent_id", parentId_); + q.exec(); + + int noteIndex = from; + while (q.next()) { + Note f; + f.setId(q.value(0).toInt()); + f.setTitle(q.value(1).toString()); + f.setIsPartial(true); + + qDebug() << "Adding" << noteIndex; + notes_[noteIndex] = f; + + noteIndex++; + } + + qDebug() << notes_.contains(index); + return notes_[index]; +} + +// TODO: cache result +int NoteCollection::count() const { + if (!parentId_) return 0; + + QSqlQuery q = db_.query("SELECT count(*) as row_count FROM notes WHERE parent_id = :parent_id"); + q.bindValue(":parent_id", parentId_); + q.exec(); + q.next(); + return q.value(0).toInt(); +} diff --git a/QtClient/JoplinQtClient/models/notecollection.h b/QtClient/JoplinQtClient/models/notecollection.h new file mode 100755 index 000000000..fb21a80a7 --- /dev/null +++ b/QtClient/JoplinQtClient/models/notecollection.h @@ -0,0 +1,39 @@ +#ifndef NOTECOLLECTION_H +#define NOTECOLLECTION_H + +#include + +#include "database.h" +#include "models/note.h" +#include "services/notecache.h" + +namespace jop { + +class NoteCollection { + +public: + + NoteCollection(); + NoteCollection(Database& db, NoteCache cache, int parentId, const QString& orderBy); + Note itemAt(int index) const; + int count() const; + +private: + + int parentId_; + QString orderBy_; + Database db_; + NoteCache cache_; + + int cacheMinIndex() const; + int cacheMaxIndex() const; + + mutable int cacheMinIndex_; + mutable int cacheMaxIndex_; + mutable QMap notes_; + +}; + +} + +#endif // NOTECOLLECTION_H diff --git a/QtClient/JoplinQtClient/models/notemodel.cpp b/QtClient/JoplinQtClient/models/notemodel.cpp index cb85e1531..0f88bd428 100755 --- a/QtClient/JoplinQtClient/models/notemodel.cpp +++ b/QtClient/JoplinQtClient/models/notemodel.cpp @@ -1,22 +1,45 @@ #include "notemodel.h" -jop::NoteModel::NoteModel(NoteService ¬eService) +jop::NoteModel::NoteModel() { - noteService_ = noteService; + } -int jop::NoteModel::rowCount(const QModelIndex &parent) const -{ - return 0; +int jop::NoteModel::rowCount(const QModelIndex &parent) const { + return collection_.count(); } -QVariant jop::NoteModel::data(const QModelIndex &index, int role) const -{ +QVariant jop::NoteModel::data(const QModelIndex &index, int role) const { + if (index.row() < 0 || index.row() >= rowCount()) return QVariant(); + + Note note = collection_.itemAt(index.row()); + + return QVariant(note.title()); + +// int from = std::max(0, index.row() - 16); +// int to = from + 32; +// QList list = noteService_.overviewList(folderId_, from, to, "title ASC"); + + + return QVariant(); } -QHash jop::NoteModel::roleNames() const -{ +void jop::NoteModel::setFolderId(const QString &v) { + folderId_ = v; +} + +void jop::NoteModel::setService(jop::NoteService &v) { + noteService_ = v; +} + +void jop::NoteModel::setCollection(jop::NoteCollection ¬eCollection) { + beginResetModel(); + collection_ = noteCollection; + endResetModel(); +} + +QHash jop::NoteModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); // roles[TitleRole] = "title"; // roles[UuidRole] = "uuid"; diff --git a/QtClient/JoplinQtClient/models/notemodel.h b/QtClient/JoplinQtClient/models/notemodel.h index 04e4a6fd9..29716e53a 100755 --- a/QtClient/JoplinQtClient/models/notemodel.h +++ b/QtClient/JoplinQtClient/models/notemodel.h @@ -4,6 +4,7 @@ #include #include "services/noteservice.h" +#include "models/notecollection.h" namespace jop { @@ -13,9 +14,12 @@ class NoteModel : public QAbstractListModel { public: - NoteModel(NoteService ¬eService); + NoteModel(); int rowCount(const QModelIndex & parent = QModelIndex()) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + void setFolderId(const QString& v); + void setService(NoteService& v); + void setCollection(NoteCollection& noteCollection); protected: @@ -25,6 +29,8 @@ private: QList notes_; NoteService noteService_; + QString folderId_; + NoteCollection collection_; }; diff --git a/QtClient/JoplinQtClient/services/folderservice.cpp b/QtClient/JoplinQtClient/services/folderservice.cpp index 2c1f0c5ed..f5b964d62 100755 --- a/QtClient/JoplinQtClient/services/folderservice.cpp +++ b/QtClient/JoplinQtClient/services/folderservice.cpp @@ -16,7 +16,7 @@ int FolderService::count() const { return q.value(0).toInt(); } -Folder FolderService::byId(const QString &id) const { +Folder FolderService::byId(int id) const { QSqlQuery q = database_.query("SELECT title, created_time FROM folders WHERE id = :id"); q.bindValue(":id", id); q.exec(); @@ -37,7 +37,7 @@ const QList FolderService::overviewList() const { q.exec(); while (q.next()) { Folder f; - f.setId(q.value(0).toString()); + f.setId(q.value(0).toInt()); f.setTitle(q.value(1).toString()); f.setIsPartial(true); output << f; diff --git a/QtClient/JoplinQtClient/services/folderservice.h b/QtClient/JoplinQtClient/services/folderservice.h index 51c88363d..de43b6eab 100755 --- a/QtClient/JoplinQtClient/services/folderservice.h +++ b/QtClient/JoplinQtClient/services/folderservice.h @@ -14,7 +14,7 @@ public: FolderService(); FolderService(Database& database); int count() const; - Folder byId(const QString& id) const; + Folder byId(int id) const; //Folder partialAt(int index) const; const QList overviewList() const; diff --git a/QtClient/JoplinQtClient/services/notecache.cpp b/QtClient/JoplinQtClient/services/notecache.cpp new file mode 100755 index 000000000..5a2a4ce7c --- /dev/null +++ b/QtClient/JoplinQtClient/services/notecache.cpp @@ -0,0 +1,18 @@ +#include "notecache.h" + +using namespace jop; + +NoteCache::NoteCache() { + +} + +void NoteCache::add(QList notes) { + foreach (Note note, notes) { + cache_[note.id()] = note; + } +} + +std::pair NoteCache::get(int id) const { + if (cache_.contains(id)) return std::make_pair(cache_[id], true); + return std::make_pair(Note(), true); +} diff --git a/QtClient/JoplinQtClient/services/notecache.h b/QtClient/JoplinQtClient/services/notecache.h new file mode 100755 index 000000000..9b7161560 --- /dev/null +++ b/QtClient/JoplinQtClient/services/notecache.h @@ -0,0 +1,25 @@ +#ifndef NOTECACHE_H +#define NOTECACHE_H + +#include +#include "models/note.h" + +namespace jop { + +class NoteCache { + +public: + + NoteCache(); + void add(QList notes); + std::pair get(int id) const; + +private: + + QMap cache_; + +}; + +} + +#endif // NOTECACHE_H diff --git a/QtClient/JoplinQtClient/services/noteservice.cpp b/QtClient/JoplinQtClient/services/noteservice.cpp index b007934ae..f457227fb 100755 --- a/QtClient/JoplinQtClient/services/noteservice.cpp +++ b/QtClient/JoplinQtClient/services/noteservice.cpp @@ -8,7 +8,7 @@ NoteService::NoteService(jop::Database &database) { database_ = database; } -int NoteService::count(int parentFolderId) const { +int NoteService::count(const QString &parentFolderId) const { QSqlQuery q = database_.query("SELECT count(*) as row_count FROM notes WHERE parent_id = :parent_id"); q.bindValue(":parent_id", parentFolderId); q.exec(); @@ -21,6 +21,34 @@ Note NoteService::byId(const QString &id) const { return n; } -const QList NoteService::overviewList(const QString &orderBy, int from, int to) const { - return QList(); +const QList NoteService::overviewList(const QString& folderId, int from, int to, const QString &orderBy) const { + QList output; + QSqlQuery q = database_.query("SELECT id, title FROM notes WHERE parent_id = :parent_id ORDER BY " + orderBy + " LIMIT " + QString::number(to - from) + " OFFSET " + QString::number(from)); + q.bindValue(":parent_id", folderId); + q.exec(); + + while (q.next()) { + Note f; + f.setId(q.value(0).toInt()); + f.setTitle(q.value(1).toString()); + f.setIsPartial(true); + output << f; + } + + return output; +} + +std::pair NoteService::overviewAt(const QString &folderId, int index, const QString &orderBy) const { + QSqlQuery q = database_.query("SELECT id, title FROM notes WHERE parent_id = :parent_id ORDER BY " + orderBy + " LIMIT 1 OFFSET " + QString::number(index)); + q.bindValue(":parent_id", folderId); + q.exec(); + q.next(); + if (!q.isValid()) return std::make_pair(Note(), false); + + Note f; + f.setId(q.value(0).toInt()); + f.setTitle(q.value(1).toString()); + f.setIsPartial(true); + + return std::make_pair(f, true); } diff --git a/QtClient/JoplinQtClient/services/noteservice.h b/QtClient/JoplinQtClient/services/noteservice.h index 07fd322fe..e7c3cbe33 100755 --- a/QtClient/JoplinQtClient/services/noteservice.h +++ b/QtClient/JoplinQtClient/services/noteservice.h @@ -13,9 +13,10 @@ public: NoteService(); NoteService(Database& database); - int count(int parentFolderId) const; + int count(const QString& parentFolderId) const; Note byId(const QString& id) const; - const QList overviewList(const QString& orderBy, int from, int to) const; + const QList overviewList(const QString &folderId, int from, int to, const QString& orderBy) const; + std::pair overviewAt(const QString& folderId, int index, const QString& orderBy) const; private: