void generate_class_header()

in library/grt/src/grtpp_helper.cpp [322:660]


  void generate_class_header(const std::string &dll_export) {
    FILE *f = header_file;

    // check if we will need a implementation file (.cpp)
    if (gstruct->force_impl() || !methods.empty())
      needs_body = true;

    for (std::map<std::string, MetaClass::Member>::const_iterator iter = members.begin(); iter != members.end();
         ++iter) {
      if (iter->second.delegate_get || iter->second.delegate_set || iter->second.calculated) {
        needs_body = true;
        break;
      }
    }

    generate_class_doc(f);
    fprintf(f, "class %s %s : public %s {\n", needs_body ? dll_export.c_str() : "", cname.c_str(), pname.c_str());
    fprintf(f, "  typedef %s super;\n\n", pname.c_str());
    fprintf(f, "public:\n");
    std::string klass = gstruct->get_attribute("simple-impl-data");
    if (gstruct->impl_data() || !klass.empty()) {
      if (klass.empty()) {
        fprintf(f, "  class ImplData;\n");
        fprintf(f, "  friend class ImplData;\n");
      } else
        fprintf(f, "  typedef %s ImplData;\n", klass.c_str());
    }
    // generate constructors
    bool default_ctor_created = false;

    for (std::map<std::string, MetaClass::Method>::const_iterator iter = methods.begin(); iter != methods.end();
         ++iter) {
      if (iter->second.constructor) {
        fprintf(f, "  %s(%s%s, grt::MetaClass *meta = nullptr);\n", cname.c_str(), iter->second.arg_types.empty() ? "" : ", ",
                format_arg_list(iter->second.arg_types).c_str());

        if (iter->second.arg_types.empty())
          default_ctor_created = true;
      }
    }

    if (!default_ctor_created) {
      fprintf(f, "  %s(grt::MetaClass *meta = nullptr)\n", cname.c_str());

      output_constructor_init_list(f);

      fprintf(f, " {\n");
      // reinit overridden lists
      output_overriden_list_reset_code(f);
      fprintf(f, "  }\n");
      fprintf(f, "\n");
    }

    if (needs_body || !gstruct->get_attribute("simple-impl-data").empty()) {
      if (gstruct->get_attribute("simple-impl-data").empty())
        fprintf(f, "  virtual ~%s();\n\n", cname.c_str());
      else {
        fprintf(f, "  virtual ~%s() {\n    if (_release_data && _data)\n      _release_data(_data);\n  }\n\n", cname.c_str());
      }
    }

    fprintf(f, "  static std::string static_class_name() {\n    return \"%s\";\n  }\n\n", gstruct->name().c_str());

    // generate signal access methods
    for (MetaClass::SignalList::const_iterator iter = gstruct->get_signals_partial().begin();
         iter != gstruct->get_signals_partial().end(); ++iter) {
      fprintf(f, "  // args: %s\n", format_signal_names(iter->arg_types).c_str());
      fprintf(f, "  boost::signals2::signal<void (%s)>* signal_%s() { return &_signal_%s; }\n",
              format_signal_args(iter->arg_types).c_str(), iter->name.c_str(), iter->name.c_str());
    }

    // generate member variable accessors
    for (MetaClass::MemberList::const_iterator iter = members.begin(); iter != members.end(); ++iter) {
      if (iter->second.private_)
        continue;

      bool overrides_with_same_type = false;
      // if the member is overridden, check if the type has been changed
      if (iter->second.overrides && gstruct->parent()) {
        const MetaClass::Member *member = gstruct->parent()->get_member_info(iter->second.name);

        if (member && member->type == iter->second.type)
          overrides_with_same_type = true;
      }

      // getter
      if (iter->second.owned_object)
        fprintf(f, "  // %s is owned by %s\n", iter->second.name.c_str(), cname.c_str());

      generate_getter_doc(f, iter->second);
      if (iter->second.delegate_get) {
        fprintf(f, "  %s %s() const;\n", format_type_cpp(iter->second.type).c_str(), iter->second.name.c_str());
      } else {
        if (iter->second.overrides) {
          if (!overrides_with_same_type) {
            fprintf(f, "  %s %s() const { return %s::cast_from(_%s); }\n", format_type_cpp(iter->second.type).c_str(),
                    iter->second.name.c_str(), format_type_cpp(iter->second.type).c_str(), iter->second.name.c_str());
          } else {
            // if we're overriding and the setter is delegated, we need to declare the getter too
            if (iter->second.delegate_set)
              fprintf(f, "  %s %s() const { return super::%s(); }\n", format_type_cpp(iter->second.type).c_str(),
                      iter->second.name.c_str(), iter->second.name.c_str());
          }
        } else
          fprintf(f, "  %s %s() const { return _%s; }\n", format_type_cpp(iter->second.type).c_str(),
                  iter->second.name.c_str(), iter->second.name.c_str());
      }
      fprintf(f, "\n");

      // setter
      if (iter->second.read_only)
        fprintf(f, "\nprivate: // The next attribute is read-only.\n");
      else
        generate_setter_doc(f, iter->second);

      if (iter->second.overrides) {
        if (overrides_with_same_type) {
          // check if the override is for overriding the setter
          if (iter->second.delegate_set) {
            fprintf(f, "  virtual void %s(const %s &value);\n", iter->second.name.c_str(),
                    format_type_cpp(iter->second.type).c_str());
          }
        } else {
          // variable is overriding another

          // list and dict members cannot be changed
          if (iter->second.type.base.type != ListType && iter->second.type.base.type != DictType) {
            if (iter->second.delegate_set)
              fprintf(f, "  virtual void %s(const %s &value);\n", iter->second.name.c_str(),
                      format_type_cpp(iter->second.type).c_str());
            else
              fprintf(f, "  virtual void %s(const %s &value) { super::%s(value); }\n", iter->second.name.c_str(),
                      format_type_cpp(iter->second.type).c_str(), iter->second.name.c_str());
          }
        }
      } else {
        if (iter->second.delegate_set) {
          fprintf(f, "  virtual void %s(const %s &value);\n", iter->second.name.c_str(),
                  format_type_cpp(iter->second.type).c_str());
        } else { // read-only vars need setter for unserialization  if (!iter->second.read_only)
          if (!iter->second.calculated) {
            fprintf(f, "  virtual void %s%s(const %s &value) {\n",
                    /*iter->second.read_only?"__":*/ "", iter->second.name.c_str(),
                    format_type_cpp(iter->second.type).c_str());

            fprintf(f, "    grt::ValueRef ovalue(_%s);\n", iter->second.name.c_str());
            if (iter->second.owned_object) {
              // if member is owned by this object, we have to mark/unmark it as global
              // in case we're in the global tree as well (done in owned_member_changed)
              fprintf(f, "\n");
              fprintf(f, "    _%s = value;\n", iter->second.name.c_str());
              fprintf(f, "    owned_member_changed(\"%s\", ovalue, value);\n", iter->second.name.c_str());
            } else {
              fprintf(f, "    _%s = value;\n", iter->second.name.c_str());
              fprintf(f, "    member_changed(\"%s\", ovalue, value);\n", iter->second.name.c_str());
            }
            fprintf(f, "  }\n");
          }
        }
      }

      if (iter->second.read_only)
        fprintf(f, "public:\n");
      fprintf(f, "\n");
    }

    // generate methods
    for (std::map<std::string, MetaClass::Method>::const_iterator iter = methods.begin(); iter != methods.end();
         ++iter) {
      generate_method_doc(f, iter->second);
      if (iter->second.abstract)
        fprintf(f, "  virtual %s %s(%s) = 0;\n", format_type_cpp(iter->second.ret_type, true).c_str(),
                iter->second.name.c_str(), format_arg_list(iter->second.arg_types).c_str());
      else
        fprintf(f, "  virtual %s %s(%s);\n", format_type_cpp(iter->second.ret_type, true).c_str(),
                iter->second.name.c_str(), format_arg_list(iter->second.arg_types).c_str());
    }

    if (needs_body || !gstruct->get_attribute("simple-impl-data").empty()) {
      bool needs_init = true;
      if (gstruct->impl_data()) {
        if (gstruct->get_attribute("simple-impl-data").empty()) {
          fprintf(f, "\n  ImplData *get_data() const { return _data; }\n\n");
          fprintf(f, "  void set_data(ImplData *data);\n");
        } else {
          fprintf(f, "\n  ImplData *get_data() const { return _data; }\n\n");
          fprintf(f, "  void set_data(ImplData *data, void (*release)(ImplData*)) {\n");
          fprintf(f, "    if (_data == data) return;\n");
          fprintf(f, "    if (_data && _release_data) _release_data(_data);\n");
          fprintf(f, "    _data= data;\n");
          fprintf(f, "    _release_data = release;\n");
          fprintf(f, "  }\n");
          needs_init = false;
        }
      }
      if (needs_init) {
        fprintf(f, "  // default initialization function. auto-called by ObjectRef constructor\n");
        fprintf(f, "  virtual void init();\n\n");
      }
    }

    fprintf(f, "protected:\n");

    // special methods
    if (gstruct->watch_lists()) {
      fprintf(f, "  virtual void owned_list_item_added(grt::internal::OwnedList *list, const grt::ValueRef &value);\n");
      fprintf(f,
              "  virtual void owned_list_item_removed(grt::internal::OwnedList *list, const grt::ValueRef &value);\n");
    }

    if (gstruct->watch_dicts()) {
      fprintf(f, "  virtual void owned_dict_item_set(grt::internal::OwnedDict *dict, const std::string &key);\n");
      fprintf(f, "  virtual void owned_dict_item_removed(grt::internal::OwnedDict *dict, const std::string &key);\n");
    }

    // signals
    for (auto iter = gstruct->get_signals_partial().begin(); iter != gstruct->get_signals_partial().end(); ++iter) {
      fprintf(f, "  boost::signals2::signal<void (%s)> _signal_%s;\n", format_signal_args(iter->arg_types).c_str(),
              iter->name.c_str());
    }
    fprintf(f, "\n");

    // generate member variables
    for (auto iter = members.begin(); iter != members.end(); ++iter) {
      if (!iter->second.calculated && !iter->second.overrides)
        fprintf(f, "  %s _%s;%s\n", format_type_cpp(iter->second.type).c_str(), iter->second.name.c_str(),
                iter->second.owned_object ? "// owned" : "");
    }
    fprintf(f, "\n");

    fprintf(f, "private: // Wrapper methods for use by the grt.\n");
    if ((needs_body && gstruct->impl_data()) || !gstruct->get_attribute("simple-impl-data").empty()) {
      fprintf(f, "  ImplData *_data;\n");
      if (!gstruct->get_attribute("simple-impl-data").empty())
        fprintf(f, "  void (*_release_data)(ImplData *);\n");
      fprintf(f, "\n");
    }
    // function to create the object
    if (!gstruct->is_abstract()) {
      fprintf(f, "  static grt::ObjectRef create() {\n");
      fprintf(f, "    return grt::ObjectRef(new %s());\n", cname.c_str());
      fprintf(f, "  }\n");
      fprintf(f, "\n");
    }

    // generate method wrappers for grt
    for (auto iter = methods.begin(); iter != methods.end(); ++iter) {
      if (!iter->second.constructor) {
        if (iter->second.ret_type.base.type == UnknownType)
          fprintf(f,
                  "  static grt::ValueRef call_%s(grt::internal::Object *self, const grt::BaseListRef &args)"
                  "{ dynamic_cast<%s*>(self)->%s(%s); return grt::ValueRef(); }\n",
                  iter->second.name.c_str(), cname.c_str(), iter->second.name.c_str(),
                  format_wraparg_list(iter->second.arg_types).c_str());
        else
          fprintf(f,
                  "  static grt::ValueRef call_%s(grt::internal::Object *self, const grt::BaseListRef &args)"
                  "{ return dynamic_cast<%s*>(self)->%s(%s); }\n",
                  iter->second.name.c_str(), cname.c_str(), iter->second.name.c_str(),
                  format_wraparg_list(iter->second.arg_types).c_str());
        fprintf(f, "\n");
      }
    }

    // Class registration.
    fprintf(f, "public:\n");
    fprintf(f, "  static void grt_register() {\n");
    fprintf(f, "    grt::MetaClass *meta = grt::GRT::get()->get_metaclass(static_class_name());\n");
    fprintf(f,
            "    if (meta == nullptr)\n      throw std::runtime_error(\"error initializing grt object class, metaclass not found\");\n");

    if (gstruct->is_abstract())
      fprintf(f, "    meta->bind_allocator(nullptr);\n");
    else
      fprintf(f, "    meta->bind_allocator(&%s::create);\n", cname.c_str());

    for (std::map<std::string, MetaClass::Member>::const_iterator iter = members.begin(); iter != members.end();
         ++iter) {
      if (iter->second.calculated) {
        if (!iter->second.delegate_set)
          fprintf(f, "    meta->bind_member(\"%s\", new grt::MetaClass::Property<%s,%s>(&%s::%s));\n",
                  iter->second.name.c_str(), cname.c_str(), format_type_cpp(iter->second.type).c_str(), cname.c_str(),
                  iter->second.name.c_str());
        else {
          fprintf(f, "    {\n");
          fprintf(f, "      void (%s::*setter)(const %s &) = &%s::%s%s;\n", cname.c_str(),
                  format_type_cpp(iter->second.type).c_str(), cname.c_str(), /*iter->second.read_only?"__":*/ "",
                  iter->second.name.c_str());
          fprintf(f, "      %s (%s::*getter)() const = &%s::%s;\n", format_type_cpp(iter->second.type).c_str(),
                  cname.c_str(), cname.c_str(), iter->second.name.c_str());

          fprintf(f, "      meta->bind_member(\"%s\", new grt::MetaClass::Property<%s,%s>(getter, setter));\n",
                  iter->second.name.c_str(), cname.c_str(), format_type_cpp(iter->second.type).c_str());
          fprintf(f, "    }\n");
        }
      } else {
        fprintf(f, "    {\n");
        if (iter->second.overrides) {
          if (iter->second.delegate_set) {
            fprintf(f, "      void (%s::*setter)(const %s &) = &%s::%s%s;\n", cname.c_str(),
                    format_type_cpp(iter->second.type).c_str(), cname.c_str(), /*iter->second.read_only?"__":*/ "",
                    iter->second.name.c_str());
          } else {
            fprintf(f, "      void (%s::*setter)(const %s &) = 0;\n", cname.c_str(),
                    format_type_cpp(iter->second.type).c_str());
          }
        } else { // read-only members should still have a setter for unserialization
          fprintf(f, "      void (%s::*setter)(const %s &) = &%s::%s%s;\n", cname.c_str(),
                  format_type_cpp(iter->second.type).c_str(), cname.c_str(), /*iter->second.read_only?"__":*/ "",
                  iter->second.name.c_str());
        }

        if (iter->second.overrides) {
          if (iter->second.delegate_get)
            fprintf(f, "      %s (%s::*getter)() const = &%s::%s;\n", format_type_cpp(iter->second.type).c_str(),
                    cname.c_str(), cname.c_str(), iter->second.name.c_str());
          else
            fprintf(f, "      %s (%s::*getter)() const = 0;\n", format_type_cpp(iter->second.type).c_str(),
                    cname.c_str());
        } else {
          fprintf(f, "      %s (%s::*getter)() const = &%s::%s;\n", format_type_cpp(iter->second.type).c_str(),
                  cname.c_str(), cname.c_str(), iter->second.name.c_str());
        }

        fprintf(f, "      meta->bind_member(\"%s\", new grt::MetaClass::Property<%s,%s>(getter, setter));\n",
                iter->second.name.c_str(), cname.c_str(), format_type_cpp(iter->second.type).c_str());
        fprintf(f, "    }\n");
      }
    }

    for (std::map<std::string, MetaClass::Method>::const_iterator iter = methods.begin(); iter != methods.end();
         ++iter) {
      fprintf(f, "    meta->bind_method(\"%s\", &%s::call_%s);\n", iter->second.name.c_str(), cname.c_str(),
              iter->second.name.c_str());
    }
    fprintf(f, "  }\n");

    fprintf(f, "};\n\n");
  }