Progress on QAbstractItemModel

master
Jos van den Oever 2017-08-04 13:21:11 +02:00
parent b56d1faf9b
commit 8d4d71a4b8
7 changed files with 323 additions and 46 deletions

View File

@ -15,6 +15,12 @@ include(KDECMakeSettings)
include(KDECompilerSettings)
include(FeatureSummary)
#add_custom_target(rust
# OUTPUT "${CMAKE_SOURCE_DIR}/target/debug/librust.a"
# COMMAND cargo build
# COMMAND cargo build --release
# DEPENDS
set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust)
ExternalProject_Add(

View File

@ -1,14 +1,16 @@
use interface::*;
use types::*;
use libc::{c_int};
pub struct Hello {
notifier: HelloNotifier,
emit: HelloEmitter,
hello: String,
}
impl HelloTrait for Hello {
fn create(notifier: HelloNotifier) -> Self {
fn create(emit: HelloEmitter) -> Self {
Hello {
notifier: notifier,
emit: emit,
hello: String::new()
}
}
@ -17,7 +19,7 @@ impl HelloTrait for Hello {
}
fn set_hello(&mut self, value: String) {
self.hello = value;
self.notifier.hello_changed();
self.emit.hello_changed();
}
}
@ -27,13 +29,29 @@ impl Drop for Hello {
}
pub struct RItemModel {
notifier: RItemModelNotifier
emit: RItemModelEmitter,
// string: String
}
impl RItemModelTrait for RItemModel {
fn create(notifier: RItemModelNotifier) -> Self {
fn create(emit: RItemModelEmitter) -> Self {
RItemModel {
notifier: notifier
emit: emit
}
}
fn column_count(&self, parent: QModelIndex) -> c_int {
if parent.is_valid() { 0 } else { 2 }
}
fn row_count(&self, parent: QModelIndex) -> c_int {
if parent.is_valid() { 0 } else { 2 }
}
fn index(&self, row: i32, column: i32, parent: QModelIndex) -> QModelIndex {
QModelIndex::flat(row, column)
}
fn parent(&self, index: QModelIndex) -> QModelIndex {
QModelIndex::invalid()
}
fn data(&self, index: QModelIndex, role: c_int) -> Variant {
Variant::String(String::from("hello"))
}
}

View File

@ -1,35 +1,36 @@
use std::slice;
use libc::{uint8_t, uint16_t, size_t};
use libc::{c_int, uint8_t, uint16_t, size_t, c_void};
use types::*;
use implementation::Hello;
use implementation::RItemModel;
pub struct HelloQObject {}
pub struct HelloNotifier {
pub struct HelloEmitter {
qobject: *const HelloQObject,
hello_changed: fn (*const HelloQObject)
}
impl HelloNotifier {
impl HelloEmitter {
pub fn hello_changed(&self) {
(self.hello_changed)(self.qobject);
}
}
pub trait HelloTrait {
fn create(notifier: HelloNotifier) -> Self;
fn create(emit: HelloEmitter) -> Self;
fn get_hello(&self) -> &String;
fn set_hello(&mut self, value: String);
}
#[no_mangle]
pub extern fn hello_new(qobject: *const HelloQObject, changed: fn(*const HelloQObject)) -> *mut Hello {
let notifier = HelloNotifier {
let emit = HelloEmitter {
qobject: qobject,
hello_changed: changed
};
let hello = Hello::create(notifier);
let hello = Hello::create(emit);
Box::into_raw(Box::new(hello))
}
@ -48,40 +49,37 @@ pub extern fn hello_set(ptr: *mut Hello, s: *const uint16_t, len: size_t) {
}
#[no_mangle]
pub extern fn hello_size(ptr: *mut Hello) -> size_t {
pub extern fn hello_get(ptr: *mut Hello) -> QString {
let hello = unsafe {
&mut *ptr
};
hello.get_hello().len()
}
#[no_mangle]
pub extern fn hello_get(ptr: *mut Hello) -> *const uint8_t {
let hello = unsafe {
&mut *ptr
};
hello.get_hello().as_ptr()
QString::from(hello.get_hello())
}
pub struct RItemModelQObject {}
pub struct RItemModelNotifier {
pub struct RItemModelEmitter {
qobject: *const RItemModelQObject
}
impl RItemModelNotifier {
impl RItemModelEmitter {
}
pub trait RItemModelTrait {
fn create(notifier: RItemModelNotifier) -> Self;
fn create(emit: RItemModelEmitter) -> Self;
fn column_count(&self, parent: QModelIndex) -> c_int;
fn row_count(&self, parent: QModelIndex) -> c_int;
fn index(&self, row: c_int, column: c_int, parent: QModelIndex) -> QModelIndex;
fn parent(&self, index: QModelIndex) -> QModelIndex;
fn data(&self, index: QModelIndex, role: c_int) -> Variant;
}
#[no_mangle]
pub extern fn ritemmodel_new(qobject: *const RItemModelQObject) -> *mut RItemModel {
let notifier = RItemModelNotifier {
let emit = RItemModelEmitter {
qobject: qobject
};
let ritemmodel = RItemModel::create(notifier);
let ritemmodel = RItemModel::create(emit);
Box::into_raw(Box::new(ritemmodel))
}
@ -90,3 +88,44 @@ pub extern fn ritemmodel_free(ptr: *mut RItemModel) {
if ptr.is_null() { return }
unsafe { Box::from_raw(ptr); }
}
#[no_mangle]
pub extern fn ritemmodel_column_count(ptr: *const RItemModel, parent: QModelIndex) -> i32 {
let ritemmodel = unsafe {
&*ptr
};
ritemmodel.column_count(parent)
}
#[no_mangle]
pub extern fn ritemmodel_row_count(ptr: *const RItemModel, parent: QModelIndex) -> i32 {
let ritemmodel = unsafe {
&*ptr
};
ritemmodel.row_count(parent)
}
#[no_mangle]
pub extern fn ritemmodel_index(ptr: *const RItemModel, row: i32, column: i32, parent: QModelIndex) -> QModelIndex {
let ritemmodel = unsafe {
&*ptr
};
ritemmodel.index(row, column, parent)
}
#[no_mangle]
pub extern fn ritemmodel_parent(ptr: *const RItemModel, index: QModelIndex) -> QModelIndex {
let ritemmodel = unsafe {
&*ptr
};
ritemmodel.parent(index)
}
#[no_mangle]
pub extern fn ritemmodel_data(ptr: *const RItemModel, index: QModelIndex, role: c_int, d: *mut c_void, set: fn (*mut c_void, &QVariant)) {
let ritemmodel = unsafe {
&*ptr
};
let data = ritemmodel.data(index, role);
set(d, &QVariant::from(&data));
}

View File

@ -1,5 +1,5 @@
extern crate libc;
#[macro_use]
pub mod types;
pub mod interface;
pub mod implementation;

100
common-rust/src/types.rs Normal file
View File

@ -0,0 +1,100 @@
use libc::{c_int, c_uint, uint8_t};
use std::ptr::null;
use std::marker::PhantomData;
#[repr(C)]
pub struct QString {
data: *const uint8_t,
len: c_int
}
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 enum Variant {
None,
Bool(bool),
String(String)
}
/* values from qvariant.h and qmetatype.h */
#[repr(u32)]
#[derive(Clone, Copy)]
enum VariantType {
Invalid = 0,
Bool = 1,
String = 10,
ByteArray = 12,
}
#[repr(C)]
pub struct QVariant<'a> {
type_: c_uint,
len: c_int,
data: *const uint8_t,
phantom: PhantomData<&'a u8>
}
impl<'a> QVariant<'a> {
pub fn type_(&self) -> u32 {
self.type_ as u32
}
}
impl<'a> From<&'a Variant> for QVariant<'a> {
fn from(variant: &'a Variant) -> QVariant {
match variant {
&Variant::None => QVariant {
data: null(),
len: 0,
type_: VariantType::Invalid as c_uint,
phantom: PhantomData
},
&Variant::Bool(v) => QVariant {
data: null(),
len: v as c_int,
type_: VariantType::Bool as c_uint,
phantom: PhantomData
},
&Variant::String(ref v) => QVariant {
data: v.as_ptr(),
len: v.len() as c_int,
type_: VariantType::String as c_uint,
phantom: PhantomData
}
}
}
}
#[repr(C)]
pub struct QModelIndex {
row: c_int,
column: c_int,
internal_id: usize
}
impl QModelIndex {
pub fn invalid() -> QModelIndex {
QModelIndex {
row: -1,
column: -1,
internal_id: 0
}
}
pub fn flat(row: c_int, column: c_int) -> QModelIndex {
QModelIndex {
row: row,
column: column,
internal_id: 1
}
}
pub fn is_valid(&self) -> bool {
self.internal_id != 0 && self.row >= 0 && self.column >= 0
}
}

View File

@ -1,16 +1,79 @@
#include "RMailObject.h"
#include <QSize>
#include <QDebug>
#include <cstdint>
#include <unistd.h>
namespace {
typedef struct {
private:
const char* data;
int len;
public:
operator QByteArray() const {
return QByteArray(data, len);
}
} qbytearray_t;
struct qstring_t {
private:
const char* data;
int len;
public:
operator QString() const {
return QString::fromUtf8(data, len);
}
};
typedef struct {
int row;
int column;
uint64_t id;
} qmodelindex_t;
typedef struct qvariant_t {
unsigned int type;
int value;
const char* data;
} qvariant_t;
QVariant variant(const qvariant_t& v) {
switch (v.type) {
case QVariant::Bool: return QVariant((bool)v.value);
case QVariant::String: return QString::fromUtf8(v.data, v.value);
default:;
}
return QVariant();
}
/*
qvariant_t variant(const QVariant& v) {
auto t = v.type();
switch (t) {
case QVariant::Bool:
return { .type = t, .value = { .vbool = 0 } };
case QVariant::ByteArray:
return { .type = t, .value = { .vbool = 0 } };
case QVariant::String:
return { .type = t, .value = { .vbool = 0 } };
default:;
}
return { .type = QVariant::Invalid, .value = { .vbool = false } };
}
*/
}
typedef void (*qvariant_set)(void*, qvariant_t*);
extern "C" {
RMailObjectInterface* hello_new(void*, void (*)(RMailObject*));
void hello_free(RMailObjectInterface*);
void hello_set(RMailObjectInterface*, const uint16_t *, size_t);
size_t hello_size(RMailObjectInterface*);
const char* hello_get(RMailObjectInterface*);
qstring_t hello_get(RMailObjectInterface*);
RItemModelInterface* ritemmodel_new(void*);
void ritemmodel_free(RItemModelInterface*);
int ritemmodel_column_count(RItemModelInterface*, qmodelindex_t parent);
int ritemmodel_row_count(RItemModelInterface*, qmodelindex_t parent);
qmodelindex_t ritemmodel_index(RItemModelInterface*, int row, int column, qmodelindex_t parent);
qmodelindex_t ritemmodel_parent(RItemModelInterface*, qmodelindex_t);
void ritemmodel_data(RItemModelInterface*, qmodelindex_t, int, void*, qvariant_set);
}
RMailObject::RMailObject(QObject *parent):
@ -27,7 +90,7 @@ RMailObject::~RMailObject() {
QString
RMailObject::userName() const {
return QString::fromUtf8(hello_get(d), hello_size(d));
return hello_get(d);
}
void
@ -58,21 +121,64 @@ RItemModel::~RItemModel() {
int RItemModel::columnCount(const QModelIndex &parent) const
{
return 0;
}
QVariant RItemModel::data(const QModelIndex &index, int role) const
{
return 0;
}
QModelIndex RItemModel::index(int row, int column, const QModelIndex &parent) const
{
return QModelIndex();
}
QModelIndex RItemModel::parent(const QModelIndex &index) const
{
return QModelIndex();
const qmodelindex_t p = {
.row = parent.row(),
.column = parent.column(),
.id = parent.internalId()
};
return ritemmodel_column_count(d, p);
}
int RItemModel::rowCount(const QModelIndex &parent) const
{
return 0;
const qmodelindex_t p = {
.row = parent.row(),
.column = parent.column(),
.id = parent.internalId()
};
return ritemmodel_row_count(d, p);
}
void set_variant(void* v, qvariant_t* val) {
*static_cast<QVariant*>(v) = variant(*val);
}
QVariant RItemModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (role != Qt::DisplayRole) {
return QVariant();
}
const qmodelindex_t i = {
.row = index.row(),
.column = index.column(),
.id = index.internalId()
};
QVariant v;
ritemmodel_data(d, i, role, &v, set_variant);
return v;
}
QModelIndex RItemModel::index(int row, int column, const QModelIndex &parent) const
{
const qmodelindex_t p = {
.row = parent.row(),
.column = parent.column(),
.id = parent.internalId()
};
const qmodelindex_t i = ritemmodel_index(d, row, column, p);
return i.id ?createIndex(i.row, i.column, i.id) :QModelIndex();
}
QModelIndex RItemModel::parent(const QModelIndex &index) const
{
if (!index.isValid()) {
return QModelIndex();
}
const qmodelindex_t i = {
.row = index.row(),
.column = index.column(),
.id = index.internalId()
};
const qmodelindex_t parent = ritemmodel_parent(d, i);
return parent.id ?createIndex(parent.row, parent.column, parent.id) :QModelIndex();
}

View File

@ -1,6 +1,7 @@
#include "RMailObject.h"
#include <cstdlib>
#include <QTreeView>
#include <QApplication>
#include <QCommandLineParser>
#include <KAboutData>
@ -44,6 +45,12 @@ int main (int argc, char *argv[])
parser.process(app);
aboutData.processCommandLine(&parser);
RItemModel model;
QTreeView view;
view.setModel(&model);
view.show();
return app.exec();
/*
RMailObject rmail;
rmail.setUserName("RMail");
rmail.userName();
@ -56,4 +63,5 @@ int main (int argc, char *argv[])
KMessageBox::questionYesNo
(0, i18n( "Hello World" ), i18n( "Hello" ), yesButton )
== KMessageBox::Yes? EXIT_SUCCESS: EXIT_FAILURE;
*/
}