Allow nesting of binding types.

master
Jos van den Oever 2017-08-26 19:10:18 +02:00
parent 31f2e0078d
commit 64bcac54f0
40 changed files with 1234 additions and 470 deletions

View File

@ -14,6 +14,10 @@ ApplicationWindow {
id: selectionModel
model: sortedFileSystem
}
ItemSelectionModel {
id: processSelection
model: processes
}
TabView {
id: tabView
anchors.fill: parent
@ -116,11 +120,17 @@ ApplicationWindow {
}
}
TreeView {
onClicked: {
processSelection.select(index, ItemSelectionModel.ToggleCurrent);
}
width: parent.width
anchors.top: processFilterInput.bottom
anchors.bottom: parent.bottom
id: processView
model: processes
selection: processSelection
selectionMode: SelectionMode.ExtendedSelection
// selectionMode: SelectionMode.SingleSelection
sortIndicatorVisible: true
alternatingRowColors: true
TableViewColumn {

View File

@ -83,17 +83,17 @@ pub trait FibonacciTrait {
}
#[no_mangle]
pub extern "C" fn fibonacci_new(qobject: *const FibonacciQObject,
pub extern "C" fn fibonacci_new(fibonacci: *mut FibonacciQObject,
input_changed: fn(*const FibonacciQObject),
result_changed: fn(*const FibonacciQObject))
-> *mut Fibonacci {
let emit = FibonacciEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let fibonacci_emit = FibonacciEmitter {
qobject: Arc::new(Mutex::new(fibonacci)),
input_changed: input_changed,
result_changed: result_changed,
};
let d = Fibonacci::create(emit);
Box::into_raw(Box::new(d))
let d_fibonacci = Fibonacci::create(fibonacci_emit);
Box::into_raw(Box::new(d_fibonacci))
}
#[no_mangle]
@ -180,7 +180,7 @@ pub trait FibonacciListTrait {
}
#[no_mangle]
pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject,
pub extern "C" fn fibonacci_list_new(fibonacci_list: *mut FibonacciListQObject,
new_data_ready: fn(*const FibonacciListQObject),
begin_reset_model: fn(*const FibonacciListQObject),
end_reset_model: fn(*const FibonacciListQObject),
@ -193,12 +193,12 @@ pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject,
usize),
end_remove_rows: fn(*const FibonacciListQObject))
-> *mut FibonacciList {
let emit = FibonacciListEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let fibonacci_list_emit = FibonacciListEmitter {
qobject: Arc::new(Mutex::new(fibonacci_list)),
new_data_ready: new_data_ready,
};
let model = FibonacciListList {
qobject: qobject,
qobject: fibonacci_list,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -206,8 +206,8 @@ pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = FibonacciList::create(emit, model);
Box::into_raw(Box::new(d))
let d_fibonacci_list = FibonacciList::create(fibonacci_list_emit, model);
Box::into_raw(Box::new(d_fibonacci_list))
}
#[no_mangle]

View File

@ -178,7 +178,7 @@ pub trait TreeTrait {
}
#[no_mangle]
pub extern "C" fn tree_new(qobject: *const TreeQObject,
pub extern "C" fn tree_new(tree: *mut TreeQObject,
path_changed: fn(*const TreeQObject),
new_data_ready: fn(*const TreeQObject, item: usize, valid: bool),
begin_reset_model: fn(*const TreeQObject),
@ -192,13 +192,13 @@ pub extern "C" fn tree_new(qobject: *const TreeQObject,
usize),
end_remove_rows: fn(*const TreeQObject))
-> *mut Tree {
let emit = TreeEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let tree_emit = TreeEmitter {
qobject: Arc::new(Mutex::new(tree)),
path_changed: path_changed,
new_data_ready: new_data_ready,
};
let model = TreeUniformTree {
qobject: qobject,
qobject: tree,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -206,8 +206,8 @@ pub extern "C" fn tree_new(qobject: *const TreeQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = Tree::create(emit, model);
Box::into_raw(Box::new(d))
let d_tree = Tree::create(tree_emit, model);
Box::into_raw(Box::new(d_tree))
}
#[no_mangle]

View File

@ -147,7 +147,7 @@ pub trait ProcessesTrait {
}
#[no_mangle]
pub extern "C" fn processes_new(qobject: *const ProcessesQObject,
pub extern "C" fn processes_new(processes: *mut ProcessesQObject,
new_data_ready: fn(*const ProcessesQObject, item: usize, valid: bool),
begin_reset_model: fn(*const ProcessesQObject),
end_reset_model: fn(*const ProcessesQObject),
@ -160,12 +160,12 @@ pub extern "C" fn processes_new(qobject: *const ProcessesQObject,
usize),
end_remove_rows: fn(*const ProcessesQObject))
-> *mut Processes {
let emit = ProcessesEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let processes_emit = ProcessesEmitter {
qobject: Arc::new(Mutex::new(processes)),
new_data_ready: new_data_ready,
};
let model = ProcessesUniformTree {
qobject: qobject,
qobject: processes,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -173,8 +173,8 @@ pub extern "C" fn processes_new(qobject: *const ProcessesQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = Processes::create(emit, model);
Box::into_raw(Box::new(d))
let d_processes = Processes::create(processes_emit, model);
Box::into_raw(Box::new(d_processes))
}
#[no_mangle]

View File

@ -112,7 +112,7 @@ pub trait TimeSeriesTrait {
}
#[no_mangle]
pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject,
pub extern "C" fn time_series_new(time_series: *mut TimeSeriesQObject,
new_data_ready: fn(*const TimeSeriesQObject),
begin_reset_model: fn(*const TimeSeriesQObject),
end_reset_model: fn(*const TimeSeriesQObject),
@ -125,12 +125,12 @@ pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject,
usize),
end_remove_rows: fn(*const TimeSeriesQObject))
-> *mut TimeSeries {
let emit = TimeSeriesEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let time_series_emit = TimeSeriesEmitter {
qobject: Arc::new(Mutex::new(time_series)),
new_data_ready: new_data_ready,
};
let model = TimeSeriesList {
qobject: qobject,
qobject: time_series,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -138,8 +138,8 @@ pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = TimeSeries::create(emit, model);
Box::into_raw(Box::new(d))
let d_time_series = TimeSeries::create(time_series_emit, model);
Box::into_raw(Box::new(d_time_series))
}
#[no_mangle]

View File

@ -44,6 +44,15 @@ namespace {
int row;
quintptr id;
};
inline void fibonacciInputChanged(Fibonacci* o)
{
emit o->inputChanged();
}
inline void fibonacciResultChanged(Fibonacci* o)
{
emit o->resultChanged();
}
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +62,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
Fibonacci::Private* fibonacci_new(Fibonacci*, void (*)(Fibonacci*), void (*)(Fibonacci*));
void fibonacci_free(Fibonacci::Private*);
@ -81,7 +89,7 @@ bool FibonacciList::hasChildren(const QModelIndex &parent) const
int FibonacciList::rowCount(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : fibonacci_list_row_count(d);
return (parent.isValid()) ? 0 : fibonacci_list_row_count(m_d);
}
QModelIndex FibonacciList::index(int row, int column, const QModelIndex &parent) const
@ -99,19 +107,19 @@ QModelIndex FibonacciList::parent(const QModelIndex &) const
bool FibonacciList::canFetchMore(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(d);
return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(m_d);
}
void FibonacciList::fetchMore(const QModelIndex &parent)
{
if (!parent.isValid()) {
fibonacci_list_fetch_more(d);
fibonacci_list_fetch_more(m_d);
}
}
void FibonacciList::sort(int column, Qt::SortOrder order)
{
fibonacci_list_sort(d, column, order);
fibonacci_list_sort(m_d, column, order);
}
Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const
{
@ -129,7 +137,7 @@ QVariant FibonacciList::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 0:
v = fibonacci_list_data_result(d, index.row());
v = fibonacci_list_data_result(m_d, index.row());
break;
}
break;
@ -160,29 +168,41 @@ extern "C" {
void (*)(FibonacciList*));
void fibonacci_list_free(FibonacciList::Private*);
};
Fibonacci::Fibonacci(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
Fibonacci::Fibonacci(QObject *parent):
QObject(parent),
d(fibonacci_new(this,
[](Fibonacci* o) { emit o->inputChanged(); },
[](Fibonacci* o) { emit o->resultChanged(); })) {}
m_d(fibonacci_new(this,
fibonacciInputChanged,
fibonacciResultChanged)),
m_ownsPrivate(true) {
}
Fibonacci::~Fibonacci() {
fibonacci_free(d);
if (m_ownsPrivate) {
fibonacci_free(m_d);
}
}
quint32 Fibonacci::input() const
{
return fibonacci_input_get(d);
return fibonacci_input_get(m_d);
}
void Fibonacci::setInput(uint v) {
fibonacci_input_set(d, v);
fibonacci_input_set(m_d, v);
}
quint64 Fibonacci::result() const
{
return fibonacci_result_get(d);
return fibonacci_result_get(m_d);
}
FibonacciList::FibonacciList(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
FibonacciList::FibonacciList(QObject *parent):
QAbstractItemModel(parent),
d(fibonacci_list_new(this,
m_d(fibonacci_list_new(this,
[](const FibonacciList* o) {
emit o->newDataReady(QModelIndex());
},
@ -204,13 +224,15 @@ FibonacciList::FibonacciList(QObject *parent):
[](FibonacciList* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &FibonacciList::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
FibonacciList::~FibonacciList() {
fibonacci_list_free(d);
if (m_ownsPrivate) {
fibonacci_list_free(m_d);
}
}

View File

@ -11,9 +11,11 @@ class Fibonacci : public QObject
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(quint32 input READ input WRITE setInput NOTIFY inputChanged FINAL)
Q_PROPERTY(quint64 result READ result NOTIFY resultChanged FINAL)
explicit Fibonacci(bool owned, QObject *parent);
public:
explicit Fibonacci(QObject *parent = nullptr);
~Fibonacci();
@ -23,9 +25,6 @@ public:
signals:
void inputChanged();
void resultChanged();
private:
quint32 m_input;
quint64 m_result;
};
class FibonacciList : public QAbstractItemModel
@ -34,7 +33,9 @@ class FibonacciList : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
explicit FibonacciList(bool owned, QObject *parent);
public:
explicit FibonacciList(QObject *parent = nullptr);
~FibonacciList();
@ -55,6 +56,5 @@ signals:
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
private:
};
#endif // FIBONACCI_H

View File

@ -44,6 +44,7 @@ namespace {
int row;
quintptr id;
};
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
void processes_data_cmd(const Processes::Private*, quintptr, QString*, qstring_set);
quint8 processes_data_cpu_percentage(const Processes::Private*, quintptr);
@ -86,7 +86,7 @@ int Processes::rowCount(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return 0;
}
return processes_row_count(d, parent.internalId(), parent.isValid());
return processes_row_count(m_d, parent.internalId(), parent.isValid());
}
QModelIndex Processes::index(int row, int column, const QModelIndex &parent) const
@ -100,7 +100,7 @@ QModelIndex Processes::index(int row, int column, const QModelIndex &parent) con
if (row >= rowCount(parent)) {
return QModelIndex();
}
const quintptr id = processes_index(d, parent.internalId(), parent.isValid(), row);
const quintptr id = processes_index(m_d, parent.internalId(), parent.isValid(), row);
return createIndex(row, column, id);
}
@ -109,7 +109,7 @@ QModelIndex Processes::parent(const QModelIndex &index) const
if (!index.isValid()) {
return QModelIndex();
}
const qmodelindex_t parent = processes_parent(d, index.internalId());
const qmodelindex_t parent = processes_parent(m_d, index.internalId());
return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex();
}
@ -118,17 +118,17 @@ bool Processes::canFetchMore(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return false;
}
return processes_can_fetch_more(d, parent.internalId(), parent.isValid());
return processes_can_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Processes::fetchMore(const QModelIndex &parent)
{
processes_fetch_more(d, parent.internalId(), parent.isValid());
processes_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Processes::sort(int column, Qt::SortOrder order)
{
processes_sort(d, column, order);
processes_sort(m_d, column, order);
}
Qt::ItemFlags Processes::flags(const QModelIndex &i) const
{
@ -145,29 +145,29 @@ QVariant Processes::data(const QModelIndex &index, int role) const
case 0:
switch (role) {
case Qt::UserRole + 0:
processes_data_cmd(d, index.internalId(), &s, set_qstring);
processes_data_cmd(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::UserRole + 1:
v = processes_data_cpu_percentage(d, index.internalId());
v = processes_data_cpu_percentage(m_d, index.internalId());
break;
case Qt::UserRole + 2:
v = processes_data_cpu_usage(d, index.internalId());
v = processes_data_cpu_usage(m_d, index.internalId());
break;
case Qt::UserRole + 3:
v = processes_data_memory(d, index.internalId());
v = processes_data_memory(m_d, index.internalId());
break;
case Qt::DisplayRole:
case Qt::UserRole + 4:
processes_data_name(d, index.internalId(), &s, set_qstring);
processes_data_name(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::ToolTipRole:
case Qt::UserRole + 5:
v = processes_data_pid(d, index.internalId());
v = processes_data_pid(m_d, index.internalId());
break;
case Qt::UserRole + 6:
v = processes_data_uid(d, index.internalId());
v = processes_data_uid(m_d, index.internalId());
break;
}
break;
@ -175,7 +175,7 @@ QVariant Processes::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 2:
v = processes_data_cpu_usage(d, index.internalId());
v = processes_data_cpu_usage(m_d, index.internalId());
break;
}
break;
@ -183,7 +183,7 @@ QVariant Processes::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 3:
v = processes_data_memory(d, index.internalId());
v = processes_data_memory(m_d, index.internalId());
break;
}
break;
@ -220,12 +220,16 @@ extern "C" {
void (*)(Processes*));
void processes_free(Processes::Private*);
};
Processes::Processes(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
Processes::Processes(QObject *parent):
QAbstractItemModel(parent),
d(processes_new(this,
m_d(processes_new(this,
[](const Processes* o, quintptr id, bool valid) {
if (valid) {
int row = processes_row(o->d, id);
int row = processes_row(o->m_d, id);
emit o->newDataReady(o->createIndex(row, 0, id));
} else {
emit o->newDataReady(QModelIndex());
@ -239,7 +243,7 @@ Processes::Processes(QObject *parent):
},
[](Processes* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = processes_row(o->d, id.value);
int row = processes_row(o->m_d, id.value);
o->beginInsertRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginInsertRows(QModelIndex(), first, last);
@ -250,7 +254,7 @@ Processes::Processes(QObject *parent):
},
[](Processes* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = processes_row(o->d, id.value);
int row = processes_row(o->m_d, id.value);
o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginRemoveRows(QModelIndex(), first, last);
@ -259,13 +263,15 @@ Processes::Processes(QObject *parent):
[](Processes* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &Processes::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Processes::~Processes() {
processes_free(d);
if (m_ownsPrivate) {
processes_free(m_d);
}
}

View File

@ -11,7 +11,9 @@ class Processes : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
explicit Processes(bool owned, QObject *parent);
public:
explicit Processes(QObject *parent = nullptr);
~Processes();
@ -32,6 +34,5 @@ signals:
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
private:
};
#endif // PROCESSES_H

View File

@ -44,6 +44,7 @@ namespace {
int row;
quintptr id;
};
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
uint time_series_data_input(const TimeSeries::Private*, int);
bool time_series_set_data_input(TimeSeries::Private*, int, uint);
@ -77,7 +77,7 @@ bool TimeSeries::hasChildren(const QModelIndex &parent) const
int TimeSeries::rowCount(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : time_series_row_count(d);
return (parent.isValid()) ? 0 : time_series_row_count(m_d);
}
QModelIndex TimeSeries::index(int row, int column, const QModelIndex &parent) const
@ -95,19 +95,19 @@ QModelIndex TimeSeries::parent(const QModelIndex &) const
bool TimeSeries::canFetchMore(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : time_series_can_fetch_more(d);
return (parent.isValid()) ? 0 : time_series_can_fetch_more(m_d);
}
void TimeSeries::fetchMore(const QModelIndex &parent)
{
if (!parent.isValid()) {
time_series_fetch_more(d);
time_series_fetch_more(m_d);
}
}
void TimeSeries::sort(int column, Qt::SortOrder order)
{
time_series_sort(d, column, order);
time_series_sort(m_d, column, order);
}
Qt::ItemFlags TimeSeries::flags(const QModelIndex &i) const
{
@ -132,10 +132,10 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 0:
v = time_series_data_input(d, index.row());
v = time_series_data_input(m_d, index.row());
break;
case Qt::UserRole + 1:
v = time_series_data_result(d, index.row());
v = time_series_data_result(m_d, index.row());
break;
}
break;
@ -144,7 +144,7 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 1:
v = time_series_data_result(d, index.row());
v = time_series_data_result(m_d, index.row());
break;
}
break;
@ -162,15 +162,15 @@ bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int ro
bool set = false;
if (index.column() == 0) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) {
set = time_series_set_data_input(d, index.row(), value.value<quint32>());
set = time_series_set_data_input(m_d, index.row(), value.value<quint32>());
}
if (role == Qt::UserRole + 1) {
set = time_series_set_data_result(d, index.row(), value.value<quint32>());
set = time_series_set_data_result(m_d, index.row(), value.value<quint32>());
}
}
if (index.column() == 1) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 1) {
set = time_series_set_data_result(d, index.row(), value.value<quint32>());
set = time_series_set_data_result(m_d, index.row(), value.value<quint32>());
}
}
if (set) {
@ -189,9 +189,13 @@ extern "C" {
void (*)(TimeSeries*));
void time_series_free(TimeSeries::Private*);
};
TimeSeries::TimeSeries(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
TimeSeries::TimeSeries(QObject *parent):
QAbstractItemModel(parent),
d(time_series_new(this,
m_d(time_series_new(this,
[](const TimeSeries* o) {
emit o->newDataReady(QModelIndex());
},
@ -213,13 +217,15 @@ TimeSeries::TimeSeries(QObject *parent):
[](TimeSeries* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
TimeSeries::~TimeSeries() {
time_series_free(d);
if (m_ownsPrivate) {
time_series_free(m_d);
}
}

View File

@ -11,7 +11,9 @@ class TimeSeries : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
explicit TimeSeries(bool owned, QObject *parent);
public:
explicit TimeSeries(QObject *parent = nullptr);
~TimeSeries();
@ -32,6 +34,5 @@ signals:
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
private:
};
#endif // TIMESERIES_H

View File

@ -44,6 +44,11 @@ namespace {
int row;
quintptr id;
};
inline void treePathChanged(Tree* o)
{
emit o->pathChanged();
}
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +58,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
void tree_data_file_icon(const Tree::Private*, quintptr, QByteArray*, qbytearray_set);
void tree_data_file_name(const Tree::Private*, quintptr, QString*, qstring_set);
@ -85,7 +89,7 @@ int Tree::rowCount(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return 0;
}
return tree_row_count(d, parent.internalId(), parent.isValid());
return tree_row_count(m_d, parent.internalId(), parent.isValid());
}
QModelIndex Tree::index(int row, int column, const QModelIndex &parent) const
@ -99,7 +103,7 @@ QModelIndex Tree::index(int row, int column, const QModelIndex &parent) const
if (row >= rowCount(parent)) {
return QModelIndex();
}
const quintptr id = tree_index(d, parent.internalId(), parent.isValid(), row);
const quintptr id = tree_index(m_d, parent.internalId(), parent.isValid(), row);
return createIndex(row, column, id);
}
@ -108,7 +112,7 @@ QModelIndex Tree::parent(const QModelIndex &index) const
if (!index.isValid()) {
return QModelIndex();
}
const qmodelindex_t parent = tree_parent(d, index.internalId());
const qmodelindex_t parent = tree_parent(m_d, index.internalId());
return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex();
}
@ -117,17 +121,17 @@ bool Tree::canFetchMore(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return false;
}
return tree_can_fetch_more(d, parent.internalId(), parent.isValid());
return tree_can_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Tree::fetchMore(const QModelIndex &parent)
{
tree_fetch_more(d, parent.internalId(), parent.isValid());
tree_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Tree::sort(int column, Qt::SortOrder order)
{
tree_sort(d, column, order);
tree_sort(m_d, column, order);
}
Qt::ItemFlags Tree::flags(const QModelIndex &i) const
{
@ -145,26 +149,26 @@ QVariant Tree::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DecorationRole:
case Qt::UserRole + 0:
tree_data_file_icon(d, index.internalId(), &b, set_qbytearray);
tree_data_file_icon(m_d, index.internalId(), &b, set_qbytearray);
if (!b.isNull()) v.setValue<QByteArray>(b);
break;
case Qt::DisplayRole:
case Qt::UserRole + 1:
tree_data_file_name(d, index.internalId(), &s, set_qstring);
tree_data_file_name(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::UserRole + 2:
tree_data_file_path(d, index.internalId(), &s, set_qstring);
tree_data_file_path(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::UserRole + 3:
v = tree_data_file_permissions(d, index.internalId());
v = tree_data_file_permissions(m_d, index.internalId());
break;
case Qt::UserRole + 4:
v = tree_data_file_size(d, index.internalId());
v = tree_data_file_size(m_d, index.internalId());
break;
case Qt::UserRole + 5:
v = tree_data_file_type(d, index.internalId());
v = tree_data_file_type(m_d, index.internalId());
break;
}
break;
@ -172,7 +176,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 4:
v = tree_data_file_size(d, index.internalId());
v = tree_data_file_size(m_d, index.internalId());
break;
}
break;
@ -180,7 +184,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 2:
tree_data_file_path(d, index.internalId(), &s, set_qstring);
tree_data_file_path(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
}
@ -189,7 +193,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 3:
v = tree_data_file_permissions(d, index.internalId());
v = tree_data_file_permissions(m_d, index.internalId());
break;
}
break;
@ -197,7 +201,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole:
case Qt::UserRole + 5:
v = tree_data_file_type(d, index.internalId());
v = tree_data_file_type(m_d, index.internalId());
break;
}
break;
@ -236,13 +240,17 @@ extern "C" {
void tree_path_set(Tree::Private*, qstring_t);
void tree_path_set_none(Tree::Private*);
};
Tree::Tree(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
Tree::Tree(QObject *parent):
QAbstractItemModel(parent),
d(tree_new(this,
[](Tree* o) { emit o->pathChanged(); },
m_d(tree_new(this,
treePathChanged,
[](const Tree* o, quintptr id, bool valid) {
if (valid) {
int row = tree_row(o->d, id);
int row = tree_row(o->m_d, id);
emit o->newDataReady(o->createIndex(row, 0, id));
} else {
emit o->newDataReady(QModelIndex());
@ -256,7 +264,7 @@ Tree::Tree(QObject *parent):
},
[](Tree* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = tree_row(o->d, id.value);
int row = tree_row(o->m_d, id.value);
o->beginInsertRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginInsertRows(QModelIndex(), first, last);
@ -267,7 +275,7 @@ Tree::Tree(QObject *parent):
},
[](Tree* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = tree_row(o->d, id.value);
int row = tree_row(o->m_d, id.value);
o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginRemoveRows(QModelIndex(), first, last);
@ -276,26 +284,28 @@ Tree::Tree(QObject *parent):
[](Tree* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Tree::~Tree() {
tree_free(d);
if (m_ownsPrivate) {
tree_free(m_d);
}
}
QString Tree::path() const
{
QString v;
tree_path_get(d, &v, set_qstring);
tree_path_get(m_d, &v, set_qstring);
return v;
}
void Tree::setPath(const QString& v) {
if (v.isNull()) {
tree_path_set_none(d);
tree_path_set_none(m_d);
} else {
tree_path_set(d, v);
tree_path_set(m_d, v);
}
}

View File

@ -11,8 +11,10 @@ class Tree : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged FINAL)
explicit Tree(bool owned, QObject *parent);
public:
explicit Tree(QObject *parent = nullptr);
~Tree();
@ -36,7 +38,5 @@ signals:
void newDataReady(const QModelIndex &parent) const;
signals:
void pathChanged();
private:
QString m_path;
};
#endif // TREE_H

View File

@ -16,6 +16,10 @@ QString upperInitial(const QString& name) {
return name.left(1).toUpper() + name.mid(1);
}
QString lowerInitial(const QString& name) {
return name.left(1).toLower() + name.mid(1);
}
QString writeProperty(const QString& name) {
return "WRITE set" + upperInitial(name) + " ";
}
@ -106,7 +110,7 @@ bool %1::hasChildren(const QModelIndex &parent) const
int %1::rowCount(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : %2_row_count(d);
return (parent.isValid()) ? 0 : %2_row_count(m_d);
}
QModelIndex %1::index(int row, int column, const QModelIndex &parent) const
@ -124,13 +128,13 @@ QModelIndex %1::parent(const QModelIndex &) const
bool %1::canFetchMore(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : %2_can_fetch_more(d);
return (parent.isValid()) ? 0 : %2_can_fetch_more(m_d);
}
void %1::fetchMore(const QModelIndex &parent)
{
if (!parent.isValid()) {
%2_fetch_more(d);
%2_fetch_more(m_d);
}
}
)").arg(o.name, lcname, QString::number(o.columnCount));
@ -158,7 +162,7 @@ int %1::rowCount(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return 0;
}
return %2_row_count(d, parent.internalId(), parent.isValid());
return %2_row_count(m_d, parent.internalId(), parent.isValid());
}
QModelIndex %1::index(int row, int column, const QModelIndex &parent) const
@ -172,7 +176,7 @@ QModelIndex %1::index(int row, int column, const QModelIndex &parent) const
if (row >= rowCount(parent)) {
return QModelIndex();
}
const quintptr id = %2_index(d, parent.internalId(), parent.isValid(), row);
const quintptr id = %2_index(m_d, parent.internalId(), parent.isValid(), row);
return createIndex(row, column, id);
}
@ -181,7 +185,7 @@ QModelIndex %1::parent(const QModelIndex &index) const
if (!index.isValid()) {
return QModelIndex();
}
const qmodelindex_t parent = %2_parent(d, index.internalId());
const qmodelindex_t parent = %2_parent(m_d, index.internalId());
return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex();
}
@ -190,12 +194,12 @@ bool %1::canFetchMore(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return false;
}
return %2_can_fetch_more(d, parent.internalId(), parent.isValid());
return %2_can_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void %1::fetchMore(const QModelIndex &parent)
{
%2_fetch_more(d, parent.internalId(), parent.isValid());
%2_fetch_more(m_d, parent.internalId(), parent.isValid());
}
)").arg(o.name, lcname, QString::number(o.columnCount));
}
@ -203,7 +207,7 @@ void %1::fetchMore(const QModelIndex &parent)
cpp << QString(R"(
void %1::sort(int column, Qt::SortOrder order)
{
%2_sort(d, column, order);
%2_sort(m_d, column, order);
}
Qt::ItemFlags %1::flags(const QModelIndex &i) const
{
@ -241,15 +245,15 @@ QVariant %1::data(const QModelIndex &index, int role) const
}
cpp << QString(" case Qt::UserRole + %1:\n").arg(i);
if (ip.type.name == "QString") {
cpp << QString(" %1_data_%2(d%4, &s, set_%3);\n")
cpp << QString(" %1_data_%2(m_d%4, &s, set_%3);\n")
.arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index);
cpp << " if (!s.isNull()) v.setValue<QString>(s);\n";
} else if (ip.type.name == "QByteArray") {
cpp << QString(" %1_data_%2(d%4, &b, set_%3);\n")
cpp << QString(" %1_data_%2(m_d%4, &b, set_%3);\n")
.arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index);
cpp << " if (!b.isNull()) v.setValue<QByteArray>(b);\n";
} else {
cpp << QString(" v = %1_data_%2(d%3);\n")
cpp << QString(" v = %1_data_%2(m_d%3);\n")
.arg(lcname, snakeCase(ip.name), index);
}
cpp << " break;\n";
@ -295,12 +299,12 @@ bool %1::setData(const QModelIndex &index, const QVariant &value, int role)
test += " || value.isNull()";
}
cpp << " if (" << test << ") {\n";
cpp << QString(" set = %1_set_data_%2_none(d%3);")
cpp << QString(" set = %1_set_data_%2_none(m_d%3);")
.arg(lcname, snakeCase(ip.name), index) << endl;
cpp << " } else\n";
}
QString val = QString("value.value<%1>()").arg(ip.type.name);
cpp << QString(" set = %1_set_data_%2(d%3, %4);")
cpp << QString(" set = %1_set_data_%2(m_d%3, %4);")
.arg(lcname, snakeCase(ip.name), index, val) << endl;
cpp << " }\n";
}
@ -314,29 +318,52 @@ bool %1::setData(const QModelIndex &index, const QVariant &value, int role)
)";
}
void writeHeaderObject(QTextStream& h, const Object& o) {
void writeHeaderObject(QTextStream& h, const Object& o, const Configuration& conf) {
h << QString(R"(
class %1 : public %3
{
Q_OBJEC%2
public:
)").arg(o.name, "T", baseType(o));
for (auto object: conf.objects) {
if (object.containsObject()) {
h << " friend class " << object.name << ";\n";
}
}
h << R"(public:
class Private;
private:
Private * const d;
)").arg(o.name, "T", baseType(o));
)";
for (auto p: o.properties) {
h << QString(" Q_PROPERTY(%1 %2 READ %2 %3NOTIFY %2Changed FINAL)")
.arg(p.type.name, p.name,
p.write ? writeProperty(p.name) :"") << endl;
if (p.type.type == BindingType::Object) {
h << " " << p.type.name << "* const m_" << p.name << ";\n";
}
}
h << QString(R"(public:
h << R"( Private * m_d;
bool m_ownsPrivate;
)";
for (auto p: o.properties) {
bool obj = p.type.type == BindingType::Object;
h << QString(" Q_PROPERTY(%1 %2 READ %2 %3%4FINAL)")
.arg(p.type.name + (obj ?"*" :""),
p.name,
p.write ? writeProperty(p.name) :"",
obj ?"" :("NOTIFY " +p.name + "Changed "))
<< endl;
}
h << QString(R"( explicit %1(bool owned, QObject *parent);
public:
explicit %1(QObject *parent = nullptr);
~%1();
)").arg(o.name);
for (auto p: o.properties) {
h << " " << p.type.name << " " << p.name << "() const;" << endl;
if (p.write) {
h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl;
if (p.type.type == BindingType::Object) {
h << " const " << p.type.name << "* " << p.name << "() const;" << endl;
h << " " << p.type.name << "* " << p.name << "();" << endl;
} else {
h << " " << p.type.name << " " << p.name << "() const;" << endl;
if (p.write) {
h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl;
}
}
}
if (baseType(o) == "QAbstractItemModel") {
@ -344,20 +371,22 @@ private:
}
h << "signals:" << endl;
for (auto p: o.properties) {
h << " void " << p.name << "Changed();" << endl;
}
h << "private:" << endl;
for (auto p: o.properties) {
h << " " << p.type.name << " m_" << p.name << ";" << endl;
if (p.type.type != BindingType::Object) {
h << " void " << p.name << "Changed();" << endl;
}
}
h << "};" << endl;
}
void writeObjectCDecl(QTextStream& cpp, const Object& o) {
const QString lcname(snakeCase(o.name));
cpp << QString(" %1::Private* %2_new(%1*").arg(o.name, lcname);
for (int i = 0; i < o.properties.size(); ++i) {
cpp << QString(", void (*)(%1*)").arg(o.name);
void constructorArgsDecl(QTextStream& cpp, const Object& o, const Configuration& conf) {
cpp << o.name << "*";
for (auto p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(", ");
constructorArgsDecl(cpp, conf.findObject(p.type.name), conf);
} else {
cpp << QString(", void (*)(%1*)").arg(o.name);
}
}
if (o.type == ObjectType::List) {
cpp << QString(R"(,
@ -379,37 +408,21 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o) {
void (*)(%1*, option<quintptr>, int, int),
void (*)(%1*))").arg(o.name);
}
cpp << ");" << endl;
cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname)
<< endl;
for (const Property& p: o.properties) {
const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name));
if (p.type.isComplex()) {
cpp << QString(" void %2_get(const %1::Private*, %3);")
.arg(o.name, base, cGetType(p.type)) << endl;
} else {
cpp << QString(" %3 %2_get(const %1::Private*);")
.arg(o.name, base, p.type.name) << endl;
}
if (p.write) {
cpp << QString(" void %2_set(%1::Private*, %3);")
.arg(o.name, base, p.type.cSetType) << endl;
if (p.optional) {
cpp << QString(" void %2_set_none(%1::Private*);")
.arg(o.name, base) << endl;
}
}
}
}
void writeCppObject(QTextStream& cpp, const Object& o) {
QString changedF(const Object& o, const Property& p) {
return lowerInitial(o.name) + upperInitial(p.name) + "Changed";
}
void constructorArgs(QTextStream& cpp, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
cpp << QString("%1::%1(QObject *parent):\n %2(parent),")
.arg(o.name, baseType(o)) << endl;
cpp << QString(" d(%1_new(this").arg(lcname);
for (const Property& p: o.properties) {
cpp << QString(",\n [](%1* o) { emit o->%2Changed(); }")
.arg(o.name, p.name);
if (p.type.type == BindingType::Object) {
cpp << ", m_" << p.name;
constructorArgs(cpp, conf.findObject(p.type.name), conf);
} else {
cpp << ",\n " << changedF(o, p);
}
}
if (o.type == ObjectType::List) {
cpp << QString(R"(,
@ -434,18 +447,13 @@ void writeCppObject(QTextStream& cpp, const Object& o) {
[](%1* o) {
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"(,
[](const %1* o, quintptr id, bool valid) {
if (valid) {
int row = %2_row(o->d, id);
int row = %2_row(o->m_d, id);
emit o->newDataReady(o->createIndex(row, 0, id));
} else {
emit o->newDataReady(QModelIndex());
@ -459,7 +467,7 @@ void writeCppObject(QTextStream& cpp, const Object& o) {
},
[](%1* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = %2_row(o->d, id.value);
int row = %2_row(o->m_d, id.value);
o->beginInsertRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginInsertRows(QModelIndex(), first, last);
@ -470,7 +478,7 @@ void writeCppObject(QTextStream& cpp, const Object& o) {
},
[](%1* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = %2_row(o->d, id.value);
int row = %2_row(o->m_d, id.value);
o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginRemoveRows(QModelIndex(), first, last);
@ -479,44 +487,115 @@ void writeCppObject(QTextStream& cpp, const Object& o) {
[](%1* o) {
o->endRemoveRows();
}
)) {
connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
)").arg(o.name, lcname);
}
if (o.type == ObjectType::Object) {
cpp << QString(")) {}");
}
void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
cpp << QString(" %1::Private* %2_new(").arg(o.name, lcname);
constructorArgsDecl(cpp, o, conf);
cpp << ");" << endl;
cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname)
<< endl;
for (const Property& p: o.properties) {
const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name));
if (p.type.type == BindingType::Object) {
cpp << QString(" %3::Private* %2_get(const %1::Private*);")
.arg(o.name, base, p.type.name) << endl;
} else if (p.type.isComplex()) {
cpp << QString(" void %2_get(const %1::Private*, %3);")
.arg(o.name, base, cGetType(p.type)) << endl;
} else {
cpp << QString(" %3 %2_get(const %1::Private*);")
.arg(o.name, base, p.type.name) << endl;
}
if (p.write) {
cpp << QString(" void %2_set(%1::Private*, %3);")
.arg(o.name, base, p.type.cSetType) << endl;
if (p.optional) {
cpp << QString(" void %2_set_none(%1::Private*);")
.arg(o.name, base) << endl;
}
}
}
cpp << QString(R"(
}
void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
cpp << QString("%1::%1(bool /*owned*/, QObject *parent):\n %2(parent),")
.arg(o.name, baseType(o)) << endl;
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1(new %2(false, this)),\n")
.arg(p.name, p.type.name);
}
}
cpp << " m_d(0),\n m_ownsPrivate(false) {}\n";
cpp << QString("%1::%1(QObject *parent):\n %2(parent),")
.arg(o.name, baseType(o)) << endl;
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1(new %2(false, this)),\n")
.arg(p.name, p.type.name);
}
}
cpp << QString(" m_d(%1_new(this").arg(lcname);
constructorArgs(cpp, o, conf);
cpp << ")),\n m_ownsPrivate(true) {\n";
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1->m_d = %2_%1_get(this->m_d);\n")
.arg(p.name, snakeCase(o.name));
}
}
if (o.type != ObjectType::Object) {
cpp << QString(R"( connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
)").arg(o.name);
}
cpp << QString(R"(}
%1::~%1() {
%2_free(d);
if (m_ownsPrivate) {
%2_free(m_d);
}
}
)").arg(o.name, lcname);
for (const Property& p: o.properties) {
const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name));
cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name);
if (p.type.isComplex()) {
if (p.type.type == BindingType::Object) {
cpp << QString(R"(const %3* %1::%2() const
{
return m_%4;
}
%3* %1::%2()
{
return m_%4;
}
)").arg(o.name, p.name, p.type.name, snakeCase(p.name));
} else if (p.type.isComplex()) {
cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name);
cpp << " " << p.type.name << " v;\n";
cpp << " " << base << "_get(d, &v, set_" << p.type.name.toLower()
cpp << " " << base << "_get(m_d, &v, set_" << p.type.name.toLower()
<< ");\n";
cpp << " return v;\n}\n";
} else {
cpp << QString(" return %1_get(d);\n}\n").arg(base);
cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name);
cpp << QString(" return %1_get(m_d);\n}\n").arg(base);
}
if (p.write) {
cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v) {" << endl;
if (p.optional) {
cpp << QString(" if (v.isNull()) {") << endl;
cpp << QString(" %1_set_none(d);").arg(base) << endl;
cpp << QString(" %1_set_none(m_d);").arg(base) << endl;
cpp << QString(" } else {") << endl;
cpp << QString(" %1_set(d, v);").arg(base) << endl;
cpp << QString(" %1_set(m_d, v);").arg(base) << endl;
cpp << QString(" }") << endl;
} else {
cpp << QString(" %1_set(d, v);").arg(base) << endl;
cpp << QString(" %1_set(m_d, v);").arg(base) << endl;
}
cpp << "}" << endl;
}
@ -536,7 +615,12 @@ void writeHeader(const Configuration& conf) {
)").arg(guard);
for (auto object: conf.objects) {
writeHeaderObject(h, object);
if (object.containsObject()) {
h << "class " << object.name << ";\n";
}
}
for (auto object: conf.objects) {
writeHeaderObject(h, object, conf);
}
h << QString("#endif // %1\n").arg(guard);
@ -591,6 +675,19 @@ namespace {
int row;
quintptr id;
};
)").arg(conf.hFile.fileName());
for (auto o: conf.objects) {
for (auto p: o.properties) {
if (p.type.type == BindingType::Object) {
continue;
}
cpp << " inline void " << changedF(o, p) << "(" << o.name << "* o)\n";
cpp << " {\n emit o->" << p.name << "Changed();\n }\n";
}
}
cpp << R"(
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -600,8 +697,7 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
)").arg(conf.hFile.fileName());
)";
for (auto object: conf.objects) {
if (object.type != ObjectType::Object) {
@ -609,11 +705,11 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) {
}
cpp << "extern \"C\" {\n";
writeObjectCDecl(cpp, object);
writeObjectCDecl(cpp, object, conf);
cpp << "};" << endl;
}
for (auto object: conf.objects) {
writeCppObject(cpp, object);
writeCppObject(cpp, object, conf);
}
}

