summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Parente Lima <hugo.pl@gmail.com>2012-02-23 20:35:14 -0200
committerHugo Parente Lima <hugo.pl@gmail.com>2012-02-23 20:35:14 -0200
commitfde271521a750b7d5936435f8fcac4b86c8540f1 (patch)
treeca72de13df2cb2a979419c57ebc7b733cc36fcaf
parent2c198ea403aa6c374bc062f85ac95b61acbb87ae (diff)
parentbbb7d417e75043dec53c84ceafec5c07cc282a81 (diff)
downloadshiboken-master.tar.gz
shiboken-master.tar.xz
shiboken-master.zip
Merge GeneratorRunner project into Shiboken.HEADmaster
This initial merge introduces few regression that can easily be fixed, they are: - You can't choose what generator will be run, it always run CppGenerator and HeaderGenerator. - DummyGenerator test of GeneratorRunner was commented out. The directory structure is also nto ideal and may change a bit in later commits. Conflicts: CMakeLists.txt data/CMakeLists.txt doc/CMakeLists.txt doc/_templates/index.html doc/_templates/layout.html doc/_themes/pysidedocs/static/pysidedocs.css doc/commandlineoptions.rst doc/conf.py.in doc/contents.rst doc/images/bindinggen-development.png doc/images/boostqtarch.png tests/CMakeLists.txt
-rw-r--r--AUTHORS8
-rw-r--r--CMakeLists.txt6
-rw-r--r--Doxyfile311
-rw-r--r--data/GeneratorRunnerConfig.cmake.in17
-rw-r--r--data/GeneratorRunnerConfigVersion.cmake.in10
l---------data/docgenerator.11
-rw-r--r--data/generatorrunner.176
-rw-r--r--data/generatorrunner.pc.in13
-rw-r--r--doc/commandlineoptions.rst70
-rw-r--r--doc/contents.rst2
-rw-r--r--doc/dependency-pyside.svg527
-rw-r--r--doc/images/bindinggen-development.pngbin34333 -> 0 bytes
-rw-r--r--doc/images/bindinggen-development.svg543
-rw-r--r--doc/images/boostqtarch.pngbin34257 -> 0 bytes
-rw-r--r--doc/images/boostqtarch.svg226
-rw-r--r--doc/images/genrunnerarch.pngbin0 -> 68761 bytes
-rw-r--r--doc/images/genrunnerarch.svg654
-rw-r--r--doc/overview.rst46
-rw-r--r--doc/projectfile.rst65
-rw-r--r--generator/CMakeLists.txt36
-rw-r--r--generator/main.cpp53
-rw-r--r--generators/CMakeLists.txt6
-rw-r--r--generators/generator.cpp708
-rw-r--r--generators/generator.h341
-rw-r--r--generators/qtdoc/CMakeLists.txt21
-rw-r--r--generators/qtdoc/main.cpp (renamed from generator/shiboken.cpp)15
-rw-r--r--generators/qtdoc/qtdocgenerator.cpp1652
-rw-r--r--generators/qtdoc/qtdocgenerator.h226
-rw-r--r--generators/shiboken/CMakeLists.txt30
-rw-r--r--generators/shiboken/cppgenerator.cpp (renamed from generator/cppgenerator.cpp)0
-rw-r--r--generators/shiboken/cppgenerator.h (renamed from generator/cppgenerator.h)0
-rw-r--r--generators/shiboken/headergenerator.cpp (renamed from generator/headergenerator.cpp)0
-rw-r--r--generators/shiboken/headergenerator.h (renamed from generator/headergenerator.h)0
-rw-r--r--generators/shiboken/main.cpp471
-rw-r--r--generators/shiboken/overloaddata.cpp (renamed from generator/overloaddata.cpp)0
-rw-r--r--generators/shiboken/overloaddata.h (renamed from generator/overloaddata.h)0
-rw-r--r--generators/shiboken/shibokenconfig.h.in (renamed from generator/shibokenconfig.h.in)0
-rw-r--r--generators/shiboken/shibokengenerator.cpp (renamed from generator/shibokengenerator.cpp)0
-rw-r--r--generators/shiboken/shibokengenerator.h (renamed from generator/shibokengenerator.h)0
-rw-r--r--generators/shiboken/shibokennormalize.cpp (renamed from generator/shibokennormalize.cpp)0
-rw-r--r--generators/shiboken/shibokennormalize_p.h (renamed from generator/shibokennormalize_p.h)0
-rw-r--r--shibokenmodule/CMakeLists.txt2
-rw-r--r--tests/CMakeLists.txt29
-rw-r--r--tests/minimalbinding/CMakeLists.txt2
-rw-r--r--tests/otherbinding/CMakeLists.txt2
-rw-r--r--tests/samplebinding/CMakeLists.txt2
-rw-r--r--tests/sphinxtabletest.cpp327
-rw-r--r--tests/sphinxtabletest.h49
-rw-r--r--tests/test_generator/CMakeLists.txt63
-rw-r--r--tests/test_generator/dummygenerator.cpp64
-rw-r--r--tests/test_generator/dummygenerator.h44
-rw-r--r--tests/test_generator/dummygentest-project.txt.in20
-rw-r--r--tests/test_generator/dummygentest.cpp133
-rw-r--r--tests/test_generator/dummygentest.h51
-rw-r--r--tests/test_generator/dummygentestconfig.h.in15
-rw-r--r--tests/test_generator/main.cpp34
-rw-r--r--tests/test_generator/run_test.cmake11
-rw-r--r--tests/test_generator/test_global.h1
-rw-r--r--tests/test_generator/test_typesystem.xml3
59 files changed, 6885 insertions, 101 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..6e802fb5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,8 @@
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruno Araujo <bruno.araujo@openbossa.org>
+Hugo Parente Lima <hugo.lima@openbossa.org>
+Lauro Moura <lauro.neto@openbossa.org>
+Luciano Wolf <luciano.wolf@openbossa.org>
+Marcelo Lira <marcelo.lira@openbossa.org>
+Renato Araujo Oliveira Filho <renato.filho@openbossa.org>
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba40b23c..58942e66 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules/
find_package(Qt4 4.5.0)
find_package(ApiExtractor 0.10.11 REQUIRED)
-find_package(GeneratorRunner 0.6.17 REQUIRED)
add_definitions(${QT_DEFINITIONS})
@@ -61,6 +60,7 @@ if (WIN32)
else()
set(PATH_SEP ":")
endif()
+set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX})
# uninstall target
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake"
@@ -101,8 +101,8 @@ add_subdirectory(libshiboken)
add_subdirectory(doc)
# deps found, compile the generator.
-if (QT4_FOUND AND ApiExtractor_FOUND AND GeneratorRunner_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND)
- add_subdirectory(generator)
+if (QT4_FOUND AND ApiExtractor_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND)
+ add_subdirectory(generators)
add_subdirectory(shibokenmodule)
if (BUILD_TESTS)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 00000000..9be56a0e
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,311 @@
+# Doxyfile 1.5.7.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "Generator Runner"
+PROJECT_NUMBER = 0.1
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = /tmp/src/generatorrunner/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+TYPEDEF_HIDES_STRUCT = NO
+SYMBOL_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /tmp/src/generatorrunner
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY \
+ *.F90 \
+ *.F \
+ *.VHD \
+ *.VHDL
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+HTML_DYNAMIC_SECTIONS = NO
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHG_LOCATION =
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NONE
+TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES = ../libgenrunner/libgenrunner.tag=../libgenrunner
+GENERATE_TAGFILE = generatorrunner.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+DOT_FONTNAME = FreeSans
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = NO
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/data/GeneratorRunnerConfig.cmake.in b/data/GeneratorRunnerConfig.cmake.in
new file mode 100644
index 00000000..cf973e2a
--- /dev/null
+++ b/data/GeneratorRunnerConfig.cmake.in
@@ -0,0 +1,17 @@
+# GENERATORRUNNER_INCLUDE_DIR - Directories to include to use GENERATORRUNNER
+# GENERATORRUNNER_LIBRARIES - Files to link against to use GENERATORRUNNER
+# GENERATORRUNNER_PLUGIN_DIR - Where to find/put plugins for generator runner
+# GENERATORRUNNER_BINARY - Executable name
+
+SET(GENERATORRUNNER_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include/generatorrunner@generator_SUFFIX@")
+if(MSVC)
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@.lib")
+elseif(CYGWIN)
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_IMPORT_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+elseif(WIN32)
+ SET(GENERATORRUNNER_LIBRARY "@CMAKE_INSTALL_PREFIX@/bin/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+else()
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+endif()
+SET(GENERATORRUNNER_PLUGIN_DIR "@generator_plugin_DIR@")
+SET(GENERATORRUNNER_BINARY "@CMAKE_INSTALL_PREFIX@/bin/generatorrunner@generator_SUFFIX@")
diff --git a/data/GeneratorRunnerConfigVersion.cmake.in b/data/GeneratorRunnerConfigVersion.cmake.in
new file mode 100644
index 00000000..8eb5ba47
--- /dev/null
+++ b/data/GeneratorRunnerConfigVersion.cmake.in
@@ -0,0 +1,10 @@
+set(PACKAGE_VERSION @generator_VERSION@)
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
diff --git a/data/docgenerator.1 b/data/docgenerator.1
new file mode 120000
index 00000000..c65282f9
--- /dev/null
+++ b/data/docgenerator.1
@@ -0,0 +1 @@
+generatorrunner.1 \ No newline at end of file
diff --git a/data/generatorrunner.1 b/data/generatorrunner.1
new file mode 100644
index 00000000..045b55ad
--- /dev/null
+++ b/data/generatorrunner.1
@@ -0,0 +1,76 @@
+.TH GENERATORRUNNER 1 "SEPTEMBER 2009" Linux "User Manuals"
+.SH NAME
+generatorrunner - plugin-based binding source code generator
+.SH SYNOPSIS
+.B generatorrunner \-\-generator-set=<plugin name> [options] header-file typesystem-file
+.SH DESCRIPTION
+.B generatorrunner
+is a utility that uses the information taken from APIExtractor
+related to the provided C++ headers and typesystem files and execute
+generators using this information. Generators are plugins and you need
+to specify one using the \-\-generator-set parameter. At the moment there
+are two generators available:
+
+.B qtdoc
+\- Generates Sphinx-based documentation for C++ libraries documented using
+.B qdoc3
+documentation syntax, using the XML files created by the documentation tool
+.B (qdoc3).
+Can be called supplying
+.B \-\-generator-set=qtdoc
+to
+.B generatorrunner
+or by calling the convenience executable
+.B docgenerator.
+
+Other plugins can be used with
+.B generatorrunner,
+provided that they follow the generator front-end specifications,
+and can be written to generate code or documentation for any target
+languague you desire. For more information about the generator front-end
+architecture and current limitations, refer to http://www.pyside.org/home-binding.
+
+.SH OPTIONS
+.SS "General options"
+.IP \-\-api-version=<version>
+Specify the supported api version used to generate the bindings.
+.IP \-\-debug-level=[sparse|medium|full]
+The amount of messages displayed.
+.IP \-\-documentation-only
+Only generates the documentation.
+.IP \-\-drop-type-entries="<TypeEntry0>[;TypeEntry1;...]"
+Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation.
+.IP \-\-help \fR,\fP \-h \fR,\fP -?
+Prints the usage message.
+.IP \-\-project-file=<file>
+Text file containing a description of the binding project. Replaces and overrides command line arguments.
+.IP \-\-include\-paths=\fI<path>[:path:..]\fR
+The directories where the generator will search for the
+headers. Works like gcc's \-I flag.
+.IP \-\-license\-file=\fI[licensefile]\fR
+Template for copyright headers of generated files.
+.IP \-\-no\-supress\-warnings
+Show all warnings.
+.IP \-\-output\-directory=\fI[dir]\fR
+The directory where the generated files will be written.
+.IP \-\-silent
+Avoid printing any messages.
+.IP \-\-typesytem\-paths=\fI<path>[:path:..]\fR
+The directories where the generator will search for the
+external typesystems referred by the main one.
+.IP \-\-version
+Displays the current version.
+Drops support for named args.
+.SS "Specific to qtdoc plugin"
+.IP \-\-documentation\-code\-snippets\-dir
+Directory used to search code snippets used by the documentation
+.IP \-\-documentation\-data\-dir
+Directory with XML files generated by documentation tool (qdoc3 or Doxygen)
+.IP \-\-documentation\-out\-dir
+The directory where the generated documentation files will be written
+.IP \-\-library\-source\-dir
+Directory where library source code is located
+
+.SH AUTHORS
+Lauro Moura <lauro.neto at openbossa dot org>, Bruno Araujo <bruno.araujo at openbossa dot org>, Hugo Lima <hugo.lima at openbossa dot org>
+
diff --git a/data/generatorrunner.pc.in b/data/generatorrunner.pc.in
new file mode 100644
index 00000000..a566f435
--- /dev/null
+++ b/data/generatorrunner.pc.in
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@CMAKE_INSTALL_PREFIX@/include
+
+
+Name: generatorrunner@generator_SUFFIX@
+Description: Generator Runner loads and calls binding generator front-ends.
+Requires: apiextractor
+Version: @generatorrunner_VERSION@
+Libs: -L${libdir} -lgenrunner@generator_SUFFIX@
+Cflags: -I${includedir}@generator_SUFFIX@
+
diff --git a/doc/commandlineoptions.rst b/doc/commandlineoptions.rst
index 2dacfc13..d373561c 100644
--- a/doc/commandlineoptions.rst
+++ b/doc/commandlineoptions.rst
@@ -1,3 +1,5 @@
+.. _command-line:
+
Command line options
********************
@@ -6,7 +8,7 @@ Usage
::
- shiboken [options]
+ shiboken [options] header-file typesystem-file
Options
@@ -35,3 +37,69 @@ Options
Enable heuristics to detect parent relationship on return values.
For more info, check :ref:`return-value-heuristics`.
+.. _api-version:
+
+``--api-version=<version>``
+ Specify the supported api version used to generate the bindings.
+
+.. _debug-level:
+
+``--debug-level=[sparse|medium|full]``
+ Set the debug level.
+
+.. _documentation-only:
+
+``--documentation-only``
+ Do not generate any code, just the documentation.
+
+.. _drop-type-entries:
+
+``--drop-type-entries="<TypeEntry0>[;TypeEntry1;...]"``
+ Semicolon separated list of type system entries (classes, namespaces,
+ global functions and enums) to be dropped from generation.
+
+.. _generation-set:
+
+``--generation-set``
+ Generator set to be used (e.g. qtdoc).
+
+.. _help:
+
+``--help``
+ Display this help and exit.
+
+.. _include-paths:
+
+``--include-paths=<path>[:<path>:...]``
+ Include paths used by the C++ parser.
+
+.. _license-file=[license-file]:
+
+``--license-file=[license-file]``
+ File used for copyright headers of generated files.
+
+.. _no-suppress-warnings:
+
+``--no-suppress-warnings``
+ Show all warnings.
+
+.. _output-directory:
+
+``--output-directory=[dir]``
+ The directory where the generated files will be written.
+
+.. _silent:
+
+``--silent``
+ Avoid printing any message.
+
+.. _typesystem-paths:
+
+``--typesystem-paths=<path>[:<path>:...]``
+ Paths used when searching for type system files.
+
+.. _version:
+
+``--version``
+ Output version information and exit.
+
diff --git a/doc/contents.rst b/doc/contents.rst
index 03e0eec6..24adb1c6 100644
--- a/doc/contents.rst
+++ b/doc/contents.rst
@@ -5,7 +5,9 @@ Table of contents
:maxdepth: 3
faq.rst
+ overview.rst
commandlineoptions.rst
+ projectfile.rst
typesystemvariables.rst
typeconverters.rst
codeinjectionsemantics.rst
diff --git a/doc/dependency-pyside.svg b/doc/dependency-pyside.svg
new file mode 100644
index 00000000..786bdb8a
--- /dev/null
+++ b/doc/dependency-pyside.svg
@@ -0,0 +1,527 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="900"
+ height="560"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="dependency-pyside.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/tmp/dependency-pyside.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3270"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible">
+ <path
+ id="path3679"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.79440331"
+ inkscape:cx="-36.66006"
+ inkscape:cy="372.04724"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1278"
+ inkscape:window-height="949"
+ inkscape:window-x="0"
+ inkscape:window-y="0">
+ <sodipodi:guide
+ orientation="1,0"
+ position="384.28571,590"
+ id="guide2601" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="678.57143,491.42857"
+ id="guide2603" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="78.571429,257.14286"
+ id="guide2605" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="93.571429,280.71429"
+ id="guide7565" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="148.57143,216.42857"
+ id="guide7567" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-78.088635,-190.95252)" />
+ <g
+ id="g5394"
+ transform="translate(6.1314759,14.304617)">
+ <g
+ transform="translate(-65.84289,-190.95252)"
+ id="g5205">
+ <g
+ id="g5171">
+ <rect
+ rx="9.3643799"
+ y="338.7739"
+ x="678.57141"
+ height="73.281754"
+ width="274.54263"
+ id="rect2393"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="13.104657" />
+ <text
+ id="text2395"
+ y="355.93701"
+ x="683.46539"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="355.93701"
+ x="683.46539"
+ id="tspan2397"
+ sodipodi:role="line">boost::python</tspan></text>
+ <text
+ id="text2399"
+ y="371.60172"
+ x="683.46539"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="371.60172"
+ x="683.46539"
+ id="tspan2401"
+ sodipodi:role="line">1.38.0</tspan></text>
+ <text
+ id="text2403"
+ y="387.14166"
+ x="683.46539"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2435"
+ y="387.14166"
+ x="683.46539"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2413"
+ y="402.4646"
+ x="683.46539"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="402.4646"
+ x="683.46539"
+ id="tspan2415"
+ sodipodi:role="line">Boost Software License 1.0</tspan></text>
+ </g>
+ <g
+ id="g5193">
+ <rect
+ rx="8.3239012"
+ y="342.86383"
+ x="78.571426"
+ height="73.282379"
+ width="274.18781"
+ id="rect2417"
+ style="fill:#b3ff80;fill-rule:evenodd;stroke:#2a7800;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="9.2689295" />
+ <text
+ id="text2419"
+ y="359.67014"
+ x="88.822823"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="359.67014"
+ x="88.822823"
+ id="tspan2421"
+ sodipodi:role="line">Qt 4.5</tspan></text>
+ <text
+ id="text2423"
+ y="375.33484"
+ x="88.822823"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="375.33484"
+ x="88.822823"
+ id="tspan2425"
+ sodipodi:role="line">4.5</tspan></text>
+ <text
+ id="text2427"
+ y="390.87479"
+ x="88.822823"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="390.87479"
+ x="88.822823"
+ id="tspan2429"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2431"
+ y="400.84058"
+ x="88.822823"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="400.84058"
+ x="88.822823"
+ id="tspan2433"
+ sodipodi:role="line">GNU General Public License v3 /</tspan><tspan
+ y="411.1687"
+ x="88.822823"
+ sodipodi:role="line"
+ id="tspan2472">GNU Lesser General Public Licence v2.1</tspan></text>
+ </g>
+ <g
+ id="g5120">
+ <rect
+ y="496.43558"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2441"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="13.104635"
+ rx="10.404889" />
+ <text
+ id="text2443"
+ y="513.59869"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="513.59869"
+ x="389.17969"
+ id="tspan2445"
+ sodipodi:role="line">libapiextractor</tspan></text>
+ <text
+ id="text2447"
+ y="529.26337"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="529.26337"
+ x="389.17969"
+ id="tspan2449"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2451"
+ y="544.80334"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2453"
+ y="544.80334"
+ x="389.17969"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2455"
+ y="560.12628"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="560.12628"
+ x="389.17969"
+ id="tspan2457"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5131">
+ <rect
+ y="340.72134"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2459"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="10.309408"
+ rx="9.3644047" />
+ <text
+ id="text2461"
+ y="357.88449"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="357.88449"
+ x="389.17969"
+ id="tspan2463"
+ sodipodi:role="line">BoostPythonGenerator</tspan></text>
+ <text
+ id="text2465"
+ y="373.54916"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="373.54916"
+ x="389.17969"
+ id="tspan2467"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2469"
+ y="389.08914"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2471"
+ y="389.08914"
+ x="389.17969"
+ sodipodi:role="line">Binary executable - compile-time</tspan></text>
+ <text
+ id="text2473"
+ y="404.41208"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="404.41208"
+ x="389.17969"
+ id="tspan2475"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5142">
+ <rect
+ y="191.43562"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2523"
+ style="fill:#e9ddaf;fill-opacity:1;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="14.285714" />
+ <text
+ id="text2525"
+ y="208.59874"
+ x="389.17966"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="208.59874"
+ x="389.17966"
+ id="tspan2527"
+ sodipodi:role="line">Qt Python bindings</tspan></text>
+ <text
+ id="text2529"
+ y="224.26344"
+ x="389.17966"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="224.26344"
+ x="389.17966"
+ id="tspan2531"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2533"
+ y="239.80339"
+ x="389.17966"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2535"
+ y="239.80339"
+ x="389.17966"
+ sodipodi:role="line">Target</tspan></text>
+ <text
+ id="text2537"
+ y="255.12633"
+ x="389.17966"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="255.12633"
+ x="389.17966"
+ id="tspan2539"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5182">
+ <rect
+ rx="10.404877"
+ y="648.57843"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2563"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="11.287985" />
+ <text
+ id="text2565"
+ y="665.74158"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="665.74158"
+ x="389.17969"
+ id="tspan2567"
+ sodipodi:role="line">boost::graph</tspan></text>
+ <text
+ id="text2569"
+ y="681.40625"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="681.40625"
+ x="389.17969"
+ id="tspan2571"
+ sodipodi:role="line">1.38.0</tspan></text>
+ <text
+ id="text2573"
+ y="696.94623"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2575"
+ y="696.94623"
+ x="389.17969"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2577"
+ y="712.26917"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="712.26917"
+ x="389.17969"
+ id="tspan2579"
+ sodipodi:role="line">Boost Software License 1.0</tspan></text>
+ </g>
+ </g>
+ <path
+ inkscape:connector-type="polyline"
+ id="path2869"
+ d="M 212.85114,151.42852 L 368.56822,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2871"
+ d="M 663.60462,147.33826 L 517.61788,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2877"
+ d="M 443.4684,149.28571 L 443.46839,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2879"
+ d="M 443.4684,304.99994 L 443.4684,223.53367"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2881"
+ d="M 443.4684,457.14279 L 443.4684,379.2479"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:none;stroke-opacity:1" />
+ <rect
+ ry="17.142857"
+ y="293.85626"
+ x="0.48279184"
+ height="124.28571"
+ width="211.42857"
+ id="rect7541"
+ style="fill:#e3e2db;stroke:#000000;stroke-opacity:1" />
+ <text
+ id="text7543"
+ y="325.44049"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="325.44049"
+ x="70.482788"
+ id="tspan7545"
+ sodipodi:role="line">Boost</tspan></text>
+ <text
+ id="text7547"
+ y="358.37042"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="358.37042"
+ x="70.482788"
+ id="tspan7549"
+ sodipodi:role="line">Qt Software</tspan></text>
+ <text
+ id="text7551"
+ y="394.07593"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="394.07593"
+ x="70.482788"
+ id="tspan7553"
+ sodipodi:role="line">INdT/Nokia</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="307.24911"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7555"
+ style="fill:#aaeeff;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ <rect
+ ry="6.4285707"
+ y="341.17767"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7561"
+ style="fill:#b3ff80;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ <rect
+ ry="6.4285707"
+ y="376.17767"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7563"
+ style="fill:#e9ddaf;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/doc/images/bindinggen-development.png b/doc/images/bindinggen-development.png
deleted file mode 100644
index 2dd64ba1..00000000
--- a/doc/images/bindinggen-development.png
+++ /dev/null
Binary files differ
diff --git a/doc/images/bindinggen-development.svg b/doc/images/bindinggen-development.svg
new file mode 100644
index 00000000..3b6b3a26
--- /dev/null
+++ b/doc/images/bindinggen-development.svg
@@ -0,0 +1,543 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="640"
+ height="200"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="bindgen-development.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="bindinggen-development.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="EmptyDiamondL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyDiamondL"
+ style="overflow:visible">
+ <path
+ id="path3930"
+ d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.8,0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="EmptyTriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyTriangleInL"
+ style="overflow:visible">
+ <path
+ id="path3975"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path3835"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.2,0,0,0.2,1.2,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mend"
+ style="overflow:visible">
+ <path
+ id="path3832"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Tail"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Tail"
+ style="overflow:visible">
+ <g
+ id="g3859"
+ transform="scale(-1.2,-1.2)">
+ <path
+ id="path3861"
+ d="M -3.8048674,-3.9585227 L 0.54352094,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3863"
+ d="M -1.2866832,-3.9585227 L 3.0617053,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3865"
+ d="M 1.3053582,-3.9585227 L 5.6537466,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3867"
+ d="M -3.8048674,4.1775838 L 0.54352094,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3869"
+ d="M -1.2866832,4.1775838 L 3.0617053,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3871"
+ d="M 1.3053582,4.1775838 L 5.6537466,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3636"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.0859375"
+ inkscape:cx="320"
+ inkscape:cy="136.17463"
+ inkscape:document-units="px"
+ inkscape:current-layer="g5658"
+ showgrid="false"
+ inkscape:window-width="1156"
+ inkscape:window-height="883"
+ inkscape:window-x="1396"
+ inkscape:window-y="35"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <sodipodi:guide
+ orientation="1,0"
+ position="-557.55608,678.10875"
+ id="guide7299" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-1758.7331,-2056.8567)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3229"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ transform="translate(4.1137413,-2.3429609)"><flowRegion
+ id="flowRegion3231"><rect
+ id="rect3233"
+ width="125.74072"
+ height="40.5849"
+ x="388.45547"
+ y="279.5423" /></flowRegion><flowPara
+ id="flowPara3235" /></flowRoot> <g
+ id="g5658"
+ transform="translate(6.5767925,7.0112479)">
+ <g
+ id="g5634">
+ <g
+ id="g6271"
+ transform="translate(1086.3689,746.93837)">
+ <g
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ id="g6252">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.5317,1300.2858 L 1586.6222,1389.8124"
+ id="path11089"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path2758"
+ d="M 1586.7489,1389.4756 L 1594.7468,1380.3688"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path2760"
+ d="M 1586.6031,1389.5063 L 1578.6052,1380.3994"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(134.35978,44.472131)"
+ id="g2777">
+ <rect
+ style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.82399696;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5172"
+ width="185.49777"
+ height="75.08918"
+ x="2047.775"
+ y="2029.4594"
+ ry="3.0323718"
+ rx="2.6724329" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="2140.5562"
+ y="2062.9375"
+ id="text5174"><tspan
+ sodipodi:role="line"
+ x="2140.5562"
+ y="2062.9375"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan5176">Qt bindings</tspan><tspan
+ id="tspan6109"
+ sodipodi:role="line"
+ x="2140.5562"
+ y="2084.457"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">(generated code)</tspan></text>
+ </g>
+ <g
+ transform="translate(141.86951,-31.391207)"
+ id="g3216">
+ <rect
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.64492828;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3625"
+ width="185.67708"
+ height="75.268074"
+ x="1829.1727"
+ y="2105.2332"
+ ry="2.3353095"
+ rx="2.1257713" />
+ <text
+ xml:space="preserve"
+ style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1921.9705"
+ y="2136.9409"
+ id="text3627"
+ transform="scale(1.0000266,0.9999734)"><tspan
+ id="tspan3697"
+ sodipodi:role="line"
+ x="1921.9705"
+ y="2136.9409"
+ style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">generator</tspan><tspan
+ sodipodi:role="line"
+ x="1921.9705"
+ y="2163.5559"
+ style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan2464">front-end</tspan></text>
+ </g>
+ <g
+ id="g5641">
+ <g
+ id="g5465"
+ transform="translate(874.42628,746.93837)">
+ <g
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ id="g5467">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.5317,1300.2858 L 1586.6222,1389.8124"
+ id="path5469"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5471"
+ d="M 1586.7489,1389.4756 L 1594.7468,1380.3688"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5473"
+ d="M 1586.6031,1389.5063 L 1578.6052,1380.3994"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(-194.79968,-212.08495)"
+ id="g5440">
+ <rect
+ rx="1.2158648"
+ ry="2.9911308"
+ y="2285.8806"
+ x="1953.809"
+ height="75.360634"
+ width="185.76964"
+ id="rect3166"
+ style="fill:#dfe994;fill-opacity:1;stroke:#d5f400;stroke-width:0.55236381;stroke-opacity:1" />
+ <text
+ id="text3168"
+ y="2328.8809"
+ x="2046.646"
+ style="font-size:27.94354057px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ style="font-size:19.56047821px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="2328.8809"
+ x="2046.646"
+ sodipodi:role="line"
+ id="tspan5424">API Extractor</tspan></text>
+ </g>
+ <g
+ transform="translate(-102.30216,-279.71223)"
+ id="g5541">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5535"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1946.3259"
+ y="2435.7"
+ id="text5537"><tspan
+ sodipodi:role="line"
+ id="tspan5539"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">1</tspan></text>
+ </g>
+ <g
+ transform="translate(52.589867,-352.69787)"
+ id="g5546">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5548"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1946.3259"
+ y="2435.7"
+ id="text5550"><tspan
+ sodipodi:role="line"
+ id="tspan5552"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">2</tspan></text>
+ </g>
+ <g
+ transform="matrix(0,-1,1,0,697.50638,3244.256)"
+ id="g5624">
+ <g
+ id="g5626"
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5628"
+ d="M 1586.5317,1348.2858 L 1586.6222,1389.8124"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.7489,1389.4756 L 1594.7468,1380.3688"
+ id="path5630"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.6031,1389.5063 L 1578.6052,1380.3994"
+ id="path5632"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <g
+ transform="translate(5.3442137,15.993306)"
+ id="g5459">
+ <rect
+ rx="2.4652832"
+ ry="2.9818845"
+ y="2151.3206"
+ x="1965.7682"
+ height="75.127686"
+ width="185.53668"
+ id="rect3485"
+ style="fill:#b2e994;fill-opacity:1;stroke:#56f400;stroke-width:0.78531456;stroke-opacity:1" />
+ <text
+ id="text3487"
+ y="2184.2461"
+ x="2059.1909"
+ style="font-size:27.94354057px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2509"
+ style="font-size:19.56047821px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="2184.2461"
+ x="2059.1909"
+ sodipodi:role="line">typesystem</tspan><tspan
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="2205.1477"
+ x="2059.1909"
+ sodipodi:role="line"
+ id="tspan5432">(handwritten)</tspan></text>
+ </g>
+ <g
+ transform="matrix(0,-1,1,0,908.50929,3242.9612)"
+ id="g5648">
+ <g
+ id="g5650"
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5652"
+ d="M 1586.5317,1348.2858 L 1586.6222,1389.8124"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.7489,1389.4756 L 1594.7468,1380.3688"
+ id="path5654"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ d="M 1586.6031,1389.5063 L 1578.6052,1380.3994"
+ id="path5656"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <g
+ transform="translate(299.78191,21.148391)"
+ id="g2771">
+ <rect
+ style="fill:#cce994;fill-opacity:1;stroke:#a1f400;stroke-width:0.62429351;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2733"
+ width="185.69771"
+ height="75.288704"
+ x="1882.2529"
+ y="2146.085"
+ ry="2.2607138"
+ rx="2.0576432" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1975.134"
+ y="2180.2722"
+ id="text2735"><tspan
+ sodipodi:role="line"
+ x="1975.134"
+ y="2180.2722"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan2737">injected code</tspan><tspan
+ id="tspan2743"
+ sodipodi:role="line"
+ x="1975.134"
+ y="2201.7917"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">(handwritten)</tspan></text>
+ </g>
+ <g
+ transform="translate(200.4676,-222.96766)"
+ id="g5554">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5556"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1946.3259"
+ y="2435.7"
+ id="text5558"><tspan
+ sodipodi:role="line"
+ id="tspan5560"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">3</tspan></text>
+ </g>
+ <g
+ transform="translate(413.633,-206.84535)"
+ id="g5562">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5564"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="1946.3259"
+ y="2435.7"
+ id="text5566"><tspan
+ sodipodi:role="line"
+ id="tspan5568"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">4</tspan></text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/images/boostqtarch.png b/doc/images/boostqtarch.png
deleted file mode 100644
index f1b145e9..00000000
--- a/doc/images/boostqtarch.png
+++ /dev/null
Binary files differ
diff --git a/doc/images/boostqtarch.svg b/doc/images/boostqtarch.svg
new file mode 100644
index 00000000..9fbb3827
--- /dev/null
+++ b/doc/images/boostqtarch.svg
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="350"
+ height="220"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="boostqtarch.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="boostqtarch.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3636"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4812981"
+ inkscape:cx="145.70936"
+ inkscape:cy="94.089827"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1278"
+ inkscape:window-height="951"
+ inkscape:window-x="1592"
+ inkscape:window-y="29"
+ showguides="true"
+ inkscape:guide-bbox="true" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-61.076804,-301.50489)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3229"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ transform="translate(2.0918751e-6,-6.0000008)"><flowRegion
+ id="flowRegion3231"><rect
+ id="rect3233"
+ width="125.74072"
+ height="40.5849"
+ x="388.45547"
+ y="279.5423" /></flowRegion><flowPara
+ id="flowPara3235" /></flowRoot> <g
+ id="g3010"
+ transform="matrix(0.9508755,0,0,0.9508755,11.317746,20.273572)">
+ <g
+ transform="translate(0,-9.7919846e-6)"
+ id="g2952">
+ <rect
+ style="fill:#dfe994;fill-opacity:1;stroke:#d5f400;stroke-width:0.7162478;stroke-opacity:1"
+ id="rect3166"
+ width="349.23203"
+ height="67.403336"
+ x="61.417336"
+ y="377.74161"
+ ry="2.6752985"
+ rx="2.285728" />
+ <text
+ xml:space="preserve"
+ style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="236.08904"
+ y="397.98755"
+ id="text3168"><tspan
+ sodipodi:role="line"
+ x="236.08904"
+ y="397.98755"
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan3176">Boost::Python</tspan><tspan
+ sodipodi:role="line"
+ x="236.08904"
+ y="418.35535"
+ style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan2880">helper library to interface with CPython API</tspan><tspan
+ id="tspan2922"
+ sodipodi:role="line"
+ x="236.08904"
+ y="437.36487"
+ style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and expose C++ entities to Python</tspan></text>
+ </g>
+ <g
+ transform="translate(0,-9.7025776e-6)"
+ id="g2959">
+ <rect
+ style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.71624762;stroke-opacity:1"
+ id="rect3542"
+ width="349.23203"
+ height="67.403351"
+ x="61.417336"
+ y="301.84543"
+ ry="2.675298"
+ rx="2.285728" />
+ <text
+ xml:space="preserve"
+ style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="236.5123"
+ y="322.09137"
+ id="text3544"><tspan
+ id="tspan3596"
+ sodipodi:role="line"
+ x="236.5123"
+ y="322.09137"
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">Qt-Python Bindings</tspan><tspan
+ sodipodi:role="line"
+ x="236.5123"
+ y="342.45917"
+ style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan12937">Qt classes and functions</tspan><tspan
+ sodipodi:role="line"
+ x="236.5123"
+ y="361.46869"
+ style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan2411">exported to Python</tspan></text>
+ </g>
+ <g
+ id="g2998">
+ <g
+ id="g2986">
+ <rect
+ rx="2.285728"
+ ry="2.675298"
+ y="453.63776"
+ x="61.417336"
+ height="67.403336"
+ width="172.02341"
+ id="rect3485"
+ style="fill:#b2e994;fill-opacity:1;stroke:#56f400;stroke-width:0.71624762;stroke-opacity:1" />
+ <text
+ id="text3487"
+ y="482.29712"
+ x="147.73038"
+ style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="482.29712"
+ x="147.73038"
+ sodipodi:role="line"
+ id="tspan3499">CPython</tspan><tspan
+ id="tspan2509"
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="508.01089"
+ x="147.73038"
+ sodipodi:role="line">API</tspan></text>
+ </g>
+ <g
+ id="g2992">
+ <rect
+ rx="2.285728"
+ ry="2.675298"
+ y="453.63776"
+ x="239.30101"
+ height="67.403351"
+ width="172.02295"
+ id="rect2459"
+ style="fill:#cce994;fill-opacity:1;stroke:#a1f400;stroke-width:0.71624762;stroke-opacity:1" />
+ <text
+ id="text2461"
+ y="481.97067"
+ x="324.86047"
+ style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="481.97067"
+ x="324.86047"
+ sodipodi:role="line"
+ id="tspan2467">Qt4</tspan><tspan
+ id="tspan2490"
+ style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="507.68445"
+ x="324.86047"
+ sodipodi:role="line">Libraries</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/images/genrunnerarch.png b/doc/images/genrunnerarch.png
new file mode 100644
index 00000000..db1077cd
--- /dev/null
+++ b/doc/images/genrunnerarch.png
Binary files differ
diff --git a/doc/images/genrunnerarch.svg b/doc/images/genrunnerarch.svg
new file mode 100644
index 00000000..ea7eb73e
--- /dev/null
+++ b/doc/images/genrunnerarch.svg
@@ -0,0 +1,654 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="980"
+ height="380"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47pre4 r22446"
+ version="1.0"
+ sodipodi:docname="genrunnerarch.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="genrunnerarch.png"
+ inkscape:export-xdpi="56.549999"
+ inkscape:export-ydpi="56.549999">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="EmptyDiamondL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyDiamondL"
+ style="overflow:visible">
+ <path
+ id="path3930"
+ d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.8,0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="EmptyTriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyTriangleInL"
+ style="overflow:visible">
+ <path
+ id="path3975"
+ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path3835"
+ d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.2,0,0,0.2,1.2,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mend"
+ style="overflow:visible">
+ <path
+ id="path3832"
+ d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Tail"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Tail"
+ style="overflow:visible">
+ <g
+ id="g3859"
+ transform="scale(-1.2,-1.2)">
+ <path
+ id="path3861"
+ d="M -3.8048674,-3.9585227 0.54352094,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3863"
+ d="M -1.2866832,-3.9585227 3.0617053,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3865"
+ d="M 1.3053582,-3.9585227 5.6537466,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3867"
+ d="M -3.8048674,4.1775838 0.54352094,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3869"
+ d="M -1.2866832,4.1775838 3.0617053,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3871"
+ d="M 1.3053582,4.1775838 5.6537466,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3636"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective3033"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3881"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3915"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3956"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective5100"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective5322"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective5365"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective5391"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <marker
+ inkscape:stockid="EmptyTriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyTriangleInL-4"
+ style="overflow:visible">
+ <path
+ id="path3975-9"
+ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
+ </marker>
+ <inkscape:perspective
+ id="perspective5621"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective5643"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <marker
+ inkscape:stockid="EmptyDiamondL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyDiamondL-7"
+ style="overflow:visible">
+ <path
+ id="path3930-7"
+ d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.8,0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.0716799"
+ inkscape:cx="460.27913"
+ inkscape:cy="148.01364"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1862"
+ inkscape:window-height="1019"
+ inkscape:window-x="20"
+ inkscape:window-y="89"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(472.44407,-697.53823)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3229"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ transform="translate(2.0918751e-6,-6.0000008)"><flowRegion
+ id="flowRegion3231"><rect
+ id="rect3233"
+ width="125.74072"
+ height="40.5849"
+ x="388.45547"
+ y="279.5423" /></flowRegion><flowPara
+ id="flowPara3235" /></flowRoot> <g
+ id="g5867"
+ transform="translate(6.7062969,-7.6922472)">
+ <rect
+ rx="3.4968286"
+ ry="5.2462597"
+ y="713.31403"
+ x="-472.05276"
+ height="363.61459"
+ width="393.78473"
+ id="rect3609"
+ style="fill:#e4fae3;fill-opacity:0.65882353;stroke:#8eff89;stroke-width:0.78260708;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ transform="scale(1.0000266,0.9999734)"
+ id="text3601"
+ y="742.43872"
+ x="-275.16165"
+ style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3605"
+ style="font-size:27.09890556px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="742.43872"
+ x="-275.16165"
+ sodipodi:role="line"><tspan
+ id="tspan2508"
+ style="font-weight:bold">API Extractor</tspan></tspan></text>
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-587.62742,-106.48682)"
+ id="g3763">
+ <rect
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.79775763;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3737"
+ width="244.82956"
+ height="101.59812"
+ x="267.06232"
+ y="905.13727"
+ ry="3.1522403"
+ rx="2.4096873" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="389.39117"
+ y="931.86993"
+ id="text3739"><tspan
+ sodipodi:role="line"
+ x="389.39117"
+ y="931.86993"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan3741">ApiExtractor</tspan><tspan
+ id="tspan2523"
+ sodipodi:role="line"
+ x="389.39117"
+ y="953.38947"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">commands the parsing and</tspan><tspan
+ id="tspan2517"
+ sodipodi:role="line"
+ x="389.39117"
+ y="973.38947"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">building of the data model</tspan><tspan
+ id="tspan2519"
+ sodipodi:role="line"
+ x="389.39117"
+ y="993.38947"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and calls the user generators</tspan></text>
+ </g>
+ <rect
+ rx="2.1814992"
+ ry="5.2485871"
+ y="713.45312"
+ x="219.72128"
+ height="363.77597"
+ width="274.11292"
+ id="rect9190"
+ style="fill:#b8d1f1;fill-opacity:0.51184836;stroke:#0045a4;stroke-width:0.6182732;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ transform="scale(1.0000266,0.9999734)"
+ id="text9192"
+ y="742.66901"
+ x="357.65579"
+ style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#002e7a;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan9194"
+ style="font-size:27.09890556px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002e7a;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="742.66901"
+ x="357.65579"
+ sodipodi:role="line"><tspan
+ id="tspan2512"
+ style="font-weight:bold;fill:#002e7a;fill-opacity:1">front-end</tspan><tspan
+ id="tspan2514"
+ style="font-size:22px;fill:#002e7a;fill-opacity:1" /></tspan></text>
+ <rect
+ rx="2.2192271"
+ ry="5.2485123"
+ y="713.23639"
+ x="-68.659073"
+ height="363.77075"
+ width="278.85358"
+ id="rect9190-9"
+ style="fill:#cbe990;fill-opacity:0.51184836;stroke:#6ca400;stroke-width:0.62359226;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ transform="scale(1.0000266,0.9999734)"
+ id="text9192-3"
+ y="741.71094"
+ x="70.291061"
+ style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan9194-7"
+ style="font-size:26px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ y="741.71094"
+ x="70.291061"
+ sodipodi:role="line">Generator Runner</tspan></text>
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-687.04869,-241.74888)"
+ id="g9234-4">
+ <rect
+ style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.73640609;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect9206-4"
+ width="218.17299"
+ height="83.517967"
+ x="694.6994"
+ y="1044.8701"
+ ry="2.5912752"
+ rx="2.4978092" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="803.78589"
+ y="1072.3693"
+ id="text9208-3"><tspan
+ sodipodi:role="line"
+ x="803.78589"
+ y="1072.3693"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan9210-0">Generator</tspan><tspan
+ id="tspan9222-8"
+ sodipodi:role="line"
+ x="803.78589"
+ y="1093.8888"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">base class for front-end</tspan><tspan
+ id="tspan3946"
+ sodipodi:role="line"
+ x="803.78589"
+ y="1113.8888"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">output classes</tspan></text>
+ </g>
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-726.09128,-46.791689)"
+ id="g10497-6">
+ <rect
+ style="fill:#89b3e7;fill-opacity:1;stroke:#0049a4;stroke-width:1.04736876;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect10444-8"
+ width="256.05252"
+ height="143.95157"
+ x="990.81482"
+ y="843.58032"
+ ry="4.4663219"
+ rx="2.9314826" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="1118.0945"
+ y="873.04047"
+ id="text10446-8"><tspan
+ sodipodi:role="line"
+ x="1118.0945"
+ y="873.04047"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan10448-4">SpecificGenerator</tspan><tspan
+ id="tspan4063"
+ sodipodi:role="line"
+ x="1118.0945"
+ y="894.56"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">generators written for any</tspan><tspan
+ id="tspan5381"
+ sodipodi:role="line"
+ x="1118.0945"
+ y="914.56"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">desired output,</tspan><tspan
+ id="tspan4065"
+ sodipodi:role="line"
+ x="1118.0945"
+ y="934.56"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"> e.g.: HppGenerator,</tspan><tspan
+ id="tspan4071"
+ sodipodi:role="line"
+ x="1118.0945"
+ y="954.56"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">CppGenerator,</tspan><tspan
+ id="tspan4073"
+ sodipodi:role="line"
+ x="1118.0945"
+ y="974.56"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#002758;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">ConverterGenerator</tspan></text>
+ </g>
+ <path
+ sodipodi:nodetypes="cc"
+ transform="translate(109.91989,748.26874)"
+ id="path4056"
+ d="m -201.98482,41.728896 76.97065,5e-6"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 1;stroke-dashoffset:0" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4056-2"
+ d="m 197.04022,787.89746 35.38656,0"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#EmptyTriangleInL)" />
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-1010.4541,91.401187)"
+ id="g10497">
+ <rect
+ style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.88060772;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect10444"
+ width="256.21927"
+ height="101.69494"
+ x="990.73145"
+ y="843.49695"
+ ry="3.1552441"
+ rx="2.9333918" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:start;text-anchor:start;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="1012.22"
+ y="870.08466"
+ id="text10446"><tspan
+ sodipodi:role="line"
+ x="1012.22"
+ y="870.08466"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;text-anchor:start;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan10448">Generator App</tspan><tspan
+ id="tspan10456"
+ sodipodi:role="line"
+ x="1012.22"
+ y="891.60419"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">* loads generators</tspan><tspan
+ id="tspan5353"
+ sodipodi:role="line"
+ x="1012.22"
+ y="911.60419"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">* setup API Extractor</tspan><tspan
+ id="tspan5355"
+ sodipodi:role="line"
+ x="1012.22"
+ y="931.60419"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">* executes each generator</tspan></text>
+ </g>
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4056-9"
+ d="m 72.409302,850.57374 0,56.99122"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 1;stroke-dashoffset:0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path4056-2-0"
+ d="m -86.437722,825.54499 52.188784,0 0.06367,81.67009"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#EmptyDiamondL)" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4056-91"
+ d="m -394.83596,853.70064 0,121.42437"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 1;stroke-dashoffset:0" />
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-707.18032,-153.53291)"
+ id="g3809">
+ <rect
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:1.00168562;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3785"
+ width="332.48172"
+ height="82.830231"
+ x="302.83319"
+ y="1068.9153"
+ ry="3.1461167"
+ rx="3.8065021" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="469.03497"
+ y="1095.5493"
+ id="text3787"><tspan
+ id="tspan3791"
+ sodipodi:role="line"
+ x="469.03497"
+ y="1095.5493"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">AbstractMetaBuilder</tspan><tspan
+ sodipodi:role="line"
+ x="469.03497"
+ y="1117.0688"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan3807">builds the data model with information</tspan><tspan
+ id="tspan2545"
+ sodipodi:role="line"
+ x="469.03497"
+ y="1137.0688"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">from headers and binding directives</tspan><tspan
+ id="tspan3795"
+ sodipodi:role="line"
+ x="469.03497"
+ y="1157.0688"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></text>
+ </g>
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-755.89347,194.37862)"
+ id="g3709">
+ <rect
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.69825613;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2821"
+ width="198.90968"
+ height="93.892342"
+ x="305.2475"
+ y="807.38849"
+ ry="2.6812849"
+ rx="2.1703238" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="405.17499"
+ y="831.81903"
+ id="text3611"><tspan
+ id="tspan3687"
+ sodipodi:role="line"
+ x="405.17499"
+ y="831.81903"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">TypeDatabase</tspan><tspan
+ id="tspan5641"
+ sodipodi:role="line"
+ x="405.17499"
+ y="853.33856"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">parses typesystem</tspan><tspan
+ id="tspan3689"
+ sodipodi:role="line"
+ x="405.17499"
+ y="873.33856"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and stores information</tspan></text>
+ </g>
+ <g
+ transform="matrix(0.9678438,0,0,0.9677923,-589.50555,-13.923919)"
+ id="g3728">
+ <rect
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.54871088;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3625"
+ width="117.15066"
+ height="86.355225"
+ x="133.25664"
+ y="809.36938"
+ ry="2.6793056"
+ rx="1.3412292" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="191.58197"
+ y="838.75159"
+ id="text3627"><tspan
+ sodipodi:role="line"
+ x="191.58197"
+ y="838.75159"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ id="tspan3631">Parser</tspan><tspan
+ id="tspan3695"
+ sodipodi:role="line"
+ x="191.58197"
+ y="860.27112"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">parses the</tspan><tspan
+ id="tspan3697"
+ sodipodi:role="line"
+ x="191.58197"
+ y="880.27112"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">lib headers</tspan></text>
+ </g>
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path4056-2-0-1"
+ d="m 197.39006,961.71122 158.27877,0 0.19429,-51.88885"
+ style="fill:none;stroke:#000000;stroke-width:1.38812411;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.32874408, 1.38812401;stroke-dashoffset:0;marker-start:none" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644
index 00000000..5f50610f
--- /dev/null
+++ b/doc/overview.rst
@@ -0,0 +1,46 @@
+.. _gen-overview:
+
+******************
+Generator Overview
+******************
+
+In a few words, the Generator is a utility that parses a collection of header and
+typesystem files, generating other files (code, documentation, etc.) as result.
+
+Creating new bindings
+=====================
+
+.. figure:: images/bindinggen-development.png
+ :scale: 80
+ :align: center
+
+ Creating new bindings
+
+Each module of the generator system has an specific role.
+
+1. Provide enough data about the classes and functions.
+2. Generate valid code, with modifications from typesystems and injected codes.
+3. Modify the API to expose the objects in a way that fits you target language best.
+4. Insert customizations where handwritten code is needed.
+
+.. figure:: images/boostqtarch.png
+ :scale: 80
+ :align: center
+
+ Runtime architecture
+
+The newly created binding will run on top of Boost.Python library which takes
+care of interfacing Python and the underlying C++ library.
+
+Handwritten inputs
+==================
+
+Creating new bindings involves creating two pieces of "code": the typesystem and
+the inject code.
+
+:typesystem: XML files that provides the developer with a tool to customize the
+ way that the generators will see the classes and functions. For
+ example, functions can be renamed, have its signature changed and
+ many other actions.
+:inject code: allows the developer to insert handwritten code where the generated
+ code is not suitable or needs some customization.
diff --git a/doc/projectfile.rst b/doc/projectfile.rst
new file mode 100644
index 00000000..6c9808da
--- /dev/null
+++ b/doc/projectfile.rst
@@ -0,0 +1,65 @@
+.. _project-file:
+
+********************
+Binding Project File
+********************
+
+Instead of directing the Generator behaviour via command line, the binding developer
+can write a text project file describing the same information, and avoid the hassle
+of a long stream of command line arguments.
+
+.. _project-file-structure:
+
+The project file structure
+==========================
+
+Here follows a comprehensive example of a generator project file.
+
+ .. code-block:: ini
+
+ [generator-project]
+ generator-set = path/to/generator/CHOICE_GENERATOR
+ header-file = DIR/global.h" />
+ typesystem-file = DIR/typesystem_for_your_binding.xml
+ output-directory location="OUTPUTDIR" />
+ include-path = path/to/library/being/wrapped/headers/1
+ include-path = path/to/library/being/wrapped/headers/2
+ typesystem-path = path/to/directory/containing/type/system/files/1
+ typesystem-path = path/to/directory/containing/type/system/files/2
+ enable-parent-ctor-heuristic
+
+
+Project file tags
+=================
+
+The generator project file tags are in direct relation to the
+:ref:`command line arguments <command-line>`. All of the current command line
+options provided by |project| were already seen on the :ref:`project-file-structure`,
+for new command line options provided by additional generator modules (e.g.: qtdoc,
+Shiboken) could also be used in the generator project file following simple conversion rules.
+
+For tags without options, just write as an empty tag without any attributes. Example:
+
+ .. code-block:: bash
+
+ --BOOLEAN-ARGUMENT
+
+becomes
+
+ .. code-block:: ini
+
+ BOOLEAN-ARGUMENT
+
+and
+
+ .. code-block:: bash
+
+ --VALUE-ARGUMENT=VALUE
+
+becomes
+
+ .. code-block:: ini
+
+ VALUE-ARGUMENT = VALUE
+
+
diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt
deleted file mode 100644
index f3cbe084..00000000
--- a/generator/CMakeLists.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-project(generators)
-
-set(shiboken_SRC
-cppgenerator.cpp
-headergenerator.cpp
-overloaddata.cpp
-shiboken.cpp
-shibokengenerator.cpp
-shibokennormalize.cpp
-)
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_BINARY_DIR}
- ${APIEXTRACTOR_INCLUDE_DIR}
- ${GENERATORRUNNER_INCLUDE_DIR}
- ${QT_INCLUDE_DIR}
- ${QT_QTCORE_INCLUDE_DIR})
-
-add_library(shiboken_generator SHARED ${shiboken_SRC})
-set_property(TARGET shiboken_generator PROPERTY PREFIX "")
-
-target_link_libraries(shiboken_generator
- ${APIEXTRACTOR_LIBRARY}
- ${GENERATORRUNNER_LIBRARY}
- ${QT_QTCORE_LIBRARY})
-
-configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
-
-add_executable(shiboken main.cpp)
-set_target_properties(shiboken PROPERTIES OUTPUT_NAME shiboken${shiboken_SUFFIX})
-target_link_libraries(shiboken ${QT_QTCORE_LIBRARY})
-
-add_dependencies(shiboken shiboken_generator)
-
-install(TARGETS shiboken_generator DESTINATION "${GENERATORRUNNER_PLUGIN_DIR}")
-install(TARGETS shiboken DESTINATION bin)
diff --git a/generator/main.cpp b/generator/main.cpp
deleted file mode 100644
index 75f3171a..00000000
--- a/generator/main.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of the Shiboken Python Bindings Generator project.
- *
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
- *
- * Contact: PySide team <contact@pyside.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include "shibokenconfig.h"
-#include <iostream>
-#include <QtCore>
-
-int main(int argc, char* argv[])
-{
- QStringList args;
- args.append("--generator-set=shiboken");
- for (int i = 1; i < argc; i++) {
- if (QString("--version") == argv[i]) {
- std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl;
- std::cout << "Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)" << std::endl;
- return EXIT_SUCCESS;
- }
- args.append(argv[i]);
- }
-
- /* This will be necessary when the Generatorrunner calls the printUsage()
- * function and the message that'll printed on the screen shows "shiboken"
- * instead of "generator".
- *
- * Note: this argument doesn't do anything else other than just to set up
- * the message that will be printed on the screen when calling printUsage()
- * from Generatorrunner.
- */
- args.append("--alias-name=shiboken");
-
- return QProcess::execute(GENERATOR_BINARY, args);
-}
-
diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt
new file mode 100644
index 00000000..07720ff5
--- /dev/null
+++ b/generators/CMakeLists.txt
@@ -0,0 +1,6 @@
+project(generators)
+
+# if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED)
+# add_subdirectory(qtdoc)
+# endif()
+add_subdirectory(shiboken)
diff --git a/generators/generator.cpp b/generators/generator.cpp
new file mode 100644
index 00000000..9f81b93a
--- /dev/null
+++ b/generators/generator.cpp
@@ -0,0 +1,708 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "generator.h"
+#include "reporthandler.h"
+#include "fileout.h"
+#include "apiextractor.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QDebug>
+#include <typedatabase.h>
+
+struct Generator::GeneratorPrivate {
+ const ApiExtractor* apiextractor;
+ QString outDir;
+ // License comment
+ QString licenseComment;
+ QString packageName;
+ int numGenerated;
+ int numGeneratedWritten;
+ QStringList instantiatedContainersNames;
+ QList<const AbstractMetaType*> instantiatedContainers;
+};
+
+Generator::Generator() : m_d(new GeneratorPrivate)
+{
+ m_d->numGenerated = 0;
+ m_d->numGeneratedWritten = 0;
+ m_d->instantiatedContainers = QList<const AbstractMetaType*>();
+ m_d->instantiatedContainersNames = QStringList();
+}
+
+Generator::~Generator()
+{
+ delete m_d;
+}
+
+bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args)
+{
+ m_d->apiextractor = &extractor;
+ TypeEntryHash allEntries = TypeDatabase::instance()->allEntries();
+ TypeEntry* entryFound = 0;
+ foreach (QList<TypeEntry*> entryList, allEntries.values()) {
+ foreach (TypeEntry* entry, entryList) {
+ if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
+ entryFound = entry;
+ break;
+ }
+ }
+ if (entryFound)
+ break;
+ }
+ if (entryFound)
+ m_d->packageName = entryFound->name();
+ else
+ ReportHandler::warning("Couldn't find the package name!!");
+
+ collectInstantiatedContainers();
+
+ return doSetup(args);
+}
+
+QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type)
+{
+ if (!type->typeEntry()->isContainer())
+ return type->cppSignature();
+ QString typeName = type->cppSignature();
+ if (type->isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (type->isReference())
+ typeName.chop(1);
+ while (typeName.endsWith('*') || typeName.endsWith(' '))
+ typeName.chop(1);
+ return typeName;
+}
+
+void Generator::addInstantiatedContainers(const AbstractMetaType* type)
+{
+ if (!type)
+ return;
+ foreach (const AbstractMetaType* t, type->instantiations())
+ addInstantiatedContainers(t);
+ if (!type->typeEntry()->isContainer())
+ return;
+ QString typeName = getSimplifiedContainerTypeName(type);
+ if (!m_d->instantiatedContainersNames.contains(typeName)) {
+ m_d->instantiatedContainersNames.append(typeName);
+ m_d->instantiatedContainers.append(type);
+ }
+}
+
+void Generator::collectInstantiatedContainers(const AbstractMetaFunction* func)
+{
+ addInstantiatedContainers(func->type());
+ foreach (const AbstractMetaArgument* arg, func->arguments())
+ addInstantiatedContainers(arg->type());
+}
+
+void Generator::collectInstantiatedContainers(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ foreach (const AbstractMetaFunction* func, metaClass->functions())
+ collectInstantiatedContainers(func);
+ foreach (const AbstractMetaField* field, metaClass->fields())
+ addInstantiatedContainers(field->type());
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses())
+ collectInstantiatedContainers(innerClass);
+}
+
+void Generator::collectInstantiatedContainers()
+{
+ foreach (const AbstractMetaFunction* func, globalFunctions())
+ collectInstantiatedContainers(func);
+ foreach (const AbstractMetaClass* metaClass, classes())
+ collectInstantiatedContainers(metaClass);
+}
+
+QList<const AbstractMetaType*> Generator::instantiatedContainers() const
+{
+ return m_d->instantiatedContainers;
+}
+
+QMap< QString, QString > Generator::options() const
+{
+ return QMap<QString, QString>();
+}
+
+AbstractMetaClassList Generator::classes() const
+{
+ return m_d->apiextractor->classes();
+}
+
+AbstractMetaFunctionList Generator::globalFunctions() const
+{
+ return m_d->apiextractor->globalFunctions();
+}
+
+AbstractMetaEnumList Generator::globalEnums() const
+{
+ return m_d->apiextractor->globalEnums();
+}
+
+QList<const PrimitiveTypeEntry*> Generator::primitiveTypes() const
+{
+ return m_d->apiextractor->primitiveTypes();
+}
+
+QList<const ContainerTypeEntry*> Generator::containerTypes() const
+{
+ return m_d->apiextractor->containerTypes();
+}
+
+const AbstractMetaEnum* Generator::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
+{
+ return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
+}
+
+const AbstractMetaEnum* Generator::findAbstractMetaEnum(const TypeEntry* typeEntry) const
+{
+ return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
+}
+
+const AbstractMetaEnum* Generator::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
+{
+ return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
+}
+
+const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* metaType) const
+{
+ return m_d->apiextractor->findAbstractMetaEnum(metaType);
+}
+
+QSet< QString > Generator::qtMetaTypeDeclaredTypeNames() const
+{
+ return m_d->apiextractor->qtMetaTypeDeclaredTypeNames();
+}
+
+QString Generator::licenseComment() const
+{
+ return m_d->licenseComment;
+}
+
+void Generator::setLicenseComment(const QString& licenseComment)
+{
+ m_d->licenseComment = licenseComment;
+}
+
+QString Generator::packageName() const
+{
+ return m_d->packageName;
+}
+
+QString Generator::moduleName() const
+{
+ QString& pkgName = m_d->packageName;
+ return QString(pkgName).remove(0, pkgName.lastIndexOf('.') + 1);
+}
+
+QString Generator::outputDirectory() const
+{
+ return m_d->outDir;
+}
+
+void Generator::setOutputDirectory(const QString &outDir)
+{
+ m_d->outDir = outDir;
+}
+
+int Generator::numGenerated() const
+{
+ return m_d->numGenerated;
+}
+
+int Generator::numGeneratedAndWritten() const
+{
+ return m_d->numGeneratedWritten;
+}
+
+void Generator::generate()
+{
+ foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) {
+ if (!shouldGenerate(cls))
+ continue;
+
+ QString fileName = fileNameForClass(cls);
+ if (fileName.isNull())
+ continue;
+ ReportHandler::debugSparse(QString("generating: %1").arg(fileName));
+
+ FileOut fileOut(outputDirectory() + '/' + subDirectoryForClass(cls) + '/' + fileName);
+ generateClass(fileOut.stream, cls);
+
+ if (fileOut.done())
+ ++m_d->numGeneratedWritten;
+ ++m_d->numGenerated;
+ }
+ finishGeneration();
+}
+
+bool Generator::shouldGenerateTypeEntry(const TypeEntry* type) const
+{
+ return type->codeGeneration() & TypeEntry::GenerateTargetLang;
+}
+
+bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
+{
+ return shouldGenerateTypeEntry(metaClass->typeEntry());
+}
+
+void verifyDirectoryFor(const QFile &file)
+{
+ QDir dir = QFileInfo(file).dir();
+ if (!dir.exists()) {
+ if (!dir.mkpath(dir.absolutePath()))
+ ReportHandler::warning(QString("unable to create directory '%1'")
+ .arg(dir.absolutePath()));
+ }
+}
+
+void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func)
+{
+ const AbstractMetaClass *cpp_class = func->ownerClass();
+ if (cpp_class)
+ code.replace("%TYPE", cpp_class->name());
+
+ foreach (AbstractMetaArgument *arg, func->arguments())
+ code.replace("%" + QString::number(arg->argumentIndex() + 1), arg->name());
+
+ //template values
+ code.replace("%RETURN_TYPE", translateType(func->type(), cpp_class));
+ code.replace("%FUNCTION_NAME", func->originalName());
+
+ if (code.contains("%ARGUMENT_NAMES")) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
+ code.replace("%ARGUMENT_NAMES", str);
+ }
+
+ if (code.contains("%ARGUMENTS")) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments);
+ code.replace("%ARGUMENTS", str);
+ }
+}
+
+QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor)
+{
+ // detect number of spaces before the first character
+ QStringList lst(code.split("\n"));
+ QRegExp nonSpaceRegex("[^\\s]");
+ int spacesToRemove = 0;
+ foreach(QString line, lst) {
+ if (!line.trimmed().isEmpty()) {
+ spacesToRemove = line.indexOf(nonSpaceRegex);
+ if (spacesToRemove == -1)
+ spacesToRemove = 0;
+ break;
+ }
+ }
+
+ static QRegExp emptyLine("\\s*[\\r]?[\\n]?\\s*");
+
+ foreach(QString line, lst) {
+ if (!line.isEmpty() && !emptyLine.exactMatch(line)) {
+ while (line.end()->isSpace())
+ line.chop(1);
+ int limit = 0;
+ for(int i = 0; i < spacesToRemove; ++i) {
+ if (!line[i].isSpace())
+ break;
+ limit++;
+ }
+
+ s << indentor << line.remove(0, limit);
+ }
+ s << endl;
+ }
+ return s;
+}
+
+AbstractMetaFunctionList Generator::implicitConversions(const TypeEntry* type) const
+{
+ if (type->isValue()) {
+ const AbstractMetaClass* metaClass = classes().findClass(type);
+ if (metaClass)
+ return metaClass->implicitConversions();
+ }
+ return AbstractMetaFunctionList();
+}
+
+AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType* metaType) const
+{
+ return implicitConversions(metaType->typeEntry());
+}
+
+bool Generator::isObjectType(const TypeEntry* type)
+{
+ if (type->isComplex())
+ return Generator::isObjectType((const ComplexTypeEntry*)type);
+ return type->isObject();
+}
+bool Generator::isObjectType(const ComplexTypeEntry* type)
+{
+ return type->isObject() || type->isQObject();
+}
+bool Generator::isObjectType(const AbstractMetaClass* metaClass)
+{
+ return Generator::isObjectType(metaClass->typeEntry());
+}
+bool Generator::isObjectType(const AbstractMetaType* metaType)
+{
+ return isObjectType(metaType->typeEntry());
+}
+
+bool Generator::isPointer(const AbstractMetaType* type)
+{
+ return type->indirections() > 0
+ || type->isNativePointer()
+ || type->isValuePointer();
+}
+
+bool Generator::isCString(const AbstractMetaType* type)
+{
+ return type->isNativePointer()
+ && type->indirections() == 1
+ && type->name() == "char";
+}
+
+bool Generator::isVoidPointer(const AbstractMetaType* type)
+{
+ return type->isNativePointer()
+ && type->indirections() == 1
+ && type->name() == "void";
+}
+
+QString Generator::getFullTypeName(const TypeEntry* type) const
+{
+ return QString("%1%2").arg(type->isCppPrimitive() ? "" : "::").arg(type->qualifiedCppName());
+}
+
+QString Generator::getFullTypeName(const AbstractMetaType* type) const
+{
+ if (isCString(type))
+ return "const char*";
+ if (isVoidPointer(type))
+ return "void*";
+ if (type->typeEntry()->isContainer())
+ return QString("::%1").arg(type->cppSignature());
+ QString typeName;
+ if (type->typeEntry()->isComplex() && type->hasInstantiations())
+ typeName = getFullTypeNameWithoutModifiers(type);
+ else
+ typeName = getFullTypeName(type->typeEntry());
+ return typeName + QString("*").repeated(type->indirections());
+}
+
+QString Generator::getFullTypeName(const AbstractMetaClass* metaClass) const
+{
+ return QString("::%1").arg(metaClass->qualifiedCppName());
+}
+
+QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const
+{
+ if (isCString(type))
+ return "const char*";
+ if (isVoidPointer(type))
+ return "void*";
+ if (!type->hasInstantiations())
+ return getFullTypeName(type->typeEntry());
+ QString typeName = type->cppSignature();
+ if (type->isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (type->isReference())
+ typeName.chop(1);
+ while (typeName.endsWith('*') || typeName.endsWith(' '))
+ typeName.chop(1);
+ return QString("::%1").arg(typeName);
+}
+
+QString Generator::minimalConstructor(const AbstractMetaType* type) const
+{
+ if (!type || (type->isReference() && Generator::isObjectType(type)))
+ return QString();
+
+ if (type->isContainer()) {
+ QString ctor = type->cppSignature();
+ if (ctor.endsWith("*"))
+ return QString("0");
+ if (ctor.startsWith("const "))
+ ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (ctor.endsWith("&")) {
+ ctor.chop(1);
+ ctor = ctor.trimmed();
+ }
+ return QString("::%1()").arg(ctor);
+ }
+
+ if (type->isNativePointer())
+ return QString("((%1*)0)").arg(type->typeEntry()->qualifiedCppName());
+
+ if (Generator::isPointer(type))
+ return QString("((::%1*)0)").arg(type->typeEntry()->qualifiedCppName());
+
+ if (type->typeEntry()->isComplex()) {
+ const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry());
+ QString ctor = cType->defaultConstructor();
+ if (!ctor.isEmpty())
+ return ctor;
+ ctor = minimalConstructor(classes().findClass(cType));
+ if (type->hasInstantiations())
+ ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ return ctor;
+ }
+
+ return minimalConstructor(type->typeEntry());
+}
+
+QString Generator::minimalConstructor(const TypeEntry* type) const
+{
+ if (!type)
+ return QString();
+
+ if (type->isCppPrimitive())
+ return QString("((%1)0)").arg(type->qualifiedCppName());
+
+ if (type->isEnum() || type->isFlags())
+ return QString("((::%1)0)").arg(type->qualifiedCppName());
+
+ if (type->isPrimitive()) {
+ QString ctor = reinterpret_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
+ // If a non-C++ (i.e. defined by the user) primitive type does not have
+ // a default constructor defined by the user, the empty constructor is
+ // heuristically returned. If this is wrong the build of the generated
+ // bindings will tell.
+ return (ctor.isEmpty()) ? QString("::%1()").arg(type->qualifiedCppName()) : ctor;
+ }
+
+ if (type->isComplex())
+ return minimalConstructor(classes().findClass(type));
+
+ return QString();
+}
+
+QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+{
+ if (!metaClass)
+ return QString();
+
+ const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return cType->defaultConstructor();
+
+ AbstractMetaFunctionList constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ int maxArgs = 0;
+ foreach (const AbstractMetaFunction* ctor, constructors) {
+ if (ctor->isUserAdded() || ctor->isPrivate() || ctor->isCopyConstructor())
+ continue;
+ int numArgs = ctor->arguments().size();
+ if (numArgs == 0) {
+ maxArgs = 0;
+ break;
+ }
+ if (numArgs > maxArgs)
+ maxArgs = numArgs;
+ }
+
+ QString qualifiedCppName = metaClass->typeEntry()->qualifiedCppName();
+ QStringList templateTypes;
+ foreach (TypeEntry* templateType, metaClass->templateArguments())
+ templateTypes << templateType->qualifiedCppName();
+ QString fixedTypeName = QString("%1<%2 >").arg(qualifiedCppName).arg(templateTypes.join(", "));
+
+ // Empty constructor.
+ if (maxArgs == 0)
+ return QString("::%1()").arg(qualifiedCppName);
+
+ QList<const AbstractMetaFunction*> candidates;
+
+ // Constructors with C++ primitive types, enums or pointers only.
+ // Start with the ones with fewer arguments.
+ for (int i = 1; i <= maxArgs; ++i) {
+ foreach (const AbstractMetaFunction* ctor, constructors) {
+ if (ctor->isUserAdded() || ctor->isPrivate() || ctor->isCopyConstructor())
+ continue;
+
+ AbstractMetaArgumentList arguments = ctor->arguments();
+ if (arguments.size() != i)
+ continue;
+
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, arguments) {
+ const TypeEntry* type = arg->type()->typeEntry();
+ if (type == metaClass->typeEntry()) {
+ args.clear();
+ break;
+ }
+
+ if (!arg->originalDefaultValueExpression().isEmpty()) {
+ if (!arg->defaultValueExpression().isEmpty()
+ && arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
+ args << arg->defaultValueExpression();
+ }
+ break;
+ }
+
+ if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) {
+ QString argValue = minimalConstructor(arg->type());
+ if (argValue.isEmpty()) {
+ args.clear();
+ break;
+ }
+ args << argValue;
+ } else {
+ args.clear();
+ break;
+ }
+ }
+
+ if (!args.isEmpty())
+ return QString("::%1(%2)").arg(qualifiedCppName).arg(args.join(", "));
+
+ candidates << ctor;
+ }
+ }
+
+ // Constructors with C++ primitive types, enums, pointers, value types,
+ // and user defined primitive types.
+ // Builds the minimal constructor recursively.
+ foreach (const AbstractMetaFunction* ctor, candidates) {
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, ctor->arguments()) {
+ if (arg->type()->typeEntry() == metaClass->typeEntry()) {
+ args.clear();
+ break;
+ }
+ QString argValue = minimalConstructor(arg->type());
+ if (argValue.isEmpty()) {
+ args.clear();
+ break;
+ }
+ args << argValue;
+ }
+ if (!args.isEmpty()) {
+ return QString("::%1(%2)").arg(qualifiedCppName)
+ .arg(args.join(", "));
+ }
+ }
+
+ return QString();
+}
+
+QString Generator::translateType(const AbstractMetaType *cType,
+ const AbstractMetaClass *context,
+ Options options) const
+{
+ QString s;
+ static int constLen = strlen("const");
+
+ if (context && cType &&
+ context->typeEntry()->isGenericClass() &&
+ cType->originalTemplateType()) {
+ cType = cType->originalTemplateType();
+ }
+
+ if (!cType) {
+ s = "void";
+ } else if (cType->isArray()) {
+ s = translateType(cType->arrayElementType(), context, options) + "[]";
+ } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) {
+ s = "int";
+ } else {
+ if (options & Generator::OriginalName) {
+ s = cType->originalTypeDescription().trimmed();
+ if ((options & Generator::ExcludeReference) && s.endsWith("&"))
+ s = s.left(s.size()-1);
+
+ // remove only the last const (avoid remove template const)
+ if (options & Generator::ExcludeConst) {
+ int index = s.lastIndexOf("const");
+
+ if (index >= (s.size() - (constLen + 1))) // (VarType const) or (VarType const[*|&])
+ s = s.remove(index, constLen);
+ }
+ } else if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) {
+ AbstractMetaType* copyType = cType->copy();
+
+ if (options & Generator::ExcludeConst)
+ copyType->setConstant(false);
+
+ if (options & Generator::ExcludeReference)
+ copyType->setReference(false);
+
+ s = copyType->cppSignature();
+ if (!copyType->typeEntry()->isVoid() && !copyType->typeEntry()->isCppPrimitive())
+ s.prepend("::");
+ delete copyType;
+ } else {
+ s = cType->cppSignature();
+ }
+ }
+
+ return s;
+}
+
+
+QString Generator::subDirectoryForClass(const AbstractMetaClass* clazz) const
+{
+ return subDirectoryForPackage(clazz->package());
+}
+
+QString Generator::subDirectoryForPackage(QString packageName) const
+{
+ if (packageName.isEmpty())
+ packageName = m_d->packageName;
+ return QString(packageName).replace(".", QDir::separator());
+}
+
+template<typename T>
+static QString getClassTargetFullName_(const T* t, bool includePackageName)
+{
+ QString name = t->name();
+ const AbstractMetaClass* context = t->enclosingClass();
+ while (context) {
+ name.prepend('.');
+ name.prepend(context->name());
+ context = context->enclosingClass();
+ }
+ if (includePackageName) {
+ name.prepend('.');
+ name.prepend(t->package());
+ }
+ return name;
+}
+
+QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName)
+{
+ return getClassTargetFullName_(metaClass, includePackageName);
+}
+
+QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName)
+{
+ return getClassTargetFullName_(metaEnum, includePackageName);
+}
diff --git a/generators/generator.h b/generators/generator.h
new file mode 100644
index 00000000..92f7219c
--- /dev/null
+++ b/generators/generator.h
@@ -0,0 +1,341 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <QtCore/QObject>
+#include <QtCore/QDir>
+#include <QtCore/QLinkedList>
+#include <abstractmetalang.h>
+
+class ApiExtractor;
+class AbstractMetaBuilder;
+class QFile;
+
+QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor);
+void verifyDirectoryFor(const QFile &file);
+
+QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true);
+QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true);
+
+/**
+ * Base class for all generators. The default implementations does nothing,
+ * you must subclass this to create your own generators.
+ */
+class Generator
+{
+public:
+ /// Optiosn used around the generator code
+ enum Option {
+ NoOption = 0x00000000,
+ BoxedPrimitive = 0x00000001,
+ ExcludeConst = 0x00000002,
+ ExcludeReference = 0x00000004,
+ UseNativeIds = 0x00000008,
+
+ EnumAsInts = 0x00000010,
+ SkipName = 0x00000020,
+ NoCasts = 0x00000040,
+ SkipReturnType = 0x00000080,
+ OriginalName = 0x00000100,
+ ShowStatic = 0x00000200,
+ UnderscoreSpaces = 0x00000400,
+ ForceEnumCast = 0x00000800,
+ ArrayAsPointer = 0x00001000,
+ VirtualCall = 0x00002000,
+ SkipTemplateParameters = 0x00004000,
+ SkipAttributes = 0x00008000,
+ OriginalTypeDescription = 0x00010000,
+ SkipRemovedArguments = 0x00020000,
+ IncludeDefaultExpression = 0x00040000,
+ NoReturnStatement = 0x00080000,
+ NoBlockedSlot = 0x00100000,
+
+ SuperCall = 0x00200000,
+
+ GlobalRefJObject = 0x00100000,
+
+ SkipDefaultValues = 0x00400000,
+
+ WriteSelf = 0x00800000,
+ ExcludeMethodConst = 0x01000000,
+
+ ForceValueType = ExcludeReference | ExcludeConst
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ Generator();
+ virtual ~Generator();
+
+ bool setup(const ApiExtractor& extractor, const QMap<QString, QString> args);
+
+ virtual QMap<QString, QString> options() const;
+
+ /// Returns the classes used to generate the binding code.
+ AbstractMetaClassList classes() const;
+
+ /// Returns all global functions found by APIExtractor
+ AbstractMetaFunctionList globalFunctions() const;
+
+ /// Returns all global enums found by APIExtractor
+ AbstractMetaEnumList globalEnums() const;
+
+ /// Returns all primitive types found by APIExtractor
+ QList<const PrimitiveTypeEntry*> primitiveTypes() const;
+
+ /// Returns all container types found by APIExtractor
+ QList<const ContainerTypeEntry*> containerTypes() const;
+
+ /// Returns an AbstractMetaEnum for a given EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for the enum related to a given FlagsTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
+
+ /// Returns the output directory
+ QString outputDirectory() const;
+
+ /// Set the output directory
+ void setOutputDirectory(const QString &outDir);
+
+ /**
+ * Start the code generation, be sure to call setClasses before callign this method.
+ * For each class it creates a QTextStream, call the write method with the current
+ * class and the associated text stream, then write the text stream contents if needed.
+ * \see #write
+ */
+ void generate();
+
+ /// Returns the number of generated items
+ int numGenerated() const;
+
+ /// Returns the number of generated items written
+ int numGeneratedAndWritten() const;
+
+ /// Returns the generator's name. Used for cosmetic purposes.
+ virtual const char* name() const = 0;
+
+ /// Returns true if the generator should generate any code for the TypeEntry.
+ bool shouldGenerateTypeEntry(const TypeEntry*) const;
+
+ /// Returns true if the generator should generate any code for the AbstractMetaClass.
+ virtual bool shouldGenerate(const AbstractMetaClass *) const;
+
+ /// Returns the subdirectory used to write the binding code of an AbstractMetaClass.
+ virtual QString subDirectoryForClass(const AbstractMetaClass* clazz) const;
+
+ /**
+ * Translate metatypes to binding source format.
+ * \param metatype a pointer to metatype
+ * \param context the current meta class
+ * \param option some extra options
+ * \return the metatype translated to binding source format
+ */
+ QString translateType(const AbstractMetaType *metatype,
+ const AbstractMetaClass *context,
+ Options options = NoOption) const;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param metafunction the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ virtual void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ Options options = NoOption) const = 0;
+
+ virtual void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ Options options = NoOption) const = 0;
+
+ void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
+
+ // QtScript
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const;
+
+ /**
+ * Returns the license comment to be prepended to each source file generated.
+ */
+ QString licenseComment() const;
+
+ /**
+ * Sets the license comment to be prepended to each source file generated.
+ */
+ void setLicenseComment(const QString &licenseComment);
+
+ /**
+ * Returns the package name.
+ */
+ QString packageName() const;
+
+ /**
+ * Retrieves the name of the currently processed module.
+ * While package name is a complete package idetification, e.g. 'PySide.QtCore',
+ * a module name represents the last part of the package, e.g. 'QtCore'.
+ * If the target language separates the modules with characters other than
+ * dots ('.') the generator subclass must overload this method.
+ * \return a string representing the last part of a package name
+ */
+ virtual QString moduleName() const;
+
+ /**
+ * Retrieves a list of constructors used in implicit conversions
+ * available on the given type. The TypeEntry must be a value-type
+ * or else it will return an empty list.
+ * \param type a TypeEntry that is expected to be a value-type
+ * \return a list of constructors that could be used as implicit converters
+ */
+ AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
+
+ /// Convenience function for implicitConversions(const TypeEntry* type).
+ AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
+
+ /// Check if type is a pointer.
+ static bool isPointer(const AbstractMetaType* type);
+
+ /// Tells if the type or class is an Object (or QObject) Type.
+ static bool isObjectType(const TypeEntry* type);
+ static bool isObjectType(const ComplexTypeEntry* type);
+ static bool isObjectType(const AbstractMetaType* metaType);
+ static bool isObjectType(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the type is a C string (const char*).
+ static bool isCString(const AbstractMetaType* type);
+ /// Returns true if the type is a void pointer.
+ static bool isVoidPointer(const AbstractMetaType* type);
+
+ // Returns the full name of the type.
+ QString getFullTypeName(const TypeEntry* type) const;
+ QString getFullTypeName(const AbstractMetaType* type) const;
+ QString getFullTypeName(const AbstractMetaClass* metaClass) const;
+
+ /**
+ * Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
+ * as 'const', '&', and '*' (except if the class is not derived from a template).
+ * This is useful for instantiated templates.
+ */
+ QString getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const;
+
+ /**
+ * Tries to build a minimal constructor for the type.
+ * It will check first for a user defined default constructor.
+ * Returns a null string if it fails.
+ */
+ QString minimalConstructor(const TypeEntry* type) const;
+ QString minimalConstructor(const AbstractMetaType* type) const;
+ QString minimalConstructor(const AbstractMetaClass* metaClass) const;
+protected:
+ /**
+ * Returns the file name used to write the binding code of an AbstractMetaClass.
+ * \param metaClass the AbstractMetaClass for which the file name must be
+ * returned
+ * \return the file name used to write the binding code for the class
+ */
+ virtual QString fileNameForClass(const AbstractMetaClass* metaClass) const = 0;
+
+
+ virtual bool doSetup(const QMap<QString, QString>& args) = 0;
+
+ /**
+ * Write the bindding code for an AbstractMetaClass.
+ * This is called by generate method.
+ * \param s text stream to write the generated output
+ * \param metaClass the class that should be generated
+ */
+ virtual void generateClass(QTextStream& s, const AbstractMetaClass* metaClass) = 0;
+ virtual void finishGeneration() = 0;
+
+ /**
+ * Returns the subdirectory path for a given package
+ * (aka module, aka library) name.
+ * If the target language separates the package modules with characters other
+ * than dots ('.') the generator subclass must overload this method.
+ * /param packageName complete package name for which to return the subdirectory path
+ * or nothing the use the name of the currently processed package
+ * /return a string representing the subdirectory path for the given package
+ */
+ virtual QString subDirectoryForPackage(QString packageName = QString()) const;
+
+ QList<const AbstractMetaType*> instantiatedContainers() const;
+
+ static QString getSimplifiedContainerTypeName(const AbstractMetaType* type);
+ void addInstantiatedContainers(const AbstractMetaType* type);
+
+private:
+ struct GeneratorPrivate;
+ GeneratorPrivate* m_d;
+ void collectInstantiatedContainers(const AbstractMetaFunction* func);
+ void collectInstantiatedContainers(const AbstractMetaClass* metaClass);
+ void collectInstantiatedContainers();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
+typedef QLinkedList<Generator*> GeneratorList;
+
+/**
+* Utility class to store the identation level, use it in a QTextStream.
+*/
+class Indentor
+{
+public:
+ Indentor() : indent(0) {}
+ int indent;
+};
+
+/**
+* Class that use the RAII idiom to set and unset the identation level.
+*/
+class Indentation
+{
+public:
+ Indentation(Indentor &indentor) : indentor(indentor)
+ {
+ indentor.indent++;
+ }
+ ~Indentation()
+ {
+ indentor.indent--;
+ }
+
+private:
+ Indentor &indentor;
+};
+
+inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor)
+{
+ for (int i = 0; i < indentor.indent; ++i)
+ s << " ";
+ return s;
+}
+
+#endif // GENERATOR_H
+
diff --git a/generators/qtdoc/CMakeLists.txt b/generators/qtdoc/CMakeLists.txt
new file mode 100644
index 00000000..541e7c6e
--- /dev/null
+++ b/generators/qtdoc/CMakeLists.txt
@@ -0,0 +1,21 @@
+project(qtdoc_generator)
+
+set(qtdoc_generator_SRC
+qtdocgenerator.cpp
+)
+
+include_directories(${generators_SOURCE_DIR}
+ ${QT_QTCORE_INCLUDE_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR})
+add_executable(docgenerator main.cpp)
+set_target_properties(docgenerator PROPERTIES OUTPUT_NAME docgenerator${generator_SUFFIX})
+
+target_link_libraries(docgenerator ${QT_QTCORE_LIBRARY})
+
+add_library(qtdoc_generator SHARED ${qtdoc_generator_SRC})
+target_link_libraries(qtdoc_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner)
+set_property(TARGET qtdoc_generator PROPERTY PREFIX "")
+
+install(TARGETS qtdoc_generator DESTINATION ${generator_plugin_DIR})
+install(TARGETS docgenerator DESTINATION bin)
+
diff --git a/generator/shiboken.cpp b/generators/qtdoc/main.cpp
index 005df90e..21fab147 100644
--- a/generator/shiboken.cpp
+++ b/generators/qtdoc/main.cpp
@@ -1,5 +1,5 @@
/*
- * This file is part of the Shiboken Python Bindings Generator project.
+ * This file is part of the PySide project.
*
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
*
@@ -21,7 +21,14 @@
*
*/
-#include "cppgenerator.h"
-#include "headergenerator.h"
+#include <QtCore>
+
+int main(int argc, char *argv[])
+{
+ QStringList args;
+ args.append("--generator-set=qtdoc");
+ for (int i = 1; i < argc; i++)
+ args.append(argv[i]);
+ return QProcess::execute("generatorrunner", args);
+}
-EXPORT_GENERATOR_PLUGIN(new CppGenerator << new HeaderGenerator)
diff --git a/generators/qtdoc/qtdocgenerator.cpp b/generators/qtdoc/qtdocgenerator.cpp
new file mode 100644
index 00000000..59345640
--- /dev/null
+++ b/generators/qtdoc/qtdocgenerator.cpp
@@ -0,0 +1,1652 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "qtdocgenerator.h"
+#include <reporthandler.h>
+#include <qtdocparser.h>
+#include <doxygenparser.h>
+#include <typedatabase.h>
+#include <algorithm>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <fileout.h>
+#include <limits>
+
+static Indentor INDENT;
+
+static bool shouldSkip(const AbstractMetaFunction* func)
+{
+ bool skipable = func->isConstructor()
+ || func->isModifiedRemoved()
+ || func->declaringClass() != func->ownerClass()
+ || func->isCastOperator()
+ || func->name() == "operator=";
+
+ // Search a const clone
+ if (!skipable && !func->isConstant()) {
+ const AbstractMetaArgumentList funcArgs = func->arguments();
+ foreach (AbstractMetaFunction* f, func->ownerClass()->functions()) {
+ if (f != func
+ && f->isConstant()
+ && f->name() == func->name()
+ && f->arguments().count() == funcArgs.count()) {
+ // Compare each argument
+ bool cloneFound = true;
+
+ const AbstractMetaArgumentList fargs = f->arguments();
+ for (int i = 0, max = funcArgs.count(); i < max; ++i) {
+ if (funcArgs.at(i)->type()->typeEntry() != fargs.at(i)->type()->typeEntry()) {
+ cloneFound = false;
+ break;
+ }
+ }
+ if (cloneFound)
+ return true;
+ }
+ }
+ }
+ return skipable;
+}
+
+static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFunction* func2)
+{
+ return func1->name() < func2->name();
+}
+
+static QString createRepeatedChar(int i, char c)
+{
+ QString out;
+ for (int j = 0; j < i; ++j)
+ out += c;
+
+ return out;
+}
+
+static QString escape(QString& str)
+{
+ return str
+ .replace("*", "\\*")
+ .replace("_", "\\_");
+}
+
+static QString escape(const QStringRef& strref)
+{
+ QString str = strref.toString();
+ return escape(str);
+}
+
+
+QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
+ : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
+{
+ m_handlerMap.insert("heading", &QtXmlToSphinx::handleHeadingTag);
+ m_handlerMap.insert("brief", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("para", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("italic", &QtXmlToSphinx::handleItalicTag);
+ m_handlerMap.insert("bold", &QtXmlToSphinx::handleBoldTag);
+ m_handlerMap.insert("see-also", &QtXmlToSphinx::handleSeeAlsoTag);
+ m_handlerMap.insert("snippet", &QtXmlToSphinx::handleSnippetTag);
+ m_handlerMap.insert("dots", &QtXmlToSphinx::handleDotsTag);
+ m_handlerMap.insert("codeline", &QtXmlToSphinx::handleDotsTag);
+ m_handlerMap.insert("table", &QtXmlToSphinx::handleTableTag);
+ m_handlerMap.insert("header", &QtXmlToSphinx::handleRowTag);
+ m_handlerMap.insert("row", &QtXmlToSphinx::handleRowTag);
+ m_handlerMap.insert("item", &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert("argument", &QtXmlToSphinx::handleArgumentTag);
+ m_handlerMap.insert("teletype", &QtXmlToSphinx::handleArgumentTag);
+ m_handlerMap.insert("link", &QtXmlToSphinx::handleLinkTag);
+ m_handlerMap.insert("inlineimage", &QtXmlToSphinx::handleImageTag);
+ m_handlerMap.insert("image", &QtXmlToSphinx::handleImageTag);
+ m_handlerMap.insert("list", &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert("term", &QtXmlToSphinx::handleTermTag);
+ m_handlerMap.insert("raw", &QtXmlToSphinx::handleRawTag);
+ m_handlerMap.insert("underline", &QtXmlToSphinx::handleItalicTag);
+ m_handlerMap.insert("superscript", &QtXmlToSphinx::handleSuperScriptTag);
+ m_handlerMap.insert("code", &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert("badcode", &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert("legalese", &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert("section", &QtXmlToSphinx::handleAnchorTag);
+ m_handlerMap.insert("quotefile", &QtXmlToSphinx::handleQuoteFileTag);
+
+ // ignored tags
+ m_handlerMap.insert("generatedlist", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("tableofcontents", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("quotefromfile", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("skipto", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("target", &QtXmlToSphinx::handleIgnoredTag);
+
+ // useless tags
+ m_handlerMap.insert("description", &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert("definition", &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert("printuntil", &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert("relation", &QtXmlToSphinx::handleUselessTag);
+
+ // Doxygen tags
+ m_handlerMap.insert("title", &QtXmlToSphinx::handleHeadingTag);
+ m_handlerMap.insert("ref", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("computeroutput", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("detaileddescription", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("name", &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert("listitem", &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert("parametername", &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert("parameteritem", &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert("ulink", &QtXmlToSphinx::handleLinkTag);
+ m_handlerMap.insert("itemizedlist", &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert("parameternamelist", &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert("parameterlist", &QtXmlToSphinx::handleListTag);
+
+ // Doxygen ignored tags
+ m_handlerMap.insert("highlight", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("linebreak", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("programlisting", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("xreftitle", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("sp", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("entry", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("simplesect", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("verbatim", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("xrefsect", &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert("xrefdescription", &QtXmlToSphinx::handleIgnoredTag);
+
+ m_result = transform(doc);
+}
+
+void QtXmlToSphinx::pushOutputBuffer()
+{
+ QString* buffer = new QString();
+ m_buffers << buffer;
+ m_output.setString(buffer);
+}
+
+QString QtXmlToSphinx::popOutputBuffer()
+{
+ Q_ASSERT(!m_buffers.isEmpty());
+ QString* str = m_buffers.pop();
+ QString strcpy(*str);
+ delete str;
+ m_output.setString(m_buffers.isEmpty() ? 0 : m_buffers.top());
+ return strcpy;
+}
+
+QString QtXmlToSphinx::expandFunction(const QString& function)
+{
+ QStringList functionSpec = function.split('.');
+ QString className = functionSpec.first();
+ const AbstractMetaClass* metaClass = 0;
+ foreach (const AbstractMetaClass* cls, m_generator->classes()) {
+ if (cls->name() == className) {
+ metaClass = cls;
+ break;
+ }
+ }
+
+ if (metaClass) {
+ functionSpec.removeFirst();
+ return metaClass->typeEntry()->qualifiedTargetLangName() + "." + functionSpec.join(".");
+ } else {
+ return function;
+ }
+}
+
+QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName)
+{
+ QString currentClass = m_context.split(".").last();
+
+ const AbstractMetaClass* metaClass = 0;
+ foreach (const AbstractMetaClass* cls, m_generator->classes()) {
+ if (cls->name() == currentClass) {
+ metaClass = cls;
+ break;
+ }
+ }
+
+ if (metaClass) {
+ QList<const AbstractMetaFunction*> funcList;
+ foreach (const AbstractMetaFunction* func, metaClass->queryFunctionsByName(methodName)) {
+ if (methodName == func->name())
+ funcList.append(func);
+ }
+
+ const AbstractMetaClass* implementingClass = 0;
+ foreach (const AbstractMetaFunction* func, funcList) {
+ implementingClass = func->implementingClass();
+ if (implementingClass->name() == currentClass)
+ break;
+ }
+
+ if (implementingClass)
+ return implementingClass->typeEntry()->qualifiedTargetLangName();
+ }
+
+ return QLatin1String("~") + m_context;
+}
+
+QString QtXmlToSphinx::transform(const QString& doc)
+{
+ Q_ASSERT(m_buffers.isEmpty());
+ Indentation indentation(INDENT);
+ if (doc.trimmed().isEmpty())
+ return doc;
+
+ pushOutputBuffer();
+
+ QXmlStreamReader reader(doc);
+
+ while (!reader.atEnd()) {
+ QXmlStreamReader::TokenType token = reader.readNext();
+ if (reader.hasError()) {
+ m_output << INDENT << "XML Error: " + reader.errorString() + "\n" + doc;
+ ReportHandler::warning("XML Error: " + reader.errorString() + "\n" + doc);
+ break;
+ }
+
+ if (token == QXmlStreamReader::StartElement) {
+ QStringRef tagName = reader.name();
+ TagHandler handler = m_handlerMap.value(tagName.toString(), &QtXmlToSphinx::handleUnknownTag);
+ if (!m_handlers.isEmpty() && ( (m_handlers.top() == &QtXmlToSphinx::handleIgnoredTag) ||
+ (m_handlers.top() == &QtXmlToSphinx::handleRawTag)) )
+ handler = &QtXmlToSphinx::handleIgnoredTag;
+
+ m_handlers.push(handler);
+ }
+ if (!m_handlers.isEmpty())
+ (this->*(m_handlers.top()))(reader);
+
+ if (token == QXmlStreamReader::EndElement) {
+ m_handlers.pop();
+ m_lastTagName = reader.name().toString();
+ }
+ }
+ m_output.flush();
+ QString retval = popOutputBuffer();
+ Q_ASSERT(m_buffers.isEmpty());
+ return retval;
+}
+
+QString QtXmlToSphinx::readFromLocations(const QStringList& locations, const QString& path, const QString& identifier)
+{
+ QString result;
+ bool ok;
+ foreach (QString location, locations) {
+ location.append('/');
+ location.append(path);
+ result = readFromLocation(location, identifier, &ok);
+ if (ok)
+ break;
+ }
+ if (!ok)
+ ReportHandler::warning("Couldn't read code snippet file: {"+ locations.join("|") + '}' + path);
+ return result;
+}
+
+QString QtXmlToSphinx::readFromLocation(const QString& location, const QString& identifier, bool* ok)
+{
+ QFile inputFile;
+ inputFile.setFileName(location);
+ if (!inputFile.open(QIODevice::ReadOnly)) {
+ if (!ok)
+ ReportHandler::warning("Couldn't read code snippet file: "+inputFile.fileName());
+ else
+ *ok = false;
+ return QString();
+ }
+
+ QRegExp searchString("//!\\s*\\[" + identifier + "\\]");
+ QRegExp codeSnippetCode("//!\\s*\\[[\\w\\d\\s]+\\]");
+ QString code;
+ QString line;
+ bool identifierIsEmpty = identifier.isEmpty();
+ bool getCode = false;
+
+ while (!inputFile.atEnd()) {
+ line = inputFile.readLine();
+ if (identifierIsEmpty) {
+ code += line;
+ } else if (getCode && !line.contains(searchString)) {
+ code += line.replace(codeSnippetCode, "");
+ } else if (line.contains(searchString)) {
+ if (getCode)
+ break;
+ else
+ getCode = true;
+ }
+ }
+
+ if (!identifierIsEmpty && !getCode)
+ ReportHandler::warning("Code snippet file found ("+location+"), but snippet "+ identifier +" not found.");
+
+ if (ok)
+ *ok = true;
+ return code;
+}
+
+void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
+{
+ static QString heading;
+ static char type;
+ static char types[] = { '-', '^' };
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ uint typeIdx = reader.attributes().value("level").toString().toInt();
+ if (typeIdx >= sizeof(types))
+ type = types[sizeof(types)-1];
+ else
+ type = types[typeIdx];
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << createRepeatedChar(heading.length(), type) << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ heading = escape(reader.text()).trimmed();
+ m_output << endl << endl << heading << endl;
+ }
+}
+
+void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::EndElement) {
+ QString result = popOutputBuffer().simplified();
+ if (result.startsWith("**Warning:**"))
+ result.replace(0, 12, ".. warning:: ");
+ else if (result.startsWith("**Note:**"))
+ result.replace(0, 9, ".. note:: ");
+
+ m_output << INDENT << result << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ QString text = escape(reader.text());
+ if (!m_output.string()->isEmpty()) {
+ QChar start = text[0];
+ QChar end = m_output.string()->at(m_output.string()->length() - 1);
+ if ((end == '*' || end == '`') && start != ' ' && !start.isPunct())
+ m_output << '\\';
+ }
+ m_output << INDENT << text;
+ }
+}
+
+void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) {
+ m_insideItalic = !m_insideItalic;
+ m_output << '*';
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << escape(reader.text()).trimmed();
+ }
+}
+
+void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) {
+ m_insideBold = !m_insideBold;
+ m_output << "**";
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << escape(reader.text()).trimmed();
+ }
+}
+
+void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement)
+ m_output << "``";
+ else if (token == QXmlStreamReader::Characters)
+ m_output << reader.text().toString().trimmed();
+}
+
+void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement)
+ m_output << INDENT << ".. seealso:: ";
+ else if (token == QXmlStreamReader::EndElement)
+ m_output << endl;
+}
+
+void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline";
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(2);
+ }
+ QString location = reader.attributes().value("location").toString();
+ QString identifier = reader.attributes().value("identifier").toString();
+ QString code = readFromLocations(m_generator->codeSnippetDirs(), location, identifier);
+ if (!consecutiveSnippet)
+ m_output << INDENT << "::\n\n";
+
+ Indentation indentation(INDENT);
+ if (code.isEmpty()) {
+ m_output << INDENT << "<Code snippet \"" << location << ':' << identifier << "\" not found>" << endl;
+ } else {
+ foreach (QString line, code.split("\n")) {
+ if (!QString(line).trimmed().isEmpty())
+ m_output << INDENT << line;
+
+ m_output << endl;
+ }
+ }
+ m_output << endl;
+ }
+}
+void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline";
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(2);
+ }
+ Indentation indentation(INDENT);
+ pushOutputBuffer();
+ m_output << INDENT;
+ int indent = reader.attributes().value("indent").toString().toInt();
+ for (int i = 0; i < indent; ++i)
+ m_output << ' ';
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << popOutputBuffer() << "\n\n\n";
+ }
+}
+
+void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_currentTable.clear();
+ m_tableHasHeader = false;
+ } else if (token == QXmlStreamReader::EndElement) {
+ // write the table on m_output
+ m_currentTable.enableHeader(m_tableHasHeader);
+ m_currentTable.normalize();
+ m_output << m_currentTable;
+ m_currentTable.clear();
+ }
+}
+
+void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString().replace("::", ".");
+ } else if (token == QXmlStreamReader::EndElement) {
+ TableCell cell;
+ cell.data = popOutputBuffer().trimmed();
+ m_currentTable << (TableRow() << cell);
+ }
+}
+
+
+void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ if (m_currentTable.isEmpty())
+ m_currentTable << TableRow();
+ TableRow& row = m_currentTable.last();
+ TableCell cell;
+ cell.colSpan = reader.attributes().value("colspan").toString().toShort();
+ cell.rowSpan = reader.attributes().value("rowspan").toString().toShort();
+ row << cell;
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::EndElement) {
+ QString data = popOutputBuffer().trimmed();
+ if (!m_currentTable.isEmpty()) {
+ TableRow& row = m_currentTable.last();
+ if (!row.isEmpty())
+ row.last().data = data;
+ }
+ }
+}
+
+void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_tableHasHeader = reader.name() == "header";
+ m_currentTable << TableRow();
+ }
+}
+
+void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
+{
+ // BUG We do not support a list inside a table cell
+ static QString listType;
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ listType = reader.attributes().value("type").toString();
+ if (listType == "enum") {
+ m_currentTable << (TableRow() << "Constant" << "Description");
+ m_tableHasHeader = true;
+ }
+ INDENT.indent--;
+ } else if (token == QXmlStreamReader::EndElement) {
+ INDENT.indent++;
+ if (!m_currentTable.isEmpty()) {
+ if (listType == "bullet") {
+ m_output << endl;
+ foreach (TableCell cell, m_currentTable.first()) {
+ QStringList itemLines = cell.data.split('\n');
+ m_output << INDENT << "* " << itemLines.first() << endl;
+ for (int i = 1, max = itemLines.count(); i < max; ++i)
+ m_output << INDENT << " " << itemLines[i] << endl;
+ }
+ m_output << endl;
+ } else if (listType == "enum") {
+ m_currentTable.enableHeader(m_tableHasHeader);
+ m_currentTable.normalize();
+ m_output << m_currentTable;
+ }
+ }
+ m_currentTable.clear();
+ }
+}
+
+void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
+{
+ static QString l_linktag;
+ static QString l_linkref;
+ static QString l_linktext;
+ static QString l_linktagending;
+ static QString l_type;
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ l_linktagending = "` ";
+ if (m_insideBold) {
+ l_linktag.prepend("**");
+ l_linktagending.append("**");
+ } else if (m_insideItalic) {
+ l_linktag.prepend('*');
+ l_linktagending.append('*');
+ }
+ l_type = reader.attributes().value("type").toString();
+
+ // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
+ // are recognized as such or not in the binding
+ if (l_type == "property")
+ l_type = "function";
+
+ if (l_type == "typedef")
+ l_type = "class";
+
+ QString linkSource;
+ if (l_type == "function" || l_type == "class") {
+ linkSource = "raw";
+ } else if (l_type == "enum") {
+ linkSource = "enum";
+ } else if (l_type == "page") {
+ linkSource = "page";
+ } else {
+ linkSource = "href";
+ }
+
+ l_linkref = reader.attributes().value(linkSource).toString();
+ l_linkref.replace("::", ".");
+ l_linkref.remove("()");
+
+ if (l_type == "function" && !m_context.isEmpty()) {
+ l_linktag = " :meth:`";
+ QStringList rawlinklist = l_linkref.split(".");
+ if (rawlinklist.size() == 1 || rawlinklist.first() == m_context) {
+ QString context = resolveContextForMethod(rawlinklist.last());
+ if (!l_linkref.startsWith(context))
+ l_linkref.prepend(context + '.');
+ } else {
+ l_linkref = expandFunction(l_linkref);
+ }
+ } else if (l_type == "function" && m_context.isEmpty()) {
+ l_linktag = " :func:`";
+ } else if (l_type == "class") {
+ l_linktag = " :class:`";
+ TypeEntry* type = TypeDatabase::instance()->findType(l_linkref);
+ if (type) {
+ l_linkref = type->qualifiedTargetLangName();
+ } else { // fall back to the old heuristic if the type wasn't found.
+ QStringList rawlinklist = l_linkref.split(".");
+ QStringList splittedContext = m_context.split(".");
+ if (rawlinklist.size() == 1 || rawlinklist.first() == splittedContext.last()) {
+ splittedContext.removeLast();
+ l_linkref.prepend('~' + splittedContext.join(".") + '.');
+ }
+ }
+ } else if (l_type == "enum") {
+ l_linktag = " :attr:`";
+ } else if (l_type == "page" && l_linkref == m_generator->moduleName()) {
+ l_linktag = " :mod:`";
+ } else {
+ l_linktag = " :ref:`";
+ }
+
+ } else if (token == QXmlStreamReader::Characters) {
+ QString linktext = reader.text().toString();
+ linktext.replace("::", ".");
+ QString item = l_linkref.split(".").last();
+ if (l_linkref == linktext
+ || (l_linkref + "()") == linktext
+ || item == linktext
+ || (item + "()") == linktext)
+ l_linktext.clear();
+ else
+ l_linktext = linktext + QLatin1String("<");
+ } else if (token == QXmlStreamReader::EndElement) {
+ if (!l_linktext.isEmpty())
+ l_linktagending.prepend('>');
+ m_output << l_linktag << l_linktext << escape(l_linkref) << l_linktagending;
+ }
+}
+
+void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString href = reader.attributes().value("href").toString();
+ QDir dir(m_generator->outputDirectory() + '/' + m_generator->packageName().replace(".", "/"));
+ QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + "/doc/src/") + '/' + href;
+
+ if (reader.name() == "image")
+ m_output << INDENT << ".. image:: " << imgPath << endl << endl;
+ else
+ m_output << ".. image:: " << imgPath << ' ';
+ }
+}
+
+void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString format = reader.attributes().value("format").toString();
+ m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ QStringList lst(reader.text().toString().split("\n"));
+ foreach(QString row, lst)
+ m_output << INDENT << INDENT << row << endl;
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << endl << endl;
+ }
+}
+
+void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString format = reader.attributes().value("format").toString();
+ m_output << INDENT << "::" << endl << endl;
+ INDENT.indent++;
+ } else if (token == QXmlStreamReader::Characters) {
+ QStringList lst(reader.text().toString().split("\n"));
+ foreach(QString row, lst)
+ m_output << INDENT << INDENT << row << endl;
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << endl << endl;
+ INDENT.indent--;
+ }
+}
+
+void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement)
+ ReportHandler::warning("Unknow QtDoc tag: \"" + reader.name().toString() + "\".");
+}
+
+void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_output << " :sup:`";
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << popOutputBuffer();
+ m_output << '`';
+ }
+}
+
+void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&)
+{
+}
+
+void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&)
+{
+ // Tag "description" just marks the init of "Detailed description" title.
+ // Tag "definition" just marks enums. We have a different way to process them.
+}
+
+void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString anchor;
+ if (reader.attributes().hasAttribute("id"))
+ anchor = reader.attributes().value("id").toString();
+ else if (reader.attributes().hasAttribute("name"))
+ anchor = reader.attributes().value("name").toString();
+ if (!anchor.isEmpty() && m_opened_anchor != anchor) {
+ m_opened_anchor = anchor;
+ m_output << INDENT << ".. _" << m_context << "_" << anchor.toLower() << ":" << endl << endl;
+ }
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_opened_anchor = "";
+ }
+}
+
+void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::Characters) {
+ QString location = reader.text().toString();
+ QString identifier = "";
+ location.prepend(m_generator->libSourceDir() + '/');
+ QString code = readFromLocation(location, identifier);
+
+ m_output << INDENT << "::\n\n";
+ Indentation indentation(INDENT);
+ if (code.isEmpty()) {
+ m_output << INDENT << "<Code snippet \"" << location << "\" not found>" << endl;
+ } else {
+ foreach (QString line, code.split("\n")) {
+ if (!QString(line).trimmed().isEmpty())
+ m_output << INDENT << line;
+
+ m_output << endl;
+ }
+ }
+ m_output << endl;
+ }
+}
+
+void QtXmlToSphinx::Table::normalize()
+{
+ if (m_normalized || isEmpty())
+ return;
+
+ int row;
+ int col;
+ QtXmlToSphinx::Table& self = *this;
+
+ //QDoc3 generates tables with wrong number of columns. We have to
+ //check and if necessary, merge the last columns.
+ int maxCols = self.at(0).count();
+ // add col spans
+ for (row = 0; row < count(); ++row) {
+ for (col = 0; col < at(row).count(); ++col) {
+ QtXmlToSphinx::TableCell& cell = self[row][col];
+ bool mergeCols = (col >= maxCols);
+ if (cell.colSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.colSpan = -1;
+ for (int i = 0, max = cell.colSpan-1; i < max; ++i) {
+ self[row].insert(col+1, newCell);
+ }
+ cell.colSpan = 0;
+ col++;
+ } else if (mergeCols) {
+ self[row][maxCols - 1].data += " " + cell.data;
+ }
+ }
+ }
+
+ // row spans
+ const int numCols = first().count();
+ for (col = 0; col < numCols; ++col) {
+ for (row = 0; row < count(); ++row) {
+ if (col < self[row].count()) {
+ QtXmlToSphinx::TableCell& cell = self[row][col];
+ if (cell.rowSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.rowSpan = -1;
+ int max = std::min(cell.rowSpan - 1, count());
+ cell.rowSpan = 0;
+ for (int i = 0; i < max; ++i) {
+ self[row+i+1].insert(col, newCell);
+ }
+ row++;
+ }
+ }
+ }
+ }
+ m_normalized = true;
+}
+
+QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
+{
+ if (table.isEmpty())
+ return s;
+
+ if (!table.isNormalized()) {
+ ReportHandler::warning("Attempt to print an unnormalized table!");
+ return s;
+ }
+
+ // calc width and height of each column and row
+ QVector<int> colWidths(table.first().count());
+ QVector<int> rowHeights(table.count());
+ for (int i = 0, maxI = table.count(); i < maxI; ++i) {
+ const QtXmlToSphinx::TableRow& row = table[i];
+ for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) {
+ QStringList rowLines = row[j].data.split('\n'); // cache this would be a good idea
+ foreach (QString str, rowLines)
+ colWidths[j] = std::max(colWidths[j], str.count());
+ rowHeights[i] = std::max(rowHeights[i], row[j].data.count('\n') + 1);
+ }
+ }
+
+ if (!*std::max_element(colWidths.begin(), colWidths.end()))
+ return s; // empty table (table with empty cells)
+
+ // create a horizontal line to be used later.
+ QString horizontalLine("+");
+ for (int i = 0, max = colWidths.count(); i < max; ++i) {
+ horizontalLine += createRepeatedChar(colWidths[i], '-');
+ horizontalLine += '+';
+ }
+
+ // write table rows
+ for (int i = 0, maxI = table.count(); i < maxI; ++i) { // for each row
+ const QtXmlToSphinx::TableRow& row = table[i];
+
+ // print line
+ s << INDENT << '+';
+ for (int col = 0, max = colWidths.count(); col < max; ++col) {
+ char c;
+ if (col >= row.length() || row[col].rowSpan == -1)
+ c = ' ';
+ else if (i == 1 && table.hasHeader())
+ c = '=';
+ else
+ c = '-';
+ s << createRepeatedChar(colWidths[col], c) << '+';
+ }
+ s << endl;
+
+
+ // Print the table cells
+ for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row
+ for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { // for each column
+ const QtXmlToSphinx::TableCell& cell = row[j];
+ QStringList rowLines = cell.data.split('\n'); // FIXME: Cache this!!!
+ if (!j) // First column, so we need print the identation
+ s << INDENT;
+
+ if (!j || !cell.colSpan)
+ s << '|';
+ else
+ s << ' ';
+ s << qSetFieldWidth(colWidths[j]) << left;
+ s << (rowLine < rowLines.count() ? rowLines[rowLine] : "");
+ s << qSetFieldWidth(0);
+ }
+ s << '|' << endl;
+ }
+ }
+ s << INDENT << horizontalLine << endl;
+ s << endl;
+ return s;
+}
+
+static QString getFuncName(const AbstractMetaFunction* cppFunc) {
+ static bool hashInitialized = false;
+ static QHash<QString, QString> operatorsHash;
+ if (!hashInitialized) {
+ operatorsHash.insert("operator+", "__add__");
+ operatorsHash.insert("operator+=", "__iadd__");
+ operatorsHash.insert("operator-", "__sub__");
+ operatorsHash.insert("operator-=", "__isub__");
+ operatorsHash.insert("operator*", "__mul__");
+ operatorsHash.insert("operator*=", "__imul__");
+ operatorsHash.insert("operator/", "__div__");
+ operatorsHash.insert("operator/=", "__idiv__");
+ operatorsHash.insert("operator%", "__mod__");
+ operatorsHash.insert("operator%=", "__imod__");
+ operatorsHash.insert("operator<<", "__lshift__");
+ operatorsHash.insert("operator<<=", "__ilshift__");
+ operatorsHash.insert("operator>>", "__rshift__");
+ operatorsHash.insert("operator>>=", "__irshift__");
+ operatorsHash.insert("operator&", "__and__");
+ operatorsHash.insert("operator&=", "__iand__");
+ operatorsHash.insert("operator|", "__or__");
+ operatorsHash.insert("operator|=", "__ior__");
+ operatorsHash.insert("operator^", "__xor__");
+ operatorsHash.insert("operator^=", "__ixor__");
+ operatorsHash.insert("operator==", "__eq__");
+ operatorsHash.insert("operator!=", "__ne__");
+ operatorsHash.insert("operator<", "__lt__");
+ operatorsHash.insert("operator<=", "__le__");
+ operatorsHash.insert("operator>", "__gt__");
+ operatorsHash.insert("operator>=", "__ge__");
+ hashInitialized = true;
+ }
+
+ QHash<QString, QString>::const_iterator it = operatorsHash.find(cppFunc->name());
+ QString result = it != operatorsHash.end() ? it.value() : cppFunc->name();
+ return result.replace("::", ".");
+}
+
+QtDocGenerator::QtDocGenerator() : m_docParser(0)
+{
+}
+
+QtDocGenerator::~QtDocGenerator()
+{
+ delete m_docParser;
+}
+
+QString QtDocGenerator::fileNameForClass(const AbstractMetaClass* cppClass) const
+{
+ return QString("%1.rst").arg(getClassTargetFullName(cppClass, false));
+}
+
+void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass)
+{
+ QString metaClassName;
+
+ if (metaClass)
+ metaClassName = getClassTargetFullName(metaClass);
+
+ if (doc.format() == Documentation::Native) {
+ QtXmlToSphinx x(this, doc.value(), metaClassName);
+ s << x;
+ } else {
+ QStringList lines = doc.value().split("\n");
+ QRegExp regex("\\S"); // non-space character
+ int typesystemIndentation = std::numeric_limits<int>().max();
+ // check how many spaces must be removed from the begining of each line
+ foreach (QString line, lines) {
+ int idx = line.indexOf(regex);
+ if (idx >= 0)
+ typesystemIndentation = qMin(typesystemIndentation, idx);
+ }
+ foreach (QString line, lines)
+ s << INDENT << line.remove(0, typesystemIndentation) << endl;
+ }
+
+ s << endl;
+}
+
+static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaClass, const AbstractMetaClassList& allClasses)
+{
+ AbstractMetaClassList res;
+ foreach (AbstractMetaClass* c, allClasses) {
+ if (c != metaClass && c->inheritsFrom(metaClass))
+ res << c;
+ }
+
+ if (res.isEmpty())
+ return;
+
+ s << "**Inherited by:** ";
+ QStringList classes;
+ foreach (AbstractMetaClass* c, res)
+ classes << QString(":ref:`%1`").arg(getClassTargetFullName(c, false));
+ s << classes.join(", ") << endl << endl;
+}
+
+void QtDocGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ ReportHandler::debugSparse("Generating Documentation for " + metaClass->fullName());
+
+ m_packages[metaClass->package()] << fileNameForClass(metaClass);
+
+ m_docParser->setPackageName(metaClass->package());
+ m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass));
+
+ s << ".. module:: " << metaClass->package() << endl;
+ QString className = getClassTargetFullName(metaClass, false);
+ s << ".. _" << className << ":" << endl << endl;
+
+ s << className << endl;
+ s << createRepeatedChar(className.count(), '*') << endl << endl;
+
+ s << ".. inheritance-diagram:: " << className << endl
+ << " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future...
+
+
+ writeInheritedByList(s, metaClass, classes());
+
+ if (metaClass->typeEntry() && (metaClass->typeEntry()->version() != 0))
+ s << ".. note:: This class was introduced in Qt " << metaClass->typeEntry()->version() << endl;
+
+ writeFunctionList(s, metaClass);
+
+ //Function list
+ AbstractMetaFunctionList functionList = metaClass->functions();
+ qSort(functionList.begin(), functionList.end(), functionSort);
+
+ s << "Detailed Description\n"
+ "--------------------\n\n";
+
+ writeInjectDocumentation(s, DocModification::Prepend, metaClass, 0);
+ if (!writeInjectDocumentation(s, DocModification::Replace, metaClass, 0))
+ writeFormatedText(s, metaClass->documentation(), metaClass);
+
+ if (!metaClass->isNamespace())
+ writeConstructors(s, metaClass);
+ writeEnums(s, metaClass);
+ if (!metaClass->isNamespace())
+ writeFields(s, metaClass);
+
+
+ foreach (AbstractMetaFunction* func, functionList) {
+ if (shouldSkip(func))
+ continue;
+
+ if (func->isStatic())
+ s << ".. staticmethod:: ";
+ else
+ s << ".. method:: ";
+
+ writeFunction(s, true, metaClass, func);
+ }
+
+ writeInjectDocumentation(s, DocModification::Append, metaClass, 0);
+}
+
+void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ QStringList functionList;
+ QStringList virtualList;
+ QStringList signalList;
+ QStringList slotList;
+ QStringList staticFunctionList;
+
+ foreach (AbstractMetaFunction* func, cppClass->functions()) {
+ if (shouldSkip(func))
+ continue;
+
+ QString className;
+ if (!func->isConstructor())
+ className = getClassTargetFullName(cppClass) + '.';
+ else if (func->implementingClass() && func->implementingClass()->enclosingClass())
+ className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + '.';
+ QString funcName = getFuncName(func);
+
+ QString str("def :meth:`");
+
+ str += funcName;
+ str += '<';
+ if (!funcName.startsWith(className))
+ str += className;
+ str += funcName;
+ str += ">` (";
+ str += parseArgDocStyle(cppClass, func);
+ str += ')';
+
+ if (func->isStatic())
+ staticFunctionList << str;
+ else if (func->isVirtual())
+ virtualList << str;
+ else if (func->isSignal())
+ signalList << str;
+ else if (func->isSlot())
+ slotList << str;
+ else
+ functionList << str;
+ }
+
+ if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
+ QtXmlToSphinx::Table functionTable;
+ QtXmlToSphinx::TableRow row;
+
+ s << "Synopsis" << endl
+ << "--------" << endl << endl;
+
+ writeFunctionBlock(s, "Functions", functionList);
+ writeFunctionBlock(s, "Virtual functions", virtualList);
+ writeFunctionBlock(s, "Slots", slotList);
+ writeFunctionBlock(s, "Signals", signalList);
+ writeFunctionBlock(s, "Static functions", staticFunctionList);
+ }
+}
+
+void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions)
+{
+ if (functions.size() > 0) {
+ s << title << endl
+ << QString('^').repeated(title.size()) << endl;
+
+ qSort(functions);
+
+ s << ".. container:: function_list" << endl << endl;
+ Indentation indentation(INDENT);
+ foreach (QString func, functions)
+ s << '*' << INDENT << func << endl;
+
+ s << endl << endl;
+ }
+}
+
+void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString section_title(".. attribute:: ");
+
+ foreach (AbstractMetaEnum* en, cppClass->enums()) {
+ s << section_title << getClassTargetFullName(cppClass) << "." << en->name() << endl << endl;
+ writeFormatedText(s, en->documentation(), cppClass);
+
+ if (en->typeEntry() && (en->typeEntry()->version() != 0))
+ s << ".. note:: This enum was introduced or modified in Qt " << en->typeEntry()->version() << endl;
+ }
+
+}
+
+void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString section_title(".. attribute:: ");
+
+ foreach (AbstractMetaField* field, cppClass->fields()) {
+ s << section_title << getClassTargetFullName(cppClass) << "." << field->name() << endl << endl;
+ //TODO: request for member ‘documentation’ is ambiguous
+ writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
+ }
+}
+
+void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString sectionTitle = ".. class:: ";
+ static const QString sectionTitleSpace = QString(sectionTitle.size(), ' ');
+
+ AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible);
+
+ bool first = true;
+ QHash<QString, AbstractMetaArgument*> arg_map;
+
+ foreach(AbstractMetaFunction* func, lst) {
+ if (func->isModifiedRemoved())
+ continue;
+
+ if (first) {
+ first = false;
+ s << sectionTitle;
+ } else {
+ s << sectionTitleSpace;
+ }
+ writeFunction(s, false, cppClass, func);
+ foreach(AbstractMetaArgument* arg, func->arguments())
+ {
+ if (!arg_map.contains(arg->name())) {
+ arg_map.insert(arg->name(), arg);
+ }
+ }
+ }
+
+ s << endl;
+
+ foreach (AbstractMetaArgument* arg, arg_map.values()) {
+ Indentation indentation(INDENT);
+ writeParamerteType(s, cppClass, arg);
+ }
+
+ s << endl;
+
+ foreach (AbstractMetaFunction* func, lst) {
+ writeFormatedText(s, func->documentation(), cppClass);
+ }
+}
+
+QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ QString ret;
+ int optArgs = 0;
+
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ bool thisIsoptional = !arg->defaultValueExpression().isEmpty();
+ if (optArgs || thisIsoptional) {
+ ret += '[';
+ optArgs++;
+ }
+
+ if (arg->argumentIndex() > 0)
+ ret += ", ";
+
+ ret += arg->name();
+
+ if (thisIsoptional) {
+ QString defValue = arg->defaultValueExpression();
+ if (defValue == "QString()") {
+ defValue = "\"\"";
+ } else if (defValue == "QStringList()" || defValue.startsWith("QVector") || defValue.startsWith("QList")) {
+ defValue = "list()";
+ } else if (defValue == "QVariant()") {
+ defValue = "None";
+ } else {
+ defValue.replace("::", ".");
+ if (defValue == "0" && (arg->type()->isQObject() || arg->type()->isObject()))
+ defValue = "None";
+ }
+ ret += "=" + defValue;
+ }
+ }
+
+ ret += QString(']').repeated(optArgs);
+ return ret;
+}
+
+void QtDocGenerator::writeDocSnips(QTextStream &s,
+ const CodeSnipList &codeSnips,
+ CodeSnip::Position position,
+ TypeSystem::Language language)
+{
+ Indentation indentation(INDENT);
+ QStringList invalidStrings;
+ const static QString startMarkup("[sphinx-begin]");
+ const static QString endMarkup("[sphinx-end]");
+
+ invalidStrings << "*" << "//" << "/*" << "*/";
+
+ foreach (CodeSnip snip, codeSnips) {
+ if ((snip.position != position) ||
+ !(snip.language & language))
+ continue;
+
+ QString code = snip.code();
+ while (code.contains(startMarkup) && code.contains(endMarkup)) {
+ int startBlock = code.indexOf(startMarkup) + startMarkup.size();
+ int endBlock = code.indexOf(endMarkup);
+
+ if ((startBlock == -1) || (endBlock == -1))
+ break;
+
+ QString codeBlock = code.mid(startBlock, endBlock - startBlock);
+ QStringList rows = codeBlock.split("\n");
+ int currenRow = 0;
+ int offset = 0;
+
+ foreach(QString row, rows) {
+ foreach(QString invalidString, invalidStrings) {
+ row = row.remove(invalidString);
+ }
+
+ if (row.trimmed().size() == 0) {
+ if (currenRow == 0)
+ continue;
+ else
+ s << endl;
+ }
+
+ if (currenRow == 0) {
+ //find offset
+ for (int i=0, i_max = row.size(); i < i_max; i++) {
+ if (row[i] == ' ')
+ offset++;
+ else if (row[i] == '\n')
+ offset = 0;
+ else
+ break;
+ }
+ }
+ row = row.mid(offset);
+ s << row << endl;
+ currenRow++;
+ }
+
+ code = code.mid(endBlock+endMarkup.size());
+ }
+ }
+}
+
+bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
+ DocModification::Mode mode,
+ const AbstractMetaClass* cppClass,
+ const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ bool didSomething = false;
+
+ foreach (DocModification mod, cppClass->typeEntry()->docModifications()) {
+ if (mod.mode() == mode) {
+ bool modOk = func ? mod.signature() == func->minimalSignature() : mod.signature().isEmpty();
+
+ if (modOk) {
+ Documentation doc;
+ Documentation::Format fmt;
+
+ if (mod.format == TypeSystem::NativeCode)
+ fmt = Documentation::Native;
+ else if (mod.format == TypeSystem::TargetLangCode)
+ fmt = Documentation::Target;
+ else
+ continue;
+
+ doc.setValue(mod.code() , fmt);
+ writeFormatedText(s, doc, cppClass);
+ didSomething = true;
+ }
+ }
+ }
+
+ s << endl;
+
+ // TODO: Deprecate the use of doc string on glue code.
+ // This is pre "add-function" and "inject-documentation" tags.
+ if (func) {
+ writeDocSnips(s, func->injectedCodeSnips(),
+ (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End),
+ TypeSystem::TargetLangCode);
+ } else {
+ writeDocSnips(s, cppClass->typeEntry()->codeSnips(),
+ (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End),
+ TypeSystem::TargetLangCode);
+ }
+ return didSomething;
+}
+
+void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ QString className;
+ if (!func->isConstructor())
+ className = getClassTargetFullName(cppClass) + '.';
+ else if (func->implementingClass() && func->implementingClass()->enclosingClass())
+ className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + '.';
+
+ QString funcName = getFuncName(func);
+ if (!funcName.startsWith(className))
+ funcName = className + funcName;
+
+ s << funcName << "(" << parseArgDocStyle(cppClass, func) << ")";
+}
+
+QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, const AbstractMetaClass* cppClass)
+{
+ QString strType;
+ if (type->name() == "QString") {
+ strType = "unicode";
+ } else if (type->name() == "QVariant") {
+ strType = "object";
+ } else if (type->name() == "QStringList") {
+ strType = "list of strings";
+ } else if (type->isConstant() && type->name() == "char" && type->indirections() == 1) {
+ strType = "str";
+ } else if (type->name().startsWith("unsigned short")) {
+ strType = "int";
+ } else if (type->name().startsWith("unsigned ")) { // uint and ulong
+ strType = "long";
+ } else if (type->isContainer()) {
+ QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference);
+ strType.remove("*");
+ strType.remove(">");
+ strType.remove("<");
+ strType.replace("::", ".");
+ if (strType.contains("QList") || strType.contains("QVector")) {
+ strType.replace("QList", "list of ");
+ strType.replace("QVector", "list of ");
+ } else if (strType.contains("QHash") || strType.contains("QMap")) {
+ strType.remove("QHash");
+ strType.remove("QMap");
+ QStringList types = strType.split(",");
+ strType = QString("Dictionary with keys of type %1 and values of type %2.")
+ .arg(types[0]).arg(types[1]);
+ }
+ } else {
+ QString refTag;
+ if (type->isEnum())
+ refTag = "attr";
+ else
+ refTag = "class";
+ strType = ':' + refTag + ":`" + type->fullName() + '`';
+ }
+ return strType;
+}
+
+void QtDocGenerator::writeParamerteType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg)
+{
+ s << INDENT << ":param " << arg->name() << ": "
+ << translateToPythonType(arg->type(), cppClass) << endl;
+}
+
+void QtDocGenerator::writeFunctionParametersType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+
+ s << endl;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ writeParamerteType(s, cppClass, arg);
+ }
+
+ if (!func->isConstructor() && func->type()) {
+
+ QString retType;
+ // check if the return type was modified
+ foreach (FunctionModification mod, func->modifications()) {
+ foreach (ArgumentModification argMod, mod.argument_mods) {
+ if (argMod.index == 0) {
+ retType = argMod.modified_type;
+ break;
+ }
+ }
+ }
+
+ if (retType.isEmpty())
+ retType = translateToPythonType(func->type(), cppClass);
+ s << INDENT << ":rtype: " << retType << endl;
+ }
+ s << endl;
+}
+
+void QtDocGenerator::writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ writeFunctionSignature(s, cppClass, func);
+ s << endl;
+
+ if (func->typeEntry() && (func->typeEntry()->version() != 0))
+ s << ".. note:: This method was introduced in Qt " << func->typeEntry()->version() << endl;
+
+ if (writeDoc) {
+ s << endl;
+ writeFunctionParametersType(s, cppClass, func);
+ s << endl;
+ writeInjectDocumentation(s, DocModification::Prepend, cppClass, func);
+ if (!writeInjectDocumentation(s, DocModification::Replace, cppClass, func))
+ writeFormatedText(s, func->documentation(), cppClass);
+ writeInjectDocumentation(s, DocModification::Append, cppClass, func);
+ }
+}
+
+static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4)
+{
+ typedef QMap<QChar, QStringList> TocMap;
+ TocMap tocMap;
+ QChar Q('Q');
+ QChar idx;
+ foreach (QString item, items) {
+ if (item.isEmpty())
+ continue;
+ if (item.startsWith(Q) && item.length() > 1)
+ idx = item[1];
+ item.chop(4); // Remove the .rst extension
+ tocMap[idx] << item;
+ }
+ QtXmlToSphinx::Table table;
+ QtXmlToSphinx::TableRow row;
+
+ int itemsPerCol = (items.size() + tocMap.size()*2) / cols;
+ QString currentColData;
+ int i = 0;
+ QTextStream ss(&currentColData);
+ QMutableMapIterator<QChar, QStringList> it(tocMap);
+ while (it.hasNext()) {
+ it.next();
+ qSort(it.value());
+
+ if (i)
+ ss << endl;
+
+ ss << "**" << it.key() << "**" << endl << endl;
+ i += 2; // a letter title is equivalent to two entries in space
+ foreach (QString item, it.value()) {
+ ss << "* :doc:`" << item << "`" << endl;
+ ++i;
+
+ // end of column detected!
+ if (i > itemsPerCol) {
+ ss.flush();
+ QtXmlToSphinx::TableCell cell(currentColData);
+ row << cell;
+ currentColData.clear();
+ i = 0;
+ }
+ }
+ }
+ if (i) {
+ ss.flush();
+ QtXmlToSphinx::TableCell cell(currentColData);
+ row << cell;
+ currentColData.clear();
+ i = 0;
+ }
+ table << row;
+ table.normalize();
+ s << ".. container:: pysidetoc" << endl << endl;
+ s << table;
+}
+
+void QtDocGenerator::finishGeneration()
+{
+ if (classes().isEmpty())
+ return;
+
+ QMap<QString, QStringList>::iterator it = m_packages.begin();
+ for (; it != m_packages.end(); ++it) {
+ QString outputDir = outputDirectory() + '/' + QString(it.key()).replace(".", "/");
+ FileOut output(outputDir + "/index.rst");
+ QTextStream& s = output.stream;
+
+ s << ".. module:: " << it.key() << endl << endl;
+
+ QString title = it.key();
+ s << title << endl;
+ s << createRepeatedChar(title.length(), '*') << endl << endl;
+
+ /* Avoid showing "Detailed Description for *every* class in toc tree */
+ Indentation indentation(INDENT);
+
+ // Search for extra-sections
+ if (!m_extraSectionDir.isEmpty()) {
+ QDir extraSectionDir(m_extraSectionDir);
+ QStringList fileList = extraSectionDir.entryList(QStringList() << (it.key() + "?*.rst"), QDir::Files);
+ QStringList::iterator it2 = fileList.begin();
+ for (; it2 != fileList.end(); ++it2) {
+ QString origFileName(*it2);
+ it2->remove(0, it.key().count() + 1);
+ QString newFilePath = outputDir + '/' + *it2;
+ if (QFile::exists(newFilePath))
+ QFile::remove(newFilePath);
+ if (!QFile::copy(m_extraSectionDir + '/' + origFileName, newFilePath)) {
+ ReportHandler::warning("Error copying extra doc " + (m_extraSectionDir + '/' + origFileName)
+ + " to " + newFilePath);
+ }
+ }
+ it.value().append(fileList);
+ }
+
+ writeFancyToc(s, it.value());
+
+ s << INDENT << ".. container:: hide" << endl << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << ".. toctree::" << endl;
+ Indentation deeperIndentation(INDENT);
+ s << INDENT << ":maxdepth: 1" << endl << endl;
+ foreach (QString className, it.value())
+ s << INDENT << className << endl;
+ s << endl << endl;
+ }
+
+ s << "Detailed Description" << endl;
+ s << "--------------------" << endl << endl;
+
+ // module doc is always wrong and C++istic, so go straight to the extra directory!
+ QFile moduleDoc(m_extraSectionDir + '/' + it.key() + ".rst");
+ if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ s << moduleDoc.readAll();
+ moduleDoc.close();
+ } else {
+ // try the normal way
+ Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key());
+ if (moduleDoc.format() == Documentation::Native) {
+ QtXmlToSphinx x(this, moduleDoc.value(), QString(it.key()).remove(0, it.key().lastIndexOf('.') + 1));
+ s << x;
+ } else {
+ s << moduleDoc.value();
+ }
+ }
+ }
+}
+
+bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ m_libSourceDir = args.value("library-source-dir");
+ m_docDataDir = args.value("documentation-data-dir");
+#ifdef __WIN32__
+# define PATH_SEP ";"
+#else
+# define PATH_SEP ":"
+#endif
+ m_codeSnippetDirs = args.value("documentation-code-snippets-dir", m_libSourceDir).split(PATH_SEP);
+ m_extraSectionDir = args.value("documentation-extra-sections-dir");
+
+ m_docParser = args.value("doc-parser") == "doxygen" ? reinterpret_cast<DocParser*>(new DoxygenParser) : reinterpret_cast<DocParser*>(new QtDocParser);
+ ReportHandler::warning("doc-parser: " + args.value("doc-parser"));
+
+ if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) {
+ ReportHandler::warning("Documentation data dir and/or Qt source dir not informed, "
+ "documentation will not be extracted from Qt sources.");
+ return false;
+ } else {
+ m_docParser->setDocumentationDataDirectory(m_docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_libSourceDir);
+ }
+ return true;
+}
+
+
+QMap<QString, QString> QtDocGenerator::options() const
+{
+ QMap<QString, QString> options;
+ options.insert("doc-parser", "The documentation parser used to interpret the documentaion input files (qdoc3|doxygen)");
+ options.insert("library-source-dir", "Directory where library source code is located");
+ options.insert("documentation-data-dir", "Directory with XML files generated by documentation tool (qdoc3 or Doxygen)");
+ options.insert("documentation-code-snippets-dir", "Directory used to search code snippets used by the documentation");
+ options.insert("documentation-extra-sections-dir", "Directory used to search for extra documentation sections");
+ return options;
+}
+
diff --git a/generators/qtdoc/qtdocgenerator.h b/generators/qtdoc/qtdocgenerator.h
new file mode 100644
index 00000000..247b4836
--- /dev/null
+++ b/generators/qtdoc/qtdocgenerator.h
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef DOCGENERATOR_H
+#define DOCGENERATOR_H
+
+#include <QtCore/QStack>
+#include <QtCore/QHash>
+#include <QtCore/QTextStream>
+#include <QXmlStreamReader>
+#include <abstractmetalang.h>
+#include "generator.h"
+#include "docparser.h"
+
+class QtDocParser;
+class AbstractMetaFunction;
+class AbstractMetaClass;
+class QXmlStreamReader;
+class QtDocGenerator;
+
+class QtXmlToSphinx
+{
+public:
+ struct TableCell
+ {
+ short rowSpan;
+ short colSpan;
+ QString data;
+
+ TableCell(const QString& text = QString()) : rowSpan(0), colSpan(0), data(text) {}
+ TableCell(const char* text) : rowSpan(0), colSpan(0), data(text) {}
+ };
+
+ typedef QList<TableCell> TableRow;
+ class Table : public QList<TableRow>
+ {
+ public:
+ Table() : m_hasHeader(false), m_normalized(false)
+ {
+ }
+
+ void enableHeader(bool enable)
+ {
+ m_hasHeader = enable;
+ }
+
+ bool hasHeader() const
+ {
+ return m_hasHeader;
+ }
+
+ void normalize();
+
+ bool isNormalized() const
+ {
+ return m_normalized;
+ }
+
+ void clear() {
+ m_normalized = false;
+ QList<TableRow>::clear();
+ }
+
+ private:
+ bool m_hasHeader;
+ bool m_normalized;
+ };
+
+ QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context = QString());
+
+ QString result() const
+ {
+ return m_result;
+ }
+
+private:
+ QString resolveContextForMethod(const QString& methodName);
+ QString expandFunction(const QString& function);
+ QString transform(const QString& doc);
+
+ void handleHeadingTag(QXmlStreamReader& reader);
+ void handleParaTag(QXmlStreamReader& reader);
+ void handleItalicTag(QXmlStreamReader& reader);
+ void handleBoldTag(QXmlStreamReader& reader);
+ void handleArgumentTag(QXmlStreamReader& reader);
+ void handleSeeAlsoTag(QXmlStreamReader& reader);
+ void handleSnippetTag(QXmlStreamReader& reader);
+ void handleDotsTag(QXmlStreamReader& reader);
+ void handleLinkTag(QXmlStreamReader& reader);
+ void handleImageTag(QXmlStreamReader& reader);
+ void handleListTag(QXmlStreamReader& reader);
+ void handleTermTag(QXmlStreamReader& reader);
+ void handleSuperScriptTag(QXmlStreamReader& reader);
+ void handleQuoteFileTag(QXmlStreamReader& reader);
+
+ // table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader)
+
+ void handleTableTag(QXmlStreamReader& reader);
+ void handleRowTag(QXmlStreamReader& reader);
+ void handleItemTag(QXmlStreamReader& reader);
+ void handleRawTag(QXmlStreamReader& reader);
+ void handleCodeTag(QXmlStreamReader& reader);
+
+ void handleIgnoredTag(QXmlStreamReader& reader);
+ void handleUnknownTag(QXmlStreamReader& reader);
+ void handleUselessTag(QXmlStreamReader& reader);
+ void handleAnchorTag(QXmlStreamReader& reader);
+
+ typedef void (QtXmlToSphinx::*TagHandler)(QXmlStreamReader&);
+ QHash<QString, TagHandler> m_handlerMap;
+ QStack<TagHandler> m_handlers;
+ QTextStream m_output;
+ QString m_result;
+
+ QStack<QString*> m_buffers;
+
+
+ Table m_currentTable;
+ bool m_tableHasHeader;
+ QString m_context;
+ QtDocGenerator* m_generator;
+ bool m_insideBold;
+ bool m_insideItalic;
+ QString m_lastTagName;
+ QString m_opened_anchor;
+
+ QString readFromLocations(const QStringList& locations, const QString& path, const QString& identifier);
+ QString readFromLocation(const QString& location, const QString& identifier, bool* ok = 0);
+ void pushOutputBuffer();
+ QString popOutputBuffer();
+ void writeTable(Table& table);
+};
+
+inline QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx& xmlToSphinx)
+{
+ return s << xmlToSphinx.result();
+}
+
+QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table);
+
+/**
+* The DocGenerator generates documentation from library being binded.
+*/
+class QtDocGenerator : public Generator
+{
+public:
+ QtDocGenerator();
+ ~QtDocGenerator();
+
+ QString libSourceDir() const
+ {
+ return m_libSourceDir;
+ }
+
+ bool doSetup(const QMap<QString, QString>& args);
+
+ const char* name() const
+ {
+ return "QtDocGenerator";
+ }
+
+ QMap<QString, QString> options() const;
+
+ QStringList codeSnippetDirs() const
+ {
+ return m_codeSnippetDirs;
+ }
+
+protected:
+ QString fileNameForClass(const AbstractMetaClass* cppClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration();
+
+ void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {}
+
+private:
+ void writeEnums(QTextStream& s, const AbstractMetaClass* cppClass);
+
+ void writeFields(QTextStream &s, const AbstractMetaClass *cppClass);
+ void writeArguments(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func);
+ void writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func);
+ void writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass);
+ void writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions);
+ void writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg);
+
+ void writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass);
+ void writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaclass = 0);
+ bool writeInjectDocumentation(QTextStream& s, DocModification::Mode mode, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, CodeSnip::Position position, TypeSystem::Language language);
+
+
+ QString parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func);
+ QString translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass);
+
+ QString m_docDataDir;
+ QString m_libSourceDir;
+ QStringList m_codeSnippetDirs;
+ QString m_extraSectionDir;
+ QStringList m_functionList;
+ QMap<QString, QStringList> m_packages;
+ DocParser* m_docParser;
+};
+
+#endif // DOCGENERATOR_H
diff --git a/generators/shiboken/CMakeLists.txt b/generators/shiboken/CMakeLists.txt
new file mode 100644
index 00000000..57aac33a
--- /dev/null
+++ b/generators/shiboken/CMakeLists.txt
@@ -0,0 +1,30 @@
+project(shibokengenerator)
+
+set(shiboken_SRC
+../generator.cpp
+cppgenerator.cpp
+headergenerator.cpp
+overloaddata.cpp
+shibokengenerator.cpp
+shibokennormalize.cpp
+main.cpp
+)
+
+include_directories(${generators_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR}
+ ${QT_INCLUDE_DIR}
+ ${QT_QTCORE_INCLUDE_DIR}
+ ${QT_QTXML_INCLUDE_DIR})
+
+add_executable(shiboken ${shiboken_SRC})
+set_target_properties(shiboken PROPERTIES OUTPUT_NAME shiboken${shiboken_SUFFIX})
+target_link_libraries(shiboken
+ ${APIEXTRACTOR_LIBRARY}
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTXML_LIBRARY})
+
+configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
+
+install(TARGETS shiboken DESTINATION bin)
diff --git a/generator/cppgenerator.cpp b/generators/shiboken/cppgenerator.cpp
index fa19f7a3..fa19f7a3 100644
--- a/generator/cppgenerator.cpp
+++ b/generators/shiboken/cppgenerator.cpp
diff --git a/generator/cppgenerator.h b/generators/shiboken/cppgenerator.h
index 62551499..62551499 100644
--- a/generator/cppgenerator.h
+++ b/generators/shiboken/cppgenerator.h
diff --git a/generator/headergenerator.cpp b/generators/shiboken/headergenerator.cpp
index 9be27206..9be27206 100644
--- a/generator/headergenerator.cpp
+++ b/generators/shiboken/headergenerator.cpp
diff --git a/generator/headergenerator.h b/generators/shiboken/headergenerator.h
index e830efae..e830efae 100644
--- a/generator/headergenerator.h
+++ b/generators/shiboken/headergenerator.h
diff --git a/generators/shiboken/main.cpp b/generators/shiboken/main.cpp
new file mode 100644
index 00000000..290808bc
--- /dev/null
+++ b/generators/shiboken/main.cpp
@@ -0,0 +1,471 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <QCoreApplication>
+#include <QLinkedList>
+#include <QLibrary>
+#include <QDomDocument>
+#include <iostream>
+#include <apiextractor.h>
+#include "generator.h"
+#include "shibokenconfig.h"
+#include "cppgenerator.h"
+#include "headergenerator.h"
+
+#ifdef _WINDOWS
+ #define PATH_SPLITTER ";"
+#else
+ #define PATH_SPLITTER ":"
+#endif
+
+namespace {
+
+class ArgsHandler
+{
+public:
+ explicit ArgsHandler(const QMap<QString, QString>& other);
+ virtual ~ArgsHandler();
+
+ inline QMap<QString, QString>& args() const
+ {
+ return *m_args;
+ }
+
+ inline bool argExists(const QString& s) const
+ {
+ return m_args->contains(s);
+ }
+
+ QString removeArg(const QString& s);
+ bool argExistsRemove(const QString& s);
+
+ inline QString argValue(const QString& s) const
+ {
+ return m_args->value(s);
+ }
+
+ inline bool noArgs() const
+ {
+ return m_args->isEmpty();
+ }
+
+private:
+ QMap<QString, QString>* m_args;
+};
+
+ArgsHandler::ArgsHandler(const QMap<QString, QString>& other)
+ : m_args(new QMap<QString, QString>(other))
+{
+}
+
+ArgsHandler::~ArgsHandler()
+{
+ delete m_args;
+}
+
+QString ArgsHandler::removeArg(const QString& s)
+{
+ QString retval;
+
+ if (argExists(s)) {
+ retval = argValue(s);
+ m_args->remove(s);
+ }
+
+ return retval;
+}
+
+bool ArgsHandler::argExistsRemove(const QString& s)
+{
+ bool retval = false;
+
+ if (argExists(s)) {
+ retval = true;
+ m_args->remove(s);
+ }
+
+ return retval;
+}
+
+}
+
+static void printOptions(QTextStream& s, const QMap<QString, QString>& options)
+{
+ QMap<QString, QString>::const_iterator it = options.constBegin();
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ for (; it != options.constEnd(); ++it) {
+ s << " --";
+ s.setFieldWidth(38);
+ s << it.key() << it.value();
+ s.setFieldWidth(0);
+ s << endl;
+ }
+}
+
+typedef void (*getGeneratorsFunc)(QLinkedList<Generator*>*);
+
+static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
+{
+ QByteArray line = projectFile.readLine().trimmed();
+ if (line.isEmpty() || line != "[generator-project]")
+ return false;
+
+ QStringList includePaths;
+ QStringList typesystemPaths;
+ QStringList apiVersions;
+
+ while (!projectFile.atEnd()) {
+ line = projectFile.readLine().trimmed();
+ if (line.isEmpty())
+ continue;
+
+ int split = line.indexOf("=");
+ QString key;
+ QString value;
+ if (split > 0) {
+ key = line.left(split - 1).trimmed();
+ value = line.mid(split + 1).trimmed();
+ } else {
+ key = line;
+ }
+
+ if (key == "include-path")
+ includePaths << QDir::toNativeSeparators(value);
+ else if (key == "typesystem-path")
+ typesystemPaths << QDir::toNativeSeparators(value);
+ else if (key == "api-version")
+ apiVersions << value;
+ else if (key == "header-file")
+ args["arg-1"] = value;
+ else if (key == "typesystem-file")
+ args["arg-2"] = value;
+ else
+ args[key] = value;
+ }
+
+ if (!includePaths.isEmpty())
+ args["include-paths"] = includePaths.join(PATH_SPLITTER);
+
+ if (!typesystemPaths.isEmpty())
+ args["typesystem-paths"] = typesystemPaths.join(PATH_SPLITTER);
+ if (!apiVersions.isEmpty())
+ args["api-version"] = apiVersions.join("|");
+ return true;
+}
+
+static QMap<QString, QString> getInitializedArguments()
+{
+ QMap<QString, QString> args;
+ QStringList arguments = QCoreApplication::arguments();
+ QString appName = arguments.first();
+ arguments.removeFirst();
+
+ QString projectFileName;
+ foreach (const QString& arg, arguments) {
+ if (arg.startsWith("--project-file")) {
+ int split = arg.indexOf("=");
+ if (split > 0)
+ projectFileName = arg.mid(split + 1).trimmed();
+ break;
+ }
+ }
+
+ if (projectFileName.isNull())
+ return args;
+
+ if (!QFile::exists(projectFileName)) {
+ std::cerr << qPrintable(appName) << ": Project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" not found.";
+ std::cerr << std::endl;
+ return args;
+ }
+
+ QFile projectFile(projectFileName);
+ if (!projectFile.open(QIODevice::ReadOnly))
+ return args;
+
+ if (!processProjectFile(projectFile, args)) {
+ std::cerr << qPrintable(appName) << ": first line of project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" must be the string \"[generator-project]\"";
+ std::cerr << std::endl;
+ return args;
+ }
+
+ return args;
+}
+
+static QMap<QString, QString> getCommandLineArgs()
+{
+ QMap<QString, QString> args = getInitializedArguments();
+ QStringList arguments = QCoreApplication::arguments();
+ arguments.removeFirst();
+
+ int argNum = 0;
+ foreach (QString arg, arguments) {
+ arg = arg.trimmed();
+ if (arg.startsWith("--")) {
+ int split = arg.indexOf("=");
+ if (split > 0)
+ args[arg.mid(2).left(split-2)] = arg.mid(split + 1).trimmed();
+ else
+ args[arg.mid(2)] = QString();
+ } else if (arg.startsWith("-")) {
+ args[arg.mid(1)] = QString();
+ } else {
+ argNum++;
+ args[QString("arg-%1").arg(argNum)] = arg;
+ }
+ }
+ return args;
+}
+
+void printUsage(const GeneratorList& generators)
+{
+ QTextStream s(stdout);
+ s << "Usage:\n "
+ << "shiboken [options] header-file typesystem-file\n\n"
+ << "General options:\n";
+ QMap<QString, QString> generalOptions;
+ generalOptions.insert("project-file=<file>", "text file containing a description of the binding project. Replaces and overrides command line arguments");
+ generalOptions.insert("debug-level=[sparse|medium|full]", "Set the debug level");
+ generalOptions.insert("silent", "Avoid printing any message");
+ generalOptions.insert("help", "Display this help and exit");
+ generalOptions.insert("no-suppress-warnings", "Show all warnings");
+ generalOptions.insert("output-directory=<path>", "The directory where the generated files will be written");
+ generalOptions.insert("include-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Include paths used by the C++ parser");
+ generalOptions.insert("typesystem-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Paths used when searching for typesystems");
+ generalOptions.insert("documentation-only", "Do not generates any code, just the documentation");
+ generalOptions.insert("license-file=<license-file>", "File used for copyright headers of generated files");
+ generalOptions.insert("version", "Output version information and exit");
+ generalOptions.insert("generator-set=<\"generator module\">", "generator-set to be used. e.g. qtdoc");
+ generalOptions.insert("api-version=<\"package mask\">,<\"version\">", "Specify the supported api version used to generate the bindings");
+ generalOptions.insert("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\"", "Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation.");
+ printOptions(s, generalOptions);
+
+ foreach (Generator* generator, generators) {
+ QMap<QString, QString> options = generator->options();
+ if (!options.isEmpty()) {
+ s << endl << generator->name() << " options:\n";
+ printOptions(s, generator->options());
+ }
+ }
+}
+
+static inline void printVerAndBanner()
+{
+ std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl;
+ std::cout << "Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies)" << std::endl;
+}
+
+static inline void errorPrint(const QString& s,
+ const bool& verAndBanner = false)
+{
+ if (verAndBanner)
+ printVerAndBanner();
+
+ std::cerr << s.toAscii().constData() << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+ // needed by qxmlpatterns
+ QCoreApplication app(argc, argv);
+
+ // Store command arguments in a map
+ QMap<QString, QString> args = getCommandLineArgs();
+ ArgsHandler argsHandler(args);
+ GeneratorList generators;
+
+ if (argsHandler.argExistsRemove("version")) {
+ printVerAndBanner();
+ return EXIT_SUCCESS;
+ }
+
+ // FIXME: This should be choosen by command line!
+ generators << new CppGenerator << new HeaderGenerator;
+#if 0
+ // Try to load a generator
+ QString generatorSet = argsHandler.removeArg("generator-set");
+
+ // Also check "generatorSet" command line argument for backward compatibility.
+ if (generatorSet.isEmpty())
+ generatorSet = argsHandler.removeArg("generatorSet");
+
+ if (!generatorSet.isEmpty()) {
+ QFileInfo generatorFile(generatorSet);
+ if (!generatorFile.exists()) {
+ QString generatorSetName(generatorSet + "_generator");
+
+ // More library paths may be added via the QT_PLUGIN_PATH environment variable.
+ QCoreApplication::addLibraryPath("foobar");
+ foreach (const QString& path, QCoreApplication::libraryPaths()) {
+ generatorFile.setFile(QDir(path), generatorSetName);
+ if (generatorFile.exists())
+ break;
+ }
+ }
+
+ if (!generatorFile.exists()) {
+ errorPrint(QString("shiboken: Error loading generator-set plugin: %2 module not found.").arg(qPrintable(generatorFile.baseName())), true);
+ return EXIT_FAILURE;
+ }
+
+ QLibrary plugin(generatorFile.filePath());
+ getGeneratorsFunc getGenerators = (getGeneratorsFunc)plugin.resolve("getGenerators");
+ if (getGenerators) {
+ getGenerators(&generators);
+ } else {
+ errorPrint(QString("shiboken: Error loading generator-set plugin: %2").
+ arg(qPrintable(plugin.errorString())), true);
+ return EXIT_FAILURE;
+ }
+ } else if (!argsHandler.argExists("help")) {
+ errorPrint("shiboken: You need to specify a generator with --generator-set=GENERATOR_NAME");
+ return EXIT_FAILURE;
+ }
+#endif
+
+ if (argsHandler.argExistsRemove("help")) {
+ printUsage(generators);
+ return EXIT_SUCCESS;
+ }
+
+ QString licenseComment;
+ QString licenseFileName = argsHandler.removeArg("license-file");
+ if (!licenseFileName.isEmpty()) {
+ if (QFile::exists(licenseFileName)) {
+ QFile licenseFile(licenseFileName);
+ if (licenseFile.open(QIODevice::ReadOnly))
+ licenseComment = licenseFile.readAll();
+ } else {
+ errorPrint(QString("Couldn't find the file containing the license heading: %1").
+ arg(qPrintable(licenseFileName)));
+ return EXIT_FAILURE;
+ }
+ }
+
+ QString outputDirectory = argsHandler.removeArg("output-directory");
+ if (outputDirectory.isEmpty())
+ outputDirectory = "out";
+
+ if (!QDir(outputDirectory).exists()) {
+ if (!QDir().mkpath(outputDirectory)) {
+ ReportHandler::warning("Can't create output directory: "+outputDirectory);
+ return EXIT_FAILURE;
+ }
+ }
+
+ // Create and set-up API Extractor
+ ApiExtractor extractor;
+ extractor.setLogDirectory(outputDirectory);
+
+ if (argsHandler.argExistsRemove("silent")) {
+ extractor.setSilent(true);
+ } else {
+ QString level = argsHandler.removeArg("debug-level");
+ if (!level.isEmpty()) {
+ if (level == "sparse")
+ extractor.setDebugLevel(ReportHandler::SparseDebug);
+ else if (level == "medium")
+ extractor.setDebugLevel(ReportHandler::MediumDebug);
+ else if (level == "full")
+ extractor.setDebugLevel(ReportHandler::FullDebug);
+ }
+ }
+ if (argsHandler.argExistsRemove("no-suppress-warnings"))
+ extractor.setSuppressWarnings(false);
+
+ if (argsHandler.argExists("api-version")) {
+ QStringList versions = argsHandler.removeArg("api-version").split("|");
+ foreach (QString fullVersion, versions) {
+ QStringList parts = fullVersion.split(",");
+ QString package;
+ QString version;
+ package = parts.count() == 1 ? "*" : parts.first();
+ version = parts.last();
+ extractor.setApiVersion(package, version.toAscii());
+ }
+ }
+
+ if (argsHandler.argExists("drop-type-entries"))
+ extractor.setDropTypeEntries(argsHandler.removeArg("drop-type-entries"));
+
+ QString path = argsHandler.removeArg("typesystem-paths");
+ if (!path.isEmpty())
+ extractor.addTypesystemSearchPath(path.split(PATH_SPLITTER));
+
+ path = argsHandler.removeArg("include-paths");
+ if (!path.isEmpty())
+ extractor.addIncludePath(path.split(PATH_SPLITTER));
+
+ QString cppFileName = argsHandler.removeArg("arg-1");
+ QString typeSystemFileName = argsHandler.removeArg("arg-2");
+
+ /* Make sure to remove the project file's arguments (if any) and
+ * --project-file, also the arguments of each generator before
+ * checking if there isn't any existing arguments in argsHandler.
+ */
+ argsHandler.removeArg("project-file");
+ QMap<QString, QString> projectFileArgs = getInitializedArguments();
+ if (!projectFileArgs.isEmpty()) {
+ QMap<QString, QString>::const_iterator it =
+ projectFileArgs.constBegin();
+ for ( ; it != projectFileArgs.constEnd(); ++it)
+ argsHandler.removeArg(it.key());
+ }
+ foreach (Generator* generator, generators) {
+ QMap<QString, QString> options = generator->options();
+ if (!options.isEmpty()) {
+ QMap<QString, QString>::const_iterator it = options.constBegin();
+ for ( ; it != options.constEnd(); ++it)
+ argsHandler.removeArg(it.key());
+ }
+ }
+
+ if (!argsHandler.noArgs()) {
+ errorPrint("shiboken: Called with wrong arguments.");
+ std::cout << "Note: use --help option for more information." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ extractor.setCppFileName(cppFileName);
+ extractor.setTypeSystem(typeSystemFileName);
+ if (!extractor.run())
+ return EXIT_FAILURE;
+
+ if (!extractor.classCount())
+ ReportHandler::warning("No C++ classes found!");
+
+ foreach (Generator* g, generators) {
+ g->setOutputDirectory(outputDirectory);
+ g->setLicenseComment(licenseComment);
+ if (g->setup(extractor, args))
+ g->generate();
+ }
+ qDeleteAll(generators);
+
+ ReportHandler::flush();
+ std::cout << "Done, " << ReportHandler::warningCount();
+ std::cout << " warnings (" << ReportHandler::suppressedCount() << " known issues)";
+ std::cout << std::endl;
+}
diff --git a/generator/overloaddata.cpp b/generators/shiboken/overloaddata.cpp
index 57084558..57084558 100644
--- a/generator/overloaddata.cpp
+++ b/generators/shiboken/overloaddata.cpp
diff --git a/generator/overloaddata.h b/generators/shiboken/overloaddata.h
index a0bd4640..a0bd4640 100644
--- a/generator/overloaddata.h
+++ b/generators/shiboken/overloaddata.h
diff --git a/generator/shibokenconfig.h.in b/generators/shiboken/shibokenconfig.h.in
index 7d844a94..7d844a94 100644
--- a/generator/shibokenconfig.h.in
+++ b/generators/shiboken/shibokenconfig.h.in
diff --git a/generator/shibokengenerator.cpp b/generators/shiboken/shibokengenerator.cpp
index 2ae213db..2ae213db 100644
--- a/generator/shibokengenerator.cpp
+++ b/generators/shiboken/shibokengenerator.cpp
diff --git a/generator/shibokengenerator.h b/generators/shiboken/shibokengenerator.h
index 4a73cbc9..4a73cbc9 100644
--- a/generator/shibokengenerator.h
+++ b/generators/shiboken/shibokengenerator.h
diff --git a/generator/shibokennormalize.cpp b/generators/shiboken/shibokennormalize.cpp
index 01aad973..01aad973 100644
--- a/generator/shibokennormalize.cpp
+++ b/generators/shiboken/shibokennormalize.cpp
diff --git a/generator/shibokennormalize_p.h b/generators/shiboken/shibokennormalize_p.h
index 0a55b507..0a55b507 100644
--- a/generator/shibokennormalize_p.h
+++ b/generators/shiboken/shibokennormalize_p.h
diff --git a/shibokenmodule/CMakeLists.txt b/shibokenmodule/CMakeLists.txt
index df5040fd..c4b36dc7 100644
--- a/shibokenmodule/CMakeLists.txt
+++ b/shibokenmodule/CMakeLists.txt
@@ -9,7 +9,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/shiboken/shiboken_module_wrapper.cpp
)
add_custom_command(OUTPUT ${sample_SRC}
-COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt ${GENERATOR_EXTRA_FLAGS}
+COMMAND ${shibokengenerator_BINARY_DIR}/shiboken --project-file=${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt ${GENERATOR_EXTRA_FLAGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running generator for 'shiboken'..."
)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index df240cc6..ecea43c6 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -63,3 +63,32 @@ else()
endif()
endforeach()
endif()
+
+# FIXME Skipped until add an option to choose the generator
+# add_subdirectory(test_generator)
+
+if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED)
+# project(sphinxtabletest)
+#
+# # TODO
+# set(sphinxtabletest_SRC sphinxtabletest.cpp)
+# qt4_automoc(${sphinxtabletest_SRC})
+#
+# include_directories(${QT_INCLUDE_DIR}
+# ${QT_QTCORE_INCLUDE_DIR}
+# ${CMAKE_CURRENT_BINARY_DIR}
+# ${qtdoc_generator_SOURCE_DIR})
+#
+# add_executable(sphinxtabletest ${sphinxtabletest_SRC})
+#
+# target_link_libraries(sphinxtabletest
+# ${QT_QTTEST_LIBRARY}
+# ${APIEXTRACTOR_LIBRARY}
+# qtdoc_generator
+# genrunner)
+#
+# add_test("sphinxtable" sphinxtabletest)
+# if (INSTALL_TESTS)
+# install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/sphinxtabletest DESTINATION ${TEST_INSTALL_DIR})
+# endif()
+endif()
diff --git a/tests/minimalbinding/CMakeLists.txt b/tests/minimalbinding/CMakeLists.txt
index 6229dd7c..5933d5fd 100644
--- a/tests/minimalbinding/CMakeLists.txt
+++ b/tests/minimalbinding/CMakeLists.txt
@@ -16,7 +16,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY)
add_custom_command(OUTPUT ${minimal_SRC}
-COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS}
+COMMAND ${shibokengenerator_BINARY_DIR}/shiboken --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running generator for 'minimal' test binding..."
)
diff --git a/tests/otherbinding/CMakeLists.txt b/tests/otherbinding/CMakeLists.txt
index 366bdbd5..292b9d96 100644
--- a/tests/otherbinding/CMakeLists.txt
+++ b/tests/otherbinding/CMakeLists.txt
@@ -18,7 +18,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY)
add_custom_command(OUTPUT ${other_SRC}
-COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS}
+COMMAND ${shibokengenerator_BINARY_DIR}/shiboken --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running generator for 'other' test binding..."
)
diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt
index d7734592..74955ba1 100644
--- a/tests/samplebinding/CMakeLists.txt
+++ b/tests/samplebinding/CMakeLists.txt
@@ -116,7 +116,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY)
add_custom_command(OUTPUT ${sample_SRC}
-COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS}
+COMMAND ${shibokengenerator_BINARY_DIR}/shiboken --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running generator for 'sample' test binding..."
)
diff --git a/tests/sphinxtabletest.cpp b/tests/sphinxtabletest.cpp
new file mode 100644
index 00000000..c1ba59e6
--- /dev/null
+++ b/tests/sphinxtabletest.cpp
@@ -0,0 +1,327 @@
+/*
+* This file is part of the Boost Python Generator project.
+*
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+*
+* Contact: PySide team <contact@pyside.org>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#include "sphinxtabletest.h"
+#include "qtdocgenerator.h"
+#include <QtTest/QTest>
+#include <QDebug>
+
+QString SphinxTableTest::transformXml(const char* xml)
+{
+ return QtXmlToSphinx(m_generator, xml).result();
+}
+
+void SphinxTableTest::setUp()
+{
+ m_generator = new QtDocGenerator;
+}
+
+void SphinxTableTest::tearDown()
+{
+ delete m_generator;
+}
+
+void SphinxTableTest::testEmptyString()
+{
+ const char* xml = "";
+ QCOMPARE(transformXml(xml), QString());
+}
+
+void SphinxTableTest::testSimpleTable()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item>\
+ <para>Header 1</para>\
+ </item>\
+ <item>\
+ <para>Header 2</para>\
+ </item>\
+ </header>\
+ <row>\
+ <item>\
+ <para>1 1</para>\
+ </item>\
+ <item>\
+ <para>1 2</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item>\
+ <para>2 1</para>\
+ </item>\
+ <item>\
+ <para>2 2</para>\
+ </item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +--------+--------+\n\
+ |Header 1|Header 2|\n\
+ +--------+--------+\n\
+ |1 1 |1 2 |\n\
+ +--------+--------+\n\
+ |2 1 |2 2 |\n\
+ +--------+--------+\n\
+\n"));
+}
+
+void SphinxTableTest::testColSpan()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item>\
+ <para>Header 1</para>\
+ </item>\
+ <item>\
+ <para>Header 2</para>\
+ </item>\
+ </header>\
+ <row>\
+ <item colspan=\"2\">\
+ <para>I'm a big text!</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item>\
+ <para>2 1</para>\
+ </item>\
+ <item>\
+ <para>2 2</para>\
+ </item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +---------------+--------+\n\
+ |Header 1 |Header 2|\n\
+ +---------------+--------+\n\
+ |I'm a big text! |\n\
+ +---------------+--------+\n\
+ |2 1 |2 2 |\n\
+ +---------------+--------+\n\
+\n"));
+}
+
+
+void SphinxTableTest::testRowSpan()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item>\
+ <para>Header 1</para>\
+ </item>\
+ <item>\
+ <para>Header 2</para>\
+ </item>\
+ </header>\
+ <row>\
+ <item rowspan=\"2\">\
+ <para>1.1</para>\
+ </item>\
+ <item>\
+ <para>1.2</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item>\
+ <para>2 2</para>\
+ </item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +--------+--------+\n\
+ |Header 1|Header 2|\n\
+ +--------+--------+\n\
+ |1.1 |1.2 |\n\
+ + +--------+\n\
+ | |2 2 |\n\
+ +--------+--------+\n\
+\n"));
+}
+
+
+void SphinxTableTest::testComplexTable()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item>\
+ <para>Header 1</para>\
+ </item>\
+ <item>\
+ <para>Header 2</para>\
+ </item>\
+ <item>\
+ <para>Header 3</para>\
+ </item>\
+ </header>\
+ <row>\
+ <item rowspan=\"2\">\
+ <para>1.1</para>\
+ </item>\
+ <item colspan=\"2\">\
+ <para>1.2</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item>\
+ <para>2 2</para>\
+ </item>\
+ <item>\
+ <para>2 3</para>\
+ </item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +--------+--------+--------+\n\
+ |Header 1|Header 2|Header 3|\n\
+ +--------+--------+--------+\n\
+ |1.1 |1.2 |\n\
+ + +--------+--------+\n\
+ | |2 2 |2 3 |\n\
+ +--------+--------+--------+\n\
+\n"));
+}
+
+void SphinxTableTest::testRowSpan2()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item><para>h1</para></item>\
+ <item><para>h2</para></item>\
+ <item><para>h3</para></item>\
+ <item><para>h4</para></item>\
+ </header>\
+ <row>\
+ <item rowspan=\"6\"><para>A</para></item>\
+ <item rowspan=\"6\"><para>B</para></item>\
+ <item><para>C</para></item>\
+ <item><para>D</para></item>\
+ </row>\
+ <row>\
+ <item><para>E</para></item>\
+ <item><para>F</para></item>\
+ </row>\
+ <row>\
+ <item><para>E</para></item>\
+ <item><para>F</para></item>\
+ </row>\
+ <row>\
+ <item><para>E</para></item>\
+ <item><para>F</para></item>\
+ </row>\
+ <row>\
+ <item><para>E</para></item>\
+ <item><para>F</para></item>\
+ </row>\
+ <row>\
+ <item><para>E</para></item>\
+ <item><para>F</para></item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +--+--+--+--+\n\
+ |h1|h2|h3|h4|\n\
+ +--+--+--+--+\n\
+ |A |B |C |D |\n\
+ + + +--+--+\n\
+ | | |E |F |\n\
+ + + +--+--+\n\
+ | | |E |F |\n\
+ + + +--+--+\n\
+ | | |E |F |\n\
+ + + +--+--+\n\
+ | | |E |F |\n\
+ + + +--+--+\n\
+ | | |E |F |\n\
+ +--+--+--+--+\n\
+\n"));
+}
+
+void SphinxTableTest::testBrokenTable()
+{
+ const char* xml = "\
+<table>\
+ <header>\
+ <item>\
+ <para>Header 1</para>\
+ </item>\
+ <item>\
+ <para>Header 2</para>\
+ </item>\
+ </header>\
+ <row>\
+ <item>\
+ <para>1.1</para>\
+ </item>\
+ <item>\
+ <para>1.2</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item colspan=\"2\">\
+ <para>2 2</para>\
+ </item>\
+ <item>\
+ <para>2 3</para>\
+ </item>\
+ <item>\
+ <para>2 4</para>\
+ </item>\
+ <item>\
+ <para>2 5</para>\
+ </item>\
+ </row>\
+ <row>\
+ <item>\
+ <para>3 1</para>\
+ </item>\
+ <item>\
+ <para>3 2</para>\
+ </item>\
+ <item>\
+ <para>3 3</para>\
+ </item>\
+ </row>\
+</table>";
+ QCOMPARE(transformXml(xml), QString("\
+ +--------+------------+\n\
+ |Header 1|Header 2 |\n\
+ +--------+------------+\n\
+ |1.1 |1.2 |\n\
+ +--------+------------+\n\
+ |2 2 2 3 2 4 2 5|\n\
+ +--------+------------+\n\
+ |3 1 |3 2 3 3 |\n\
+ +--------+------------+\n\
+\n"));
+}
+
+
+QTEST_APPLESS_MAIN( SphinxTableTest )
+
+#include "sphinxtabletest.moc"
diff --git a/tests/sphinxtabletest.h b/tests/sphinxtabletest.h
new file mode 100644
index 00000000..e056021b
--- /dev/null
+++ b/tests/sphinxtabletest.h
@@ -0,0 +1,49 @@
+/*
+* This file is part of the Boost Python Generator project.
+*
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+*
+* Contact: PySide team <contact@pyside.org>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#ifndef SPHINXTABLETEST_H
+#define SPHINXTABLETEST_H
+
+#include <QObject>
+
+class QtDocGenerator;
+class SphinxTableTest : public QObject {
+ Q_OBJECT
+
+private slots:
+ void setUp();
+ void tearDown();
+ void testEmptyString();
+ void testSimpleTable();
+ void testRowSpan();
+ void testColSpan();
+ void testComplexTable();
+ void testRowSpan2();
+ void testBrokenTable();
+private:
+ QtDocGenerator* m_generator;
+
+ QString transformXml(const char* xml);
+};
+
+#endif
diff --git a/tests/test_generator/CMakeLists.txt b/tests/test_generator/CMakeLists.txt
new file mode 100644
index 00000000..498d6624
--- /dev/null
+++ b/tests/test_generator/CMakeLists.txt
@@ -0,0 +1,63 @@
+project(test_generator)
+
+set(dummy_generator_SRC dummygenerator.cpp)
+add_library(dummy_generator SHARED ${dummy_generator_SRC})
+target_link_libraries(dummy_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner)
+set_property(TARGET dummy_generator PROPERTY PREFIX "")
+
+add_executable(dummygenerator main.cpp)
+set(DUMMYGENERATOR_EXECUTABLE dummygenerator${generator_SUFFIX})
+set_target_properties(dummygenerator PROPERTIES OUTPUT_NAME ${DUMMYGENERATOR_EXECUTABLE})
+target_link_libraries(dummygenerator ${QT_QTCORE_LIBRARY})
+
+configure_file(dummygentestconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/dummygentestconfig.h" @ONLY)
+
+get_filename_component(APIEXTRACTOR_LIBRARY_DIRS ${APIEXTRACTOR_LIBRARY} PATH)
+if(WIN32)
+ set(PATH_SEP ";")
+ find_program(APIEXTRACTOR_BINARY apiextractor.dll HINTS ${APIEXTRACTOR_LIBRARY_DIRS})
+ get_filename_component(APIEXTRACTOR_BINARY_DIR ${APIEXTRACTOR_BINARY} PATH)
+ set(APIEXTRACTOR_LIBRARY_DIRS "${APIEXTRACTOR_LIBRARY_DIRS}${PATH_SEP}${APIEXTRACTOR_BINARY_DIR}")
+else()
+ set(PATH_SEP ":")
+endif()
+
+set(ENV_PATH "${generatorrunner_BINARY_DIR}${PATH_SEP}${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{PATH}${PATH_SEP}${APIEXTRACTOR_LIBRARY_DIRS}")
+set(ENV_QT_PLUGIN_PATH "${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{QT_PLUGIN_PATH}")
+if(WIN32)
+ string(REPLACE "\\;" ";" ENV_PATH "${ENV_PATH}")
+ string(REPLACE ";" "\\;" ENV_PATH "${ENV_PATH}")
+ string(REPLACE "\\;" ";" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}")
+ string(REPLACE ";" "\\;" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}")
+endif()
+
+macro(m_add_test testname)
+ if(CMAKE_VERSION VERSION_LESS 2.8)
+ add_test(${testname} ${CMAKE_COMMAND} -DTEST=${testname}
+ -DWORKDIR=${CMAKE_CURRENT_BINARY_DIR}
+ -DENV_PATH=${ENV_PATH} -DENV_QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/run_test.cmake)
+ else()
+ add_test(${testname} ${testname})
+ set_property(TEST ${testname} PROPERTY ENVIRONMENT "PATH=${ENV_PATH}" "QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}")
+ endif()
+endmacro()
+
+macro(declare_test testname)
+ qt4_automoc("${testname}.cpp")
+ add_executable(${testname} "${testname}.cpp")
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+ target_link_libraries(${testname} ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY})
+ m_add_test(${testname})
+endmacro(declare_test testname)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_global.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_global.h" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_typesystem.xml"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_typesystem.xml" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dummygentest-project.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/dummygentest-project.txt" @ONLY)
+declare_test(dummygentest)
+
+add_dependencies(dummygenerator generatorrunner)
+
diff --git a/tests/test_generator/dummygenerator.cpp b/tests/test_generator/dummygenerator.cpp
new file mode 100644
index 00000000..795d7afd
--- /dev/null
+++ b/tests/test_generator/dummygenerator.cpp
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <iostream>
+#include "dummygenerator.h"
+
+EXPORT_GENERATOR_PLUGIN(new DummyGenerator)
+
+using namespace std;
+
+QString
+DummyGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const
+{
+ return QString("%1_generated.txt").arg(metaClass->name().toLower());
+}
+
+void
+DummyGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "// Generated code for class: " << qPrintable(metaClass->name()) << endl;
+}
+
+bool
+DummyGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ if (args.contains("dump-arguments") && !args["dump-arguments"].isEmpty()) {
+ QFile logFile(args["dump-arguments"]);
+ logFile.open(QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream out(&logFile);
+ foreach (const QString& key, args.keys()) {
+ if (key == "arg-1")
+ out << "header-file";
+ else if (key == "arg-2")
+ out << "typesystem-file";
+ else
+ out << key;
+ if (!args[key].isEmpty())
+ out << " = " << args[key];
+ out << endl;
+ }
+ }
+ return true;
+}
+
diff --git a/tests/test_generator/dummygenerator.h b/tests/test_generator/dummygenerator.h
new file mode 100644
index 00000000..079c1d5b
--- /dev/null
+++ b/tests/test_generator/dummygenerator.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef DUMMYGENERATOR_H
+#define DUMMYGENERATOR_H
+
+#include "generator.h"
+
+class GENRUNNER_API DummyGenerator : public Generator
+{
+public:
+ DummyGenerator() {}
+ ~DummyGenerator() {}
+ bool doSetup(const QMap<QString, QString>& args);
+ const char* name() const { return "DummyGenerator"; }
+
+protected:
+ void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration() {}
+};
+
+#endif // DUMMYGENERATOR_H
diff --git a/tests/test_generator/dummygentest-project.txt.in b/tests/test_generator/dummygentest-project.txt.in
new file mode 100644
index 00000000..0a076d8b
--- /dev/null
+++ b/tests/test_generator/dummygentest-project.txt.in
@@ -0,0 +1,20 @@
+[generator-project]
+
+generator-set = dummy
+header-file = @CMAKE_CURRENT_BINARY_DIR@/test_global.h
+typesystem-file = @CMAKE_CURRENT_BINARY_DIR@/test_typesystem.xml
+output-directory = /tmp/output
+
+dump-arguments = @CMAKE_CURRENT_BINARY_DIR@/dummygen-args.log
+
+include-path = /include/path/location1
+include-path = /include/path/location2
+
+typesystem-path = /typesystem/path/location1
+typesystem-path = /typesystem/path/location2
+
+api-version = 1.2.3
+debug = sparse
+
+no-suppress-warnings
+
diff --git a/tests/test_generator/dummygentest.cpp b/tests/test_generator/dummygentest.cpp
new file mode 100644
index 00000000..a71abfcc
--- /dev/null
+++ b/tests/test_generator/dummygentest.cpp
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "dummygentest.h"
+#include "dummygenerator.h"
+#include "dummygentestconfig.h"
+#include <QTemporaryFile>
+#include <QtTest/QTest>
+#include <QProcess>
+
+#define GENERATED_CONTENTS "// Generated code for class: Dummy"
+
+void DummyGenTest::initTestCase()
+{
+ int argc = 0;
+ char* argv[] = {NULL};
+ QCoreApplication app(argc, argv);
+ workDir = QDir::currentPath();
+
+ headerFilePath = workDir + "/test_global.h";
+ typesystemFilePath = workDir + "/test_typesystem.xml";
+ projectFilePath = workDir + "/dummygentest-project.txt";
+ generatedFilePath = QString("%1/dummy/dummy_generated.txt").arg(QDir::tempPath());
+}
+
+void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule()
+{
+ QStringList args;
+ args.append("--generator-set=" DUMMYGENERATOR_BINARY_DIR "/dummy_generator" MODULE_EXTENSION);
+ args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule()
+{
+ QStringList args;
+ args.append("--generator-set=dummy");
+ args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testCallDummyGeneratorExecutable()
+{
+ QStringList args;
+ args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute(DUMMYGENERATOR_BINARY, args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testProjectFileArgumentsReading()
+{
+ QStringList args(QString("--project-file=%1/dummygentest-project.txt").arg(workDir));
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile logFile(workDir + "/dummygen-args.log");
+ logFile.open(QIODevice::ReadOnly);
+ QStringList logContents;
+ while (!logFile.atEnd())
+ logContents << logFile.readLine().trimmed();
+ logContents.sort();
+ QCOMPARE(logContents[0], QString("api-version = 1.2.3"));
+ QCOMPARE(logContents[1], QString("debug = sparse"));
+ QVERIFY(logContents[2].startsWith("dump-arguments = "));
+ QVERIFY(logContents[2].endsWith("dummygen-args.log"));
+ QCOMPARE(logContents[3], QString("generator-set = dummy"));
+ QVERIFY(logContents[4].startsWith("header-file = "));
+ QVERIFY(logContents[4].endsWith("test_global.h"));
+ QCOMPARE(logContents[5],
+ QDir::toNativeSeparators(QString("include-paths = /include/path/location1%1/include/path/location2").arg(PATH_SPLITTER)));
+ QCOMPARE(logContents[6], QString("no-suppress-warnings"));
+ QCOMPARE(logContents[7], QString("output-directory = /tmp/output"));
+ QVERIFY(logContents[8].startsWith("project-file = "));
+ QVERIFY(logContents[8].endsWith("dummygentest-project.txt"));
+ QVERIFY(logContents[9].startsWith("typesystem-file = "));
+ QVERIFY(logContents[9].endsWith("test_typesystem.xml"));
+ QCOMPARE(logContents[10],
+ QDir::toNativeSeparators(QString("typesystem-paths = /typesystem/path/location1%1/typesystem/path/location2").arg(PATH_SPLITTER)));
+}
+
+QTEST_APPLESS_MAIN(DummyGenTest)
+
+#include "dummygentest.moc"
+
diff --git a/tests/test_generator/dummygentest.h b/tests/test_generator/dummygentest.h
new file mode 100644
index 00000000..0f485ae8
--- /dev/null
+++ b/tests/test_generator/dummygentest.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef DUMMYGENTABLETEST_H
+#define DUMMYGENTABLETEST_H
+
+#include <QObject>
+
+class DummyGenerator;
+
+class DummyGenTest : public QObject
+{
+ Q_OBJECT
+
+private:
+ QString workDir;
+ QString headerFilePath;
+ QString typesystemFilePath;
+ QString generatedFilePath;
+ QString projectFilePath;
+
+private slots:
+ void initTestCase();
+ void testCallGenRunnerWithFullPathToDummyGenModule();
+ void testCallGenRunnerWithNameOfDummyGenModule();
+ void testCallDummyGeneratorExecutable();
+ void testProjectFileArgumentsReading();
+};
+
+#endif
+
diff --git a/tests/test_generator/dummygentestconfig.h.in b/tests/test_generator/dummygentestconfig.h.in
new file mode 100644
index 00000000..9da17dcd
--- /dev/null
+++ b/tests/test_generator/dummygentestconfig.h.in
@@ -0,0 +1,15 @@
+#ifndef DUMMYGENTESTCONFIG_H
+#define DUMMYGENTESTCONFIG_H
+
+#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@"
+#define DUMMYGENERATOR_BINARY "@DUMMYGENERATOR_EXECUTABLE@"
+#define DUMMYGENERATOR_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@"
+
+#ifdef _WINDOWS
+ #define PATH_SPLITTER ";"
+#else
+ #define PATH_SPLITTER ":"
+#endif
+
+#endif // DUMMYGENTESTCONFIG_H
+
diff --git a/tests/test_generator/main.cpp b/tests/test_generator/main.cpp
new file mode 100644
index 00000000..47ad4d0a
--- /dev/null
+++ b/tests/test_generator/main.cpp
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the PySide project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <QtCore>
+
+int main(int argc, char *argv[])
+{
+ QStringList args;
+ args.append("--generator-set=dummy");
+ for (int i = 1; i < argc; i++)
+ args.append(argv[i]);
+ return QProcess::execute("generatorrunner", args);
+}
+
diff --git a/tests/test_generator/run_test.cmake b/tests/test_generator/run_test.cmake
new file mode 100644
index 00000000..34a821d8
--- /dev/null
+++ b/tests/test_generator/run_test.cmake
@@ -0,0 +1,11 @@
+# The tests are run through this script due to a limitation
+# on versions of CMake lesser than 2.8, that prevent setting
+# environment variables for tests from working.
+
+set(ENV{PATH} "${ENV_PATH}")
+set(ENV{QT_PLUGIN_PATH} "${ENV_QT_PLUGIN_PATH}")
+execute_process(COMMAND ${TEST} WORKING_DIRECTORY "${WORKDIR}" RESULT_VARIABLE OK)
+
+if(NOT OK EQUAL 0)
+ message(SEND_ERROR "${TEST} failed!")
+endif()
diff --git a/tests/test_generator/test_global.h b/tests/test_generator/test_global.h
new file mode 100644
index 00000000..6a95200c
--- /dev/null
+++ b/tests/test_generator/test_global.h
@@ -0,0 +1 @@
+struct Dummy {};
diff --git a/tests/test_generator/test_typesystem.xml b/tests/test_generator/test_typesystem.xml
new file mode 100644
index 00000000..c19a4e95
--- /dev/null
+++ b/tests/test_generator/test_typesystem.xml
@@ -0,0 +1,3 @@
+<typesystem package='dummy'>
+ <value-type name='Dummy'/>
+</typesystem>