diff --git a/etgtools/extractors.py b/etgtools/extractors.py index 9e09dae0..118c3957 100644 --- a/etgtools/extractors.py +++ b/etgtools/extractors.py @@ -4,7 +4,7 @@ # # Created: 3-Nov-2010 # Copyright: (c) 2010 by Total Control Software -# Licence: wxWindows license +# License: wxWindows License #--------------------------------------------------------------------------- """ @@ -107,6 +107,9 @@ class BaseDef(object): + def addItem(self, item): + self.items.append(item) + def insertItem(self, index, item): self.items.insert(index, item) @@ -343,7 +346,8 @@ class MethodDef(FunctionDef): def extract(self, element, className): super(MethodDef, self).extract(element) self.isStatic = element.get('static') == 'yes' - self.isVirtual = element.get('virt') == 'virtual' + self.isVirtual = element.get('virt') in ['virtual', 'pure-virtual'] + self.isPureVirtual = element.get('virt') == 'pure-virtual' self.isCtor = self.name == className self.isDtor = self.name == '~' + className self.protection = element.get('prot') @@ -515,7 +519,10 @@ class ClassDef(BaseDef): def addCppMethod(self, type, name, argsString, body, doc=None, **kw): """ - Add a new C++ method to a class. + Add a new C++ method to a class. This method doesn't have to actually + exist in the real C++ class. Instead it will be grafted on by the + back-end wrapper generator such that it is visible in the class in the + target language. """ md = CppMethodDef(type, name, argsString, body, doc, **kw) self.items.append(md) @@ -549,6 +556,65 @@ class ClassDef(BaseDef): return pc + def addPublic(self, code=''): + """ + Adds a 'public:' protection keyword to the class, optionally followed + by some additional code. + """ + text = 'public:' + if code: + text = text + '\n' + code + self.addItem(WigCode(text)) + + def addProtected(self, code=''): + """ + Adds a 'protected:' protection keyword to the class, optionally followed + by some additional code. + """ + text = 'protected:' + if code: + text = text + '\n' + code + self.addItem(WigCode(text)) + + + def addPrivate(self, code=''): + """ + Adds a 'private:' protection keyword to the class, optionally followed + by some additional code. + """ + text = 'private:' + if code: + text = text + '\n' + code + self.addItem(WigCode(text)) + + + def addCopyCtor(self, prot='protected'): + # add declaration of a copy constructor to this class + wig = WigCode(""" +{PROT}: + {CLASS}(const {CLASS}&); +""".format(CLASS=self.name, PROT=prot)) + self.addItem(wig) + + def addPrivateCopyCtor(self): + self.addCopyCtor('private') + + def addPrivateAssignOp(self): + # add declaration of an assignment opperator to this class + wig = WigCode(""" +private: + {CLASS}& operator=(const {CLASS}&); +""".format(CLASS=self.name)) + self.addItem(wig) + + def addDtor(self, prot='protected'): + # add declaration of a destructor to this class + wig = WigCode(""" +{PROT}: + ~{CLASS}(); +""".format(CLASS=self.name, PROT=prot)) + self.addItem(wig) + #--------------------------------------------------------------------------- class EnumDef(BaseDef): diff --git a/etgtools/sip_generator.py b/etgtools/sip_generator.py index 2aaf7973..e94f6964 100644 --- a/etgtools/sip_generator.py +++ b/etgtools/sip_generator.py @@ -4,7 +4,7 @@ # # Created: 3-Nov-2010 # Copyright: (c) 2010 by Total Control Software -# Licence: wxWindows license +# License: wxWindows License #--------------------------------------------------------------------------- """ @@ -46,15 +46,18 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): // This file is generated by wxPython's SIP generator. Do not edit by hand. // // Copyright: (c) 2010 by Total Control Software -// Licence: wxWindows license +// License: wxWindows License """) if module.name == module.module: stream.write(""" %%Module(name=%s.%s, use_argument_names=True, language="C++") +{ + %%AutoPyName(remove_leading="wx") +} %%Copying Copyright: (c) 2010 by Total Control Software - Licence: wxWindows license + License: wxWindows License %%End """ % (module.package, module.name)) @@ -68,7 +71,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): # This file is generated by wxPython's SIP generator. Do not edit by hand. # # Copyright: (c) 2010 by Total Control Software -# Licence: wxWindows license +# License: wxWindows License %s from %s import * @@ -80,7 +83,14 @@ from %s import * stream.write("//\n// This file will be included by %s.sip\n//\n" % module.module) stream.write(divider) - + + # C++ code to be written to the module's header + if module.headerCode: + stream.write("\n%ModuleHeaderCode\n") + for c in module.headerCode: + stream.write('%s\n' % c) + stream.write("%End\n\n") + # %Imports and %Includes for i in module.imports: stream.write("%%Import %s.sip\n" % i) @@ -89,12 +99,6 @@ from %s import * stream.write("%%Include %s.sip\n" % i) # C++ code to be written out to the generated module - if module.headerCode: - stream.write("\n%ModuleHeaderCode\n") - for c in module.headerCode: - stream.write('%s\n' % c) - stream.write("%End\n\n") - if module.cppCode: stream.write("%ModuleCode\n") for c in module.cppCode: @@ -181,14 +185,14 @@ from %s import * name = enum.name if name.startswith('@'): name = '' - stream.write('%senum %s%s\n{\n' % (indent, name, self.annotate(enum))) + stream.write('%senum %s%s\n%s{\n' % (indent, name, self.annotate(enum), indent)) values = [] for v in enum.items: if v.ignored: continue values.append("%s %s%s" % (indent, v.name, self.annotate(v))) stream.write(',\n'.join(values)) - stream.write('%s\n};\n\n' % (indent, )) + stream.write('%s\n%s};\n\n' % (indent, indent)) #----------------------------------------------------------------------- @@ -344,7 +348,10 @@ from %s import * stream.write('\n') self.generateParameters(method.items, stream, indent+' '*4) stream.write(indent) - stream.write(')%s;\n\n' % self.annotate(method)) + stream.write(')') + if method.isPureVirtual: + stream.write(' = 0') + stream.write('%s;\n\n' % self.annotate(method)) if method.overloads: for m in method.overloads: self.generateMethod(m, stream, indent) @@ -385,7 +392,8 @@ from %s import * def annotate(self, item): annotations = [] if item.pyName: - annotations.append('PyName=%s' % item.pyName) + if not getattr(item, 'wxDropped', False): + annotations.append('PyName=%s' % item.pyName) if isinstance(item, extractors.ParamDef): if item.out: diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index 92be4d4b..814869ac 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -4,7 +4,7 @@ # # Created: 3-Nov-2010 # Copyright: (c) 2010 by Total Control Software -# Licence: wxWindows license +# License: wxWindows License #--------------------------------------------------------------------------- """ @@ -18,7 +18,10 @@ import extractors def removeWxPrefixes(node): """ - Rename items with a 'wx' prefix to not have the prefix. + Rename items with a 'wx' prefix to not have the prefix. If the back-end + generator supports auto-renaming then it can ignore the pyName value for + those that are changed here. We'll still change them all incase the + pyNames are needed elsewhere. """ for item in node.allItems(): if not item.pyName \ @@ -27,9 +30,13 @@ def removeWxPrefixes(node): and not isinstance(item, (extractors.TypedefDef, extractors.MethodDef )): # TODO: Any others? item.pyName = item.name[2:] + item.wxDropped = True + if item.name.startswith('wxEVT_'): + # give these theire actual name so the auto-renamer won't touch them + item.pyName = item.name - + def ignoreAssignmentOperators(node): """ Set the ignored flag for all class methods that are assignment operators @@ -169,3 +176,46 @@ def convertTwoDoublesTemplate(CLASS): """.format(**locals()) +def convertFourDoublesTemplate(CLASS): + return """\ + // is it just a typecheck? + if (!sipIsErr) {{ + if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) + return 1; + + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 4) {{ + int rval = 1; + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + PyObject* o3 = PySequence_ITEM(sipPy, 2); + PyObject* o4 = PySequence_ITEM(sipPy, 3); + if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) + rval = 0; + Py_DECREF(o1); + Py_DECREF(o2); + Py_DECREF(o3); + Py_DECREF(o4); + return rval; + }} + return 0; + }} + + // otherwise do the conversion + if (PySequence_Check(sipPy)) {{ + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + PyObject* o3 = PySequence_ITEM(sipPy, 2); + PyObject* o4 = PySequence_ITEM(sipPy, 3); + *sipCppPtr = new {CLASS}(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2), + PyFloat_AsDouble(o3), PyFloat_AsDouble(o4)); + Py_DECREF(o1); + Py_DECREF(o2); + return sipGetState(sipTransferObj); + }} + *sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType( + sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); + return 0; + """.format(**locals()) + + +