From 4e549695cf820032c56472019c575418b70f4ce9 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 12 Jan 2017 17:59:19 +0100 Subject: [PATCH] Display notes --- QtClient/JoplinQtClient/AddButton.qml | 2 +- QtClient/JoplinQtClient/JoplinQtClient.pro | 2 - QtClient/JoplinQtClient/LoginPage.qml | 10 ---- QtClient/JoplinQtClient/MainPage.qml | 4 +- QtClient/JoplinQtClient/app.qml | 2 - QtClient/JoplinQtClient/application.cpp | 36 ++---------- QtClient/JoplinQtClient/application.h | 5 -- QtClient/JoplinQtClient/database.cpp | 18 +++--- QtClient/JoplinQtClient/database.h | 1 + QtClient/JoplinQtClient/models/basemodel.cpp | 39 +++++++++++-- QtClient/JoplinQtClient/models/basemodel.h | 1 + QtClient/JoplinQtClient/models/folder.cpp | 29 ++++++++++ QtClient/JoplinQtClient/models/folder.h | 3 + .../JoplinQtClient/models/foldermodel.cpp | 33 +---------- QtClient/JoplinQtClient/models/foldermodel.h | 3 +- QtClient/JoplinQtClient/models/note.cpp | 29 +++------- QtClient/JoplinQtClient/models/note.h | 11 +--- .../JoplinQtClient/models/notecollection.cpp | 3 +- QtClient/JoplinQtClient/models/notemodel.cpp | 58 ++++++++++++++----- QtClient/JoplinQtClient/models/notemodel.h | 9 ++- QtClient/JoplinQtClient/models/setting.cpp | 3 +- QtClient/JoplinQtClient/schema.sql | 2 +- QtClient/evernote-import/main.cpp | 33 ++++++++--- 23 files changed, 178 insertions(+), 158 deletions(-) diff --git a/QtClient/JoplinQtClient/AddButton.qml b/QtClient/JoplinQtClient/AddButton.qml index f2c81ad78..11c939daa 100755 --- a/QtClient/JoplinQtClient/AddButton.qml +++ b/QtClient/JoplinQtClient/AddButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.1 diff --git a/QtClient/JoplinQtClient/JoplinQtClient.pro b/QtClient/JoplinQtClient/JoplinQtClient.pro index e7b03eb48..3bc69a24a 100755 --- a/QtClient/JoplinQtClient/JoplinQtClient.pro +++ b/QtClient/JoplinQtClient/JoplinQtClient.pro @@ -11,7 +11,6 @@ SOURCES += \ models/notemodel.cpp \ models/note.cpp \ application.cpp \ - models/notecollection.cpp \ models/qmlnote.cpp \ webapi.cpp \ synchronizer.cpp \ @@ -45,7 +44,6 @@ HEADERS += \ models/notemodel.h \ models/note.h \ application.h \ - models/notecollection.h \ sparsevector.hpp \ models/qmlnote.h \ webapi.h \ diff --git a/QtClient/JoplinQtClient/LoginPage.qml b/QtClient/JoplinQtClient/LoginPage.qml index dd8700bd1..d0ec887cf 100755 --- a/QtClient/JoplinQtClient/LoginPage.qml +++ b/QtClient/JoplinQtClient/LoginPage.qml @@ -32,14 +32,4 @@ LoginPageForm { } } -// Connections { -// target: dispatcher -// onLoginFailed: { -// root.enabled = true; -// } -// onLoginSuccess: { -// root.enabled = true; -// } -// } - } diff --git a/QtClient/JoplinQtClient/MainPage.qml b/QtClient/JoplinQtClient/MainPage.qml index cec40e88e..43cac1769 100755 --- a/QtClient/JoplinQtClient/MainPage.qml +++ b/QtClient/JoplinQtClient/MainPage.qml @@ -1,6 +1,6 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 -import QtQuick.Controls 1.4 +//import QtQuick.Controls 1.4 import QtQuick.Layouts 1.0 Item { @@ -103,7 +103,7 @@ Item { text: "Logout" anchors.right: syncButton.left anchors.top: parent.top - onClicked: appRoot.logoutClicked() //dispatcher.logoutClicked() + onClicked: appRoot.logoutClicked() } } diff --git a/QtClient/JoplinQtClient/app.qml b/QtClient/JoplinQtClient/app.qml index 570acc3a1..e3aed6750 100755 --- a/QtClient/JoplinQtClient/app.qml +++ b/QtClient/JoplinQtClient/app.qml @@ -58,12 +58,10 @@ Item { } function emitLoginStarted() { - print("CALLING emitLoginStarted"); root.loginStarted(); } function emitLoginFailed() { - print("CALLING emitLoginFailed"); root.loginFailed(); } diff --git a/QtClient/JoplinQtClient/application.cpp b/QtClient/JoplinQtClient/application.cpp index 321619890..6fc68ea4e 100755 --- a/QtClient/JoplinQtClient/application.cpp +++ b/QtClient/JoplinQtClient/application.cpp @@ -17,8 +17,7 @@ using namespace jop; Application::Application(int &argc, char **argv) : QGuiApplication(argc, argv), db_(jop::db()), - synchronizer_(db_), - folderModel_(db_) + synchronizer_(db_) { @@ -51,7 +50,6 @@ Application::Application(int &argc, char **argv) : ctxt->setContextProperty("folderListModel", &folderModel_); ctxt->setContextProperty("noteListModel", ¬eModel_); ctxt->setContextProperty("noteModel", &selectedQmlNote_); - ctxt->setContextProperty("dispatcher", &dispatcher()); ctxt->setContextProperty("settings", qmlSettings); view_.setSource(QUrl("qrc:/app.qml")); @@ -65,12 +63,6 @@ Application::Application(int &argc, char **argv) : connect(rootObject, SIGNAL(loginClicked(QString,QString,QString)), this, SLOT(dispatcher_loginClicked(QString,QString,QString))); connect(rootObject, SIGNAL(logoutClicked()), this, SLOT(dispatcher_logoutClicked())); - connect(&dispatcher(), SIGNAL(folderCreated(QString)), this, SLOT(dispatcher_folderCreated(QString))); - connect(&dispatcher(), SIGNAL(folderUpdated(QString)), this, SLOT(dispatcher_folderUpdated(QString))); - connect(&dispatcher(), SIGNAL(folderDeleted(QString)), this, SLOT(dispatcher_folderDeleted(QString))); - //connect(&dispatcher(), SIGNAL(loginClicked(QString,QString,QString)), this, SLOT(dispatcher_loginClicked(QString,QString,QString))); - //connect(&dispatcher(), SIGNAL(logoutClicked()), this, SLOT(dispatcher_logoutClicked())); - view_.show(); synchronizerTimer_.setInterval(1000 * 120); @@ -81,6 +73,7 @@ Application::Application(int &argc, char **argv) : connect(&api_, SIGNAL(requestDone(const QJsonObject&, const QString&)), this, SLOT(api_requestDone(const QJsonObject&, const QString&))); if (!settings.contains("user.email") || !settings.contains("session.id") || !settings.contains("api.baseUrl")) { + synchronizer_.freeze(); view_.showPage("login"); } else { afterSessionInitialization(); @@ -121,9 +114,7 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta if (tag == "getSession") { if (response.contains("error")) { qWarning() << "Could not get session:" << response.value("error").toString(); - //dispatcher().emitLoginFailed(); view_.emitSignal("loginFailed"); - //qDebug() << "FAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILEDFAILED"; view_.showPage("login"); } else { QString sessionId = response.value("id").toString(); @@ -131,7 +122,6 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta Settings settings; settings.setValue("session.id", sessionId); afterSessionInitialization(); - //dispatcher().emitLoginSuccess(); view_.emitSignal("loginSuccess"); view_.showPage("main"); } @@ -139,21 +129,6 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta } } -void Application::dispatcher_folderCreated(const QString &folderId) { - qDebug() << "Folder created" << folderId; - //synchronizerTimer_.start(1000 * 3); -} - -void Application::dispatcher_folderUpdated(const QString &folderId) { - qDebug() << "Folder udpated" << folderId; - //synchronizerTimer_.start(1000 * 3); -} - -void Application::dispatcher_folderDeleted(const QString &folderId) { - qDebug() << "Folder deleted" << folderId; - //synchronizerTimer_.start(1000 * 3); -} - void Application::dispatcher_loginClicked(const QString &apiBaseUrl, const QString &email, const QString &password) { qDebug() << apiBaseUrl << email << password; @@ -188,7 +163,7 @@ void Application::dispatcher_logoutClicked() { synchronizer_.freeze(); Settings settings; - settings.setValue("session.id", ""); + settings.remove("session.id"); api_.setSessionId(""); synchronizer_.setSessionId(""); @@ -232,9 +207,8 @@ void Application::afterSessionInitialization() { } void Application::view_currentFolderChanged() { -// QString folderId = selectedFolderId(); -// noteCollection_ = NoteCollection(db_, folderId, "title ASC"); -// noteModel_.setCollection(noteCollection_); + QString folderId = selectedFolderId(); + noteModel_.setFolderId(folderId); } void Application::view_currentNoteChanged() { diff --git a/QtClient/JoplinQtClient/application.h b/QtClient/JoplinQtClient/application.h index 91c62c41b..506f62b0a 100755 --- a/QtClient/JoplinQtClient/application.h +++ b/QtClient/JoplinQtClient/application.h @@ -5,7 +5,6 @@ #include "database.h" #include "models/foldermodel.h" -#include "models/notecollection.h" #include "models/notemodel.h" #include "models/qmlnote.h" #include "webapi.h" @@ -27,7 +26,6 @@ private: Window view_; Database& db_; - NoteCollection noteCollection_; FolderModel folderModel_; NoteModel noteModel_; QString selectedFolderId() const; @@ -49,9 +47,6 @@ public slots: void api_requestDone(const QJsonObject& response, const QString& tag); - void dispatcher_folderCreated(const QString& folderId); - void dispatcher_folderUpdated(const QString& folderId); - void dispatcher_folderDeleted(const QString& folderId); void dispatcher_loginClicked(const QString &domain, const QString &email, const QString &password); void dispatcher_logoutClicked(); diff --git a/QtClient/JoplinQtClient/database.cpp b/QtClient/JoplinQtClient/database.cpp index d7be398ee..24beb847c 100755 --- a/QtClient/JoplinQtClient/database.cpp +++ b/QtClient/JoplinQtClient/database.cpp @@ -7,6 +7,7 @@ Database::Database() {} void Database::initialize(const QString &path) { version_ = -1; transactionCount_ = 0; + logQueries_ = false; //QFile::remove(path); @@ -19,9 +20,6 @@ void Database::initialize(const QString &path) { qDebug() << "Database: connection ok"; } -// execQuery("DELETE FROM folders"); -// execQuery("DELETE FROM settings"); - upgrade(); } @@ -131,13 +129,15 @@ bool Database::commit() { } bool Database::execQuery(QSqlQuery &query) { -// qDebug().noquote() << "SQL:" << query.lastQuery(); + if (logQueries_) { + qDebug().noquote() << "SQL:" << query.lastQuery(); -// QMapIterator i(query.boundValues()); -// while (i.hasNext()) { -// i.next(); -// qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString(); -// } + QMapIterator i(query.boundValues()); + while (i.hasNext()) { + i.next(); + qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString(); + } + } return query.exec(); } diff --git a/QtClient/JoplinQtClient/database.h b/QtClient/JoplinQtClient/database.h index 021649da2..6cd6b2ab1 100755 --- a/QtClient/JoplinQtClient/database.h +++ b/QtClient/JoplinQtClient/database.h @@ -33,6 +33,7 @@ private: mutable int version_; QStringList sqlStringToLines(const QString& sql); int transactionCount_; + bool logQueries_; }; diff --git a/QtClient/JoplinQtClient/models/basemodel.cpp b/QtClient/JoplinQtClient/models/basemodel.cpp index 064212003..743c18862 100755 --- a/QtClient/JoplinQtClient/models/basemodel.cpp +++ b/QtClient/JoplinQtClient/models/basemodel.cpp @@ -52,8 +52,6 @@ bool BaseModel::load(const QString &id) { bool BaseModel::save(bool trackChanges) { bool isNew = this->isNew(); - qDebug() << "SAVING" << valuesToString(); - if (!changedFields_.size() && !isNew) return true; QStringList fields = changedFields(); @@ -170,7 +168,7 @@ bool BaseModel::dispose() { } Table BaseModel::table() const { - qCritical() << "BaseModel::table() must be overriden"; + qFatal("BaseModel::table() must be overriden"); return jop::UndefinedTable; } @@ -209,12 +207,33 @@ QVector BaseModel::tableFields(jop::Table table) { output.push_back(createField("title", QMetaType::QString )); output.push_back(createField("created_time", QMetaType::Int )); output.push_back(createField("updated_time", QMetaType::Int )); + } else if (table == jop::NotesTable) { + output.push_back(createField("id", QMetaType::Int )); + output.push_back(createField("title", QMetaType::QString )); + output.push_back(createField("body", QMetaType::QString )); + output.push_back(createField("parent_id", QMetaType::QString )); + output.push_back(createField("created_time", QMetaType::Int )); + output.push_back(createField("updated_time", QMetaType::Int )); + output.push_back(createField("latitude", QMetaType::QString )); + output.push_back(createField("longitude", QMetaType::QString )); + output.push_back(createField("altitude", QMetaType::QString )); + output.push_back(createField("source", QMetaType::QString )); + output.push_back(createField("author", QMetaType::QString )); + output.push_back(createField("source_url", QMetaType::QString )); + output.push_back(createField("is_todo", QMetaType::Int )); + output.push_back(createField("todo_due", QMetaType::Int )); + output.push_back(createField("todo_completed", QMetaType::Int )); + output.push_back(createField("source_application", QMetaType::QString )); + output.push_back(createField("application_data", QMetaType::QString )); + output.push_back(createField("order", QMetaType::Int )); } else if (table == jop::ChangesTable) { output.push_back(createField("id", QMetaType::Int )); output.push_back(createField("type", QMetaType::Int )); output.push_back(createField("item_id", QMetaType::QString )); output.push_back(createField("item_type", QMetaType::Int )); output.push_back(createField("item_field", QMetaType::QString )); + } else { + qFatal("Field not defined for table %d", table); } BaseModel::tableFields_[table] = output; @@ -238,6 +257,16 @@ QStringList BaseModel::tableFieldNames(Table table) { return output; } +QString BaseModel::sqlTableFields(Table table) { + QString output = ""; + QStringList fields = BaseModel::tableFieldNames(table); + for (int i = 0; i < fields.size(); i++) { + if (output != "") output += ","; + output += QString("`%1`").arg(fields[i]); + } + return output; +} + bool BaseModel::isValidFieldName(Table table, const QString &name) { QVector fields = BaseModel::tableFields(table); foreach (BaseModel::Field col, fields) { @@ -348,7 +377,7 @@ void BaseModel::setValue(const QString &name, const QJsonValue &value, QMetaType } else if (type == QMetaType::Int) { setValue(name, value.toInt()); } else { - qCritical() << "Unsupported value type" << name << type; + qFatal("Unsupported value type %s %d", name.toStdString(), type); } } @@ -370,7 +399,7 @@ QString BaseModel::tableName(Table t) { if (t == jop::FoldersTable) return "folders"; if (t == jop::NotesTable) return "notes"; if (t == jop::ChangesTable) return "changes"; - return "UNDEFINED"; + qFatal("Unknown table %d", t); } QVariant BaseModel::cacheGet(const QString &key) { diff --git a/QtClient/JoplinQtClient/models/basemodel.h b/QtClient/JoplinQtClient/models/basemodel.h index 8b4ae2c07..3954d4f7b 100755 --- a/QtClient/JoplinQtClient/models/basemodel.h +++ b/QtClient/JoplinQtClient/models/basemodel.h @@ -56,6 +56,7 @@ public: static QVector tableFields(Table table); static bool hasField(jop::Table table, const QString& name); static QStringList tableFieldNames(Table table); + static QString sqlTableFields(Table table); static bool isValidFieldName(Table table, const QString& name); static void deleteAll(Table table); diff --git a/QtClient/JoplinQtClient/models/folder.cpp b/QtClient/JoplinQtClient/models/folder.cpp index e5754870d..fe0bb1b7b 100755 --- a/QtClient/JoplinQtClient/models/folder.cpp +++ b/QtClient/JoplinQtClient/models/folder.cpp @@ -20,6 +20,35 @@ bool Folder::trackChanges() const { return true; } +int Folder::noteCount() const { + QSqlQuery q = jop::db().prepare(QString("SELECT count(*) AS row_count FROM %1 WHERE parent_id = :parent_id").arg(BaseModel::tableName(jop::NotesTable))); + q.bindValue(":parent_id", id().toString()); + jop::db().execQuery(q); + q.next(); + return q.value(0).toInt(); +} + +QVector Folder::notes(const QString &orderBy, int limit, int offset) const { + QVector output; + + QSqlQuery q = jop::db().prepare(QString("SELECT %1 FROM notes WHERE parent_id = :parent_id ORDER BY %2 LIMIT %3 OFFSET %4") + .arg(BaseModel::sqlTableFields(jop::NotesTable)) + .arg(orderBy) + .arg(limit) + .arg(offset)); + q.bindValue(":parent_id", id().toString()); + jop::db().execQuery(q); + if (!jop::db().errorCheck(q)) return output; + + while (q.next()) { + Note note; + note.loadSqlQuery(q); + output.push_back(note); + } + + return output; +} + int Folder::count() { return BaseModel::count(jop::FoldersTable); } diff --git a/QtClient/JoplinQtClient/models/folder.h b/QtClient/JoplinQtClient/models/folder.h index a3ec452e9..c4809eb6d 100755 --- a/QtClient/JoplinQtClient/models/folder.h +++ b/QtClient/JoplinQtClient/models/folder.h @@ -3,6 +3,7 @@ #include #include "models/item.h" +#include "models/note.h" namespace jop { @@ -18,6 +19,8 @@ public: Table table() const; bool primaryKeyIsUuid() const; bool trackChanges() const; + int noteCount() const; + QVector notes(const QString& orderBy, int limit, int offset) const; // bool save(); // bool dispose(); diff --git a/QtClient/JoplinQtClient/models/foldermodel.cpp b/QtClient/JoplinQtClient/models/foldermodel.cpp index cd4a2a251..4c7def9d4 100755 --- a/QtClient/JoplinQtClient/models/foldermodel.cpp +++ b/QtClient/JoplinQtClient/models/foldermodel.cpp @@ -4,7 +4,7 @@ using namespace jop; -FolderModel::FolderModel(Database &database) : QAbstractListModel(), db_(database), orderBy_("title") { +FolderModel::FolderModel() : QAbstractListModel(), orderBy_("title") { virtualItemShown_ = false; connect(&dispatcher(), SIGNAL(folderCreated(QString)), this, SLOT(dispatcher_folderCreated(QString))); @@ -17,9 +17,6 @@ int FolderModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent); return Folder::count() + (virtualItemShown_ ? 1 : 0); } -// NOTE: to lazy load - send back "Loading..." if item not currently loaded -// queue the item for loading. -// Then batch load them a bit later. QVariant FolderModel::data(const QModelIndex & index, int role) const { Folder folder; @@ -47,10 +44,6 @@ bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int r folder.setValue("title", value); if (!folder.save()) return false; cache_.clear(); - -// QVector roles; -// roles << Qt::DisplayRole; -// emit dataChanged(this->index(0), this->index(rowCount() - 1), roles); return true; } @@ -134,36 +127,12 @@ void FolderModel::addData(const QString &title) { folder.setValue("title", title); if (!folder.save()) return; - //cache_.clear(); - lastInsertId_ = folder.id().toString(); - -// 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) { Folder folder = atIndex(index); if (!folder.dispose()) return; - -// cache_.clear(); - -// beginRemoveRows(QModelIndex(), index, index); -// endRemoveRows(); - -// QVector roles; -// roles << Qt::DisplayRole; -// emit dataChanged(this->index(0), this->index(rowCount() - 1), roles); } // TODO: instead of clearing the whole cache every time, the individual items diff --git a/QtClient/JoplinQtClient/models/foldermodel.h b/QtClient/JoplinQtClient/models/foldermodel.h index 120b8e02c..c29aeb3f9 100755 --- a/QtClient/JoplinQtClient/models/foldermodel.h +++ b/QtClient/JoplinQtClient/models/foldermodel.h @@ -20,7 +20,7 @@ public: RawRole }; - FolderModel(Database& database); + FolderModel(); void addFolder(Folder* folder); int rowCount(const QModelIndex & parent = QModelIndex()) const; @@ -38,7 +38,6 @@ private: QList folders_; bool virtualItemShown_; QString orderBy_; - Database& db_; mutable QVector cache_; QString lastInsertId_; diff --git a/QtClient/JoplinQtClient/models/note.cpp b/QtClient/JoplinQtClient/models/note.cpp index 865df377a..e4d37511f 100755 --- a/QtClient/JoplinQtClient/models/note.cpp +++ b/QtClient/JoplinQtClient/models/note.cpp @@ -2,27 +2,16 @@ using namespace jop; -Note::Note() -{ +Note::Note() : Item() {} +Table Note::table() const { + return jop::NotesTable; } -//QString Note::body() const { -// return body_; -//} +bool Note::primaryKeyIsUuid() const { + return true; +} -//void Note::setBody(const QString &v) { -// body_ = v; -//} - -//QStringList Note::dbFields() { -// QStringList output = Item::dbFields(); -// output << "body"; -// return output; -//} - -//void Note::fromSqlQuery(const QSqlQuery &q) { -// Item::fromSqlQuery(q); -// int idx = Item::dbFields().size(); -// body_ = q.value(idx).toString(); -//} +bool Note::trackChanges() const { + return true; +} diff --git a/QtClient/JoplinQtClient/models/note.h b/QtClient/JoplinQtClient/models/note.h index abe94a4b8..74c013a14 100755 --- a/QtClient/JoplinQtClient/models/note.h +++ b/QtClient/JoplinQtClient/models/note.h @@ -11,14 +11,9 @@ class Note : public Item { public: Note(); -// QString body() const; -// void setBody(const QString& v); -// static QStringList dbFields(); -// void fromSqlQuery(const QSqlQuery &q); - -//private: - -// QString body_; + Table table() const; + bool primaryKeyIsUuid() const; + bool trackChanges() const; }; diff --git a/QtClient/JoplinQtClient/models/notecollection.cpp b/QtClient/JoplinQtClient/models/notecollection.cpp index 8ae47cf06..c4dbcb4bc 100755 --- a/QtClient/JoplinQtClient/models/notecollection.cpp +++ b/QtClient/JoplinQtClient/models/notecollection.cpp @@ -78,5 +78,6 @@ Note NoteCollection::byId(const QString& id) const { // note.setId(q.value(0).toString()); // note.setTitle(q.value(1).toString()); // note.setBody(q.value(2).toString()); -// return note; + // return note; } + diff --git a/QtClient/JoplinQtClient/models/notemodel.cpp b/QtClient/JoplinQtClient/models/notemodel.cpp index 79f0a787c..55fc59f37 100755 --- a/QtClient/JoplinQtClient/models/notemodel.cpp +++ b/QtClient/JoplinQtClient/models/notemodel.cpp @@ -1,35 +1,65 @@ #include "notemodel.h" -jop::NoteModel::NoteModel() -{ - +jop::NoteModel::NoteModel() { + folderId_ = ""; + orderBy_ = "title"; } int jop::NoteModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return collection_.count(); + return folder().noteCount(); } QVariant jop::NoteModel::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= rowCount()) return QVariant(); + Note note = atIndex(index.row()); -// Note note = collection_.at(index.row()); + if (role == IdRole) { + return QVariant(note.id().toString()); + } -// if (role == IdRole) { -// return QVariant(note.id()); -// } + return QVariant(note.value("title").toString()); +} -// return QVariant(note.title()); +jop::Note jop::NoteModel::atIndex(int index) const { + if (folderId_ == "") return Note(); + if (index < 0 || index >= rowCount()) return Note(); + + if (cache_.isset(index)) return cache_.get(index); + + std::vector indexes = cache_.availableBufferAround(index, 32); + if (!indexes.size()) { + qWarning() << "Couldn't acquire buffer"; // "Cannot happen" + return Note(); + } + + int from = indexes[0]; + int to = indexes[indexes.size() - 1]; + + Folder folder = this->folder(); + + QVector notes = folder.notes(orderBy_, to - from + 1, from); + int noteIndex = from; + for (int i = 0; i < notes.size(); i++) { + cache_.set(noteIndex, notes[i]); + noteIndex++; + } + + return cache_.get(index); } void jop::NoteModel::setFolderId(const QString &v) { + if (v == folderId_) return; + beginResetModel(); + cache_.clear(); folderId_ = v; + endResetModel(); } -void jop::NoteModel::setCollection(jop::NoteCollection ¬eCollection) { - beginResetModel(); - collection_ = noteCollection; - endResetModel(); +jop::Folder jop::NoteModel::folder() const { + Folder folder; + if (folderId_ == "") return folder; + folder.load(folderId_); + return folder; } QHash jop::NoteModel::roleNames() const { diff --git a/QtClient/JoplinQtClient/models/notemodel.h b/QtClient/JoplinQtClient/models/notemodel.h index 7e1007ccf..08feea32b 100755 --- a/QtClient/JoplinQtClient/models/notemodel.h +++ b/QtClient/JoplinQtClient/models/notemodel.h @@ -3,7 +3,8 @@ #include -#include "models/notecollection.h" +#include "models/folder.h" +#include "sparsevector.hpp" namespace jop { @@ -21,8 +22,9 @@ public: NoteModel(); int rowCount(const QModelIndex & parent = QModelIndex()) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + Note atIndex(int index) const; void setFolderId(const QString& v); - void setCollection(NoteCollection& noteCollection); + Folder folder() const; protected: @@ -32,7 +34,8 @@ private: QList notes_; QString folderId_; - NoteCollection collection_; + QString orderBy_; + mutable SparseVector cache_; }; diff --git a/QtClient/JoplinQtClient/models/setting.cpp b/QtClient/JoplinQtClient/models/setting.cpp index ec07539ae..fefa5b94c 100755 --- a/QtClient/JoplinQtClient/models/setting.cpp +++ b/QtClient/JoplinQtClient/models/setting.cpp @@ -6,7 +6,8 @@ using namespace jop; void Setting::setSettings(const QSettings::SettingsMap &map) { jop::db().transaction(); - QString sql = "INSERT OR REPLACE INTO settings (`key`, `value`, `type`) VALUES (:key, :value, :type)"; + jop::db().execQuery("DELETE FROM settings"); + QString sql = "INSERT INTO settings (`key`, `value`, `type`) VALUES (:key, :value, :type)"; QSqlQuery query = jop::db().prepare(sql); for (QSettings::SettingsMap::const_iterator it = map.begin(); it != map.end(); ++it) { query.bindValue(":key", it.key()); diff --git a/QtClient/JoplinQtClient/schema.sql b/QtClient/JoplinQtClient/schema.sql index 1c210a842..995d46277 100755 --- a/QtClient/JoplinQtClient/schema.sql +++ b/QtClient/JoplinQtClient/schema.sql @@ -9,7 +9,7 @@ CREATE TABLE notes ( id TEXT PRIMARY KEY, title TEXT, body TEXT, - parent_id INT, + parent_id TEXT, created_time INT, updated_time INT, latitude NUMERIC, diff --git a/QtClient/evernote-import/main.cpp b/QtClient/evernote-import/main.cpp index ba0acd804..92cbdd078 100755 --- a/QtClient/evernote-import/main.cpp +++ b/QtClient/evernote-import/main.cpp @@ -355,8 +355,10 @@ int main(int argc, char *argv[]) { qsrand(QTime::currentTime().msec()); - QString dbPath = "D:/Web/www/joplin/QtClient/data/notes.sqlite"; - QString resourceDir = "D:/Web/www/joplin/QtClient/data/resources"; + QString dbPath = "C:/Users/Laurent/AppData/Local/Joplin/Joplin.sqlite"; + QString resourceDir = "C:/Users/Laurent/AppData/Local/Joplin/resources"; + + QDir(resourceDir).mkpath("."); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbPath); @@ -371,9 +373,11 @@ int main(int argc, char *argv[]) { // TODO: REMOVE REMOVE REMOVE db.exec("DELETE FROM folders"); db.exec("DELETE FROM notes"); + db.exec("DELETE FROM changes"); db.exec("DELETE FROM resources"); db.exec("DELETE FROM note_resources"); db.exec("DELETE FROM tags"); + db.exec("DELETE FROM settings WHERE key = 'lastRevId'"); // TODO: REMOVE REMOVE REMOVE QDir dir("S:/Docs/Textes/Calendrier/EvernoteBackup/Enex20161219"); @@ -388,13 +392,24 @@ int main(int argc, char *argv[]) { QString folderId = createUuid(QString("%1%2%3%4").arg(fileInfo.baseName()).arg(fileInfo.created().toTime_t()).arg((int)qrand()).arg(QDateTime::currentMSecsSinceEpoch())); - QSqlQuery query(db); - query.prepare("INSERT INTO folders (id, title, created_time, updated_time) VALUES (?, ?, ?, ?)"); - query.addBindValue(folderId); - query.addBindValue(fileInfo.baseName()); - query.addBindValue(fileInfo.created().toTime_t()); - query.addBindValue(fileInfo.created().toTime_t()); - query.exec(); + { + QSqlQuery query(db); + query.prepare("INSERT INTO folders (id, title, created_time, updated_time) VALUES (?, ?, ?, ?)"); + query.addBindValue(folderId); + query.addBindValue(fileInfo.baseName()); + query.addBindValue(fileInfo.created().toTime_t()); + query.addBindValue(fileInfo.created().toTime_t()); + query.exec(); + } + + { + QSqlQuery query(db); + query.prepare("INSERT INTO changes (type, item_id, item_type) VALUES (?, ?, ?)"); + query.addBindValue(1); + query.addBindValue(folderId); + query.addBindValue(1); + query.exec(); + } std::vector notes = parseXmlFile(fileInfo.absoluteFilePath());