Warning, /sdk/rust-qt-binding-generator/src/cpp.rs is written in an unsupported language. File is not indexed.
0001 //! `cpp` is the module that generates the cpp code for the bindings 0002 0003 use configuration::*; 0004 use configuration_private::*; 0005 use std::io::{Result, Write}; 0006 use util::{snake_case, write_if_different}; 0007 0008 fn property_type(p: &ItemProperty) -> String { 0009 if p.optional && !p.item_property_type.is_complex() { 0010 return "QVariant".into(); 0011 } 0012 p.type_name().to_string() 0013 } 0014 0015 fn upper_initial(name: &str) -> String { 0016 format!("{}{}", &name[..1].to_uppercase(), &name[1..]) 0017 } 0018 0019 fn lower_initial(name: &str) -> String { 0020 format!("{}{}", &name[..1].to_lowercase(), &name[1..]) 0021 } 0022 0023 fn write_property(name: &str) -> String { 0024 format!("WRITE set{} ", upper_initial(name)) 0025 } 0026 0027 fn base_type(o: &Object) -> &str { 0028 if o.object_type != ObjectType::Object { 0029 return "QAbstractItemModel"; 0030 } 0031 "QObject" 0032 } 0033 0034 fn model_is_writable(o: &Object) -> bool { 0035 let mut write = false; 0036 for p in o.item_properties.values() { 0037 write |= p.write; 0038 } 0039 write 0040 } 0041 0042 fn write_header_item_model(h: &mut Vec<u8>, o: &Object) -> Result<()> { 0043 writeln!( 0044 h, 0045 " 0046 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0047 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 0048 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0049 QModelIndex parent(const QModelIndex &index) const override; 0050 bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; 0051 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0052 bool canFetchMore(const QModelIndex &parent) const override; 0053 void fetchMore(const QModelIndex &parent) override; 0054 Qt::ItemFlags flags(const QModelIndex &index) const override; 0055 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; 0056 int role(const char* name) const; 0057 QHash<int, QByteArray> roleNames() const override; 0058 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 0059 bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; 0060 Q_INVOKABLE bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; 0061 Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;" 0062 )?; 0063 if model_is_writable(o) { 0064 writeln!( 0065 h, 0066 " bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;" 0067 )?; 0068 } 0069 for (name, ip) in &o.item_properties { 0070 let r = property_type(ip); 0071 let rw = if r == "QVariant" || ip.item_property_type.is_complex() { 0072 format!("const {}&", r) 0073 } else { 0074 r.clone() 0075 }; 0076 if o.object_type == ObjectType::List { 0077 writeln!(h, " Q_INVOKABLE {} {}(int row) const;", r, name)?; 0078 if ip.write { 0079 writeln!( 0080 h, 0081 " Q_INVOKABLE bool set{}(int row, {} value);", 0082 upper_initial(name), 0083 rw 0084 )?; 0085 } 0086 } else { 0087 writeln!( 0088 h, 0089 " Q_INVOKABLE {} {}(const QModelIndex& index) const;", 0090 r, name 0091 )?; 0092 if ip.write { 0093 writeln!( 0094 h, 0095 " Q_INVOKABLE bool set{}(const QModelIndex& index, {} value);", 0096 upper_initial(name), 0097 rw 0098 )?; 0099 } 0100 } 0101 } 0102 writeln!( 0103 h, 0104 " 0105 Q_SIGNALS: 0106 // new data is ready to be made available to the model with fetchMore() 0107 void newDataReady(const QModelIndex &parent) const; 0108 private: 0109 QHash<QPair<int,Qt::ItemDataRole>, QVariant> m_headerData; 0110 void initHeaderData(); 0111 void updatePersistentIndexes();" 0112 )?; 0113 Ok(()) 0114 } 0115 0116 fn write_header_object(h: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> { 0117 writeln!( 0118 h, 0119 " 0120 class {} : public {} 0121 {{ 0122 Q_OBJECT", 0123 o.name, 0124 base_type(o) 0125 )?; 0126 for object in conf.objects.values() { 0127 if object.contains_object() && o.name != object.name { 0128 writeln!(h, " friend class {};", object.name)?; 0129 } 0130 } 0131 writeln!( 0132 h, 0133 "public: 0134 class Private; 0135 private:" 0136 )?; 0137 for (name, p) in &o.properties { 0138 if p.is_object() { 0139 writeln!(h, " {}* const m_{};", p.type_name(), name)?; 0140 } 0141 } 0142 writeln!( 0143 h, 0144 " Private * m_d; 0145 bool m_ownsPrivate;" 0146 )?; 0147 for (name, p) in &o.properties { 0148 let mut t = if p.optional && !p.is_complex() { 0149 "QVariant" 0150 } else { 0151 p.type_name() 0152 } 0153 .to_string(); 0154 if p.is_object() { 0155 t.push('*'); 0156 } 0157 writeln!( 0158 h, 0159 " Q_PROPERTY({0} {1} READ {1} {2}NOTIFY {1}Changed FINAL)", 0160 t, 0161 name, 0162 if p.write { 0163 write_property(name) 0164 } else { 0165 String::new() 0166 } 0167 )?; 0168 } 0169 writeln!( 0170 h, 0171 " explicit {}(bool owned, QObject *parent); 0172 public: 0173 explicit {0}(QObject *parent = nullptr); 0174 ~{0}();", 0175 o.name 0176 )?; 0177 for (name, p) in &o.properties { 0178 if p.is_object() { 0179 writeln!(h, " const {}* {}() const;", p.type_name(), name)?; 0180 writeln!(h, " {}* {}();", p.type_name(), name)?; 0181 } else { 0182 let (t, t2) = if p.optional && !p.is_complex() { 0183 ("QVariant", "const QVariant&") 0184 } else { 0185 (p.type_name(), p.property_type.cpp_set_type()) 0186 }; 0187 writeln!(h, " {} {}() const;", t, name)?; 0188 if p.write { 0189 writeln!(h, " void set{}({} v);", upper_initial(name), t2)?; 0190 } 0191 } 0192 } 0193 for (name, f) in &o.functions { 0194 write!(h, " Q_INVOKABLE {} {}(", f.return_type.name(), name)?; 0195 for (i, a) in f.arguments.iter().enumerate() { 0196 if i != 0 { 0197 write!(h, ", ")?; 0198 } 0199 write!(h, "{} {}", a.argument_type.cpp_set_type(), a.name)?; 0200 } 0201 writeln!(h, "){};", if f.mutable { "" } else { " const" })?; 0202 } 0203 if base_type(o) == "QAbstractItemModel" { 0204 write_header_item_model(h, o)?; 0205 } 0206 writeln!(h, "Q_SIGNALS:")?; 0207 for name in o.properties.keys() { 0208 writeln!(h, " void {}Changed();", name)?; 0209 } 0210 writeln!(h, "}};")?; 0211 Ok(()) 0212 } 0213 0214 fn is_column_write(o: &Object, col: usize) -> bool { 0215 o.item_properties 0216 .values() 0217 .any(|ip| ip.write && (col == 0 || (ip.roles.len() > col && !ip.roles[col].is_empty()))) 0218 } 0219 0220 fn write_function_c_decl( 0221 w: &mut Vec<u8>, 0222 (name, f): (&String, &Function), 0223 lcname: &str, 0224 o: &Object, 0225 ) -> Result<()> { 0226 let lc = snake_case(name); 0227 write!(w, " ")?; 0228 if f.return_type.is_complex() { 0229 write!(w, "void")?; 0230 } else { 0231 write!(w, "{}", f.type_name())?; 0232 } 0233 let name = format!("{}_{}", lcname, lc); 0234 write!( 0235 w, 0236 " {}({}{}::Private*", 0237 name, 0238 if f.mutable { "" } else { "const " }, 0239 o.name 0240 )?; 0241 0242 // write all the input arguments, for QString and QByteArray, write 0243 // pointers to their content and the length 0244 for a in &f.arguments { 0245 if a.type_name() == "QString" { 0246 write!(w, ", const ushort*, int")?; 0247 } else if a.type_name() == "QByteArray" { 0248 write!(w, ", const char*, int")?; 0249 } else { 0250 write!(w, ", {}", a.type_name())?; 0251 } 0252 } 0253 // If the return type is QString or QByteArray, append a pointer to the 0254 // variable that will be set to the argument list. Also add a setter 0255 // function. 0256 if f.return_type.name() == "QString" { 0257 write!(w, ", QString*, qstring_set")?; 0258 } else if f.return_type.name() == "QByteArray" { 0259 write!(w, ", QByteArray*, qbytearray_set")?; 0260 } 0261 writeln!(w, ");")?; 0262 Ok(()) 0263 } 0264 0265 fn write_object_c_decl(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> { 0266 let lcname = snake_case(&o.name); 0267 write!(w, " {}::Private* {}_new(", o.name, lcname)?; 0268 constructor_args_decl(w, o, conf)?; 0269 writeln!(w, ");")?; 0270 writeln!(w, " void {}_free({}::Private*);", lcname, o.name)?; 0271 for (name, p) in &o.properties { 0272 let base = format!("{}_{}", lcname, snake_case(name)); 0273 if p.is_object() { 0274 writeln!( 0275 w, 0276 " {}::Private* {}_get(const {}::Private*);", 0277 p.type_name(), 0278 base, 0279 o.name 0280 )?; 0281 } else if p.is_complex() { 0282 writeln!( 0283 w, 0284 " void {}_get(const {}::Private*, {});", 0285 base, 0286 o.name, 0287 p.c_get_type() 0288 )?; 0289 } else if p.optional { 0290 writeln!( 0291 w, 0292 " option_{} {}_get(const {}::Private*);", 0293 p.type_name(), 0294 base, 0295 o.name 0296 )?; 0297 } else { 0298 writeln!( 0299 w, 0300 " {} {}_get(const {}::Private*);", 0301 p.type_name(), 0302 base, 0303 o.name 0304 )?; 0305 } 0306 if p.write { 0307 let mut t = p.property_type.c_set_type(); 0308 if t == "qstring_t" { 0309 t = "const ushort *str, int len"; 0310 } else if t == "qbytearray_t" { 0311 t = "const char* bytes, int len"; 0312 } 0313 writeln!(w, " void {}_set({}::Private*, {});", base, o.name, t)?; 0314 if p.optional { 0315 writeln!(w, " void {}_set_none({}::Private*);", base, o.name)?; 0316 } 0317 } 0318 } 0319 for f in &o.functions { 0320 write_function_c_decl(w, f, &lcname, o)?; 0321 } 0322 Ok(()) 0323 } 0324 0325 fn initialize_members_zero(w: &mut Vec<u8>, o: &Object) -> Result<()> { 0326 for (name, p) in &o.properties { 0327 if p.is_object() { 0328 writeln!(w, " m_{}(new {}(false, this)),", name, p.type_name())?; 0329 } 0330 } 0331 Ok(()) 0332 } 0333 0334 fn initialize_members(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) -> Result<()> { 0335 for (name, p) in &o.properties { 0336 if let Type::Object(object) = &p.property_type { 0337 writeln!( 0338 w, 0339 " {}m_{}->m_d = {}_{}_get({0}m_d);", 0340 prefix, 0341 name, 0342 snake_case(&o.name), 0343 snake_case(name) 0344 )?; 0345 initialize_members(w, &format!("m_{}->", name), object, conf)?; 0346 } 0347 } 0348 Ok(()) 0349 } 0350 0351 fn connect(w: &mut Vec<u8>, d: &str, o: &Object, conf: &Config) -> Result<()> { 0352 for (name, p) in &o.properties { 0353 if let Type::Object(object) = &p.property_type { 0354 connect(w, &format!("{}->m_{}", d, name), object, conf)?; 0355 } 0356 } 0357 if o.object_type != ObjectType::Object { 0358 writeln!( 0359 w, 0360 " connect({}, &{1}::newDataReady, {0}, [this](const QModelIndex& i) {{ 0361 {0}->fetchMore(i); 0362 }}, Qt::QueuedConnection);", 0363 d, o.name 0364 )?; 0365 } 0366 Ok(()) 0367 } 0368 0369 fn write_cpp_object_properties(w: &mut Vec<u8>, o: &Object, lcname: &str) -> Result<()> { 0370 for (name, p) in &o.properties { 0371 let base = format!("{}_{}", lcname, snake_case(name)); 0372 if p.is_object() { 0373 writeln!( 0374 w, 0375 "const {}* {}::{}() const 0376 {{ 0377 return m_{2}; 0378 }} 0379 {0}* {1}::{2}() 0380 {{ 0381 return m_{2}; 0382 }}", 0383 p.type_name(), 0384 o.name, 0385 name 0386 )?; 0387 } else if p.is_complex() { 0388 writeln!( 0389 w, 0390 "{} {}::{}() const 0391 {{ 0392 {0} v; 0393 {3}_get(m_d, &v, set_{4}); 0394 return v; 0395 }}", 0396 p.type_name(), 0397 o.name, 0398 name, 0399 base, 0400 p.type_name().to_lowercase() 0401 )?; 0402 } else if p.optional { 0403 writeln!( 0404 w, 0405 "QVariant {}::{}() const 0406 {{ 0407 QVariant v; 0408 auto r = {2}_get(m_d); 0409 if (r.some) {{ 0410 v.setValue(r.value); 0411 }} 0412 return r; 0413 }}", 0414 o.name, name, base 0415 )?; 0416 } else { 0417 writeln!( 0418 w, 0419 "{} {}::{}() const 0420 {{ 0421 return {}_get(m_d); 0422 }}", 0423 p.type_name(), 0424 o.name, 0425 name, 0426 base 0427 )?; 0428 } 0429 if p.write { 0430 let t = if p.optional && !p.is_complex() { 0431 "const QVariant&" 0432 } else { 0433 p.property_type.cpp_set_type() 0434 }; 0435 writeln!(w, "void {}::set{}({} v) {{", o.name, upper_initial(name), t)?; 0436 if p.optional { 0437 if p.is_complex() { 0438 writeln!(w, " if (v.isNull()) {{")?; 0439 } else { 0440 writeln!( 0441 w, 0442 " if (v.isNull() || !v.canConvert<{}>()) {{", 0443 p.type_name() 0444 )?; 0445 } 0446 writeln!(w, " {}_set_none(m_d);", base)?; 0447 writeln!(w, " }} else {{")?; 0448 if p.type_name() == "QString" { 0449 writeln!( 0450 w, 0451 " {}_set(m_d, reinterpret_cast<const ushort*>(v.data()), v.size());", 0452 base 0453 )?; 0454 } else if p.type_name() == "QByteArray" { 0455 writeln!(w, " {}_set(m_d, v.data(), v.size());", base)?; 0456 } else if p.optional { 0457 writeln!( 0458 w, 0459 " {}_set(m_d, v.value<{}>());", 0460 base, 0461 p.type_name() 0462 )?; 0463 } else { 0464 writeln!(w, " {}_set(m_d, v);", base)?; 0465 } 0466 writeln!(w, " }}")?; 0467 } else if p.type_name() == "QString" { 0468 writeln!( 0469 w, 0470 " {}_set(m_d, reinterpret_cast<const ushort*>(v.data()), v.size());", 0471 base 0472 )?; 0473 } else if p.type_name() == "QByteArray" { 0474 writeln!(w, " {}_set(m_d, v.data(), v.size());", base)?; 0475 } else { 0476 writeln!(w, " {}_set(m_d, v);", base)?; 0477 } 0478 writeln!(w, "}}")?; 0479 } 0480 } 0481 Ok(()) 0482 } 0483 0484 fn write_cpp_object(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> { 0485 let lcname = snake_case(&o.name); 0486 writeln!( 0487 w, 0488 "{}::{0}(bool /*owned*/, QObject *parent): 0489 {}(parent),", 0490 o.name, 0491 base_type(o) 0492 )?; 0493 initialize_members_zero(w, o)?; 0494 writeln!( 0495 w, 0496 " m_d(nullptr), 0497 m_ownsPrivate(false) 0498 {{" 0499 )?; 0500 if o.object_type != ObjectType::Object { 0501 writeln!(w, " initHeaderData();")?; 0502 } 0503 writeln!( 0504 w, 0505 "}} 0506 0507 {}::{0}(QObject *parent): 0508 {}(parent),", 0509 o.name, 0510 base_type(o) 0511 )?; 0512 initialize_members_zero(w, o)?; 0513 write!(w, " m_d({}_new(this", lcname)?; 0514 constructor_args(w, "", o, conf)?; 0515 writeln!( 0516 w, 0517 ")), 0518 m_ownsPrivate(true) 0519 {{" 0520 )?; 0521 initialize_members(w, "", o, conf)?; 0522 connect(w, "this", o, conf)?; 0523 if o.object_type != ObjectType::Object { 0524 writeln!(w, " initHeaderData();")?; 0525 } 0526 writeln!( 0527 w, 0528 "}} 0529 0530 {}::~{0}() {{ 0531 if (m_ownsPrivate) {{ 0532 {1}_free(m_d); 0533 }} 0534 }}", 0535 o.name, lcname 0536 )?; 0537 if o.object_type != ObjectType::Object { 0538 writeln!(w, "void {}::initHeaderData() {{", o.name)?; 0539 for col in 0..o.column_count() { 0540 for (name, ip) in &o.item_properties { 0541 let empty = Vec::new(); 0542 let roles = ip.roles.get(col).unwrap_or(&empty); 0543 if roles.contains(&"display".to_string()) { 0544 writeln!( 0545 w, 0546 " m_headerData.insert(qMakePair({}, Qt::DisplayRole), QVariant(\"{}\"));", 0547 col, 0548 name 0549 )?; 0550 } 0551 } 0552 } 0553 writeln!(w, "}}")?; 0554 } 0555 0556 write_cpp_object_properties(w, o, &lcname)?; 0557 0558 for (name, f) in &o.functions { 0559 let base = format!("{}_{}", lcname, snake_case(name)); 0560 write!(w, "{} {}::{}(", f.type_name(), o.name, name)?; 0561 for (i, a) in f.arguments.iter().enumerate() { 0562 write!( 0563 w, 0564 "{} {}{}", 0565 a.argument_type.cpp_set_type(), 0566 a.name, 0567 if i + 1 < f.arguments.len() { ", " } else { "" } 0568 )?; 0569 } 0570 writeln!(w, "){}\n{{", if f.mutable { "" } else { " const" })?; 0571 let mut arg_list = String::new(); 0572 for a in &f.arguments { 0573 if a.type_name() == "QString" { 0574 arg_list.push_str(&format!(", {}.utf16(), {0}.size()", a.name)); 0575 } else if a.type_name() == "QByteArray" { 0576 arg_list.push_str(&format!(", {}.data(), {0}.size()", a.name)); 0577 } else { 0578 arg_list.push_str(&format!(", {}", a.name)); 0579 } 0580 } 0581 if f.return_type.name() == "QString" { 0582 writeln!( 0583 w, 0584 " {} s; 0585 {}(m_d{}, &s, set_qstring); 0586 return s;", 0587 f.type_name(), 0588 base, 0589 arg_list 0590 )?; 0591 } else if f.return_type.name() == "QByteArray" { 0592 writeln!( 0593 w, 0594 " {} s; 0595 {}(m_d{}, &s, set_qbytearray); 0596 return s;", 0597 f.type_name(), 0598 base, 0599 arg_list 0600 )?; 0601 } else { 0602 writeln!(w, " return {}(m_d{});", base, arg_list)?; 0603 } 0604 writeln!(w, "}}")?; 0605 } 0606 Ok(()) 0607 } 0608 0609 fn role_name(role: &str) -> String { 0610 match role { 0611 "display" => "DisplayRole".into(), 0612 "decoration" => "DecorationRole".into(), 0613 "edit" => "EditRole".into(), 0614 "toolTip" => "ToolTipRole".into(), 0615 "statustip" => "StatusTipRole".into(), 0616 "whatsthis" => "WhatsThisRole".into(), 0617 _ => panic!("Unknown role {}", role), 0618 } 0619 } 0620 0621 fn write_model_getter_setter( 0622 w: &mut Vec<u8>, 0623 index: &str, 0624 name: &str, 0625 ip: &ItemProperty, 0626 o: &Object, 0627 ) -> Result<()> { 0628 let lcname = snake_case(&o.name); 0629 let mut idx = index; 0630 0631 // getter 0632 let mut r = property_type(ip); 0633 if o.object_type == ObjectType::List { 0634 idx = ", row"; 0635 writeln!(w, "{} {}::{}(int row) const\n{{", r, o.name, name)?; 0636 } else { 0637 writeln!( 0638 w, 0639 "{} {}::{}(const QModelIndex& index) const\n{{", 0640 r, o.name, name 0641 )?; 0642 } 0643 if ip.type_name() == "QString" { 0644 writeln!(w, " QString s;")?; 0645 writeln!( 0646 w, 0647 " {}_data_{}(m_d{}, &s, set_{});", 0648 lcname, 0649 snake_case(name), 0650 idx, 0651 ip.type_name().to_lowercase() 0652 )?; 0653 writeln!(w, " return s;")?; 0654 } else if ip.type_name() == "QByteArray" { 0655 writeln!(w, " QByteArray b;")?; 0656 writeln!( 0657 w, 0658 " {}_data_{}(m_d{}, &b, set_{});", 0659 lcname, 0660 snake_case(name), 0661 idx, 0662 ip.type_name().to_lowercase() 0663 )?; 0664 writeln!(w, " return b;")?; 0665 } else if ip.optional { 0666 writeln!(w, " QVariant v;")?; 0667 writeln!( 0668 w, 0669 " v = {}_data_{}(m_d{});", 0670 lcname, 0671 snake_case(name), 0672 idx 0673 )?; 0674 writeln!(w, " return v;")?; 0675 } else { 0676 writeln!( 0677 w, 0678 " return {}_data_{}(m_d{});", 0679 lcname, 0680 snake_case(name), 0681 idx 0682 )?; 0683 } 0684 writeln!(w, "}}\n")?; 0685 if !ip.write { 0686 return Ok(()); 0687 } 0688 0689 //setter 0690 if r == "QVariant" || ip.is_complex() { 0691 r = format!("const {}&", r); 0692 } 0693 if o.object_type == ObjectType::List { 0694 idx = ", row"; 0695 writeln!( 0696 w, 0697 "bool {}::set{}(int row, {} value)\n{{", 0698 o.name, 0699 upper_initial(name), 0700 r 0701 )?; 0702 } else { 0703 writeln!( 0704 w, 0705 "bool {}::set{}(const QModelIndex& index, {} value)\n{{", 0706 o.name, 0707 upper_initial(name), 0708 r 0709 )?; 0710 } 0711 writeln!(w, " bool set = false;")?; 0712 if ip.optional { 0713 let mut test = "value.isNull()".to_string(); 0714 if !ip.is_complex() { 0715 test += " || !value.isValid()"; 0716 } 0717 writeln!(w, " if ({}) {{", test)?; 0718 writeln!( 0719 w, 0720 " set = {}_set_data_{}_none(m_d{});", 0721 lcname, 0722 snake_case(name), 0723 idx 0724 )?; 0725 writeln!(w, " }} else {{")?; 0726 } 0727 if ip.optional && !ip.is_complex() { 0728 writeln!( 0729 w, 0730 " if (!value.canConvert(qMetaTypeId<{}>())) {{ 0731 return false; 0732 }}", 0733 ip.type_name() 0734 )?; 0735 writeln!( 0736 w, 0737 " set = {}_set_data_{}(m_d{}, value.value<{}>());", 0738 lcname, 0739 snake_case(name), 0740 idx, 0741 ip.type_name() 0742 )?; 0743 } else { 0744 let mut val = "value"; 0745 if ip.is_complex() { 0746 if ip.type_name() == "QString" { 0747 val = "value.utf16(), value.length()"; 0748 } else { 0749 val = "value.data(), value.length()"; 0750 } 0751 } 0752 writeln!( 0753 w, 0754 " set = {}_set_data_{}(m_d{}, {});", 0755 lcname, 0756 snake_case(name), 0757 idx, 0758 val 0759 )?; 0760 } 0761 if ip.optional { 0762 writeln!(w, " }}")?; 0763 } 0764 if o.object_type == ObjectType::List { 0765 writeln!( 0766 w, 0767 " if (set) {{ 0768 QModelIndex index = createIndex(row, 0, row); 0769 Q_EMIT dataChanged(index, index); 0770 }} 0771 return set; 0772 }} 0773 " 0774 )?; 0775 } else { 0776 writeln!( 0777 w, 0778 " if (set) {{ 0779 Q_EMIT dataChanged(index, index); 0780 }} 0781 return set; 0782 }} 0783 " 0784 )?; 0785 } 0786 Ok(()) 0787 } 0788 0789 fn write_cpp_model(w: &mut Vec<u8>, o: &Object) -> Result<()> { 0790 let lcname = snake_case(&o.name); 0791 let (index_decl, index) = if o.object_type == ObjectType::Tree { 0792 (", quintptr", ", index.internalId()") 0793 } else { 0794 (", int", ", index.row()") 0795 }; 0796 writeln!(w, "extern \"C\" {{")?; 0797 0798 for (name, ip) in &o.item_properties { 0799 if ip.is_complex() { 0800 writeln!( 0801 w, 0802 " void {}_data_{}(const {}::Private*{}, {});", 0803 lcname, 0804 snake_case(name), 0805 o.name, 0806 index_decl, 0807 ip.c_get_type() 0808 )?; 0809 } else { 0810 writeln!( 0811 w, 0812 " {} {}_data_{}(const {}::Private*{});", 0813 ip.cpp_set_type(), 0814 lcname, 0815 snake_case(name), 0816 o.name, 0817 index_decl 0818 )?; 0819 } 0820 if ip.write { 0821 let a = format!(" bool {}_set_data_{}", lcname, snake_case(name)); 0822 let b = format!("({}::Private*{}", o.name, index_decl); 0823 if ip.type_name() == "QString" { 0824 writeln!(w, "{}{}, const ushort* s, int len);", a, b)?; 0825 } else if ip.type_name() == "QByteArray" { 0826 writeln!(w, "{}{}, const char* s, int len);", a, b)?; 0827 } else { 0828 writeln!(w, "{}{}, {});", a, b, ip.c_set_type())?; 0829 } 0830 if ip.optional { 0831 writeln!(w, "{}_none{});", a, b)?; 0832 } 0833 } 0834 } 0835 writeln!( 0836 w, 0837 " void {}_sort({}::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder);", 0838 lcname, 0839 o.name 0840 )?; 0841 if o.object_type == ObjectType::List { 0842 writeln!( 0843 w, 0844 " 0845 int {1}_row_count(const {0}::Private*); 0846 bool {1}_insert_rows({0}::Private*, int, int); 0847 bool {1}_remove_rows({0}::Private*, int, int); 0848 bool {1}_can_fetch_more(const {0}::Private*); 0849 void {1}_fetch_more({0}::Private*); 0850 }} 0851 int {0}::columnCount(const QModelIndex &parent) const 0852 {{ 0853 return (parent.isValid()) ? 0 : {2}; 0854 }} 0855 0856 bool {0}::hasChildren(const QModelIndex &parent) const 0857 {{ 0858 return rowCount(parent) > 0; 0859 }} 0860 0861 int {0}::rowCount(const QModelIndex &parent) const 0862 {{ 0863 return (parent.isValid()) ? 0 : {1}_row_count(m_d); 0864 }} 0865 0866 bool {0}::insertRows(int row, int count, const QModelIndex &) 0867 {{ 0868 return {1}_insert_rows(m_d, row, count); 0869 }} 0870 0871 bool {0}::removeRows(int row, int count, const QModelIndex &) 0872 {{ 0873 return {1}_remove_rows(m_d, row, count); 0874 }} 0875 0876 QModelIndex {0}::index(int row, int column, const QModelIndex &parent) const 0877 {{ 0878 if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < {2}) {{ 0879 return createIndex(row, column, (quintptr)row); 0880 }} 0881 return QModelIndex(); 0882 }} 0883 0884 QModelIndex {0}::parent(const QModelIndex &) const 0885 {{ 0886 return QModelIndex(); 0887 }} 0888 0889 bool {0}::canFetchMore(const QModelIndex &parent) const 0890 {{ 0891 return (parent.isValid()) ? 0 : {1}_can_fetch_more(m_d); 0892 }} 0893 0894 void {0}::fetchMore(const QModelIndex &parent) 0895 {{ 0896 if (!parent.isValid()) {{ 0897 {1}_fetch_more(m_d); 0898 }} 0899 }} 0900 void {0}::updatePersistentIndexes() {{}}", 0901 o.name, 0902 lcname, 0903 o.column_count() 0904 )?; 0905 } else { 0906 writeln!( 0907 w, 0908 " 0909 int {1}_row_count(const {0}::Private*, option_quintptr); 0910 bool {1}_can_fetch_more(const {0}::Private*, option_quintptr); 0911 void {1}_fetch_more({0}::Private*, option_quintptr); 0912 quintptr {1}_index(const {0}::Private*, option_quintptr, int); 0913 qmodelindex_t {1}_parent(const {0}::Private*, quintptr); 0914 int {1}_row(const {0}::Private*, quintptr); 0915 option_quintptr {1}_check_row(const {0}::Private*, quintptr, int); 0916 }} 0917 int {0}::columnCount(const QModelIndex &) const 0918 {{ 0919 return {2}; 0920 }} 0921 0922 bool {0}::hasChildren(const QModelIndex &parent) const 0923 {{ 0924 return rowCount(parent) > 0; 0925 }} 0926 0927 int {0}::rowCount(const QModelIndex &parent) const 0928 {{ 0929 if (parent.isValid() && parent.column() != 0) {{ 0930 return 0; 0931 }} 0932 const option_quintptr rust_parent = {{ 0933 parent.internalId(), 0934 parent.isValid() 0935 }}; 0936 return {1}_row_count(m_d, rust_parent); 0937 }} 0938 0939 bool {0}::insertRows(int, int, const QModelIndex &) 0940 {{ 0941 return false; // not supported yet 0942 }} 0943 0944 bool {0}::removeRows(int, int, const QModelIndex &) 0945 {{ 0946 return false; // not supported yet 0947 }} 0948 0949 QModelIndex {0}::index(int row, int column, const QModelIndex &parent) const 0950 {{ 0951 if (row < 0 || column < 0 || column >= {2}) {{ 0952 return QModelIndex(); 0953 }} 0954 if (parent.isValid() && parent.column() != 0) {{ 0955 return QModelIndex(); 0956 }} 0957 if (row >= rowCount(parent)) {{ 0958 return QModelIndex(); 0959 }} 0960 const option_quintptr rust_parent = {{ 0961 parent.internalId(), 0962 parent.isValid() 0963 }}; 0964 const quintptr id = {1}_index(m_d, rust_parent, row); 0965 return createIndex(row, column, id); 0966 }} 0967 0968 QModelIndex {0}::parent(const QModelIndex &index) const 0969 {{ 0970 if (!index.isValid()) {{ 0971 return QModelIndex(); 0972 }} 0973 const qmodelindex_t parent = {1}_parent(m_d, index.internalId()); 0974 return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex(); 0975 }} 0976 0977 bool {0}::canFetchMore(const QModelIndex &parent) const 0978 {{ 0979 if (parent.isValid() && parent.column() != 0) {{ 0980 return false; 0981 }} 0982 const option_quintptr rust_parent = {{ 0983 parent.internalId(), 0984 parent.isValid() 0985 }}; 0986 return {1}_can_fetch_more(m_d, rust_parent); 0987 }} 0988 0989 void {0}::fetchMore(const QModelIndex &parent) 0990 {{ 0991 const option_quintptr rust_parent = {{ 0992 parent.internalId(), 0993 parent.isValid() 0994 }}; 0995 {1}_fetch_more(m_d, rust_parent); 0996 }} 0997 void {0}::updatePersistentIndexes() {{ 0998 const auto from = persistentIndexList(); 0999 auto to = from; 1000 auto len = to.size(); 1001 for (int i = 0; i < len; ++i) {{ 1002 auto index = to.at(i); 1003 auto row = {1}_check_row(m_d, index.internalId(), index.row()); 1004 if (row.some) {{ 1005 to[i] = createIndex(row.value, index.column(), index.internalId()); 1006 }} else {{ 1007 to[i] = QModelIndex(); 1008 }} 1009 }} 1010 changePersistentIndexList(from, to); 1011 }}", 1012 o.name, 1013 lcname, 1014 o.column_count() 1015 )?; 1016 } 1017 writeln!( 1018 w, 1019 " 1020 void {0}::sort(int column, Qt::SortOrder order) 1021 {{ 1022 {1}_sort(m_d, column, order); 1023 }} 1024 Qt::ItemFlags {0}::flags(const QModelIndex &i) const 1025 {{ 1026 auto flags = QAbstractItemModel::flags(i);", 1027 o.name, lcname 1028 )?; 1029 for col in 0..o.column_count() { 1030 if is_column_write(o, col) { 1031 writeln!(w, " if (i.column() == {}) {{", col)?; 1032 writeln!(w, " flags |= Qt::ItemIsEditable;\n }}")?; 1033 } 1034 } 1035 writeln!(w, " return flags;\n}}\n")?; 1036 for ip in &o.item_properties { 1037 write_model_getter_setter(w, index, ip.0, ip.1, o)?; 1038 } 1039 writeln!( 1040 w, 1041 "QVariant {}::data(const QModelIndex &index, int role) const 1042 {{ 1043 Q_ASSERT(rowCount(index.parent()) > index.row()); 1044 switch (index.column()) {{", 1045 o.name 1046 )?; 1047 1048 for col in 0..o.column_count() { 1049 writeln!(w, " case {}:", col)?; 1050 writeln!(w, " switch (role) {{")?; 1051 for (i, (name, ip)) in o.item_properties.iter().enumerate() { 1052 let empty = Vec::new(); 1053 let roles = ip.roles.get(col).unwrap_or(&empty); 1054 if col > 0 && roles.is_empty() { 1055 continue; 1056 } 1057 for role in roles { 1058 writeln!(w, " case Qt::{}:", role_name(role))?; 1059 } 1060 writeln!(w, " case Qt::UserRole + {}:", i)?; 1061 let ii = if o.object_type == ObjectType::List { 1062 ".row()" 1063 } else { 1064 "" 1065 }; 1066 if ip.optional && !ip.is_complex() { 1067 writeln!(w, " return {}(index{});", name, ii)?; 1068 } else if ip.optional { 1069 writeln!( 1070 w, 1071 " return cleanNullQVariant(QVariant::fromValue({}(index{})));", 1072 name, ii 1073 )?; 1074 } else { 1075 writeln!( 1076 w, 1077 " return QVariant::fromValue({}(index{}));", 1078 name, ii 1079 )?; 1080 } 1081 } 1082 writeln!(w, " }}\n break;")?; 1083 } 1084 writeln!( 1085 w, 1086 " }} 1087 return QVariant(); 1088 }} 1089 1090 int {}::role(const char* name) const {{ 1091 auto names = roleNames(); 1092 auto i = names.constBegin(); 1093 while (i != names.constEnd()) {{ 1094 if (i.value() == name) {{ 1095 return i.key(); 1096 }} 1097 ++i; 1098 }} 1099 return -1; 1100 }} 1101 QHash<int, QByteArray> {0}::roleNames() const {{ 1102 QHash<int, QByteArray> names = QAbstractItemModel::roleNames();", 1103 o.name 1104 )?; 1105 for (i, (name, _)) in o.item_properties.iter().enumerate() { 1106 writeln!(w, " names.insert(Qt::UserRole + {}, \"{}\");", i, name)?; 1107 } 1108 writeln!( 1109 w, 1110 " return names; 1111 }} 1112 QVariant {0}::headerData(int section, Qt::Orientation orientation, int role) const 1113 {{ 1114 if (orientation != Qt::Horizontal) {{ 1115 return QVariant(); 1116 }} 1117 return m_headerData.value(qMakePair(section, (Qt::ItemDataRole)role), role == Qt::DisplayRole ?QString::number(section + 1) :QVariant()); 1118 }} 1119 1120 bool {0}::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) 1121 {{ 1122 if (orientation != Qt::Horizontal) {{ 1123 return false; 1124 }} 1125 m_headerData.insert(qMakePair(section, (Qt::ItemDataRole)role), value); 1126 return true; 1127 }} 1128 ", 1129 o.name 1130 )?; 1131 if model_is_writable(o) { 1132 writeln!( 1133 w, 1134 "bool {}::setData(const QModelIndex &index, const QVariant &value, int role)\n{{", 1135 o.name 1136 )?; 1137 for col in 0..o.column_count() { 1138 if !is_column_write(o, col) { 1139 continue; 1140 } 1141 writeln!(w, " if (index.column() == {}) {{", col)?; 1142 for (i, (name, ip)) in o.item_properties.iter().enumerate() { 1143 if !ip.write { 1144 continue; 1145 } 1146 let empty = Vec::new(); 1147 let roles = ip.roles.get(col).unwrap_or(&empty); 1148 if col > 0 && roles.is_empty() { 1149 continue; 1150 } 1151 write!(w, " if (")?; 1152 for role in roles { 1153 write!(w, "role == Qt::{} || ", role_name(role))?; 1154 } 1155 writeln!(w, "role == Qt::UserRole + {}) {{", i)?; 1156 let ii = if o.object_type == ObjectType::List { 1157 ".row()" 1158 } else { 1159 "" 1160 }; 1161 if ip.optional && !ip.is_complex() { 1162 writeln!( 1163 w, 1164 " return set{}(index{}, value);", 1165 upper_initial(name), 1166 ii 1167 )?; 1168 } else { 1169 let pre = if ip.optional { 1170 "!value.isValid() || value.isNull() ||" 1171 } else { 1172 "" 1173 }; 1174 writeln!( 1175 w, 1176 " if ({}value.canConvert(qMetaTypeId<{}>())) {{", 1177 pre, 1178 ip.type_name() 1179 )?; 1180 writeln!( 1181 w, 1182 " return set{}(index{}, value.value<{}>());", 1183 upper_initial(name), 1184 ii, 1185 ip.type_name() 1186 )?; 1187 writeln!(w, " }}")?; 1188 } 1189 writeln!(w, " }}")?; 1190 } 1191 writeln!(w, " }}")?; 1192 } 1193 writeln!(w, " return false;\n}}\n")?; 1194 } 1195 Ok(()) 1196 } 1197 1198 fn constructor_args_decl(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> { 1199 write!(w, "{}*", o.name)?; 1200 for p in o.properties.values() { 1201 if let Type::Object(object) = &p.property_type { 1202 write!(w, ", ")?; 1203 constructor_args_decl(w, object, conf)?; 1204 } else { 1205 write!(w, ", void (*)({}*)", o.name)?; 1206 } 1207 } 1208 if o.object_type == ObjectType::List { 1209 write!( 1210 w, 1211 ", 1212 void (*)(const {}*), 1213 void (*)({0}*), 1214 void (*)({0}*), 1215 void (*)({0}*, quintptr, quintptr), 1216 void (*)({0}*), 1217 void (*)({0}*), 1218 void (*)({0}*, int, int), 1219 void (*)({0}*), 1220 void (*)({0}*, int, int, int), 1221 void (*)({0}*), 1222 void (*)({0}*, int, int), 1223 void (*)({0}*)", 1224 o.name 1225 )?; 1226 } 1227 if o.object_type == ObjectType::Tree { 1228 write!( 1229 w, 1230 ", 1231 void (*)(const {0}*, option_quintptr), 1232 void (*)({0}*), 1233 void (*)({0}*), 1234 void (*)({0}*, quintptr, quintptr), 1235 void (*)({0}*), 1236 void (*)({0}*), 1237 void (*)({0}*, option_quintptr, int, int), 1238 void (*)({0}*), 1239 void (*)({0}*, option_quintptr, int, int, option_quintptr, int), 1240 void (*)({0}*), 1241 void (*)({0}*, option_quintptr, int, int), 1242 void (*)({0}*)", 1243 o.name 1244 )?; 1245 } 1246 Ok(()) 1247 } 1248 1249 fn changed_f(o: &Object, p_name: &str) -> String { 1250 lower_initial(&o.name) + &upper_initial(p_name) + "Changed" 1251 } 1252 1253 fn constructor_args(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) -> Result<()> { 1254 let lcname = snake_case(&o.name); 1255 for (name, p) in &o.properties { 1256 if let Type::Object(object) = &p.property_type { 1257 write!(w, ", {}m_{}", prefix, name)?; 1258 constructor_args(w, &format!("m_{}->", name), object, conf)?; 1259 } else { 1260 write!(w, ",\n {}", changed_f(o, name))?; 1261 } 1262 } 1263 if o.object_type == ObjectType::List { 1264 writeln!( 1265 w, 1266 ", 1267 [](const {0}* o) {{ 1268 Q_EMIT o->newDataReady(QModelIndex()); 1269 }}, 1270 []({0}* o) {{ 1271 Q_EMIT o->layoutAboutToBeChanged(); 1272 }}, 1273 []({0}* o) {{ 1274 o->updatePersistentIndexes(); 1275 Q_EMIT o->layoutChanged(); 1276 }}, 1277 []({0}* o, quintptr first, quintptr last) {{ 1278 o->dataChanged(o->createIndex(first, 0, first), 1279 o->createIndex(last, {1}, last)); 1280 }}, 1281 []({0}* o) {{ 1282 o->beginResetModel(); 1283 }}, 1284 []({0}* o) {{ 1285 o->endResetModel(); 1286 }}, 1287 []({0}* o, int first, int last) {{ 1288 o->beginInsertRows(QModelIndex(), first, last); 1289 }}, 1290 []({0}* o) {{ 1291 o->endInsertRows(); 1292 }}, 1293 []({0}* o, int first, int last, int destination) {{ 1294 o->beginMoveRows(QModelIndex(), first, last, QModelIndex(), destination); 1295 }}, 1296 []({0}* o) {{ 1297 o->endMoveRows(); 1298 }}, 1299 []({0}* o, int first, int last) {{ 1300 o->beginRemoveRows(QModelIndex(), first, last); 1301 }}, 1302 []({0}* o) {{ 1303 o->endRemoveRows(); 1304 }}", 1305 o.name, 1306 o.column_count() - 1 1307 )?; 1308 } 1309 if o.object_type == ObjectType::Tree { 1310 writeln!( 1311 w, 1312 ", 1313 [](const {0}* o, option_quintptr id) {{ 1314 if (id.some) {{ 1315 int row = {1}_row(o->m_d, id.value); 1316 Q_EMIT o->newDataReady(o->createIndex(row, 0, id.value)); 1317 }} else {{ 1318 Q_EMIT o->newDataReady(QModelIndex()); 1319 }} 1320 }}, 1321 []({0}* o) {{ 1322 Q_EMIT o->layoutAboutToBeChanged(); 1323 }}, 1324 []({0}* o) {{ 1325 o->updatePersistentIndexes(); 1326 Q_EMIT o->layoutChanged(); 1327 }}, 1328 []({0}* o, quintptr first, quintptr last) {{ 1329 quintptr frow = {1}_row(o->m_d, first); 1330 quintptr lrow = {1}_row(o->m_d, first); 1331 o->dataChanged(o->createIndex(frow, 0, first), 1332 o->createIndex(lrow, {2}, last)); 1333 }}, 1334 []({0}* o) {{ 1335 o->beginResetModel(); 1336 }}, 1337 []({0}* o) {{ 1338 o->endResetModel(); 1339 }}, 1340 []({0}* o, option_quintptr id, int first, int last) {{ 1341 if (id.some) {{ 1342 int row = {1}_row(o->m_d, id.value); 1343 o->beginInsertRows(o->createIndex(row, 0, id.value), first, last); 1344 }} else {{ 1345 o->beginInsertRows(QModelIndex(), first, last); 1346 }} 1347 }}, 1348 []({0}* o) {{ 1349 o->endInsertRows(); 1350 }}, 1351 []({0}* o, option_quintptr sourceParent, int first, int last, option_quintptr destinationParent, int destination) {{ 1352 QModelIndex s; 1353 if (sourceParent.some) {{ 1354 int row = {1}_row(o->m_d, sourceParent.value); 1355 s = o->createIndex(row, 0, sourceParent.value); 1356 }} 1357 QModelIndex d; 1358 if (destinationParent.some) {{ 1359 int row = {1}_row(o->m_d, destinationParent.value); 1360 d = o->createIndex(row, 0, destinationParent.value); 1361 }} 1362 o->beginMoveRows(s, first, last, d, destination); 1363 }}, 1364 []({0}* o) {{ 1365 o->endMoveRows(); 1366 }}, 1367 []({0}* o, option_quintptr id, int first, int last) {{ 1368 if (id.some) {{ 1369 int row = {1}_row(o->m_d, id.value); 1370 o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last); 1371 }} else {{ 1372 o->beginRemoveRows(QModelIndex(), first, last); 1373 }} 1374 }}, 1375 []({0}* o) {{ 1376 o->endRemoveRows(); 1377 }}", 1378 o.name, 1379 lcname, 1380 o.column_count() - 1 1381 )?; 1382 } 1383 Ok(()) 1384 } 1385 1386 pub fn write_header(conf: &Config) -> Result<()> { 1387 let mut h_file = conf.config_file.parent().unwrap().join(&conf.cpp_file); 1388 h_file.set_extension("h"); 1389 let mut h = Vec::new(); 1390 let guard = h_file 1391 .file_name() 1392 .unwrap() 1393 .to_string_lossy() 1394 .replace('.', "_") 1395 .to_uppercase(); 1396 writeln!( 1397 h, 1398 "/* generated by rust_qt_binding_generator */ 1399 #ifndef {0} 1400 #define {0} 1401 1402 #include <QtCore/QObject> 1403 #include <QtCore/QAbstractItemModel> 1404 ", 1405 guard 1406 )?; 1407 1408 for name in conf.objects.keys() { 1409 writeln!(h, "class {};", name)?; 1410 } 1411 for object in conf.objects.values() { 1412 write_header_object(&mut h, object, conf)?; 1413 } 1414 writeln!(h, "#endif // {}", guard)?; 1415 1416 write_if_different(h_file, &h)?; 1417 Ok(()) 1418 } 1419 1420 pub fn write_cpp(conf: &Config) -> Result<()> { 1421 let mut w = Vec::new(); 1422 let mut h_file = conf.config_file.parent().unwrap().join(&conf.cpp_file); 1423 h_file.set_extension("h"); 1424 let file_name = h_file.file_name().unwrap().to_string_lossy(); 1425 writeln!( 1426 w, 1427 "/* generated by rust_qt_binding_generator */ 1428 #include \"{}\" 1429 1430 namespace {{", 1431 file_name 1432 )?; 1433 for option in conf.optional_types() { 1434 if option != "QString" && option != "QByteArray" { 1435 writeln!( 1436 w, 1437 " 1438 struct option_{} {{ 1439 public: 1440 {0} value; 1441 bool some; 1442 operator QVariant() const {{ 1443 if (some) {{ 1444 return QVariant::fromValue(value); 1445 }} 1446 return QVariant(); 1447 }} 1448 }}; 1449 static_assert(std::is_pod<option_{0}>::value, \"option_{0} must be a POD type.\");", 1450 option 1451 )?; 1452 } 1453 } 1454 if conf.types().contains("QString") { 1455 writeln!( 1456 w, 1457 " 1458 typedef void (*qstring_set)(QString* val, const char* utf8, int nbytes); 1459 void set_qstring(QString* val, const char* utf8, int nbytes) {{ 1460 *val = QString::fromUtf8(utf8, nbytes); 1461 }}" 1462 )?; 1463 } 1464 if conf.types().contains("QByteArray") { 1465 writeln!( 1466 w, 1467 " 1468 typedef void (*qbytearray_set)(QByteArray* val, const char* bytes, int nbytes); 1469 void set_qbytearray(QByteArray* v, const char* bytes, int nbytes) {{ 1470 if (v->isNull() && nbytes == 0) {{ 1471 *v = QByteArray(bytes, nbytes); 1472 }} else {{ 1473 v->truncate(0); 1474 v->append(bytes, nbytes); 1475 }} 1476 }}" 1477 )?; 1478 } 1479 if conf.has_list_or_tree() { 1480 writeln!( 1481 w, 1482 " 1483 struct qmodelindex_t {{ 1484 int row; 1485 quintptr id; 1486 }}; 1487 inline QVariant cleanNullQVariant(const QVariant& v) {{ 1488 return (v.isNull()) ?QVariant() :v; 1489 }}" 1490 )?; 1491 } 1492 for (name, o) in &conf.objects { 1493 for (p_name, p) in &o.properties { 1494 if p.is_object() { 1495 continue; 1496 } 1497 writeln!(w, " inline void {}({}* o)", changed_f(o, p_name), name)?; 1498 writeln!(w, " {{\n Q_EMIT o->{}Changed();\n }}", p_name)?; 1499 } 1500 } 1501 writeln!(w, "}}")?; 1502 1503 for o in conf.objects.values() { 1504 if o.object_type != ObjectType::Object { 1505 write_cpp_model(&mut w, o)?; 1506 } 1507 writeln!(w, "extern \"C\" {{")?; 1508 write_object_c_decl(&mut w, o, conf)?; 1509 writeln!(w, "}};\n")?; 1510 } 1511 1512 for o in conf.objects.values() { 1513 write_cpp_object(&mut w, o, conf)?; 1514 } 1515 let file = conf.config_file.parent().unwrap().join(&conf.cpp_file); 1516 write_if_different(file, &w) 1517 }