123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import errno
- import os
- import re
- from string import Template
- PYTHONQT_WRAPPER_WITH_PARENT = Template("""
- //-----------------------------------------------------------------------------
- class PythonQtWrapper_${className} : public QObject
- {
- Q_OBJECT
- public:
- public Q_SLOTS:
- ${className}* new_${className}(${parentClassName}* parent = 0)
- {
- return new ${className}(parent);
- }
- void delete_${className}(${className}* obj) { delete obj; }
- };
- """)
- PYTHONQT_WRAPPER_WITHOUT_PARENT = Template("""
- //-----------------------------------------------------------------------------
- class PythonQtWrapper_${className} : public QObject
- {
- Q_OBJECT
- public:
- public Q_SLOTS:
- ${className}* new_${className}()
- {
- return new ${className}();
- }
- void delete_${className}(${className}* obj) { delete obj; }
- };
- """)
- def _mkdir_p(path):
- """See """
- try:
- os.makedirs(path)
- except OSError as exc:
- if exc.errno == errno.EEXIST and os.path.isdir(path):
- pass
- else: raise
- def ctk_wrap_pythonqt(target, namespace, output_dir, input_files, extra_verbose):
- if extra_verbose:
- print("target: %s" % target)
- print("namespace: %s" % namespace)
- print("output_dir: %s" % output_dir)
- print("input_files: %s" % input_files)
-
- _mkdir_p(output_dir)
-
- includes = []
- pythonqtWrappers = []
- registerclasses = []
- namespace = namespace.replace('.', '_')
-
- for input_file in input_files:
- filename = os.path.basename(input_file)
- if extra_verbose:
- print("Wrapping %s" % filename)
-
- # what is the filename without the extension
- filename_we = os.path.splitext(filename)[0]
- # Extract classname - NOTE: We assume the filename matches the associated class
- className = filename_we
- if extra_verbose:
- print("\tclassName:%s" % className)
- # Extract parent classname
- parentClassName = None
- # Read input files
- with open(input_file) as f:
- content = f.read()
-
- # Skip wrapping if file do NOT contain Q_OBJECT
- if 'Q_OBJECT' not in content:
- if extra_verbose:
- print("\tskipping - No Q_OBJECT macro")
- continue
- # Skip wrapping if constructor doesn't match:
- # my_class()
- # my_class(QObject* newParent ...)
- # my_class(QWidget* newParent ...)
- # Constructor with either QWidget or QObject as first parameter
- regex = r"[^~]%s[\s\n]*\([\s\n]*((QObject|QWidget)[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\)|\)))" % className
- res = re.search(regex, content, re.MULTILINE)
- if res is None:
- if extra_verbose:
- print("\tskipping - Missing expected constructor signature")
- continue
-
- # Skip wrapping if object has a virtual pure method
- # "x3b" is the unicode for semicolon
- regex = r"virtual[\w\n\s\*\(\)]+\=[\s\n]*(0|NULL)[\s\n]*\x3b"
- res = re.search(regex, content, re.MULTILINE)
- if res is not None:
- if extra_verbose:
- print("skipping - Contains a virtual pure method")
- continue
- if parentClassName is None:
- # Does constructor signature is of the form: myclass()
- regex = r"[^~]%s[\s\n]*\([\s\n]*\)" % className
- res = re.search(regex, content, re.MULTILINE)
-
- if res is not None:
- parentClassName = ""
- if extra_verbose:
- print("\tconstructor of the form: %s()" % className)
- if parentClassName is None:
- # Does constructor signature is of the form: myclass(QObject * parent ...)
- regex = r"%s[\s\n]*\([\s\n]*QObject[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\))" % className
- res = re.search(regex, content, re.MULTILINE)
- if res is not None:
- parentClassName = "QObject"
- if extra_verbose:
- print("\tconstructor of the form: %s(QObject * parent ... )" % className)
- if parentClassName is None:
- # Does constructor signature is of the form: myclass(QWidget * parent ...)
- regex = r"%s[\s\n]*\([\s\n]*QWidget[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\))" % className
- res = re.search(regex, content, re.MULTILINE)
- if res is not None:
- parentClassName = "QWidget"
- if extra_verbose:
- print("\tconstructor of the form: %s(QWidget * parent ... )" % className)
- if parentClassName is not None:
- includes.append('#include "%s.h"' % filename_we)
- # Generate PythonQtWrapper class
- if parentClassName == "QObject" or parentClassName == "QWidget":
- pythonqtWrappers.append(
- PYTHONQT_WRAPPER_WITH_PARENT.substitute(className = className, parentClassName = parentClassName))
-
- elif parentClassName == "":
- pythonqtWrappers.append(PYTHONQT_WRAPPER_WITHOUT_PARENT.substitute(className = className))
- else: # Case parentClassName is None
- raise Exception("Problem wrapping %s" % input_file)
-
- # Generate code allowing to register the class metaobject and its associated "light" wrapper
- registerclasses.append(
- Template("""
- PythonQt::self()->registerClass(
- &${className}::staticMetaObject, "${target}",
- PythonQtCreateObject<PythonQtWrapper_${className}>);
- """).substitute(className = className, target = target))
- output_header = output_dir + "/" + namespace + "_" + target + ".h"
- if extra_verbose:
- print("output_header: %s" % output_header)
- # Write master include file
- with open(output_header, "w") as f:
- f.write(Template(
- """
- //
- // File auto-generated by ctkWrapPythonQt.py
- //
- #ifndef __${namespace}_${target}_h
- #define __${namespace}_${target}_h
- #include <QObject>
- ${includes}
- ${pythonqtWrappers}
- #endif
- """).substitute(namespace = namespace, target = target, includes = '\n'.join(includes), pythonqtWrappers = '\n'.join(pythonqtWrappers)))
- output_cpp = output_dir + "/" + namespace + "_" + target + "_init.cpp"
- if extra_verbose:
- print("output_cpp: %s" % output_cpp)
- with open(output_cpp , "w") as f:
- # Write wrapper header
- f.write(Template(
- """
- //
- // File auto-generated by ctkWrapPythonQt.py
- //
- #include <PythonQt.h>
- // XXX Avoid warning: "HAVE_XXXX" redefined
- #undef HAVE_STAT
- #undef HAVE_FTIME
- #undef HAVE_GETPID
- #undef HAVE_IO_H
- #undef HAVE_STRERROR
- #undef HAVE_SYS_UTIME_H
- #undef HAVE_TEMPNAM
- #undef HAVE_TMPNAM
- #undef HAVE_LONG_LONG
- #undef HAVE_INT64_T
- #include "${namespace}_${target}.h"
- void PythonQt_init_${namespace}_${target}(PyObject* module)
- {
- Q_UNUSED(module);
- ${registerclasses}
- }
- """).substitute(namespace = namespace, target = target, registerclasses = '\n'.join(registerclasses)))
- if __name__ == '__main__':
- from optparse import OptionParser
- usage = "usage: %prog [options] <output_file> <input_file> [<input_file1> [...]]"
- parser = OptionParser(usage=usage)
- parser.add_option("-t", "--target",
- dest="target", action="store", type="string",
- help="Name of the associated library")
- parser.add_option("-n", "--namespace",
- dest="namespace", action="store", type="string",
- help="Wrapping namespace")
- parser.add_option("--output-dir",
- dest="output_dir", action="store", type="string",
- help="Output directory")
- parser.add_option("-v", "--verbose",
- dest="verbose", action="store_true",
- help="Print verbose information")
- parser.add_option("--extra-verbose",
- dest="extra_verbose", action="store_true",
- help="Print extra verbose information")
- (options, args) = parser.parse_args()
- #if len(args) < 2:
- # parser.error("arguments '%s' are required !" % '<output_file> <input_file>')
- if options.extra_verbose:
- options.verbose = True
- ctk_wrap_pythonqt(options.target, options.namespace, options.output_dir, args, options.extra_verbose)
-
- if options.verbose:
- print("Wrapped %d files" % len(args))
|