You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
Recreating item list
This commit is contained in:
@ -5,14 +5,23 @@ Item {
|
||||
id: root
|
||||
signal rowsRequested(int fromRowIndex, int toRowIndex)
|
||||
|
||||
property int blabla: 123456;
|
||||
|
||||
property variant items: [];
|
||||
property int itemCount: 0;
|
||||
property int itemHeight: 0;
|
||||
property int itemCount_: 0;
|
||||
property int itemHeight_: 0;
|
||||
property bool needToRequestRows_: false;
|
||||
|
||||
function testing() {
|
||||
console.info("WXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
|
||||
function itemHeight() {
|
||||
if (root.itemHeight_) return root.itemHeight_;
|
||||
var item = itemComponent.createObject(root)
|
||||
item.content = { title: "dummy", id: "" };
|
||||
item.updateDisplay();
|
||||
item.visible = false;
|
||||
root.itemHeight_ = item.height;
|
||||
return root.itemHeight_;
|
||||
}
|
||||
|
||||
function itemCount() {
|
||||
return itemCount_;
|
||||
}
|
||||
|
||||
function setItem(index, itemContent) {
|
||||
@ -21,18 +30,18 @@ Item {
|
||||
return;
|
||||
}
|
||||
|
||||
var item = itemComponent.createObject(scrollArea.contentItem)
|
||||
item.title = itemContent.title;
|
||||
item.invalidateDisplay();
|
||||
var contentTitle = itemContent.title;
|
||||
|
||||
if (!itemHeight) {
|
||||
item.updateDisplay();
|
||||
itemHeight = item.height;
|
||||
}
|
||||
var item = itemComponent.createObject(scrollArea.contentItem)
|
||||
item.content = {
|
||||
id: itemContent.id,
|
||||
title: itemContent.title
|
||||
};
|
||||
item.invalidateDisplay();
|
||||
|
||||
items[index] = item;
|
||||
|
||||
this.invalidateDisplay();
|
||||
root.invalidateDisplay();
|
||||
}
|
||||
|
||||
function setItems(fromIndex, itemContents) {
|
||||
@ -49,46 +58,61 @@ Item {
|
||||
items.push(item);
|
||||
if (!itemHeight) itemHeight = item.height;
|
||||
|
||||
this.invalidateDisplay();
|
||||
root.invalidateDisplay();
|
||||
}
|
||||
|
||||
function setItemCount(count) {
|
||||
this.itemCount = count;
|
||||
this.invalidateDisplay();
|
||||
if (count === root.itemCount_) return;
|
||||
root.itemCount_ = count;
|
||||
root.needToRequestRows_ = true;
|
||||
root.invalidateDisplay();
|
||||
}
|
||||
|
||||
function invalidateDisplay() {
|
||||
updateDisplay();
|
||||
root.updateDisplay();
|
||||
}
|
||||
|
||||
function updateDisplay() {
|
||||
var itemY = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
if (item) {
|
||||
item.y = itemY;
|
||||
}
|
||||
itemY += itemHeight
|
||||
if (item) item.y = itemY;
|
||||
itemY += itemHeight()
|
||||
}
|
||||
|
||||
scrollArea.contentHeight = itemCount * itemHeight;
|
||||
scrollArea.contentHeight = itemCount() * itemHeight();
|
||||
|
||||
// console.info("itemCount itemHeight", this.itemCount, this.itemHeight);
|
||||
// console.info("scrollArea.contentHeight", scrollArea.contentHeight);
|
||||
if (root.needToRequestRows_) {
|
||||
root.needToRequestRows_ = false;
|
||||
var indexes = itemIndexesInView();
|
||||
root.rowsRequested(indexes[0], indexes[1]);
|
||||
}
|
||||
}
|
||||
|
||||
function itemIndexesInView() {
|
||||
var maxVisibleItems = Math.ceil(scrollArea.height / itemHeight());
|
||||
|
||||
var fromIndex = Math.max(0, Math.floor(scrollArea.contentY / itemHeight()));
|
||||
var toIndex = fromIndex + maxVisibleItems;
|
||||
var maxIndex = itemCount() - 1;
|
||||
|
||||
return [Math.min(fromIndex, maxIndex), Math.min(toIndex, maxIndex)];
|
||||
}
|
||||
|
||||
Component {
|
||||
id: itemComponent
|
||||
Item {
|
||||
|
||||
property alias title: label.text
|
||||
id: container
|
||||
//property alias title: label.text
|
||||
property variant content;
|
||||
|
||||
function invalidateDisplay() {
|
||||
this.updateDisplay();
|
||||
container.updateDisplay();
|
||||
}
|
||||
|
||||
function updateDisplay() {
|
||||
this.height = label.height
|
||||
label.text = content.title;
|
||||
container.height = label.height
|
||||
}
|
||||
|
||||
Text {
|
||||
|
@ -47,8 +47,9 @@ SOURCES += \
|
||||
models/abstractlistmodel.cpp \
|
||||
cliapplication.cpp \
|
||||
command.cpp \
|
||||
itemlistcontroller.cpp \
|
||||
qmlutils.cpp
|
||||
qmlutils.cpp \
|
||||
baseitemlistcontroller.cpp \
|
||||
folderlistcontroller.cpp
|
||||
|
||||
RESOURCES += qml.qrc \
|
||||
database.qrc
|
||||
@ -88,8 +89,9 @@ HEADERS += \
|
||||
models/abstractlistmodel.h \
|
||||
cliapplication.h \
|
||||
command.h \
|
||||
itemlistcontroller.h \
|
||||
qmlutils.h
|
||||
qmlutils.h \
|
||||
baseitemlistcontroller.h \
|
||||
folderlistcontroller.h
|
||||
|
||||
defined(JOP_FRONT_END_GUI, var) {
|
||||
SOURCES += application.cpp
|
||||
|
@ -22,7 +22,7 @@ Item {
|
||||
ItemList2 {
|
||||
id: itemList
|
||||
width: 800
|
||||
height: 600
|
||||
height: 500
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,8 +62,13 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
QObject* itemList = qmlUtils::childFromProperty(rootObject, "itemList");
|
||||
|
||||
itemListController_.setItemList(itemList);
|
||||
itemListController_.setParentId(QString(""));
|
||||
|
||||
|
||||
//qmlUtils::callQml(itemList, "testing");
|
||||
|
||||
|
||||
qmlUtils::callQml(itemList, "testing");
|
||||
|
||||
//qDebug() << itemList;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "webapi.h"
|
||||
#include "synchronizer.h"
|
||||
#include "window.h"
|
||||
#include "folderlistcontroller.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
@ -34,6 +35,7 @@ private:
|
||||
WebApi api_;
|
||||
Synchronizer synchronizer_;
|
||||
QTimer synchronizerTimer_;
|
||||
FolderListController itemListController_;
|
||||
|
||||
void afterSessionInitialization();
|
||||
|
||||
|
69
QtClient/JoplinQtClient/baseitemlistcontroller.cpp
Executable file
69
QtClient/JoplinQtClient/baseitemlistcontroller.cpp
Executable file
@ -0,0 +1,69 @@
|
||||
#include "baseitemlistcontroller.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
BaseItemListController::BaseItemListController() :
|
||||
parentId_(QString("")),
|
||||
itemList_(NULL),
|
||||
orderBy_("title") {
|
||||
}
|
||||
|
||||
void BaseItemListController::setItemList(QObject *itemList) {
|
||||
if (itemList_) {
|
||||
qFatal("Cannot reset itemList - create a new ItemListController instead");
|
||||
return;
|
||||
}
|
||||
|
||||
itemList_ = itemList;
|
||||
|
||||
connect(itemList, SIGNAL(rowsRequested(int,int)), this, SLOT(itemList_rowsRequested(int,int)));
|
||||
}
|
||||
|
||||
void BaseItemListController::setParentId(const QString &parentId) {
|
||||
parentId_= parentId;
|
||||
updateItemCount();
|
||||
}
|
||||
|
||||
QString BaseItemListController::parentId() const {
|
||||
return parentId_;
|
||||
}
|
||||
|
||||
QObject *BaseItemListController::itemList() const {
|
||||
return itemList_;
|
||||
}
|
||||
|
||||
void BaseItemListController::setOrderBy(const QString &v) {
|
||||
orderBy_ = v;
|
||||
}
|
||||
|
||||
QString BaseItemListController::orderBy() const {
|
||||
return orderBy_;
|
||||
}
|
||||
|
||||
void BaseItemListController::updateItemCount() {
|
||||
qFatal("BaseItemListController::updateItemCount() must be implemented by child class");
|
||||
}
|
||||
|
||||
void BaseItemListController::itemList_rowsRequested(int fromIndex, int toIndex) {
|
||||
qFatal("BaseItemListController::itemList_rowsRequested() must be implemented by child class");
|
||||
}
|
||||
|
||||
const BaseModel *BaseItemListController::cacheGet(int index) const {
|
||||
qFatal("BaseItemListController::cacheGet() not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BaseItemListController::cacheSet(int index, BaseModel* baseModel) const {
|
||||
qFatal("BaseItemListController::cacheSet() not implemented");
|
||||
}
|
||||
|
||||
bool BaseItemListController::cacheIsset(int index) const {
|
||||
qFatal("BaseItemListController::cacheIsset() not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseItemListController::cacheClear() const {
|
||||
qFatal("BaseItemListController::cacheClear() not implemented");
|
||||
}
|
||||
|
||||
}
|
49
QtClient/JoplinQtClient/baseitemlistcontroller.h
Executable file
49
QtClient/JoplinQtClient/baseitemlistcontroller.h
Executable file
@ -0,0 +1,49 @@
|
||||
#ifndef BASEITEMLISTCONTROLLER_H
|
||||
#define BASEITEMLISTCONTROLLER_H
|
||||
|
||||
#include <stable.h>
|
||||
#include "models/basemodel.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
class BaseItemListController : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BaseItemListController();
|
||||
void setItemList(QObject* itemList);
|
||||
void setParentId(const QString& parentId);
|
||||
QString parentId() const;
|
||||
QObject* itemList() const;
|
||||
void setOrderBy(const QString& v);
|
||||
QString orderBy() const;
|
||||
|
||||
private:
|
||||
|
||||
QObject* itemList_;
|
||||
QString parentId_;
|
||||
QString orderBy_;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void updateItemCount();
|
||||
|
||||
// All these methods are const because we want to be able to clear the
|
||||
// cache or set values from any method including const ones.
|
||||
// http://stackoverflow.com/a/4248661/561309
|
||||
virtual const BaseModel* cacheGet(int index) const;
|
||||
virtual void cacheSet(int index, BaseModel* baseModel) const;
|
||||
virtual bool cacheIsset(int index) const;
|
||||
virtual void cacheClear() const;
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void itemList_rowsRequested(int fromIndex, int toIndex);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BASEITEMLISTCONTROLLER_H
|
@ -116,7 +116,7 @@ int CliApplication::exec() {
|
||||
if (command == "ls") {
|
||||
QString path = args.size() ? args[0] : QString();
|
||||
if (path == "") {
|
||||
std::vector<std::unique_ptr<Folder>> folders = Folder::all();
|
||||
std::vector<std::unique_ptr<Folder>> folders = Folder::all(QString(""));
|
||||
for (size_t i = 0; i < folders.size(); i++) {
|
||||
qDebug().noquote() << folders[i].get()->value("title").toString();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ void Database::initialize(const QString &path) {
|
||||
transactionCount_ = 0;
|
||||
logQueries_ = true;
|
||||
|
||||
//QFile::remove(path);
|
||||
// QFile::remove(path);
|
||||
|
||||
db_ = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db_.setDatabaseName(path);
|
||||
@ -137,7 +137,6 @@ bool Database::commit() {
|
||||
bool Database::execQuery(QSqlQuery &query) {
|
||||
if (logQueries_) {
|
||||
QString sql = query.lastQuery();
|
||||
// if (sql.startsWith("insert", Qt::CaseInsensitive)) {
|
||||
qDebug().noquote() << "SQL:" << sql;
|
||||
|
||||
QMapIterator<QString, QVariant> i(query.boundValues());
|
||||
@ -145,7 +144,6 @@ bool Database::execQuery(QSqlQuery &query) {
|
||||
i.next();
|
||||
qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString();
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
return query.exec();
|
||||
|
61
QtClient/JoplinQtClient/folderlistcontroller.cpp
Executable file
61
QtClient/JoplinQtClient/folderlistcontroller.cpp
Executable file
@ -0,0 +1,61 @@
|
||||
#include "folderlistcontroller.h"
|
||||
#include "qmlutils.h"
|
||||
|
||||
#include "models/folder.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
FolderListController::FolderListController() : BaseItemListController() {}
|
||||
|
||||
void FolderListController::updateItemCount() {
|
||||
int itemCount = Folder::count(parentId());
|
||||
qmlUtils::callQml(itemList(), "setItemCount", QVariantList() << itemCount);
|
||||
}
|
||||
|
||||
const BaseModel *FolderListController::cacheGet(int index) const {
|
||||
return cache_[index].get();
|
||||
}
|
||||
|
||||
void FolderListController::cacheSet(int index, BaseModel *baseModel) const {
|
||||
Folder* folder = static_cast<Folder*>(baseModel);
|
||||
cache_[index] = std::unique_ptr<Folder>(folder);
|
||||
}
|
||||
|
||||
bool FolderListController::cacheIsset(int index) const {
|
||||
return index > 0 && cache_.size() > index;
|
||||
}
|
||||
|
||||
void FolderListController::cacheClear() const {
|
||||
cache_.clear();
|
||||
}
|
||||
|
||||
void FolderListController::itemList_rowsRequested(int fromIndex, int toIndex) {
|
||||
if (!cache_.size()) {
|
||||
cache_ = Folder::all(parentId(), orderBy());
|
||||
}
|
||||
|
||||
//qDebug() << cache_.size();
|
||||
|
||||
if (fromIndex < 0 || toIndex >= cache_.size() || !cache_.size()) {
|
||||
qWarning() << "Invalid folder indexes" << fromIndex << toIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantList output;
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
const BaseModel* model = cacheGet(i);
|
||||
//qDebug() << model;
|
||||
//QVariant v(cacheGet(i));
|
||||
QVariant v = QVariant::fromValue((QObject*)model);
|
||||
//qDebug() << v;
|
||||
output.push_back(v);
|
||||
}
|
||||
|
||||
QVariantList args;
|
||||
args.push_back(fromIndex);
|
||||
args.push_back(output);
|
||||
|
||||
qmlUtils::callQml(itemList(), "setItems", args);
|
||||
}
|
||||
|
||||
}
|
39
QtClient/JoplinQtClient/folderlistcontroller.h
Executable file
39
QtClient/JoplinQtClient/folderlistcontroller.h
Executable file
@ -0,0 +1,39 @@
|
||||
#ifndef ITEMLISTCONTROLLER_H
|
||||
#define ITEMLISTCONTROLLER_H
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
#include "models/folder.h"
|
||||
#include "baseitemlistcontroller.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
class FolderListController : public BaseItemListController {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
FolderListController();
|
||||
|
||||
protected:
|
||||
|
||||
void updateItemCount();
|
||||
const BaseModel* cacheGet(int index) const;
|
||||
void cacheSet(int index, BaseModel* baseModel) const;
|
||||
bool cacheIsset(int index) const;
|
||||
void cacheClear() const;
|
||||
|
||||
private:
|
||||
|
||||
mutable std::vector<std::unique_ptr<Folder>> cache_;
|
||||
|
||||
public slots:
|
||||
|
||||
void itemList_rowsRequested(int fromIndex, int toIndex);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ITEMLISTCONTROLLER_H
|
@ -1,10 +0,0 @@
|
||||
#include "itemlistcontroller.h"
|
||||
|
||||
namespace jop {
|
||||
|
||||
ItemListController::ItemListController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#ifndef ITEMLISTCONTROLLER_H
|
||||
#define ITEMLISTCONTROLLER_H
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
namespace jop {
|
||||
|
||||
class ItemListController {
|
||||
|
||||
public:
|
||||
|
||||
ItemListController();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ITEMLISTCONTROLLER_H
|
@ -20,15 +20,17 @@ QStringList BaseModel::changedFields() const {
|
||||
return output;
|
||||
}
|
||||
|
||||
int BaseModel::count(Table table) {
|
||||
int BaseModel::count(Table table, const QString &parentId) {
|
||||
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("SELECT count(*) AS row_count FROM " + t);
|
||||
QSqlQuery q = jop::db().prepare("SELECT count(*) AS row_count FROM " + t + " WHERE parent_id = :parent_id");
|
||||
q.bindValue(":parent_id", parentId);
|
||||
jop::db().execQuery(q);
|
||||
q.next();
|
||||
if (!jop::db().errorCheck(q)) return 0;
|
||||
int output = q.value(0).toInt();
|
||||
BaseModel::cacheSet(k, QVariant(output));
|
||||
return output;
|
||||
@ -457,6 +459,10 @@ void BaseModel::cacheDelete(const QString &key) {
|
||||
BaseModel::cache_.remove(key);
|
||||
}
|
||||
|
||||
QString BaseModel::title() const {
|
||||
return value("title").toString();
|
||||
}
|
||||
|
||||
void BaseModel::setValue(const QString &name, const QString &value) {
|
||||
setValue(name, Value(value));
|
||||
}
|
||||
|
@ -7,7 +7,12 @@
|
||||
|
||||
namespace jop {
|
||||
|
||||
class BaseModel {
|
||||
class BaseModel : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString title READ title)
|
||||
Q_PROPERTY(QString id READ idString)
|
||||
|
||||
public:
|
||||
|
||||
@ -41,7 +46,7 @@ public:
|
||||
|
||||
BaseModel();
|
||||
QStringList changedFields() const;
|
||||
static int count(jop::Table table);
|
||||
static int count(jop::Table table, const QString &parentId);
|
||||
bool load(const QString& id);
|
||||
bool loadByField(const QString& parentId, const QString& field, const QString& fieldValue);
|
||||
virtual bool save(bool trackChanges = true);
|
||||
@ -74,7 +79,6 @@ public:
|
||||
void setValue(const QString& name, const QJsonValue& value, QMetaType::Type type);
|
||||
//void setValues(const QHash<QString, Value> values);
|
||||
Value id() const;
|
||||
QString idString() const;
|
||||
QString valuesToString() const;
|
||||
void clone(const BaseModel& baseModel);
|
||||
|
||||
@ -93,6 +97,12 @@ protected:
|
||||
static QMap<int, QVector<BaseModel::Field>> tableFields_;
|
||||
static QHash<QString, QVariant> cache_;
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
QString title() const;
|
||||
QString idString() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ QVector<Change> Change::all(int limit) {
|
||||
|
||||
QVector<Change> output;
|
||||
|
||||
while (q.next()) {
|
||||
Change change;
|
||||
change.loadSqlQuery(q);
|
||||
output.push_back(change);
|
||||
}
|
||||
qWarning() << "TODO: fix change iteration";
|
||||
|
||||
// while (q.next()) {
|
||||
// Change change;
|
||||
// change.loadSqlQuery(q);
|
||||
// output.push_back(change);
|
||||
// }
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -36,46 +38,48 @@ QVector<Change> Change::mergedChanges(const QVector<Change>& changes) {
|
||||
QStringList deletedItems;
|
||||
QHash<QString, Change> itemChanges;
|
||||
|
||||
foreach (Change change, changes) {
|
||||
QString itemId = change.value("item_id").toString();
|
||||
Change::Type type = (Change::Type)change.value("type").toInt();
|
||||
qWarning() << "TODO: fix change iteration";
|
||||
|
||||
if (type == Change::Create) {
|
||||
createdItems.push_back(itemId);
|
||||
} else if (type == Change::Delete) {
|
||||
deletedItems.push_back(itemId);
|
||||
}
|
||||
// foreach (Change change, changes) {
|
||||
// QString itemId = change.value("item_id").toString();
|
||||
// Change::Type type = (Change::Type)change.value("type").toInt();
|
||||
|
||||
if (itemChanges.contains(itemId) && type == Change::Update) {
|
||||
// Merge all the "Update" event into one.
|
||||
Change& existingChange = itemChanges[itemId];
|
||||
existingChange.addMergedField(change.value("item_field").toString());
|
||||
} else {
|
||||
itemChanges[itemId] = change;
|
||||
}
|
||||
}
|
||||
// if (type == Change::Create) {
|
||||
// createdItems.push_back(itemId);
|
||||
// } else if (type == Change::Delete) {
|
||||
// deletedItems.push_back(itemId);
|
||||
// }
|
||||
|
||||
// if (itemChanges.contains(itemId) && type == Change::Update) {
|
||||
// // Merge all the "Update" event into one.
|
||||
// Change& existingChange = itemChanges[itemId];
|
||||
// existingChange.addMergedField(change.value("item_field").toString());
|
||||
// } else {
|
||||
// itemChanges[itemId] = change;
|
||||
// }
|
||||
// }
|
||||
|
||||
QVector<Change> output;
|
||||
|
||||
for (QHash<QString, Change>::iterator it = itemChanges.begin(); it != itemChanges.end(); ++it) {
|
||||
QString itemId = it.key();
|
||||
Change& change = it.value();
|
||||
// for (QHash<QString, Change>::iterator it = itemChanges.begin(); it != itemChanges.end(); ++it) {
|
||||
// QString itemId = it.key();
|
||||
// Change& change = it.value();
|
||||
|
||||
if (createdItems.contains(itemId) && deletedItems.contains(itemId)) {
|
||||
// Item both created then deleted - skip
|
||||
continue;
|
||||
}
|
||||
// if (createdItems.contains(itemId) && deletedItems.contains(itemId)) {
|
||||
// // Item both created then deleted - skip
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (deletedItems.contains(itemId)) {
|
||||
// Item was deleted at some point - just return one 'delete' event
|
||||
change.setValue("type", Change::Delete);
|
||||
} else if (createdItems.contains(itemId)) {
|
||||
// Item was created then updated - just return one 'create' event with the latest changes
|
||||
change.setValue("type", Change::Create);
|
||||
}
|
||||
// if (deletedItems.contains(itemId)) {
|
||||
// // Item was deleted at some point - just return one 'delete' event
|
||||
// change.setValue("type", Change::Delete);
|
||||
// } else if (createdItems.contains(itemId)) {
|
||||
// // Item was created then updated - just return one 'create' event with the latest changes
|
||||
// change.setValue("type", Change::Create);
|
||||
// }
|
||||
|
||||
output.push_back(change);
|
||||
}
|
||||
// output.push_back(change);
|
||||
// }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -84,16 +84,22 @@ int Folder::noteIndexById(const QString &orderBy, const QString& id) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Folder::count() {
|
||||
return BaseModel::count(jop::FoldersTable);
|
||||
int Folder::count(const QString &parentId) {
|
||||
return BaseModel::count(jop::FoldersTable, parentId);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Folder>> Folder::all(const QString &orderBy) {
|
||||
QSqlQuery q("SELECT " + BaseModel::tableFieldNames(jop::FoldersTable).join(",") + " FROM " + BaseModel::tableName(jop::FoldersTable) + " ORDER BY " + orderBy);
|
||||
std::vector<std::unique_ptr<Folder>> Folder::all(const QString& parentId, const QString &orderBy) {
|
||||
QSqlQuery q = jop::db().prepare(QString("SELECT %1 FROM %2 WHERE parent_id = :parent_id ORDER BY %3")
|
||||
.arg(BaseModel::tableFieldNames(jop::FoldersTable).join(","))
|
||||
.arg(BaseModel::tableName(jop::FoldersTable))
|
||||
.arg(orderBy));
|
||||
q.bindValue(":parent_id", parentId);
|
||||
jop::db().execQuery(q);
|
||||
|
||||
std::vector<std::unique_ptr<Folder>> output;
|
||||
|
||||
//if (!jop::db().errorCheck(q)) return output;
|
||||
|
||||
while (q.next()) {
|
||||
std::unique_ptr<Folder> folder(new Folder());
|
||||
folder->loadSqlQuery(q);
|
||||
|
@ -9,12 +9,14 @@ namespace jop {
|
||||
|
||||
class Folder : public Item {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Folder();
|
||||
|
||||
static int count();
|
||||
static std::vector<std::unique_ptr<Folder>> all(const QString& orderBy = "title");
|
||||
static int count(const QString& parentId);
|
||||
static std::vector<std::unique_ptr<Folder>> all(const QString& parentId, const QString& orderBy = "title");
|
||||
static std::vector<std::unique_ptr<Folder>> pathToFolders(const QString& path, bool isNotePath);
|
||||
|
||||
//Table table() const;
|
||||
|
@ -66,7 +66,7 @@ void FolderModel::deleteData(const int index) {
|
||||
}
|
||||
|
||||
int FolderModel::baseModelCount() const {
|
||||
return Folder::count();
|
||||
return Folder::count("");
|
||||
}
|
||||
|
||||
const BaseModel *FolderModel::cacheGet(int index) const {
|
||||
|
@ -9,6 +9,8 @@ namespace jop {
|
||||
|
||||
class Item : public BaseModel {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Item();
|
||||
|
@ -26,15 +26,15 @@ const Note *NoteModel::atIndex(int index) const {
|
||||
int from = indexes[0];
|
||||
int to = indexes[indexes.size() - 1];
|
||||
|
||||
Folder folder = this->folder();
|
||||
// Folder folder = this->folder();
|
||||
|
||||
qDebug() << "NoteModel: cache recreated";
|
||||
std::vector<std::unique_ptr<Note>> notes = folder.notes(orderBy_, to - from + 1, from);
|
||||
int noteIndex = from;
|
||||
for (int i = 0; i < notes.size(); i++) {
|
||||
cache_.set(noteIndex, notes[i].release());
|
||||
noteIndex++;
|
||||
}
|
||||
// qDebug() << "NoteModel: cache recreated";
|
||||
// std::vector<std::unique_ptr<Note>> notes = folder.notes(orderBy_, to - from + 1, from);
|
||||
// int noteIndex = from;
|
||||
// for (int i = 0; i < notes.size(); i++) {
|
||||
// cache_.set(noteIndex, notes[i].release());
|
||||
// noteIndex++;
|
||||
// }
|
||||
|
||||
return cache_.get(index);
|
||||
}
|
||||
@ -47,12 +47,12 @@ void NoteModel::setFolderId(const QString &v) {
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
Folder NoteModel::folder() const {
|
||||
Folder folder;
|
||||
if (folderId_ == "") return folder;
|
||||
folder.load(folderId_);
|
||||
return folder;
|
||||
}
|
||||
//Folder NoteModel::folder() const {
|
||||
// Folder folder;
|
||||
// //if (folderId_ == "") return folder;
|
||||
// folder.load(folderId_);
|
||||
// return folder;
|
||||
//}
|
||||
|
||||
int NoteModel::idToIndex(const QString &id) const {
|
||||
std::vector<int> indexes = cache_.indexes();
|
||||
@ -61,8 +61,10 @@ int NoteModel::idToIndex(const QString &id) const {
|
||||
if (note->idString() == id) return indexes[i];
|
||||
}
|
||||
|
||||
Folder f = this->folder();
|
||||
return f.noteIndexById(orderBy_, id);
|
||||
return 0;
|
||||
|
||||
//Folder f = this->folder();
|
||||
//return f.noteIndexById(orderBy_, id);
|
||||
}
|
||||
|
||||
void NoteModel::addData(const QString &title) {
|
||||
@ -81,7 +83,8 @@ void NoteModel::deleteData(int index) {
|
||||
}
|
||||
|
||||
int NoteModel::baseModelCount() const {
|
||||
return folder().noteCount();
|
||||
return 0;
|
||||
//return folder().noteCount();
|
||||
}
|
||||
|
||||
const BaseModel *NoteModel::cacheGet(int index) const {
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
NoteModel();
|
||||
const Note* atIndex(int index) const;
|
||||
void setFolderId(const QString& v);
|
||||
Folder folder() const;
|
||||
//Folder folder() const;
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -13,6 +13,6 @@ QString QmlNote::body() const {
|
||||
}
|
||||
|
||||
void QmlNote::setNote(const Note ¬e) {
|
||||
note_ = note;
|
||||
// note_ = note;
|
||||
emit changed();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace qmlUtils {
|
||||
|
||||
QVariant callQml(QObject* o, const QString &name, const QVariantList &args) {
|
||||
QVariant returnedValue;
|
||||
qDebug() << "Going to call QML:" << name << args;
|
||||
//qDebug() << "Going to call QML:" << name << args;
|
||||
if (args.size() == 0) {
|
||||
QMetaObject::invokeMethod(o, name.toStdString().c_str(), Q_RETURN_ARG(QVariant, returnedValue));
|
||||
} else if (args.size() == 1) {
|
||||
|
@ -20,8 +20,8 @@ CREATE TABLE notes (
|
||||
author TEXT NOT NULL DEFAULT "",
|
||||
source_url TEXT NOT NULL DEFAULT "",
|
||||
is_todo BOOLEAN NOT NULL DEFAULT 0,
|
||||
todo_due INT NOT NULL DEFAULT 0,
|
||||
todo_completed INT NOT NULL DEFAULT 0,
|
||||
todo_due INT NOT NULL DEFAULT "",
|
||||
todo_completed INT NOT NULL DEFAULT "",
|
||||
source_application TEXT NOT NULL DEFAULT "",
|
||||
application_data TEXT NOT NULL DEFAULT "",
|
||||
`order` INT NOT NULL DEFAULT 0
|
||||
|
@ -122,38 +122,40 @@ void Synchronizer::switchState(Synchronizer::SynchronizationState state) {
|
||||
|
||||
uploadsRemaining_ = changes.size();
|
||||
|
||||
foreach (Change change, changes) {
|
||||
jop::Table itemType = (jop::Table)change.value("item_type").toInt();
|
||||
QString itemId = change.value("item_id").toString();
|
||||
Change::Type type = (Change::Type)change.value("type").toInt();
|
||||
qWarning() << "TODO: fix change iteration";
|
||||
|
||||
if (itemType == jop::FoldersTable) {
|
||||
// foreach (Change change, changes) {
|
||||
// jop::Table itemType = (jop::Table)change.value("item_type").toInt();
|
||||
// QString itemId = change.value("item_id").toString();
|
||||
// Change::Type type = (Change::Type)change.value("type").toInt();
|
||||
|
||||
if (type == Change::Create) {
|
||||
// if (itemType == jop::FoldersTable) {
|
||||
|
||||
Folder folder;
|
||||
folder.load(itemId);
|
||||
QUrlQuery data = valuesToUrlQuery(folder.values());
|
||||
api_.put("folders/" + folder.id().toString(), QUrlQuery(), data, "upload:putFolder:" + folder.id().toString());
|
||||
// if (type == Change::Create) {
|
||||
|
||||
} else if (type == Change::Update) {
|
||||
// Folder folder;
|
||||
// folder.load(itemId);
|
||||
// QUrlQuery data = valuesToUrlQuery(folder.values());
|
||||
// api_.put("folders/" + folder.id().toString(), QUrlQuery(), data, "upload:putFolder:" + folder.id().toString());
|
||||
|
||||
Folder folder;
|
||||
folder.load(itemId);
|
||||
QStringList mergedFields = change.mergedFields();
|
||||
QUrlQuery data;
|
||||
foreach (QString field, mergedFields) {
|
||||
data.addQueryItem(field, folder.value(field).toString());
|
||||
}
|
||||
api_.patch("folders/" + folder.id().toString(), QUrlQuery(), data, "upload:patchFolder:" + folder.id().toString());
|
||||
// } else if (type == Change::Update) {
|
||||
|
||||
} else if (type == Change::Delete) {
|
||||
// Folder folder;
|
||||
// folder.load(itemId);
|
||||
// QStringList mergedFields = change.mergedFields();
|
||||
// QUrlQuery data;
|
||||
// foreach (QString field, mergedFields) {
|
||||
// data.addQueryItem(field, folder.value(field).toString());
|
||||
// }
|
||||
// api_.patch("folders/" + folder.id().toString(), QUrlQuery(), data, "upload:patchFolder:" + folder.id().toString());
|
||||
|
||||
api_.del("folders/" + itemId, QUrlQuery(), QUrlQuery(), "upload:deleteFolder:" + itemId);
|
||||
// } else if (type == Change::Delete) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// api_.del("folders/" + itemId, QUrlQuery(), QUrlQuery(), "upload:deleteFolder:" + itemId);
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
checkNextState();
|
||||
|
||||
|
@ -348,6 +348,16 @@ QString extensionFromMimeType(const QString& mimeType) {
|
||||
return "";
|
||||
}
|
||||
|
||||
QString enforceNotNull(const QString& s) {
|
||||
if (s.isEmpty() || s.isNull()) return QString("");
|
||||
return s;
|
||||
}
|
||||
|
||||
QString enforceZero(const QString& f) {
|
||||
if (f.isEmpty() || f.isNull()) return QString("0");
|
||||
return f;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
@ -466,22 +476,22 @@ int main(int argc, char *argv[]) {
|
||||
QSqlQuery query(db);
|
||||
query.prepare("INSERT INTO notes (id, title, body, parent_id, created_time, updated_time, longitude, latitude, altitude, source, author, source_url, is_todo, todo_due, todo_completed, source_application, application_data, `order`) VALUES (:id, :title,:body, :parent_id, :created_time,:updated_time,:longitude,:latitude,:altitude,:source,:author,:source_url,:is_todo,:todo_due,:todo_completed,:source_application,:application_data,:order)");
|
||||
query.bindValue(":id", n.id);
|
||||
query.bindValue(":title", n.title);
|
||||
query.bindValue(":body", markdown);
|
||||
query.bindValue(":parent_id", folderId);
|
||||
query.bindValue(":title", enforceNotNull(n.title));
|
||||
query.bindValue(":body", enforceNotNull(markdown));
|
||||
query.bindValue(":parent_id", enforceNotNull(folderId));
|
||||
query.bindValue(":created_time", n.created);
|
||||
query.bindValue(":updated_time", n.updated);
|
||||
query.bindValue(":longitude", n.longitude);
|
||||
query.bindValue(":latitude", n.latitude);
|
||||
query.bindValue(":altitude", n.altitude);
|
||||
query.bindValue(":source", n.source);
|
||||
query.bindValue(":author", n.author);
|
||||
query.bindValue(":source_url", n.sourceUrl);
|
||||
query.bindValue(":longitude", enforceZero(n.longitude));
|
||||
query.bindValue(":latitude", enforceZero(n.latitude));
|
||||
query.bindValue(":altitude", enforceZero(n.altitude));
|
||||
query.bindValue(":source", enforceNotNull(n.source));
|
||||
query.bindValue(":author", enforceNotNull(n.author));
|
||||
query.bindValue(":source_url", enforceNotNull(n.sourceUrl));
|
||||
query.bindValue(":is_todo", reminderOrder ? 1 : 0);
|
||||
query.bindValue(":todo_due", dateStringToTimestamp(n.reminderTime));
|
||||
query.bindValue(":todo_completed", dateStringToTimestamp(n.reminderDoneTime));
|
||||
query.bindValue(":source_application", n.sourceApplication);
|
||||
query.bindValue(":application_data", n.applicationData);
|
||||
query.bindValue(":source_application", enforceNotNull(n.sourceApplication));
|
||||
query.bindValue(":application_data", enforceNotNull(n.applicationData));
|
||||
query.bindValue(":order", reminderOrder);
|
||||
query.exec();
|
||||
|
||||
|
Reference in New Issue
Block a user