View File

@ -16,78 +16,76 @@ BindingTypeProperties simpleType(BindingType type, const char* name, const char*
};
}
const QMap<BindingType, BindingTypeProperties>& bindingTypeProperties() {
static QMap<BindingType, BindingTypeProperties> p;
QList<BindingTypeProperties>& bindingTypeProperties() {
static QList<BindingTypeProperties> p;
if (p.empty()) {
QMap<BindingType, BindingTypeProperties> f;
f.insert(BindingType::Bool, simpleType(BindingType::Bool, "bool", "true"));
f.insert(BindingType::UChar, {
.type = BindingType::UChar,
.name = "quint8",
.cppSetType = "quint8",
.cSetType = "quint8",
.rustType = "u8",
.rustTypeInit = "0",
});
f.insert(BindingType::Int, {
.type = BindingType::Int,
.name = "qint32",
.cppSetType = "qint32",
.cSetType = "qint32",
.rustType = "i32",
.rustTypeInit = "0",
});
f.insert(BindingType::UInt, {
.type = BindingType::UInt,
.name = "quint32",
.cppSetType = "uint",
.cSetType = "uint",
.rustType = "u32",
.rustTypeInit = "0"
});
f.insert(BindingType::ULongLong, {
.type = BindingType::ULongLong,
.name = "quint64",
.cppSetType = "quint64",
.cSetType = "quint64",
.rustType = "u64",
.rustTypeInit = "0"
});
f.insert(BindingType::Float, {
.type = BindingType::Float,
.name = "float",
.cppSetType = "float",
.cSetType = "float",
.rustType = "f32",
.rustTypeInit = "0.0"
});
f.insert(BindingType::QString, {
.type = BindingType::QString,
.name = "QString",
.cppSetType = "const QString&",
.cSetType = "qstring_t",
.rustType = "String",
.rustTypeInit = "String::new()"
});
f.insert(BindingType::QByteArray, {
.type = BindingType::QByteArray,
.name = "QByteArray",
.cppSetType = "const QByteArray&",
.cSetType = "qbytearray_t",
.rustType = "Vec<u8>",
.rustTypeInit = "Vec::new()"
});
QList<BindingTypeProperties> f;
f.append(simpleType(BindingType::Bool, "bool", "true"));
f.append({
.type = BindingType::UChar,
.name = "quint8",
.cppSetType = "quint8",
.cSetType = "quint8",
.rustType = "u8",
.rustTypeInit = "0",
});
f.append({
.type = BindingType::Int,
.name = "qint32",
.cppSetType = "qint32",
.cSetType = "qint32",
.rustType = "i32",
.rustTypeInit = "0",
});
f.append({
.type = BindingType::UInt,
.name = "quint32",
.cppSetType = "uint",
.cSetType = "uint",
.rustType = "u32",
.rustTypeInit = "0"
});
f.append({
.type = BindingType::ULongLong,
.name = "quint64",
.cppSetType = "quint64",
.cSetType = "quint64",
.rustType = "u64",
.rustTypeInit = "0"
});
f.append({
.type = BindingType::Float,
.name = "float",
.cppSetType = "float",
.cSetType = "float",
.rustType = "f32",
.rustTypeInit = "0.0"
});
f.append({
.type = BindingType::QString,
.name = "QString",
.cppSetType = "const QString&",
.cSetType = "qstring_t",
.rustType = "String",
.rustTypeInit = "String::new()"
});
f.append({
.type = BindingType::QByteArray,
.name = "QByteArray",
.cppSetType = "const QByteArray&",
.cSetType = "qbytearray_t",
.rustType = "Vec<u8>",
.rustTypeInit = "Vec::new()"
});
p = f;
}
return p;
}
BindingTypeProperties parseBindingType(const QString& value) {
QMapIterator<BindingType, BindingTypeProperties> i(bindingTypeProperties());
while (i.hasNext()) {
i.next();
if (value == i.value().name) {
return i.value();
for (auto type: bindingTypeProperties()) {
if (value == type.name) {
return type;
}
}
QTextStream err(stderr);
@ -206,7 +204,16 @@ parseConfiguration(const QString& path) {
c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h");
const QJsonObject& object = o.value("objects").toObject();
for (const QString& key: object.keys()) {
c.objects.append(parseObject(key, object[key].toObject()));
Object o = parseObject(key, object[key].toObject());
c.objects.append(o);
bindingTypeProperties().append({
.type = BindingType::Object,
.name = o.name,
.cppSetType = o.name,
.cSetType = o.name,
.rustType = o.name,
.rustTypeInit = "",
});
}
const QJsonObject rust = o.value("rust").toObject();
c.rustdir = QDir(base.filePath(rust.value("dir").toString()));

View File

@ -28,7 +28,86 @@ QString rustTypeInit(const T& p)
return p.type.rustTypeInit;
}
void writeRustInterfaceObject(QTextStream& r, const Object& o) {
void rConstructorArgsDecl(QTextStream& r, const QString& name, const Object& o, const Configuration& conf) {
r << QString("%2: *mut %1QObject").arg(o.name, name);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
r << QString(", ");
rConstructorArgsDecl(r, p.name, conf.findObject(p.type.name), conf);
} else {
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, item: usize, valid: bool)")
.arg(o.name);
}
if (o.type != ObjectType::Object) {
QString indexDecl;
if (o.type == ObjectType::UniformTree) {
indexDecl = " item: usize, valid: bool,";
}
r << QString(R"(,
begin_reset_model: fn(*const %1QObject),
end_reset_model: fn(*const %1QObject),
begin_insert_rows: fn(*const %1QObject,%2
usize,
usize),
end_insert_rows: fn(*const %1QObject),
begin_remove_rows: fn(*const %1QObject,%2
usize,
usize),
end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl);
}
}
void rConstructorArgs(QTextStream& r, const QString& name, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
rConstructorArgs(r, p.name, conf.findObject(p.type.name), conf);
}
}
r << QString(R"( let %2_emit = %1Emitter {
qobject: Arc::new(Mutex::new(%2)),
)").arg(o.name, name);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) continue;
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";
model = ", model";
r << QString(R"( };
let model = %1%2 {
qobject: %3,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
end_insert_rows: end_insert_rows,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
)").arg(o.name, type, name);
}
r << QString(" };\n let d_%3 = %1::create(%3_emit%2")
.arg(o.name, model, name);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
r << ",\n d_" << p.name;
}
}
r << ");\n";
}
void writeRustInterfaceObject(QTextStream& r, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
r << QString(R"(
pub struct %1QObject {}
@ -38,6 +117,9 @@ pub struct %1Emitter {
qobject: Arc<Mutex<*const %1QObject>>,
)").arg(o.name);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
continue;
}
r << QString(" %2_changed: fn(*const %1QObject),\n")
.arg(o.name, snakeCase(p.name));
}
@ -58,6 +140,9 @@ impl %1Emitter {
}
)").arg(o.name);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
continue;
}
r << QString(R"( pub fn %1_changed(&self) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
@ -133,14 +218,25 @@ impl %1%2 {
r << QString(R"(}
pub trait %1Trait {
fn create(emit: %1Emitter%2) -> Self;
fn create(emit: %1Emitter%2)").arg(o.name, modelStruct);
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
r << ",\n " << snakeCase(p.name) << ": " << p.type.name;
}
}
r << QString(R"() -> Self;
fn emit(&self) -> &%1Emitter;
)").arg(o.name, modelStruct);
)").arg(o.name);
for (const Property& p: o.properties) {
const QString lc(snakeCase(p.name));
r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p));
if (p.write) {
r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p));
if (p.type.type == BindingType::Object) {
r << QString(" fn get_%1(&self) -> &%2;\n").arg(lc, rustType(p));
r << QString(" fn get_mut_%1(&mut self) -> &mut %2;\n").arg(lc, rustType(p));
} else {
r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p));
if (p.write) {
r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p));
}
}
}
if (o.type == ObjectType::List) {
@ -173,75 +269,30 @@ pub trait %1Trait {
r << QString(R"(}
#[no_mangle]
pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname);
for (const Property& p: o.properties) {
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, item: usize, valid: bool)")
.arg(o.name);
}
if (o.type != ObjectType::Object) {
QString indexDecl;
if (o.type == ObjectType::UniformTree) {
indexDecl = " item: usize, valid: bool,";
}
r << QString(R"(,
begin_reset_model: fn(*const %1QObject),
end_reset_model: fn(*const %1QObject),
begin_insert_rows: fn(*const %1QObject,%2
usize,
usize),
end_insert_rows: fn(*const %1QObject),
begin_remove_rows: fn(*const %1QObject,%2
usize,
usize),
end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl);
}
r << QString(R"()
-> *mut %1 {
let emit = %1Emitter {
qobject: Arc::new(Mutex::new(qobject)),
)").arg(o.name);
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";
model = ", model";
r << QString(R"( };
let model = %1%2 {
qobject: qobject,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
end_insert_rows: end_insert_rows,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
)").arg(o.name, type);
}
r << QString(R"( };
let d = %1::create(emit%3);
Box::into_raw(Box::new(d))
pub extern "C" fn %1_new()").arg(lcname);
rConstructorArgsDecl(r, lcname, o, conf);
r << QString(")\n -> *mut %1 {\n").arg(o.name);
rConstructorArgs(r, lcname, o, conf);
r << QString(R"( Box::into_raw(Box::new(d_%2))
}
#[no_mangle]
pub unsafe extern "C" fn %2_free(ptr: *mut %1) {
Box::from_raw(ptr).emit().clear();
}
)").arg(o.name, lcname, model);
)").arg(o.name, lcname);
for (const Property& p: o.properties) {
const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name));
QString ret = ") -> " + rustType(p);
if (p.type.isComplex() && !p.optional) {
if (p.type.type == BindingType::Object) {
r << QString(R"(
#[no_mangle]
pub unsafe extern "C" fn %2_get(ptr: *mut %1) -> *mut %4 {
(&mut *ptr).get_mut_%3()
}
)").arg(o.name, base, snakeCase(p.name), rustType(p));
} else if (p.type.isComplex() && !p.optional) {
r << QString(R"(
#[no_mangle]
pub unsafe extern "C" fn %2_get(ptr: *const %1,
@ -589,7 +640,7 @@ use %1::*;
writeRustTypes(conf, r);
for (auto object: conf.objects) {
writeRustInterfaceObject(r, object);
writeRustInterfaceObject(r, object, conf);
}
}
@ -621,6 +672,11 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
r << QString(" list: Vec<%1Item>,\n").arg(o.name);
}
r << "}\n\n";
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
modelStruct += ", " + p.name + ": " + p.type.name;
}
}
r << QString(R"(impl %1Trait for %1 {
fn create(emit: %1Emitter%2) -> %1 {
%1 {
@ -631,7 +687,11 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
}
for (const Property& p: o.properties) {
const QString lc(snakeCase(p.name));
r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p));
if (p.type.type == BindingType::Object) {
r << QString(" %1: %1,\n").arg(lc);
} else {
r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p));
}
}
if (o.type != ObjectType::Object) {
r << QString(" list: vec![%1Item::default(); 10],\n")
@ -645,19 +705,29 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
)").arg(o.name);
for (const Property& p: o.properties) {
const QString lc(snakeCase(p.name));
r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p));
if (p.type.isComplex()) {
r << QString(" self.%1.clone()\n").arg(lc);
if (p.type.type == BindingType::Object) {
r << QString(R"( fn get_%1(&self) -> &%2 {
&self.%1
}
fn get_mut_%1(&mut self) -> &mut %2 {
&mut self.%1
}
)").arg(lc, rustType(p));
} else {
r << QString(" self.%1\n").arg(lc);
}
r << " }\n";
if (p.write) {
r << QString(R"( fn set_%1(&mut self, value: %2) {
r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p));
if (p.type.isComplex()) {
r << QString(" self.%1.clone()\n").arg(lc);
} else {
r << QString(" self.%1\n").arg(lc);
}
r << " }\n";
if (p.write) {
r << QString(R"( fn set_%1(&mut self, value: %2) {
self.%1 = value;
self.emit.%1_changed();
}
)").arg(lc, rustType(p));
)").arg(lc, rustType(p));
}
}
}
if (o.type == ObjectType::List) {

View File

@ -3,6 +3,8 @@
#include <QList>
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
#include <QCoreApplication>
enum class ObjectType {
Object,
@ -18,7 +20,8 @@ enum class BindingType {
ULongLong,
Float,
QString,
QByteArray
QByteArray,
Object,
};
struct BindingTypeProperties {
@ -54,6 +57,14 @@ struct Object {
QList<Property> properties;
QList<ItemProperty> itemProperties;
int columnCount;
bool containsObject() {
for (auto p: properties) {
if (p.type.type == BindingType::Object) {
return true;
}
}
return false;
}
};
struct Configuration {
@ -64,5 +75,17 @@ struct Configuration {
QString implementationModule;
QList<Object> objects;
bool overwriteImplementation;
const Object& findObject(const QString& name) const {
for (auto& o: objects) {
if (o.name == name) {
return o;
}
}
QTextStream err(stderr);
err << QCoreApplication::translate("main",
"Cannot find type %1.\n").arg(name);
err.flush();
exit(1);
}
};

View File

@ -65,3 +65,4 @@ rust_test(test_object rust_object)
rust_test(test_object_types rust_object_types)
rust_test(test_list rust_list)
rust_test(test_tree rust_tree)
rust_test(test_objects rust_objects)

View File

@ -139,7 +139,7 @@ pub trait PersonsTrait {
}
#[no_mangle]
pub extern "C" fn persons_new(qobject: *const PersonsQObject,
pub extern "C" fn persons_new(persons: *mut PersonsQObject,
new_data_ready: fn(*const PersonsQObject),
begin_reset_model: fn(*const PersonsQObject),
end_reset_model: fn(*const PersonsQObject),
@ -152,12 +152,12 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject,
usize),
end_remove_rows: fn(*const PersonsQObject))
-> *mut Persons {
let emit = PersonsEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let persons_emit = PersonsEmitter {
qobject: Arc::new(Mutex::new(persons)),
new_data_ready: new_data_ready,
};
let model = PersonsList {
qobject: qobject,
qobject: persons,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -165,8 +165,8 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = Persons::create(emit, model);
Box::into_raw(Box::new(d))
let d_persons = Persons::create(persons_emit, model);
Box::into_raw(Box::new(d_persons))
}
#[no_mangle]

View File

@ -25,4 +25,4 @@ impl PersonTrait for Person {
self.user_name = value;
self.emit.user_name_changed();
}
}
}

View File

@ -68,15 +68,15 @@ pub trait PersonTrait {
}
#[no_mangle]
pub extern "C" fn person_new(qobject: *const PersonQObject,
pub extern "C" fn person_new(person: *mut PersonQObject,
user_name_changed: fn(*const PersonQObject))
-> *mut Person {
let emit = PersonEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let person_emit = PersonEmitter {
qobject: Arc::new(Mutex::new(person)),
user_name_changed: user_name_changed,
};
let d = Person::create(emit);
Box::into_raw(Box::new(d))
let d_person = Person::create(person_emit);
Box::into_raw(Box::new(d_person))
}
#[no_mangle]

View File

@ -39,53 +39,53 @@ impl ObjectTrait for Object {
self.boolean = value;
self.emit.boolean_changed();
}
fn get_bytearray(&self) -> Vec<u8> {
fn get_bytearray(&self) -> Vec<u8> {
self.bytearray.clone()
}
fn set_bytearray(&mut self, value: Vec<u8>) {
self.bytearray = value;
self.emit.bytearray_changed();
}
fn get_integer(&self) -> i32 {
fn get_integer(&self) -> i32 {
self.integer
}
fn set_integer(&mut self, value: i32) {
self.integer = value;
self.emit.integer_changed();
}
fn get_optional_bytearray(&self) -> Option<Vec<u8>> {
fn get_optional_bytearray(&self) -> Option<Vec<u8>> {
self.optional_bytearray.clone()
}
fn set_optional_bytearray(&mut self, value: Option<Vec<u8>>) {
self.optional_bytearray = value;
self.emit.optional_bytearray_changed();
}
fn get_optional_string(&self) -> Option<String> {
fn get_optional_string(&self) -> Option<String> {
self.optional_string.clone()
}
fn set_optional_string(&mut self, value: Option<String>) {
self.optional_string = value;
self.emit.optional_string_changed();
}
fn get_string(&self) -> String {
fn get_string(&self) -> String {
self.string.clone()
}
fn set_string(&mut self, value: String) {
self.string = value;
self.emit.string_changed();
}
fn get_u64(&self) -> u64 {
fn get_u64(&self) -> u64 {
self.u64
}
fn set_u64(&mut self, value: u64) {
self.u64 = value;
self.emit.u64_changed();
}
fn get_uinteger(&self) -> u32 {
fn get_uinteger(&self) -> u32 {
self.uinteger
}
fn set_uinteger(&mut self, value: u32) {
self.uinteger = value;
self.emit.uinteger_changed();
}
}
}

View File

@ -177,7 +177,7 @@ pub trait ObjectTrait {
}
#[no_mangle]
pub extern "C" fn object_new(qobject: *const ObjectQObject,
pub extern "C" fn object_new(object: *mut ObjectQObject,
boolean_changed: fn(*const ObjectQObject),
bytearray_changed: fn(*const ObjectQObject),
integer_changed: fn(*const ObjectQObject),
@ -187,8 +187,8 @@ pub extern "C" fn object_new(qobject: *const ObjectQObject,
u64_changed: fn(*const ObjectQObject),
uinteger_changed: fn(*const ObjectQObject))
-> *mut Object {
let emit = ObjectEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let object_emit = ObjectEmitter {
qobject: Arc::new(Mutex::new(object)),
boolean_changed: boolean_changed,
bytearray_changed: bytearray_changed,
integer_changed: integer_changed,
@ -198,8 +198,8 @@ pub extern "C" fn object_new(qobject: *const ObjectQObject,
u64_changed: u64_changed,
uinteger_changed: uinteger_changed,
};
let d = Object::create(emit);
Box::into_raw(Box::new(d))
let d_object = Object::create(object_emit);
Box::into_raw(Box::new(d_object))
}
#[no_mangle]

View File

@ -0,0 +1,10 @@
[package]
name = "rust_objects"
version = "1.0.0"
[dependencies]
libc = "*"
[lib]
name = "rust"
crate-type = ["staticlib"]

View File

@ -0,0 +1,50 @@
#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(dead_code)]
use interface::*;
pub struct InnerObject {
emit: InnerObjectEmitter,
description: String,
}
impl InnerObjectTrait for InnerObject {
fn create(emit: InnerObjectEmitter) -> InnerObject {
InnerObject {
emit: emit,
description: String::new(),
}
}
fn emit(&self) -> &InnerObjectEmitter {
&self.emit
}
fn get_description(&self) -> String {
self.description.clone()
}
fn set_description(&mut self, value: String) {
self.description = value;
self.emit.description_changed();
}
}
pub struct Person {
emit: PersonEmitter,
object: InnerObject,
}
impl PersonTrait for Person {
fn create(emit: PersonEmitter, object: InnerObject) -> Person {
Person {
emit: emit,
object: object,
}
}
fn emit(&self) -> &PersonEmitter {
&self.emit
}
fn get_object(&self) -> &InnerObject {
&self.object
}
fn get_mut_object(&mut self) -> &mut InnerObject {
&mut self.object
}
}

View File

@ -0,0 +1,148 @@
/* generated by rust_qt_binding_generator */
#![allow(unknown_lints)]
#![allow(mutex_atomic, needless_pass_by_value)]
use libc::{c_int, c_void, uint8_t, uint16_t};
use std::slice;
use std::sync::{Arc, Mutex};
use std::ptr::null;
use implementation::*;
#[repr(C)]
pub struct QString {
data: *const uint8_t,
len: c_int,
}
#[repr(C)]
pub struct QStringIn {
data: *const uint16_t,
len: c_int,
}
impl QStringIn {
fn convert(&self) -> String {
let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) };
String::from_utf16_lossy(data)
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
pub struct InnerObjectQObject {}
#[derive (Clone)]
pub struct InnerObjectEmitter {
qobject: Arc<Mutex<*const InnerObjectQObject>>,
description_changed: fn(*const InnerObjectQObject),
}
unsafe impl Send for InnerObjectEmitter {}
impl InnerObjectEmitter {
fn clear(&self) {
*self.qobject.lock().unwrap() = null();
}
pub fn description_changed(&self) {
let ptr = *self.qobject.lock().unwrap();
if !ptr.is_null() {
(self.description_changed)(ptr);
}
}
}
pub trait InnerObjectTrait {
fn create(emit: InnerObjectEmitter) -> Self;
fn emit(&self) -> &InnerObjectEmitter;
fn get_description(&self) -> String;
fn set_description(&mut self, value: String);
}
#[no_mangle]
pub extern "C" fn inner_object_new(inner_object: *mut InnerObjectQObject,
description_changed: fn(*const InnerObjectQObject))
-> *mut InnerObject {
let inner_object_emit = InnerObjectEmitter {
qobject: Arc::new(Mutex::new(inner_object)),
description_changed: description_changed,
};
let d_inner_object = InnerObject::create(inner_object_emit);
Box::into_raw(Box::new(d_inner_object))
}
#[no_mangle]
pub unsafe extern "C" fn inner_object_free(ptr: *mut InnerObject) {
Box::from_raw(ptr).emit().clear();
}
#[no_mangle]
pub unsafe extern "C" fn inner_object_description_get(ptr: *const InnerObject,
p: *mut c_void,
set: fn(*mut c_void, QString)) {
let data = (&*ptr).get_description();
set(p, QString::from(&data));
}
#[no_mangle]
pub unsafe extern "C" fn inner_object_description_set(ptr: *mut InnerObject, v: QStringIn) {
(&mut *ptr).set_description(v.convert());
}
pub struct PersonQObject {}
#[derive (Clone)]
pub struct PersonEmitter {
qobject: Arc<Mutex<*const PersonQObject>>,
}
unsafe impl Send for PersonEmitter {}
impl PersonEmitter {
fn clear(&self) {
*self.qobject.lock().unwrap() = null();
}
}
pub trait PersonTrait {
fn create(emit: PersonEmitter,
object: InnerObject) -> Self;
fn emit(&self) -> &PersonEmitter;
fn get_object(&self) -> &InnerObject;
fn get_mut_object(&mut self) -> &mut InnerObject;
}
#[no_mangle]
pub extern "C" fn person_new(person: *mut PersonQObject, object: *mut InnerObjectQObject,
description_changed: fn(*const InnerObjectQObject))
-> *mut Person {
let object_emit = InnerObjectEmitter {
qobject: Arc::new(Mutex::new(object)),
description_changed: description_changed,
};
let d_object = InnerObject::create(object_emit);
let person_emit = PersonEmitter {
qobject: Arc::new(Mutex::new(person)),
};
let d_person = Person::create(person_emit,
d_object);
Box::into_raw(Box::new(d_person))
}
#[no_mangle]
pub unsafe extern "C" fn person_free(ptr: *mut Person) {
Box::from_raw(ptr).emit().clear();
}
#[no_mangle]
pub unsafe extern "C" fn person_object_get(ptr: *mut Person) -> *mut InnerObject {
(&mut *ptr).get_mut_object()
}

View File

@ -0,0 +1,4 @@
extern crate libc;
pub mod interface;
mod implementation;

View File

@ -142,7 +142,7 @@ pub trait PersonsTrait {
}
#[no_mangle]
pub extern "C" fn persons_new(qobject: *const PersonsQObject,
pub extern "C" fn persons_new(persons: *mut PersonsQObject,
new_data_ready: fn(*const PersonsQObject, item: usize, valid: bool),
begin_reset_model: fn(*const PersonsQObject),
end_reset_model: fn(*const PersonsQObject),
@ -155,12 +155,12 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject,
usize),
end_remove_rows: fn(*const PersonsQObject))
-> *mut Persons {
let emit = PersonsEmitter {
qobject: Arc::new(Mutex::new(qobject)),
let persons_emit = PersonsEmitter {
qobject: Arc::new(Mutex::new(persons)),
new_data_ready: new_data_ready,
};
let model = PersonsUniformTree {
qobject: qobject,
qobject: persons,
begin_reset_model: begin_reset_model,
end_reset_model: end_reset_model,
begin_insert_rows: begin_insert_rows,
@ -168,8 +168,8 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject,
begin_remove_rows: begin_remove_rows,
end_remove_rows: end_remove_rows,
};
let d = Persons::create(emit, model);
Box::into_raw(Box::new(d))
let d_persons = Persons::create(persons_emit, model);
Box::into_raw(Box::new(d_persons))
}
#[no_mangle]

View File

@ -44,6 +44,7 @@ namespace {
int row;
quintptr id;
};
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
void persons_data_user_name(const Persons::Private*, int, QString*, qstring_set);
bool persons_set_data_user_name(Persons::Private*, int, qstring_t);
@ -75,7 +75,7 @@ bool Persons::hasChildren(const QModelIndex &parent) const
int Persons::rowCount(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : persons_row_count(d);
return (parent.isValid()) ? 0 : persons_row_count(m_d);
}
QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const
@ -93,19 +93,19 @@ QModelIndex Persons::parent(const QModelIndex &) const
bool Persons::canFetchMore(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : persons_can_fetch_more(d);
return (parent.isValid()) ? 0 : persons_can_fetch_more(m_d);
}
void Persons::fetchMore(const QModelIndex &parent)
{
if (!parent.isValid()) {
persons_fetch_more(d);
persons_fetch_more(m_d);
}
}
void Persons::sort(int column, Qt::SortOrder order)
{
persons_sort(d, column, order);
persons_sort(m_d, column, order);
}
Qt::ItemFlags Persons::flags(const QModelIndex &i) const
{
@ -127,7 +127,7 @@ QVariant Persons::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 0:
persons_data_user_name(d, index.row(), &s, set_qstring);
persons_data_user_name(m_d, index.row(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
}
@ -145,7 +145,7 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role)
bool set = false;
if (index.column() == 0) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) {
set = persons_set_data_user_name(d, index.row(), value.value<QString>());
set = persons_set_data_user_name(m_d, index.row(), value.value<QString>());
}
}
if (set) {
@ -164,9 +164,13 @@ extern "C" {
void (*)(Persons*));
void persons_free(Persons::Private*);
};
Persons::Persons(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
Persons::Persons(QObject *parent):
QAbstractItemModel(parent),
d(persons_new(this,
m_d(persons_new(this,
[](const Persons* o) {
emit o->newDataReady(QModelIndex());
},
@ -188,13 +192,15 @@ Persons::Persons(QObject *parent):
[](Persons* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Persons::~Persons() {
persons_free(d);
if (m_ownsPrivate) {
persons_free(m_d);
}
}

View File

@ -11,7 +11,9 @@ class Persons : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
explicit Persons(bool owned, QObject *parent);
public:
explicit Persons(QObject *parent = nullptr);
~Persons();
@ -32,6 +34,5 @@ signals:
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
private:
};
#endif // TEST_LIST_RUST_H

View File

@ -44,6 +44,11 @@ namespace {
int row;
quintptr id;
};
inline void personUserNameChanged(Person* o)
{
emit o->userNameChanged();
}
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,27 +58,34 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
Person::Private* person_new(Person*, void (*)(Person*));
void person_free(Person::Private*);
void person_user_name_get(const Person::Private*, QString*, qstring_set);
void person_user_name_set(Person::Private*, qstring_t);
};
Person::Person(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
Person::Person(QObject *parent):
QObject(parent),
d(person_new(this,
[](Person* o) { emit o->userNameChanged(); })) {}
m_d(person_new(this,
personUserNameChanged)),
m_ownsPrivate(true) {
}
Person::~Person() {
person_free(d);
if (m_ownsPrivate) {
person_free(m_d);
}
}
QString Person::userName() const
{
QString v;
person_user_name_get(d, &v, set_qstring);
person_user_name_get(m_d, &v, set_qstring);
return v;
}
void Person::setUserName(const QString& v) {
person_user_name_set(d, v);
person_user_name_set(m_d, v);
}

View File

@ -11,8 +11,10 @@ class Person : public QObject
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged FINAL)
explicit Person(bool owned, QObject *parent);
public:
explicit Person(QObject *parent = nullptr);
~Person();
@ -20,7 +22,5 @@ public:
void setUserName(const QString& v);
signals:
void userNameChanged();
private:
QString m_userName;
};
#endif // TEST_OBJECT_RUST_H

View File

@ -44,6 +44,39 @@ namespace {
int row;
quintptr id;
};
inline void objectBooleanChanged(Object* o)
{
emit o->booleanChanged();
}
inline void objectBytearrayChanged(Object* o)
{
emit o->bytearrayChanged();
}
inline void objectIntegerChanged(Object* o)
{
emit o->integerChanged();
}
inline void objectOptionalBytearrayChanged(Object* o)
{
emit o->optionalBytearrayChanged();
}
inline void objectOptionalStringChanged(Object* o)
{
emit o->optionalStringChanged();
}
inline void objectStringChanged(Object* o)
{
emit o->stringChanged();
}
inline void objectU64Changed(Object* o)
{
emit o->u64Changed();
}
inline void objectUintegerChanged(Object* o)
{
emit o->uintegerChanged();
}
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +86,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
Object::Private* object_new(Object*, void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*));
void object_free(Object::Private*);
@ -76,90 +108,98 @@ extern "C" {
quint32 object_uinteger_get(const Object::Private*);
void object_uinteger_set(Object::Private*, uint);
};
Object::Object(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
Object::Object(QObject *parent):
QObject(parent),
d(object_new(this,
[](Object* o) { emit o->booleanChanged(); },
[](Object* o) { emit o->bytearrayChanged(); },
[](Object* o) { emit o->integerChanged(); },
[](Object* o) { emit o->optionalBytearrayChanged(); },
[](Object* o) { emit o->optionalStringChanged(); },
[](Object* o) { emit o->stringChanged(); },
[](Object* o) { emit o->u64Changed(); },
[](Object* o) { emit o->uintegerChanged(); })) {}
m_d(object_new(this,
objectBooleanChanged,
objectBytearrayChanged,
objectIntegerChanged,
objectOptionalBytearrayChanged,
objectOptionalStringChanged,
objectStringChanged,
objectU64Changed,
objectUintegerChanged)),
m_ownsPrivate(true) {
}
Object::~Object() {
object_free(d);
if (m_ownsPrivate) {
object_free(m_d);
}
}
bool Object::boolean() const
{
return object_boolean_get(d);
return object_boolean_get(m_d);
}
void Object::setBoolean(bool v) {
object_boolean_set(d, v);
object_boolean_set(m_d, v);
}
QByteArray Object::bytearray() const
{
QByteArray v;
object_bytearray_get(d, &v, set_qbytearray);
object_bytearray_get(m_d, &v, set_qbytearray);
return v;
}
void Object::setBytearray(const QByteArray& v) {
object_bytearray_set(d, v);
object_bytearray_set(m_d, v);
}
qint32 Object::integer() const
{
return object_integer_get(d);
return object_integer_get(m_d);
}
void Object::setInteger(qint32 v) {
object_integer_set(d, v);
object_integer_set(m_d, v);
}
QByteArray Object::optionalBytearray() const
{
QByteArray v;
object_optional_bytearray_get(d, &v, set_qbytearray);
object_optional_bytearray_get(m_d, &v, set_qbytearray);
return v;
}
void Object::setOptionalBytearray(const QByteArray& v) {
if (v.isNull()) {
object_optional_bytearray_set_none(d);
object_optional_bytearray_set_none(m_d);
} else {
object_optional_bytearray_set(d, v);
object_optional_bytearray_set(m_d, v);
}
}
QString Object::optionalString() const
{
QString v;
object_optional_string_get(d, &v, set_qstring);
object_optional_string_get(m_d, &v, set_qstring);
return v;
}
void Object::setOptionalString(const QString& v) {
if (v.isNull()) {
object_optional_string_set_none(d);
object_optional_string_set_none(m_d);
} else {
object_optional_string_set(d, v);
object_optional_string_set(m_d, v);
}
}
QString Object::string() const
{
QString v;
object_string_get(d, &v, set_qstring);
object_string_get(m_d, &v, set_qstring);
return v;
}
void Object::setString(const QString& v) {
object_string_set(d, v);
object_string_set(m_d, v);
}
quint64 Object::u64() const
{
return object_u64_get(d);
return object_u64_get(m_d);
}
void Object::setU64(quint64 v) {
object_u64_set(d, v);
object_u64_set(m_d, v);
}
quint32 Object::uinteger() const
{
return object_uinteger_get(d);
return object_uinteger_get(m_d);
}
void Object::setUinteger(uint v) {
object_uinteger_set(d, v);
object_uinteger_set(m_d, v);
}

View File

@ -11,7 +11,8 @@ class Object : public QObject
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(bool boolean READ boolean WRITE setBoolean NOTIFY booleanChanged FINAL)
Q_PROPERTY(QByteArray bytearray READ bytearray WRITE setBytearray NOTIFY bytearrayChanged FINAL)
Q_PROPERTY(qint32 integer READ integer WRITE setInteger NOTIFY integerChanged FINAL)
@ -20,6 +21,7 @@ private:
Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged FINAL)
Q_PROPERTY(quint64 u64 READ u64 WRITE setU64 NOTIFY u64Changed FINAL)
Q_PROPERTY(quint32 uinteger READ uinteger WRITE setUinteger NOTIFY uintegerChanged FINAL)
explicit Object(bool owned, QObject *parent);
public:
explicit Object(QObject *parent = nullptr);
~Object();
@ -48,14 +50,5 @@ signals:
void stringChanged();
void u64Changed();
void uintegerChanged();
private:
bool m_boolean;
QByteArray m_bytearray;
qint32 m_integer;
QByteArray m_optionalBytearray;
QString m_optionalString;
QString m_string;
quint64 m_u64;
quint32 m_uinteger;
};
#endif // TEST_OBJECT_TYPES_RUST_H

41
tests/test_objects.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "test_objects_rust.h"
#include <QTest>
#include <QSignalSpy>
class TestRustObjects : public QObject
{
Q_OBJECT
private slots:
void testConstructor();
void testStringGetter();
void testStringSetter();
};
void TestRustObjects::testConstructor()
{
Person person;
}
void TestRustObjects::testStringGetter()
{
Person person;
person.object()->setDescription("Konqi");
}
void TestRustObjects::testStringSetter()
{
// GIVEN
Person person;
QSignalSpy spy(person.object(), &InnerObject::descriptionChanged);
// WHEN
person.object()->setDescription("Konqi");
// THEN
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QCOMPARE(person.object()->description(), QString("Konqi"));
}
QTEST_MAIN(TestRustObjects)
#include "test_objects.moc"

28
tests/test_objects.json Normal file
View File

@ -0,0 +1,28 @@
{
"cppFile": "test_objects_rust.cpp",
"rust": {
"dir": "rust_objects",
"interfaceModule": "interface",
"implementationModule": "implementation",
"typesModule": "types"
},
"objects": {
"InnerObject": {
"type": "Object",
"properties": {
"description": {
"type": "QString",
"write": true
}
}
},
"Person": {
"type": "Object",
"properties": {
"object": {
"type": "InnerObject"
}
}
}
}
}

123
tests/test_objects_rust.cpp Normal file
View File

@ -0,0 +1,123 @@
/* generated by rust_qt_binding_generator */
#include "test_objects_rust.h"
namespace {
template <typename T>
struct option {
public:
T value;
bool some;
operator QVariant() const {
if (some) {
return QVariant(value);
}
return QVariant();
}
};
struct qbytearray_t {
private:
const char* data;
int len;
public:
qbytearray_t(const QByteArray& v):
data(v.data()),
len(v.size()) {
}
operator QByteArray() const {
return QByteArray(data, len);
}
};
struct qstring_t {
private:
const void* data;
int len;
public:
qstring_t(const QString& v):
data(static_cast<const void*>(v.utf16())),
len(v.size()) {
}
operator QString() const {
return QString::fromUtf8(static_cast<const char*>(data), len);
}
};
struct qmodelindex_t {
int row;
quintptr id;
};
inline void innerObjectDescriptionChanged(InnerObject* o)
{
emit o->descriptionChanged();
}
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
*v = *val;
}
typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
InnerObject::Private* inner_object_new(InnerObject*, void (*)(InnerObject*));
void inner_object_free(InnerObject::Private*);
void inner_object_description_get(const InnerObject::Private*, QString*, qstring_set);
void inner_object_description_set(InnerObject::Private*, qstring_t);
};
extern "C" {
Person::Private* person_new(Person*, InnerObject*, void (*)(InnerObject*));
void person_free(Person::Private*);
InnerObject::Private* person_object_get(const Person::Private*);
};
InnerObject::InnerObject(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
InnerObject::InnerObject(QObject *parent):
QObject(parent),
m_d(inner_object_new(this,
innerObjectDescriptionChanged)),
m_ownsPrivate(true) {
}
InnerObject::~InnerObject() {
if (m_ownsPrivate) {
inner_object_free(m_d);
}
}
QString InnerObject::description() const
{
QString v;
inner_object_description_get(m_d, &v, set_qstring);
return v;
}
void InnerObject::setDescription(const QString& v) {
inner_object_description_set(m_d, v);
}
Person::Person(bool /*owned*/, QObject *parent):
QObject(parent),
m_object(new InnerObject(false, this)),
m_d(0),
m_ownsPrivate(false) {}
Person::Person(QObject *parent):
QObject(parent),
m_object(new InnerObject(false, this)),
m_d(person_new(this, m_object,
innerObjectDescriptionChanged)),
m_ownsPrivate(true) {
m_object->m_d = person_object_get(this->m_d);
}
Person::~Person() {
if (m_ownsPrivate) {
person_free(m_d);
}
}
const InnerObject* Person::object() const
{
return m_object;
}
InnerObject* Person::object()
{
return m_object;
}

48
tests/test_objects_rust.h Normal file
View File

@ -0,0 +1,48 @@
/* generated by rust_qt_binding_generator */
#ifndef TEST_OBJECTS_RUST_H
#define TEST_OBJECTS_RUST_H
#include <QObject>
#include <QAbstractItemModel>
class Person;
class InnerObject : public QObject
{
Q_OBJECT
friend class Person;
public:
class Private;
private:
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
explicit InnerObject(bool owned, QObject *parent);
public:
explicit InnerObject(QObject *parent = nullptr);
~InnerObject();
QString description() const;
void setDescription(const QString& v);
signals:
void descriptionChanged();
};
class Person : public QObject
{
Q_OBJECT
friend class Person;
public:
class Private;
private:
InnerObject* const m_object;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(InnerObject* object READ object FINAL)
explicit Person(bool owned, QObject *parent);
public:
explicit Person(QObject *parent = nullptr);
~Person();
const InnerObject* object() const;
InnerObject* object();
signals:
};
#endif // TEST_OBJECTS_RUST_H

View File

@ -44,6 +44,7 @@ namespace {
int row;
quintptr id;
};
}
typedef void (*qstring_set)(QString*, qstring_t*);
void set_qstring(QString* v, qstring_t* val) {
@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
void persons_data_user_name(const Persons::Private*, quintptr, QString*, qstring_set);
bool persons_set_data_user_name(Persons::Private*, quintptr, qstring_t);
@ -81,7 +81,7 @@ int Persons::rowCount(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return 0;
}
return persons_row_count(d, parent.internalId(), parent.isValid());
return persons_row_count(m_d, parent.internalId(), parent.isValid());
}
QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const
@ -95,7 +95,7 @@ QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const
if (row >= rowCount(parent)) {
return QModelIndex();
}
const quintptr id = persons_index(d, parent.internalId(), parent.isValid(), row);
const quintptr id = persons_index(m_d, parent.internalId(), parent.isValid(), row);
return createIndex(row, column, id);
}
@ -104,7 +104,7 @@ QModelIndex Persons::parent(const QModelIndex &index) const
if (!index.isValid()) {
return QModelIndex();
}
const qmodelindex_t parent = persons_parent(d, index.internalId());
const qmodelindex_t parent = persons_parent(m_d, index.internalId());
return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex();
}
@ -113,17 +113,17 @@ bool Persons::canFetchMore(const QModelIndex &parent) const
if (parent.isValid() && parent.column() != 0) {
return false;
}
return persons_can_fetch_more(d, parent.internalId(), parent.isValid());
return persons_can_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Persons::fetchMore(const QModelIndex &parent)
{
persons_fetch_more(d, parent.internalId(), parent.isValid());
persons_fetch_more(m_d, parent.internalId(), parent.isValid());
}
void Persons::sort(int column, Qt::SortOrder order)
{
persons_sort(d, column, order);
persons_sort(m_d, column, order);
}
Qt::ItemFlags Persons::flags(const QModelIndex &i) const
{
@ -145,7 +145,7 @@ QVariant Persons::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 0:
persons_data_user_name(d, index.internalId(), &s, set_qstring);
persons_data_user_name(m_d, index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
}
@ -163,7 +163,7 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role)
bool set = false;
if (index.column() == 0) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) {
set = persons_set_data_user_name(d, index.internalId(), value.value<QString>());
set = persons_set_data_user_name(m_d, index.internalId(), value.value<QString>());
}
}
if (set) {
@ -182,12 +182,16 @@ extern "C" {
void (*)(Persons*));
void persons_free(Persons::Private*);
};
Persons::Persons(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
Persons::Persons(QObject *parent):
QAbstractItemModel(parent),
d(persons_new(this,
m_d(persons_new(this,
[](const Persons* o, quintptr id, bool valid) {
if (valid) {
int row = persons_row(o->d, id);
int row = persons_row(o->m_d, id);
emit o->newDataReady(o->createIndex(row, 0, id));
} else {
emit o->newDataReady(QModelIndex());
@ -201,7 +205,7 @@ Persons::Persons(QObject *parent):
},
[](Persons* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = persons_row(o->d, id.value);
int row = persons_row(o->m_d, id.value);
o->beginInsertRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginInsertRows(QModelIndex(), first, last);
@ -212,7 +216,7 @@ Persons::Persons(QObject *parent):
},
[](Persons* o, option<quintptr> id, int first, int last) {
if (id.some) {
int row = persons_row(o->d, id.value);
int row = persons_row(o->m_d, id.value);
o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last);
} else {
o->beginRemoveRows(QModelIndex(), first, last);
@ -221,13 +225,15 @@ Persons::Persons(QObject *parent):
[](Persons* o) {
o->endRemoveRows();
}
)) {
)),
m_ownsPrivate(true) {
connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);
}
Persons::~Persons() {
persons_free(d);
if (m_ownsPrivate) {
persons_free(m_d);
}
}

View File

@ -11,7 +11,9 @@ class Persons : public QAbstractItemModel
public:
class Private;
private:
Private * const d;
Private * m_d;
bool m_ownsPrivate;
explicit Persons(bool owned, QObject *parent);
public:
explicit Persons(QObject *parent = nullptr);
~Persons();
@ -32,6 +34,5 @@ signals:
// new data is ready to be made available to the model with fetchMore()
void newDataReady(const QModelIndex &parent) const;
signals:
private:
};
#endif // TEST_TREE_RUST_H