From eb9feb6a12411ac38a7c57992af59c9d94d891eb Mon Sep 17 00:00:00 2001 From: Jos van den Oever Date: Tue, 22 Aug 2017 00:51:48 +0200 Subject: [PATCH] Change the json format and add charts --- CMakeLists.txt | 46 +++- demo/CMakeLists.txt | 40 ++- demo/fibonacci.json | 45 ++-- demo/rust/src/implementation.rs | 29 -- demo/rust/src/interface.rs | 54 +--- demo/rust/src/lib.rs | 4 + demo/rust/src/time_series_implementation.rs | 57 ++++ demo/rust/src/time_series_interface.rs | 149 +++++++++++ demo/rust/src/time_series_types.rs | 104 ++++++++ demo/src/Fibonacci.cpp | 11 +- demo/src/TimeSeries.cpp | 231 ++++++++++++++++ demo/src/TimeSeries.h | 37 +++ demo/src/Tree.cpp | 185 +++++++------ demo/src/main.cpp | 68 ++++- demo/time_series.json | 26 ++ demo/tree.json | 120 +++------ .../rust_qt_binding_generator.cpp | 250 +++++++++--------- tests/rust_object_types/src/implementation.rs | 90 +++---- tests/rust_object_types/src/interface.rs | 174 ++++++------ tests/test_list.json | 26 +- tests/test_list_rust.cpp | 18 +- tests/test_object.json | 20 +- tests/test_object_types.json | 81 +++--- tests/test_object_types_rust.cpp | 120 ++++----- tests/test_object_types_rust.h | 50 ++-- tests/test_tree.json | 26 +- tests/test_tree_rust.cpp | 14 +- 27 files changed, 1349 insertions(+), 726 deletions(-) create mode 100644 demo/rust/src/time_series_implementation.rs create mode 100644 demo/rust/src/time_series_interface.rs create mode 100644 demo/rust/src/time_series_types.rs create mode 100644 demo/src/TimeSeries.cpp create mode 100644 demo/src/TimeSeries.h create mode 100644 demo/time_series.json diff --git a/CMakeLists.txt b/CMakeLists.txt index ebd5486..4522577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,35 +4,59 @@ cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) cmake_policy(SET CMP0046 NEW) cmake_policy(SET CMP0063 NEW) set(QT_MIN_VERSION "5.6.0") +set(KF5_MIN_VERSION "5.2.0") + +find_package(ECM 1.0.0 NO_MODULE) +if (ECM_FOUND) + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + include(KDEInstallDirs) + include(KDECMakeSettings) + include(KDECompilerSettings) +endif() include(FeatureSummary) # Find Qt modules -find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS - Core - Test +find_package(Qt5 ${QT_MIN_VERSION} CONFIG + REQUIRED COMPONENTS + Core + Test + OPTIONAL_COMPONENTS + Widgets + Quick ) -find_package(Qt5Widgets ${QT_MIN_VERSION} CONFIG) -find_package(Qt5Quick ${QT_MIN_VERSION} CONFIG) -find_package(Qt5QuickControls2 ${QT_MIN_VERSION} CONFIG) +find_package(Qt5QuickControls2 EXACT ${Qt5Core_VERSION}) +find_package(Qt5Charts EXACT ${Qt5Core_VERSION}) set(CMAKE_AUTOMOC ON) +if (ECM_FOUND) + # Find KDE Modules + find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS + CoreAddons # KAboutData + I18n # KLocalizedString + WidgetsAddons # KMessageBox + ) + find_package(KF5Kirigami CONFIG) +endif() + feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPER) if(CMAKE_BUILD_TYPE_UPPER STREQUAL DEBUG) - set(RUST_TARGET_DIR target/debug/) - set(RUST_BUILD_FLAG) + set(RUST_TARGET_DIR target/debug/) + set(RUST_BUILD_FLAG) else() - set(RUST_TARGET_DIR target/release/) - set(RUST_BUILD_FLAG --release) + set(RUST_TARGET_DIR target/release/) + set(RUST_BUILD_FLAG --release) endif() add_subdirectory(rust_qt_binding_generator) + enable_testing() add_subdirectory(tests) if(Qt5Widgets_FOUND) - add_subdirectory(demo) + add_subdirectory(demo) endif() diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 57efb0d..48de002 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -6,7 +6,7 @@ add_custom_command( "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/fibonacci_types.rs" "${CMAKE_CURRENT_SOURCE_DIR}/src/Fibonacci.h" # if the cpp file is marked GENERATED, CMake will not check it for moc - # "${CMAKE_CURRENT_SOURCE_DIR}/src/tmp.cpp" + # "${CMAKE_CURRENT_SOURCE_DIR}/src/Fibonacci.cpp" COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/fibonacci.json" DEPENDS rust_qt_binding_generator fibonacci.json ) @@ -17,11 +17,22 @@ add_custom_command( "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/types.rs" "${CMAKE_CURRENT_SOURCE_DIR}/src/Tree.h" # if the cpp file is marked GENERATED, CMake will not check it for moc - # "${CMAKE_CURRENT_SOURCE_DIR}/src/tmp.cpp" + # "${CMAKE_CURRENT_SOURCE_DIR}/src/Tree.cpp" COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/tree.json" DEPENDS rust_qt_binding_generator tree.json ) +# generate c++ and rust code from time_series.json +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/time_series_interface.rs" + "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/time_series_types.rs" + "${CMAKE_CURRENT_SOURCE_DIR}/src/TimeSeries.h" + # if the cpp file is marked GENERATED, CMake will not check it for moc + # "${CMAKE_CURRENT_SOURCE_DIR}/src/TimeSeries.cpp" + COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/time_series.json" + DEPENDS rust_qt_binding_generator time_series.json +) + # compile the rust code into a static library add_custom_command( OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a" @@ -33,30 +44,33 @@ add_custom_command( rust/src/implementation.rs rust/src/interface.rs rust/src/types.rs + rust/src/time_series_interface.rs + rust/src/time_series_implementation.rs + rust/src/time_series_types.rs WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rust" ) add_custom_target(rust_target DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a") -if(Qt5Quick_FOUND) - add_definitions(-DQTQUICK) - set(Qt5Quick_LIBS Qt5::Quick) +list(APPEND DemoLibs "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a") +list(APPEND DemoLibs Qt5::Widgets) +if (Qt5Quick_FOUND) + list(APPEND DemoLibs Qt5::Quick) endif() -if(Qt5QuickControls2_FOUND) +if (Qt5QuickControls2_FOUND) add_definitions(-DQTQUICKCONTROLS2) - set(Qt5QuickControls2_LIBS Qt5::QuickControls2) +# list(APPEND DemoLibs Qt5::QuickControls2) +endif() +if (Qt5Charts_FOUND) + list(APPEND DemoLibs Qt5::Charts) endif() -set(Demo_SRCS src/main.cpp src/Tree.cpp src/Fibonacci.cpp +set(Demo_SRCS src/main.cpp src/Fibonacci.cpp src/Tree.cpp src/TimeSeries.cpp resource_file.qrc) add_executable(Demo ${Demo_SRCS}) add_dependencies(Demo rust_target) -target_link_libraries(Demo - Qt5::Widgets - "${Qt5Quick_LIBS}" - "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a" -) +target_link_libraries(Demo ${DemoLibs}) set_target_properties(Demo PROPERTIES CXX_STANDARD 11 diff --git a/demo/fibonacci.json b/demo/fibonacci.json index 9ad53e1..bdeb7b3 100644 --- a/demo/fibonacci.json +++ b/demo/fibonacci.json @@ -6,26 +6,27 @@ "implementationModule": "fibonacci_implementation", "typesModule": "fibonacci_types" }, - "objects": [{ - "name": "Fibonacci", - "type": "Object", - "properties": [{ - "name": "input", - "type": "quint32", - "write": true - }, { - "name": "result", - "type": "quint64" - }] - }, { - "name": "FibonacciList", - "type": "List", - "roles": [ - [{ - "name": "result", - "value": "Qt::DisplayRole", - "type": "quint64" - }] - ] - }] + "objects": { + "Fibonacci": { + "type": "Object", + "properties": { + "input": { + "type": "quint32", + "write": true + }, + "result": { + "type": "quint64" + } + } + }, + "FibonacciList": { + "type": "List", + "itemProperties": { + "result": { + "type": "quint64", + "roles": [ [ "display" ] ] + } + } + } + } } diff --git a/demo/rust/src/implementation.rs b/demo/rust/src/implementation.rs index a792859..917e8ce 100644 --- a/demo/rust/src/implementation.rs +++ b/demo/rust/src/implementation.rs @@ -36,14 +36,6 @@ impl Item for DirEntry { fn file_path(&self) -> Option { self.path.as_ref().map(|p| p.to_string_lossy().into()) } - fn set_file_name(&mut self, file_name: String) -> bool { - self.name = file_name.into(); - true - } - fn set_file_path(&mut self, file_path: Option) -> bool { - self.path = file_path.map(|f| f.into()); - true - } fn file_permissions(&self) -> c_int { 42 } @@ -53,9 +45,6 @@ impl Item for DirEntry { fn file_size(&self) -> Option { self.metadata.as_ref().map(|m|m.len()) } - fn set_file_size(&mut self, file_size: Option) -> bool { - true - } fn retrieve(id: usize, parents: Vec<&DirEntry>, q: Incoming, emit: TreeEmitter) { @@ -98,12 +87,9 @@ pub trait Item: Default { fn retrieve(id: usize, parents: Vec<&Self>, q: Incoming, emit: TreeEmitter); fn file_name(&self) -> String; fn file_path(&self) -> Option; - fn set_file_name(&mut self, file_name: String) -> bool; fn file_permissions(&self) -> c_int; fn file_type(&self) -> c_int; fn file_size(&self) -> Option; - fn set_file_path(&mut self, file_path: Option) -> bool; - fn set_file_size(&mut self, file_size: Option) -> bool; } pub type Tree = RGeneralItemModel; @@ -284,11 +270,6 @@ impl TreeTrait for RGeneralItemModel where T: Sync + Send { .map(|entry| entry.data.file_name()) .unwrap_or_default() } - fn set_file_name(&mut self, row: c_int, parent: usize, v: String) -> bool { - self.get_mut(row, parent) - .map(|mut entry| entry.data.set_file_name(v)) - .unwrap_or(false) - } fn file_permissions(&self, row: c_int, parent: usize) -> c_int { self.get(row, parent) .map(|entry| entry.data.file_permissions()) @@ -302,11 +283,6 @@ impl TreeTrait for RGeneralItemModel where T: Sync + Send { .map(|entry| entry.data.file_path()) .unwrap_or_default() } - fn set_file_path(&mut self, row: c_int, parent: usize, v: Option) -> bool { - self.get_mut(row, parent) - .map(|mut entry| entry.data.set_file_path(v)) - .unwrap_or(false) - } fn file_type(&self, row: c_int, parent: usize) -> c_int { self.get(row, parent) .map(|entry| entry.data.file_type()) @@ -317,9 +293,4 @@ impl TreeTrait for RGeneralItemModel where T: Sync + Send { .map(|entry| entry.data.file_size()) .unwrap_or(None) } - fn set_file_size(&mut self, row: c_int, parent: usize, v: Option) -> bool { - self.get_mut(row, parent) - .map(|mut entry| entry.data.set_file_size(v)) - .unwrap_or(false) - } } diff --git a/demo/rust/src/interface.rs b/demo/rust/src/interface.rs index d2c1db4..fc64d8f 100644 --- a/demo/rust/src/interface.rs +++ b/demo/rust/src/interface.rs @@ -78,15 +78,12 @@ pub trait TreeTrait { fn can_fetch_more(&self, c_int, usize) -> bool { false } fn fetch_more(&mut self, c_int, usize) {} fn sort(&mut self, c_int, SortOrder) {} - fn file_name(&self, row: c_int, parent: usize) -> String; - fn set_file_name(&mut self, row: c_int, parent: usize, String) -> bool; fn file_icon(&self, row: c_int, parent: usize) -> Vec; + fn file_name(&self, row: c_int, parent: usize) -> String; fn file_path(&self, row: c_int, parent: usize) -> Option; - fn set_file_path(&mut self, row: c_int, parent: usize, Option) -> bool; fn file_permissions(&self, row: c_int, parent: usize) -> i32; - fn file_type(&self, row: c_int, parent: usize) -> i32; fn file_size(&self, row: c_int, parent: usize) -> Option; - fn set_file_size(&mut self, row: c_int, parent: usize, Option) -> bool; + fn file_type(&self, row: c_int, parent: usize) -> i32; fn index(&self, row: c_int, parent: usize) -> usize; fn parent(&self, parent: usize) -> QModelIndex; } @@ -165,20 +162,6 @@ pub unsafe extern "C" fn tree_sort(ptr: *mut Tree, column: c_int, order: SortOrd (&mut *ptr).sort(column, order) } -#[no_mangle] -pub unsafe extern "C" fn tree_data_file_name(ptr: *const Tree, - row: c_int, parent: usize, - d: *mut c_void, - set: fn(*mut c_void, QString)) { - let data = (&*ptr).file_name(row, parent); - set(d, QString::from(&data)); -} - -#[no_mangle] -pub unsafe extern "C" fn tree_set_data_file_name(ptr: *mut Tree, row: c_int, parent: usize, v: QStringIn) -> bool { - (&mut *ptr).set_file_name(row, parent, v.convert()) -} - #[no_mangle] pub unsafe extern "C" fn tree_data_file_icon(ptr: *const Tree, row: c_int, parent: usize, @@ -188,6 +171,15 @@ pub unsafe extern "C" fn tree_data_file_icon(ptr: *const Tree, set(d, QByteArray::from(&data)); } +#[no_mangle] +pub unsafe extern "C" fn tree_data_file_name(ptr: *const Tree, + row: c_int, parent: usize, + d: *mut c_void, + set: fn(*mut c_void, QString)) { + let data = (&*ptr).file_name(row, parent); + set(d, QString::from(&data)); +} + #[no_mangle] pub unsafe extern "C" fn tree_data_file_path(ptr: *const Tree, row: c_int, parent: usize, @@ -199,39 +191,19 @@ pub unsafe extern "C" fn tree_data_file_path(ptr: *const Tree, } } -#[no_mangle] -pub unsafe extern "C" fn tree_set_data_file_path(ptr: *mut Tree, row: c_int, parent: usize, v: QStringIn) -> bool { - (&mut *ptr).set_file_path(row, parent, Some(v.convert())) -} - -#[no_mangle] -pub unsafe extern "C" fn tree_set_data_file_path_none(ptr: *mut Tree, row: c_int, parent: usize) -> bool { - (&mut *ptr).set_file_path(row, parent, None) -} - #[no_mangle] pub unsafe extern "C" fn tree_data_file_permissions(ptr: *const Tree, row: c_int, parent: usize) -> i32 { (&*ptr).file_permissions(row, parent).into() } -#[no_mangle] -pub unsafe extern "C" fn tree_data_file_type(ptr: *const Tree, row: c_int, parent: usize) -> i32 { - (&*ptr).file_type(row, parent).into() -} - #[no_mangle] pub unsafe extern "C" fn tree_data_file_size(ptr: *const Tree, row: c_int, parent: usize) -> COption { (&*ptr).file_size(row, parent).into() } #[no_mangle] -pub unsafe extern "C" fn tree_set_data_file_size(ptr: *mut Tree, row: c_int, parent: usize, v: u64) -> bool { - (&mut *ptr).set_file_size(row, parent, Some(v)) -} - -#[no_mangle] -pub unsafe extern "C" fn tree_set_data_file_size_none(ptr: *mut Tree, row: c_int, parent: usize) -> bool { - (&mut *ptr).set_file_size(row, parent, None) +pub unsafe extern "C" fn tree_data_file_type(ptr: *const Tree, row: c_int, parent: usize) -> i32 { + (&*ptr).file_type(row, parent).into() } #[no_mangle] diff --git a/demo/rust/src/lib.rs b/demo/rust/src/lib.rs index 163eb6e..faadbf5 100644 --- a/demo/rust/src/lib.rs +++ b/demo/rust/src/lib.rs @@ -7,3 +7,7 @@ pub mod fibonacci_interface; mod types; mod implementation; pub mod interface; + +mod time_series_types; +mod time_series_implementation; +pub mod time_series_interface; diff --git a/demo/rust/src/time_series_implementation.rs b/demo/rust/src/time_series_implementation.rs new file mode 100644 index 0000000..f742bfd --- /dev/null +++ b/demo/rust/src/time_series_implementation.rs @@ -0,0 +1,57 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(dead_code)] +use libc::c_int; +use libc::c_uint; +use types::*; +use time_series_interface::*; + +#[derive (Default, Clone)] +struct TimeSeriesItem { + input: u32, + result: u32, +} + +pub struct TimeSeries { + emit: TimeSeriesEmitter, + model: TimeSeriesList, + list: Vec, +} + +impl TimeSeriesTrait for TimeSeries { + fn create(emit: TimeSeriesEmitter, model: TimeSeriesList) -> TimeSeries { + let mut series = TimeSeries { + emit: emit, + model: model, + list: Vec::new() + }; + for i in 0..100 { + series.list.push(TimeSeriesItem { + input: i, + result: 2 * i + }); + } + series + } + fn emit(&self) -> &TimeSeriesEmitter { + &self.emit + } + fn row_count(&self) -> c_int { + self.list.len() as c_int + } + fn input(&self, row: c_int) -> u32 { + self.list[row as usize].input + } + fn set_input(&mut self, row: c_int, v: u32) -> bool { +println!("setting input to {} {}", row, v); + self.list[row as usize].input = v; + true + } + fn result(&self, row: c_int) -> u32 { + self.list[row as usize].result + } + fn set_result(&mut self, row: c_int, v: u32) -> bool { + self.list[row as usize].result = v; + true + } +} diff --git a/demo/rust/src/time_series_interface.rs b/demo/rust/src/time_series_interface.rs new file mode 100644 index 0000000..64dae7e --- /dev/null +++ b/demo/rust/src/time_series_interface.rs @@ -0,0 +1,149 @@ +/* generated by rust_qt_binding_generator */ +#![allow(unknown_lints)] +#![allow(mutex_atomic, needless_pass_by_value)] +#![allow(unused_imports)] +use libc::{c_int, c_uint, c_void}; +use types::*; +use std::sync::{Arc, Mutex}; +use std::ptr::null; + +use time_series_implementation::*; + +pub struct TimeSeriesQObject {} + +#[derive (Clone)] +pub struct TimeSeriesEmitter { + qobject: Arc>, + new_data_ready: fn(*const TimeSeriesQObject), +} + +unsafe impl Send for TimeSeriesEmitter {} + +impl TimeSeriesEmitter { + fn clear(&self) { + *self.qobject.lock().unwrap() = null(); + } + pub fn new_data_ready(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.new_data_ready)(ptr); + } + } +} + +pub struct TimeSeriesList { + qobject: *const TimeSeriesQObject, + begin_reset_model: fn(*const TimeSeriesQObject), + end_reset_model: fn(*const TimeSeriesQObject), + begin_insert_rows: fn(*const TimeSeriesQObject, c_int, c_int), + end_insert_rows: fn(*const TimeSeriesQObject), + begin_remove_rows: fn(*const TimeSeriesQObject, c_int, c_int), + end_remove_rows: fn(*const TimeSeriesQObject), +} + +impl TimeSeriesList { + pub fn begin_reset_model(&self) { + (self.begin_reset_model)(self.qobject); + } + pub fn end_reset_model(&self) { + (self.end_reset_model)(self.qobject); + } + pub fn begin_insert_rows(&self, first: c_int, last: c_int) { + (self.begin_insert_rows)(self.qobject, first, last); + } + pub fn end_insert_rows(&self) { + (self.end_insert_rows)(self.qobject); + } + pub fn begin_remove_rows(&self, first: c_int, last: c_int) { + (self.begin_remove_rows)(self.qobject, first, last); + } + pub fn end_remove_rows(&self) { + (self.end_remove_rows)(self.qobject); + } +} + +pub trait TimeSeriesTrait { + fn create(emit: TimeSeriesEmitter, model: TimeSeriesList) -> Self; + fn emit(&self) -> &TimeSeriesEmitter; + fn row_count(&self) -> c_int; + fn can_fetch_more(&self) -> bool { false } + fn fetch_more(&mut self) {} + fn sort(&mut self, c_int, SortOrder) {} + fn input(&self, row: c_int) -> u32; + fn set_input(&mut self, row: c_int, u32) -> bool; + fn result(&self, row: c_int) -> u32; + fn set_result(&mut self, row: c_int, u32) -> bool; +} + +#[no_mangle] +pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject, + new_data_ready: fn(*const TimeSeriesQObject), + begin_reset_model: fn(*const TimeSeriesQObject), + end_reset_model: fn(*const TimeSeriesQObject), + begin_insert_rows: fn(*const TimeSeriesQObject, + c_int, + c_int), + end_insert_rows: fn(*const TimeSeriesQObject), + begin_remove_rows: fn(*const TimeSeriesQObject, + c_int, + c_int), + end_remove_rows: fn(*const TimeSeriesQObject)) + -> *mut TimeSeries { + let emit = TimeSeriesEmitter { + qobject: Arc::new(Mutex::new(qobject)), + new_data_ready: new_data_ready, + }; + let model = TimeSeriesList { + 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, + }; + let d = TimeSeries::create(emit, model); + Box::into_raw(Box::new(d)) +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_free(ptr: *mut TimeSeries) { + Box::from_raw(ptr).emit().clear(); +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_row_count(ptr: *const TimeSeries) -> c_int { + (&*ptr).row_count() +} +#[no_mangle] +pub unsafe extern "C" fn time_series_can_fetch_more(ptr: *const TimeSeries) -> bool { + (&*ptr).can_fetch_more() +} +#[no_mangle] +pub unsafe extern "C" fn time_series_fetch_more(ptr: *mut TimeSeries) { + (&mut *ptr).fetch_more() +} +#[no_mangle] +pub unsafe extern "C" fn time_series_sort(ptr: *mut TimeSeries, column: c_int, order: SortOrder) { + (&mut *ptr).sort(column, order) +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_data_input(ptr: *const TimeSeries, row: c_int) -> u32 { + (&*ptr).input(row).into() +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_set_data_input(ptr: *mut TimeSeries, row: c_int, v: u32) -> bool { + (&mut *ptr).set_input(row, v) +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_data_result(ptr: *const TimeSeries, row: c_int) -> u32 { + (&*ptr).result(row).into() +} + +#[no_mangle] +pub unsafe extern "C" fn time_series_set_data_result(ptr: *mut TimeSeries, row: c_int, v: u32) -> bool { + (&mut *ptr).set_result(row, v) +} diff --git a/demo/rust/src/time_series_types.rs b/demo/rust/src/time_series_types.rs new file mode 100644 index 0000000..dbe4009 --- /dev/null +++ b/demo/rust/src/time_series_types.rs @@ -0,0 +1,104 @@ +/* generated by rust_qt_binding_generator */ +#![allow(dead_code)] +use std::slice; +use libc::{c_int, uint8_t, uint16_t}; + +#[repr(C)] +pub struct COption { + data: T, + some: bool, +} + +impl From> for COption where T: Default { + fn from(t: Option) -> COption { + if let Some(v) = t { + COption { + data: v, + some: true + } + } else { + COption { + data: T::default(), + some: false + } + } + } +} + +#[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 { + pub 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(), + } + } +} + +#[repr(C)] +pub struct QByteArray { + data: *const uint8_t, + len: c_int, +} + +impl QByteArray { + pub fn convert(&self) -> Vec { + let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; + Vec::from(data) + } +} + +impl<'a> From<&'a Vec> for QByteArray { + fn from(value: &'a Vec) -> QByteArray { + QByteArray { + len: value.len() as c_int, + data: value.as_ptr(), + } + } +} + +#[repr(C)] +pub struct QModelIndex { + row: c_int, + internal_id: usize, +} + +impl QModelIndex { + pub fn invalid() -> QModelIndex { + QModelIndex { + row: -1, + internal_id: 0, + } + } + pub fn create(row: c_int, id: usize) -> QModelIndex { + QModelIndex { + row: row, + internal_id: id, + } + } +} + +#[repr(C)] +pub enum SortOrder { + Ascending = 0, + Descending = 1 +} + diff --git a/demo/src/Fibonacci.cpp b/demo/src/Fibonacci.cpp index 30d474d..48ba47e 100644 --- a/demo/src/Fibonacci.cpp +++ b/demo/src/Fibonacci.cpp @@ -150,8 +150,8 @@ int FibonacciList::rowCount(const QModelIndex &parent) const QModelIndex FibonacciList::index(int row, int column, const QModelIndex &parent) const { - if (!parent.isValid() && column == 0) { - return createIndex(row, 0, (quintptr)0); + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 1) { + return createIndex(row, column, (quintptr)0); } return QModelIndex(); } @@ -190,7 +190,8 @@ QVariant FibonacciList::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case Qt::DisplayRole: + case 256: + case 0: v = fibonacci_list_data_result(d, index.row()); break; } @@ -199,8 +200,8 @@ QVariant FibonacciList::data(const QModelIndex &index, int role) const return v; } QHash FibonacciList::roleNames() const { - QHash names; - names.insert(Qt::DisplayRole, "result"); + QHash names = QAbstractItemModel::roleNames(); + names.insert(256, "result"); return names; } bool FibonacciList::setData(const QModelIndex &index, const QVariant &value, int role) diff --git a/demo/src/TimeSeries.cpp b/demo/src/TimeSeries.cpp new file mode 100644 index 0000000..c532397 --- /dev/null +++ b/demo/src/TimeSeries.cpp @@ -0,0 +1,231 @@ +/* generated by rust_qt_binding_generator */ +#include "TimeSeries.h" + +namespace { + template + struct option { + private: + T value; + bool some; + public: + 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(v.utf16())), + len(v.size()) { + } + operator QString() const { + return QString::fromUtf8(static_cast(data), len); + } + }; + struct qmodelindex_t { + int row; + quintptr id; + }; +} +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" { + TimeSeries::Private* time_series_new(TimeSeries*, + void (*)(const TimeSeries*), + void (*)(TimeSeries*), + void (*)(TimeSeries*), + void (*)(TimeSeries*, int, int), + void (*)(TimeSeries*), + void (*)(TimeSeries*, int, int), + void (*)(TimeSeries*)); + void time_series_free(TimeSeries::Private*); +}; +TimeSeries::TimeSeries(QObject *parent): + QAbstractItemModel(parent), + d(time_series_new(this, + [](const TimeSeries* o) { + emit o->newDataReady(QModelIndex()); + }, + [](TimeSeries* o) { + o->beginResetModel(); + }, + [](TimeSeries* o) { + o->endResetModel(); + }, + [](TimeSeries* o, int first, int last) { + o->beginInsertRows(QModelIndex(), first, last); + }, + [](TimeSeries* o) { + o->endInsertRows(); + }, + [](TimeSeries* o, int first, int last) { + o->beginRemoveRows(QModelIndex(), first, last); + }, + [](TimeSeries* o) { + o->endRemoveRows(); + } + )) { + connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} + + +TimeSeries::~TimeSeries() { + time_series_free(d); +} +extern "C" { + uint time_series_data_input(const TimeSeries::Private*, int); + bool time_series_set_data_input(TimeSeries::Private*, int, uint); + uint time_series_data_result(const TimeSeries::Private*, int); + bool time_series_set_data_result(TimeSeries::Private*, int, uint); + void time_series_sort(TimeSeries::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); + + int time_series_row_count(const TimeSeries::Private*); + bool time_series_can_fetch_more(const TimeSeries::Private*); + void time_series_fetch_more(TimeSeries::Private*); +} +int TimeSeries::columnCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : 2; +} + +bool TimeSeries::hasChildren(const QModelIndex &parent) const +{ + return rowCount(parent) > 0; +} + +int TimeSeries::rowCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : time_series_row_count(d); +} + +QModelIndex TimeSeries::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 2) { + return createIndex(row, column, (quintptr)0); + } + return QModelIndex(); +} + +QModelIndex TimeSeries::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +bool TimeSeries::canFetchMore(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : time_series_can_fetch_more(d); +} + +void TimeSeries::fetchMore(const QModelIndex &parent) +{ + if (!parent.isValid()) { + time_series_fetch_more(d); + } +} + +void TimeSeries::sort(int column, Qt::SortOrder order) +{ + time_series_sort(d, column, order); +} +Qt::ItemFlags TimeSeries::flags(const QModelIndex &i) const +{ + auto flags = QAbstractItemModel::flags(i); + if (i.column() == 0) { + flags |= Qt::ItemIsEditable; + } + if (i.column() == 1) { + flags |= Qt::ItemIsEditable; + } + return flags; +} +QVariant TimeSeries::data(const QModelIndex &index, int role) const +{ + QVariant v; + QString s; + QByteArray b; + switch (index.column()) { + case 0: + switch (role) { + case 256: + case 0: + case 2: + v = time_series_data_input(d, index.row()); + break; + case 257: + v = time_series_data_result(d, index.row()); + break; + } + break; + case 1: + switch (role) { + case 256: + v = time_series_data_input(d, index.row()); + break; + case 257: + case 0: + case 2: + v = time_series_data_result(d, index.row()); + break; + } + break; + } + return v; +} +QHash TimeSeries::roleNames() const { + QHash names = QAbstractItemModel::roleNames(); + names.insert(256, "input"); + names.insert(257, "result"); + return names; +} +bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int role) +{ + bool set = false; + if (index.column() == 0) { + if (role == 256 || role == 0 || role == 2) { + set = time_series_set_data_input(d, index.row(), value.value()); + } + if (role == 257) { + set = time_series_set_data_result(d, index.row(), value.value()); + } + } + if (index.column() == 1) { + if (role == 256) { + set = time_series_set_data_input(d, index.row(), value.value()); + } + if (role == 257 || role == 0 || role == 2) { + set = time_series_set_data_result(d, index.row(), value.value()); + } + } + if (set) { + emit dataChanged(index, index, QVector() << role); + } + return set; +} diff --git a/demo/src/TimeSeries.h b/demo/src/TimeSeries.h new file mode 100644 index 0000000..27b0627 --- /dev/null +++ b/demo/src/TimeSeries.h @@ -0,0 +1,37 @@ +/* generated by rust_qt_binding_generator */ +#ifndef TIMESERIES_H +#define TIMESERIES_H + +#include +#include + +class TimeSeries : public QAbstractItemModel +{ + Q_OBJECT +public: + class Private; +private: + Private * const d; +public: + explicit TimeSeries(QObject *parent = nullptr); + ~TimeSeries(); + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + bool canFetchMore(const QModelIndex &parent) const override; + void fetchMore(const QModelIndex &parent) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; + QHash roleNames() const override; +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 diff --git a/demo/src/Tree.cpp b/demo/src/Tree.cpp index fe6f5a5..b1d7132 100644 --- a/demo/src/Tree.cpp +++ b/demo/src/Tree.cpp @@ -118,17 +118,12 @@ void Tree::setPath(const QString& v) { } } extern "C" { - void tree_data_file_name(const Tree::Private*, int, quintptr, QString*, qstring_set); - bool tree_set_data_file_name(Tree::Private*, int, quintptr, qstring_t); void tree_data_file_icon(const Tree::Private*, int, quintptr, QByteArray*, qbytearray_set); + void tree_data_file_name(const Tree::Private*, int, quintptr, QString*, qstring_set); void tree_data_file_path(const Tree::Private*, int, quintptr, QString*, qstring_set); - bool tree_set_data_file_path(Tree::Private*, int, quintptr, qstring_t); - bool tree_set_data_file_path_none(Tree::Private*, int, quintptr); qint32 tree_data_file_permissions(const Tree::Private*, int, quintptr); - qint32 tree_data_file_type(const Tree::Private*, int, quintptr); option tree_data_file_size(const Tree::Private*, int, quintptr); - bool tree_set_data_file_size(Tree::Private*, int, quintptr, quint64); - bool tree_set_data_file_size_none(Tree::Private*, int, quintptr); + qint32 tree_data_file_type(const Tree::Private*, int, quintptr); void tree_sort(Tree::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); int tree_row_count(const Tree::Private*, int, quintptr); @@ -196,15 +191,6 @@ void Tree::sort(int column, Qt::SortOrder order) Qt::ItemFlags Tree::flags(const QModelIndex &i) const { auto flags = QAbstractItemModel::flags(i); - if (i.column() == 0) { - flags |= Qt::ItemIsEditable; - } - if (i.column() == 1) { - flags |= Qt::ItemIsEditable; - } - if (i.column() == 4) { - flags |= Qt::ItemIsEditable; - } return flags; } QVariant Tree::data(const QModelIndex &index, int role) const @@ -215,122 +201,151 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case Qt::DisplayRole: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case Qt::EditRole: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case Qt::DecorationRole: + case 256: + case 1: tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); if (!b.isNull()) v.setValue(b); break; - case Qt::UserRole + 1: - tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case Qt::UserRole + 2: + case 257: + case 0: tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; - case Qt::UserRole + 3: + case 258: + tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 259: v = tree_data_file_permissions(d, index.row(), index.internalId()); break; - case Qt::UserRole + 4: - v = tree_data_file_type(d, index.row(), index.internalId()); - break; - case Qt::UserRole + 5: + case 260: v = tree_data_file_size(d, index.row(), index.internalId()); break; + case 261: + v = tree_data_file_type(d, index.row(), index.internalId()); + break; } break; case 1: switch (role) { - case Qt::DisplayRole: + case 256: + tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); + if (!b.isNull()) v.setValue(b); + break; + case 257: + tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 258: tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; - case Qt::EditRole: - tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); + case 259: + v = tree_data_file_permissions(d, index.row(), index.internalId()); + break; + case 260: + case 0: + v = tree_data_file_size(d, index.row(), index.internalId()); + break; + case 261: + v = tree_data_file_type(d, index.row(), index.internalId()); break; } break; case 2: switch (role) { - case Qt::DisplayRole: + case 256: + tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); + if (!b.isNull()) v.setValue(b); + break; + case 257: + tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 258: + case 0: + tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 259: v = tree_data_file_permissions(d, index.row(), index.internalId()); break; + case 260: + v = tree_data_file_size(d, index.row(), index.internalId()); + break; + case 261: + v = tree_data_file_type(d, index.row(), index.internalId()); + break; } break; case 3: switch (role) { - case Qt::DisplayRole: + case 256: + tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); + if (!b.isNull()) v.setValue(b); + break; + case 257: + tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 258: + tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 259: + case 0: + v = tree_data_file_permissions(d, index.row(), index.internalId()); + break; + case 260: + v = tree_data_file_size(d, index.row(), index.internalId()); + break; + case 261: v = tree_data_file_type(d, index.row(), index.internalId()); break; } break; case 4: switch (role) { - case Qt::DisplayRole: + case 256: + tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); + if (!b.isNull()) v.setValue(b); + break; + case 257: + tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 258: + tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); + if (!s.isNull()) v.setValue(s); + break; + case 259: + v = tree_data_file_permissions(d, index.row(), index.internalId()); + break; + case 260: v = tree_data_file_size(d, index.row(), index.internalId()); break; + case 261: + case 0: + v = tree_data_file_type(d, index.row(), index.internalId()); + break; } break; } return v; } QHash Tree::roleNames() const { - QHash names; - names.insert(Qt::DisplayRole, "fileName"); - names.insert(Qt::DecorationRole, "fileIcon"); - names.insert(Qt::UserRole + 1, "filePath"); - names.insert(Qt::UserRole + 3, "filePermissions"); - names.insert(Qt::UserRole + 4, "fileType"); - names.insert(Qt::UserRole + 5, "fileSize"); + QHash names = QAbstractItemModel::roleNames(); + names.insert(256, "fileIcon"); + names.insert(257, "fileName"); + names.insert(258, "filePath"); + names.insert(259, "filePermissions"); + names.insert(260, "fileSize"); + names.insert(261, "fileType"); return names; } bool Tree::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; - if (index.column() == 0) { - if (role == Qt::DisplayRole) { - set = tree_set_data_file_name(d, index.row(), index.internalId(), value.value()); - } - if (role == Qt::EditRole) { - set = tree_set_data_file_name(d, index.row(), index.internalId(), value.value()); - } - if (role == Qt::UserRole + 1) { - if (!value.isValid() || value.isNull()) { - set = tree_set_data_file_path_none(d, index.row(), index.internalId()); - } else - set = tree_set_data_file_path(d, index.row(), index.internalId(), value.value()); - } - } - if (index.column() == 1) { - if (role == Qt::DisplayRole) { - if (!value.isValid() || value.isNull()) { - set = tree_set_data_file_path_none(d, index.row(), index.internalId()); - } else - set = tree_set_data_file_path(d, index.row(), index.internalId(), value.value()); - } - if (role == Qt::EditRole) { - if (!value.isValid() || value.isNull()) { - set = tree_set_data_file_path_none(d, index.row(), index.internalId()); - } else - set = tree_set_data_file_path(d, index.row(), index.internalId(), value.value()); - } - } - if (index.column() == 4) { - if (role == Qt::DisplayRole) { - if (!value.isValid()) { - set = tree_set_data_file_size_none(d, index.row(), index.internalId()); - } else - set = tree_set_data_file_size(d, index.row(), index.internalId(), value.value()); - } - } if (set) { emit dataChanged(index, index, QVector() << role); } diff --git a/demo/src/main.cpp b/demo/src/main.cpp index c840eb2..f88b571 100644 --- a/demo/src/main.cpp +++ b/demo/src/main.cpp @@ -1,7 +1,12 @@ #include "Tree.h" #include "Fibonacci.h" +#include "TimeSeries.h" -#ifdef QTQUICK +#ifdef QT_CHARTS_LIB +#include +#endif + +#ifdef QT_QUICK_LIB #include #include #include @@ -19,21 +24,24 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include struct Models { - Tree tree; - QSortFilterProxyModel sortedTree; + QStringListModel styles; Fibonacci fibonacci; FibonacciList fibonacciList; - QStringListModel styles; + Tree tree; + QSortFilterProxyModel sortedTree; + TimeSeries timeSeries; }; void setStyle(QWidget* w, QStyle* style) { @@ -54,7 +62,7 @@ QWindow* getWindow(QWidget* w) { return top->windowHandle(); } -#ifdef QTQUICK +#ifdef QT_QUICK_LIB void copyWindowGeometry(QWidget* w, QQmlContext* c) { QWindow* window = getWindow(w); @@ -94,7 +102,7 @@ QComboBox* createStyleComboBox(Models* models) { box->setCurrentText(v); } } -#ifdef QTQUICK +#ifdef QT_QUICK_LIB box->addItem("QtQuick"); #endif #ifdef QTQUICKCONTROLS2 @@ -118,7 +126,7 @@ QWidget* createStyleTab(Models* models, QWidget* tabs) { window->setHeight(windowRect.height()); } setStyle(tabs, QStyleFactory::create(text.mid(9))); -#ifdef QTQUICK +#ifdef QT_QUICK_LIB } else { if (window) { windowRect.setX(window->x()); @@ -188,6 +196,47 @@ QWidget* createTreeTab(Models* models) { return view; } +#ifdef QT_CHARTS_LIB + +using namespace QtCharts; + +QWidget* createChartTab(Models* models) { + QLineSeries *series = new QLineSeries(); + series->setName("Line 1"); + QVXYModelMapper *mapper = new QVXYModelMapper(series); + mapper->setXColumn(0); + mapper->setYColumn(1); + mapper->setSeries(series); + mapper->setModel(&models->timeSeries); + + QChart* chart = new QChart; + chart->addSeries(series); + QDateTimeAxis *axisX = new QDateTimeAxis; + axisX->setTickCount(10); + axisX->setFormat("MMM yyyy"); + axisX->setTitleText("Date"); + chart->addAxis(axisX, Qt::AlignBottom); + series->attachAxis(axisX); + + QValueAxis *axisY = new QValueAxis; + axisY->setLabelFormat("%i"); + axisY->setTitleText("Sunspots count"); + chart->addAxis(axisY, Qt::AlignLeft); + series->attachAxis(axisY); + + QWidget* view = new QWidget; + QTableView* data = new QTableView; + data->setModel(&models->timeSeries); + QChartView *chartView = new QChartView(chart); + + QHBoxLayout *layout = new QHBoxLayout; + layout->addWidget(data); + layout->addWidget(chartView); + view->setLayout(layout); + return view; +} +#endif + void createWidgets(Models* models) { QTabWidget* tabs = new QTabWidget(); @@ -195,6 +244,9 @@ void createWidgets(Models* models) { tabs->addTab(createObjectTab(models), "object"); tabs->addTab(createListTab(models), "list"); tabs->addTab(createTreeTab(models), "tree"); +#ifdef QT_CHARTS_LIB + tabs->addTab(createChartTab(models), "chart"); +#endif tabs->setMinimumSize(QSize(500, 500)); tabs->show(); } @@ -203,7 +255,7 @@ int main (int argc, char *argv[]) { QApplication app(argc, argv); -#ifdef QTQUICK +#ifdef QT_QUICK_LIB qmlRegisterType("org.qtproject.example", 1, 0, "SortFilterProxyModel"); qmlRegisterType("rust", 1, 0, "Fibonacci"); diff --git a/demo/time_series.json b/demo/time_series.json new file mode 100644 index 0000000..5f169e3 --- /dev/null +++ b/demo/time_series.json @@ -0,0 +1,26 @@ +{ + "cppFile": "src/TimeSeries.cpp", + "rust": { + "dir": "rust", + "interfaceModule": "time_series_interface", + "implementationModule": "time_series_implementation", + "typesModule": "time_series_types" + }, + "objects": { + "TimeSeries": { + "type": "List", + "itemProperties": { + "input": { + "type": "quint32", + "write": true, + "roles": [ [ "display", "edit" ] ] + }, + "result": { + "type": "quint32", + "write": true, + "roles": [ [], [ "display", "edit" ] ] + } + } + } + } +} diff --git a/demo/tree.json b/demo/tree.json index 0caad42..784948b 100644 --- a/demo/tree.json +++ b/demo/tree.json @@ -6,84 +6,44 @@ "implementationModule": "implementation", "typesModule": "types" }, - "objects": [{ - "name": "Tree", - "type": "UniformTree", - "properties": [{ - "name": "path", - "type": "QString", - "write": true, - "optional": true - }], - "roles": [ - [{ - "name": "fileName", - "value": "Qt::DisplayRole", - "type": "QString", - "write": true - }, { - "name": "fileName", - "value": "Qt::EditRole", - "type": "QString", - "write": true - }, { - "name": "fileIcon", - "value": "Qt::DecorationRole", - "type": "QByteArray" - }, { - "name": "filePath", - "value": "Qt::UserRole + 1", - "type": "QString", - "write": true, - "optional": true - }, { - "name": "fileName", - "value": "Qt::UserRole + 2", - "type": "QString" - }, { - "name": "filePermissions", - "value": "Qt::UserRole + 3", - "type": "qint32" - }, { - "name": "fileType", - "value": "Qt::UserRole + 4", - "type": "qint32" - }, { - "name": "fileSize", - "value": "Qt::UserRole + 5", - "type": "quint64", - "optional": true - }], - [{ - "name": "filePath", - "value": "Qt::DisplayRole", - "type": "QString", - "write": true, - "optional": true - }, { - "name": "filePath", - "value": "Qt::EditRole", - "type": "QString", - "write": true, - "optional": true - }], - [{ - "name": "filePermissions", - "value": "Qt::DisplayRole", - "type": "qint32" - }], - [{ - "name": "fileType", - "value": "Qt::DisplayRole", - "type": "qint32" - }], - [{ - "name": "fileSize", - "value": "Qt::DisplayRole", - "type": "quint64", - "write": true, - "optional": true - }] - ] - }] + "objects": { + "Tree": { + "type": "UniformTree", + "properties": { + "path": { + "type": "QString", + "write": true, + "optional": true + } + }, + "itemProperties": { + "fileName": { + "type": "QString", + "roles": [ ["display"] ] + }, + "fileIcon": { + "type": "QByteArray", + "roles": [ ["decoration"] ] + }, + "fileSize": { + "type": "quint64", + "optional": true, + "roles": [ [], ["display"] ] + }, + "filePath": { + "type": "QString", + "optional": true, + "roles": [ [], [], ["display"] ] + }, + "filePermissions": { + "type": "qint32", + "roles": [ [], [], [], ["display"] ] + }, + "fileType": { + "type": "qint32", + "roles": [ [], [], [], [],["display"] ] + } + } + } + } } diff --git a/rust_qt_binding_generator/rust_qt_binding_generator.cpp b/rust_qt_binding_generator/rust_qt_binding_generator.cpp index b25edfd..7579111 100644 --- a/rust_qt_binding_generator/rust_qt_binding_generator.cpp +++ b/rust_qt_binding_generator/rust_qt_binding_generator.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -99,20 +100,21 @@ struct Property { bool optional; }; -struct Role { +struct ItemProperty { QString name; - QString value; BindingTypeProperties type; bool write; bool optional; + int userRole; + QList> roles; }; struct Object { QString name; ObjectType type; QList properties; - QList> columnRoles; - QList allRoles; + QList itemProperties; + int columnCount; }; struct Configuration { @@ -180,56 +182,51 @@ QString rustTypeInit(const T& p) } Property -parseProperty(const QJsonObject& json) { +parseProperty(const QString& name, const QJsonObject& json) { Property p; - p.name = json.value("name").toString(); + p.name = name; p.type = parseBindingType(json.value("type").toString()); p.write = json.value("write").toBool(); p.optional = json.value("optional").toBool(); return p; } -Role -parseRole(const QJsonObject& json) { - Role r; - r.name = json.value("name").toString(); - r.value = json.value("value").toString(); - r.type = parseBindingType(json.value("type").toString()); - r.write = json.value("write").toBool(); - r.optional = json.value("optional").toBool(); - return r; +Qt::ItemDataRole parseItemDataRole(const QString& s) { + const QString name = s.left(1).toUpper() + s.mid(1) + "Role"; + int v = QMetaEnum::fromType() + .keyToValue(name.toUtf8()); + if (v >= 0) { + return (Qt::ItemDataRole)v; + } + err << QCoreApplication::translate("main", + "%1 is not a valid role name.\n").arg(s); + err.flush(); + exit(1); } -QList parseRoles(const QJsonArray& roles, QList& all) { - QList r; - for (const QJsonValue& val: roles) { - const Role role = parseRole(val.toObject()); - r.append(role); - bool found = false; - for (Role& ar: all) { - if (ar.name == role.name) { - found = true; - ar.write |= role.write; - if (ar.type.name != role.type.name) { - err << QCoreApplication::translate("main", - "Role %1 has two different types: %2 and %3.\n") - .arg(ar.name, ar.type.name, role.type.name); - err.flush(); - exit(1); - } - } - } - if (!found) { - all.append(role); +ItemProperty +parseItemProperty(const QString& name, const QJsonObject& json, int userRole) { + ItemProperty ip; + ip.name = name; + ip.type = parseBindingType(json.value("type").toString()); + ip.write = json.value("write").toBool(); + ip.optional = json.value("optional").toBool(); + ip.userRole = userRole; + QJsonArray roles = json.value("roles").toArray(); + for (auto r: roles) { + QList l; + for (auto v: r.toArray()) { + l.append(parseItemDataRole(v.toString())); } + ip.roles.append(l); } - return r; + return ip; } Object -parseObject(const QJsonObject& json) { +parseObject(const QString& name, const QJsonObject& json) { Object o; - o.name = json.value("name").toString(); + o.name = name; QString type = json.value("type").toString(); if (type == "List") { o.type = ObjectType::List; @@ -238,22 +235,28 @@ parseObject(const QJsonObject& json) { } else { o.type = ObjectType::Object; } - for (const QJsonValue& val: json.value("properties").toArray()) { - o.properties.append(parseProperty(val.toObject())); + const QJsonObject& properties = json.value("properties").toObject(); + for (const QString& key: properties.keys()) { + o.properties.append(parseProperty(key, properties[key].toObject())); } - QJsonArray roles = json.value("roles").toArray(); - if (o.type != ObjectType::Object && roles.size() == 0) { + const QJsonObject& itemProperties = json.value("itemProperties").toObject(); + if (o.type != ObjectType::Object && itemProperties.size() == 0) { err << QCoreApplication::translate("main", - "No roles are defined for %1.\n").arg(o.name); + "No item properties are defined for %1.\n").arg(o.name); + err.flush(); + exit(1); + } else if (o.type == ObjectType::Object && itemProperties.size() > 0) { + err << QCoreApplication::translate("main", + "%1 is an Object and should not have itemProperties.").arg(o.name); err.flush(); exit(1); } - if (roles.at(0).isArray()) { - for (const QJsonValue& val: roles) { - o.columnRoles.append(parseRoles(val.toArray(), o.allRoles)); - } - } else { - o.columnRoles.append(parseRoles(roles, o.allRoles)); + o.columnCount = 0; + for (const QString& key: itemProperties.keys()) { + ItemProperty p = parseItemProperty(key, itemProperties[key].toObject(), + Qt::UserRole + o.itemProperties.size()); + o.columnCount = qMax(o.columnCount, p.roles.size()); + o.itemProperties.append(p); } return o; } @@ -281,8 +284,9 @@ parseConfiguration(const QString& path) { c.cppFile = QFileInfo(base, o.value("cppFile").toString()); QDir(c.cppFile.dir()).mkpath("."); c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h"); - for (const QJsonValue& val: o.value("objects").toArray()) { - c.objects.append(parseObject(val.toObject())); + const QJsonObject& object = o.value("objects").toObject(); + for (const QString& key: object.keys()) { + c.objects.append(parseObject(key, object[key].toObject())); } const QJsonObject rust = o.value("rust").toObject(); c.rustdir = QDir(base.filePath(rust.value("dir").toString())); @@ -336,12 +340,13 @@ signals: )"); } -bool isWrite(const QList& roles) { - bool write = false; - for (auto role: roles) { - write = write | role.write; +bool isColumnWrite(const Object& o, int col) { + for (auto ip: o.itemProperties) { + if (ip.write && ip.roles.size() > col && ip.roles[col].size() > 0) { + return true; + } } - return write; + return false; } void writeCppModel(QTextStream& cpp, const Object& o) { @@ -354,20 +359,20 @@ void writeCppModel(QTextStream& cpp, const Object& o) { } cpp << "extern \"C\" {\n"; - for (auto role: o.allRoles) { - if (role.type.isComplex()) { + for (auto ip: o.itemProperties) { + if (ip.type.isComplex()) { cpp << QString(" void %2_data_%3(const %1::Private*%5, %4);\n") - .arg(o.name, lcname, snakeCase(role.name), cGetType(role.type), indexDecl); + .arg(o.name, lcname, snakeCase(ip.name), cGetType(ip.type), indexDecl); } else { cpp << QString(" %4 %2_data_%3(const %1::Private*%5);\n") - .arg(o.name, lcname, snakeCase(role.name), cppSetType(role), indexDecl); + .arg(o.name, lcname, snakeCase(ip.name), cppSetType(ip), indexDecl); } - if (role.write) { + if (ip.write) { cpp << QString(" bool %2_set_data_%3(%1::Private*%5, %4);") - .arg(o.name, lcname, snakeCase(role.name), role.type.cSetType, indexDecl) << endl; - if (role.optional) { + .arg(o.name, lcname, snakeCase(ip.name), ip.type.cSetType, indexDecl) << endl; + if (ip.optional) { cpp << QString(" bool %2_set_data_%3_none(%1::Private*%4);") - .arg(o.name, lcname, snakeCase(role.name), indexDecl) << endl; + .arg(o.name, lcname, snakeCase(ip.name), indexDecl) << endl; } } } @@ -395,8 +400,8 @@ int %1::rowCount(const QModelIndex &parent) const QModelIndex %1::index(int row, int column, const QModelIndex &parent) const { - if (!parent.isValid() && column == 0) { - return createIndex(row, 0, (quintptr)0); + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < %3) { + return createIndex(row, column, (quintptr)0); } return QModelIndex(); } @@ -417,7 +422,7 @@ void %1::fetchMore(const QModelIndex &parent) %2_fetch_more(d); } } -)").arg(o.name, lcname, QString::number(o.columnRoles.size())); +)").arg(o.name, lcname, QString::number(o.columnCount)); } else { cpp << QString(R"( int %2_row_count(const %1::Private*, int, quintptr); @@ -477,7 +482,7 @@ void %1::fetchMore(const QModelIndex &parent) { %2_fetch_more(d, parent.row(), parent.internalId()); } -)").arg(o.name, lcname, QString::number(o.columnRoles.size())); +)").arg(o.name, lcname, QString::number(o.columnCount)); } cpp << QString(R"( @@ -489,8 +494,8 @@ Qt::ItemFlags %1::flags(const QModelIndex &i) const { auto flags = QAbstractItemModel::flags(i); )").arg(o.name, lcname); - for (int col = 0; col < o.columnRoles.size(); ++col) { - if (isWrite(o.columnRoles[col])) { + for (int col = 0; col < o.columnCount; ++col) { + if (isColumnWrite(o, col)) { cpp << " if (i.column() == " << col << ") {\n"; cpp << " flags |= Qt::ItemIsEditable;\n }\n"; } @@ -505,23 +510,25 @@ QVariant %1::data(const QModelIndex &index, int role) const switch (index.column()) { )").arg(o.name); - for (int col = 0; col < o.columnRoles.size(); ++col) { - auto roles = o.columnRoles[col]; + for (int col = 0; col < o.columnCount; ++col) { cpp << QString(" case %1:\n").arg(col); cpp << QString(" switch (role) {\n"); - for (auto role: roles) { - cpp << QString(" case %1:\n").arg(role.value); - if (role.type.name == "QString") { + for (auto ip: o.itemProperties) { + cpp << QString(" case %1:\n").arg(ip.userRole); + for (auto r: ip.roles.value(col)) { + cpp << QString(" case %1:\n").arg(r); + } + if (ip.type.name == "QString") { cpp << QString(" %1_data_%2(d%4, &s, set_%3);\n") - .arg(lcname, snakeCase(role.name), role.type.name.toLower(), index); + .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); cpp << " if (!s.isNull()) v.setValue(s);\n"; - } else if (role.type.name == "QByteArray") { + } else if (ip.type.name == "QByteArray") { cpp << QString(" %1_data_%2(d%4, &b, set_%3);\n") - .arg(lcname, snakeCase(role.name), role.type.name.toLower(), index); + .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); cpp << " if (!b.isNull()) v.setValue(b);\n"; } else { cpp << QString(" v = %1_data_%2(d%3);\n") - .arg(lcname, snakeCase(role.name), index); + .arg(lcname, snakeCase(ip.name), index); } cpp << " break;\n"; } @@ -530,9 +537,9 @@ QVariant %1::data(const QModelIndex &index, int role) const } cpp << " }\n return v;\n}\n"; cpp << "QHash " << o.name << "::roleNames() const {\n"; - cpp << " QHash names;\n"; - for (auto role: o.allRoles) { - cpp << " names.insert(" << role.value << ", \"" << role.name << "\");\n"; + cpp << " QHash names = QAbstractItemModel::roleNames();\n"; + for (auto ip: o.itemProperties) { + cpp << " names.insert(" << ip.userRole << ", \"" << ip.name << "\");\n"; } cpp << " return names;\n"; cpp << QString(R"(} @@ -540,30 +547,33 @@ bool %1::setData(const QModelIndex &index, const QVariant &value, int role) { )").arg(o.name); cpp << " bool set = false;\n"; - for (int col = 0; col < o.columnRoles.size(); ++col) { - if (!isWrite(o.columnRoles[col])) { + for (int col = 0; col < o.columnCount; ++col) { + if (!isColumnWrite(o, col)) { continue; } cpp << " if (index.column() == " << col << ") {\n"; - auto roles = o.columnRoles[col]; - for (auto role: roles) { - if (!role.write) { + for (auto ip: o.itemProperties) { + if (!ip.write) { continue; } - cpp << " if (role == " << role.value << ") {\n"; - if (role.optional) { + cpp << " if (role == " << ip.userRole; + for (auto r: ip.roles.value(col)) { + cpp << QString(" || role == %1").arg(r); + } + cpp << ") {\n"; + if (ip.optional) { QString test = "!value.isValid()"; - if (role.type.isComplex()) { + if (ip.type.isComplex()) { test += " || value.isNull()"; } cpp << " if (" << test << ") {\n"; cpp << QString(" set = %1_set_data_%2_none(d%3);") - .arg(lcname, snakeCase(role.name), index) << endl; + .arg(lcname, snakeCase(ip.name), index) << endl; cpp << " } else\n"; } - QString val = QString("value.value<%1>()").arg(role.type.name); + QString val = QString("value.value<%1>()").arg(ip.type.name); cpp << QString(" set = %1_set_data_%2(d%3, %4);") - .arg(lcname, snakeCase(role.name), index, val) << endl; + .arg(lcname, snakeCase(ip.name), index, val) << endl; cpp << " }\n"; } cpp << " }\n"; @@ -1032,12 +1042,12 @@ pub trait %1Trait { } else if (o.type == ObjectType::UniformTree) { index = ", row: c_int, parent: usize"; } - for (auto role: o.allRoles) { + for (auto ip: o.itemProperties) { r << QString(" fn %1(&self%3) -> %2;\n") - .arg(snakeCase(role.name), rustType(role), index); - if (role.write) { + .arg(snakeCase(ip.name), rustType(ip), index); + if (ip.write) { r << QString(" fn set_%1(&mut self%3, %2) -> bool;\n") - .arg(snakeCase(role.name), rustType(role), index); + .arg(snakeCase(ip.name), rustType(ip), index); } } } @@ -1207,8 +1217,8 @@ pub unsafe extern "C" fn %2_sort(ptr: *mut %1, column: c_int, order: SortOrder) indexDecl = ", parent: usize"; index = ", parent"; } - for (auto role: o.allRoles) { - if (role.type.isComplex() && !role.optional) { + for (auto ip: o.itemProperties) { + if (ip.type.isComplex() && !ip.optional) { r << QString(R"( #[no_mangle] pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, @@ -1218,8 +1228,8 @@ pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, let data = (&*ptr).%3(row%6); set(d, %4::from(&data)); } -)").arg(o.name, lcname, snakeCase(role.name), role.type.name, indexDecl, index); - } else if (role.type.isComplex()) { +)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); + } else if (ip.type.isComplex()) { r << QString(R"( #[no_mangle] pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, @@ -1231,23 +1241,23 @@ pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, set(d, %4::from(&data)); } } -)").arg(o.name, lcname, snakeCase(role.name), role.type.name, indexDecl, index); +)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); } else { r << QString(R"( #[no_mangle] pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, row: c_int%5) -> %4 { (&*ptr).%3(row%6).into() } -)").arg(o.name, lcname, snakeCase(role.name), rustCType(role), indexDecl, index); +)").arg(o.name, lcname, snakeCase(ip.name), rustCType(ip), indexDecl, index); } - if (role.write) { + if (ip.write) { QString val = "v"; - QString type = role.type.rustType; - if (role.type.isComplex()) { + QString type = ip.type.rustType; + if (ip.type.isComplex()) { val = val + ".convert()"; - type = role.type.name == "QString" ? "QStringIn" : role.type.name; + type = ip.type.name == "QString" ? "QStringIn" : ip.type.name; } - if (role.optional) { + if (ip.optional) { val = "Some(" + val + ")"; } r << QString(R"( @@ -1255,15 +1265,15 @@ pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, row: c_int%5) -> %4 { pub unsafe extern "C" fn %2_set_data_%3(ptr: *mut %1, row: c_int%4, v: %6) -> bool { (&mut *ptr).set_%3(row%5, %7) } -)").arg(o.name, lcname, snakeCase(role.name), indexDecl, index, type, val); +)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index, type, val); } - if (role.write && role.optional) { + if (ip.write && ip.optional) { r << QString(R"( #[no_mangle] pub unsafe extern "C" fn %2_set_data_%3_none(ptr: *mut %1, row: c_int%4) -> bool { (&mut *ptr).set_%3(row%5, None) } -)").arg(o.name, lcname, snakeCase(role.name), indexDecl, index); +)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index); } } } @@ -1313,9 +1323,9 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { if (o.type != ObjectType::Object) { r << "#[derive (Default, Clone)]\n"; r << QString("struct %1Item {\n").arg(o.name); - for (auto role: o.allRoles) { - const QString lc(snakeCase(role.name)); - r << QString(" %1: %2,\n").arg(lc, role.type.rustType); + for (auto ip: o.itemProperties) { + const QString lc(snakeCase(ip.name)); + r << QString(" %1: %2,\n").arg(lc, ip.type.rustType); } r << "}\n\n"; } @@ -1384,15 +1394,15 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { if (o.type == ObjectType::UniformTree) { index = ", parent: usize"; } - for (auto role: o.allRoles) { - const QString lc(snakeCase(role.name)); + for (auto ip: o.itemProperties) { + const QString lc(snakeCase(ip.name)); r << QString(" fn %1(&self, row: c_int%3) -> %2 {\n") - .arg(lc, rustType(role), index); + .arg(lc, rustType(ip), index); r << " self.list[row as usize]." << lc << ".clone()\n"; r << " }\n"; - if (role.write) { + if (ip.write) { r << QString(" fn set_%1(&mut self, row: c_int%3, v: %2) -> bool {\n") - .arg(snakeCase(role.name), rustType(role), index); + .arg(snakeCase(ip.name), rustType(ip), index); r << " self.list[row as usize]." << lc << " = v;\n"; r << " true\n"; r << " }\n"; diff --git a/tests/rust_object_types/src/implementation.rs b/tests/rust_object_types/src/implementation.rs index b11f24c..0493ec4 100644 --- a/tests/rust_object_types/src/implementation.rs +++ b/tests/rust_object_types/src/implementation.rs @@ -9,13 +9,13 @@ use interface::*; pub struct Object { emit: ObjectEmitter, boolean: bool, - integer: i32, - uinteger: u32, - u64: u64, - string: String, - optional_string: Option, bytearray: Vec, + integer: i32, optional_bytearray: Option>, + optional_string: Option, + string: String, + u64: u64, + uinteger: u32, } impl ObjectTrait for Object { @@ -23,13 +23,13 @@ impl ObjectTrait for Object { Object { emit: emit, boolean: true, - integer: 0, - uinteger: 0, - u64: 0, - string: String::new(), - optional_string: None, bytearray: Vec::new(), + integer: 0, optional_bytearray: None, + optional_string: None, + string: String::new(), + u64: 0, + uinteger: 0, } } fn emit(&self) -> &ObjectEmitter { @@ -42,41 +42,6 @@ impl ObjectTrait for Object { self.boolean = value; self.emit.boolean_changed(); } - fn get_integer(&self) -> i32 { - self.integer - } - fn set_integer(&mut self, value: i32) { - self.integer = value; - self.emit.integer_changed(); - } - fn get_uinteger(&self) -> u32 { - self.uinteger - } - fn set_uinteger(&mut self, value: u32) { - self.uinteger = value; - self.emit.uinteger_changed(); - } - fn get_u64(&self) -> u64 { - self.u64 - } - fn set_u64(&mut self, value: u64) { - self.u64 = value; - self.emit.u64_changed(); - } - fn get_string(&self) -> String { - self.string.clone() - } - fn set_string(&mut self, value: String) { - self.string = value; - self.emit.string_changed(); - } - fn get_optional_string(&self) -> Option { - self.optional_string.clone() - } - fn set_optional_string(&mut self, value: Option) { - self.optional_string = value; - self.emit.optional_string_changed(); - } fn get_bytearray(&self) -> Vec { self.bytearray.clone() } @@ -84,6 +49,13 @@ impl ObjectTrait for Object { self.bytearray = value; self.emit.bytearray_changed(); } + 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> { self.optional_bytearray.clone() } @@ -91,4 +63,32 @@ impl ObjectTrait for Object { self.optional_bytearray = value; self.emit.optional_bytearray_changed(); } + fn get_optional_string(&self) -> Option { + self.optional_string.clone() + } + fn set_optional_string(&mut self, value: Option) { + self.optional_string = value; + self.emit.optional_string_changed(); + } + 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 { + self.u64 + } + fn set_u64(&mut self, value: u64) { + self.u64 = value; + self.emit.u64_changed(); + } + fn get_uinteger(&self) -> u32 { + self.uinteger + } + fn set_uinteger(&mut self, value: u32) { + self.uinteger = value; + self.emit.uinteger_changed(); + } } diff --git a/tests/rust_object_types/src/interface.rs b/tests/rust_object_types/src/interface.rs index a14804e..c01604e 100644 --- a/tests/rust_object_types/src/interface.rs +++ b/tests/rust_object_types/src/interface.rs @@ -15,13 +15,13 @@ pub struct ObjectQObject {} pub struct ObjectEmitter { qobject: Arc>, boolean_changed: fn(*const ObjectQObject), - integer_changed: fn(*const ObjectQObject), - uinteger_changed: fn(*const ObjectQObject), - u64_changed: fn(*const ObjectQObject), - string_changed: fn(*const ObjectQObject), - optional_string_changed: fn(*const ObjectQObject), bytearray_changed: fn(*const ObjectQObject), + integer_changed: fn(*const ObjectQObject), optional_bytearray_changed: fn(*const ObjectQObject), + optional_string_changed: fn(*const ObjectQObject), + string_changed: fn(*const ObjectQObject), + u64_changed: fn(*const ObjectQObject), + uinteger_changed: fn(*const ObjectQObject), } unsafe impl Send for ObjectEmitter {} @@ -36,28 +36,22 @@ impl ObjectEmitter { (self.boolean_changed)(ptr); } } + pub fn bytearray_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.bytearray_changed)(ptr); + } + } pub fn integer_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { (self.integer_changed)(ptr); } } - pub fn uinteger_changed(&self) { + pub fn optional_bytearray_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { - (self.uinteger_changed)(ptr); - } - } - pub fn u64_changed(&self) { - let ptr = *self.qobject.lock().unwrap(); - if !ptr.is_null() { - (self.u64_changed)(ptr); - } - } - pub fn string_changed(&self) { - let ptr = *self.qobject.lock().unwrap(); - if !ptr.is_null() { - (self.string_changed)(ptr); + (self.optional_bytearray_changed)(ptr); } } pub fn optional_string_changed(&self) { @@ -66,16 +60,22 @@ impl ObjectEmitter { (self.optional_string_changed)(ptr); } } - pub fn bytearray_changed(&self) { + pub fn string_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { - (self.bytearray_changed)(ptr); + (self.string_changed)(ptr); } } - pub fn optional_bytearray_changed(&self) { + pub fn u64_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { - (self.optional_bytearray_changed)(ptr); + (self.u64_changed)(ptr); + } + } + pub fn uinteger_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.uinteger_changed)(ptr); } } } @@ -85,43 +85,43 @@ pub trait ObjectTrait { fn emit(&self) -> &ObjectEmitter; fn get_boolean(&self) -> bool; fn set_boolean(&mut self, value: bool); - fn get_integer(&self) -> i32; - fn set_integer(&mut self, value: i32); - fn get_uinteger(&self) -> u32; - fn set_uinteger(&mut self, value: u32); - fn get_u64(&self) -> u64; - fn set_u64(&mut self, value: u64); - fn get_string(&self) -> String; - fn set_string(&mut self, value: String); - fn get_optional_string(&self) -> Option; - fn set_optional_string(&mut self, value: Option); fn get_bytearray(&self) -> Vec; fn set_bytearray(&mut self, value: Vec); + fn get_integer(&self) -> i32; + fn set_integer(&mut self, value: i32); fn get_optional_bytearray(&self) -> Option>; fn set_optional_bytearray(&mut self, value: Option>); + fn get_optional_string(&self) -> Option; + fn set_optional_string(&mut self, value: Option); + fn get_string(&self) -> String; + fn set_string(&mut self, value: String); + fn get_u64(&self) -> u64; + fn set_u64(&mut self, value: u64); + fn get_uinteger(&self) -> u32; + fn set_uinteger(&mut self, value: u32); } #[no_mangle] pub extern "C" fn object_new(qobject: *const ObjectQObject, boolean_changed: fn(*const ObjectQObject), - integer_changed: fn(*const ObjectQObject), - uinteger_changed: fn(*const ObjectQObject), - u64_changed: fn(*const ObjectQObject), - string_changed: fn(*const ObjectQObject), - optional_string_changed: fn(*const ObjectQObject), bytearray_changed: fn(*const ObjectQObject), - optional_bytearray_changed: fn(*const ObjectQObject)) + integer_changed: fn(*const ObjectQObject), + optional_bytearray_changed: fn(*const ObjectQObject), + optional_string_changed: fn(*const ObjectQObject), + string_changed: fn(*const ObjectQObject), + u64_changed: fn(*const ObjectQObject), + uinteger_changed: fn(*const ObjectQObject)) -> *mut Object { let emit = ObjectEmitter { qobject: Arc::new(Mutex::new(qobject)), boolean_changed: boolean_changed, - integer_changed: integer_changed, - uinteger_changed: uinteger_changed, - u64_changed: u64_changed, - string_changed: string_changed, - optional_string_changed: optional_string_changed, bytearray_changed: bytearray_changed, + integer_changed: integer_changed, optional_bytearray_changed: optional_bytearray_changed, + optional_string_changed: optional_string_changed, + string_changed: string_changed, + u64_changed: u64_changed, + uinteger_changed: uinteger_changed, }; let d = Object::create(emit); Box::into_raw(Box::new(d)) @@ -142,6 +142,19 @@ pub unsafe extern "C" fn object_boolean_set(ptr: *mut Object, v: bool) { (&mut *ptr).set_boolean(v); } +#[no_mangle] +pub unsafe extern "C" fn object_bytearray_get(ptr: *const Object, + p: *mut c_void, + set: fn(*mut c_void, QByteArray)) { + let data = (&*ptr).get_bytearray(); + set(p, QByteArray::from(&data)); +} + +#[no_mangle] +pub unsafe extern "C" fn object_bytearray_set(ptr: *mut Object, v: QByteArray) { + (&mut *ptr).set_bytearray(v.convert()); +} + #[no_mangle] pub unsafe extern "C" fn object_integer_get(ptr: *const Object) -> i32 { (&*ptr).get_integer() @@ -153,36 +166,22 @@ pub unsafe extern "C" fn object_integer_set(ptr: *mut Object, v: i32) { } #[no_mangle] -pub unsafe extern "C" fn object_uinteger_get(ptr: *const Object) -> u32 { - (&*ptr).get_uinteger() -} - -#[no_mangle] -pub unsafe extern "C" fn object_uinteger_set(ptr: *mut Object, v: u32) { - (&mut *ptr).set_uinteger(v); -} - -#[no_mangle] -pub unsafe extern "C" fn object_u64_get(ptr: *const Object) -> u64 { - (&*ptr).get_u64() -} - -#[no_mangle] -pub unsafe extern "C" fn object_u64_set(ptr: *mut Object, v: u64) { - (&mut *ptr).set_u64(v); -} - -#[no_mangle] -pub unsafe extern "C" fn object_string_get(ptr: *const Object, +pub unsafe extern "C" fn object_optional_bytearray_get(ptr: *const Object, p: *mut c_void, - set: fn(*mut c_void, QString)) { - let data = (&*ptr).get_string(); - set(p, QString::from(&data)); + set: fn(*mut c_void, QByteArray)) { + let data = (&*ptr).get_optional_bytearray(); + if let Some(data) = data { + set(p, QByteArray::from(&data)); + } } #[no_mangle] -pub unsafe extern "C" fn object_string_set(ptr: *mut Object, v: QStringIn) { - (&mut *ptr).set_string(v.convert()); +pub unsafe extern "C" fn object_optional_bytearray_set(ptr: *mut Object, v: QByteArray) { + (&mut *ptr).set_optional_bytearray(Some(v.convert())); +} +#[no_mangle] +pub unsafe extern "C" fn object_optional_bytearray_set_none(ptr: *mut Object) { + (&mut *ptr).set_optional_bytearray(None); } #[no_mangle] @@ -205,33 +204,34 @@ pub unsafe extern "C" fn object_optional_string_set_none(ptr: *mut Object) { } #[no_mangle] -pub unsafe extern "C" fn object_bytearray_get(ptr: *const Object, +pub unsafe extern "C" fn object_string_get(ptr: *const Object, p: *mut c_void, - set: fn(*mut c_void, QByteArray)) { - let data = (&*ptr).get_bytearray(); - set(p, QByteArray::from(&data)); + set: fn(*mut c_void, QString)) { + let data = (&*ptr).get_string(); + set(p, QString::from(&data)); } #[no_mangle] -pub unsafe extern "C" fn object_bytearray_set(ptr: *mut Object, v: QByteArray) { - (&mut *ptr).set_bytearray(v.convert()); +pub unsafe extern "C" fn object_string_set(ptr: *mut Object, v: QStringIn) { + (&mut *ptr).set_string(v.convert()); } #[no_mangle] -pub unsafe extern "C" fn object_optional_bytearray_get(ptr: *const Object, - p: *mut c_void, - set: fn(*mut c_void, QByteArray)) { - let data = (&*ptr).get_optional_bytearray(); - if let Some(data) = data { - set(p, QByteArray::from(&data)); - } +pub unsafe extern "C" fn object_u64_get(ptr: *const Object) -> u64 { + (&*ptr).get_u64() } #[no_mangle] -pub unsafe extern "C" fn object_optional_bytearray_set(ptr: *mut Object, v: QByteArray) { - (&mut *ptr).set_optional_bytearray(Some(v.convert())); +pub unsafe extern "C" fn object_u64_set(ptr: *mut Object, v: u64) { + (&mut *ptr).set_u64(v); } + #[no_mangle] -pub unsafe extern "C" fn object_optional_bytearray_set_none(ptr: *mut Object) { - (&mut *ptr).set_optional_bytearray(None); +pub unsafe extern "C" fn object_uinteger_get(ptr: *const Object) -> u32 { + (&*ptr).get_uinteger() +} + +#[no_mangle] +pub unsafe extern "C" fn object_uinteger_set(ptr: *mut Object, v: u32) { + (&mut *ptr).set_uinteger(v); } diff --git a/tests/test_list.json b/tests/test_list.json index f21fe54..a1caf88 100644 --- a/tests/test_list.json +++ b/tests/test_list.json @@ -6,18 +6,16 @@ "implementationModule": "implementation", "typesModule": "types" }, - "objects": [{ - "name": "Persons", - "type": "List", - "roles": [{ - "name": "userName", - "value": "Qt::DisplayRole", - "type": "QString" - }, { - "name": "userName", - "value": "Qt::EditRole", - "type": "QString", - "write": true - }] - }] + "objects": { + "Persons": { + "type": "List", + "itemProperties": { + "userName": { + "type": "QString", + "write": true, + "roles": [ [ "display", "edit" ] ] + } + } + } + } } diff --git a/tests/test_list_rust.cpp b/tests/test_list_rust.cpp index 5f6126f..35cf9b5 100644 --- a/tests/test_list_rust.cpp +++ b/tests/test_list_rust.cpp @@ -126,8 +126,8 @@ int Persons::rowCount(const QModelIndex &parent) const QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const { - if (!parent.isValid() && column == 0) { - return createIndex(row, 0, (quintptr)0); + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 1) { + return createIndex(row, column, (quintptr)0); } return QModelIndex(); } @@ -169,11 +169,9 @@ QVariant Persons::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case Qt::DisplayRole: - persons_data_user_name(d, index.row(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case Qt::EditRole: + case 256: + case 0: + case 2: persons_data_user_name(d, index.row(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; @@ -183,15 +181,15 @@ QVariant Persons::data(const QModelIndex &index, int role) const return v; } QHash Persons::roleNames() const { - QHash names; - names.insert(Qt::DisplayRole, "userName"); + QHash names = QAbstractItemModel::roleNames(); + names.insert(256, "userName"); return names; } bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; if (index.column() == 0) { - if (role == Qt::EditRole) { + if (role == 256 || role == 0 || role == 2) { set = persons_set_data_user_name(d, index.row(), value.value()); } } diff --git a/tests/test_object.json b/tests/test_object.json index 6ede659..a823406 100644 --- a/tests/test_object.json +++ b/tests/test_object.json @@ -6,13 +6,15 @@ "implementationModule": "implementation", "typesModule": "types" }, - "objects": [{ - "name": "Person", - "type": "Object", - "properties": [{ - "name": "userName", - "type": "QString", - "write": true - }] - }] + "objects": { + "Person": { + "type": "Object", + "properties": { + "userName": { + "type": "QString", + "write": true + } + } + } + } } diff --git a/tests/test_object_types.json b/tests/test_object_types.json index 01c24d8..78506f2 100644 --- a/tests/test_object_types.json +++ b/tests/test_object_types.json @@ -6,44 +6,45 @@ "implementationModule": "implementation", "typesModule": "types" }, - "objects": [{ - "name": "Object", - "type": "Object", - "properties": [{ - "name": "boolean", - "type": "bool", - "write": true - }, { - "name": "integer", - "type": "qint32", - "write": true - }, { - "name": "uinteger", - "type": "quint32", - "write": true - }, { - "name": "u64", - "type": "quint64", - "write": true - }, { - "name": "string", - "type": "QString", - "write": true, - "nullable": true - }, { - "name": "optionalString", - "type": "QString", - "write": true, - "optional": true - }, { - "name": "bytearray", - "type": "QByteArray", - "write": true - }, { - "name": "optionalBytearray", - "type": "QByteArray", - "write": true, - "optional": true - }] - }] + "objects": { + "Object": { + "type": "Object", + "properties": { + "boolean": { + "type": "bool", + "write": true + }, + "integer": { + "type": "qint32", + "write": true + }, + "uinteger": { + "type": "quint32", + "write": true + }, + "u64": { + "type": "quint64", + "write": true + }, + "string": { + "type": "QString", + "write": true + }, + "optionalString": { + "type": "QString", + "write": true, + "optional": true + }, + "bytearray": { + "type": "QByteArray", + "write": true + }, + "optionalBytearray": { + "type": "QByteArray", + "write": true, + "optional": true + } + } + } + } } diff --git a/tests/test_object_types_rust.cpp b/tests/test_object_types_rust.cpp index f364f6b..287cfa6 100644 --- a/tests/test_object_types_rust.cpp +++ b/tests/test_object_types_rust.cpp @@ -60,34 +60,34 @@ extern "C" { void object_free(Object::Private*); bool object_boolean_get(const Object::Private*); void object_boolean_set(Object::Private*, bool); - qint32 object_integer_get(const Object::Private*); - void object_integer_set(Object::Private*, qint32); - quint32 object_uinteger_get(const Object::Private*); - void object_uinteger_set(Object::Private*, uint); - quint64 object_u64_get(const Object::Private*); - void object_u64_set(Object::Private*, quint64); - void object_string_get(const Object::Private*, QString*, qstring_set); - void object_string_set(Object::Private*, qstring_t); - void object_optional_string_get(const Object::Private*, QString*, qstring_set); - void object_optional_string_set(Object::Private*, qstring_t); - void object_optional_string_set_none(Object::Private*); void object_bytearray_get(const Object::Private*, QByteArray*, qbytearray_set); void object_bytearray_set(Object::Private*, qbytearray_t); + qint32 object_integer_get(const Object::Private*); + void object_integer_set(Object::Private*, qint32); void object_optional_bytearray_get(const Object::Private*, QByteArray*, qbytearray_set); void object_optional_bytearray_set(Object::Private*, qbytearray_t); void object_optional_bytearray_set_none(Object::Private*); + void object_optional_string_get(const Object::Private*, QString*, qstring_set); + void object_optional_string_set(Object::Private*, qstring_t); + void object_optional_string_set_none(Object::Private*); + void object_string_get(const Object::Private*, QString*, qstring_set); + void object_string_set(Object::Private*, qstring_t); + quint64 object_u64_get(const Object::Private*); + void object_u64_set(Object::Private*, quint64); + quint32 object_uinteger_get(const Object::Private*); + void object_uinteger_set(Object::Private*, uint); }; Object::Object(QObject *parent): QObject(parent), d(object_new(this, [](Object* o) { emit o->booleanChanged(); }, - [](Object* o) { emit o->integerChanged(); }, - [](Object* o) { emit o->uintegerChanged(); }, - [](Object* o) { emit o->u64Changed(); }, - [](Object* o) { emit o->stringChanged(); }, - [](Object* o) { emit o->optionalStringChanged(); }, [](Object* o) { emit o->bytearrayChanged(); }, - [](Object* o) { emit o->optionalBytearrayChanged(); })) {} + [](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(); })) {} Object::~Object() { object_free(d); @@ -99,49 +99,6 @@ bool Object::boolean() const void Object::setBoolean(bool v) { object_boolean_set(d, v); } -qint32 Object::integer() const -{ - return object_integer_get(d); -} -void Object::setInteger(qint32 v) { - object_integer_set(d, v); -} -quint32 Object::uinteger() const -{ - return object_uinteger_get(d); -} -void Object::setUinteger(uint v) { - object_uinteger_set(d, v); -} -quint64 Object::u64() const -{ - return object_u64_get(d); -} -void Object::setU64(quint64 v) { - object_u64_set(d, v); -} -QString Object::string() const -{ - QString v; - object_string_get(d, &v, set_qstring); - return v; -} -void Object::setString(const QString& v) { - object_string_set(d, v); -} -QString Object::optionalString() const -{ - QString v; - object_optional_string_get(d, &v, set_qstring); - return v; -} -void Object::setOptionalString(const QString& v) { - if (v.isNull()) { - object_optional_string_set_none(d); - } else { - object_optional_string_set(d, v); - } -} QByteArray Object::bytearray() const { QByteArray v; @@ -151,6 +108,13 @@ QByteArray Object::bytearray() const void Object::setBytearray(const QByteArray& v) { object_bytearray_set(d, v); } +qint32 Object::integer() const +{ + return object_integer_get(d); +} +void Object::setInteger(qint32 v) { + object_integer_set(d, v); +} QByteArray Object::optionalBytearray() const { QByteArray v; @@ -164,3 +128,39 @@ void Object::setOptionalBytearray(const QByteArray& v) { object_optional_bytearray_set(d, v); } } +QString Object::optionalString() const +{ + QString v; + object_optional_string_get(d, &v, set_qstring); + return v; +} +void Object::setOptionalString(const QString& v) { + if (v.isNull()) { + object_optional_string_set_none(d); + } else { + object_optional_string_set(d, v); + } +} +QString Object::string() const +{ + QString v; + object_string_get(d, &v, set_qstring); + return v; +} +void Object::setString(const QString& v) { + object_string_set(d, v); +} +quint64 Object::u64() const +{ + return object_u64_get(d); +} +void Object::setU64(quint64 v) { + object_u64_set(d, v); +} +quint32 Object::uinteger() const +{ + return object_uinteger_get(d); +} +void Object::setUinteger(uint v) { + object_uinteger_set(d, v); +} diff --git a/tests/test_object_types_rust.h b/tests/test_object_types_rust.h index 84646de..a6ad932 100644 --- a/tests/test_object_types_rust.h +++ b/tests/test_object_types_rust.h @@ -13,49 +13,49 @@ public: private: Private * const d; Q_PROPERTY(bool boolean READ boolean WRITE setBoolean NOTIFY booleanChanged FINAL) - Q_PROPERTY(qint32 integer READ integer WRITE setInteger NOTIFY integerChanged FINAL) - Q_PROPERTY(quint32 uinteger READ uinteger WRITE setUinteger NOTIFY uintegerChanged FINAL) - Q_PROPERTY(quint64 u64 READ u64 WRITE setU64 NOTIFY u64Changed FINAL) - Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged FINAL) - Q_PROPERTY(QString optionalString READ optionalString WRITE setOptionalString NOTIFY optionalStringChanged FINAL) Q_PROPERTY(QByteArray bytearray READ bytearray WRITE setBytearray NOTIFY bytearrayChanged FINAL) + Q_PROPERTY(qint32 integer READ integer WRITE setInteger NOTIFY integerChanged FINAL) Q_PROPERTY(QByteArray optionalBytearray READ optionalBytearray WRITE setOptionalBytearray NOTIFY optionalBytearrayChanged FINAL) + Q_PROPERTY(QString optionalString READ optionalString WRITE setOptionalString NOTIFY optionalStringChanged FINAL) + 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) public: explicit Object(QObject *parent = nullptr); ~Object(); bool boolean() const; void setBoolean(bool v); - qint32 integer() const; - void setInteger(qint32 v); - quint32 uinteger() const; - void setUinteger(uint v); - quint64 u64() const; - void setU64(quint64 v); - QString string() const; - void setString(const QString& v); - QString optionalString() const; - void setOptionalString(const QString& v); QByteArray bytearray() const; void setBytearray(const QByteArray& v); + qint32 integer() const; + void setInteger(qint32 v); QByteArray optionalBytearray() const; void setOptionalBytearray(const QByteArray& v); + QString optionalString() const; + void setOptionalString(const QString& v); + QString string() const; + void setString(const QString& v); + quint64 u64() const; + void setU64(quint64 v); + quint32 uinteger() const; + void setUinteger(uint v); signals: void booleanChanged(); - void integerChanged(); - void uintegerChanged(); - void u64Changed(); - void stringChanged(); - void optionalStringChanged(); void bytearrayChanged(); + void integerChanged(); void optionalBytearrayChanged(); + void optionalStringChanged(); + void stringChanged(); + void u64Changed(); + void uintegerChanged(); private: bool m_boolean; - qint32 m_integer; - quint32 m_uinteger; - quint64 m_u64; - QString m_string; - QString m_optionalString; 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 diff --git a/tests/test_tree.json b/tests/test_tree.json index 4e47c6a..a83c486 100644 --- a/tests/test_tree.json +++ b/tests/test_tree.json @@ -6,18 +6,16 @@ "implementationModule": "implementation", "typesModule": "types" }, - "objects": [{ - "name": "Persons", - "type": "UniformTree", - "roles": [{ - "name": "userName", - "value": "Qt::DisplayRole", - "type": "QString" - }, { - "name": "userName", - "value": "Qt::EditRole", - "type": "QString", - "write": true - }] - }] + "objects": { + "Persons": { + "type": "UniformTree", + "itemProperties": { + "userName": { + "type": "QString", + "write": true, + "roles": [ [ "display", "edit" ] ] + } + } + } + } } diff --git a/tests/test_tree_rust.cpp b/tests/test_tree_rust.cpp index 40daaee..05be20d 100644 --- a/tests/test_tree_rust.cpp +++ b/tests/test_tree_rust.cpp @@ -183,11 +183,9 @@ QVariant Persons::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case Qt::DisplayRole: - persons_data_user_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case Qt::EditRole: + case 256: + case 0: + case 2: persons_data_user_name(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; @@ -197,15 +195,15 @@ QVariant Persons::data(const QModelIndex &index, int role) const return v; } QHash Persons::roleNames() const { - QHash names; - names.insert(Qt::DisplayRole, "userName"); + QHash names = QAbstractItemModel::roleNames(); + names.insert(256, "userName"); return names; } bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; if (index.column() == 0) { - if (role == Qt::EditRole) { + if (role == 256 || role == 0 || role == 2) { set = persons_set_data_user_name(d, index.row(), index.internalId(), value.value()); } }