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
1516 writeln!(w, "extern \"C\" {{
1517 void qmetaobject__invokeMethod__0(QObject *obj, const char *member) {{
1518 QMetaObject::invokeMethod(obj, member);
1519 }}
1520 }}")?;
1521
1522
1523 let file = conf.config_file.parent().unwrap().join(&conf.cpp_file);
1524 write_if_different(file, &w)
1525 }