Add signal newDataReady() so the model can signal new data.

master
Jos van den Oever 2017-08-15 13:06:17 +02:00
parent 9202051101
commit f6db39755c
10 changed files with 249 additions and 176 deletions

View File

@ -33,7 +33,7 @@ add_custom_command(
)
add_custom_target(rust_target DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a")
set(Demo_SRCS src/main.cpp src/Tree.cpp src/Bindings.cpp #src/modeltest.cpp
set(Demo_SRCS src/main.cpp src/Tree.cpp src/Bindings.cpp
resource_file.qrc)
add_executable(Demo ${Demo_SRCS})

View File

@ -96,7 +96,7 @@ impl<T: Item> RGeneralItemModel<T> {
let none0 = Entry {
parent: 0,
row: 0,
children: Some(vec![2]),
children: Some(vec![1]),
data: T::default(),
};
self.entries.push(none0);
@ -116,20 +116,17 @@ impl<T: Item> RGeneralItemModel<T> {
self.entries.push(root);
self.model.end_reset_model();
}
fn get_index(&self, mut row: c_int, parent: usize) -> Option<usize> {
fn get_index(&self, row: c_int, parent: usize) -> Option<usize> {
// for an invalid index return the root
if parent == 0 || row < 0 {
return Some(1);
}
let r = self.entries.get(parent)
self.entries.get(parent)
.and_then(|i| i.children.as_ref())
.and_then(|i| i.get(row as usize))
.map(|i| *i);
if r.is_some() {
println!("get_index {} {} {}", row, parent, r.unwrap());}
r
.map(|i| *i)
}
fn get(&self, row: c_int, parent: usize) -> Option<&Entry<T>> {
println!("get entries {}", self.entries.len());
self.get_index(row, parent)
.map(|i| &self.entries[i])
}
@ -152,7 +149,6 @@ println!("get entries {}", self.entries.len());
new_entries.push(e);
}
if new_entries.len() > 0 {
println!("begin_insert_rows {} {} {} {}", entry.row, id, 0, new_entries.len() - 1);
self.model.begin_insert_rows(row, parent, 0,
(new_entries.len() - 1) as c_int);
}
@ -199,12 +195,9 @@ impl<T: Item> TreeTrait for RGeneralItemModel<T> {
}
}
fn can_fetch_more(&self, row: c_int, parent: usize) -> bool {
println!("entries {}", self.entries.len());
let r = self.get(row, parent)
self.get(row, parent)
.map(|entry| entry.children.is_none())
.unwrap_or(false);
println!("can_fetch_more {} {} {}", row, parent, r);
r
.unwrap_or(false)
}
fn fetch_more(&mut self, row: c_int, parent: usize) {
if !self.can_fetch_more(row, parent) {
@ -217,35 +210,31 @@ println!("entries {}", self.entries.len());
.and_then(|entry| entry.children.as_ref())
.map(|i| i.len())
.unwrap_or(0) as c_int;
println!("rrow_count {} {} {}", row, parent, r);
// model does lazy loading, signal that data may be available
if r == 0 && self.can_fetch_more(row, parent) {
self.emit.new_data_ready(row, parent);
}
r
}
fn index(&self, row: c_int, parent: usize) -> usize {
let r = self.get_index(row, parent)
.unwrap_or(0);
println!("index {} {} {}", row, parent, r);
r
self.get_index(row, parent).unwrap_or(0)
}
fn parent(&self, index: usize) -> QModelIndex {
if index > 1 {
if let Some(entry) = self.entries.get(index) {
println!("parent {} {} {}", index, entry.row, entry.parent);
return QModelIndex::create(entry.row as i32, entry.parent);
}
if index >= self.entries.len() {
return QModelIndex::invalid();
}
println!("parent {} invalid", index);
QModelIndex::invalid()
let entry = &self.entries[index];
QModelIndex::create(entry.row as i32, entry.parent)
}
fn file_name(&self, row: c_int, parent: usize) -> String {
println!("file_name {} {}", row, parent);
self.get(row, parent)
.map(|entry| entry.data.file_name())
.unwrap_or_default()
}
fn file_permissions(&self, row: c_int, parent: usize) -> c_int {
//let i = self.get(row,parent);
//self.entries[i].data.file_permissions()
0
self.get(row, parent)
.map(|entry| entry.data.file_permissions())
.unwrap_or_default()
}
fn file_icon(&self, row: c_int, parent: usize) -> Vec<u8> {
Vec::new()
@ -254,7 +243,9 @@ println!("parent {} invalid", index);
String::new()
}
fn file_type(&self, row: c_int, parent: usize) -> c_int {
0
self.get(row, parent)
.map(|entry| entry.data.file_type())
.unwrap_or_default()
}
fn file_size(&self, row: c_int, parent: usize) -> c_ulonglong {
self.get(row, parent)

View File

@ -15,6 +15,7 @@ pub struct TreeQObject {}
pub struct TreeEmitter {
qobject: Arc<Mutex<*const TreeQObject>>,
path_changed: fn(*const TreeQObject),
new_data_ready: fn(*const TreeQObject, row: c_int, parent: usize),
}
unsafe impl Send for TreeEmitter {}
@ -29,6 +30,12 @@ impl TreeEmitter {
(self.path_changed)(ptr);
}
}
pub fn new_data_ready(&self, row: c_int, parent: usize) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.new_data_ready)(ptr, row, parent);
}
}
}
pub struct TreeUniformTree {
@ -68,8 +75,8 @@ pub trait TreeTrait {
fn get_path(&self) -> String;
fn set_path(&mut self, value: String);
fn row_count(&self, row: c_int, parent: usize) -> c_int;
fn can_fetch_more(&self, row: c_int, parent: usize) -> bool { false }
fn fetch_more(&mut self, row: c_int, parent: usize) {}
fn can_fetch_more(&self, c_int, usize) -> bool { false }
fn fetch_more(&mut self, c_int, usize) {}
fn file_name(&self, row: c_int, parent: usize) -> String;
fn file_icon(&self, row: c_int, parent: usize) -> Vec<u8>;
fn file_path(&self, row: c_int, parent: usize) -> String;
@ -83,6 +90,7 @@ pub trait TreeTrait {
#[no_mangle]
pub extern "C" fn tree_new(qobject: *const TreeQObject,
path_changed: fn(*const TreeQObject),
new_data_ready: fn(*const TreeQObject, row: c_int, parent: usize),
begin_reset_model: fn(*const TreeQObject),
end_reset_model: fn(*const TreeQObject),
begin_insert_rows: fn(*const TreeQObject,row: c_int, parent: usize,
@ -97,6 +105,7 @@ pub extern "C" fn tree_new(qobject: *const TreeQObject,
let emit = TreeEmitter {
qobject: Arc::new(Mutex::new(qobject)),
path_changed: path_changed,
new_data_ready: new_data_ready,
};
let model = TreeUniformTree {
qobject: qobject,

View File

@ -134,6 +134,7 @@ pub struct DirectoryQObject {}
pub struct DirectoryEmitter {
qobject: Arc<Mutex<*const DirectoryQObject>>,
path_changed: fn(*const DirectoryQObject),
new_data_ready: fn(*const DirectoryQObject),
}
unsafe impl Send for DirectoryEmitter {}
@ -148,6 +149,12 @@ impl DirectoryEmitter {
(self.path_changed)(ptr);
}
}
pub fn new_data_ready(&self) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.new_data_ready)(ptr);
}
}
}
pub struct DirectoryList {
@ -198,6 +205,7 @@ pub trait DirectoryTrait {
#[no_mangle]
pub extern "C" fn directory_new(qobject: *const DirectoryQObject,
path_changed: fn(*const DirectoryQObject),
new_data_ready: fn(*const DirectoryQObject),
begin_reset_model: fn(*const DirectoryQObject),
end_reset_model: fn(*const DirectoryQObject),
begin_insert_rows: fn(*const DirectoryQObject,
@ -212,6 +220,7 @@ pub extern "C" fn directory_new(qobject: *const DirectoryQObject,
let emit = DirectoryEmitter {
qobject: Arc::new(Mutex::new(qobject)),
path_changed: path_changed,
new_data_ready: new_data_ready,
};
let model = DirectoryList {
qobject: qobject,
@ -295,6 +304,7 @@ pub struct TestTreeQObject {}
pub struct TestTreeEmitter {
qobject: Arc<Mutex<*const TestTreeQObject>>,
path_changed: fn(*const TestTreeQObject),
new_data_ready: fn(*const TestTreeQObject, row: c_int, parent: usize),
}
unsafe impl Send for TestTreeEmitter {}
@ -309,6 +319,12 @@ impl TestTreeEmitter {
(self.path_changed)(ptr);
}
}
pub fn new_data_ready(&self, row: c_int, parent: usize) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.new_data_ready)(ptr, row, parent);
}
}
}
pub struct TestTreeUniformTree {
@ -348,8 +364,8 @@ pub trait TestTreeTrait {
fn get_path(&self) -> String;
fn set_path(&mut self, value: String);
fn row_count(&self, row: c_int, parent: usize) -> c_int;
fn can_fetch_more(&self, row: c_int, parent: usize) -> bool { false }
fn fetch_more(&mut self, row: c_int, parent: usize) {}
fn can_fetch_more(&self, c_int, usize) -> bool { false }
fn fetch_more(&mut self, c_int, usize) {}
fn file_name(&self, row: c_int, parent: usize) -> String;
fn file_icon(&self, row: c_int, parent: usize) -> Vec<u8>;
fn file_path(&self, row: c_int, parent: usize) -> String;
@ -361,6 +377,7 @@ pub trait TestTreeTrait {
#[no_mangle]
pub extern "C" fn test_tree_new(qobject: *const TestTreeQObject,
path_changed: fn(*const TestTreeQObject),
new_data_ready: fn(*const TestTreeQObject, row: c_int, parent: usize),
begin_reset_model: fn(*const TestTreeQObject),
end_reset_model: fn(*const TestTreeQObject),
begin_insert_rows: fn(*const TestTreeQObject,row: c_int, parent: usize,
@ -375,6 +392,7 @@ pub extern "C" fn test_tree_new(qobject: *const TestTreeQObject,
let emit = TestTreeEmitter {
qobject: Arc::new(Mutex::new(qobject)),
path_changed: path_changed,
new_data_ready: new_data_ready,
};
let model = TestTreeUniformTree {
qobject: qobject,

View File

@ -53,6 +53,7 @@ extern "C" {
void person_icon_get(PersonInterface*, QByteArray*, qbytearray_set);
void person_icon_set(void*, qbytearray_t);
DirectoryInterface* directory_new(Directory*, void (*)(Directory*),
void (*)(const Directory*),
void (*)(Directory*),
void (*)(Directory*),
void (*)(Directory*, int, int),
@ -63,6 +64,7 @@ extern "C" {
void directory_path_get(DirectoryInterface*, QString*, qstring_set);
void directory_path_set(void*, qstring_t);
TestTreeInterface* test_tree_new(TestTree*, void (*)(TestTree*),
void (*)(const TestTree*, int, quintptr),
void (*)(TestTree*),
void (*)(TestTree*),
void (*)(TestTree*, int, quintptr, int, int),
@ -117,25 +119,33 @@ Directory::Directory(QObject *parent):
QAbstractItemModel(parent),
d(directory_new(this,
[](Directory* o) { emit o->pathChanged(); },
[](Directory* o) {
emit o->beginResetModel();
[](const Directory* o) {
emit o->newDataReady(QModelIndex());
},
[](Directory* o) {
emit o->endResetModel();
o->beginResetModel();
},
[](Directory* o) {
o->endResetModel();
},
[](Directory* o, int first, int last) {
emit o->beginInsertRows(QModelIndex(), first, last);
o->beginInsertRows(QModelIndex(), first, last);
},
[](Directory* o) {
emit o->endInsertRows();
o->endInsertRows();
},
[](Directory* o, int first, int last) {
emit o->beginRemoveRows(QModelIndex(), first, last);
o->beginRemoveRows(QModelIndex(), first, last);
},
[](Directory* o) {
emit o->endRemoveRows();
o->endRemoveRows();
}
)) {}
)) {
connect(this, &Directory::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Directory::~Directory() {
directory_free(d);
@ -259,25 +269,33 @@ TestTree::TestTree(QObject *parent):
QAbstractItemModel(parent),
d(test_tree_new(this,
[](TestTree* o) { emit o->pathChanged(); },
[](TestTree* o) {
emit o->beginResetModel();
[](const TestTree* o, int row, quintptr id) {
emit o->newDataReady(o->createIndex(row, 0, id));
},
[](TestTree* o) {
emit o->endResetModel();
o->beginResetModel();
},
[](TestTree* o) {
o->endResetModel();
},
[](TestTree* o, int row, quintptr id, int first, int last) {
emit o->beginInsertRows(o->createIndex(row, 0, id), first, last);
o->beginInsertRows(o->createIndex(row, 0, id), first, last);
},
[](TestTree* o) {
emit o->endInsertRows();
o->endInsertRows();
},
[](TestTree* o, int row, quintptr id, int first, int last) {
emit o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
},
[](TestTree* o) {
emit o->endRemoveRows();
o->endRemoveRows();
}
)) {}
)) {
connect(this, &TestTree::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
TestTree::~TestTree() {
test_tree_free(d);
@ -326,8 +344,11 @@ QModelIndex TestTree::index(int row, int column, const QModelIndex &parent) cons
if (row < 0 || column < 0 || column >= 3) {
return QModelIndex();
}
if (parent.isValid() && parent.column() != 0) {
return QModelIndex();
}
const quintptr id = test_tree_index(d, parent.row(), parent.internalId());
return id ?createIndex(row, column, id) :QModelIndex();
return createIndex(row, column, id);
}
QModelIndex TestTree::parent(const QModelIndex &index) const
@ -341,6 +362,9 @@ QModelIndex TestTree::parent(const QModelIndex &index) const
bool TestTree::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0) {
return false;
}
return test_tree_can_fetch_more(d, parent.row(), parent.internalId());
}

View File

@ -48,17 +48,18 @@ public:
QString path() const;
void setPath(const QString& v);
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
QHash<int, QByteArray> roleNames() const;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
QHash<int, QByteArray> roleNames() const override;
signals:
void newDataReady();
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
void pathChanged();
private:
@ -77,17 +78,18 @@ public:
QString path() const;
void setPath(const QString& v);
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
QHash<int, QByteArray> roleNames() const;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
QHash<int, QByteArray> roleNames() const override;
signals:
void newDataReady();
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
void pathChanged();
private:

View File

@ -44,6 +44,7 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) {
extern "C" {
TreeInterface* tree_new(Tree*, void (*)(Tree*),
void (*)(const Tree*, int, quintptr),
void (*)(Tree*),
void (*)(Tree*),
void (*)(Tree*, int, quintptr, int, int),
@ -58,25 +59,33 @@ Tree::Tree(QObject *parent):
QAbstractItemModel(parent),
d(tree_new(this,
[](Tree* o) { emit o->pathChanged(); },
[](Tree* o) {
emit o->beginResetModel();
[](const Tree* o, int row, quintptr id) {
emit o->newDataReady(o->createIndex(row, 0, id));
},
[](Tree* o) {
emit o->endResetModel();
o->beginResetModel();
},
[](Tree* o) {
o->endResetModel();
},
[](Tree* o, int row, quintptr id, int first, int last) {
emit o->beginInsertRows(o->createIndex(row, 0, id), first, last);
o->beginInsertRows(o->createIndex(row, 0, id), first, last);
},
[](Tree* o) {
emit o->endInsertRows();
o->endInsertRows();
},
[](Tree* o, int row, quintptr id, int first, int last) {
emit o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
},
[](Tree* o) {
emit o->endRemoveRows();
o->endRemoveRows();
}
)) {}
)) {
connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Tree::~Tree() {
tree_free(d);
@ -127,8 +136,11 @@ QModelIndex Tree::index(int row, int column, const QModelIndex &parent) const
if (row < 0 || column < 0 || column >= 5) {
return QModelIndex();
}
if (parent.isValid() && parent.column() != 0) {
return QModelIndex();
}
const quintptr id = tree_index(d, parent.row(), parent.internalId());
return id ?createIndex(row, column, id) :QModelIndex();
return createIndex(row, column, id);
}
QModelIndex Tree::parent(const QModelIndex &index) const
@ -142,6 +154,9 @@ QModelIndex Tree::parent(const QModelIndex &index) const
bool Tree::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0) {
return false;
}
return tree_can_fetch_more(d, parent.row(), parent.internalId());
}

View File

@ -17,17 +17,18 @@ public:
QString path() const;
void setPath(const QString& v);
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
QHash<int, QByteArray> roleNames() const;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
QHash<int, QByteArray> roleNames() const override;
signals:
void newDataReady();
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
void pathChanged();
private:

View File

@ -11,10 +11,6 @@
#include <QQmlApplicationEngine>
#include <QtQml/qqml.h>
#include <QQmlContext>
#include <QDebug>
#include <QFileSystemModel>
#include <QStandardItemModel>
//#include "modeltest.h"
int main (int argc, char *argv[])
{
@ -56,64 +52,14 @@ int main (int argc, char *argv[])
qmlRegisterType<Directory>("rust", 1, 0, "Directory");
qmlRegisterType<Person>("rust", 1, 0, "Person");
QFileSystemModel m;
m.setRootPath("/");
qDebug() << m.rowCount();
QModelIndex i = m.index(0,0);
qDebug() << i;
qDebug() << m.parent(i);
qDebug() << m.data(i);
qDebug() << m.rowCount(i) << m.canFetchMore(i);
qDebug() << "---";
/*
QStandardItemModel sm;
sm.appendRow(new QStandardItem());
*/
Tree model;
//ModelTest test(&model);
model.setPath("/");
qDebug() << "rowCount()" << model.rowCount();
i = model.index(0,0);
qDebug() << i;
qDebug() << model.parent(i);
qDebug() << model.data(i);
qDebug() << "rowCount(i)" << model.rowCount(i) << model.canFetchMore(i);
model.fetchMore(i);
model.fetchMore(model.index(1,0,i));
model.fetchMore(model.index(2,0,i));
model.fetchMore(model.index(3,0,i));
model.fetchMore(model.index(4,0,i));
model.fetchMore(model.index(5,0,i));
qDebug() << "rowCount(i)" << model.rowCount(i) << model.canFetchMore(i);
i = model.index(0, 0, i);
model.fetchMore(model.index(1,0,i));
model.fetchMore(model.index(2,0,i));
model.fetchMore(model.index(3,0,i));
model.fetchMore(model.index(4,0,i));
model.fetchMore(model.index(5,0,i));
qDebug() << "rowCount(i)" << model.data(i) << model.rowCount(i) << model.canFetchMore(i);
model.fetchMore(i);
model.fetchMore(model.index(1,0,i));
model.fetchMore(model.index(2,0,i));
model.fetchMore(model.index(3,0,i));
model.fetchMore(model.index(4,0,i));
model.fetchMore(model.index(5,0,i));
qDebug() << "rowCount(i)" << model.data(i) << model.rowCount(i) << model.canFetchMore(i);
i = model.index(0, 0, i);
qDebug() << "rowCount(i)" << model.data(i) << model.rowCount(i) << model.canFetchMore(i);
model.fetchMore(i);
//qDebug() << "rowCount(i)" << model.data(i) << model.rowCount(i) << model.canFetchMore(i);
QTreeView view;
view.setUniformRowHeights(true);
view.setModel(&model);
view.expandAll();
view.show();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("fsModel", &model);
engine.load(QUrl(QStringLiteral("qrc:///demo.qml")));
/**/
return app.exec();
}

View File

@ -270,19 +270,20 @@ QString baseType(const Object& o) {
return "QObject";
}
void writeHeaderItemModel(QTextStream& h, const Object&) {
void writeHeaderItemModel(QTextStream& h) {
h << QString(R"(
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
QHash<int, QByteArray> roleNames() const;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
QHash<int, QByteArray> roleNames() const override;
signals:
void newDataReady();
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
)");
}
@ -382,8 +383,11 @@ QModelIndex %1::index(int row, int column, const QModelIndex &parent) const
if (row < 0 || column < 0 || column >= %3) {
return QModelIndex();
}
if (parent.isValid() && parent.column() != 0) {
return QModelIndex();
}
const quintptr id = %2_index(d, parent.row(), parent.internalId());
return id ?createIndex(row, column, id) :QModelIndex();
return createIndex(row, column, id);
}
QModelIndex %1::parent(const QModelIndex &index) const
@ -397,6 +401,9 @@ QModelIndex %1::parent(const QModelIndex &index) const
bool %1::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0) {
return false;
}
return %2_can_fetch_more(d, parent.row(), parent.internalId());
}
@ -473,7 +480,7 @@ class %1 : public %3
}
}
if (baseType(o) == "QAbstractItemModel") {
writeHeaderItemModel(h, o);
writeHeaderItemModel(h);
}
h << "signals:" << endl;
for (auto p: o.properties) {
@ -494,6 +501,7 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o) {
}
if (o.type == ObjectType::List) {
cpp << QString(R"(,
void (*)(const %1*),
void (*)(%1*),
void (*)(%1*),
void (*)(%1*, int, int),
@ -503,6 +511,7 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o) {
}
if (o.type == ObjectType::UniformTree) {
cpp << QString(R"(,
void (*)(const %1*, int, quintptr),
void (*)(%1*),
void (*)(%1*),
void (*)(%1*, int, quintptr, int, int),
@ -540,49 +549,68 @@ void writeCppObject(QTextStream& cpp, const Object& o) {
}
if (o.type == ObjectType::List) {
cpp << QString(R"(,
[](%1* o) {
emit o->beginResetModel();
[](const %1* o) {
emit o->newDataReady(QModelIndex());
},
[](%1* o) {
emit o->endResetModel();
o->beginResetModel();
},
[](%1* o) {
o->endResetModel();
},
[](%1* o, int first, int last) {
emit o->beginInsertRows(QModelIndex(), first, last);
o->beginInsertRows(QModelIndex(), first, last);
},
[](%1* o) {
emit o->endInsertRows();
o->endInsertRows();
},
[](%1* o, int first, int last) {
emit o->beginRemoveRows(QModelIndex(), first, last);
o->beginRemoveRows(QModelIndex(), first, last);
},
[](%1* o) {
emit o->endRemoveRows();
o->endRemoveRows();
}
)) {
connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
)").arg(o.name);
}
if (o.type == ObjectType::UniformTree) {
cpp << QString(R"(,
[](%1* o) {
emit o->beginResetModel();
[](const %1* o, int row, quintptr id) {
emit o->newDataReady(o->createIndex(row, 0, id));
},
[](%1* o) {
emit o->endResetModel();
o->beginResetModel();
},
[](%1* o) {
o->endResetModel();
},
[](%1* o, int row, quintptr id, int first, int last) {
emit o->beginInsertRows(o->createIndex(row, 0, id), first, last);
o->beginInsertRows(o->createIndex(row, 0, id), first, last);
},
[](%1* o) {
emit o->endInsertRows();
o->endInsertRows();
},
[](%1* o, int row, quintptr id, int first, int last) {
emit o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
o->beginRemoveRows(o->createIndex(row, 0, id), first, last);
},
[](%1* o) {
emit o->endRemoveRows();
o->endRemoveRows();
}
)) {
connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
)").arg(o.name);
}
cpp << QString(R"()) {}
if (o.type == ObjectType::Object) {
cpp << QString(")) {}");
}
cpp << QString(R"(
%1::~%1() {
%2_free(d);
@ -739,6 +767,13 @@ pub struct %1Emitter {
r << QString(" %2_changed: fn(*const %1QObject),\n")
.arg(o.name, snakeCase(p.name));
}
if (o.type == ObjectType::List) {
r << QString(" new_data_ready: fn(*const %1QObject),\n")
.arg(o.name);
} else if (o.type == ObjectType::UniformTree) {
r << QString(" new_data_ready: fn(*const %1QObject, row: c_int, parent: usize),\n")
.arg(o.name);
}
r << QString(R"(}
unsafe impl Send for %1Emitter {}
@ -757,6 +792,23 @@ impl %1Emitter {
}
)").arg(snakeCase(p.name));
}
if (o.type == ObjectType::List) {
r << R"( pub fn new_data_ready(&self) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.new_data_ready)(ptr);
}
}
)";
} else if (o.type == ObjectType::UniformTree) {
r << R"( pub fn new_data_ready(&self, row: c_int, parent: usize) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.new_data_ready)(ptr, row, parent);
}
}
)";
}
QString modelStruct = "";
if (o.type != ObjectType::Object) {
@ -820,12 +872,17 @@ pub trait %1Trait {
if (o.type == ObjectType::UniformTree) {
index = ", row: c_int, parent: usize";
}
r << QString(R"( fn row_count(&self%1) -> c_int;
fn can_fetch_more(&self%1) -> bool { false }
r << QString(" fn row_count(&self%1) -> c_int;\n").arg(index);
if (o.type == ObjectType::UniformTree) {
index = ", c_int, usize";
}
r << QString(R"( fn can_fetch_more(&self%1) -> bool { false }
fn fetch_more(&mut self%1) {}
)").arg(index);
if (o.type == ObjectType::List) {
index = ", row: c_int";
} else if (o.type == ObjectType::UniformTree) {
index = ", row: c_int, parent: usize";
}
for (auto role: o.allRoles) {
r << QString(" fn %1(&self%3) -> %2;\n")
@ -845,6 +902,13 @@ pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname);
r << QString(",\n %2_changed: fn(*const %1QObject)")
.arg(o.name, snakeCase(p.name));
}
if (o.type == ObjectType::List) {
r << QString(",\n new_data_ready: fn(*const %1QObject)")
.arg(o.name);
} else if (o.type == ObjectType::UniformTree) {
r << QString(",\n new_data_ready: fn(*const %1QObject, row: c_int, parent: usize)")
.arg(o.name);
}
if (o.type != ObjectType::Object) {
QString indexDecl;
if (o.type == ObjectType::UniformTree) {
@ -870,6 +934,9 @@ pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname);
for (const Property& p: o.properties) {
r << QString(" %1_changed: %1_changed,\n").arg(snakeCase(p.name));
}
if (o.type != ObjectType::Object) {
r << QString(" new_data_ready: new_data_ready,\n");
}
QString model = "";
if (o.type != ObjectType::Object) {
const QString type = o.type == ObjectType::List ? "List" : "UniformTree";