mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-09 05:20:08 +01:00
* Replacing method code with .setCppCode is now not SIP-specific. The generated code creates a new function to place the code in, like CppMethodDef does, so the given code can use 'self' and return values instead of using special SIP variables.
* added setCppCode_sip for when SIP-specific stuff is needed. * Adding the 'const' on to const methods had somehow been forgotten, fix that. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@69187 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
10
TODO.txt
10
TODO.txt
@@ -169,16 +169,6 @@ Deprecated C++ items
|
||||
|
||||
|
||||
|
||||
custom wrapper code
|
||||
-------------------
|
||||
Currently function.setCppCode requires some sip-isms (using sipRes and
|
||||
sipCpp for example) to be able to replace the wrapper code used to
|
||||
wrap the C++ function. Try making it work more like addCppMethod
|
||||
where it will generate a new function that is passed "self" and that
|
||||
you can simply return a value from.
|
||||
|
||||
|
||||
|
||||
WingIDE support
|
||||
---------------
|
||||
WingIDE (and maybe other IDEs too?) has the ability to display
|
||||
|
||||
@@ -56,11 +56,11 @@ def run():
|
||||
|
||||
gud = c.find('GetUserData')
|
||||
gud.type = 'wxPyUserData*'
|
||||
gud.setCppCode('sipRes = dynamic_cast<wxPyUserData*>(sipCpp->GetUserData());')
|
||||
gud.setCppCode('return dynamic_cast<wxPyUserData*>(self->GetUserData());')
|
||||
sud = c.find('SetUserData')
|
||||
sud.find('userData').transfer = True
|
||||
sud.find('userData').type = 'wxPyUserData*'
|
||||
sud.setCppCode('sipCpp->SetUserData(dynamic_cast<wxObject*>(userData));')
|
||||
sud.setCppCode('self->SetUserData(dynamic_cast<wxObject*>(userData));')
|
||||
|
||||
c.addPrivateCopyCtor()
|
||||
|
||||
|
||||
@@ -39,14 +39,14 @@ def run():
|
||||
c.find('SetInstallPrefix').setCppCode("""\
|
||||
#ifdef __WXMSW__
|
||||
#else
|
||||
sipCpp->SetInstallPrefix(*prefix);
|
||||
self->SetInstallPrefix(*prefix);
|
||||
#endif
|
||||
""")
|
||||
c.find('GetInstallPrefix').setCppCode("""\
|
||||
#ifdef __WXMSW__
|
||||
sipRes = new wxString;
|
||||
return new wxString;
|
||||
#else
|
||||
sipRes = new wxString(sipCpp->GetInstallPrefix());
|
||||
return new wxString(self->GetInstallPrefix());
|
||||
#endif
|
||||
""")
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ def run():
|
||||
m.find('externalLeading').out = True
|
||||
|
||||
c.find('GetHandle').type = 'void*'
|
||||
c.find('GetHandle').setCppCode("sipRes = wxPyGetWinHandle(sipCpp);")
|
||||
c.find('GetHandle').setCppCode("return wxPyGetWinHandle(self);")
|
||||
|
||||
c.addCppMethod('void*', 'GetGtkWidget', '()', """\
|
||||
#ifdef __WXGTK__
|
||||
@@ -119,16 +119,16 @@ def run():
|
||||
# and empty stubs otherwise
|
||||
c.find('RegisterHotKey').setCppCode("""\
|
||||
#if wxUSE_HOTKEY
|
||||
sipRes = sipCpp->RegisterHotKey(hotkeyId, modifiers, virtualKeyCode);
|
||||
return self->RegisterHotKey(hotkeyId, modifiers, virtualKeyCode);
|
||||
#else
|
||||
sipRes = false;
|
||||
return false;
|
||||
#endif
|
||||
""")
|
||||
c.find('UnregisterHotKey').setCppCode("""\
|
||||
#if wxUSE_HOTKEY
|
||||
sipRes = sipCpp->UnregisterHotKey(hotkeyId);
|
||||
return self->UnregisterHotKey(hotkeyId);
|
||||
#else
|
||||
sipRes = false;
|
||||
return false;
|
||||
#endif
|
||||
""")
|
||||
c.find('RegisterHotKey').isVirtual = False
|
||||
@@ -137,7 +137,7 @@ def run():
|
||||
|
||||
c.find('SetDoubleBuffered').setCppCode("""\
|
||||
#if defined(__WXGTK20__) || defined(__WXMSW__)
|
||||
sipCpp->SetDoubleBuffered(on);
|
||||
self->SetDoubleBuffered(on);
|
||||
#endif
|
||||
""")
|
||||
|
||||
|
||||
@@ -255,6 +255,21 @@ class FunctionDef(BaseDef):
|
||||
|
||||
def releaseGIL(self, release=True):
|
||||
self.pyReleaseGIL = release
|
||||
|
||||
|
||||
def setCppCode_sip(self, code):
|
||||
"""
|
||||
Use the given C++ code instead of that automatically generated by the
|
||||
back-end. This is similar to adding a new C++ method, except it uses
|
||||
info we've alread received from the source XML such as the argument
|
||||
types and names, docstring, etc.
|
||||
|
||||
The code generated for this verison will expect the given code to use
|
||||
SIP specfic variable names, etc. For example::
|
||||
|
||||
sipRes = sipCpp->Foo();
|
||||
"""
|
||||
self.cppCode = (code, 'sip')
|
||||
|
||||
|
||||
def setCppCode(self, code):
|
||||
@@ -263,9 +278,15 @@ class FunctionDef(BaseDef):
|
||||
back-end. This is similar to adding a new C++ method, except it uses
|
||||
info we've alread received from the source XML such as the argument
|
||||
types and names, docstring, etc.
|
||||
"""
|
||||
self.cppCode = code
|
||||
|
||||
The code generated for this version will put the given code in a
|
||||
wrapper function that will enable it to be more independent, not SIP
|
||||
specific, and also more natural. For example::
|
||||
|
||||
return self->Foo();
|
||||
"""
|
||||
self.cppCode = (code, 'function')
|
||||
|
||||
|
||||
def checkForOverload(self, methods):
|
||||
for m in methods:
|
||||
@@ -301,6 +322,9 @@ class FunctionDef(BaseDef):
|
||||
"""
|
||||
Create a pythonized version of the argsString in function and method
|
||||
items that can be used as part of the docstring.
|
||||
|
||||
TODO: Maybe (optionally) use this syntax to document arg types?
|
||||
http://www.python.org/dev/peps/pep-3107/
|
||||
"""
|
||||
def _cleanName(name):
|
||||
for txt in ['const', '*', '&', ' ']:
|
||||
@@ -366,6 +390,7 @@ class MethodDef(FunctionDef):
|
||||
self.className = className
|
||||
self.isVirtual = False
|
||||
self.isStatic = False
|
||||
self.isConst = False
|
||||
self.isCtor = False
|
||||
self.isDtor = False
|
||||
self.protection = ''
|
||||
@@ -380,6 +405,7 @@ class MethodDef(FunctionDef):
|
||||
self.isStatic = element.get('static') == 'yes'
|
||||
self.isVirtual = element.get('virt') in ['virtual', 'pure-virtual']
|
||||
self.isPureVirtual = element.get('virt') == 'pure-virtual'
|
||||
self.isConst = element.get('const') == 'yes'
|
||||
self.isCtor = self.name == self.className
|
||||
self.isDtor = self.name == '~' + self.className
|
||||
self.protection = element.get('prot')
|
||||
@@ -816,6 +842,19 @@ class CppMethodDef(MethodDef):
|
||||
self.isConst = isConst
|
||||
self.__dict__.update(kw)
|
||||
|
||||
@staticmethod
|
||||
def FromMethod(method):
|
||||
"""
|
||||
Create a new CppMethodDef that is essentially a copy of a MethodDef,
|
||||
so it can be used to write the code for a new wrapper function.
|
||||
|
||||
TODO: It might be better to just refactor the code in the generator
|
||||
so it can be shared more easily intstead of using a hack like this...
|
||||
"""
|
||||
m = CppMethodDef('', '', '', '')
|
||||
m.__dict__.update(method.__dict__)
|
||||
return m
|
||||
|
||||
|
||||
class CppMethodDef_sip(CppMethodDef):
|
||||
"""
|
||||
|
||||
@@ -21,6 +21,12 @@ from cStringIO import StringIO
|
||||
divider = '//' + '-'*75 + '\n'
|
||||
phoenixRoot = os.path.abspath(os.path.split(__file__)[0]+'/..')
|
||||
|
||||
# This is a list of types that are used as return by value or by reference
|
||||
# function return types that we need to ensure are actually using pointer
|
||||
# types in their CppMethodDef or cppCode wrappers.
|
||||
forcePtrTypes = [ 'wxString',
|
||||
]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class SipWrapperGenerator(generators.WrapperGeneratorBase):
|
||||
@@ -176,9 +182,13 @@ from %s import *
|
||||
_needDocstring = False
|
||||
|
||||
if function.cppCode:
|
||||
stream.write('%MethodCode\n')
|
||||
stream.write(nci(function.cppCode, 4))
|
||||
stream.write('%End\n')
|
||||
code, codeType = function.cppCode
|
||||
if codeType == 'sip':
|
||||
stream.write('%MethodCode\n')
|
||||
stream.write(nci(code, 4))
|
||||
stream.write('%End\n')
|
||||
elif codeType == 'function':
|
||||
raise NotImplementedError() # TODO: See generateMethod for an example, refactor to share code...
|
||||
for f in function.overloads:
|
||||
self.generateFunction(f, stream, _needDocstring)
|
||||
stream.write('\n')
|
||||
@@ -334,6 +344,7 @@ from %s import *
|
||||
f(item, stream, indent + ' '*4)
|
||||
|
||||
for item in public:
|
||||
item.klass = klass
|
||||
f = dispatch[item.__class__]
|
||||
f(item, stream, indent + ' '*4)
|
||||
|
||||
@@ -438,6 +449,8 @@ from %s import *
|
||||
self.generateParameters(method.items, stream, indent+' '*4)
|
||||
stream.write(indent)
|
||||
stream.write(')')
|
||||
if method.isConst:
|
||||
stream.write(' const')
|
||||
if method.isPureVirtual:
|
||||
stream.write(' = 0')
|
||||
stream.write('%s;\n' % self.annotate(method))
|
||||
@@ -449,66 +462,32 @@ from %s import *
|
||||
_needDocstring = False
|
||||
|
||||
if method.cppCode:
|
||||
stream.write('%s%%MethodCode\n' % indent)
|
||||
stream.write(nci(method.cppCode, len(indent)+4))
|
||||
stream.write('%s%%End\n' % indent)
|
||||
code, codeType = method.cppCode
|
||||
if codeType == 'sip':
|
||||
stream.write('%s%%MethodCode\n' % indent)
|
||||
stream.write(nci(code, len(indent)+4))
|
||||
stream.write('%s%%End\n' % indent)
|
||||
elif codeType == 'function':
|
||||
cm = extractors.CppMethodDef.FromMethod(method)
|
||||
cm.body = code
|
||||
self.generateCppMethod(cm, stream, indent, skipDeclaration=True)
|
||||
|
||||
stream.write('\n')
|
||||
if method.overloads:
|
||||
for m in method.overloads:
|
||||
self.generateMethod(m, stream, indent, _needDocstring)
|
||||
|
||||
|
||||
def generateCppMethod(self, method, stream, indent=''):
|
||||
def generateCppMethod(self, method, stream, indent='', skipDeclaration=False):
|
||||
# Add a new C++ method to a class. This one adds the code as a
|
||||
# separate function and then adds a call to that function in the
|
||||
# MethodCode directive.
|
||||
assert isinstance(method, extractors.CppMethodDef)
|
||||
if method.ignored:
|
||||
return
|
||||
klass = method.klass
|
||||
if klass:
|
||||
assert isinstance(klass, extractors.ClassDef)
|
||||
|
||||
# create the new function
|
||||
fargs = method.argsString.strip('()').split(',')
|
||||
for idx, arg in enumerate(fargs):
|
||||
# take only the part before the =, if there is one
|
||||
arg = arg.split('=')[0].strip()
|
||||
arg = arg.replace('&', '*') # SIP will always want to use pointers for parameters
|
||||
fargs[idx] = arg
|
||||
fargs = ', '.join(fargs)
|
||||
if fargs:
|
||||
fargs = ', ' + fargs
|
||||
if method.isCtor:
|
||||
fname = '_%s_newCtor' % klass.name
|
||||
fargs = '(int& _isErr%s)' % fargs
|
||||
stream.write('%s%%TypeCode\n' % indent)
|
||||
typ = klass.name
|
||||
if method.useDerivedName:
|
||||
typ = 'sip'+klass.name
|
||||
stream.write('%sclass %s;\n' % (indent, typ)) # forward decalre the derived class
|
||||
stream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent))
|
||||
stream.write(nci(method.body, len(indent)+4))
|
||||
stream.write('%s}\n' % indent)
|
||||
stream.write('%s%%End\n' % indent)
|
||||
|
||||
else:
|
||||
if klass:
|
||||
fname = '_%s_%s' % (klass.name, method.name)
|
||||
fargs = '(%s* self, int& _isErr%s)' % (klass.name, fargs)
|
||||
stream.write('%s%%TypeCode\n' % indent)
|
||||
else:
|
||||
fname = '_%s_function' % method.name
|
||||
fargs = '(int& _isErr%s)' % fargs
|
||||
stream.write('%s%%ModuleCode\n' % indent)
|
||||
stream.write('%s%s %s%s\n%s{\n' % (indent, method.type, fname, fargs, indent))
|
||||
stream.write(nci(method.body, len(indent)+4))
|
||||
stream.write('%s}\n' % indent)
|
||||
stream.write('%s%%End\n' % indent)
|
||||
|
||||
# now insert the method declaration and the code to call the new function
|
||||
# first, find the parameter names
|
||||
pnames = method.argsString.strip('()').split(',')
|
||||
|
||||
lastP = method.argsString.rfind(')')
|
||||
pnames = method.argsString[:lastP].strip('()').split(',')
|
||||
for idx, pn in enumerate(pnames):
|
||||
# take only the part before the =, if there is one
|
||||
name = pn.split('=')[0].strip()
|
||||
@@ -521,19 +500,83 @@ from %s import *
|
||||
pnames = ', ' + pnames
|
||||
typ = method.type
|
||||
argsString = method.argsString
|
||||
# spit it all out
|
||||
|
||||
if not skipDeclaration:
|
||||
# First insert the method declaration
|
||||
if method.isCtor:
|
||||
stream.write('%s%s%s%s;\n' %
|
||||
(indent, method.name, argsString, self.annotate(method)))
|
||||
else:
|
||||
constMod = ""
|
||||
if method.isConst:
|
||||
constMod = " const"
|
||||
stream.write('%s%s %s%s%s%s;\n' %
|
||||
(indent, typ, method.name, argsString, constMod, self.annotate(method)))
|
||||
|
||||
# write the docstring
|
||||
self.generateDocstring(method, stream, indent)
|
||||
|
||||
klass = method.klass
|
||||
if klass:
|
||||
assert isinstance(klass, extractors.ClassDef)
|
||||
|
||||
# create the new function
|
||||
fstream = StringIO() # using a new stream so we can do the actual write a little later
|
||||
lastP = method.argsString.rfind(')')
|
||||
fargs = method.argsString[:lastP].strip('()').split(',')
|
||||
for idx, arg in enumerate(fargs):
|
||||
# take only the part before the =, if there is one
|
||||
arg = arg.split('=')[0].strip()
|
||||
arg = arg.replace('&', '*') # SIP will always want to use pointers for parameters
|
||||
fargs[idx] = arg
|
||||
fargs = ', '.join(fargs)
|
||||
if fargs:
|
||||
fargs = ', ' + fargs
|
||||
if method.isCtor:
|
||||
stream.write('%s%s%s%s;\n' %
|
||||
(indent, method.name, argsString, self.annotate(method)))
|
||||
else:
|
||||
constMod = ""
|
||||
if method.isConst:
|
||||
constMod = " const"
|
||||
stream.write('%s%s %s%s%s%s;\n' %
|
||||
(indent, typ, method.name, argsString, constMod, self.annotate(method)))
|
||||
|
||||
self.generateDocstring(method, stream, indent)
|
||||
fname = '_%s_newCtor' % klass.name
|
||||
fargs = '(int& _isErr%s)' % fargs
|
||||
fstream.write('%s%%TypeCode\n' % indent)
|
||||
typ = klass.name
|
||||
if method.useDerivedName:
|
||||
typ = 'sip'+klass.name
|
||||
fstream.write('%sclass %s;\n' % (indent, typ)) # forward decalre the derived class
|
||||
fstream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent))
|
||||
fstream.write(nci(method.body, len(indent)+4))
|
||||
fstream.write('%s}\n' % indent)
|
||||
fstream.write('%s%%End\n' % indent)
|
||||
|
||||
else:
|
||||
if klass:
|
||||
fname = '_%s_%s' % (klass.name, method.name)
|
||||
if method.isStatic:
|
||||
# If the method is static then there is no sipCpp to send to
|
||||
# the new function, so it should not have a self parameter.
|
||||
fargs = '(int& _isErr%s)' % fargs
|
||||
else:
|
||||
fargs = '(%s* self, int& _isErr%s)' % (klass.name, fargs)
|
||||
fstream.write('%s%%TypeCode\n' % indent)
|
||||
else:
|
||||
fname = '_%s_function' % method.name
|
||||
fargs = '(int& _isErr%s)' % fargs
|
||||
fstream.write('%s%%ModuleCode\n' % indent)
|
||||
|
||||
# If the return type is in the forcePtrTypes list then make sure
|
||||
# that it is a pointer, not a return by value or reference, since
|
||||
# SIP almost always deals with pointers to newly allocated
|
||||
# objects.
|
||||
typPtr = method.type
|
||||
if typPtr in forcePtrTypes:
|
||||
if '&' in typPtr:
|
||||
typPtr.replace('&', '*')
|
||||
elif '*' not in typPtr:
|
||||
typPtr += '*'
|
||||
|
||||
fstream.write('%s%s %s%s\n%s{\n' % (indent, typPtr, fname, fargs, indent))
|
||||
fstream.write(nci(method.body, len(indent)+4))
|
||||
fstream.write('%s}\n' % indent)
|
||||
fstream.write('%s%%End\n' % indent)
|
||||
|
||||
# Write the code that will call the new function
|
||||
stream.write('%s%%MethodCode\n' % indent)
|
||||
stream.write(indent+' '*4)
|
||||
if method.isCtor:
|
||||
@@ -542,12 +585,20 @@ from %s import *
|
||||
if method.type != 'void':
|
||||
stream.write('sipRes = ')
|
||||
if klass:
|
||||
stream.write('%s(sipCpp, sipIsErr%s);\n' % (fname, pnames))
|
||||
if method.isStatic:
|
||||
# If the method is static then there is no sipCpp to send to
|
||||
# the new function, so it should not have a self parameter.
|
||||
stream.write('%s(sipIsErr%s);\n' % (fname, pnames))
|
||||
else:
|
||||
stream.write('%s(sipCpp, sipIsErr%s);\n' % (fname, pnames))
|
||||
else:
|
||||
stream.write('%s(sipIsErr%s);\n' % (fname, pnames))
|
||||
stream.write('%s%%End\n\n' % indent)
|
||||
stream.write('%s%%End\n' % indent)
|
||||
|
||||
|
||||
# and finally, add the new function itself
|
||||
stream.write(fstream.getvalue())
|
||||
stream.write('\n')
|
||||
|
||||
|
||||
|
||||
def generateCppMethod_sip(self, method, stream, indent=''):
|
||||
|
||||
@@ -32,7 +32,7 @@ def removeWxPrefixes(node):
|
||||
extractors.MethodDef )): # TODO: Any others?
|
||||
item.pyName = item.name[2:]
|
||||
item.wxDropped = True
|
||||
if item.name.startswith('wxEVT_'):
|
||||
if item.name.startswith('wxEVT_') and 'CATEGORY' not in item.name:
|
||||
# give these their actual name so the auto-renamer won't touch them
|
||||
item.pyName = item.name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user