mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Added BaseModel to allow tracking changes
This commit is contained in:
parent
bc6f419d1e
commit
0a08837ef0
@ -46,7 +46,7 @@ Item {
|
||||
}
|
||||
|
||||
onCurrentItemChanged: {
|
||||
currentItemId = model.idAtIndex(currentIndex);
|
||||
currentItemId = model.indexToId(currentIndex);
|
||||
}
|
||||
|
||||
id: listView
|
||||
|
@ -18,7 +18,8 @@ SOURCES += \
|
||||
settings.cpp \
|
||||
uuid.cpp \
|
||||
dispatcher.cpp \
|
||||
models/change.cpp
|
||||
models/change.cpp \
|
||||
models/basemodel.cpp
|
||||
|
||||
RESOURCES += qml.qrc \
|
||||
database.qrc
|
||||
@ -49,7 +50,9 @@ HEADERS += \
|
||||
simpletypes.h \
|
||||
uuid.h \
|
||||
dispatcher.h \
|
||||
models/change.h
|
||||
models/change.h \
|
||||
models/basemodel.h \
|
||||
enum.h
|
||||
|
||||
DISTFILES +=
|
||||
|
||||
|
@ -105,15 +105,15 @@ void Application::afterSessionInitialization() {
|
||||
}
|
||||
|
||||
void Application::view_currentFolderChanged() {
|
||||
QString folderId = selectedFolderId();
|
||||
noteCollection_ = NoteCollection(db_, folderId, "title ASC");
|
||||
noteModel_.setCollection(noteCollection_);
|
||||
// QString folderId = selectedFolderId();
|
||||
// noteCollection_ = NoteCollection(db_, folderId, "title ASC");
|
||||
// noteModel_.setCollection(noteCollection_);
|
||||
}
|
||||
|
||||
void Application::view_currentNoteChanged() {
|
||||
QString noteId = selectedNoteId();
|
||||
Note note = noteCollection_.byId(noteId);
|
||||
selectedQmlNote_.setNote(note);
|
||||
// QString noteId = selectedNoteId();
|
||||
// Note note = noteCollection_.byId(noteId);
|
||||
// selectedQmlNote_.setNote(note);
|
||||
}
|
||||
|
||||
void Application::view_addNoteButtonClicked() {
|
||||
|
@ -2,23 +2,6 @@
|
||||
|
||||
using namespace jop;
|
||||
|
||||
Database::Database(const QString &path) {
|
||||
// version_ = -1;
|
||||
|
||||
// // QFile::remove(path);
|
||||
|
||||
// db_ = QSqlDatabase::addDatabase("QSQLITE");
|
||||
// db_.setDatabaseName(path);
|
||||
|
||||
// if (!db_.open()) {
|
||||
// qDebug() << "Error: connection with database fail";
|
||||
// } else {
|
||||
// qDebug() << "Database: connection ok";
|
||||
// }
|
||||
|
||||
// upgrade();
|
||||
}
|
||||
|
||||
Database::Database() {}
|
||||
|
||||
void Database::initialize(const QString &path) {
|
||||
@ -26,6 +9,8 @@ void Database::initialize(const QString &path) {
|
||||
|
||||
// QFile::remove(path);
|
||||
|
||||
//qDebug() << Select << Text;
|
||||
|
||||
db_ = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db_.setDatabaseName(path);
|
||||
|
||||
@ -41,6 +26,7 @@ void Database::initialize(const QString &path) {
|
||||
QSqlQuery Database::query(const QString &sql) const {
|
||||
QSqlQuery output(db_);
|
||||
output.prepare(sql);
|
||||
log(sql);
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -101,6 +87,8 @@ QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &table
|
||||
}
|
||||
}
|
||||
|
||||
log(sql, query);
|
||||
|
||||
// qDebug() <<"SQL:"<<sql;
|
||||
|
||||
// QMapIterator<QString, QVariant> i(query.boundValues());
|
||||
@ -112,6 +100,16 @@ QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &table
|
||||
return query;
|
||||
}
|
||||
|
||||
QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &tableName, const QMap<QString, QVariant> &values, const QString &whereCondition) {
|
||||
QStringList fields;
|
||||
VariantVector fieldValues;
|
||||
for (QMap<QString, QVariant>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
fields.push_back(it.key());
|
||||
fieldValues.push_back(it.value());
|
||||
}
|
||||
return buildSqlQuery(type, tableName, fields, fieldValues, whereCondition);
|
||||
}
|
||||
|
||||
bool Database::errorCheck(const QSqlQuery& query) {
|
||||
if (query.lastError().isValid()) {
|
||||
qCritical().noquote() << "SQL query error: " << query.lastError().text().trimmed() << ". Query was: " << query.lastQuery();
|
||||
@ -125,10 +123,15 @@ bool Database::errorCheck(const QSqlQuery& query) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Change Database::newChange() const {
|
||||
// return Change(*this);
|
||||
//}
|
||||
void Database::log(const QString &sql, const QSqlQuery &query) const {
|
||||
qDebug() <<"SQL:"<<sql;
|
||||
|
||||
QMapIterator<QString, QVariant> i(query.boundValues());
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
qDebug() << i.key() << ":" << i.value().toString();
|
||||
}
|
||||
}
|
||||
|
||||
int Database::version() const {
|
||||
if (version_ >= 0) return version_;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define DATABASE_H
|
||||
|
||||
#include <stable.h>
|
||||
#include "enum.h"
|
||||
#include "simpletypes.h"
|
||||
|
||||
namespace jop {
|
||||
@ -12,18 +13,18 @@ public:
|
||||
|
||||
enum QueryType { Select, Insert, Update, Delete };
|
||||
|
||||
Database(const QString& path);
|
||||
Database();
|
||||
void initialize(const QString& path);
|
||||
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 = "");
|
||||
QSqlQuery buildSqlQuery(Database::QueryType type, const QString& tableName, const QMap<QString, QVariant>& values, const QString& whereCondition = "");
|
||||
bool errorCheck(const QSqlQuery& query);
|
||||
|
||||
//Change newChange() const;
|
||||
|
||||
private:
|
||||
|
||||
void log(const QString& sql, const QSqlQuery& query = QSqlQuery()) const;
|
||||
|
||||
QSqlDatabase db_;
|
||||
void upgrade();
|
||||
int version() const;
|
||||
|
6
QtClient/JoplinQtClient/enum.cpp
Executable file
6
QtClient/JoplinQtClient/enum.cpp
Executable file
@ -0,0 +1,6 @@
|
||||
#include "enum.h"
|
||||
|
||||
enum::enum()
|
||||
{
|
||||
|
||||
}
|
14
QtClient/JoplinQtClient/enum.h
Executable file
14
QtClient/JoplinQtClient/enum.h
Executable file
@ -0,0 +1,14 @@
|
||||
#ifndef ENUM_H
|
||||
#define ENUM_H
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
namespace jop {
|
||||
|
||||
enum ColType { UndefinedType, TextColType, IntColType };
|
||||
|
||||
enum Table { UndefinedTable, FoldersTable, NotesTable };
|
||||
|
||||
}
|
||||
|
||||
#endif // ENUM_H
|
283
QtClient/JoplinQtClient/models/basemodel.cpp
Executable file
283
QtClient/JoplinQtClient/models/basemodel.cpp
Executable file
@ -0,0 +1,283 @@
|
||||
#include "basemodel.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "uuid.h"
|
||||
|
||||
using namespace jop;
|
||||
|
||||
QMap<int, QVector<BaseModel::Field>> BaseModel::tableFields_;
|
||||
QHash<QString, QVariant> BaseModel::cache_;
|
||||
|
||||
BaseModel::BaseModel() {
|
||||
|
||||
}
|
||||
|
||||
QStringList BaseModel::changedFields() const {
|
||||
QStringList output;
|
||||
for (QHash<QString, bool>::const_iterator it = changedFields_.begin(); it != changedFields_.end(); ++it) {
|
||||
output.push_back(it.key());
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
int BaseModel::count(Table table) {
|
||||
QString t = BaseModel::tableName(table);
|
||||
QString k = QString("%1:count").arg(t);
|
||||
QVariant r = BaseModel::cacheGet(k);
|
||||
if (r.isValid()) return r.toInt();
|
||||
|
||||
QSqlQuery q = jop::db().query("SELECT count(*) as row_count FROM " + t);
|
||||
q.exec();
|
||||
q.next();
|
||||
int output = q.value(0).toInt();
|
||||
BaseModel::cacheSet(k, QVariant(output));
|
||||
return output;
|
||||
}
|
||||
|
||||
bool BaseModel::save() {
|
||||
bool isNew = this->isNew();
|
||||
|
||||
if (!changedFields_.size() && !isNew) return true;
|
||||
|
||||
QStringList fields = changedFields();
|
||||
|
||||
QMap<QString, QVariant> values;
|
||||
|
||||
foreach (QString field, fields) {
|
||||
values[field] = value(field).toQVariant();
|
||||
}
|
||||
|
||||
if (isNew && primaryKeyIsUuid()) {
|
||||
values[primaryKey()] = uuid::createUuid();
|
||||
}
|
||||
|
||||
changedFields_.clear();
|
||||
|
||||
const QString& tableName = BaseModel::tableName(table());
|
||||
|
||||
if (isNew) {
|
||||
cacheDelete(QString("%1:count").arg(tableName));
|
||||
}
|
||||
|
||||
if (isNew) {
|
||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, tableName, values);
|
||||
q.exec();
|
||||
return jop::db().errorCheck(q);
|
||||
} else {
|
||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, tableName, values, QString("%1 = '%2'").arg(primaryKey()).arg(value("id").toString()));
|
||||
q.exec();
|
||||
return jop::db().errorCheck(q);
|
||||
}
|
||||
|
||||
return false; // Unreachable
|
||||
}
|
||||
|
||||
bool BaseModel::dispose() {
|
||||
const QString& tableName = BaseModel::tableName(table());
|
||||
QSqlQuery q(jop::db().database());
|
||||
q.prepare("DELETE FROM " + tableName + " WHERE " + primaryKey() + " = :id");
|
||||
q.bindValue(":id", id().toString());
|
||||
q.exec();
|
||||
cacheDelete(QString("%1:count").arg(tableName));
|
||||
return jop::db().errorCheck(q);
|
||||
}
|
||||
|
||||
Table BaseModel::table() const {
|
||||
qCritical() << "BaseModel::table() must be overriden";
|
||||
return jop::UndefinedTable;
|
||||
}
|
||||
|
||||
QString BaseModel::primaryKey() const {
|
||||
return "id";
|
||||
}
|
||||
|
||||
bool BaseModel::primaryKeyIsUuid() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseModel::isNew() const {
|
||||
return !valueIsSet(primaryKey());
|
||||
}
|
||||
|
||||
BaseModel::Field createField(const QString& name, QMetaType::Type type) {
|
||||
BaseModel::Field c;
|
||||
c.name = name;
|
||||
c.type = type;
|
||||
return c;
|
||||
}
|
||||
|
||||
QVector<BaseModel::Field> BaseModel::tableFields(jop::Table table) {
|
||||
if (BaseModel::tableFields_.contains(table)) return BaseModel::tableFields_[table];
|
||||
|
||||
QVector<BaseModel::Field> output;
|
||||
if (table == jop::FoldersTable) {
|
||||
output.push_back(createField("id", QMetaType::QString ));
|
||||
output.push_back(createField("title", QMetaType::QString ));
|
||||
output.push_back(createField("created_time", QMetaType::Int ));
|
||||
output.push_back(createField("updated_time", QMetaType::Int ));
|
||||
}
|
||||
|
||||
BaseModel::tableFields_[table] = output;
|
||||
return output;
|
||||
}
|
||||
|
||||
QStringList BaseModel::tableFieldNames(Table table) {
|
||||
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
|
||||
QStringList output;
|
||||
foreach (BaseModel::Field field, fields) {
|
||||
output.push_back(field.name);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool BaseModel::isValidFieldName(Table table, const QString &name) {
|
||||
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
|
||||
foreach (BaseModel::Field col, fields) {
|
||||
if (col.name == name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseModel::loadSqlQuery(const QSqlQuery &query) {
|
||||
values_.clear();
|
||||
QSqlRecord record = query.record();
|
||||
QVector<BaseModel::Field> fields = BaseModel::tableFields(table());
|
||||
|
||||
foreach (BaseModel::Field field, fields) {
|
||||
int idx = record.indexOf(field.name);
|
||||
if (idx < 0) {
|
||||
qCritical() << "Cannot find field" << field.name;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.type == QMetaType::QString) {
|
||||
values_.insert(field.name, Value(query.value(idx).toString()));
|
||||
} else if (field.type == QMetaType::Int) {
|
||||
values_.insert(field.name, Value(query.value(idx).toInt()));
|
||||
} else {
|
||||
qCritical() << "Unsupported value type" << field.name;
|
||||
}
|
||||
}
|
||||
|
||||
changedFields_.clear();
|
||||
}
|
||||
|
||||
QHash<QString, BaseModel::Value> BaseModel::values() const {
|
||||
return values_;
|
||||
}
|
||||
|
||||
BaseModel::Value BaseModel::value(const QString &name) const {
|
||||
if (!valueIsSet(name)) {
|
||||
qCritical() << "Value does not exist" << name;
|
||||
return Value();
|
||||
}
|
||||
return values_[name];
|
||||
}
|
||||
|
||||
bool BaseModel::valueIsSet(const QString &name) const {
|
||||
return values_.contains(name);
|
||||
}
|
||||
|
||||
void BaseModel::setValue(const QString &name, const BaseModel::Value &value) {
|
||||
if (!values_.contains(name)) {
|
||||
values_.insert(name, value);
|
||||
changedFields_.insert(name, true);
|
||||
} else {
|
||||
Value& v = values_[name];
|
||||
if (v.isEqual(value)) return;
|
||||
values_.insert(name, value);
|
||||
changedFields_.insert(name, true);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseModel::setValue(const QString &name, int value) {
|
||||
setValue(name, Value(value));
|
||||
}
|
||||
|
||||
BaseModel::Value BaseModel::id() const {
|
||||
if (!valueIsSet(primaryKey())) return QVariant();
|
||||
return value(primaryKey());
|
||||
}
|
||||
|
||||
QString BaseModel::tableName(Table t) {
|
||||
if (t == jop::FoldersTable) return "folders";
|
||||
if (t == jop::NotesTable) return "notes";
|
||||
return "UNDEFINED";
|
||||
}
|
||||
|
||||
QVariant BaseModel::cacheGet(const QString &key) {
|
||||
if (!BaseModel::cache_.contains(key)) return QVariant();
|
||||
return cache_[key];
|
||||
}
|
||||
|
||||
void BaseModel::cacheSet(const QString &key, const QVariant &value) {
|
||||
BaseModel::cache_[key] = value;
|
||||
}
|
||||
|
||||
void BaseModel::cacheDelete(const QString &key) {
|
||||
BaseModel::cache_.remove(key);
|
||||
}
|
||||
|
||||
void BaseModel::setValue(const QString &name, const QString &value) {
|
||||
setValue(name, Value(value));
|
||||
}
|
||||
|
||||
void BaseModel::setValue(const QString& name, const QVariant& value) {
|
||||
setValue(name, Value(value));
|
||||
}
|
||||
|
||||
BaseModel::Value::Value() {}
|
||||
|
||||
BaseModel::Value::Value(const QString &v) {
|
||||
type_ = QMetaType::QString;
|
||||
stringValue_ = v;
|
||||
}
|
||||
|
||||
BaseModel::Value::Value(int v) {
|
||||
type_ = QMetaType::Int;
|
||||
intValue_ = v;
|
||||
}
|
||||
|
||||
BaseModel::Value::Value(const QVariant &v) {
|
||||
type_ = (QMetaType::Type)v.type();
|
||||
if (type_ == QMetaType::QString) {
|
||||
stringValue_ = v.toString();
|
||||
} else if (type_ == QMetaType::Int) {
|
||||
intValue_ = v.toInt();
|
||||
} else {
|
||||
// Creates an invalid Value
|
||||
}
|
||||
}
|
||||
|
||||
int BaseModel::Value::toInt() const {
|
||||
return intValue_;
|
||||
}
|
||||
|
||||
QString BaseModel::Value::toString() const {
|
||||
return stringValue_;
|
||||
}
|
||||
|
||||
QVariant BaseModel::Value::toQVariant() const {
|
||||
QMetaType::Type t = type();
|
||||
if (t == QMetaType::QString) return QVariant(toString());
|
||||
if (t == QMetaType::Int) return QVariant(toInt());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QMetaType::Type BaseModel::Value::type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
bool BaseModel::Value::isValid() const {
|
||||
return type_ > 0;
|
||||
}
|
||||
|
||||
bool BaseModel::Value::isEqual(const BaseModel::Value &v) const {
|
||||
QMetaType::Type type = v.type();
|
||||
if (this->type() != type) return false;
|
||||
if (type == QMetaType::QString) return toString() == v.toString();
|
||||
if (type == QMetaType::Int) return toInt() == v.toInt();
|
||||
|
||||
qCritical() << "Unreachable";
|
||||
return false;
|
||||
}
|
88
QtClient/JoplinQtClient/models/basemodel.h
Executable file
88
QtClient/JoplinQtClient/models/basemodel.h
Executable file
@ -0,0 +1,88 @@
|
||||
#ifndef BASEMODEL_H
|
||||
#define BASEMODEL_H
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
#include "database.h"
|
||||
#include "enum.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
class BaseModel {
|
||||
|
||||
public:
|
||||
|
||||
struct Field {
|
||||
QString name;
|
||||
QMetaType::Type type;
|
||||
};
|
||||
|
||||
class Value {
|
||||
|
||||
public:
|
||||
|
||||
Value();
|
||||
Value(const QString& v);
|
||||
Value(int v);
|
||||
Value(const QVariant& v);
|
||||
int toInt() const;
|
||||
QString toString() const;
|
||||
QVariant toQVariant() const;
|
||||
QMetaType::Type type() const;
|
||||
bool isValid() const;
|
||||
bool isEqual(const Value& v) const;
|
||||
|
||||
private:
|
||||
|
||||
QMetaType::Type type_;
|
||||
QString stringValue_;
|
||||
int intValue_;
|
||||
|
||||
};
|
||||
|
||||
BaseModel();
|
||||
QStringList changedFields() const;
|
||||
static int count(jop::Table table);
|
||||
bool save();
|
||||
bool dispose();
|
||||
|
||||
virtual Table table() const;
|
||||
virtual QString primaryKey() const;
|
||||
virtual bool primaryKeyIsUuid() const;
|
||||
|
||||
bool isNew() const;
|
||||
|
||||
static QVector<BaseModel::Field> tableFields(Table table);
|
||||
static QStringList tableFieldNames(Table table);
|
||||
static bool isValidFieldName(Table table, const QString& name);
|
||||
|
||||
void loadSqlQuery(const QSqlQuery& query);
|
||||
QHash<QString, Value> values() const;
|
||||
Value value(const QString& name) const;
|
||||
bool valueIsSet(const QString& name) const;
|
||||
void setValue(const QString& name, const Value& value);
|
||||
void setValue(const QString& name, const QVariant& value);
|
||||
void setValue(const QString& name, const QString& value);
|
||||
void setValue(const QString& name, int value);
|
||||
Value id() const;
|
||||
|
||||
static QString tableName(Table t);
|
||||
|
||||
protected:
|
||||
|
||||
QHash<QString, bool> changedFields_;
|
||||
Table table_;
|
||||
QHash<QString, Value> values_;
|
||||
|
||||
static QVariant cacheGet(const QString& key);
|
||||
static void cacheSet(const QString& key, const QVariant& value);
|
||||
static void cacheDelete(const QString& key);
|
||||
|
||||
static QMap<int, QVector<BaseModel::Field>> tableFields_;
|
||||
static QHash<QString, QVariant> cache_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BASEMODEL_H
|
@ -5,64 +5,79 @@
|
||||
|
||||
using namespace jop;
|
||||
|
||||
Folder::Folder() {
|
||||
Folder::Folder() : Item() {
|
||||
|
||||
}
|
||||
|
||||
bool Folder::isNew() const {
|
||||
return id().isEmpty();
|
||||
}
|
||||
//bool Folder::isNew() const {
|
||||
// return id().isEmpty();
|
||||
//}
|
||||
|
||||
bool Folder::save() {
|
||||
bool isNew = this->isNew();
|
||||
//bool Folder::save() {
|
||||
// bool isNew = this->isNew();
|
||||
|
||||
QStringList fields;
|
||||
VariantVector values;
|
||||
if (isNew) {
|
||||
setId(uuid::createUuid());
|
||||
fields << "id";
|
||||
values << id();
|
||||
}
|
||||
fields << "title" << "synced";
|
||||
values << title() << QVariant(0);
|
||||
// QStringList fields;
|
||||
// VariantVector values;
|
||||
// if (isNew) {
|
||||
// setId(uuid::createUuid());
|
||||
// fields << "id";
|
||||
// values << id();
|
||||
// }
|
||||
// fields << "title" << "synced";
|
||||
// values << title() << QVariant(0);
|
||||
|
||||
if (isNew) {
|
||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, "folders", fields, values);
|
||||
q.exec();
|
||||
return jop::db().errorCheck(q);
|
||||
} else {
|
||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + id() + "\"");
|
||||
q.exec();
|
||||
return jop::db().errorCheck(q);
|
||||
}
|
||||
}
|
||||
// if (isNew) {
|
||||
// QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, "folders", fields, values);
|
||||
// q.exec();
|
||||
// return jop::db().errorCheck(q);
|
||||
// } else {
|
||||
// QSqlQuery q = jop::db().buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + id() + "\"");
|
||||
// q.exec();
|
||||
// return jop::db().errorCheck(q);
|
||||
// }
|
||||
//}
|
||||
|
||||
bool Folder::dispose() {
|
||||
QSqlQuery q(jop::db().database());
|
||||
q.prepare("DELETE FROM folders WHERE id = :id");
|
||||
q.bindValue(":id", id());
|
||||
q.exec();
|
||||
return jop::db().errorCheck(q);
|
||||
}
|
||||
//bool Folder::dispose() {
|
||||
// return false;
|
||||
//// QSqlQuery q(jop::db().database());
|
||||
//// q.prepare("DELETE FROM folders WHERE id = :id");
|
||||
//// q.bindValue(":id", id());
|
||||
//// q.exec();
|
||||
//// return jop::db().errorCheck(q);
|
||||
//}
|
||||
|
||||
int Folder::count() {
|
||||
QSqlQuery q = jop::db().query("SELECT count(*) as row_count FROM folders");
|
||||
q.exec();
|
||||
q.next();
|
||||
return q.value(0).toInt();
|
||||
return BaseModel::count(jop::FoldersTable);
|
||||
}
|
||||
|
||||
QVector<Folder> Folder::all(const QString &orderBy) {
|
||||
QSqlQuery q = jop::db().query("SELECT " + Folder::dbFields().join(",") + " FROM folders ORDER BY " + orderBy);
|
||||
//QSqlQuery q = jop::db().query("SELECT " + Folder::dbFields().join(",") + " FROM folders ORDER BY " + orderBy);
|
||||
QSqlQuery q = jop::db().query("SELECT " + BaseModel::tableFieldNames(jop::FoldersTable).join(",") + " FROM folders ORDER BY " + orderBy);
|
||||
q.exec();
|
||||
|
||||
QVector<Folder> output;
|
||||
|
||||
while (q.next()) {
|
||||
Folder folder;
|
||||
folder.fromSqlQuery(q);
|
||||
folder.loadSqlQuery(q);
|
||||
output.push_back(folder);
|
||||
|
||||
// Folder folder;
|
||||
// folder.fromSqlQuery(q);
|
||||
// output.push_back(folder);
|
||||
|
||||
// Folder f2;
|
||||
// f2.loadSqlQuery(q);
|
||||
// qDebug() << "xxx" << f2.value("title").toString();
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Table Folder::table() const {
|
||||
return jop::FoldersTable;
|
||||
}
|
||||
|
||||
bool Folder::primaryKeyIsUuid() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ class Folder : public Item {
|
||||
public:
|
||||
|
||||
Folder();
|
||||
bool isNew() const;
|
||||
bool save();
|
||||
bool dispose();
|
||||
|
||||
static int count();
|
||||
static QVector<Folder> all(const QString& orderBy);
|
||||
|
||||
Table table() const;
|
||||
bool primaryKeyIsUuid() const;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ FolderModel::FolderModel(Database &database) : QAbstractListModel(), db_(databas
|
||||
virtualItemShown_ = false;
|
||||
}
|
||||
|
||||
int FolderModel::rowCount(const QModelIndex & parent) const {
|
||||
int FolderModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent);
|
||||
return Folder::count() + (virtualItemShown_ ? 1 : 0);
|
||||
}
|
||||
|
||||
@ -18,17 +18,17 @@ QVariant FolderModel::data(const QModelIndex & index, int role) const {
|
||||
Folder folder;
|
||||
|
||||
if (virtualItemShown_ && index.row() == rowCount() - 1) {
|
||||
folder.setTitle("Untitled");
|
||||
folder.setValue("title", BaseModel::Value(QString("Untitled")));
|
||||
} else {
|
||||
folder = atIndex(index.row());
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant(folder.title());
|
||||
return folder.value("title").toQVariant();
|
||||
}
|
||||
|
||||
if (role == IdRole) {
|
||||
return QVariant(folder.id());
|
||||
return folder.id().toQVariant();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@ -38,7 +38,7 @@ bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int r
|
||||
Folder folder = atIndex(index.row());
|
||||
|
||||
if (role == Qt::EditRole) {
|
||||
folder.setTitle(value.toString());
|
||||
folder.setValue("title", value);
|
||||
if (!folder.save()) return false;
|
||||
cache_.clear();
|
||||
|
||||
@ -90,7 +90,7 @@ void FolderModel::hideVirtualItem() {
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
QString FolderModel::idAtIndex(int index) const {
|
||||
QString FolderModel::indexToId(int index) const {
|
||||
return data(this->index(index), IdRole).toString();
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ int FolderModel::idToIndex(const QString &id) const {
|
||||
int count = this->rowCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Folder folder = atIndex(i);
|
||||
if (folder.id() == id) return i;
|
||||
if (folder.value("id").toString() == id) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -125,12 +125,12 @@ QHash<int, QByteArray> FolderModel::roleNames() const {
|
||||
|
||||
void FolderModel::addData(const QString &title) {
|
||||
Folder folder;
|
||||
folder.setTitle(title);
|
||||
folder.setValue("title", title);
|
||||
if (!folder.save()) return;
|
||||
|
||||
cache_.clear();
|
||||
|
||||
lastInsertId_ = folder.id();
|
||||
lastInsertId_ = folder.id().toString();
|
||||
|
||||
QVector<int> roles;
|
||||
roles << Qt::DisplayRole;
|
||||
|
@ -50,14 +50,10 @@ public slots:
|
||||
void showVirtualItem();
|
||||
bool virtualItemShown() const;
|
||||
void hideVirtualItem();
|
||||
QString idAtIndex(int index) const;
|
||||
QString indexToId(int index) const;
|
||||
int idToIndex(const QString& id) const;
|
||||
QString lastInsertId() const;
|
||||
|
||||
signals:
|
||||
|
||||
void dataChanging();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -3,56 +3,62 @@
|
||||
|
||||
using namespace jop;
|
||||
|
||||
Item::Item() {
|
||||
synced_ = false;
|
||||
}
|
||||
Item::Item() {}
|
||||
|
||||
QString Item::id() const {
|
||||
return id_;
|
||||
}
|
||||
//Item::Item() {
|
||||
// synced_ = false;
|
||||
//}
|
||||
|
||||
QString Item::title() const {
|
||||
return title_;
|
||||
}
|
||||
////QString Item::id() const {
|
||||
//// return id_;
|
||||
////}
|
||||
|
||||
int Item::createdTime() const {
|
||||
return createdTime_;
|
||||
}
|
||||
//QString Item::title() const {
|
||||
// return title_;
|
||||
//}
|
||||
|
||||
int Item::updatedTime() const {
|
||||
return updatedTime_;
|
||||
}
|
||||
//int Item::createdTime() const {
|
||||
// return createdTime_;
|
||||
//}
|
||||
|
||||
bool Item::synced() const {
|
||||
return synced_;
|
||||
}
|
||||
//int Item::updatedTime() const {
|
||||
// return updatedTime_;
|
||||
//}
|
||||
|
||||
void Item::setId(const QString& v) {
|
||||
id_ = v;
|
||||
}
|
||||
//bool Item::synced() const {
|
||||
// return synced_;
|
||||
//}
|
||||
|
||||
void Item::setTitle(const QString &v) {
|
||||
title_ = v;
|
||||
}
|
||||
//void Item::setId(const QString& v) {
|
||||
//// if (id_ == v) return;
|
||||
// id_ = v;
|
||||
//// changedFields_.push_back("id");
|
||||
//}
|
||||
|
||||
void Item::setCreatedTime(int v) {
|
||||
createdTime_ = v;
|
||||
}
|
||||
//void Item::setTitle(const QString &v) {
|
||||
//// if (title_ == v) return;
|
||||
// title_ = v;
|
||||
//// changedFields_.push_back("title");
|
||||
//}
|
||||
|
||||
void Item::setSynced(bool v) {
|
||||
synced_ = v;
|
||||
}
|
||||
//void Item::setCreatedTime(int v) {
|
||||
// createdTime_ = v;
|
||||
//}
|
||||
|
||||
QStringList Item::dbFields() {
|
||||
QStringList output;
|
||||
output << "id" << "title" << "created_time" << "updated_time" << "synced";
|
||||
return output;
|
||||
}
|
||||
//void Item::setSynced(bool v) {
|
||||
// synced_ = v;
|
||||
//}
|
||||
|
||||
void Item::fromSqlQuery(const QSqlQuery &q) {
|
||||
id_ = q.value(0).toString();
|
||||
title_ = q.value(1).toString();
|
||||
createdTime_ = q.value(2).toInt();
|
||||
updatedTime_ = q.value(3).toInt();
|
||||
synced_ = q.value(4).toBool();
|
||||
}
|
||||
//QStringList Item::dbFields() {
|
||||
// QStringList output;
|
||||
// output << "id" << "title" << "created_time" << "updated_time" << "synced";
|
||||
// return output;
|
||||
//}
|
||||
|
||||
//void Item::fromSqlQuery(const QSqlQuery &q) {
|
||||
// id_ = q.value(0).toString();
|
||||
// title_ = q.value(1).toString();
|
||||
// createdTime_ = q.value(2).toInt();
|
||||
// updatedTime_ = q.value(3).toInt();
|
||||
// synced_ = q.value(4).toBool();
|
||||
//}
|
||||
|
@ -3,35 +3,36 @@
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
#include "models/basemodel.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
class Item {
|
||||
class Item : public BaseModel {
|
||||
|
||||
public:
|
||||
|
||||
Item();
|
||||
|
||||
QString id() const;
|
||||
QString title() const;
|
||||
int createdTime() const;
|
||||
int updatedTime() const;
|
||||
bool synced() const;
|
||||
static QStringList dbFields();
|
||||
// QString title() const;
|
||||
// int createdTime() const;
|
||||
// int updatedTime() const;
|
||||
// bool synced() const;
|
||||
// static QStringList dbFields();
|
||||
|
||||
void setId(const QString &v);
|
||||
void setTitle(const QString& v);
|
||||
void setCreatedTime(int v);
|
||||
void setSynced(bool v);
|
||||
// void setId(const QString &v);
|
||||
// void setTitle(const QString& v);
|
||||
// void setCreatedTime(int v);
|
||||
// void setSynced(bool v);
|
||||
|
||||
void fromSqlQuery(const QSqlQuery& query);
|
||||
// void fromSqlQuery(const QSqlQuery& query);
|
||||
|
||||
private:
|
||||
|
||||
QString id_;
|
||||
QString title_;
|
||||
time_t createdTime_;
|
||||
time_t updatedTime_;
|
||||
bool synced_;
|
||||
// QString id_;
|
||||
// QString title_;
|
||||
// time_t createdTime_;
|
||||
// time_t updatedTime_;
|
||||
// bool synced_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -7,22 +7,22 @@ Note::Note()
|
||||
|
||||
}
|
||||
|
||||
QString Note::body() const {
|
||||
return body_;
|
||||
}
|
||||
//QString Note::body() const {
|
||||
// return body_;
|
||||
//}
|
||||
|
||||
void Note::setBody(const QString &v) {
|
||||
body_ = v;
|
||||
}
|
||||
//void Note::setBody(const QString &v) {
|
||||
// body_ = v;
|
||||
//}
|
||||
|
||||
QStringList Note::dbFields() {
|
||||
QStringList output = Item::dbFields();
|
||||
output << "body";
|
||||
return output;
|
||||
}
|
||||
//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();
|
||||
}
|
||||
//void Note::fromSqlQuery(const QSqlQuery &q) {
|
||||
// Item::fromSqlQuery(q);
|
||||
// int idx = Item::dbFields().size();
|
||||
// body_ = q.value(idx).toString();
|
||||
//}
|
||||
|
@ -11,14 +11,14 @@ class Note : public Item {
|
||||
public:
|
||||
|
||||
Note();
|
||||
QString body() const;
|
||||
void setBody(const QString& v);
|
||||
static QStringList dbFields();
|
||||
void fromSqlQuery(const QSqlQuery &q);
|
||||
// QString body() const;
|
||||
// void setBody(const QString& v);
|
||||
// static QStringList dbFields();
|
||||
// void fromSqlQuery(const QSqlQuery &q);
|
||||
|
||||
private:
|
||||
//private:
|
||||
|
||||
QString body_;
|
||||
// QString body_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -11,36 +11,37 @@ NoteCollection::NoteCollection(Database& db, const QString& parentId, const QStr
|
||||
}
|
||||
|
||||
Note NoteCollection::at(int index) const {
|
||||
if (parentId_ == "") return Note();
|
||||
return Note();
|
||||
// if (parentId_ == "") return Note();
|
||||
|
||||
if (cache_.isset(index)) return cache_.get(index);
|
||||
// if (cache_.isset(index)) return cache_.get(index);
|
||||
|
||||
std::vector<int> indexes = cache_.availableBufferAround(index, 32);
|
||||
if (!indexes.size()) {
|
||||
qWarning() << "Couldn't acquire buffer"; // "Cannot happen"
|
||||
return Note();
|
||||
}
|
||||
// std::vector<int> 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];
|
||||
// int from = indexes[0];
|
||||
// int to = indexes[indexes.size() - 1];
|
||||
|
||||
QSqlQuery q = db_.query("SELECT id, title, body 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();
|
||||
// QSqlQuery q = db_.query("SELECT id, title, body 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 note;
|
||||
note.setId(q.value(0).toString());
|
||||
note.setTitle(q.value(1).toString());
|
||||
note.setBody(q.value(2).toString());
|
||||
// int noteIndex = from;
|
||||
// while (q.next()) {
|
||||
// Note note;
|
||||
// note.setId(q.value(0).toString());
|
||||
// note.setTitle(q.value(1).toString());
|
||||
// note.setBody(q.value(2).toString());
|
||||
|
||||
cache_.set(noteIndex, note);
|
||||
// cache_.set(noteIndex, note);
|
||||
|
||||
noteIndex++;
|
||||
}
|
||||
// noteIndex++;
|
||||
// }
|
||||
|
||||
return cache_.get(index);
|
||||
// return cache_.get(index);
|
||||
}
|
||||
|
||||
// TODO: cache result
|
||||
@ -55,25 +56,26 @@ int NoteCollection::count() const {
|
||||
}
|
||||
|
||||
Note NoteCollection::byId(const QString& id) const {
|
||||
std::vector<int> indexes = cache_.indexes();
|
||||
for (size_t i = 0; i < indexes.size(); i++) {
|
||||
Note note = cache_.get(indexes[i]);
|
||||
if (note.id() == id) return note;
|
||||
}
|
||||
return Note();
|
||||
// std::vector<int> indexes = cache_.indexes();
|
||||
// for (size_t i = 0; i < indexes.size(); i++) {
|
||||
// Note note = cache_.get(indexes[i]);
|
||||
// if (note.id() == id) return note;
|
||||
// }
|
||||
|
||||
QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE id = :id");
|
||||
q.bindValue(":id", id);
|
||||
q.exec();
|
||||
q.next();
|
||||
if (!q.isValid()) {
|
||||
qWarning() << "Invalid note ID:" << id;
|
||||
return Note();
|
||||
}
|
||||
// QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE id = :id");
|
||||
// q.bindValue(":id", id);
|
||||
// q.exec();
|
||||
// q.next();
|
||||
// if (!q.isValid()) {
|
||||
// qWarning() << "Invalid note ID:" << id;
|
||||
// return Note();
|
||||
// }
|
||||
|
||||
// TODO: refactor creation of note from SQL query object
|
||||
Note note;
|
||||
note.setId(q.value(0).toString());
|
||||
note.setTitle(q.value(1).toString());
|
||||
note.setBody(q.value(2).toString());
|
||||
return note;
|
||||
// // TODO: refactor creation of note from SQL query object
|
||||
// Note note;
|
||||
// note.setId(q.value(0).toString());
|
||||
// note.setTitle(q.value(1).toString());
|
||||
// note.setBody(q.value(2).toString());
|
||||
// return note;
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ int jop::NoteModel::rowCount(const QModelIndex &parent) const {
|
||||
QVariant jop::NoteModel::data(const QModelIndex &index, int role) const {
|
||||
if (index.row() < 0 || index.row() >= rowCount()) return QVariant();
|
||||
|
||||
Note note = collection_.at(index.row());
|
||||
// Note note = collection_.at(index.row());
|
||||
|
||||
if (role == IdRole) {
|
||||
return QVariant(note.id());
|
||||
}
|
||||
// if (role == IdRole) {
|
||||
// return QVariant(note.id());
|
||||
// }
|
||||
|
||||
return QVariant(note.title());
|
||||
// return QVariant(note.title());
|
||||
}
|
||||
|
||||
void jop::NoteModel::setFolderId(const QString &v) {
|
||||
|
@ -5,11 +5,11 @@ using namespace jop;
|
||||
QmlNote::QmlNote() {}
|
||||
|
||||
QString QmlNote::title() const {
|
||||
return note_.title();
|
||||
return note_.value("title").toString();
|
||||
}
|
||||
|
||||
QString QmlNote::body() const {
|
||||
return note_.body();
|
||||
return note_.value("body").toString();
|
||||
}
|
||||
|
||||
void QmlNote::setNote(const Note ¬e) {
|
||||
|
@ -14,48 +14,48 @@ void Synchronizer::start() {
|
||||
|
||||
QSqlQuery query;
|
||||
|
||||
std::vector<Folder> folders;
|
||||
query = db_.query("SELECT " + Folder::dbFields().join(',') + " FROM folders WHERE synced = 0");
|
||||
query.exec();
|
||||
// std::vector<Folder> folders;
|
||||
// query = db_.query("SELECT " + Folder::dbFields().join(',') + " FROM folders WHERE synced = 0");
|
||||
// query.exec();
|
||||
|
||||
while (query.next()) {
|
||||
Folder folder;
|
||||
folder.fromSqlQuery(query);
|
||||
folders.push_back(folder);
|
||||
}
|
||||
// while (query.next()) {
|
||||
// Folder folder;
|
||||
// folder.fromSqlQuery(query);
|
||||
// folders.push_back(folder);
|
||||
// }
|
||||
|
||||
QList<Note> notes;
|
||||
query = db_.query("SELECT " + Note::dbFields().join(',') + " FROM notes WHERE synced = 0");
|
||||
query.exec();
|
||||
// QList<Note> notes;
|
||||
// query = db_.query("SELECT " + Note::dbFields().join(',') + " FROM notes WHERE synced = 0");
|
||||
// query.exec();
|
||||
|
||||
while (query.next()) {
|
||||
Note note;
|
||||
note.fromSqlQuery(query);
|
||||
notes << note;
|
||||
}
|
||||
// while (query.next()) {
|
||||
// Note note;
|
||||
// note.fromSqlQuery(query);
|
||||
// notes << note;
|
||||
// }
|
||||
|
||||
for (size_t i = 0; i < folders.size(); i++) {
|
||||
Folder folder = folders[i];
|
||||
QUrlQuery data;
|
||||
data.addQueryItem("id", folder.id());
|
||||
data.addQueryItem("title", folder.title());
|
||||
data.addQueryItem("created_time", QString::number(folder.createdTime()));
|
||||
data.addQueryItem("updated_time", QString::number(folder.updatedTime()));
|
||||
api_.put("folders/" + folder.id(), QUrlQuery(), data, "putFolder:" + folder.id());
|
||||
}
|
||||
// for (size_t i = 0; i < folders.size(); i++) {
|
||||
// Folder folder = folders[i];
|
||||
// QUrlQuery data;
|
||||
// data.addQueryItem("id", folder.id());
|
||||
// data.addQueryItem("title", folder.title());
|
||||
// data.addQueryItem("created_time", QString::number(folder.createdTime()));
|
||||
// data.addQueryItem("updated_time", QString::number(folder.updatedTime()));
|
||||
// api_.put("folders/" + folder.id(), QUrlQuery(), data, "putFolder:" + folder.id());
|
||||
// }
|
||||
|
||||
return;
|
||||
// return;
|
||||
|
||||
for (int i = 0; i < notes.size(); i++) {
|
||||
Note note = notes[i];
|
||||
QUrlQuery data;
|
||||
data.addQueryItem("id", note.id());
|
||||
data.addQueryItem("title", note.title());
|
||||
data.addQueryItem("body", note.body());
|
||||
data.addQueryItem("created_time", QString::number(note.createdTime()));
|
||||
data.addQueryItem("updated_time", QString::number(note.updatedTime()));
|
||||
api_.put("notes/" + note.id(), QUrlQuery(), data, "putNote:" + note.id());
|
||||
}
|
||||
// for (int i = 0; i < notes.size(); i++) {
|
||||
// Note note = notes[i];
|
||||
// QUrlQuery data;
|
||||
// data.addQueryItem("id", note.id());
|
||||
// data.addQueryItem("title", note.title());
|
||||
// data.addQueryItem("body", note.body());
|
||||
// data.addQueryItem("created_time", QString::number(note.createdTime()));
|
||||
// data.addQueryItem("updated_time", QString::number(note.updatedTime()));
|
||||
// api_.put("notes/" + note.id(), QUrlQuery(), data, "putNote:" + note.id());
|
||||
// }
|
||||
}
|
||||
|
||||
void Synchronizer::api_requestDone(const QJsonObject& response, const QString& tag) {
|
||||
|
BIN
QtClient/dependencies/dll-debug/libeay32.dll
Executable file
BIN
QtClient/dependencies/dll-debug/libeay32.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/libssl32.dll
Executable file
BIN
QtClient/dependencies/dll-debug/libssl32.dll
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user