aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Lira <marcelo.lira@openbossa.org>2009-08-17 19:31:37 -0300
committerMarcelo Lira <marcelo.lira@openbossa.org>2009-08-17 19:31:37 -0300
commite0c29962e6f334452f0c9db2caaf6ed18065de85 (patch)
treecee27801c196fbcacf6130ad64216af133b555dd
The End Is the Beginning Is the End
-rw-r--r--.gitignore10
-rw-r--r--CMakeLists.txt54
-rw-r--r--COPYING342
-rw-r--r--Doxyfile311
-rw-r--r--cmake_uninstall.cmake21
-rw-r--r--cppgenerator.cpp1453
-rw-r--r--cppgenerator.h80
-rw-r--r--debian/changelog6
-rw-r--r--debian/compat1
-rw-r--r--debian/control25
-rw-r--r--debian/copyright37
-rwxr-xr-xdebian/rules15
-rw-r--r--doc/Makefile88
-rw-r--r--doc/_static/.gitignore0
-rw-r--r--doc/_templates/index.html34
-rw-r--r--doc/_templates/layout.html10
-rw-r--r--doc/compiling/cmake-primer.rst68
-rw-r--r--doc/compiling/compiling.rst9
-rw-r--r--doc/compiling/setup-apiextractor.rst56
-rw-r--r--doc/compiling/setup-generator.rst54
-rw-r--r--doc/conf.py198
-rw-r--r--doc/contents.rst10
-rw-r--r--doc/dependency-pyqtb.svg600
-rw-r--r--doc/faq.rst107
-rw-r--r--doc/images/.directory3
-rw-r--r--doc/images/bindinggen-development.pngbin0 -> 34333 bytes
-rw-r--r--doc/images/boostgen.pngbin0 -> 153473 bytes
-rw-r--r--doc/images/boostqtarch.pngbin0 -> 34257 bytes
-rw-r--r--doc/overview.rst46
-rw-r--r--doc/tutorial/bindinglibfoo.rst76
-rw-r--r--doc/tutorial/buildingthebinding.rst133
-rw-r--r--doc/tutorial/globalheader.rst36
-rw-r--r--doc/tutorial/images/generatorworkings.pngbin0 -> 37257 bytes
-rw-r--r--doc/tutorial/images/generatorworkings.svg392
-rw-r--r--doc/tutorial/introduction.rst31
-rw-r--r--doc/tutorial/libfoo.rst68
-rw-r--r--doc/tutorial/typesystemcreation.rst136
-rw-r--r--docgenerator.cpp1370
-rw-r--r--docgenerator.h213
-rw-r--r--headergenerator.cpp412
-rw-r--r--headergenerator.h49
-rw-r--r--libshiboken/CMakeLists.txt37
-rw-r--r--libshiboken/FindShiboken.cmake.in13
-rw-r--r--libshiboken/basewrapper.cpp56
-rw-r--r--libshiboken/basewrapper.h92
-rw-r--r--libshiboken/bindingmanager.cpp107
-rw-r--r--libshiboken/bindingmanager.h66
-rw-r--r--libshiboken/containers.cpp41
-rw-r--r--libshiboken/containers.h47
-rw-r--r--libshiboken/conversions.h191
-rw-r--r--libshiboken/helper.cpp67
-rw-r--r--libshiboken/helper.h72
-rw-r--r--libshiboken/pyenum.cpp96
-rw-r--r--libshiboken/pyenum.h68
-rw-r--r--libshiboken/shiboken.h47
-rw-r--r--libshiboken/shiboken.pc.in13
-rw-r--r--main.cpp38
-rw-r--r--polymorphicdata.cpp386
-rw-r--r--polymorphicdata.h87
-rw-r--r--shibokengenerator.cpp829
-rw-r--r--shibokengenerator.h213
-rw-r--r--tests/CMakeLists.txt20
-rw-r--r--tests/libsample/CMakeLists.txt22
-rw-r--r--tests/libsample/abstract.cpp64
-rw-r--r--tests/libsample/abstract.h37
-rw-r--r--tests/libsample/complex.cpp27
-rw-r--r--tests/libsample/complex.h25
-rw-r--r--tests/libsample/derived.cpp80
-rw-r--r--tests/libsample/derived.h46
-rw-r--r--tests/libsample/functions.cpp85
-rw-r--r--tests/libsample/functions.h36
-rw-r--r--tests/libsample/implicitconv.cpp38
-rw-r--r--tests/libsample/implicitconv.h44
-rw-r--r--tests/libsample/kindergarten.cpp64
-rw-r--r--tests/libsample/kindergarten.h29
-rw-r--r--tests/libsample/listuser.cpp47
-rw-r--r--tests/libsample/listuser.h23
-rw-r--r--tests/libsample/main.cpp216
-rw-r--r--tests/libsample/modifications.cpp68
-rw-r--r--tests/libsample/modifications.h73
-rw-r--r--tests/libsample/pairuser.cpp32
-rw-r--r--tests/libsample/pairuser.h19
-rw-r--r--tests/libsample/point.cpp111
-rw-r--r--tests/libsample/point.h51
-rw-r--r--tests/libsample/reference.cpp11
-rw-r--r--tests/libsample/reference.h24
-rw-r--r--tests/libsample/samplenamespace.cpp48
-rw-r--r--tests/libsample/samplenamespace.h36
-rw-r--r--tests/libsample/size.cpp11
-rw-r--r--tests/libsample/size.h152
-rwxr-xr-xtests/run_test.sh13
-rw-r--r--tests/samplebinding/CMakeLists.txt44
-rwxr-xr-xtests/samplebinding/abstract_test.py62
-rw-r--r--tests/samplebinding/complex_conversions.h23
-rwxr-xr-xtests/samplebinding/complex_test.py42
-rwxr-xr-xtests/samplebinding/derived_test.py113
-rwxr-xr-xtests/samplebinding/enum_test.py36
-rw-r--r--tests/samplebinding/global.h14
-rwxr-xr-xtests/samplebinding/implicitconv_test.py27
-rw-r--r--tests/samplebinding/list_conversions.h29
-rwxr-xr-xtests/samplebinding/modifications_test.py115
-rw-r--r--tests/samplebinding/pair_conversions.h25
-rwxr-xr-xtests/samplebinding/point_test.py42
-rwxr-xr-xtests/samplebinding/reference_test.py28
-rwxr-xr-xtests/samplebinding/sample_test.py37
-rwxr-xr-xtests/samplebinding/size_test.py83
-rw-r--r--tests/samplebinding/typesystem_sample.xml216
107 files changed, 11608 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..fa13dcc5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+build
+.kdev4
+*.log
+*.pyc
+*.o
+*.so
+.preprocessed.tmp
+.*.swp
+*.kdev4
+doc/_build
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..62a9fee5
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,54 @@
+project(shiboken)
+
+cmake_minimum_required(VERSION 2.6)
+
+find_package(Qt4 4.5.0 REQUIRED)
+find_package(ApiExtractor REQUIRED)
+
+add_definitions(${QT_DEFINITIONS})
+
+set(shiboken_VERSION 0.1)
+set(CMAKE_BUILD_TYPE Debug)
+
+set(shiboken_SRC
+shibokengenerator.cpp
+headergenerator.cpp
+cppgenerator.cpp
+docgenerator.cpp
+polymorphicdata.cpp
+main.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR}/..
+ ${QT_INCLUDE_DIR}
+ ${QT_QTCORE_INCLUDE_DIR})
+
+add_executable(shiboken ${shiboken_SRC})
+
+target_link_libraries(shiboken
+ ${APIEXTRACTOR_LIBRARY}
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTXML_LIBRARY})
+
+# uninstall target
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+add_custom_target(uninstall "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
+enable_testing()
+
+add_subdirectory(libshiboken)
+add_subdirectory(tests)
+
+# "make dist", in fact "make package_source"
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "shiboken-${shiboken_VERSION}")
+set(CPACK_SOURCE_GENERATOR TGZ)
+set(CPACK_SOURCE_IGNORE_FILES "~$" ".svn" "debian/" "build/" ".swp$" "*.kdev4")
+include(CPack)
+
+install(TARGETS shiboken DESTINATION bin)
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..4ccd7146
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,342 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 00000000..24289839
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,311 @@
+# Doxyfile 1.5.7.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "CPython Generator Backend"
+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/cpythonbackend/
+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/cpythonbackend
+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 = ../libgenerator/libgenerator.tag=../libgenerator
+GENERATE_TAGFILE = cpythonbackend.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/cmake_uninstall.cmake b/cmake_uninstall.cmake
new file mode 100644
index 00000000..df95fb9d
--- /dev/null
+++ b/cmake_uninstall.cmake
@@ -0,0 +1,21 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
new file mode 100644
index 00000000..a0de62bb
--- /dev/null
+++ b/cppgenerator.cpp
@@ -0,0 +1,1453 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 "cppgenerator.h"
+#include <apiextractor/reporthandler.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+
+static Indentor INDENT;
+
+QString CppGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+{
+ return QString("%1_cptr(%2)").arg(cpythonBaseName(metaClass->typeEntry())).arg(argName);
+}
+
+QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const
+{
+ return metaClass->qualifiedCppName().toLower() + QLatin1String("_wrapper.cpp");
+}
+
+QList<AbstractMetaFunctionList> CppGenerator::filterGroupedFunctions(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList lst;
+ if (metaClass)
+ lst = queryFunctions(metaClass, true);
+ else
+ lst = globalFunctions();
+
+ QMap<QString, AbstractMetaFunctionList> results;
+ foreach (AbstractMetaFunction* func, lst) {
+ //skip signals
+ if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract()))
+ continue;
+ if (!results.contains(func->name()))
+ results[func->name()] = AbstractMetaFunctionList();
+ results[func->name()].append(func);
+ }
+
+ //TODO: put these lines back to work
+
+ //append global operators
+ //lst += queryGlobalOperators(metaClass);
+
+ return results.values();
+}
+
+QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query)
+{
+ QMap<QPair<QString, QPair<int, bool> >, AbstractMetaFunctionList> results;
+ foreach (AbstractMetaFunction* func, metaClass->operatorOverloads(query)) {
+ if (func->isModifiedRemoved())
+ continue;
+ int args;
+ bool revOp;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ revOp = false;
+ } else {
+ args = func->arguments().size();
+ revOp = ShibokenGenerator::isReverseOperator(func);
+ }
+ QPair<QString, QPair<int, bool> > op(func->name(),
+ QPair<int, bool>(args, revOp));
+ if (!results.contains(op))
+ results[op] = AbstractMetaFunctionList();
+ results[op].append(func);
+ }
+ return results.values();
+}
+
+/*!
+ Function used to write the class generated binding code on the buffer
+ \param s the output buffer
+ \param metaClass the pointer to metaclass information
+*/
+void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ ReportHandler::debugSparse("Generating wrapper implementation for " + metaClass->fullName());
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ if (!metaClass->isNamespace()) {
+ //workaround to access protected functions
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ // headers
+ s << "// default includes" << endl;
+ s << "#include <shiboken.h>" << endl;
+ s << "#include \"" << moduleName().toLower() << "_python.h\"" << endl << endl;
+
+ QString headerfile = fileNameForClass(metaClass);
+ headerfile.replace("cpp", "h");
+ s << "#include \"" << headerfile << '"' << endl;
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) {
+ if (shouldGenerate(innerClass)) {
+ QString headerfile = fileNameForClass(metaClass);
+ headerfile.replace("cpp", "h");
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+ }
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QList<Include> includes = metaClass->typeEntry()->extraIncludes();
+ qSort(includes.begin(), includes.end());
+ foreach (Include inc, includes)
+ s << inc.toString() << endl;
+ s << endl;
+
+ if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s << "#Deprecated" << endl;
+
+ if (!canCreateWrapperFor(metaClass))
+ return;
+
+ s << "using namespace Shiboken;" << endl << endl;
+
+ if (!metaClass->isNamespace()) {
+ s << "// Native ---------------------------------------------------------" << endl << endl;
+
+ //inject code native beginner
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode);
+
+ foreach (const AbstractMetaFunction *func, filterFunctions(metaClass)) {
+ if (func->isPrivate() || (func->isModifiedRemoved() && !func->isAbstract()))
+ continue;
+
+ if (func->isConstructor() && !func->isCopyConstructor()) {
+ writeConstructorNative(s, func);
+ } else if (func->isVirtual() || func->isAbstract()) {
+ writeVirtualMethodNative(s, func);
+// } else if (func->hasInjectedCodeOrSignatureModifications() ||
+// func->isThread() || func->allowThread()) {
+// writeNonVirtualModifiedFunctionNative(s, func);
+ }
+ }
+
+ writeDestructorNative(s, metaClass);
+
+ //inject code native end
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::NativeCode);
+
+ s << endl << "// Target ---------------------------------------------------------" << endl << endl;
+ }
+
+ Indentation indentation(INDENT);
+
+ QString methodsDefinitions;
+ QTextStream md(&methodsDefinitions);
+
+ bool hasComparisonOperator = false;
+ bool typeAsNumber = false;
+
+ foreach (AbstractMetaFunctionList allOverloads, filterGroupedFunctions(metaClass)) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (!func->isModifiedRemoved() && !func->isPrivate() &&
+ func->ownerClass() == func->implementingClass())
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ const AbstractMetaFunction* rfunc = overloads[0];
+ if (rfunc->isConstructor())
+ writeConstructorWrapper(s, overloads);
+ else if (rfunc->isArithmeticOperator()
+ || rfunc->isLogicalOperator()
+ || rfunc->isBitwiseOperator())
+ typeAsNumber = true;
+ else if (rfunc->isComparisonOperator())
+ hasComparisonOperator = true;
+ else
+ writeMethodWrapper(s, overloads);
+
+ if (!rfunc->isConstructor() && !rfunc->isOperatorOverload())
+ writeMethodDefinition(md, overloads);
+ }
+
+ // Write methods definition
+ s << "static PyMethodDef Py" << metaClass->qualifiedCppName() << "_methods[] = {" << endl;
+ s << methodsDefinitions << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl;
+
+ if (typeAsNumber) {
+ QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions(
+ metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (AbstractMetaFunctionList allOverloads, opOverloads) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (!func->isModifiedRemoved()
+ && !func->isPrivate()
+ && func->ownerClass() == func->implementingClass())
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s, overloads);
+ }
+
+ s << "// type has number operators" << endl;
+ writeTypeAsNumberDefinition(s, metaClass);
+ }
+
+ if (hasComparisonOperator) {
+ s << "// Rich comparison" << endl;
+ writeRichCompareFunction(s, metaClass);
+ }
+
+ s << "extern \"C\"" << endl << '{' << endl << endl;
+ writeClassDefinition(s, metaClass);
+ s << endl;
+
+ foreach (AbstractMetaEnum* cppEnum, metaClass->enums())
+ writeEnumDefinition(s, cppEnum);
+ s << endl;
+
+ writeClassRegister(s, metaClass);
+ s << endl << "} // extern \"C\"" << endl;
+}
+
+void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << functionSignature(func, wrapperName(func->ownerClass()) + "::", "",
+ (Option)(OriginalTypeDescription | SkipDefaultValues));
+ s << " : ";
+ writeFunctionCall(s, func);
+ s << " {" << endl;
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func);
+ s << INDENT << "// ... middle" << endl;
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction* func)
+{
+ QString returnKeyword = func->type() ? QLatin1String("return ") : QString();
+ QString prefix = wrapperName(func->ownerClass()) + "::";
+ s << functionSignature(func, prefix, "", Generator::SkipDefaultValues) << endl << "{" << endl;
+
+ Indentation indentation(INDENT);
+
+ if (func->hasInjectedCode()) {
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::NativeCode, func);
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::NativeCode, func);
+ } else if (func->isAbstract() && func->isModifiedRemoved()) {
+ s << INDENT << "#error Pure virtual method \"" << func->ownerClass()->name();
+ s << "::" << func->minimalSignature();
+ s << "\" must be implement but was completely removed on typesystem." << endl;
+ } else {
+// QString converter_calls;
+// QTextStream s_converter_calls(&converter_calls);
+// QString callDefault = returnKeyword + "default_method(self";
+// foreach (const AbstractMetaArgument* arg, func->arguments()) {
+// Indentation indentation(INDENT);
+// callDefault += ", " + arg->argumentName();
+// s_converter_calls << INDENT << ", " << '&' << arg->argumentName()
+// if ((arg->type()->isQObject() || arg->type()->isObject() || arg->type()->isValue()) &&
+// !arg->type()->isReference()) {
+// s_converter_calls << '&' << arg->argumentName() << ", nagasaki::to_python_converter" << endl;
+// } else {
+// s_converter_calls << "nagasaki::convert_to_python< "
+// << argumentString(func, arg, SkipName | SkipDefaultValues)
+// << " >(" << arg->argumentName() << ')' << endl;
+// }
+// }
+// callDefault += ");";
+ if (func->allowThread())
+ s << INDENT << "// how to say to Python to allow threads?" << endl;
+
+ s << INDENT << "PyObject* method = BindingManager::instance().getOverride(this, \"";
+ s << func->name() << "\");" << endl;
+
+ s << INDENT << "if (!method) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT;
+ if (func->isAbstract()) {
+ s << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << func->name();
+ s << "()' not implemented.\");" << endl;
+ s << INDENT << "return";
+ } else {
+ s << "return this->" << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func);
+ }
+ }
+ s << ';' << endl << INDENT << '}' << endl << endl;
+
+ s << INDENT << "PyObject* args = ";
+ if (func->arguments().isEmpty()) {
+ s << "PyTuple_New(0);" << endl;
+ } else {
+ s << "Py_BuildValue(\"(" << getFormatUnitString(func->arguments()) << ")\"";
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ s << ", " << arg->argumentName();
+ if ((arg->type()->isObject() || arg->type()->isValue()) && !arg->type()->isReference()) {
+ s << ", Shiboken::Converter< "
+ << translateType(arg->type(), func->ownerClass())
+ << " >::toPython";
+ }
+ }
+ s << ");" << endl;
+ }
+ s << endl;
+
+ s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl;
+
+ s << INDENT;
+ if (!returnKeyword.isEmpty())
+ s << "PyObject* method_result = ";
+ s << "PyObject_Call(method, args, NULL);" << endl;
+ s << INDENT << "PyGILState_Release(gil_state);" << endl << endl;
+ s << INDENT << "Py_XDECREF(args);" << endl;
+ s << INDENT << "Py_XDECREF(method);" << endl;
+
+ s << endl << INDENT << "// check and set Python error here..." << endl;
+ }
+
+ if (!returnKeyword.isEmpty()) {
+ s << INDENT << returnKeyword;
+ writeToCppConversion(s, func->type(), func->implementingClass(), "method_result");
+ s << ';' << endl;
+ }
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeNonVirtualModifiedFunctionNative(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+
+ s << getFunctionReturnType(func) << ' ';
+ s << func->ownerClass()->name() << '_' << func->originalName() << "_modified(";
+
+ uint options = SkipRemovedArguments | SkipDefaultValues;
+ if (!func->isStatic())
+ options |= WriteSelf;
+
+ writeFunctionArguments(s, func, options);
+ s << ")" << endl << "{" << endl;
+
+ if (func->isThread())
+ s << INDENT << "thread_locker lock;" << endl;
+
+ if (func->allowThread())
+ s << INDENT << "py_allow_threads allow_threads;" << endl;
+
+ if (!getCodeSnips(func).isEmpty()) {
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func);
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+ } else {
+ s << INDENT;
+ if (func->type())
+ s << "return ";
+ if (func->isStatic())
+ s << func->declaringClass()->name() << "::";
+ else
+ s << "self.";
+ writeFunctionCall(s, func);
+ s << ";" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ PolymorphicData polymorphicData(overloads);
+ const AbstractMetaFunction* rfunc = polymorphicData.referenceFunction();
+ QString className = rfunc->ownerClass()->qualifiedCppName();
+
+ s << "PyObject*" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyTypeObject *type, PyObject *args, PyObject *kwds)" << endl;
+ s << '{' << endl;
+
+ s << INDENT << "PyObject* self;" << endl;
+ s << INDENT << getFunctionReturnType(rfunc) << " cptr;" << endl << endl;
+
+ if (rfunc->ownerClass()->isAbstract()) {
+ s << INDENT << "if (type == &Py" << className << "_Type) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl;
+ s << INDENT << INDENT << "\"'" << className;
+ s << "' represents a C++ abstract class and cannot be instanciated\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+ }
+
+ s << INDENT << "if (!PyType_IsSubtype(type, &Py" << className << "_Type))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+
+ if (polymorphicData.maxArgs() > 0) {
+ s << endl << INDENT << "int numArgs = ";
+ writeArgumentsInitializer(s, polymorphicData);
+ }
+
+ writeCodeSnips(s, getCodeSnips(rfunc), CodeSnip::Beginning, TypeSystem::All, rfunc);
+
+ writePolymorphicDecisor(s, &polymorphicData);
+ s << endl;
+
+ s << INDENT << "self = Shiboken::PyBaseWrapper_New(type, &Py" << className << "_Type, cptr);" << endl;
+ s << endl << INDENT << "if (!self) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "if (cptr) delete cptr;" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ writeCodeSnips(s, getCodeSnips(rfunc), CodeSnip::End, TypeSystem::All, rfunc);
+
+ s << endl << INDENT << "return self;" << endl;
+ if (polymorphicData.maxArgs() > 0)
+ writeErrorSection(s, polymorphicData);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ PolymorphicData polymorphicData(overloads);
+ const AbstractMetaFunction* rfunc = polymorphicData.referenceFunction();
+
+ //DEBUG
+ //if (rfunc->isOperatorOverload()) {
+ // QString dumpFile = QString("%1_%2.dot").arg(m_packageName).arg(pythonOperatorFunctionName(rfunc)).toLower();
+ // polymorphicData.dumpGraph(dumpFile);
+ //}
+ //DEBUG
+
+ // TODO: take this off when operator generation is fixed
+ // if (rfunc->isOperatorOverload())
+// if (rfunc->isInplaceOperator())
+// s << "/*" << endl;
+
+ int minArgs = polymorphicData.minArgs();
+ int maxArgs = polymorphicData.maxArgs();
+ if (ShibokenGenerator::isReverseOperator(rfunc)) {
+ minArgs--;
+ maxArgs--;
+ }
+
+ s << "static PyObject*" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self";
+ if (maxArgs > 0) {
+ s << ", PyObject* arg";
+ if (maxArgs > 1)
+ s << 's';
+ }
+ s << ')' << endl << '{' << endl;
+
+ if (rfunc->isAbstract()) {
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << rfunc->ownerClass()->name() << '.' << rfunc->name();
+ s << "()' not implemented.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ } else {
+ if (rfunc->implementingClass() &&
+ (!rfunc->implementingClass()->isNamespace() && !rfunc->isStatic())) {
+ // Checks if the underlying C++ object is valid.
+ // If the wrapped C++ library have no function that steals ownership and
+ // deletes the C++ object this check would not be needed.
+ s << INDENT << "if (!Shiboken::cppObjectIsValid((Shiboken::PyBaseWrapper*)self))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+ }
+
+ if (rfunc->type())
+ s << INDENT << getFunctionReturnType(rfunc) << ' ' << retvalVariableName() << ';' << endl;
+
+ if (minArgs != maxArgs || maxArgs > 1) {
+ s << INDENT << "int numArgs = ";
+ if (minArgs == 0 && maxArgs == 1)
+ s << "(arg == 0 ? 0 : 1);" << endl;
+ else
+ writeArgumentsInitializer(s, polymorphicData);
+ }
+
+ writePolymorphicDecisor(s, &polymorphicData);
+
+ s << endl << INDENT << "if (PyErr_Occurred())" << endl;
+ s << INDENT << INDENT << "return 0;" << endl;
+
+ s << INDENT;
+ if (rfunc->type()) {
+ s << "return ";
+ if (rfunc->isInplaceOperator())
+ s << "self";
+ else
+ writeToPythonConversion(s, rfunc->type(), rfunc->ownerClass(), retvalVariableName());
+ } else {
+ s << "Py_RETURN_NONE";
+ }
+ s << ';' << endl;
+
+ if (maxArgs > 0)
+ writeErrorSection(s, polymorphicData);
+ }
+ s << '}' << endl << endl;
+
+ // TODO: take this off when operator generation is fixed
+// if (rfunc->isOperatorOverload())
+// if (rfunc->isInplaceOperator())
+// s << "*/" << endl;
+}
+
+void CppGenerator::writeArgumentsInitializer(QTextStream& s, PolymorphicData& polymorphicData)
+{
+ const AbstractMetaFunction* rfunc = polymorphicData.referenceFunction();
+ s << "PyTuple_GET_SIZE(args);" << endl;
+
+ s << INDENT << "PyObject* pyargs[] = {";
+ s << QString(polymorphicData.maxArgs(), '0').split("", QString::SkipEmptyParts).join(", ");
+ s << "};" << endl << endl;
+
+ QStringList palist;
+ for (int i = 0; i < polymorphicData.maxArgs(); i++)
+ palist << QString("&(pyargs[%1])").arg(i);
+ QString pyargs = palist.join(", ");
+
+ QList<int> invalidArgsLength = polymorphicData.invalidArgumentLengths();
+ if (!invalidArgsLength.isEmpty()) {
+ QStringList invArgsLen;
+ foreach (int i, invalidArgsLength)
+ invArgsLen << QString("numArgs == %1").arg(i);
+ s << INDENT << "// invalid argument lengths" << endl;
+ s << INDENT << "if (" << invArgsLen.join(" || ") << ")" << endl;
+ s << INDENT << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl << endl;
+ }
+
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+
+ s << INDENT << "if (!PyArg_UnpackTuple(args, \"" << funcName << "\", ";
+ s << polymorphicData.minArgs() << ", " << polymorphicData.maxArgs();
+ s << ", " << pyargs << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return 0;" << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeErrorSection(QTextStream& s, PolymorphicData& polymorphicData)
+{
+ const AbstractMetaFunction* rfunc = polymorphicData.referenceFunction();
+ s << endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:" << endl;
+ Indentation indentation(INDENT);
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'" << funcName;
+ s << "()' called with wrong parameters.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const PolymorphicData* polyData, QString argumentName)
+{
+ const AbstractMetaType* argType = polyData->argType();
+ AbstractMetaFunctionList implicitConverters;
+ if (argType->isValue()) {
+ const AbstractMetaClass* metaClass = classes().findClass(argType->name());
+ if (metaClass)
+ implicitConverters = metaClass->implicitConversions();
+ }
+
+ int alternativeNumericTypes = 0;
+ foreach (PolymorphicData* pd, polyData->polymorphicDataOnPosition(polyData->argPos())) {
+ if (!pd->argType()->isPrimitive())
+ continue;
+ if (ShibokenGenerator::isNumber(pd->argType()->typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ // This condition trusts that the PolymorphicData object will arrange for
+ // PyInt type to be the last entry on a list of polymorphic argument data.
+ bool numberType = alternativeNumericTypes == 1 || ShibokenGenerator::isPyInt(argType);
+
+ if (implicitConverters.size() > 0)
+ s << '(';
+
+ s << cpythonCheckFunction(argType, numberType) << '(' << argumentName << ')';
+
+ foreach (const AbstractMetaFunction* ctor, implicitConverters) {
+ s << " || ";
+ s << cpythonCheckFunction(ctor->arguments().first()->type(), numberType);
+ s << '(' << argumentName << ')';
+ }
+
+ if (implicitConverters.size() > 0)
+ s << ')';
+}
+
+void CppGenerator::writePolymorphicDecisor(QTextStream& s, PolymorphicData* parentPolymorphicData)
+{
+ bool hasDefaultCall = parentPolymorphicData->nextArgumentHasDefaultValue();
+ if (!hasDefaultCall && parentPolymorphicData->isHeadPolymorphicData()) {
+ foreach (const AbstractMetaFunction* func, parentPolymorphicData->overloads()) {
+ if (parentPolymorphicData->isFinalOccurrence(func)) {
+ hasDefaultCall = true;
+ break;
+ }
+ }
+ }
+
+ const AbstractMetaFunction* rfunc = parentPolymorphicData->referenceFunction();
+
+ int minArgs = parentPolymorphicData->minArgs();
+ int maxArgs = parentPolymorphicData->maxArgs();
+ if (ShibokenGenerator::isReverseOperator(rfunc)) {
+ minArgs--;
+ maxArgs--;
+ }
+
+ if (maxArgs == 0
+ || (!parentPolymorphicData->isHeadPolymorphicData()
+ && (parentPolymorphicData->nextPolymorphicData().isEmpty()
+ || (!hasDefaultCall && parentPolymorphicData->overloads().size() == 1)))) {
+ const AbstractMetaFunction* func = parentPolymorphicData->overloads()[0];
+ int removed = PolymorphicData::numberOfRemovedArguments(func);
+ writeMethodCall(s, func, func->arguments().size() - removed);
+ return;
+ }
+
+ bool varargs = maxArgs > 1 || rfunc->isConstructor();
+
+ s << INDENT;
+
+ // can make a default call
+ if (hasDefaultCall) {
+ s << "if (numArgs == " << parentPolymorphicData->argPos() + 1 << ") { // hasDefaultCall" << endl;
+ {
+ Indentation indent(INDENT);
+ writeMethodCall(s, rfunc, parentPolymorphicData->argPos() + 1);
+ }
+ s << INDENT << "} else ";
+ }
+
+ // last occurrence of function signature
+ if (!parentPolymorphicData->isHeadPolymorphicData()) {
+ foreach (const AbstractMetaFunction* func, parentPolymorphicData->overloads()) {
+ if (parentPolymorphicData->isFinalOccurrence(func)) {
+ int lastArg = parentPolymorphicData->argPos() + 1;
+ s << "if (numArgs == " << lastArg << ") { // final:" << func->minimalSignature() << endl;
+ {
+ Indentation indent(INDENT);
+ writeMethodCall(s, func, lastArg);
+ }
+ s << INDENT << "} else ";
+ }
+ }
+ }
+
+ foreach (PolymorphicData* polymorphicData, parentPolymorphicData->nextPolymorphicData()) {
+ if (maxArgs > 0) {
+ bool signatureFound = polymorphicData->overloads().size() == 1 &&
+ !polymorphicData->nextArgumentHasDefaultValue();
+ const AbstractMetaFunction* func = polymorphicData->overloads()[0];
+ QString pyArgName = varargs ? QString("pyargs[%1]").arg(polymorphicData->argPos()) : "arg";
+
+ s << "if (";
+ if (signatureFound && varargs) {
+ s << "numArgs == ";
+ s << func->arguments().size() - PolymorphicData::numberOfRemovedArguments(func);
+ s << " && ";
+ }
+
+ writeTypeCheck(s, polymorphicData, pyArgName);
+
+ if (polymorphicData->argType()->isContainer() &&
+ ((ContainerTypeEntry*)polymorphicData->argType()->typeEntry())->type()
+ == ContainerTypeEntry::PairContainer) {
+ s << " && PyTuple_GET_SIZE(" << pyArgName << ") == 2";
+ }
+
+ if (signatureFound && varargs) {
+ int numArgs = func->arguments().size() - PolymorphicData::numberOfRemovedArguments(func);
+ PolymorphicData* tmp = polymorphicData;
+ for (int i = polymorphicData->argPos() + 1; i < numArgs; i++) {
+ tmp = tmp->nextPolymorphicData()[0];
+ s << " && ";
+ writeTypeCheck(s, tmp, QString("pyargs[%1]").arg(i));
+ }
+ }
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ int allRemoved = PolymorphicData::numberOfRemovedArguments(func);
+ int lastArg = signatureFound ? func->arguments().size() - allRemoved
+ : polymorphicData->argPos() + 1;
+ int removed = 0;
+ for (int i = polymorphicData->argPos(); i < lastArg; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ QString argName = QString("cpp_arg%1").arg(i);
+ if (varargs)
+ pyArgName = QString("pyargs[%1]").arg(i);
+ const AbstractMetaType* type = func->arguments()[i + removed]->type();
+ s << INDENT << translateType(type, func->implementingClass()) << ' ' << argName << " = ";
+ writeToCppConversion(s, type, func->implementingClass(), pyArgName);
+ s << ';' << endl;
+ }
+ }
+ }
+
+ {
+ Indentation indent(INDENT);
+ writePolymorphicDecisor(s, polymorphicData);
+ }
+
+ s << INDENT << "} else ";
+ }
+ if (maxArgs > 0)
+ s << "goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl;
+}
+
+void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int lastArg)
+{
+ s << INDENT << "// " << func->minimalSignature() << endl;
+
+ bool writeCall = true;
+ if (func->hasSignatureModifications()) {
+ CodeSnipList snips = getCodeSnips(func);
+ foreach (CodeSnip snip, snips) {
+ if (snip.position == CodeSnip::Beginning) {
+ // modified signature was provided with custom code for the method call
+ writeCall = false;
+ break;
+ }
+ }
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::All, func);
+ }
+
+ if (writeCall) {
+ bool badModifications = false;
+ QStringList userArgs;
+ if (!func->isCopyConstructor()) {
+ int removed = 0;
+ for (int i = 0; i < lastArg + removed; i++) {
+ const AbstractMetaArgument* arg = func->arguments()[i];
+ if (func->argumentRemoved(i + 1)) {
+ // If some argument with default value is removed from a
+ // method signature, the said value must be explicitly
+ // added to the method call.
+ removed++;
+ if (arg->defaultValueExpression().isEmpty())
+ badModifications = true;
+ else
+ userArgs << arg->defaultValueExpression();
+ } else {
+ userArgs << QString("cpp_arg%1").arg(arg->argumentIndex() - removed);
+ }
+ }
+
+ // If any argument's default value was modified the method must be called
+ // with this new value whenever the user doesn't pass a explicit value to it.
+ // Also, any unmodified default value coming after the last user specified
+ // argument and before the modified argument must be splicitly stated.
+ QStringList otherArgs;
+ bool defaultModified = false;
+ for (int i = func->arguments().size() - 1; i >= lastArg; i--) {
+ const AbstractMetaArgument* arg = func->arguments()[i];
+ defaultModified = defaultModified || arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ if (defaultModified) {
+ if (arg->defaultValueExpression().isEmpty())
+ badModifications = true;
+ else
+ otherArgs.prepend(arg->defaultValueExpression());
+ }
+ }
+
+ userArgs += otherArgs;
+ }
+
+ if (badModifications) {
+ // When an argument is removed from a method signature and no other
+ // means of calling the method is provided the generator must write
+ // a compiler error line stating the situation.
+ s << INDENT << "#error No way to call \"" << func->ownerClass()->name();
+ s << "::" << func->minimalSignature();
+ s << "\" with the modifications provided on typesystem file" << endl;
+ } else if (func->isOperatorOverload()) {
+ QString firstArg("cpp_arg0");
+ QString secondArg("cpp_arg0");
+ QString selfArg = QString("(*%1)").arg(cpythonWrapperCPtr(func->ownerClass()));
+
+ if (ShibokenGenerator::isReverseOperator(func) || func->isUnaryOperator())
+ secondArg = selfArg;
+ else
+ firstArg = selfArg;
+
+ QString op = func->originalName();
+ op = op.right(op.size() - QString("operator").size());
+
+ s << INDENT;
+ if (!func->isInplaceOperator())
+ s << retvalVariableName() << " = ";
+ if (func->isBinaryOperator())
+ s << firstArg << ' ';
+ s << op << ' ' << secondArg << ';';// << endl;
+ s << "// " << func->minimalSignature() << func->isOperatorOverload() << func->isReverseOperator() << func->isUnaryOperator() << endl;
+ } else {
+ s << INDENT;
+ if (func->isConstructor() || func->isCopyConstructor()) {
+ s << "cptr = new " << wrapperName(func->ownerClass());
+ } else {
+ if (func->type())
+ s << retvalVariableName() << " = ";
+ if (func->ownerClass()) {
+ if (!func->isStatic())
+ s << cpythonWrapperCPtr(func->ownerClass()) << "->";
+ s << func->ownerClass()->name() << "::";
+ }
+ s << func->originalName();
+ }
+
+ s << '(';
+ if (func->isCopyConstructor())
+ s << "*((" << func->ownerClass()->qualifiedCppName() << "*)cpp_arg0)";
+ else
+ s << userArgs.join(", ");
+ s << ");" << endl;
+ }
+ }
+
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+}
+
+void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString tp_flags;
+ QString tp_new;
+ QString tp_dealloc;
+ QString tp_as_number = QString('0');
+ QString tp_richcompare = QString('0');
+ QString className = metaClass->qualifiedCppName();
+ QString baseClassName;
+
+ if (metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasLogicalOperatorOverload()
+ || metaClass->hasBitwiseOperatorOverload()) {
+ tp_as_number = QString("&Py%1_as_number").arg(metaClass->qualifiedCppName());
+ }
+
+ if (metaClass->baseClass())
+ baseClassName = QString("&") + cpythonTypeName(metaClass->baseClass()->typeEntry());
+ else
+ baseClassName = QString("0");
+
+ if (metaClass->isNamespace()) {
+ tp_flags = QString("Py_TPFLAGS_HAVE_CLASS");
+ tp_new = QString("0");
+ tp_dealloc = QString("0");
+ } else {
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE";
+ tp_new = QString("(newfunc)Py%1_New").arg(className);
+ tp_dealloc = QString("(destructor)&(Shiboken::PyBaseWrapper_Dealloc< %1 >)").arg(className);
+ if (metaClass->hasComparisonOperatorOverload())
+ tp_richcompare = QString("(richcmpfunc)Py%1_richcompare").arg(className);
+ }
+
+ s << "// Class Definition -----------------------------------------------" << endl;
+
+ s << "PyTypeObject Py" << className << "_Type = {" << endl;
+ s << INDENT << "PyObject_HEAD_INIT(&PyType_Type)" << endl;
+ s << INDENT << "/*ob_size*/ 0," << endl;
+ s << INDENT << "/*tp_name*/ const_cast<char*>(\"" << className << "\")," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(Shiboken::PyBaseWrapper)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ 0," << endl;
+ s << INDENT << "/*tp_as_number*/ " << tp_as_number << ',' << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ 0," << endl;
+ s << INDENT << "/*tp_call*/ 0," << endl;
+ s << INDENT << "/*tp_str*/ 0," << endl;
+ s << INDENT << "/*tp_getattro*/ 0," << endl;
+ s << INDENT << "/*tp_setattro*/ 0," << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ 0," << endl;
+ s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ 0," << endl;
+ s << INDENT << "/*tp_iternext*/ 0," << endl;
+ s << INDENT << "/*tp_methods*/ Py" << className << "_methods," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ 0," << endl;
+ s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ 0," << endl;
+ s << INDENT << "/*tp_alloc*/ PyType_GenericAlloc," << endl;
+ s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl;
+ s << INDENT << "/*tp_free*/ PyObject_Del," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QMap<QString, QString> nb;
+
+ nb["__add__"] = QString('0');
+ nb["__sub__"] = QString('0');
+ nb["__mul__"] = QString('0');
+ nb["__div__"] = QString('0');
+ nb["__mod__"] = QString('0');
+ nb["__neg__"] = QString('0');
+ nb["__pos__"] = QString('0');
+ nb["__invert__"] = QString('0');
+ nb["__lshift__"] = QString('0');
+ nb["__rshift__"] = QString('0');
+ nb["__and__"] = QString('0');
+ nb["__xor__"] = QString('0');
+ nb["__or__"] = QString('0');
+ nb["__iadd__"] = QString('0');
+ nb["__isub__"] = QString('0');
+ nb["__imul__"] = QString('0');
+ nb["__idiv__"] = QString('0');
+ nb["__imod__"] = QString('0');
+ nb["__ilshift__"] = QString('0');
+ nb["__irshift__"] = QString('0');
+ nb["__iand__"] = QString('0');
+ nb["__ixor__"] = QString('0');
+ nb["__ior__"] = QString('0');
+
+ QList<AbstractMetaFunctionList> opOverloads =
+ filterGroupedOperatorFunctions(metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (AbstractMetaFunctionList opOverload, opOverloads) {
+ const AbstractMetaFunction* rfunc = opOverload[0];
+ QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc->originalName());
+ nb[opName] = cpythonFunctionName(rfunc);
+ }
+
+ s << "static PyNumberMethods Py" << metaClass->qualifiedCppName();
+ s << "_as_number = {" << endl;
+ s << INDENT << "/*nb_add*/ (binaryfunc)" << nb["__add__"] << ',' << endl;
+ s << INDENT << "/*nb_subtract*/ (binaryfunc)" << nb["__sub__"] << ',' << endl;
+ s << INDENT << "/*nb_multiply*/ (binaryfunc)" << nb["__mul__"] << ',' << endl;
+ s << INDENT << "/*nb_divide*/ (binaryfunc)" << nb["__div__"] << ',' << endl;
+ s << INDENT << "/*nb_remainder*/ (binaryfunc)" << nb["__mod__"] << ',' << endl;
+ s << INDENT << "/*nb_divmod*/ 0," << endl;
+ s << INDENT << "/*nb_power*/ 0," << endl;
+ s << INDENT << "/*nb_negative*/ (unaryfunc)" << nb["__neg__"] << ',' << endl;
+ s << INDENT << "/*nb_positive*/ (unaryfunc)" << nb["__pos__"] << ',' << endl;
+ s << INDENT << "/*nb_absolute*/ 0," << endl;
+ s << INDENT << "/*nb_nonzero*/ 0," << endl;
+ s << INDENT << "/*nb_invert*/ (unaryfunc)" << nb["__invert__"] << ',' << endl;
+ s << INDENT << "/*nb_lshift*/ (binaryfunc)" << nb["__lshift__"] << ',' << endl;
+ s << INDENT << "/*nb_rshift*/ (binaryfunc)" << nb["__rshift__"] << ',' << endl;
+ s << INDENT << "/*nb_and*/ (binaryfunc)" << nb["__and__"] << ',' << endl;
+ s << INDENT << "/*nb_xor*/ (binaryfunc)" << nb["__xor__"] << ',' << endl;
+ s << INDENT << "/*nb_or*/ (binaryfunc)" << nb["__or__"] << ',' << endl;
+ s << INDENT << "/*nb_coerce*/ 0," << endl;
+ s << INDENT << "/*nb_int*/ 0," << endl;
+ s << INDENT << "/*nb_long*/ 0," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "/*nb_oct*/ 0," << endl;
+ s << INDENT << "/*nb_hex*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_add*/ (binaryfunc)" << nb["__iadd__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_subtract*/ (binaryfunc)" << nb["__isub__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_multiply*/ (binaryfunc)" << nb["__imul__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_divide*/ (binaryfunc)" << nb["__idiv__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_remainder*/ (binaryfunc)" << nb["__imod__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_power*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_lshift*/ (binaryfunc)" << nb["__ilshift__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_rshift*/ (binaryfunc)" << nb["__irshift__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_and*/ (binaryfunc)" << nb["__iand__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_xor*/ (binaryfunc)" << nb["__ixor__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_or*/ (binaryfunc)" << nb["__ior__"] << ',' << endl;
+ s << INDENT << "/*nb_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_index*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "static PyObject*" << endl;
+ s << "Py" << metaClass->qualifiedCppName();
+ s << "_richcompare(PyObject* self, PyObject* other, int op)" << endl;
+ s << '{' << endl;
+
+ QList<AbstractMetaFunctionList> cmpOverloads = filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp);
+
+ s << INDENT << "bool result;" << endl;
+
+ QString arg0TypeName = metaClass->qualifiedCppName();
+ s << INDENT << arg0TypeName << "& cpp_self = *" << cpythonWrapperCPtr(metaClass) << ';' << endl;
+ s << endl;
+
+ s << INDENT << "switch (op) {" << endl;
+ {
+ Indentation indent(INDENT);
+ foreach (AbstractMetaFunctionList overloads, cmpOverloads) {
+ PolymorphicData polyData(overloads);
+ const AbstractMetaFunction* rfunc = overloads[0];
+
+ // DEBUG
+ // QString dumpFile = QString("%1_%2.dot").arg(rfunc->ownerClass()->name()).arg(pythonOperatorFunctionName(rfunc)).toLower();
+ // polyData.dumpGraph(dumpFile);
+ // DEBUG
+
+ s << INDENT << "case " << ShibokenGenerator::pythonRichCompareOperatorId(rfunc) << ':' << endl;
+
+ Indentation indent(INDENT);
+
+ QString op = rfunc->originalName();
+ op = op.right(op.size() - QString("operator").size());
+
+ int alternativeNumericTypes = 0;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments()[0]->type()->typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ bool first = true;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->isStatic())
+ continue;
+
+ const AbstractMetaType* type = func->arguments()[0]->type();
+ bool numberType = alternativeNumericTypes == 1 || ShibokenGenerator::isPyInt(type);
+
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
+ s << INDENT;
+ }
+
+ s << "if (" << cpythonCheckFunction(type, numberType) << "(other)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT;
+ if (type->isValue() || type->isObject()) {
+ s << arg0TypeName << "& cpp_other = *";
+ s << cpythonWrapperCPtr(metaClass, "other");
+ } else {
+ s << translateType(type, metaClass) << " cpp_other = ";
+ writeToCppConversion(s, type, metaClass, "other");
+ }
+ s << ';' << endl;
+ s << INDENT << "result = (cpp_self " << op << " cpp_other);" << endl;
+ }
+ s << INDENT << '}';
+ }
+ s << " else goto Py" << metaClass->name() << "_RichComparison_TypeError;" << endl;
+ s << endl;
+
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << "default:" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "if (result)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_RETURN_TRUE;" << endl;
+ }
+ s << INDENT << "Py_RETURN_FALSE;" << endl << endl;
+
+ s << INDENT << "Py" << metaClass->name() << "_RichComparison_TypeError:" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"operator called with wrong parameters.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ QPair<int, int> minMax = PolymorphicData::getMinMaxArguments(overloads);
+ const AbstractMetaFunction* func = overloads[0];
+
+ s << INDENT << "{const_cast<char*>(\"" << func->name() << "\"), (PyCFunction)";
+ s << cpythonFunctionName(func) << ", ";
+
+ if (minMax.second < 2) {
+ if (minMax.first == 0)
+ s << "METH_NOARGS";
+ if (minMax.first != minMax.second)
+ s << '|';
+ if (minMax.second == 1)
+ s << "METH_O";
+ } else {
+ s << "METH_VARARGS";
+ }
+ if (func->ownerClass() && func->isStatic())
+ s << "|METH_STATIC";
+ s << "}," << endl;
+}
+
+void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+ QString addFunction;
+ if (cppEnum->enclosingClass()) {
+ addFunction = QString("PyDict_SetItemString(Py")
+ + cppEnum->enclosingClass()->name()
+ + "_Type.tp_dict,";
+ } else {
+ addFunction = "PyModule_AddObject(module,";
+ }
+
+ s << INDENT << "// init enum class: " << cppEnum->name() << endl;
+
+ s << INDENT << "if (PyType_Ready(&" << cpythonName << "_Type) < 0)" << endl;
+ s << INDENT << INDENT << "return;" << endl;
+
+ s << INDENT << "Py_INCREF(&" << cpythonName << "_Type);" << endl;
+
+ s << INDENT << addFunction << endl;
+ s << INDENT << INDENT << INDENT << "const_cast<char*>(\"";
+ s << cppEnum->name() << "\"), ((PyObject*)&" << cpythonName;
+ s << "_Type));" << endl;
+
+ foreach (const AbstractMetaEnumValue* enumValue, cppEnum->values()) {
+ if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name()))
+ continue;
+
+ s << INDENT << "enum_item = Shiboken::PyEnumObject_New(&";
+ s << cpythonName << "_Type," << endl;
+ s << INDENT << INDENT << INDENT << "const_cast<char*>(\"";
+ s << enumValue->name() << "\"), (long) ";
+ if (cppEnum->enclosingClass())
+ s << cppEnum->enclosingClass()->qualifiedCppName() << "::";
+ s << enumValue->name() << ");" << endl;
+
+ s << INDENT << addFunction << endl;
+ s << INDENT << INDENT << INDENT << "const_cast<char*>(\"";
+ s << enumValue->name() << "\"), enum_item);" << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeEnumNewMethod(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+
+ s << "static PyObject*" << endl;
+ s << cpythonName << "_New(PyTypeObject *type, PyObject *args, PyObject *kwds)" << endl;
+ s << '{' << endl;
+
+ s << INDENT << "if (!PyType_IsSubtype(type, &" << cpythonName << "_Type))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+
+ s << INDENT << "PyStringObject* item_name;" << endl;
+ s << INDENT << "int item_value;" << endl;
+
+ s << INDENT << "if (!PyArg_ParseTuple(args, \"Si:__new__\", &item_name, &item_value))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+
+ s << INDENT << "PyObject* self = Shiboken::PyEnumObject_New";
+ s << "(type, (PyObject*) item_name, item_value);" << endl;
+
+ s << endl << INDENT << "if (!self)" << endl << INDENT << INDENT << "return 0;" << endl;
+
+ s << INDENT << "return self;" << endl << '}' << endl;
+}
+
+void CppGenerator::writeEnumDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+ QString newFunc;
+
+ if (cppEnum->typeEntry()->isExtensible()) {
+ newFunc = QString("(newfunc)") + cpythonName + "_New";
+ writeEnumNewMethod(s, cppEnum);
+ s << endl;
+ } else {
+ newFunc = "Shiboken::PyEnumObject_NonExtensibleNew";
+ }
+
+ s << "static PyGetSetDef " << cpythonName << "_getsetlist[] = {" << endl;
+ s << INDENT << "{const_cast<char *>(\"name\"), (getter)Shiboken::PyEnumObject_name}," << endl;
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+
+ s << "PyTypeObject " << cpythonName << "_Type = {" << endl;
+ s << INDENT << "PyObject_HEAD_INIT(&PyType_Type)" << endl;
+ s << INDENT << "/*ob_size*/ 0," << endl;
+ s << INDENT << "/*tp_name*/ const_cast<char*>(\"" << cppEnum->name() << "\")," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(Shiboken::PyEnumObject)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ 0," << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ Shiboken::PyEnumObject_repr," << endl;
+ s << INDENT << "/*tp_as_number*/ 0," << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ 0," << endl;
+ s << INDENT << "/*tp_call*/ 0," << endl;
+ s << INDENT << "/*tp_str*/ Shiboken::PyEnumObject_repr," << endl;
+ s << INDENT << "/*tp_getattro*/ 0," << endl;
+ s << INDENT << "/*tp_setattro*/ 0," << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ Py_TPFLAGS_DEFAULT," << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ 0," << endl;
+ s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_richcompare*/ 0," << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ 0," << endl;
+ s << INDENT << "/*tp_iternext*/ 0," << endl;
+ s << INDENT << "/*tp_methods*/ 0," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ " << cpythonName << "_getsetlist," << endl;
+ s << INDENT << "/*tp_base*/ &PyInt_Type," << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ 0," << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ " << newFunc << ',' << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString pyTypeName = "Py" + metaClass->name() + "_Type";
+ s << "PyAPI_FUNC(void)" << endl;
+ s << "init_" << metaClass->name().toLower() << "(PyObject *module)" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (PyType_Ready(&" << pyTypeName << ") < 0)" << endl;
+ s << INDENT << INDENT << "return;" << endl << endl;
+ s << INDENT << "Py_INCREF(&" << pyTypeName << ");" << endl;
+ s << INDENT << "PyModule_AddObject(module, const_cast<char*>(\"";
+ s << metaClass->name() << "\")," << endl;
+ s << INDENT << INDENT << "((PyObject*)&" << pyTypeName << "));" << endl << endl;
+
+ if (!metaClass->enums().isEmpty()) {
+ s << INDENT << "// Initialize enums" << endl;
+ s << INDENT << "PyObject* enum_item;" << endl << endl;
+ }
+ foreach (const AbstractMetaEnum* cppEnum, metaClass->enums())
+ writeEnumInitialization(s, cppEnum);
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::finishGeneration()
+{
+ //Generate CPython wrapper file
+ QString classInitDecl;
+ QTextStream s_classInitDecl(&classInitDecl);
+ QString classPythonDefines;
+ QTextStream s_classPythonDefines(&classPythonDefines);
+ QString namespaceDefines;
+ QTextStream s_namespaceDefines(&namespaceDefines);
+
+ QSet<QString> includes;
+ QString globalFunctionImpl;
+ QTextStream s_globalFunctionImpl(&globalFunctionImpl);
+ QString globalFunctionDecl;
+ QTextStream s_globalFunctionDef(&globalFunctionDecl);
+
+ Indentation indent(INDENT);
+
+ foreach (AbstractMetaFunctionList globalOverloads, filterGroupedFunctions()) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, globalOverloads) {
+ if (!func->isModifiedRemoved())
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s_globalFunctionImpl, overloads);
+ writeMethodDefinition(s_globalFunctionDef, overloads);
+ }
+
+ foreach (const AbstractMetaClass *cls, classes()) {
+ if (!shouldGenerate(cls) || cls->enclosingClass())
+ continue;
+
+ if (m_packageName.isEmpty())
+ m_packageName = cls->package();
+
+ s_classInitDecl << "extern \"C\" PyAPI_FUNC(void) init_"
+ << cls->name().toLower() << "(PyObject* module);" << endl;
+
+ QString defineStr = "init_" + cls->name().toLower() + "(module);";
+ if (cls->isNamespace())
+ s_namespaceDefines << INDENT << defineStr << endl;
+ else
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ QString moduleFileName(outputDirectory() + "/" + subDirectoryForPackage(m_packageName));
+ moduleFileName += "/" + moduleName().toLower() + "_module_wrapper.cpp";
+
+ QFile file(moduleFileName);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */" << endl;
+ s << "#define PyMODINIT_FUNC void" << endl << "#endif" << endl << endl;
+
+ s << "#include <Python.h>" << endl;
+ s << "#include <shiboken.h>" << endl;
+ s << "#include \"" << moduleName().toLower() << "_python.h\"" << endl << endl;
+ foreach (const QString& include, includes)
+ s << "#include <" << include << ">" << endl;
+ s << endl;
+
+ s << "// Global functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << globalFunctionImpl << endl;
+
+ s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl;
+ s << globalFunctionDecl;
+ s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl;
+
+ s << "// Classes initialization functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << classInitDecl << endl;
+
+ if (!globalEnums().isEmpty()) {
+ s << "// Enum definitions ";
+ s << "------------------------------------------------------------" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums()) {
+ writeEnumDefinition(s, cppEnum);
+ s << endl;
+ }
+ }
+
+ s << "// Module initialization ";
+ s << "------------------------------------------------------------" << endl;
+ s << "extern \"C\" {" << endl << endl;
+
+ s << "PyMODINIT_FUNC" << endl << "init" << moduleName() << "()" << endl;
+ s << '{' << endl;
+
+ foreach (const QString& requiredModule, TypeDatabase::instance()->requiredTargetImports()) {
+ s << INDENT << "if (PyImport_ImportModule(\"" << requiredModule << "\") == NULL) {" << endl;
+ s << INDENT << INDENT << "PyErr_SetString(PyExc_ImportError," << "\"could not import ";
+ s << requiredModule << "\");" << endl << INDENT << INDENT << "return;" << endl;
+ s << INDENT << "}" << endl << endl;
+ }
+
+ s << INDENT << "PyObject* module = Py_InitModule(\"" << moduleName() << "\", ";
+ s << moduleName() << "_methods);" << endl << endl;
+
+ s << INDENT << "// Initialize classes in the type system" << endl;
+ s << classPythonDefines << endl;
+
+ s << INDENT << "// Initialize namespaces as uninstantiable classes in the type system" << endl;
+ s << namespaceDefines << endl;
+
+ if (!globalEnums().isEmpty()) {
+ s << INDENT << "// Initialize enums" << endl;
+ s << INDENT << "PyObject* enum_item;" << endl << endl;
+ }
+
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums())
+ writeEnumInitialization(s, cppEnum);
+
+ s << INDENT << "if (PyErr_Occurred())" << endl;
+ s << INDENT << INDENT << "Py_FatalError(\"can't initialize module ";
+ s << moduleName() << "\");" << endl << '}' << endl << endl;
+ s << "} // extern \"C\"" << endl << endl;
+ }
+}
diff --git a/cppgenerator.h b/cppgenerator.h
new file mode 100644
index 00000000..79ebc19a
--- /dev/null
+++ b/cppgenerator.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 CPPGENERATOR_H
+#define CPPGENERATOR_H
+
+#include "shibokengenerator.h"
+#include "polymorphicdata.h"
+
+/**
+ * The CppGenerator generate the implementations of C++ bindings classes.
+ */
+class CppGenerator : public ShibokenGenerator
+{
+public:
+ void setDisableNamedArgs(bool disable) { m_disableNamedArgs = disable; }
+
+protected:
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ QList<AbstractMetaFunctionList> filterGroupedFunctions(const AbstractMetaClass* metaClass = 0);
+ QList<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = "self");
+
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration();
+
+private:
+ void writeNonVirtualModifiedFunctionNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeDestructorNative(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeVirtualMethodNative(QTextStream& s, const AbstractMetaFunction* func);
+
+ void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads);
+ void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads);
+ void writeArgumentsInitializer(QTextStream& s, PolymorphicData& polymorphicData);
+
+ void writeErrorSection(QTextStream& s, PolymorphicData& polymorphicData);
+ void writeTypeCheck(QTextStream& s, const PolymorphicData* polyData, QString argumentName);
+
+ void writePolymorphicDecisor(QTextStream& s, PolymorphicData* parentPolymorphicData);
+ void writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int lastArg = 0);
+
+ void writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumNewMethod(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeEnumDefinition(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+
+ bool m_disableNamedArgs;
+};
+
+#endif // CPPGENERATOR_H
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000..b8f9d489
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,6 @@
+shiboken (0.2) unstable; urgency=low
+
+ * Initial release
+
+ -- Marcelo Lira <marcelo.lira@indt.org.br> Sat, 30 May 2009 16:16:00 -0300
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000..7ed6ff82
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000..e7fb555a
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,25 @@
+Source: shiboken
+Section: devel
+Priority: extra
+Maintainer: Marcelo Lira <marcelo.lira@indt.org.br>
+Build-Depends: cdbs, debhelper (>= 5), libapiextractor-dev (>= 0.2), libqt4-dev (>= 4.5), cmake (>= 2.6.0)
+Standards-Version: 3.7.3
+
+Package: shiboken
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libapiextractor (>= 0.2)
+Description: Generates Python bindings for qt based libraries.
+ Generates CPython based bindings for C++ libraries.
+
+Package: libshiboken
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Support library for Python bindings created with Shiboken generator.
+ Support library for Python bindings created with Shiboken generator.
+
+Package: libshiboken-dev
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libshiboken
+Description: Development files for libshiboken.
+ Development files for libshiboken.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000..bef1d32d
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,37 @@
+This package was debianized based on previous debianization by Marcelo Lira <marcelo.lira@indt.org.br> on
+Sat, 30 May 2009 16:16:00 -0300.
+
+Upstream Authors:
+
+ Hugo Lima <hugo.lima@indt.org.br>
+ Luciano Wolf <luciano.wolf@indt.org.br>
+ Marcelo Lira <marcelo.lira@indt.org.br>
+ Renato Araujo <renato.filho@indt.org.br>
+
+Copyright:
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(ies)
+
+License:
+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This package 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ On Debian systems, the complete text of the GNU General Public License
+ can be found in `/usr/share/common-licenses/GPL'.
+
+
+The Debian packaging is (C) 2009, Nokia Corporation and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000..1e6acdd0
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/cmake.mk
+
+
+# Add here any variable or target overrides you need.
+
+DEB_CMAKE_EXTRA_FLAGS=-DCMAKE_MODULE_PATH=/usr/share/cmake-2.6/Modules
+
+# borrowed from python2.5 debian/rules
+COMMA = ,
+ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS))))
+ DEB_MAKE_ENVVARS := MAKEFLAGS=-j$(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS))))
+endif
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 00000000..69b857c5
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,88 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf _build/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
+ @echo
+ @echo "Build finished. The HTML pages are in _build/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in _build/dirhtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in _build/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in _build/qthelp, like this:"
+ @echo "# qcollectiongenerator _build/qthelp/PyQtB.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile _build/qthelp/PyQtB.qhc"
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in _build/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
+ @echo
+ @echo "The overview file is in _build/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in _build/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in _build/doctest/output.txt."
diff --git a/doc/_static/.gitignore b/doc/_static/.gitignore
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/doc/_static/.gitignore
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
new file mode 100644
index 00000000..f1a28907
--- /dev/null
+++ b/doc/_templates/index.html
@@ -0,0 +1,34 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+{% block body %}
+ <h1>{{ project }} {{ version }}</h1>
+
+ <p>{{ project }} is a tool that eases the development of Python bindings for Qt-based libraries by
+ automating most of the process. It relies heavily on the ApiExtractor library to parse the
+ header files and manipulate the classes information while generating the code. This generated
+ code uses the
+ <a href="http://www.boost.org/doc/libs/1_39_0/libs/python/doc/index.html">Boost::Python library</a>
+ in order to bridge the C++ library and Python.</p>
+
+ <p>{{ project }} is based on the
+ <a href="http://labs.trolltech.com/page/Projects/QtScript/Generator">QtScriptGenerator</a> project.</p>
+
+ <h2>Documentation</h2>
+ <table class="contentstable" align="center" style="margin-left: 30px"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("overview") }}">Overview</a><br/>
+ <span class="linkdescr">how generator works</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("tutorial/introduction") }}">Tutorial</a><br/>
+ <span class="linkdescr">start here</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
+ <span class="linkdescr">for a complete overview</span></p>
+ </td>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("compiling/compiling") }}">Compiling/Installing</a><br/>
+ <span class="linkdescr">how to compile and install {{ project }}</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
+ <span class="linkdescr">answers for frequent asked questions</span></p>
+ </td></tr>
+ </table>
+
+{% endblock %}
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
new file mode 100644
index 00000000..f15583b4
--- /dev/null
+++ b/doc/_templates/layout.html
@@ -0,0 +1,10 @@
+{% extends "!layout.html" %}
+{% block rootrellink %}
+ <!--<li><img src="{{ pathto('_static/py.png', 1) }}" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>-->
+ <li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
+{% endblock %}
+{% block extrahead %}
+ <!--<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/py.png', 1) }}" />-->
+{{ super() }}
+{% endblock %}
diff --git a/doc/compiling/cmake-primer.rst b/doc/compiling/cmake-primer.rst
new file mode 100644
index 00000000..884cf15c
--- /dev/null
+++ b/doc/compiling/cmake-primer.rst
@@ -0,0 +1,68 @@
+
+.. _cmake-primer:
+
+************
+CMake primer
+************
+
+This chapter will is a basic introduction to CMake, the build system
+used by PyQtB and the binding generator.
+
+The practical steps will be focusing in using cmake in a unix-like
+(GNU/Linux) environment.
+
+
+Configuring
+===========
+
+Project file - CMakeLists.txt
+-----------------------------
+
+CMake parses the file CMakeLists.txt for information about the project,
+like project name, dependencies, what should be compiled, what should be
+shipped.
+
+
+CMake variables
+---------------
+
+CMake can have its default behavior modified by providing some
+
+* ``CMAKE_INSTALL_PREFIX=<some path here>`` sets the install prefix to
+ the specified path.
+* ``CMAKE_MODULE_PATH=<some path here>`` sets the extra directories
+ where CMake will try to find its modules.
+* ``CMAKE_TOOLCHAIN_FILE=<file path>`` sets the path to the file that
+ describes the toolchain used to compile this project. Is is very useful
+ when using CMake with icecc to speedup compilation.
+
+You can define a variable using the ``-D<VARIABLE>`` switch.
+
+Invoking CMake
+--------------
+
+After writing the CMakeLists.txt and deciding which flags will be used,
+you can invoke CMake using::
+
+ cmake <CMake flags> <path to toplevel CMakeLists.txt file>
+
+For example, if you use the ``build/`` folder to build the project and
+want it to be installed into ``/opt/sandbox/``, use the following lines::
+
+ cd build/
+ cmake -DCMAKE_INSTALL_PREFIX=/opt/sandbox ..
+
+CMake will process the project file and write the output files in the
+current directory
+
+Building
+========
+
+After the configuration process, the Makefiles are written and you can build
+the project using :program:`make`.
+
+Installing
+==========
+
+As in the building process, ``make install`` will install the files into
+the target directory.
diff --git a/doc/compiling/compiling.rst b/doc/compiling/compiling.rst
new file mode 100644
index 00000000..638efa91
--- /dev/null
+++ b/doc/compiling/compiling.rst
@@ -0,0 +1,9 @@
+Compiling
+*********
+
+.. toctree::
+ :maxdepth: 3
+
+ cmake-primer
+ setup-apiextractor
+ setup-generator
diff --git a/doc/compiling/setup-apiextractor.rst b/doc/compiling/setup-apiextractor.rst
new file mode 100644
index 00000000..68c162f8
--- /dev/null
+++ b/doc/compiling/setup-apiextractor.rst
@@ -0,0 +1,56 @@
+
+.. _api-extractor:
+
+**************
+API Extractor
+**************
+
+Overview
+========
+
+The **API Extractor** library is used by the binding generator to
+parse the header and typesystem files to create an internal
+representation of the API. It is based on the QtScriptGenerator
+codebase.
+
+Getting the sources
+===================
+
+.. todo::
+ Replace with the OSS project repo info
+
+* Git URL: https://dvcs.projects.maemo.org/git/python/apiextractor
+* Web interface: https://dvcs.projects.maemo.org/git/?p=python/apiextractor
+
+To checkout the most updated version, use the following command::
+
+ $ git clone https://dvcs.projects.maemo.org/git/python/apiextractor/
+
+Build requirements
+==================
+
+* Qt4.5 development headers and libraries >= 4.5.0
+* libboost-graph >= 1.38.0
+* cmake >= 2.6.0
+
+Building and installing
+=======================
+
+To build and install just follow the generic cmake instructions in section
+:ref:`cmake-primer`.
+
+Debian packaging
+================
+
+In order to compile this package in a debian environment, make sure the
+following packages are installed:
+
+* debhelper (>= 5)
+* cdbs
+* cmake (>= 2.6.0)
+* libboost-graph1.38-dev (>= 1.38.0)
+* libqt4-dev (>= 4.5)
+
+And then you can build the package using::
+
+ $ dpkg-buildpackage -rfakeroot
diff --git a/doc/compiling/setup-generator.rst b/doc/compiling/setup-generator.rst
new file mode 100644
index 00000000..28fe2fbb
--- /dev/null
+++ b/doc/compiling/setup-generator.rst
@@ -0,0 +1,54 @@
+
+.. _python-bindings-generator:
+
+*************************
+Python Bindings Generator
+*************************
+
+Overview
+=========================================
+
+The **Python Bindings Generator** (A.K.A. :program:`shiboken`) is
+the program that creates the bindings source files from Qt headers and
+auxiliary files (typesystems, ``global.h`` and glue files). It makes
+heavy use of the :ref:`api-extractor` library.
+
+
+Getting the sources
+===================
+
+* Git URL: https://dvcs.projects.maemo.org/git/python/shiboken
+* Web interface: https://dvcs.projects.maemo.org/git/?p=python/shiboken
+
+To checkout the most updated version, use the following command::
+
+ $ git svn clone https://dvcs.projects.maemo.org/git/?p=python/shiboken
+
+Build requirements
+==================
+
++ CMake >= 2.6.0
++ Qt4.5 libraries and development headers >= 4.5.0
++ :ref:`api-extractor` + development headers
+
+Building and installing
+=======================
+
+To build and install just follow the generic cmake instructions in
+section :ref:`cmake-primer`.
+
+Debian packaging
+================
+
+In order to compile this package in a debian environment, make sure the
+following packages are installed:
+
+* debhelper (>= 5)
+* cdbs
+* cmake (>= 2.6.0)
+* libqt4-dev (>= 4.5)
+* libapiextractor-dev (>= 0.1)
+
+And then you can build the package using::
+
+ $ dpkg-buildpackage -rfakeroot
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 00000000..6862c28d
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,198 @@
+# -*- coding: utf-8 -*-
+#
+# PyQtB documentation build configuration file, created by
+# sphinx-quickstart on Wed Apr 22 15:04:20 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage']
+
+rst_epilog = """
+.. |project| replace:: Shiboken
+"""
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+#master_doc = 'contents'
+
+# General information about the project.
+project = u'Shiboken'
+copyright = u'2009, Nokia Corporation'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {
+#}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = { '' : ''}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = { 'index' : 'index.html'}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+#htmlhelp_basename = 'PyQtBdoc'
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'PyQtB.tex', u'Brian Documentation',
+ u'Nokia Corporation', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/doc/contents.rst b/doc/contents.rst
new file mode 100644
index 00000000..31d16dc9
--- /dev/null
+++ b/doc/contents.rst
@@ -0,0 +1,10 @@
+Table of contents
+*****************
+.. toctree::
+ :numbered:
+ :maxdepth: 3
+
+ overview.rst
+ faq.rst
+ tutorial/introduction.rst
+ compiling/compiling.rst
diff --git a/doc/dependency-pyqtb.svg b/doc/dependency-pyqtb.svg
new file mode 100644
index 00000000..a458bf6f
--- /dev/null
+++ b/doc/dependency-pyqtb.svg
@@ -0,0 +1,600 @@
+<?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="800"
+ height="340"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="dependency-pyqtb.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/var/www/lauro/dependency-pyqtb.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" />
+ <inkscape:perspective
+ id="perspective3480"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3498"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3541"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </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.0425"
+ inkscape:cx="400"
+ inkscape:cy="170"
+ inkscape:document-units="px"
+ inkscape:current-layer="g3995"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1280"
+ inkscape:window-height="951"
+ inkscape:window-x="0"
+ inkscape:window-y="25" />
+ <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(-94.976306,-355.09425)" />
+ <g
+ id="g4087"
+ transform="translate(2.4157429e-6,1.9999951)">
+ <g
+ id="g3995"
+ transform="translate(6,-3.2661035e-8)">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.66823119px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1"
+ d="M 281.95594,47.06539 L 314.12853,47.06538"
+ id="path2877"
+ inkscape:connector-type="polyline" />
+ <g
+ id="g3801"
+ transform="translate(-9.3125054,-154.20033)">
+ <rect
+ y="286.49988"
+ x="322.2547"
+ height="73.367416"
+ width="194.85175"
+ id="rect3595"
+ style="fill:#9ac5ff;fill-opacity:1;fill-rule:evenodd;stroke:#003378;stroke-width:0.8142156;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ ry="10.318988"
+ rx="8.598484" />
+ <g
+ transform="translate(1.7229236,-30.915768)"
+ id="g3599">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="336.95081"
+ id="text2443"><tspan
+ sodipodi:role="line"
+ id="tspan2445"
+ x="329.46826"
+ y="336.95081">API Extractor</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="352.61548"
+ id="text2447"><tspan
+ sodipodi:role="line"
+ id="tspan2449"
+ x="329.46826"
+ y="352.61548">0.2</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="368.15546"
+ id="text2451"><tspan
+ sodipodi:role="line"
+ x="329.46826"
+ y="368.15546"
+ id="tspan2453">Headers and libraries - compile-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="383.47839"
+ id="text2455"><tspan
+ sodipodi:role="line"
+ id="tspan2457"
+ x="329.46826"
+ y="383.47839">LGPL version 2.1</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3729"
+ transform="translate(-9.3125054,-153.6367)">
+ <rect
+ y="164.01837"
+ x="322.2547"
+ height="73.367416"
+ width="194.85175"
+ id="rect2459"
+ style="fill:#9ac5ff;fill-opacity:1;fill-rule:evenodd;stroke:#003378;stroke-width:0.8142156;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ ry="10.318988"
+ rx="8.598484" />
+ <g
+ transform="translate(3.673984,2.3276517)"
+ id="g3585">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="181.23659"
+ id="text2461"><tspan
+ sodipodi:role="line"
+ id="tspan2463"
+ x="329.46826"
+ y="181.23659">Shiboken (generator)</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="196.90126"
+ id="text2465"><tspan
+ sodipodi:role="line"
+ id="tspan2467"
+ x="329.46826"
+ y="196.90126">0.1</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="212.44124"
+ id="text2469"><tspan
+ sodipodi:role="line"
+ x="329.46826"
+ y="212.44124"
+ id="tspan2471">Binary executable - compile-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="227.76418"
+ id="text2473"><tspan
+ sodipodi:role="line"
+ id="tspan2475"
+ x="329.46826"
+ y="227.76418">GPL version 2</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3789"
+ transform="translate(-9.3125054,-154.20033)">
+ <rect
+ y="406.48441"
+ x="322.2547"
+ height="73.367416"
+ width="194.85175"
+ id="rect3597"
+ style="fill:#f3a6a6;fill-opacity:1;fill-rule:evenodd;stroke:#6a0e0e;stroke-width:0.8142156;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ ry="10.318988"
+ rx="8.598484" />
+ <g
+ transform="translate(-0.7447933,-64)"
+ id="g3633">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#350707;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="489.09369"
+ id="text2565"><tspan
+ sodipodi:role="line"
+ id="tspan2567"
+ x="329.46826"
+ y="489.09369">boost::graph</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#350707;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="504.75836"
+ id="text2569"><tspan
+ sodipodi:role="line"
+ id="tspan2571"
+ x="329.46826"
+ y="504.75836">1.38.0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#350707;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="520.29834"
+ id="text2573"><tspan
+ sodipodi:role="line"
+ x="329.46826"
+ y="520.29834"
+ id="tspan2575">headers and libraries - compile-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#350707;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="535.62128"
+ id="text2577"><tspan
+ sodipodi:role="line"
+ id="tspan2579"
+ x="329.46826"
+ y="535.62128">Boost Software License 1.0</tspan></text>
+ </g>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.77180147px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1"
+ d="M 410.36806,130.70564 L 410.36806,83.52386"
+ id="path2879"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.77360356px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:none;stroke-opacity:1"
+ d="M 410.36806,252.57322 L 410.36806,207.23899"
+ id="path2881"
+ inkscape:connector-type="polyline" />
+ <g
+ id="g3565"
+ transform="translate(1.4608973,-106.88798)">
+ <rect
+ ry="22.567146"
+ y="268.8403"
+ x="6.7667637"
+ height="163.45378"
+ width="273.78238"
+ id="rect7541"
+ style="fill:#e3e2db;stroke:#000000;stroke-width:1.30499184;stroke-opacity:1"
+ rx="22.567146" />
+ <g
+ transform="translate(0.2849671,3.2991583)"
+ id="g3547">
+ <g
+ id="g3516"
+ transform="translate(0,63.999998)">
+ <text
+ id="text7543"
+ y="339.74512"
+ x="76.614265"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#350707;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="339.74512"
+ x="76.614265"
+ id="tspan7545"
+ sodipodi:role="line">Boost</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="321.55374"
+ x="21.614267"
+ height="22.5"
+ width="43.163269"
+ id="rect7555"
+ style="fill:#f3a6a6;fill-opacity:1;stroke:#6a0e0e;stroke-width:0.64285713;stroke-opacity:1"
+ rx="6.4285707" />
+ </g>
+ <g
+ id="g3521"
+ transform="translate(0,-2.9523642)">
+ <text
+ id="text7547"
+ y="372.67505"
+ x="76.614265"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#1c2d0f;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="372.67505"
+ x="76.614265"
+ id="tspan7549"
+ sodipodi:role="line">Qt Software</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="355.4823"
+ x="21.614267"
+ height="22.5"
+ width="43.163269"
+ id="rect7561"
+ style="fill:#97ce6c;fill-opacity:1;stroke:#385a1e;stroke-width:0.64285713;stroke-opacity:1"
+ rx="6.4285707" />
+ </g>
+ <g
+ id="g3486"
+ transform="translate(0,2.8342009e-5)">
+ <text
+ id="text7551"
+ y="304.38055"
+ x="76.614265"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#00193c;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="304.38055"
+ x="76.614265"
+ id="tspan7553"
+ sodipodi:role="line">INdT/Nokia</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="286.4823"
+ x="21.614267"
+ height="22.5"
+ width="43.163269"
+ id="rect7563"
+ style="fill:#9ac5ff;fill-opacity:1;stroke:#003378;stroke-width:0.64285713;stroke-opacity:1"
+ rx="6.4285707" />
+ </g>
+ <g
+ id="g3526"
+ transform="translate(-1.3182277,-35.976168)"
+ style="fill:#ffe052;fill-opacity:1">
+ <text
+ id="text3528"
+ y="372.67505"
+ x="76.614265"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#3c3100;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="372.67505"
+ x="76.614265"
+ id="tspan3530"
+ sodipodi:role="line">Python Foundation</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="355.4823"
+ x="21.614267"
+ height="22.5"
+ width="43.163269"
+ id="rect3532"
+ style="fill:#ffe052;fill-opacity:1;stroke:#786200;stroke-width:0.64285713;stroke-opacity:1"
+ rx="6.4285707" />
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3717"
+ transform="translate(232.28126,-66.767457)">
+ <rect
+ y="77.149132"
+ x="322.2547"
+ height="73.367416"
+ width="194.85175"
+ id="rect3657"
+ style="fill:#9ac5ff;fill-opacity:1;fill-rule:evenodd;stroke:#003378;stroke-width:0.8142156;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ ry="10.318988"
+ rx="8.598484" />
+ <g
+ transform="translate(4.8773009,-84.541588)"
+ id="g3659">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="181.23659"
+ id="text3661"><tspan
+ sodipodi:role="line"
+ id="tspan3663"
+ x="329.46826"
+ y="181.23659">libshiboken</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="196.90126"
+ id="text3665"><tspan
+ sodipodi:role="line"
+ id="tspan3667"
+ x="329.46826"
+ y="196.90126">0.1</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="212.44124"
+ id="text3669"><tspan
+ sodipodi:role="line"
+ x="329.46826"
+ y="212.44124"
+ id="tspan3671">Headers and libraries - compile-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#00183c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="227.76418"
+ id="text3673"><tspan
+ sodipodi:role="line"
+ id="tspan3675"
+ x="329.46826"
+ y="227.76418">LGPL version 2.1</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3752"
+ transform="translate(-10.802055,-155.79173)">
+ <rect
+ rx="8.3239012"
+ y="166.21593"
+ x="18.860012"
+ height="73.282379"
+ width="274.18781"
+ id="rect2417"
+ style="fill:#97ce6c;fill-opacity:1;fill-rule:evenodd;stroke:#385a1e;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="9.2689295" />
+ <g
+ id="g3741">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#1c2d0f;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="29.111408"
+ y="183.02223"
+ id="text2419"><tspan
+ sodipodi:role="line"
+ id="tspan2421"
+ x="29.111408"
+ y="183.02223">Qt 4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#1c2d0f;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="29.111408"
+ y="198.68694"
+ id="text2423"><tspan
+ sodipodi:role="line"
+ id="tspan2425"
+ x="29.111408"
+ y="198.68694">4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#1c2d0f;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="29.111408"
+ y="214.22688"
+ id="text2427"><tspan
+ sodipodi:role="line"
+ id="tspan2429"
+ x="29.111408"
+ y="214.22688">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#1c2d0f;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="29.111408"
+ y="224.19267"
+ id="text2431"><tspan
+ sodipodi:role="line"
+ id="tspan2433"
+ x="29.111408"
+ y="224.19267">GNU General Public License v3 /</tspan><tspan
+ id="tspan2472"
+ sodipodi:role="line"
+ x="29.111408"
+ y="234.5208">GNU Lesser General Public Licence v2.1</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3765"
+ transform="translate(201.65125,55.15042)">
+ <rect
+ y="77.208275"
+ x="322.31384"
+ height="73.24913"
+ width="255.99348"
+ id="rect3767"
+ style="fill:#ffe052;fill-opacity:1;fill-rule:evenodd;stroke:#786200;stroke-width:0.93250537;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ ry="10.318988"
+ rx="8.598484" />
+ <g
+ transform="translate(4.8773009,-84.541588)"
+ id="g3769">
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#3c3100;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="181.23659"
+ id="text3771"><tspan
+ sodipodi:role="line"
+ id="tspan3773"
+ x="329.46826"
+ y="181.23659">Python</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#3c3100;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="196.90126"
+ id="text3775"><tspan
+ sodipodi:role="line"
+ id="tspan3777"
+ x="329.46826"
+ y="196.90126">2.6</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#3c3100;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="212.44124"
+ id="text3779"><tspan
+ sodipodi:role="line"
+ x="329.46826"
+ y="212.44124"
+ id="tspan3781">Headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#3c3100;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="329.46826"
+ y="227.76418"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="329.46826"
+ y="227.76418">Python license</tspan></text>
+ </g>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.77180147px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1"
+ d="M 651.96184,131.80908 L 651.96184,84.6273"
+ id="path3787"
+ inkscape:connector-type="polyline" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/faq.rst b/doc/faq.rst
new file mode 100644
index 00000000..38cc3f18
--- /dev/null
+++ b/doc/faq.rst
@@ -0,0 +1,107 @@
+**************************
+Frequently Asked Questions
+**************************
+
+This is a list of Frequently Asked Questions about |project|. Feel free to
+suggest new entries!
+
+General
+=======
+
+What is the generator?
+----------------------
+
+Here the name generator refers actually to a program composed of a set of
+*generator classes* that output different resources based on information
+contained inside C++ header files.
+
+What is the API Extractor?
+--------------------------
+
+It is a library that parses C++ header files and builds a data model around
+them in order to ease the work of manipulating these data inside
+*generators*.
+
+
+Is there any similar tools around?
+----------------------------------
+
+The generator framework actually started as a fork of the qtscriptgenerator,
+with the focus on python bindings instead of QtScript. After some time, the
+python-specific code was split from the the header parsing and data model
+code. The former became what we call *generator* while the latter is now
+called *API Extractor*.
+
+What's the relationship between the generator and the API Extractor?
+--------------------------------------------------------------------
+
+The generator system relies heavily in the API Extractor classes, using
+them as syntatic sugar to access the data model of the classes being
+wrapped.
+
+What are the dependencies to run the generator?
+-----------------------------------------------
+
+API Extractor, QtCore and QtXml.
+
+Creating bindings
+=================
+
+Can I wrap non-Qt libraries?
+----------------------------
+
+Although it's not yet well tested, there's a good chance that non-Qt
+libraries can be wrapped using the generator. But remember that
+generator injects runtime dependency on Qt for the generated binding.
+
+Is there any runtime dependency on the generated binding?
+---------------------------------------------------------
+
+Yes. Only libshiboken, and the obvious Python interpreter
+and the C++ library that is being wrapped.
+
+What do I have to do to create my bindings?
+-------------------------------------------
+
+.. todo: put link to typesystem documentation
+
+Most of the work is already done by the API Extractor. The developer creates
+a typesystem file with any customization wanted in the generated code, like
+removing classes or changing method signatures. The generator will output
+the .h and .cpp files with the CPython code that will wrap the target
+library for python.
+
+Is there any recommended build system?
+--------------------------------------
+
+Both API Extractor and generator uses and recommends the CMake build system.
+
+Can I write closed-source bindings with the generator?
+------------------------------------------------------
+
+Yes, as long as you use a LGPL version of Qt, due to runtime requirements.
+
+What is 'inject code'?
+----------------------
+
+That's how we call customized code that will be *injected* into the
+generated at specific locations. They are specified inside the typesytem.
+
+How can I document my project?
+------------------------------
+
+The generator also can generate the API documentation based on the
+C++ headers documentation using the qdoc syntax. Optionally you can
+inject documentation at specific parts. Likewise *inject code*, the
+customized documentation is specified inside the typesystem.
+
+Other
+=====
+
+Is there any current limitation within the generator/API Extractor?
+-------------------------------------------------------------------
+
+The generator currently does not automatically detects implicit C++
+type conversions. Also the code snippets in function signature and
+examples are still in C++ inside the generated documentation.
+
diff --git a/doc/images/.directory b/doc/images/.directory
new file mode 100644
index 00000000..e65475f6
--- /dev/null
+++ b/doc/images/.directory
@@ -0,0 +1,3 @@
+[Dolphin]
+ShowPreview=true
+Timestamp=2009,5,5,17,43,26
diff --git a/doc/images/bindinggen-development.png b/doc/images/bindinggen-development.png
new file mode 100644
index 00000000..2dd64ba1
--- /dev/null
+++ b/doc/images/bindinggen-development.png
Binary files differ
diff --git a/doc/images/boostgen.png b/doc/images/boostgen.png
new file mode 100644
index 00000000..ae9d9fc3
--- /dev/null
+++ b/doc/images/boostgen.png
Binary files differ
diff --git a/doc/images/boostqtarch.png b/doc/images/boostqtarch.png
new file mode 100644
index 00000000..f1b145e9
--- /dev/null
+++ b/doc/images/boostqtarch.png
Binary files differ
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644
index 00000000..2ceb42fb
--- /dev/null
+++ b/doc/overview.rst
@@ -0,0 +1,46 @@
+.. _gen-overview:
+
+******************
+Generator Overview
+******************
+
+In a few words, the Generator is a system that
+parses a collecion 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 a 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 Python-friendly way.
+4. Insert customizations where handwritten code is needed.
+
+.. figure:: images/boostqtarch.png
+ :scale: 80
+ :align: center
+
+ Runtime architecture
+
+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/tutorial/bindinglibfoo.rst b/doc/tutorial/bindinglibfoo.rst
new file mode 100644
index 00000000..fc256fba
--- /dev/null
+++ b/doc/tutorial/bindinglibfoo.rst
@@ -0,0 +1,76 @@
+.. highlight:: xml
+
+.. _gentut-bindinglibfoo:
+
+Binding libfoo with the Generator
+=================================
+
+In order to create bindings for a library based on Qt4 a number of components
+must be available in the system.
+
+ + Qt4 library (with headers and pkg-config .pc files for development -- the
+ ``-dev`` packages in a Debian distribution).
+ + Qt4 Python bindings made with **boostgenerator**.
+ + Typesystems for the Qt4 Python bindings.
+ + Headers for the library to be bound.
+
+With the above listed in place the developer must write the components from
+where the generator will gather information to create the binding source code.
+
+ + Typesystem file describing the way the binding must be done.
+ + **global.h** including all the **libfoo** headers and defining required macros.
+ + A build system to direct the process of generating, compiling and linking the binding.
+
+The directory structure for the binding project could be something like the tree
+shown below:
+
+::
+
+ foobinding/
+ |-- data/
+ `-- module_dir/
+ `-- glue/
+
+
+The **data** directory should contain the **global.h** and the typesystem
+file. This typesystem need to refer to the ones used to create the Qt4 bindings,
+commonly located on **/usr/share/PyQtB/typesystem**, the exact location
+can be checked with pkg-config:
+
+::
+
+ $ pkg-config qt4python --variable=typesystemdir
+
+
+The **module_dir** directory is the place where the sources generated should
+be placed. It starts empty except for the build instructions file (Makefile,
+Makefile.am, CMakeLists.txt, etc). The realname of this directory must be the
+same written in the typesystem file:
+
+::
+
+ <typesystem package="module_dir">
+
+
+If there is any need for handwritten source code longer than a couple of lines,
+making them unconfortable to be put on the typesystem xml file, the sources
+could be orderly placed in a **glue** directory, also referred in the
+new binding typesystem.
+
+When writing the typesystem file (more on this later) there is no need to refer
+to the other required typesystem files with absolute paths, the locations where
+they can be found could be passed to the generator through a command line
+option (``--typesystem-paths=PATH1:PATH2:[...]``) or the environment variable
+**TYPESYSTEMPATH**.
+
+For **libfoo** no glue code will be needed so this directory is not used,
+the other directories are created with proper names.
+
+::
+
+ foobinding/
+ |-- data/global.h
+ | `-- typesystem_foo.xml
+ `-- foo/
+ `-- Makefile
+
diff --git a/doc/tutorial/buildingthebinding.rst b/doc/tutorial/buildingthebinding.rst
new file mode 100644
index 00000000..bc60fe28
--- /dev/null
+++ b/doc/tutorial/buildingthebinding.rst
@@ -0,0 +1,133 @@
+.. _gentut-buildingthebinding:
+
+Building The Binding
+====================
+
+As mentioned before the build system used must perform the following tasks
+in the correct order:
+
+ + Gather data about locations of headers and external needed typesystems.
+ + Run the generator with the correct parameters.
+ + Compile and link the binding.
+
+The first and last are the usual, being the second the only novelty in the
+process.
+
+Running the Generator
+---------------------
+
+The generator is called with the following parameters and options:
+
+::
+
+ $ boostgenerator global_headers.h \
+ --include-paths=$(PATHS_TO_HEADERS)) \
+ --typesystem-paths=$(PATHS_TO_TYPESYSTEMS) \
+ --output-directory=. \
+ typesystem.xml
+
+Notice that the variables for include and typesystem paths could be determined
+at build time with the pkg-config tool.
+
+Collecting information with pkg-config
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Qt4 bindings include compile and build information through the pkg-config
+mechanism. The pkg-config name for Qt4 Python bindings is **qt4python** and a
+simple ``pkg-config qt4python --cflags --libs`` will retrieve the information
+needed to build the new binding.
+
+The Qt4 bindings file ``qt4python.pc`` for the use of pkg-config requires
+the ``.pc`` files from Qt4 to be installed. If the library is in an unusual
+location, e.g. ``/opt/qt45``, remember to export it to the ``PKG_CONFIG_PATH``
+environment variable.
+For example: ``export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/qt45/lib/pkgconfig``
+
+There is a vital information also available through pkg-config:
+the **typesystemdir** variable. It is used like this:
+``pkg-config qt4python --variable=typesystemdir`` This provides information
+where to find the typesystem files used to create the Qt4 bindings, and as said
+before the binding being created needs this to complement its own binding
+information for the generation proccess.
+
+Makefile
+--------
+
+Below is a plain Makefile for the binding project.
+
+**foobinding/foo/Makefile**
+::
+
+ LIBTEST_DIR = ../../libfoo
+ LIBS = -lboost_python-gcc43-1_38-py25 -lpython2.5 \
+ `pkg-config qt4python --libs` \
+ -lfoo -L$(LIBTEST_DIR) \
+ -lpthread -ldl -lutil
+ CFLAGS = -I/usr/share/qt4/mkspecs/linux-g++ -I. \
+ -I$(LIBTEST_DIR) \
+ `pkg-config qt4python --cflags` \
+ -I/usr/include/python2.5\
+ -I/usr/include/boost/python
+ QT4TYPESYSTEM_DIR = `pkg-config --variable=typesystemdir qt4python`
+ QT4HEADER_DIRS = `pkg-config --variable=includedir QtCore`:`pkg-config --variable=includedir QtCore`/..
+
+ SOURCES = math_wrapper.cpp foo_module_wrapper.cpp foo_global_functions_wrapper.cpp
+ OBJECTS = math_wrapper.o foo_module_wrapper.o foo_global_functions_wrapper.o
+
+ all: generate compile link
+
+ generate:
+ boostgenerator ../data/global.h \
+ --include-paths=$(LIBTEST_DIR):$(QT4HEADER_DIRS):/usr/include \
+ --typesystem-paths=../data:$(QT4TYPESYSTEM_DIR) \
+ --output-directory=.. \
+ ../data/typesystem_foo.xml
+
+ compile: $(SOURCES)
+ g++ -fPIC -DPIC $(CFLAGS) math_wrapper.cpp -c
+ g++ -fPIC -DPIC $(CFLAGS) foo_global_functions_wrapper.cpp -c
+ g++ -fPIC -DPIC $(CFLAGS) foo_module_wrapper.cpp -c
+
+ link:
+ g++ -shared -Wl,-soname,foo.so -o foo.so $(LIBS) $(OBJECTS)
+
+ test:
+ LD_LIBRARY_PATH=$(LIBTEST_DIR) python -c \
+ "import foo; print dir(foo); m = foo.Math(); print m.squared(5)"
+
+ clean:
+ rm -rf *.o *.so *.?pp *.log
+
+
+Keepe in mind that the Makefile above expects the ``libfoo`` and
+``foobinding`` directories to be in the same level in the directory
+hierarchy, remember to change any path references accordingly if
+you choose to change things.
+
+**Warning:**
+ The order in which the link flags are passed matters.
+ **libboost_python** must come first, otherwise weeping
+ and gnashing of teeth will follow.
+
+Testing the Binding
+-------------------
+Now compile the binding with ``make``:
+
+::
+
+ $ cd foobinding/foo
+ $ make
+
+To test if the new binding is working (it can pass the build phase but still
+blow up at runtime) start up a Python terminal and import it by the name.
+
+::
+
+ $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libfoo/shared/object/dir
+ $ export PYTHONPATH=$PYTHONPATH:/path/to/foo/python/module/file/dir
+ $ python
+ >> import foo
+ >> print dir(foo)
+ >> m = foo.Math()
+ >> print m.squared(5)
+
diff --git a/doc/tutorial/globalheader.rst b/doc/tutorial/globalheader.rst
new file mode 100644
index 00000000..d1ac2392
--- /dev/null
+++ b/doc/tutorial/globalheader.rst
@@ -0,0 +1,36 @@
+.. highlight:: cpp
+
+.. _gentut-globalheader:
+
+The Global Header
+=================
+
+Besides the information provided by the typesystem, the generator needs to
+gather more data from the library headers containing the classes to be exposed
+in Python. If there is a header that include all the others (or just one, as is
+the case of **libfoo**) this could be passed directly to the generator.
+
+If such a file is not available, or only a subset of the library is desired, or
+if some flags must be defined before parsing the library headers, then a
+``global.h`` file must be provided.
+
+The use of a ``global.h`` file is preferred if some macros must be defined
+before the parser gather data from the headers. For example, if ``NULL`` is not
+defined and it is used as a default paramater for some constructor or method,
+the parser will not recognize it.
+
+The solve this create a ``global.h`` including all the desired headers and the
+defined (and undefined) flags as follows:
+
+**foobinding/data/global.h**
+::
+
+ #undef QT_NO_STL
+ #undef QT_NO_STL_WCHAR
+
+ #ifndef NULL
+ #define NULL 0
+ #endif
+
+ #include <foo.h>
+
diff --git a/doc/tutorial/images/generatorworkings.png b/doc/tutorial/images/generatorworkings.png
new file mode 100644
index 00000000..d35a565f
--- /dev/null
+++ b/doc/tutorial/images/generatorworkings.png
Binary files differ
diff --git a/doc/tutorial/images/generatorworkings.svg b/doc/tutorial/images/generatorworkings.svg
new file mode 100644
index 00000000..85a7782a
--- /dev/null
+++ b/doc/tutorial/images/generatorworkings.svg
@@ -0,0 +1,392 @@
+<?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:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="680"
+ height="280"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="generatorworkings.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="generatorworkings.png"
+ inkscape:export-xdpi="86.970001"
+ inkscape:export-ydpi="86.970001"
+ version="1.0">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path4293"
+ 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>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3235">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3237" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3239" />
+ </linearGradient>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible">
+ <path
+ id="path3282"
+ 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="6.1230318e-14 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3235"
+ id="linearGradient3241"
+ x1="-29.816929"
+ y1="320.97046"
+ x2="191.17912"
+ y2="322.7244"
+ gradientUnits="userSpaceOnUse" />
+ </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.4420481"
+ inkscape:cx="361.95624"
+ inkscape:cy="122.34225"
+ inkscape:document-units="px"
+ inkscape:current-layer="g3297"
+ showgrid="false"
+ inkscape:window-width="1279"
+ inkscape:window-height="944"
+ inkscape:window-x="391"
+ inkscape:window-y="38"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <sodipodi:guide
+ orientation="1,0"
+ position="-228.99296,-21.575354"
+ id="guide3165" />
+ </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(291.86879,-366.35864)">
+ <text
+ xml:space="preserve"
+ 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"
+ x="324.86121"
+ y="308.08389"
+ id="text3395"
+ transform="translate(-28.960129,110.67739)"><tspan
+ sodipodi:role="line"
+ id="tspan3397"
+ x="324.86121"
+ y="308.08389" /></text>
+ <g
+ id="g3254">
+ <g
+ id="g3297"
+ transform="translate(15,11.795533)">
+ <rect
+ style="fill:#e4fae3;fill-opacity:0.65882353;stroke:#8eff89;stroke-width:0.52055138;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3609"
+ width="323.15158"
+ height="216.66933"
+ x="-151.9006"
+ y="364.42294"
+ ry="7.354454"
+ rx="5.3701153" />
+ <path
+ 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;display:inline"
+ d="M 195.16416,473.16835 L 149.88745,473.08346"
+ id="path3285"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connection-start="#g3276" />
+ <g
+ id="g3276"
+ transform="translate(-47.379381,-25.682818)">
+ <rect
+ ry="11.816782"
+ rx="12.0209"
+ y="462.87637"
+ x="242.78513"
+ height="72.257683"
+ width="163.85461"
+ id="rect2461"
+ style="fill:#9dcdf9;fill-opacity:1;stroke:#0084ff;stroke-width:0.48317167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text2463"
+ y="494.80786"
+ x="324.45514"
+ style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;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
+ style="font-size:22px;text-align:center;text-anchor:middle"
+ y="494.80786"
+ x="324.45514"
+ id="tspan2465"
+ sodipodi:role="line">binding</tspan><tspan
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono"
+ y="519.56543"
+ x="324.45514"
+ sodipodi:role="line"
+ id="tspan3018">source code</tspan></text>
+ </g>
+ <path
+ 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;display:inline"
+ d="M -130.41272,567.21015 L -180.20217,584.91297"
+ id="path3054"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ 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;display:inline"
+ d="M -129.57075,528.12072 L -181.18287,504.96225"
+ id="path3056"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <g
+ id="g3147"
+ transform="translate(74.301071,9.8268847)">
+ <g
+ transform="translate(62.764666,-13.729771)"
+ id="g2986">
+ <rect
+ style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.3511245;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2970"
+ width="115.38314"
+ height="55.650036"
+ x="-430.1297"
+ y="481.9653"
+ rx="11.184198"
+ ry="13.895926" />
+ <text
+ xml:space="preserve"
+ style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;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="-371.96939"
+ y="505.29422"
+ id="text2972"><tspan
+ id="tspan2976"
+ sodipodi:role="line"
+ x="-371.96939"
+ y="505.29422"
+ style="font-size:16px;text-align:center;text-anchor:middle">typesystem</tspan><tspan
+ id="tspan2980"
+ sodipodi:role="line"
+ x="-371.96939"
+ y="525.29419"
+ style="font-size:16px;text-align:center;text-anchor:middle">descriptions</tspan></text>
+ </g>
+ <g
+ transform="translate(74.533053,61.297656)"
+ id="g3020">
+ <rect
+ style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.36426121;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3022"
+ width="91.833252"
+ height="75.250854"
+ x="-418.35477"
+ y="472.16489"
+ rx="9.1466599"
+ ry="12.17058" />
+ <text
+ xml:space="preserve"
+ style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;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="-372.64865"
+ y="494.13867"
+ id="text3024"><tspan
+ id="tspan3026"
+ sodipodi:role="line"
+ x="-372.64865"
+ y="494.13867"
+ style="font-size:16px;text-align:center;text-anchor:middle">custom</tspan><tspan
+ id="tspan3028"
+ sodipodi:role="line"
+ x="-372.64865"
+ y="513.88837"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono">source</tspan><tspan
+ id="tspan3030"
+ sodipodi:role="line"
+ x="-372.64865"
+ y="536.38837"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono">code</tspan></text>
+ </g>
+ </g>
+ <path
+ 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;display:inline"
+ d="M -40.946515,396.85213 L -179.16818,396.16834"
+ id="path3098"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <g
+ id="g3141"
+ transform="translate(66.255107,-6.2939423)">
+ <rect
+ ry="11.897643"
+ rx="9.5758715"
+ y="381.30014"
+ x="-342.70132"
+ height="47.647366"
+ width="98.790642"
+ id="rect2415"
+ style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.30063155;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text2417"
+ y="401.08865"
+ x="-293.63803"
+ style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;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
+ style="font-size:16px;text-align:center;text-anchor:middle"
+ y="401.08865"
+ x="-293.63803"
+ id="tspan2419"
+ sodipodi:role="line">library</tspan><tspan
+ style="font-size:16px;text-align:center;text-anchor:middle"
+ y="421.08865"
+ x="-293.63803"
+ sodipodi:role="line"
+ id="tspan2949">headers</tspan></text>
+ </g>
+ <path
+ 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;display:inline"
+ d="M 33.165609,503.00316 L 32.819729,546.19947"
+ id="path3167"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <path
+ 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;display:inline"
+ d="M 33.145722,443.9261 L 32.799842,391.41316"
+ id="path3169"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc" />
+ <g
+ id="g2944"
+ transform="translate(85.554958,3.1233551)">
+ <rect
+ rx="6.8840375"
+ ry="10.365664"
+ y="371.05527"
+ x="-125.40932"
+ height="44.903805"
+ width="101.06483"
+ id="rect3625"
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.36750945;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ transform="scale(1.0000266,0.9999734)"
+ id="text3627"
+ y="401.12787"
+ x="-75.810593"
+ 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"
+ xml:space="preserve"><tspan
+ 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"
+ y="401.12787"
+ x="-75.810593"
+ sodipodi:role="line"
+ id="tspan3697">Parser</tspan></text>
+ </g>
+ <g
+ id="g3093"
+ transform="translate(-22.960524,10.08797)">
+ <rect
+ ry="8.5151205"
+ rx="9.4630651"
+ y="433.92093"
+ x="9.3588104"
+ height="58.626995"
+ width="163.91852"
+ id="rect2446"
+ style="fill:#b2d7b5;fill-opacity:1;stroke:#34ff34;stroke-width:0.20534486;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.69008268" />
+ <text
+ id="text2448"
+ y="457.49274"
+ x="90.813187"
+ style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;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
+ style="font-size:22px;font-weight:bold;text-align:center;text-anchor:middle"
+ y="457.49274"
+ x="90.813187"
+ id="tspan2450"
+ sodipodi:role="line">Generator</tspan><tspan
+ style="font-size:22px;font-weight:bold;text-align:center;text-anchor:middle"
+ y="484.99274"
+ x="90.813187"
+ sodipodi:role="line"
+ id="tspan3340">Backend</tspan></text>
+ </g>
+ <g
+ id="g3160"
+ transform="translate(94.301071,19.633862)">
+ <rect
+ rx="5.7330456"
+ ry="8.3964748"
+ y="506.2883"
+ x="-225.62247"
+ height="44.764942"
+ width="192.46243"
+ id="rect2933"
+ style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.50637114;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ transform="scale(1.0000266,0.9999734)"
+ id="text2935"
+ y="534.47565"
+ x="-128.93036"
+ 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"
+ xml:space="preserve"><tspan
+ 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"
+ y="534.47565"
+ x="-128.93036"
+ sodipodi:role="line"
+ id="tspan2937">TypeDatabase</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/tutorial/introduction.rst b/doc/tutorial/introduction.rst
new file mode 100644
index 00000000..5234551b
--- /dev/null
+++ b/doc/tutorial/introduction.rst
@@ -0,0 +1,31 @@
+Binding Generation Tutorial
+***************************
+
+This tutorial intends to describe the process of binding creation with
+|project| and using a very simple Qt4 based library will be used as an
+example.
+
+The image below shows the inputs needed to generate the binding source code.
+
+.. image:: images/generatorworkings.png
+
+Putting in words, the user provides the headers for the library along with a
+typesystem file describing how the classes will be exposed in the target
+language, as well as any needed custom source code to be merged with
+the generated source code.
+
+This tutorial will go through the steps needed to have the binding
+being able to be imported and used from a Python program.
+
+**NOTE:** the binding generator is intended to be used with Qt4 based libraries
+only, at least for the time being.
+
+.. toctree::
+ :maxdepth: 3
+
+ libfoo
+ bindinglibfoo
+ typesystemcreation
+ globalheader
+ buildingthebinding
+
diff --git a/doc/tutorial/libfoo.rst b/doc/tutorial/libfoo.rst
new file mode 100644
index 00000000..217577a4
--- /dev/null
+++ b/doc/tutorial/libfoo.rst
@@ -0,0 +1,68 @@
+.. highlight:: cpp
+
+.. _gentut-libfoo:
+
+Creating the foo library
+=========================
+
+In this section is the code and build instructions for a very simple Qt4 based
+library which will serve as a subject for this tutorial.
+
+The Source Code
+---------------
+
+There is only one class on this foo library plus a ``.pro`` file which means
+that the build system used will be Trolltech's **qmake**.
+
+Put the files below in a directory called **libfoo**. Be aware that this
+directory will be refered by the binding Makefile presented in a next section
+of this tutorial. If you want to use other names or paths change the binding
+Makefile accordingly. Blind copy'n'paste shortens your life.
+
+**libfoo/foo.h**
+::
+
+ #ifndef FOO_H
+ #define FOO_H
+
+ #include <QtCore/QtCore>
+
+ class Math : public QObject
+ {
+ Q_OBJECT
+ public:
+ Math() {}
+ virtual ~Math() {}
+ int squared(int x);
+ };
+ #endif // FOO_H
+
+
+**libfoo/foo.cpp**
+::
+
+ #include "foo.h"
+
+ int Math::squared(int x)
+ {
+ return x * x;
+ }
+
+
+**libfoo/foo.pro**
+::
+
+ TEMPLATE = lib
+ TARGET = foo
+ DEPENDPATH += .
+ INCLUDEPATH += .
+ HEADERS += foo.h
+ SOURCES += foo.cpp
+
+To build the lib:
+
+::
+
+ $ cd libfoo
+ $ qmake
+ $ make
diff --git a/doc/tutorial/typesystemcreation.rst b/doc/tutorial/typesystemcreation.rst
new file mode 100644
index 00000000..f36a8769
--- /dev/null
+++ b/doc/tutorial/typesystemcreation.rst
@@ -0,0 +1,136 @@
+.. highlight:: xml
+
+.. _gentut-typesystem:
+
+Creating the Typesystem Description
+===================================
+
+The type system is a specification used when mapping a C++ based library onto a
+corresponding Python module. The specification is a handwritten XML document
+listing the types that will be available in the generated binding, alterations
+to classes and function signatures to better suit the target language,
+and listing the components that should be rejected for the binding.
+
+**PyQtB** uses a typesystem format similar to the ones used **QtJambi** and
+**QtScript**, thoroughly described in the page *"The Qt Jambi Type System"*. [#]_
+
+The divergences between **PyQtB** and QtScript/QtJambi typesystems will be
+highlighted whenever they appear. Things to be aware of when writing
+a typesystem will be also mentioned.
+
+Describing **libfoo** for Python Audiences
+------------------------------------------
+
+All typesystem files start with the root ``typesystem`` tag, the
+``package`` attribute carries the name of the package as it will be seen
+from Python.
+
+Right after that, all the typesystem files providing information required for
+the generation process are included in the same fashion as header files in C.
+
+**foobinding/data/typesystem_test.xml**
+::
+
+ <?xml version="1.0"?>
+ <typesystem package="foo">
+ <load-typesystem name="typesystem_core.xml" generate="no"/>
+ <object-type name="Math"/>
+ </typesystem>
+
+
+The inclusion of the other typesystem files is achieved with the
+``load-typesystem`` tag. The ``generate`` attribute must be set to ``"no"``
+or else the generator will try to create more source code for the already
+existing bindings included for reference.
+
+The C++ classes derived from **QObject** intended to be exposed in the target
+language are described with ``object-type`` tags.
+
+
+For this example binding just specifying the name of the class does the trick,
+since the generator system will automatically catch the methods with arguments
+and return value of types known. These types can be described in the same
+typesystem file or in the ones referenced with the ``load-typesystem`` tag.
+
+In more complex situations method signatures can be changed or rejected with
+other tags that can be checked out in the typesystem reference.
+
+
+Other Common Cases and Differences
+----------------------------------
+
+What follows now is some common uses of the typesystem capabilities. All of them
+can be seen in the Qt4 typesystem files. They are not used for this binding
+tutorial example, so if you just want to have things working ASAP,
+move along.
+
+Templates
+~~~~~~~~~
+
+To ease the process of writing custom code for the binding, recurring pieces of
+code can be turned generic with the Typesystem template mechanism.
+They are declared in a way similar to this snippet:
+
+::
+
+ <template name="only_bool*_fix">
+ bool ok;
+ %RETURN_TYPE retval = self.%FUNCTION_NAME(&ok);
+ </template>
+
+And is used as in this example:
+
+::
+
+ <inject-code class="native" position="beginning">
+ <insert-template name="only_bool*_fix"/>
+ </inject-code>
+
+
+The ``typesystem_template.xml`` file from the Qt4 bindings can be used as a
+good resource for examples of this. Check also the QtJambi documentation on
+typesystem templates. [#]_
+
+Non-QObject Derived Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Even in a Qt4 based library it is common to find classes that doesn't
+pertain to the QObject hierarchy, these must be declared as ``value-type``:
+
+::
+
+ <value-type name="RectOrSomethingLikeThat"/>
+
+
+Unused Tags
+~~~~~~~~~~~
+
+Some tags defined in the QtScript/QtJambi typesystem has no effect in **PyQtB**
+typesystem, they are:
+
+ + conversion-rule
+ + argument-map
+
+Changes to ``"inject-code"`` Tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can pass a file name to the **inject-code** tag, the file contents will
+be injected in the generated code.
+
+The ``class`` attribute value ``java`` was changed to ``target``, while
+``native`` remained the same.
+
+Global Functions
+~~~~~~~~~~~~~~~~
+
+The **BoostGenerator** supports global functions, you can also reject these
+functions using the **rejection** tag like is done to reject classes, just
+pass an empty string to the class attribute.
+
+::
+
+ <rejection class="" function-name="qt_noop"/>
+
+
+.. [#] http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-typesystem.html
+.. [#] http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-typesystem.html#using-code-templates
diff --git a/docgenerator.cpp b/docgenerator.cpp
new file mode 100644
index 00000000..41b30cd6
--- /dev/null
+++ b/docgenerator.cpp
@@ -0,0 +1,1370 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 "docgenerator.h"
+#include <reporthandler.h>
+#include <qtdocparser.h>
+#include <algorithm>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+static Indentor INDENT;
+
+namespace
+{
+
+static bool functionSort(const AbstractMetaFunction *func1, const AbstractMetaFunction *func2)
+{
+ return func1->name() < func2->name();
+}
+
+QString createRepeatedChar(int i, char c)
+{
+ QString out;
+ for (int j = 0; j < i; ++j)
+ out += c;
+
+ return out;
+}
+
+QString escape(QString& str)
+{
+ return str
+ .replace("*", "\\*")
+ .replace("_", "\\_");
+}
+
+QString escape(const QStringRef& strref)
+{
+ QString str = strref.toString();
+ return escape(str);
+}
+
+}
+
+QtXmlToSphinx::QtXmlToSphinx(DocGenerator* 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("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);
+
+ 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::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::readFromLocation(QString& location, QString& identifier)
+{
+ QFile inputFile;
+ inputFile.setFileName(location);
+ if (!inputFile.open(QIODevice::ReadOnly)) {
+ ReportHandler::warning("Couldn't read code snippet file: "+inputFile.fileName());
+ 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 (code.isEmpty())
+ ReportHandler::warning("Code snippet file found ("+location+"), but snippet "+ identifier +" not found.");
+
+ 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) {
+ int 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();
+ location.prepend(m_generator->codeSnippetDir() + '/');
+ QString code = readFromLocation(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[0] == m_context)
+ l_linkref.prepend("~" + m_context + '.');
+ } else if (l_type == "function" && m_context.isEmpty()) {
+ l_linktag = " :func:`";
+ } else if (l_type == "class") {
+ l_linktag = " :class:`";
+ } 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;
+
+ // add col spans
+ for (row = 0; row < count(); ++row) {
+ for (col = 0; col < at(row).count(); ++col) {
+ QtXmlToSphinx::TableCell& cell = self[row][col];
+ 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++;
+ }
+ }
+ }
+
+ // 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 = row.count(); 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 << '+';
+ char c = (!i && table.hasHeader()) ? '=' : '-';
+ for (int col = 0, max = colWidths.count(); col < max; ++col) {
+ char c;
+ if (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 = row.count(); 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 getClassName(const AbstractMetaClass *cppClass) {
+ return cppClass->name().replace("::", ".");
+}
+
+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("::", ".");
+}
+
+QString DocGenerator::fileNameForClass(const AbstractMetaClass *cppClass) const
+{
+ return QString("%1.rst").arg(getClassName(cppClass));
+}
+
+void DocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass)
+{
+ QString metaClassName;
+
+ if (metaClass)
+ metaClassName = getClassName(metaClass);
+
+ if (doc.format() == Documentation::Native) {
+ QtXmlToSphinx x(this, doc.value(), metaClassName);
+ s << x;
+ } else {
+ s << doc.value();
+ }
+
+ s << endl;
+}
+
+void DocGenerator::writeFunctionBrief(QTextStream &s,
+ const AbstractMetaClass *cppClass,
+ const AbstractMetaFunction *cppFunction)
+{
+ s << INDENT << "def :meth:`"
+ << cppFunction->name() << "<";
+ if (cppClass && cppClass->name() != cppFunction->name())
+ s << getClassName(cppClass) << '.';
+
+ s << cppFunction->name() << ">`"
+ << " (" << parseArgDocStyle(cppClass, cppFunction) << "):";
+}
+
+void DocGenerator::generateClass(QTextStream &s, const AbstractMetaClass *cppClass)
+{
+ QString doc;
+ QTextStream doc_s(&doc);
+
+ ReportHandler::debugSparse("Generating Documentation for " + cppClass->fullName());
+ s << ".. module:: " << packageName() << endl;
+ QString className = getClassName(cppClass);
+ 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...
+
+ //Function list
+ AbstractMetaFunctionList functionList = filterFunctions(cppClass);
+ qSort(functionList.begin(), functionList.end(), functionSort);
+
+#if 0
+ if (functionList.size() > 0)
+ {
+ QtXmlToSphinx::Table functionTable;
+ QtXmlToSphinx::TableRow row;
+
+ s << "Functions\n"
+ "---------\n\n";
+
+
+ foreach (AbstractMetaFunction *func, functionList) {
+ if ((func->isConstructor() || func->isModifiedRemoved()) ||
+ (func->declaringClass() != cppClass))
+ continue;
+
+ QString rowString;
+ QTextStream rowStream(&rowString);
+
+ writeFunctionBrief(rowStream, cppClass, func);
+ row << rowString;
+ functionTable << row;
+ row.clear();
+ }
+ functionTable.normalize();
+ s << functionTable;
+ }
+
+#endif
+
+ doc_s << "Detailed Description\n"
+ "--------------------\n\n";
+
+ writeInjectDocumentation(doc_s, DocModification::Prepend, cppClass, 0);
+ writeFormatedText(doc_s, cppClass->documentation(), cppClass);
+
+
+ if (!cppClass->isNamespace()) {
+
+ writeConstructors(doc_s, cppClass);
+ writeEnums(doc_s, cppClass);
+ writeFields(doc_s, cppClass);
+
+ foreach (AbstractMetaFunction *func, functionList) {
+ if ((func->isConstructor() || func->isModifiedRemoved()) ||
+ (func->declaringClass() != cppClass))
+ continue;
+
+ if (func->isStatic())
+ doc_s << ".. staticmethod:: ";
+ else
+ doc_s << ".. method:: ";
+
+ writeFunction(doc_s, true, cppClass, func);
+ }
+ }
+
+ writeInjectDocumentation(doc_s, DocModification::Append, cppClass, 0);
+
+ writeFunctionList(s, doc, cppClass);
+
+ s << doc;
+}
+
+QString DocGenerator::parseFunctionDeclaration(const QString &doc, const AbstractMetaClass *cppClass)
+{
+ //.. method:: QObject.childEvent(arg__1)
+ //def :meth:`removeEventFilter<QObject.removeEventFilter>` (arg__1):
+
+ QString data = doc;
+ QString markup;
+
+ if (data.startsWith(".. method::"))
+ markup = ".. method::";
+ else if (data.startsWith(".. staticmethod::"))
+ markup = ".. staticmethod::";
+ else
+ return QString();
+
+ data = data.mid(markup.size()); //remove .. method::
+ data = data.mid(data.indexOf(".") + 1); //remove class name
+
+ QString methName = data.mid(0, data.indexOf("("));
+ QString methArgs = data.mid(data.indexOf("("));
+
+ data = QString("def :meth:`%1<%2.%3>` %4")
+ .arg(methName)
+ .arg(cppClass->name())
+ .arg(methName)
+ .arg(methArgs);
+
+ return data;
+}
+
+
+void DocGenerator::writeFunctionList(QTextStream &s, const QString &content, const AbstractMetaClass *cppClass)
+{
+ QStringList functionList;
+ QStringList staticFunctionList;
+
+ QStringList lst = content.split("\n");
+ foreach(QString row, lst) {
+ QString data = row.trimmed();
+ if (data.startsWith(".. method::")) {
+ functionList << parseFunctionDeclaration(data, cppClass);
+ }
+ else if (data.startsWith(".. staticmethod::")) {
+ staticFunctionList << parseFunctionDeclaration(data, cppClass);
+ }
+ }
+
+ if ((functionList.size() > 0) || (staticFunctionList.size() > 0))
+ {
+ QtXmlToSphinx::Table functionTable;
+ QtXmlToSphinx::TableRow row;
+
+ s << "Synopsis" << endl
+ << "--------" << endl << endl;
+
+ if (functionList.size() > 0) {
+ s << "Functions" << endl
+ << "^^^^^^^^^" << endl << endl;
+
+ qSort(functionList);
+ foreach (QString func, functionList) {
+ row << func;
+ functionTable << row;
+ row.clear();
+ }
+
+ functionTable.normalize();
+ s << functionTable << endl;
+ functionTable.clear();
+ }
+
+ if (staticFunctionList.size() > 0) {
+ s << "Static functions" << endl
+ << "^^^^^^^^^^^^^^^^" << endl;
+
+ qSort(staticFunctionList);
+ foreach (QString func, staticFunctionList) {
+ row << func;
+ functionTable << row;
+ row.clear();
+ }
+
+ functionTable.normalize();
+ s << functionTable << endl;
+ }
+ }
+}
+
+void DocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString section_title(".. attribute:: ");
+
+ foreach (AbstractMetaEnum *en, cppClass->enums()) {
+ s << section_title << getClassName(cppClass) << "." << en->name() << endl << endl;
+ writeFormatedText(s, en->documentation(), cppClass);
+ }
+}
+
+void DocGenerator::writeFields(QTextStream &s, const AbstractMetaClass *cppClass)
+{
+ static const QString section_title(".. attribute:: ");
+
+ foreach (AbstractMetaField *field, cppClass->fields()) {
+ s << section_title << getClassName(cppClass) << "." << field->name() << endl << endl;
+ //TODO: request for member ‘documentation’ is ambiguous
+ writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
+ }
+}
+
+void DocGenerator::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->argumentName())) {
+ arg_map.insert(arg->argumentName(), 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 DocGenerator::parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func)
+{
+ QString ret;
+ bool optional = false;
+
+ foreach (AbstractMetaArgument *arg, func->arguments()) {
+
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ if (arg->argumentIndex() > 0)
+ ret += ",";
+
+ if (!arg->defaultValueExpression().isEmpty() && (!optional)) {
+ ret += "[";
+ optional = true;
+ }
+
+ ret += arg->argumentName();
+
+ if (optional)
+ ret += "=" + arg->defaultValueExpression();
+ }
+
+ if (optional)
+ ret += "]";
+
+ return ret;
+}
+
+void DocGenerator::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());
+ }
+ }
+}
+
+void DocGenerator::writeInjectDocumentation(QTextStream &s,
+ DocModification::Mode mode,
+ const AbstractMetaClass *cppClass,
+ const AbstractMetaFunction *func)
+{
+ Indentation indentation(INDENT);
+
+ 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);
+ s << INDENT;
+ writeFormatedText(s, doc, cppClass);
+ }
+ }
+ }
+
+ s << endl;
+
+ if (func) {
+ writeDocSnips(s, getCodeSnips(func),
+ (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End),
+ TypeSystem::TargetLangCode);
+ } else {
+ writeDocSnips(s, cppClass->typeEntry()->codeSnips(),
+ (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End),
+ TypeSystem::TargetLangCode);
+ }
+}
+
+void DocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ if (!func->isConstructor())
+ s << getClassName(cppClass) << '.';
+ s << getFuncName(func) << "(" << parseArgDocStyle(cppClass, func) << ")";
+}
+
+QString DocGenerator::translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass)
+{
+ QString originalType = translateType(type, cppClass, Generator::ExcludeConst | Generator::ExcludeReference);
+ QString strType = originalType;
+
+ //remove "*"
+ strType.remove("*");
+ TypeEntry *te = TypeDatabase::instance()->findType(originalType.trimmed());
+ if (te) {
+ return te->targetLangName();
+ } else {
+ //remove <, >
+ strType.remove(">");
+ strType.remove("<");
+
+ //replace ::
+ strType.replace("::", ".");
+
+ //Translate ContainerType
+ 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]);
+ }
+ return strType;
+ }
+}
+
+void DocGenerator::writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg)
+{
+ s << INDENT << ":param " << arg->argumentName() << ": "
+ << translateToPythonType(arg->type(), cppClass) << endl;
+}
+
+void DocGenerator::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()) {
+ s << INDENT << ":rtype: " << translateToPythonType(func->type(), cppClass) << endl;
+ }
+ s << endl;
+}
+
+void DocGenerator::writeFunction(QTextStream &s, bool writeDoc, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func)
+{
+ writeFunctionSignature(s, cppClass, func);
+ s << endl;
+
+ if (writeDoc) {
+ s << endl;
+ writeFunctionParametersType(s, cppClass, func);
+ s << endl;
+ writeInjectDocumentation(s, DocModification::Prepend, cppClass, func);
+ writeFormatedText(s, func->documentation(), cppClass);
+ writeInjectDocumentation(s, DocModification::Append, cppClass, func);
+ }
+}
+
+void DocGenerator::finishGeneration()
+{
+ if (classes().isEmpty())
+ return;
+
+ QFile input(outputDirectory() + '/' + subDirectoryForPackage(packageName()) + "/index.rst");
+ input.open(QIODevice::WriteOnly);
+ QTextStream s(&input);
+
+ s << ".. module:: " << packageName() << endl << endl;
+
+ QString title = packageName() + " contents";
+ s << title << endl;
+ s << createRepeatedChar(title.length(), '*') << endl << endl;
+ s << ".. toctree::" << endl;
+
+ /* Avoid showing "Detailed Description for *every* class in toc tree */
+ Indentation indentation(INDENT);
+ s << INDENT << ":maxdepth: 1" << endl << endl;
+
+ QStringList classList;
+ foreach (AbstractMetaClass *cls, classes()) {
+ if (!shouldGenerate(cls))
+ continue;
+ classList << getClassName(cls);
+ }
+ classList.sort();
+
+ foreach (QString clazz, classList)
+ s << INDENT << clazz << endl;
+
+ s << endl << endl;
+
+ s << "Detailed Description" << endl;
+ s << "--------------------" << endl << endl;
+
+ if (m_moduleDoc.format() == Documentation::Native) {
+ QtXmlToSphinx x(this, m_moduleDoc.value(), moduleName());
+ s << x;
+ } else {
+ s << m_moduleDoc.value();
+ }
+}
+
+bool DocGenerator::prepareGeneration(const QMap<QString, QString>& args)
+{
+ ShibokenGenerator::prepareGeneration(args);
+ m_libSourceDir = args.value("library-source-dir");
+ setOutputDirectory(args.value("documentation-out-dir"));
+ m_docDataDir = args.value("documentation-data-dir");
+ m_codeSnippetDir = args.value("documentation-code-snippets-dir", m_libSourceDir);
+
+ 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 {
+ QtDocParser docParser;
+ docParser.setPackageName(packageName());
+ docParser.setDocumentationDataDirectory(m_docDataDir);
+ docParser.setLibrarySourceDirectory(m_libSourceDir);
+ foreach(AbstractMetaClass* cppClass, classes()) {
+ docParser.fillDocumentation(cppClass);
+ }
+ m_moduleDoc = docParser.retrieveModuleDocumentation();
+ return true;
+ }
+}
+
+
+QMap<QString, QString> DocGenerator::options() const
+{
+ QMap<QString, QString> options;
+ options.insert("library-source-dir", "Directory where library source code is located");
+ options.insert("documentation-out-dir", "The directory where the generated documentation files will be written");
+ 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");
+ return options;
+}
+
diff --git a/docgenerator.h b/docgenerator.h
new file mode 100644
index 00000000..6298f41c
--- /dev/null
+++ b/docgenerator.h
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 DOCGENERATOR_H
+#define DOCGENERATOR_H
+
+#include "shibokengenerator.h"
+#include <QtCore/QStack>
+
+class QXmlStreamReader;
+class DocGenerator;
+
+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(DocGenerator* generator, const QString& doc, const QString& context = QString());
+
+ QString result() const
+ {
+ return m_result;
+ }
+
+private:
+ 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;
+ DocGenerator* m_generator;
+ bool m_insideBold;
+ bool m_insideItalic;
+ QString m_lastTagName;
+ QString m_opened_anchor;
+
+ QString readFromLocation(QString& location, QString& identifier);
+ 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 DocGenerator : public ShibokenGenerator
+{
+public:
+ virtual GeneratorType type() const
+ {
+ return DocumentationType;
+ }
+
+ QString libSourceDir() const
+ {
+ return m_libSourceDir;
+ }
+
+ virtual bool prepareGeneration(const QMap<QString, QString>& args);
+
+ const char* name() const
+ {
+ return "DocGenerator";
+ }
+
+ QMap<QString, QString> options() const;
+
+ QString codeSnippetDir() const
+ {
+ return m_codeSnippetDir;
+ }
+
+protected:
+ QString fileNameForClass(const AbstractMetaClass* cppClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* cppClass);
+ void finishGeneration();
+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 writeFunctionBrief(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *cppFunction);
+ 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 &se, const QString &content, const AbstractMetaClass *cppClass);
+ 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);
+ void 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 parseFunctionDeclaration(const QString &data, const AbstractMetaClass *cppClass);
+ QString translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass);
+
+ QString m_docDataDir;
+ QString m_libSourceDir;
+ QString m_codeSnippetDir;
+ QStringList m_functionList;
+ Documentation m_moduleDoc;
+};
+
+#endif // DOCGENERATOR_H
diff --git a/headergenerator.cpp b/headergenerator.cpp
new file mode 100644
index 00000000..fe4de388
--- /dev/null
+++ b/headergenerator.cpp
@@ -0,0 +1,412 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 "headergenerator.h"
+#include <apiextractor/reporthandler.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+
+static Indentor INDENT;
+
+QString HeaderGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const
+{
+ return metaClass->qualifiedCppName().toLower() + QLatin1String("_wrapper.h");
+}
+
+void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
+{
+ s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)";
+ s << " : " << metaClass->qualifiedCppName() << "(self)" << endl;
+ s << INDENT << "{" << endl;
+ s << INDENT << "}" << endl << endl;
+}
+
+void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ ReportHandler::debugSparse("Generating header for " + metaClass->fullName());
+ Indentation indent(INDENT);
+
+ // write license comment
+ s << licenseComment();
+
+ QString wrapperName = HeaderGenerator::wrapperName(metaClass);
+
+ // Header
+ s << "#ifndef " << wrapperName.toUpper() << "_H" << endl;
+ s << "#define " << wrapperName.toUpper() << "_H" << endl<< endl;
+
+ if (!metaClass->isNamespace()) {
+ s << "// The mother of all C++ binding hacks!" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ s << "#include <shiboken.h>" << endl << endl;
+
+ //Includes
+ if (metaClass->typeEntry()->include().isValid())
+ s << metaClass->typeEntry()->include().toString() << endl << endl;
+
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(),
+ CodeSnip::Declaration, TypeSystem::NativeCode);
+
+ if (!metaClass->isNamespace()) {
+ bool createWrapper = canCreateWrapperFor(metaClass);
+
+ /*
+ * BOTOWTI (Beast of The Old World to be Investigated)
+ // detect the held type
+ QString held_type = metaClass->typeEntry()->heldTypeValue();
+ if (held_type.isEmpty() && createWrapper) {
+ held_type = "qptr";
+ }
+
+ if (!held_type.isEmpty()) {
+ s << "// held type forward decalration" << endl;
+ s << "template<typename T> class " << held_type << ';' << endl;
+ }
+ */
+
+ // Class
+ s << "class SHIBOKEN_LOCAL " << wrapperName;
+ if (createWrapper)
+ s << " : public " << metaClass->qualifiedCppName();
+
+ s << endl << '{' << endl << "public:" << endl;
+
+ if (metaClass->hasCloneOperator())
+ writeCopyCtor(s, metaClass);
+
+ foreach (AbstractMetaFunction *func, filterFunctions(metaClass))
+ writeFunction(s, func);
+
+ if (createWrapper) {
+ //destructor
+ s << INDENT << "~" << wrapperName << "();" << endl;
+
+ if (metaClass->isQObject() && (metaClass->name() != "QObject"))
+ s << INDENT << "using QObject::parent;" << endl;
+ }
+
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(),
+ CodeSnip::PrototypeInitialization, TypeSystem::NativeCode);
+
+ s << "};" << endl << endl;
+ }
+
+ s << "#endif // " << wrapperName.toUpper() << "_H" << endl << endl;
+}
+
+void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* func) const
+{
+ // pure virtual functions need a default implementation
+ if (func->isPrivate() || (func->isModifiedRemoved() && !func->isAbstract()))
+ return;
+
+ // do not write copy ctors here.
+ if (func->isCopyConstructor())
+ return;
+
+ if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
+ s << INDENT << functionSignature(func) << ';' << endl;
+
+ // TODO: when modified an abstract method ceases to be virtual but stays abstract
+ //if (func->isModifiedRemoved() && func->isAbstract()) {
+ //}
+
+ // TODO: APIExtractor: strange that something that is abstract couldn't be considered virtual too.
+ if (func->isVirtual() && !func->isAbstract() && !func->isConstructor() &&
+ !func->ownerClass()->hasPrivateDestructor() &&
+ func->implementingClass() == func->ownerClass()) {
+ writeVirtualDispatcher(s, func);
+ }
+ }
+}
+
+void HeaderGenerator::writeVirtualDispatcher(QTextStream& s, const AbstractMetaFunction* func) const
+{
+ QString returnKeyword = func->type() ? QLatin1String("return ") : QString();
+ s << INDENT << "static " << signatureForDefaultVirtualMethod(func, "", "_dispatcher") << " {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << returnKeyword;
+ if (func->isModifiedRemoved() && func->isAbstract()) {
+ if (func->type()
+ && (func->type()->isObject()
+ || func->type()->isQObject()
+ || func->type()->name() == "void"))
+ s << "0";
+ else
+ s << functionReturnType(func) << "()";
+ } else {
+ s << "self." << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func);
+ }
+ s << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void HeaderGenerator::writeTypeCheckMacro(QTextStream& s, const TypeEntry* type)
+{
+ QString pyTypeName = cpythonTypeName(type);
+ QString checkFunction = cpythonCheckFunction(type);
+ s << "PyAPI_DATA(PyTypeObject) " << pyTypeName << ';' << endl;
+ s << "#define " << checkFunction << "(op) PyObject_TypeCheck(op, &";
+ s << pyTypeName << ')' << endl;
+ s << "#define " << checkFunction << "Exact(op) ((op)->ob_type == &";
+ s << pyTypeName << ')' << endl;
+}
+
+void HeaderGenerator::writeTypeConverter(QTextStream& s, const TypeEntry* type)
+{
+ QString pyTypeName = cpythonTypeName(type);
+ QString checkFunction = cpythonCheckFunction(type);
+ QString cppName = type->name();
+ if (type->isObject())
+ cppName.append('*');
+
+ s << "template<>" << endl;
+ s << "struct Converter< " << cppName << " >" << endl << '{' << endl;
+
+ s << INDENT << "static PyObject* toPython(ValueHolder< ";
+ s << cppName << " > cppobj)" << endl << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* pyobj;" << endl;
+
+ if (!type->isEnum()) {
+ s << INDENT << "ValueHolder<void*> holder((void*) ";
+ if (type->isValue())
+ s << "new " << cppName << "(cppobj.value)";
+ else
+ s << "cppobj.value";
+ s << ");" << endl;
+ }
+
+ s << INDENT << "pyobj = ";
+
+ if (type->isEnum()) {
+ s << "Shiboken::PyEnumObject_New(&" << pyTypeName << ',' << endl;
+ s << INDENT << INDENT << "\"ReturnedValue\", (long) cppobj.value);" << endl;
+ } else {
+ QString newWrapper = QString("Shiboken::PyBaseWrapper_New(&")
+ + pyTypeName + ", &" + pyTypeName
+ + ", holder.value);";
+ if (type->isValue()) {
+ s << newWrapper << endl;
+ } else {
+ s << "Shiboken::Converter<void*>::toPython(holder);" << endl;
+ s << INDENT << "if (!pyobj)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "pyobj = " << newWrapper << endl;
+ }
+ }
+ }
+
+ s << INDENT << "return pyobj;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ s << INDENT << "static inline " << cppName << " toCpp(PyObject* pyobj)" << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+
+ if (type->isValue()) {
+ AbstractMetaFunctionList implicitConverters;
+ if (type->isValue()) {
+ const AbstractMetaClass* metaClass = classes().findClass(type->qualifiedCppName());
+ if (metaClass)
+ implicitConverters = metaClass->implicitConversions();
+ }
+ bool firstImplicitIf = true;
+ foreach (const AbstractMetaFunction* ctor, implicitConverters) {
+ const AbstractMetaType* argType = ctor->arguments().first()->type();
+ s << INDENT;
+ if (firstImplicitIf)
+ firstImplicitIf = false;
+ else
+ s << "else ";
+ s << "if (" << cpythonCheckFunction(argType) << "(pyobj))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << cppName;
+ s << "(Converter< " << argType->cppSignature() << " >::toCpp(pyobj));" << endl;
+ }
+ }
+ }
+
+ s << INDENT << "return ";
+ if (type->isEnum()) {
+ s << '(' << type->qualifiedCppName() << ") ((Shiboken::PyEnumObject*)pyobj)->ob_ival";
+ } else {
+ if (type->isValue())
+ s << '*';
+ s << "((" << cppName;
+ if (type->isValue())
+ s << '*';
+ s << ") ((Shiboken::PyBaseWrapper*)pyobj)->cptr)";
+ }
+ s << ';' << endl;
+ }
+ s << INDENT << '}' << endl << "};" << endl;
+}
+
+void HeaderGenerator::finishGeneration()
+{
+ // Generate the main header for this module.
+ // This header should be included by binding modules
+ // extendind on top of this one.
+ QString classIncludes;
+ QTextStream s_cin(&classIncludes);
+ QSet<QString> enumIncludes;
+ QString pythonTypeStuff;
+ QTextStream s_pts(&pythonTypeStuff);
+ QString converters;
+ QTextStream s_c(&converters);
+
+ Indentation indent(INDENT);
+
+ s_pts << endl << "// Global enums" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums()) {
+ QString incFile = cppEnum->includeFile().split(QDir::separator()).takeLast();
+ if (!incFile.isEmpty() && !classIncludes.contains(QString("<%1>").arg(incFile)))
+ enumIncludes << incFile;
+ writeTypeCheckMacro(s_pts, cppEnum->typeEntry());
+ s_pts << endl;
+ writeTypeConverter(s_c, cppEnum->typeEntry());
+ s_c << endl;
+ }
+
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ const TypeEntry* classType = metaClass->typeEntry();
+ if (!shouldGenerate(metaClass) || metaClass->enclosingClass() ||
+ !(classType->isObject() || classType->isValue() || classType->isNamespace()))
+ continue;
+
+ if (m_packageName.isEmpty())
+ m_packageName = metaClass->package();
+
+ //Includes
+ if (metaClass->typeEntry()->include().isValid())
+ s_cin << metaClass->typeEntry()->include().toString() << endl;
+
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) {
+ if (shouldGenerate(innerClass))
+ s_cin << innerClass->typeEntry()->include().toString() << endl;
+ }
+
+ foreach (const AbstractMetaEnum* cppEnum, metaClass->enums()) {
+ writeTypeCheckMacro(s_pts, cppEnum->typeEntry());
+ s_pts << endl;
+ writeTypeConverter(s_c, cppEnum->typeEntry());
+ s_c << endl;
+ }
+
+ if (!metaClass->isNamespace()) {
+ s_pts << "PyAPI_FUNC(PyObject*) " << cpythonBaseName(metaClass->typeEntry());
+ s_pts << "_New(PyTypeObject* type, PyObject* args, PyObject* kwds);" << endl;
+ writeTypeCheckMacro(s_pts, classType);
+ s_pts << "#define Py" << metaClass->name() << "_cptr(pyobj) ((";
+ s_pts << metaClass->name() << "*)PyBaseWrapper_cptr(pyobj))" << endl << endl;
+ writeTypeConverter(s_c, classType);
+ s_c << endl;
+ }
+ }
+
+ QString moduleHeaderFileName(outputDirectory() + QDir::separator()
+ + subDirectoryForPackage(m_packageName));
+ moduleHeaderFileName += QDir::separator() + moduleName().toLower() + "_python.h";
+
+ QString includeShield = moduleName().toUpper() + "_PYTHON_H";
+
+ QFile file(moduleHeaderFileName);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl << endl;
+
+ s << "#ifndef " << includeShield << endl;
+ s << "#define " << includeShield << endl<< endl;
+
+ s << "#include <Python.h>" << endl;
+ s << "#include <conversions.h>" << endl;
+ s << "#include <basewrapper.h>" << endl;
+ s << "#include <bindingmanager.h>" << endl << endl;
+
+ s << "// Class Includes" << endl;
+ s << classIncludes << endl;
+
+ if (!enumIncludes.isEmpty()) {
+ s << "// Enum Includes" << endl;
+ foreach (const QString& include, enumIncludes)
+ s << "#include <" << include << ">" << endl;
+ s << endl;
+ }
+
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes" << endl;
+ foreach (const ContainerTypeEntry* ctype, containerTypes()) {
+ if (ctype->include().isValid())
+ s << ctype->include().toString() << endl;
+ }
+ s << endl;
+ }
+
+ s << "extern \"C\"" << endl << '{' << endl << endl;
+ s << pythonTypeStuff << endl;
+ s << "} // extern \"C\"" << endl << endl;
+
+ s << "namespace Shiboken" << endl << '{' << endl << endl;
+
+ s << "// User defined converters --------------------------------------------" << endl;
+
+ foreach (const PrimitiveTypeEntry* ptype, primitiveTypes()) {
+ if (!ptype->codeSnips().isEmpty()) {
+ foreach (CodeSnip snip, ptype->codeSnips())
+ s << snip.code();
+ }
+ }
+
+ foreach (const ContainerTypeEntry* ctype, containerTypes()) {
+ if (!ctype->codeSnips().isEmpty()) {
+ foreach (CodeSnip snip, ctype->codeSnips())
+ s << snip.code();
+ }
+ }
+
+ s << "// Generated converters -----------------------------------------------" << endl << endl;
+
+ s << converters << endl;
+
+ s << "} // namespace Shiboken" << endl << endl;
+
+ s << "#endif // " << includeShield << endl << endl;
+ }
+}
diff --git a/headergenerator.h b/headergenerator.h
new file mode 100644
index 00000000..32c17bef
--- /dev/null
+++ b/headergenerator.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 HEADERGENERATOR_H
+#define HEADERGENERATOR_H
+
+#include "shibokengenerator.h"
+
+/**
+ * The HeaderGenerator generate the declarations of C++ bindings classes.
+ */
+class HeaderGenerator : public ShibokenGenerator
+{
+protected:
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration();
+private:
+ void writeCopyCtor(QTextStream &s, const AbstractMetaClass* metaClass) const;
+ void writeFunction(QTextStream& s, const AbstractMetaFunction* func) const;
+ void writePureVirtualEmptyImpl(QTextStream& , const AbstractMetaFunction* func) const;
+ void writeDefaultImplementation(QTextStream& s, const AbstractMetaFunction* func) const;
+ void writeVirtualDispatcher(QTextStream &s, const AbstractMetaFunction *func) const;
+ void writeTypeCheckMacro(QTextStream& s, const TypeEntry* type);
+ void writeTypeConverter(QTextStream& s, const TypeEntry* type);
+};
+
+#endif // HEADERGENERATOR_H
+
diff --git a/libshiboken/CMakeLists.txt b/libshiboken/CMakeLists.txt
new file mode 100644
index 00000000..8471fad8
--- /dev/null
+++ b/libshiboken/CMakeLists.txt
@@ -0,0 +1,37 @@
+project(libshiboken)
+
+find_package(PythonLibs REQUIRED)
+
+set(libshiboken_VERSION 0.1)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/FindShiboken.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/FindShiboken.cmake @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shiboken.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/shiboken.pc @ONLY)
+
+set(libshiboken_SRC
+basewrapper.cpp
+containers.cpp
+helper.cpp
+pyenum.cpp
+bindingmanager.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${PYTHON_INCLUDE_PATH})
+add_library(libshiboken SHARED ${libshiboken_SRC})
+set_property(TARGET libshiboken PROPERTY PREFIX "")
+target_link_libraries(libshiboken
+ ${PYTHON_LIBRARIES}
+ -lutil)
+
+install(DIRECTORY . DESTINATION include/shiboken
+ FILES_MATCHING PATTERN "*.h"
+ PATTERN ".git" EXCLUDE
+ )
+install(TARGETS libshiboken DESTINATION lib)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindShiboken.cmake
+ DESTINATION share/cmake-2.6/Modules)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/shiboken.pc
+ DESTINATION lib/pkgconfig)
+
diff --git a/libshiboken/FindShiboken.cmake.in b/libshiboken/FindShiboken.cmake.in
new file mode 100644
index 00000000..e63310dc
--- /dev/null
+++ b/libshiboken/FindShiboken.cmake.in
@@ -0,0 +1,13 @@
+# - try to find Shiboken
+# SHIBOKEN_INCLUDE_DIR - Directories to include to use Shiboken
+# SHIBOKEN_LIBRARIES - Files to link against to use Shiboken
+# SHIBOKEN_FOUND - Shiboken was found
+
+find_path(SHIBOKEN_INCLUDE_DIR shiboken.h @CMAKE_INSTALL_PREFIX@/include/shiboken)
+find_library(SHIBOKEN_LIBRARY shiboken @CMAKE_INSTALL_PREFIX@/lib)
+
+set(SHIBOKEN_FOUND "NO")
+if(SHIBOKEN_LIBRARY AND SHIBOKEN_INCLUDE_DIR)
+ set(SHIBOKEN_FOUND "YES")
+endif(SHIBOKEN_LIBRARY AND SHIBOKEN_INCLUDE_DIR)
+
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
new file mode 100644
index 00000000..d2c5101c
--- /dev/null
+++ b/libshiboken/basewrapper.cpp
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "basewrapper.h"
+#include "bindingmanager.h"
+
+namespace Shiboken
+{
+
+PyObject*
+PyBaseWrapper_New(PyTypeObject* instanceType, PyTypeObject* baseWrapperType, void* cptr, uint hasOwnership)
+{
+ if (!cptr)
+ return 0;
+
+ PyObject *self = instanceType->tp_alloc(instanceType, 0);
+ ((Shiboken::PyBaseWrapper*)self)->baseWrapperType = baseWrapperType;
+ ((Shiboken::PyBaseWrapper*)self)->cptr = cptr;
+ ((Shiboken::PyBaseWrapper*)self)->hasOwnership = hasOwnership;
+ ((Shiboken::PyBaseWrapper*)self)->validCppObject = 1;
+ BindingManager::instance().assignWrapper(self, cptr);
+ return self;
+}
+
+} // namespace Shiboken
diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
new file mode 100644
index 00000000..201851cc
--- /dev/null
+++ b/libshiboken/basewrapper.h
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 BASEWRAPPER_H
+#define BASEWRAPPER_H
+
+#include <Python.h>
+
+namespace Shiboken
+{
+
+extern "C"
+{
+
+struct PyBaseWrapper
+{
+ PyObject_HEAD
+ PyTypeObject* baseWrapperType;
+ void* cptr;
+ uint hasOwnership : 1;
+ uint validCppObject : 1;
+};
+
+} // extern "C"
+
+#define PyBaseWrapper_Check(op) PyObject_TypeCheck(op, &PyBaseWrapper_Type)
+#define PyBaseWrapper_CheckExact(op) ((op)->ob_type == &PyBaseWrapper_Type)
+
+#define PyBaseWrapper_cptr(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->cptr)
+#define PyBaseWrapper_setCptr(pyobj,c) (((Shiboken::PyBaseWrapper*)pyobj)->cptr = c)
+#define PyBaseWrapper_hasOwnership(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->hasOwnership)
+#define PyBaseWrapper_setOwnership(pyobj,o) (((Shiboken::PyBaseWrapper*)pyobj)->hasOwnership = o)
+#define PyBaseWrapper_validCppObject(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->validCppObject)
+#define PyBaseWrapper_setValidCppObject(pyobj,v) (((Shiboken::PyBaseWrapper*)pyobj)->validCppObject = v)
+
+PyAPI_FUNC(PyObject*)
+PyBaseWrapper_New(PyTypeObject *instanceType, PyTypeObject *baseWrapperType,
+ void *cptr, uint hasOwnership = 1);
+
+inline bool
+cppObjectIsValid(PyBaseWrapper* self)
+{
+ if (self->validCppObject)
+ return true;
+ PyErr_SetString(PyExc_RuntimeError, "internal C++ object already deleted.");
+ return false;
+}
+
+template <typename T>
+PyAPI_FUNC(void)
+PyBaseWrapper_Dealloc(PyObject* self)
+{
+ if (PyBaseWrapper_hasOwnership(self)) {
+ delete ((T*)PyBaseWrapper_cptr(self));
+ }
+ Py_TYPE(((PyBaseWrapper*)self))->tp_free((PyObject*)self);
+}
+
+} // namespace Shiboken
+
+#endif // BASEWRAPPER_H
diff --git a/libshiboken/bindingmanager.cpp b/libshiboken/bindingmanager.cpp
new file mode 100644
index 00000000..c81ad07b
--- /dev/null
+++ b/libshiboken/bindingmanager.cpp
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "bindingmanager.h"
+
+namespace Shiboken
+{
+
+BindingManager& BindingManager::instance() {
+ static BindingManager singleton;
+ return singleton;
+}
+
+bool BindingManager::hasWrapper(void* cptr)
+{
+ return m_wrapperMapper.count(cptr);
+}
+
+void BindingManager::assignWrapper(PyObject* wrapper, void* cptr)
+{
+ std::map<void*, PyObject*>::iterator iter = m_wrapperMapper.find(cptr);
+ if (iter == m_wrapperMapper.end())
+ m_wrapperMapper.insert(std::pair<void*, PyObject*>(cptr, wrapper));
+ else
+ iter->second = wrapper;
+}
+
+void BindingManager::releaseWrapper(void *cptr)
+{
+ std::map<void*, PyObject*>::iterator iter = m_wrapperMapper.find(cptr);
+ if (iter != m_wrapperMapper.end())
+ m_wrapperMapper.erase(iter);
+}
+
+inline void BindingManager::releaseWrapper(PyObject* wrapper)
+{
+ releaseWrapper(PyBaseWrapper_cptr(wrapper));
+}
+
+PyObject* BindingManager::retrieveWrapper(void* cptr)
+{
+ std::map<void*, PyObject*>::iterator iter = m_wrapperMapper.find(cptr);
+ if (iter == m_wrapperMapper.end())
+ return 0;
+ return iter->second;
+}
+
+PyObject* BindingManager::getOverride(void* cptr, const char* methodName)
+{
+ PyObject* wrapper = retrieveWrapper(cptr);
+
+ fprintf(stderr, "[%s:%d] method: %s, wrapper: %s\n", __FUNCTION__, __LINE__, methodName, wrapper->ob_type->tp_name);
+
+ if (wrapper) {
+ PyTypeObject* baseWrapperType = ((Shiboken::PyBaseWrapper*)wrapper)->baseWrapperType;
+ fprintf(stderr, "[%s:%d] basewrapper: %s\n", __FUNCTION__, __LINE__, baseWrapperType->tp_name);
+ PyObject* method = PyObject_GetAttrString(wrapper, const_cast<char*>(methodName));
+ if (method != 0) {
+ PyObject* defaultMethod = 0;
+ if (PyMethod_Check(method) &&
+ ((PyMethodObject*) method)->im_self == wrapper &&
+ baseWrapperType->tp_dict != 0) {
+ defaultMethod = PyDict_GetItemString(baseWrapperType->tp_dict, const_cast<char*>(methodName));
+ }
+
+ if (((PyMethodObject*)method)->im_func != defaultMethod)
+ return method;
+
+ Py_DECREF(method);
+ }
+ }
+
+ return 0;
+}
+
+} // namespace Shiboken
diff --git a/libshiboken/bindingmanager.h b/libshiboken/bindingmanager.h
new file mode 100644
index 00000000..bd447215
--- /dev/null
+++ b/libshiboken/bindingmanager.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 BINDINGMANAGER_H
+#define BINDINGMANAGER_H
+
+#include <map>
+#include <Python.h>
+#include <basewrapper.h>
+
+namespace Shiboken
+{
+
+class BindingManager
+{
+public:
+ static BindingManager& instance();
+
+ bool hasWrapper(void *cptr);
+ void assignWrapper(PyObject* wrapper, void* cptr);
+ void releaseWrapper(void* cptr);
+ inline void releaseWrapper(PyObject* wrapper);
+ PyObject* retrieveWrapper(void* cptr);
+ PyObject* getOverride(void* cptr, const char* methodName);
+
+private:
+ BindingManager() {}
+ BindingManager(const BindingManager&);
+
+ std::map<void*, PyObject*> m_wrapperMapper;
+};
+
+} // namespace Shiboken
+
+#endif // BINDINGMANAGER_H
diff --git a/libshiboken/containers.cpp b/libshiboken/containers.cpp
new file mode 100644
index 00000000..ce756871
--- /dev/null
+++ b/libshiboken/containers.cpp
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "containers.h"
+
+namespace Shiboken
+{
+
+
+} // namespace Shiboken
diff --git a/libshiboken/containers.h b/libshiboken/containers.h
new file mode 100644
index 00000000..85cadb0d
--- /dev/null
+++ b/libshiboken/containers.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 CONTAINERS_H
+#define CONTAINERS_H
+
+#include <Python.h>
+
+namespace Shiboken
+{
+
+
+} // namespace Shiboken
+
+#endif // CONTAINERS_H
+
diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h
new file mode 100644
index 00000000..cbd4ee55
--- /dev/null
+++ b/libshiboken/conversions.h
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 CONVERSIONS_H
+#define CONVERSIONS_H
+
+#include <Python.h>
+#include <basewrapper.h>
+#include <bindingmanager.h>
+
+namespace Shiboken
+{
+
+template <typename T>
+struct ValueHolder
+{
+ explicit ValueHolder(T val) : value(val) {}
+ T value;
+};
+
+template <typename T>
+struct Converter
+{
+ static PyObject* toPython(ValueHolder<T> cppobj) {
+ return 0;
+ }
+ static T toCpp(PyObject* pyobj) {
+ return T();
+ }
+};
+
+// Object Types ---------------------------------------------------------------
+template <>
+struct Converter<void*>
+{
+ static PyObject* toPython(ValueHolder<void*> cppobj)
+ {
+ PyObject* obj = BindingManager::instance().retrieveWrapper(cppobj.value);
+ Py_XINCREF(obj);
+ return obj;
+ }
+ static void* toCpp(PyObject* pyobj)
+ {
+ return ((Shiboken::PyBaseWrapper*) pyobj)->cptr;
+ }
+};
+
+// Primitive Types ------------------------------------------------------------
+template <>
+struct Converter<bool>
+{
+ static PyObject* toPython(ValueHolder<bool> holder)
+ {
+ return PyBool_FromLong(holder.value);
+ }
+ static bool toCpp(PyObject* pyobj)
+ {
+ return pyobj == Py_True;
+ }
+};
+
+template <typename PyIntEquiv>
+struct Converter_PyInt
+{
+ static PyObject* toPython(ValueHolder<PyIntEquiv> holder)
+ {
+ return PyInt_FromLong((long) holder.value);
+ }
+ static PyIntEquiv toCpp(PyObject* pyobj)
+ {
+ if (PyFloat_Check(pyobj))
+ return (PyIntEquiv) PyFloat_AS_DOUBLE(pyobj);
+ return (PyIntEquiv) PyInt_AS_LONG(pyobj);
+ }
+};
+
+template <> struct Converter<char> : Converter_PyInt<char> {};
+template <> struct Converter<unsigned char> : Converter_PyInt<unsigned char> {};
+template <> struct Converter<int> : Converter_PyInt<int> {};
+template <> struct Converter<unsigned int> : Converter_PyInt<unsigned int> {};
+template <> struct Converter<short> : Converter_PyInt<short> {};
+template <> struct Converter<unsigned short> : Converter_PyInt<unsigned short> {};
+template <> struct Converter<long> : Converter_PyInt<long> {};
+
+template <>
+struct Converter<unsigned long>
+{
+ static PyObject* toPython(ValueHolder<unsigned long> holder)
+ {
+ return PyLong_FromUnsignedLong(holder.value);
+ }
+ static unsigned long toCpp(PyObject* pyobj)
+ {
+ return (unsigned long) PyLong_AsUnsignedLong(pyobj);
+ }
+};
+
+template <>
+struct Converter<PY_LONG_LONG>
+{
+ static PyObject* toPython(ValueHolder<PY_LONG_LONG> holder)
+ {
+ return PyLong_FromLongLong(holder.value);
+ }
+ static PY_LONG_LONG toCpp(PyObject* pyobj)
+ {
+ return (PY_LONG_LONG) PyLong_AsLongLong(pyobj);
+ }
+};
+
+template <>
+struct Converter<unsigned PY_LONG_LONG>
+{
+ static PyObject* toPython(ValueHolder<unsigned PY_LONG_LONG> holder)
+ {
+ return PyLong_FromUnsignedLongLong(holder.value);
+ }
+ static unsigned PY_LONG_LONG toCpp(PyObject* pyobj)
+ {
+ return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(pyobj);
+ }
+};
+
+template <typename PyFloatEquiv>
+struct Converter_PyFloat
+{
+ static PyObject* toPython(ValueHolder<PyFloatEquiv> holder)
+ {
+ return PyFloat_FromDouble((double) holder.value);
+ }
+ static PyFloatEquiv toCpp(PyObject* pyobj)
+ {
+ if (PyInt_Check(pyobj))
+ return (PyFloatEquiv) PyInt_AS_LONG(pyobj);
+ return (PyFloatEquiv) PyFloat_AS_DOUBLE(pyobj);
+ }
+};
+
+template <> struct Converter<float> : Converter_PyFloat<float> {};
+template <> struct Converter<double> : Converter_PyFloat<double> {};
+
+// C Sting Types --------------------------------------------------------------
+
+template <>
+struct Converter<const char*>
+{
+ static PyObject* toPython(ValueHolder<const char*> holder)
+ {
+ return PyString_FromString(holder.value);
+ }
+ static const char* toCpp(PyObject* pyobj)
+ {
+ return PyString_AsString(pyobj);
+ }
+};
+
+} // namespace Shiboken
+
+#endif // CONVERSIONS_H
+
diff --git a/libshiboken/helper.cpp b/libshiboken/helper.cpp
new file mode 100644
index 00000000..eb213ed3
--- /dev/null
+++ b/libshiboken/helper.cpp
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "helper.h"
+
+namespace Shiboken
+{
+
+int
+PySequence_to_argc_argv(_object* argList, char** argv[])
+{
+ if (!PySequence_Check(argList))
+ return -1;
+
+ int argc = (int) PySequence_Size(argList);
+ (*argv) = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ PyObject* item = PySequence_GetItem(argList, i);
+ if (!PyString_Check(item)) {
+ argc = -1;
+ for (int j = 0; j < i; ++j)
+ delete (*argv)[j];
+ Py_DECREF(item);
+ return -1;
+ }
+ char *origArg = PyString_AS_STRING(item);
+ int size = strlen(origArg);
+ (*argv)[i] = new char[size+1];
+ (*argv)[i] = strcpy((*argv)[i], origArg);
+ Py_DECREF(item);
+ }
+
+ return argc;
+}
+
+} // namespace Shiboken
diff --git a/libshiboken/helper.h b/libshiboken/helper.h
new file mode 100644
index 00000000..588f0c3f
--- /dev/null
+++ b/libshiboken/helper.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 HELPER_H
+#define HELPER_H
+
+#include <Python.h>
+
+namespace Shiboken
+{
+
+// Generic helper definitions for shared library support
+#if defined _WIN32 || defined __CYGWIN__
+#define SHIBOKEN_HELPER_DLL_IMPORT __declspec(dllimport)
+#define SHIBOKEN_HELPER_DLL_EXPORT __declspec(dllexport)
+#define SHIBOKEN_HELPER_DLL_LOCAL
+#else
+#if __GNUC__ >= 4
+#define SHIBOKEN_HELPER_DLL_IMPORT __attribute__ ((visibility("default")))
+#define SHIBOKEN_HELPER_DLL_EXPORT __attribute__ ((visibility("default")))
+#define SHIBOKEN_HELPER_DLL_LOCAL __attribute__ ((visibility("internal")))
+#else
+#define SHIBOKEN_HELPER_DLL_IMPORT
+#define SHIBOKEN_HELPER_DLL_EXPORT
+#define SHIBOKEN_HELPER_DLL_LOCAL
+#endif
+#endif
+
+// Now we use the generic helper definitions above to define SHIBOKEN_API and SHIBOKEN_LOCAL.
+// SHIBOKEN_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
+// SHIBOKEN_LOCAL is used for non-api symbols.
+
+#define SHIBOKEN_API SHIBOKEN_HELPER_DLL_EXPORT
+#define SHIBOKEN_LOCAL SHIBOKEN_HELPER_DLL_LOCAL
+
+int PySequence_to_argc_argv(PyObject* argList, char** argv[]);
+
+} // namespace Shiboken
+
+#endif // HELPER_H
+
diff --git a/libshiboken/pyenum.cpp b/libshiboken/pyenum.cpp
new file mode 100644
index 00000000..d60d0344
--- /dev/null
+++ b/libshiboken/pyenum.cpp
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "pyenum.h"
+
+namespace Shiboken
+{
+
+PyObject*
+PyEnumObject_New(PyTypeObject *type, PyObject* item_name, long item_value)
+{
+ PyEnumObject* enum_obj = (PyEnumObject*) type->tp_alloc(type, 0);
+ enum_obj->ob_name = item_name;
+ enum_obj->ob_ival = item_value;
+ return (PyObject*) enum_obj;
+}
+
+PyObject*
+PyEnumObject_New(PyTypeObject *type, const char* item_name, long item_value)
+{
+ PyObject* py_item_name = PyString_FromString(item_name);
+ PyObject* enum_obj = PyEnumObject_New(type, py_item_name, item_value);
+ if (!enum_obj) {
+ Py_DECREF(py_item_name);
+ return 0;
+ }
+ PyObject* values = PyDict_GetItemString(type->tp_dict, const_cast<char*>("values"));
+ if (!values) {
+ values = PyDict_New();
+ PyDict_SetItemString(type->tp_dict, const_cast<char*>("values"), values);
+ }
+ PyDict_SetItemString(values, item_name, enum_obj);
+ return enum_obj;
+}
+
+extern "C"
+{
+
+PyObject*
+PyEnumObject_NonExtensibleNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyErr_SetString(PyExc_TypeError, "this enum is not extensible");
+ return 0;
+}
+
+
+PyObject*
+PyEnumObject_repr(PyObject* self)
+{
+ return PyString_FromFormat("<enum-item %s.%s (%ld)>",
+ self->ob_type->tp_name,
+ PyString_AS_STRING(((PyEnumObject*)self)->ob_name),
+ ((PyEnumObject*)self)->ob_ival);
+}
+
+PyObject*
+PyEnumObject_name(PyObject* self)
+{
+ Py_INCREF(((PyEnumObject*)self)->ob_name);
+ return ((PyEnumObject*)self)->ob_name;
+}
+
+} // extern "C"
+
+} // namespace Shiboken
diff --git a/libshiboken/pyenum.h b/libshiboken/pyenum.h
new file mode 100644
index 00000000..6fb9f52e
--- /dev/null
+++ b/libshiboken/pyenum.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 PYENUM_H
+#define PYENUM_H
+
+#include <Python.h>
+
+namespace Shiboken
+{
+
+extern "C"
+{
+
+typedef struct {
+ PyObject_HEAD
+ long ob_ival;
+ PyObject* ob_name;
+} PyEnumObject;
+
+PyAPI_FUNC(PyObject*) PyEnumObject_repr(PyObject* self);
+PyAPI_FUNC(PyObject*) PyEnumObject_name(PyObject* self);
+PyAPI_FUNC(PyObject*) PyEnumObject_NonExtensibleNew(PyTypeObject* type, PyObject* args, PyObject* kwds);
+
+} // extern "C"
+
+PyObject* PyEnumObject_New(PyTypeObject *instanceType,
+ const char* item_name,
+ long item_value);
+PyObject* PyEnumObject_New(PyTypeObject *instanceType,
+ PyObject* item_name,
+ long item_value);
+
+} // namespace Shiboken
+
+#endif // PYENUM_H
+
diff --git a/libshiboken/shiboken.h b/libshiboken/shiboken.h
new file mode 100644
index 00000000..3f7e6781
--- /dev/null
+++ b/libshiboken/shiboken.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 SHIBOKEN_H
+#define SHIBOKEN_H
+
+#include <Python.h>
+#include <basewrapper.h>
+#include <containers.h>
+#include <conversions.h>
+#include <helper.h>
+#include <pyenum.h>
+#include <bindingmanager.h>
+
+#endif // SHIBOKEN_H
+
diff --git a/libshiboken/shiboken.pc.in b/libshiboken/shiboken.pc.in
new file mode 100644
index 00000000..f120f00d
--- /dev/null
+++ b/libshiboken/shiboken.pc.in
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_PREFIX@/lib
+includedir=@CMAKE_INSTALL_PREFIX@/include/shiboken
+generator_location=@CMAKE_INSTALL_PREFIX@/bin/shiboken
+
+Name: shiboken
+Description: support library for Python bindings created with Shiboken generator.
+Requires: Python
+Version: @libshiboken_VERSION@
+Libs: -L${libdir} -lpython
+Cflags: -I${includedir}
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 00000000..8700551f
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 <QtCore/QCoreApplication>
+#include <apiextractor/apiextractor.h>
+#include "headergenerator.h"
+#include "cppgenerator.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv); // needed by qxmlpatterns
+
+ ApiExtractor extractor(argc, argv);
+ extractor.addGenerator(new HeaderGenerator);
+ extractor.addGenerator(new CppGenerator);
+ return extractor.exec();
+}
+
diff --git a/polymorphicdata.cpp b/polymorphicdata.cpp
new file mode 100644
index 00000000..7d3a5b4c
--- /dev/null
+++ b/polymorphicdata.cpp
@@ -0,0 +1,386 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 <QtCore/QFile>
+#include "polymorphicdata.h"
+#include "shibokengenerator.h"
+
+// Prepare the information about polymorphic methods signatures
+PolymorphicData::PolymorphicData(const AbstractMetaFunctionList overloads)
+ : m_minArgs(256), m_maxArgs(0), m_argType(0),
+ m_argPos(-1), m_headPolymorphicData(this)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ m_overloads.append(func);
+ int argSize = func->arguments().size();
+ if (m_minArgs > argSize)
+ m_minArgs = argSize;
+ else if (m_maxArgs < argSize)
+ m_maxArgs = argSize;
+ PolymorphicData* currentPolymorphicData = this;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ currentPolymorphicData = currentPolymorphicData->addPolymorphicData(func, arg->type());
+ }
+ }
+
+ // Fix minArgs
+ if (minArgs() > maxArgs())
+ m_headPolymorphicData->m_minArgs = maxArgs();
+}
+
+PolymorphicData::PolymorphicData(PolymorphicData* headPolymorphicData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos)
+ : m_minArgs(256), m_maxArgs(0), m_argType(argType), m_argPos(argPos),
+ m_headPolymorphicData(headPolymorphicData)
+{
+ if (func)
+ this->addPolymorphic(func);
+}
+
+void PolymorphicData::addPolymorphic(const AbstractMetaFunction* func)
+{
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+
+ if (numArgs > m_headPolymorphicData->m_maxArgs)
+ m_headPolymorphicData->m_maxArgs = numArgs;
+
+ if (numArgs < m_headPolymorphicData->m_minArgs)
+ m_headPolymorphicData->m_minArgs = numArgs;
+
+ for (int i = 0; m_headPolymorphicData->m_minArgs > 0 && i < origNumArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ continue;
+ if (!func->arguments()[i]->defaultValueExpression().isEmpty()) {
+ int fixedArgIndex = i - removed;
+ if (fixedArgIndex < m_headPolymorphicData->m_minArgs)
+ m_headPolymorphicData->m_minArgs = fixedArgIndex;
+ }
+ }
+
+ m_overloads.append(func);
+}
+
+PolymorphicData* PolymorphicData::addPolymorphicData(const AbstractMetaFunction* func,
+ const AbstractMetaType* argType)
+{
+ PolymorphicData* polymorphicData = 0;
+ foreach (PolymorphicData* tmp, m_nextPolymorphicData) {
+ // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry?
+ if (tmp->m_argType->typeEntry() == argType->typeEntry()) {
+ tmp->addPolymorphic(func);
+ polymorphicData = tmp;
+ continue;
+ }
+ }
+
+ if (!polymorphicData) {
+ polymorphicData = new PolymorphicData(m_headPolymorphicData, func, argType, m_argPos + 1);
+ // The following code always put PyInt as the last element to be checked.
+ // This is useful to check the python argument as PyNumber instead of
+ // PyInt, but not getting in the way of other tipes of higher precision
+ // (e.g. PyFloat)
+ if (ShibokenGenerator::isPyInt(argType))
+ m_nextPolymorphicData.append(polymorphicData);
+ else
+ m_nextPolymorphicData.prepend(polymorphicData);
+ }
+
+ return polymorphicData;
+}
+
+const AbstractMetaFunction* PolymorphicData::referenceFunction() const
+{
+ return m_overloads.at(0);
+}
+
+const AbstractMetaArgument* PolymorphicData::argument(const AbstractMetaFunction* func) const
+{
+ if (isHeadPolymorphicData() || !m_overloads.contains(func))
+ return 0;
+
+ int argPos = 0;
+ int removed = 0;
+ for (int i = 0; argPos <= m_argPos; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ else
+ argPos++;
+ }
+
+ return func->arguments()[m_argPos + removed];
+}
+
+PolymorphicDataList PolymorphicData::polymorphicDataOnPosition(PolymorphicData* polyData, int argPos) const
+{
+ PolymorphicDataList polyDataList;
+ if (polyData->argPos() == argPos) {
+ polyDataList.append(polyData);
+ } else if (polyData->argPos() < argPos) {
+ foreach (PolymorphicData* pd, polyData->nextPolymorphicData())
+ polyDataList += polymorphicDataOnPosition(pd, argPos);
+ }
+ return polyDataList;
+}
+
+PolymorphicDataList PolymorphicData::polymorphicDataOnPosition(int argPos) const
+{
+ PolymorphicDataList polyDataList;
+ polyDataList += polymorphicDataOnPosition(m_headPolymorphicData, argPos);
+ return polyDataList;
+}
+
+bool PolymorphicData::nextArgumentHasDefaultValue() const
+{
+ foreach (PolymorphicData* polymorphicData, m_nextPolymorphicData) {
+ if (polymorphicData->hasDefaultValue())
+ return true;
+ }
+ return false;
+}
+
+bool PolymorphicData::isFinalOccurrence(const AbstractMetaFunction* func) const
+{
+ foreach (const PolymorphicData* pd, m_nextPolymorphicData) {
+ if (pd->overloads().contains(func))
+ return false;
+ }
+ return true;
+}
+
+bool PolymorphicData::hasDefaultValue() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (!func->arguments()[m_argPos]->defaultValueExpression().isEmpty())
+ return true;
+ }
+ return false;
+}
+
+QList<int> PolymorphicData::invalidArgumentLengths() const
+{
+ QSet<int> validArgLengths;
+ foreach (const AbstractMetaFunction* func, m_headPolymorphicData->m_overloads) {
+ validArgLengths << func->arguments().size();
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (!arg->defaultValueExpression().isEmpty())
+ validArgLengths << arg->argumentIndex();
+ }
+ }
+
+ QList<int> invalidArgLengths;
+ for (int i = minArgs() + 1; i < maxArgs(); i++) {
+ if (!validArgLengths.contains(i))
+ invalidArgLengths.append(i);
+ }
+
+ return invalidArgLengths;
+}
+
+int PolymorphicData::numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos)
+{
+ int removed = 0;
+ if (finalArgPos < 0)
+ finalArgPos = func->arguments().size();
+ for (int i = 0; i < finalArgPos; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ return removed;
+}
+
+QPair<int, int> PolymorphicData::getMinMaxArguments(const AbstractMetaFunctionList overloads)
+{
+ int minArgs = 10000;
+ int maxArgs = 0;
+ for (int i = 0; i < overloads.size(); i++) {
+ const AbstractMetaFunction* func = overloads[i];
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+ if (maxArgs < numArgs)
+ maxArgs = numArgs;
+ if (minArgs > numArgs)
+ minArgs = numArgs;
+ for (int j = 0; j < origNumArgs; j++) {
+ if (func->argumentRemoved(j + 1))
+ continue;
+ int fixedArgIndex = j - removed;
+ if (fixedArgIndex < minArgs && !func->arguments()[j]->defaultValueExpression().isEmpty())
+ minArgs = fixedArgIndex;
+ }
+ }
+ return QPair<int, int>(minArgs, maxArgs);
+}
+
+void PolymorphicData::dumpGraph(QString filename) const
+{
+ QFile file(filename);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+ s << dumpGraph(m_headPolymorphicData);
+ }
+}
+
+QString PolymorphicData::dumpGraph(const PolymorphicData* polyData) const
+{
+ if (!polyData)
+ return QString();
+
+ QString indent(4, ' ');
+ QString result;
+ QTextStream s(&result);
+ if (polyData->m_argPos == -1) {
+ const AbstractMetaFunction* rfunc = polyData->referenceFunction();
+ s << "digraph PolymorphicFunction {" << endl;
+ s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl;
+
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ foreach (const AbstractMetaFunction* func, polyData->overloads()) {
+ s << "f" << functionNumber(func) << " : ";
+ if (func->type())
+ s << func->type()->cppSignature().replace('<', "&lt;").replace('>', "&gt;");
+ else
+ s << "void";
+ s << ' ' << func->minimalSignature().replace('<', "&lt;").replace('>', "&gt;") << "\\l";
+ }
+ s << "\"];" << endl;
+
+ // Function box title
+ s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << rfunc->name().replace('<', "&lt;").replace('>', "&gt;") << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
+ if (rfunc->type())
+ s << rfunc->type()->cppSignature().replace('<', "&lt;").replace('>', "&gt;");
+ else
+ s << "void";
+ s << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ foreach (const AbstractMetaFunction* func, polyData->overloads()) {
+ if (func->typeReplaced(0).isEmpty())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << func->typeReplaced(0).replace('<', "&lt;").replace('>', "&gt;") << "</td></tr>";
+ }
+
+ // Minimum and maximum number of arguments
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << minArgs() << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << maxArgs() << "</td></tr>";
+
+ if (rfunc->ownerClass()) {
+ if (rfunc->implementingClass() != rfunc->ownerClass())
+ s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
+ if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
+ s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, polyData->overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ s << "</table>> ];" << endl;
+
+ foreach (const PolymorphicData* pd, polyData->nextPolymorphicData())
+ s << indent << '"' << rfunc->name() << "\" -> " << dumpGraph(pd);
+
+ s << "}" << endl;
+ } else {
+ QString argId = QString("arg_%1").arg((long)polyData);
+ s << argId << ';' << endl;
+
+ s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+
+ // Argument box title
+ s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
+ s << "<font color=\"white\" point-size=\"11\">arg #" << polyData->argPos() << "</font></td></tr>";
+
+ // Argument type information
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << polyData->argType()->cppSignature().replace("&", "&amp;") << "</td></tr>";
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, polyData->overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ // Show default values (original and modified) for various functions
+ foreach (const AbstractMetaFunction* func, polyData->overloads()) {
+ const AbstractMetaArgument* arg = polyData->argument(func);
+ if (!arg)
+ continue;
+ if (!arg->defaultValueExpression().isEmpty() ||
+ arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->defaultValueExpression() << "</td></tr>";
+ }
+ if (arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
+ }
+
+ s << "</table>>];" << endl;
+
+ foreach (const PolymorphicData* pd, polyData->nextPolymorphicData())
+ s << indent << argId << " -> " << dumpGraph(pd);
+ }
+ return result;
+}
+
+int PolymorphicData::functionNumber(const AbstractMetaFunction* func) const
+{
+ m_headPolymorphicData->m_overloads.indexOf(func);
+}
+
+PolymorphicData::~PolymorphicData()
+{
+ while (!m_nextPolymorphicData.isEmpty())
+ delete m_nextPolymorphicData.takeLast();
+}
diff --git a/polymorphicdata.h b/polymorphicdata.h
new file mode 100644
index 00000000..1e474190
--- /dev/null
+++ b/polymorphicdata.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 POLYMORPHICDATA_H
+#define POLYMORPHICDATA_H
+
+#include <apiextractor/abstractmetalang.h>
+#include <QtCore/QList>
+#include <QtCore/QBitArray>
+
+class PolymorphicData;
+typedef QList<PolymorphicData*> PolymorphicDataList;
+
+class PolymorphicData
+{
+public:
+ PolymorphicData(const AbstractMetaFunctionList overloads);
+
+ int minArgs() const { return m_headPolymorphicData->m_minArgs; }
+ int maxArgs() const { return m_headPolymorphicData->m_maxArgs; }
+ int argPos() const { return m_argPos; }
+
+ const AbstractMetaType* argType() const { return m_argType; }
+ const AbstractMetaFunction* referenceFunction() const;
+ const AbstractMetaArgument* argument(const AbstractMetaFunction* func) const;
+ PolymorphicDataList polymorphicDataOnPosition(int argPos) const;
+
+ bool isHeadPolymorphicData() const { return this == m_headPolymorphicData; }
+ bool hasDefaultValue() const;
+ bool nextArgumentHasDefaultValue() const;
+ bool isFinalOccurrence(const AbstractMetaFunction* func) const;
+
+ QList<const AbstractMetaFunction*> overloads() const { return m_overloads; }
+ PolymorphicDataList nextPolymorphicData() const { return m_nextPolymorphicData; }
+
+ QList<int> invalidArgumentLengths() const;
+
+ static int numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos = -1);
+ static QPair<int, int> getMinMaxArguments(const AbstractMetaFunctionList overloads);
+
+ void dumpGraph(QString filename) const;
+
+ ~PolymorphicData();
+
+private:
+ PolymorphicData(PolymorphicData* headPolymorphicData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos);
+
+ void addPolymorphic(const AbstractMetaFunction* func);
+ PolymorphicData* addPolymorphicData(const AbstractMetaFunction* func, const AbstractMetaType* argType);
+
+ QString dumpGraph(const PolymorphicData* polyData) const;
+ int functionNumber(const AbstractMetaFunction* func) const;
+ PolymorphicDataList polymorphicDataOnPosition(PolymorphicData* polyData, int argPos) const;
+
+ int m_minArgs;
+ int m_maxArgs;
+ int m_argPos;
+ const AbstractMetaType* m_argType;
+ QList<const AbstractMetaFunction*> m_overloads;
+
+ PolymorphicData* m_headPolymorphicData;
+ PolymorphicDataList m_nextPolymorphicData;
+};
+
+
+#endif // POLYMORPHICDATA_H
diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp
new file mode 100644
index 00000000..89b5e7b4
--- /dev/null
+++ b/shibokengenerator.cpp
@@ -0,0 +1,829 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 "shibokengenerator.h"
+#include <reporthandler.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+#define NULL_VALUE "NULL"
+#define COMMENT_LINE_WIDTH 77
+
+static Indentor INDENT;
+static void dumpFunction(AbstractMetaFunctionList lst);
+
+QHash<QString, QString> ShibokenGenerator::m_pythonPrimitiveTypeName = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_pythonOperators = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_formatUnits = QHash<QString, QString>();
+
+ShibokenGenerator::ShibokenGenerator() : Generator()
+{
+ if (m_pythonPrimitiveTypeName.isEmpty())
+ ShibokenGenerator::initPrimitiveTypesCorrespondences();
+}
+
+void ShibokenGenerator::initPrimitiveTypesCorrespondences()
+{
+ // Python primitive types names
+ m_pythonPrimitiveTypeName.clear();
+
+ // PyBool
+ m_pythonPrimitiveTypeName["bool"] = "PyBool";
+
+ // PyInt
+ m_pythonPrimitiveTypeName["char"] = "PyInt";
+ m_pythonPrimitiveTypeName["unsigned char"] = "PyInt";
+ m_pythonPrimitiveTypeName["int"] = "PyInt";
+ m_pythonPrimitiveTypeName["unsigned int"] = "PyInt";
+ m_pythonPrimitiveTypeName["short"] = "PyInt";
+ m_pythonPrimitiveTypeName["unsigned short"] = "PyInt";
+ m_pythonPrimitiveTypeName["long"] = "PyInt";
+
+ // PyFloat
+ m_pythonPrimitiveTypeName["double"] = "PyFloat";
+ m_pythonPrimitiveTypeName["float"] = "PyFloat";
+
+ // PyLong
+ m_pythonPrimitiveTypeName["unsigned long"] = "PyLong";
+ m_pythonPrimitiveTypeName["long long"] = "PyLong";
+ m_pythonPrimitiveTypeName["__int64"] = "PyLong";
+ m_pythonPrimitiveTypeName["unsigned long long"] = "PyLong";
+ m_pythonPrimitiveTypeName["unsigned __int64"] = "PyLong";
+
+ // Python operators
+ m_pythonOperators.clear();
+
+ // Arithmetic operators
+ m_pythonOperators["operator+"] = "add";
+ m_pythonOperators["operator-"] = "sub";
+ m_pythonOperators["operator*"] = "mul";
+ m_pythonOperators["operator/"] = "div";
+ m_pythonOperators["operator%"] = "mod";
+
+ // Inplace arithmetic operators
+ m_pythonOperators["operator+="] = "iadd";
+ m_pythonOperators["operator-="] = "isub";
+ m_pythonOperators["operator*="] = "imul";
+ m_pythonOperators["operator/="] = "idiv";
+ m_pythonOperators["operator%="] = "imod";
+
+ // Bitwise operators
+ m_pythonOperators["operator&"] = "and";
+ m_pythonOperators["operator^"] = "xor";
+ m_pythonOperators["operator|"] = "or";
+ m_pythonOperators["operator<<"] = "lshift";
+ m_pythonOperators["operator>>"] = "rshift";
+ m_pythonOperators["operator~"] = "invert";
+
+ // Inplace bitwise operators
+ m_pythonOperators["operator&="] = "iand";
+ m_pythonOperators["operator^="] = "ixor";
+ m_pythonOperators["operator|="] = "ior";
+ m_pythonOperators["operator<<="] = "ilshift";
+ m_pythonOperators["operator>>="] = "irshift";
+
+ // Comparison operators
+ m_pythonOperators["operator=="] = "eq";
+ m_pythonOperators["operator!="] = "ne";
+ m_pythonOperators["operator<"] = "lt";
+ m_pythonOperators["operator>"] = "gt";
+ m_pythonOperators["operator<="] = "le";
+ m_pythonOperators["operator>="] = "ge";
+
+ // Initialize format units for C++->Python->C++ conversion
+ m_formatUnits.clear();
+ m_formatUnits.insert("bool", "i");
+ m_formatUnits.insert("char", "b");
+ m_formatUnits.insert("unsigned char", "B");
+ m_formatUnits.insert("int", "i");
+ m_formatUnits.insert("unsigned int", "I");
+ m_formatUnits.insert("short", "h");
+ m_formatUnits.insert("unsigned short", "H");
+ m_formatUnits.insert("long", "l");
+ m_formatUnits.insert("unsigned long", "k");
+ m_formatUnits.insert("long long", "L");
+ m_formatUnits.insert("__int64", "L");
+ m_formatUnits.insert("unsigned long long", "K");
+ m_formatUnits.insert("unsigned __int64", "K");
+ m_formatUnits.insert("double", "d");
+ m_formatUnits.insert("float", "f");
+}
+
+FunctionModificationList ShibokenGenerator::functionModifications(const AbstractMetaFunction* func)
+{
+ FunctionModificationList mods;
+ const AbstractMetaClass *cls = func->ownerClass();
+ while (cls) {
+ mods += func->modifications(cls);
+ if (cls == cls->baseClass())
+ break;
+ cls = cls->baseClass();
+ }
+ return mods;
+}
+
+QString ShibokenGenerator::translateType(const AbstractMetaType* cType,
+ const AbstractMetaClass* context,
+ int option) const
+{
+ QString s;
+
+ if (context != 0
+ && cType != 0
+ && context->typeEntry()->isGenericClass()
+ && cType->originalTemplateType())
+ {
+ cType = cType->originalTemplateType();
+ }
+
+ if (!cType) {
+ s = "void";
+ } else if (cType->isArray()) {
+ s = translateType(cType->arrayElementType(), context) + "[]";
+ } else if (cType->isEnum() || cType->isFlags()) {
+ if (option & Generator::EnumAsInts)
+ s = "int";
+ else
+ s = cType->cppSignature();
+ } else if (cType->isValue() || cType->isObject() || cType->isReference()) {
+ s = cType->typeEntry()->qualifiedCppName();
+ if (cType->isObject())
+ s.append('*');
+ } else {
+ s = cType->cppSignature();
+ if (cType->isConstant() && (option & Generator::ExcludeConst))
+ s.replace("const", "");
+ if (cType->isReference() && (option & Generator::ExcludeReference))
+ s.replace("&", "");
+ }
+
+ return s;
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass)
+{
+ QString result = metaClass->name();
+ if (metaClass->enclosingClass()) // is a inner class
+ result.replace("::", "_");
+ result +="Wrapper";
+ return result;
+}
+
+QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString result = QLatin1String("Py");
+
+ if (func->ownerClass()) {
+ result += func->ownerClass()->name();
+ if (func->ownerClass()->enclosingClass()) // is a inner class
+ result.replace("::", "_");
+
+ result += '_';
+
+ if (func->isConstructor() || func->isCopyConstructor())
+ result += "New";
+ else if (func->isOperatorOverload())
+ result += ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ result += func->name();
+ } else {
+ result += moduleName() + "Module_" + func->name();
+ }
+
+ return result;
+}
+
+QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry* enumEntry)
+{
+ QString result = QString("Py") + moduleName() + '_'
+ + enumEntry->qualifiedCppName();
+ result.replace("::", "_");
+ return result;
+}
+
+QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func) const
+{
+ if (func->ownerClass() && (func->isConstructor() || func->isCopyConstructor()))
+ return func->ownerClass()->qualifiedCppName() + '*';
+
+ return translateType(func->type(), func->implementingClass());
+
+ //TODO: check these lines
+ //QString modifiedReturnType = QString(func->typeReplaced(0));
+ //return modifiedReturnType.isNull() ?
+ //translateType(func->type(), func->implementingClass()) : modifiedReturnType;
+}
+
+QString ShibokenGenerator::writeBaseConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context)
+{
+ QString typeName;
+ if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type->typeEntry();
+ if (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ typeName = ptype->name();
+ } else {
+ typeName = translateType(type, context);
+ }
+ s << "Shiboken::Converter< " << typeName << " >::";
+ return typeName;
+}
+
+void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, QString argumentName)
+{
+ QString typeName = writeBaseConversion(s, type, context);
+ s << "toPython(Shiboken::ValueHolder< " << typeName << " >(" << argumentName << "))";
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, QString argumentName)
+{
+ writeBaseConversion(s, type, context);
+ s << "toCpp(" << argumentName << ')';
+}
+
+QString ShibokenGenerator::getFormatUnitString(const AbstractMetaArgumentList arguments) const
+{
+ QString result;
+ foreach (const AbstractMetaArgument *arg, arguments) {
+ if ((arg->type()->isQObject() || arg->type()->isObject() || arg->type()->isValue())) { // &&
+// !arg->type()->isReference()) {
+ result += "O&";
+ } else if (arg->type()->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ if (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ result += m_formatUnits[ptype->name()];
+ } else if (arg->type()->isNativePointer() && arg->type()->name() == "char") {
+ result += 'z';
+ } else {
+ result += 'Y';
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type)
+{
+ if (type->name() == "char" && type->isNativePointer())
+ return QString("PyString");
+ return cpythonBaseName(type->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
+{
+ QString baseName;
+ if ((type->isObject() || type->isValue())) { // && !type->isReference()) {
+ baseName = QString("Py") + type->name();
+ } else if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ if (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ if (ptype->targetLangApiName() == ptype->name())
+ baseName = m_pythonPrimitiveTypeName[ptype->name()];
+ else
+ baseName = ptype->targetLangApiName();
+ } else if (type->isEnum()) {
+ baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ } else if (type->isContainer()) {
+ const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ switch (ctype->type()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::StringListContainer:
+ case ContainerTypeEntry::LinkedListContainer:
+ case ContainerTypeEntry::VectorContainer:
+ case ContainerTypeEntry::StackContainer:
+ case ContainerTypeEntry::QueueContainer:
+ baseName = "PyList";
+ break;
+ case ContainerTypeEntry::PairContainer:
+ baseName = "PyTuple";
+ break;
+ case ContainerTypeEntry::SetContainer:
+ baseName = "PySet";
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ case ContainerTypeEntry::HashContainer:
+ case ContainerTypeEntry::MultiHashContainer:
+ baseName = "PyDict";
+ break;
+ }
+ } else {
+ baseName = "PyObject";
+ }
+ return baseName;
+}
+
+QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type)
+{
+ return cpythonBaseName(type) + "_Type";
+}
+
+QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ if (!func->isOperatorOverload())
+ return QString();
+ return QString("Py") + func->ownerClass()->name()
+ + '_' + pythonOperatorFunctionName(func->originalName());
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(QString cppTypeName)
+{
+ return ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type)
+{
+ if (type->basicAliasedTypeEntry())
+ type = type->basicAliasedTypeEntry();
+ return pythonPrimitiveTypeName(type->name());
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ QString op = pythonOperatorFunctionName(func->originalName());
+ if (func->arguments().isEmpty()) {
+ if (op == "__sub__")
+ op = QString("__neg__");
+ else if (op == "__add__")
+ op = QString("__pos__");
+ } else if (func->isStatic() && func->arguments().size() == 2) {
+ // If a operator overload function has 2 arguments and
+ // is static we assume that it is a reverse operator.
+ op = op.insert(2, 'r');
+ }
+ return op;
+}
+
+bool ShibokenGenerator::isNumber(QString cpythonApiName)
+{
+ return cpythonApiName == "PyInt"
+ || cpythonApiName == "PyFloat"
+ || cpythonApiName == "PyLong";
+}
+
+bool ShibokenGenerator::isNumber(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+}
+
+bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
+{
+ return isNumber(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPyInt(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == "PyInt";
+}
+
+bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
+{
+ return isPyInt(type->typeEntry());
+}
+
+bool ShibokenGenerator::isReverseOperator(const AbstractMetaFunction* func)
+{
+ if (!func->isOperatorOverload())
+ return false;
+
+ const AbstractMetaClass* cppClass = func->ownerClass();
+ AbstractMetaArgumentList args = func->arguments();
+ // Here we expect static operator overloads with
+ // 2 arguments to represent reverse operators.
+ // e.g. static operator*(double,TYPE) => double * TYPE => TYPE.__rmul__(double).
+ return args.size() == 2 && cppClass &&
+ args[1]->type()->typeEntry() == cppClass->typeEntry();
+}
+
+static QString checkFunctionName(QString baseName, bool genericNumberType)
+{
+ if (genericNumberType && ShibokenGenerator::isNumber(baseName))
+ baseName = "PyNumber";
+ return baseName + "_Check";
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* type, bool genericNumberType)
+{
+ return checkFunctionName(cpythonBaseName(type), genericNumberType);
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType)
+{
+ return checkFunctionName(cpythonBaseName(type), genericNumberType);
+}
+
+QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ uint options) const
+{
+ QString modified_type = func->typeReplaced(argument->argumentIndex() + 1);
+ QString arg;
+
+ if (modified_type.isEmpty())
+ arg = translateType(argument->type(), func->implementingClass(), (Generator::Option) options);
+ else
+ arg = modified_type.replace('$', '.');
+
+ if (!(options & Generator::SkipName)) {
+ arg += " ";
+ arg += argument->argumentName();
+ }
+
+ QList<ReferenceCount> referenceCounts;
+ referenceCounts = func->referenceCounts(func->implementingClass(), argument->argumentIndex() + 1);
+ if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues &&
+ !argument->originalDefaultValueExpression().isEmpty())
+ {
+ QString default_value = argument->originalDefaultValueExpression();
+ if (default_value == "NULL")
+ default_value = NULL_VALUE;
+
+ //WORKAROUND: fix this please
+ if (default_value.startsWith("new "))
+ default_value.remove(0, 4);
+
+ arg += " = " + default_value;
+ }
+
+ return arg;
+}
+
+void ShibokenGenerator::writeArgument(QTextStream &s,
+ const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ uint options) const
+{
+ s << argumentString(func, argument, options);
+}
+
+void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *func,
+ uint options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+
+ if (options & Generator::WriteSelf) {
+ s << func->implementingClass()->name() << '&';
+ if (!(options & SkipName))
+ s << " self";
+ }
+
+ int argUsed = 0;
+ for (int i = 0; i < arguments.size(); ++i) {
+ if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1))
+ continue;
+
+ if ((options & Generator::WriteSelf) || argUsed != 0)
+ s << ", ";
+ writeArgument(s, func, arguments[i], options);
+ argUsed++;
+ }
+}
+
+QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, int option) const
+{
+ QString modifiedReturnType = QString(func->typeReplaced(0));
+ if (!modifiedReturnType.isNull() && !(option & OriginalTypeDescription))
+ return modifiedReturnType;
+ else
+ return translateType(func->type(), func->implementingClass(), option);
+}
+
+QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
+ QString prepend,
+ QString append,
+ int option,
+ int argCount) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+ int argumentCount = argCount < 0 ? arguments.size() : argCount;
+
+ QString result;
+ QTextStream s(&result);
+ // The actual function
+ if (!(func->isEmptyFunction() ||
+ func->isNormal() ||
+ func->isSignal())) {
+ option = Option(option | Generator::SkipReturnType);
+ } else {
+ s << functionReturnType(func, option) << ' ';
+ }
+
+ // name
+ QString name(func->originalName());
+ if (func->isConstructor())
+ name = wrapperName(func->ownerClass());
+
+ s << prepend << name << append << '(';
+ writeFunctionArguments(s, func, option);
+ s << ')';
+
+ if (func->isConstant() && !(option & Generator::ExcludeMethodConst))
+ s << " const";
+
+ return result;
+}
+
+QString ShibokenGenerator::signatureForDefaultVirtualMethod(const AbstractMetaFunction *func,
+ QString prepend,
+ QString append,
+ int option,
+ int argCount) const
+{
+ QString defaultMethodSignature = functionSignature(func, prepend, append, option, argCount);
+ QString staticSelf("(");
+ if (func->isConstant())
+ staticSelf += "const ";
+ staticSelf += func->ownerClass()->qualifiedCppName()+"& self";
+ if (!func->arguments().isEmpty())
+ staticSelf += ", ";
+ defaultMethodSignature.replace(defaultMethodSignature.lastIndexOf(") const"), 7, ")");
+ defaultMethodSignature.replace(defaultMethodSignature.indexOf('('), 1, staticSelf);
+ return defaultMethodSignature;
+}
+
+bool ShibokenGenerator::hasInjectedCodeOrSignatureModification(const AbstractMetaFunction* func)
+{
+ foreach (FunctionModification mod, functionModifications(func)) {
+ if (mod.isCodeInjection() || mod.isRenameModifier())
+ return true;
+ }
+ return false;
+}
+
+void ShibokenGenerator::writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *func,
+ uint options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+ int argCount = 0;
+ for (int j = 0, max = arguments.size(); j < max; j++) {
+
+ if ((options & Generator::SkipRemovedArguments) &&
+ (func->argumentRemoved(arguments.at(j)->argumentIndex() +1)))
+ continue;
+
+ if (argCount > 0)
+ s << ", ";
+
+ QString argName;
+
+ if ((options & Generator::BoxedPrimitive) &&
+ !arguments.at(j)->type()->isReference() &&
+ (arguments.at(j)->type()->isQObject() ||
+ arguments.at(j)->type()->isObject())) {
+ //s << "brian::wrapper_manager::instance()->retrieve( " << arguments.at(j)->argumentName() << " )";
+ // TODO: replace boost thing
+ s << "python::ptr( " << arguments.at(j)->argumentName() << " )";
+ } else {
+ s << arguments.at(j)->argumentName();
+ }
+ argCount++;
+ }
+}
+
+AbstractMetaFunctionList ShibokenGenerator::queryGlobalOperators(const AbstractMetaClass *metaClass)
+{
+ AbstractMetaFunctionList result;
+
+ foreach (AbstractMetaFunction *func, metaClass->functions()) {
+ if (func->isInGlobalScope() && func->isOperatorOverload())
+ result.append(func);
+ }
+ return result;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::sortContructor(AbstractMetaFunctionList list)
+{
+ AbstractMetaFunctionList result;
+
+ foreach (AbstractMetaFunction *func, list) {
+ bool inserted = false;
+ foreach (AbstractMetaArgument *arg, func->arguments()) {
+ if (arg->type()->isFlags() || arg->type()->isEnum()) {
+ result.push_back(func);
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted)
+ result.push_front(func);
+ }
+
+ return result;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::queryFunctions(const AbstractMetaClass *metaClass, bool allFunctions)
+{
+ AbstractMetaFunctionList result;
+
+ if (allFunctions) {
+ int defaultFlags = AbstractMetaClass::NormalFunctions | AbstractMetaClass::Visible;
+ defaultFlags |= metaClass->isInterface() ? 0 : AbstractMetaClass::ClassImplements;
+
+ // Constructors
+ result = metaClass->queryFunctions(AbstractMetaClass::Constructors
+ | defaultFlags);
+
+ // put enum constructor first to avoid conflict with int contructor
+ result = sortContructor(result);
+
+ // Final functions
+ result += metaClass->queryFunctions(AbstractMetaClass::FinalInTargetLangFunctions
+ | AbstractMetaClass::NonStaticFunctions
+ | defaultFlags);
+
+ //virtual
+ result += metaClass->queryFunctions(AbstractMetaClass::VirtualInTargetLangFunctions
+ | AbstractMetaClass::NonStaticFunctions
+ | defaultFlags);
+
+ // Static functions
+ result += metaClass->queryFunctions(AbstractMetaClass::StaticFunctions | defaultFlags);
+
+ // Empty, private functions, since they aren't caught by the other ones
+ result += metaClass->queryFunctions(AbstractMetaClass::Empty
+ | AbstractMetaClass::Invisible
+ | defaultFlags);
+ // Signals
+ result += metaClass->queryFunctions(AbstractMetaClass::Signals | defaultFlags);
+ } else {
+ result = metaClass->functionsInTargetLang();
+ }
+
+ return result;
+}
+
+void ShibokenGenerator::writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* func,
+ uint options) const
+{
+ if (!(options & Generator::SkipName))
+ s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName());
+ s << '(';
+ writeArgumentNames(s, func, options);
+ s << ')';
+}
+
+AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList lst = queryFunctions(metaClass, true);
+ foreach (AbstractMetaFunction *func, lst) {
+ //skip signals
+ if (func->isSignal()
+ || func->isDestructor()
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ lst.removeOne(func);
+ }
+
+ //virtual not implemented in current class
+ AbstractMetaFunctionList virtualLst = metaClass->queryFunctions(AbstractMetaClass::VirtualFunctions);
+ foreach (AbstractMetaFunction* func, virtualLst) {
+ if ((func->implementingClass() != metaClass) && !lst.contains(func))
+ lst.append(func);
+ }
+
+ //append global operators
+ lst += queryGlobalOperators(metaClass);
+
+ return lst;
+ //return metaClass->functions();
+}
+
+CodeSnipList ShibokenGenerator::getCodeSnips(const AbstractMetaFunction *func)
+{
+ CodeSnipList result;
+ const AbstractMetaClass* metaClass = func->implementingClass();
+ while (!metaClass) {
+ foreach (FunctionModification mod, func->modifications(metaClass)) {
+ if (mod.isCodeInjection())
+ result << mod.snips;
+ }
+
+ if (metaClass == metaClass->baseClass())
+ break;
+ metaClass = metaClass->baseClass();
+ }
+
+ return result;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ CodeSnip::Position position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func)
+{
+ foreach (CodeSnip snip, codeSnips) {
+ if ((snip.position != position) || !(snip.language & language))
+ continue;
+
+ QString code;
+ QTextStream tmpStream(&code);
+ Indentation indent1(INDENT);
+ Indentation indent2(INDENT);
+ snip.formattedCode(tmpStream, INDENT);
+
+ if (func) {
+ // replace template variable for return variable name
+ code.replace("%0", retvalVariableName());
+
+ // replace template variables for individual arguments
+ int removed = 0;
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i+1))
+ removed++;
+ code.replace("%" + QString::number(i+1), QString("cpp_arg%1").arg(i - removed));
+ }
+
+ // replace template variables for not removed arguments
+ int i = 0;
+ QString argumentNames;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex()+1))
+ continue;
+ if (i > 0)
+ argumentNames += ", ";
+ argumentNames += QString("cpp_arg%1").arg(i++);
+ }
+ code.replace("%ARGUMENT_NAMES", argumentNames);
+
+ replaceTemplateVariables(code, func);
+ }
+
+ s << code;
+ }
+}
+
+bool ShibokenGenerator::canCreateWrapperFor(const AbstractMetaClass* metaClass)
+{
+ return !metaClass->hasPrivateDestructor();
+}
+
+QStringList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass)
+{
+ QStringList baseClass;
+
+ if (!metaClass->baseClassName().isEmpty() &&
+ (metaClass->name() != metaClass->baseClassName()))
+ baseClass.append(metaClass->baseClassName());
+
+ foreach (AbstractMetaClass* interface, metaClass->interfaces()) {
+ AbstractMetaClass* aux = interface->primaryInterfaceImplementor();
+ if (!aux)
+ continue;
+
+ //skip templates
+ if (!aux->templateArguments().isEmpty())
+ continue;
+
+ if (!aux->name().isEmpty() && (metaClass->name() != aux->name()))
+ baseClass.append(aux->name());
+ }
+
+ return baseClass;
+}
+
+static void dumpFunction(AbstractMetaFunctionList lst)
+{
+ qDebug() << "DUMP FUNCTIONS: ";
+ foreach (AbstractMetaFunction *func, lst)
+ qDebug() << "*" << func->ownerClass()->name()
+ << func->signature()
+ << "Private: " << func->isPrivate()
+ << "Empty: " << func->isEmptyFunction()
+ << "Static:" << func->isStatic()
+ << "Signal:" << func->isSignal()
+ << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
+ << "is operator:" << func->isOperatorOverload()
+ << "is global:" << func->isInGlobalScope();
+}
diff --git a/shibokengenerator.h b/shibokengenerator.h
new file mode 100644
index 00000000..f9cd564f
--- /dev/null
+++ b/shibokengenerator.h
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the Shiboken Python Binding 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 SHIBOKENGENERATOR_H
+#define SHIBOKENGENERATOR_H
+
+#include <apiextractor/generator.h>
+#include <QtCore/QTextStream>
+
+class DocParser;
+
+/**
+ * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
+ */
+class ShibokenGenerator : public Generator
+{
+public:
+ ShibokenGenerator();
+
+ /**
+ * Translate metatypes to C++ format.
+ * \param metaType a pointer to metatype
+ * \param context the current meta class
+ * \param option some extra options
+ * \return the metatype translated to C++ format
+ */
+ virtual QString translateType(const AbstractMetaType* metaType,
+ const AbstractMetaClass* context,
+ int option = NoOption) const;
+ /**
+ * Write a function argument in the C++ in the text stream \p s.
+ * This function just call \code s << argumentString(); \endcode
+ * \param s text stream used to write the output.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ uint options = 0) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ uint options = 0) const;
+
+ void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction* func,
+ uint options = 0) const;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param func the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction* func,
+ uint options = 0) const;
+ QString functionReturnType(const AbstractMetaFunction* func, int option = NoOption) const;
+ /**
+ * Write a code snip into the buffer \p s.
+ * CodeSnip are codes inside inject-code tags.
+ * \param s the buffer
+ * \param func the cpp function
+ * \param code_snips a list of code snips
+ * \param position the position to insert the code snip
+ * \param language the kind of code snip
+ */
+ void writeCodeSnips(QTextStream &s,
+ const CodeSnipList &code_snips,
+ CodeSnip::Position position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func = 0);
+ /// returns the code snips of a function
+ CodeSnipList getCodeSnips(const AbstractMetaFunction* func);
+ static bool canCreateWrapperFor(const AbstractMetaClass* metaClass);
+ /**
+ * Function witch parse the metafunction information
+ * \param func the function witch will be parserd
+ * \param option some extra options
+ * \param arg_count the number of function arguments
+ */
+ QString functionSignature(const AbstractMetaFunction* func,
+ QString prepend = "",
+ QString append = "",
+ int option = NoOption,
+ int arg_count = -1) const;
+
+ QString signatureForDefaultVirtualMethod(const AbstractMetaFunction* func,
+ QString prepend = "",
+ QString append = "_default",
+ int option = NoOption,
+ int arg_count = -1) const;
+
+ virtual QString subDirectoryForClass(const AbstractMetaClass* metaClass) const
+ {
+ return subDirectoryForPackage(metaClass->package());
+ }
+
+ bool hasInjectedCodeOrSignatureModification(const AbstractMetaFunction* func);
+ QStringList getBaseClasses(const AbstractMetaClass* metaClass);
+
+ QString writeBaseConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context);
+ void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, QString argumentName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, QString argumentName);
+
+ static QString wrapperName(const AbstractMetaClass* metaClass);
+
+ static QString pythonPrimitiveTypeName(QString cppTypeName);
+ static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
+
+ static QString pythonOperatorFunctionName(QString cppOpFuncName)
+ {
+ return QString("__%1__").arg(m_pythonOperators.value(cppOpFuncName));
+ }
+ static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
+ static QString pythonRichCompareOperatorId(QString cppOpFuncName)
+ {
+ return QString("Py_%1").arg(m_pythonOperators.value(cppOpFuncName).toUpper());
+ }
+ static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func)
+ {
+ return pythonRichCompareOperatorId(func->originalName());
+ }
+
+ static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func);
+
+ static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const TypeEntry* type);
+ static bool isNumber(const AbstractMetaType* type);
+ static bool isPyInt(const TypeEntry* type);
+ static bool isPyInt(const AbstractMetaType* type);
+ static bool isReverseOperator(const AbstractMetaFunction* func);
+
+ QString cpythonBaseName(const TypeEntry* type);
+ QString cpythonBaseName(const AbstractMetaType* type);
+ QString cpythonTypeName(const TypeEntry* type);
+ QString cpythonCheckFunction(const TypeEntry* type, bool genericNumberType = false);
+ QString cpythonCheckFunction(const AbstractMetaType* type, bool genericNumberType = false);
+ QString cpythonFunctionName(const AbstractMetaFunction* func);
+ QString cpythonEnumName(const EnumTypeEntry* enumEntry);
+ QString cpythonEnumName(const AbstractMetaEnum* metaEnum)
+ {
+ return cpythonEnumName(metaEnum->typeEntry());
+ }
+
+ QString getFunctionReturnType(const AbstractMetaFunction* func) const;
+ QString getFormatUnitString(const AbstractMetaArgumentList arguments) const;
+
+ virtual bool prepareGeneration(const QMap<QString, QString>& args)
+ {
+ return true;
+ }
+
+protected:
+ bool m_native_jump_table;
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+
+ const char* name() const { return "Shiboken"; }
+
+ /**
+ * Initialize correspondences between primitive and Python types
+ */
+ static void initPrimitiveTypesCorrespondences();
+
+ static QString retvalVariableName() { return QString("cpp_result"); }
+
+ static FunctionModificationList functionModifications(const AbstractMetaFunction* func);
+ AbstractMetaFunctionList queryFunctions(const AbstractMetaClass* metaClass, bool allFunction = false);
+ void writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* metaFunc,
+ uint options = 0) const;
+
+ AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass);
+ AbstractMetaFunctionList queryGlobalOperators(const AbstractMetaClass* metaClass);
+ AbstractMetaFunctionList sortContructor(AbstractMetaFunctionList list);
+};
+
+
+#endif // SHIBOKENGENERATOR_H
+
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 00000000..c1569517
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_subdirectory(libsample)
+add_subdirectory(samplebinding)
+
+file(GLOB TEST_FILES samplebinding/*_test.py)
+
+foreach(test_file ${TEST_FILES})
+ string(REGEX MATCH "/([^/]+)_test.py" test_name ${test_file})
+ add_test(${CMAKE_MATCH_1} sh
+ ${CMAKE_CURRENT_SOURCE_DIR}/run_test.sh
+ "${libsample_BINARY_DIR}:${libshiboken_BINARY_DIR}"
+ "${sample_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE}
+ ${test_file})
+ set_tests_properties(${CMAKE_MATCH_1} PROPERTIES TIMEOUT 5)
+
+# Should set python path here
+# Looks like it's fixed in 2.8:
+# http://www.vtk.org/Bug/print_bug_page.php?bug_id=7885
+endforeach(test_file ${TEST_FILES})
+
diff --git a/tests/libsample/CMakeLists.txt b/tests/libsample/CMakeLists.txt
new file mode 100644
index 00000000..a630b3cb
--- /dev/null
+++ b/tests/libsample/CMakeLists.txt
@@ -0,0 +1,22 @@
+project(libsample)
+
+set(libsample_SRC
+abstract.cpp
+complex.cpp
+derived.cpp
+functions.cpp
+implicitconv.cpp
+kindergarten.cpp
+listuser.cpp
+modifications.cpp
+pairuser.cpp
+point.cpp
+reference.cpp
+samplenamespace.cpp
+size.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+add_library(libsample SHARED ${libsample_SRC})
+set_property(TARGET libsample PROPERTY PREFIX "")
+
diff --git a/tests/libsample/abstract.cpp b/tests/libsample/abstract.cpp
new file mode 100644
index 00000000..8b49f37f
--- /dev/null
+++ b/tests/libsample/abstract.cpp
@@ -0,0 +1,64 @@
+#include <iostream>
+#include "abstract.h"
+
+using namespace std;
+
+Abstract::Abstract(int id) : m_id(id)
+{
+ cout << __PRETTY_FUNCTION__;
+ show();
+ cout << endl;
+}
+
+Abstract::~Abstract()
+{
+ cout << __PRETTY_FUNCTION__;
+ show();
+ cout << endl;
+}
+
+void
+Abstract::unpureVirtual()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+}
+
+void
+Abstract::callUnpureVirtual()
+{
+ cout << __PRETTY_FUNCTION__ << " --- BEGIN" << endl;
+ this->unpureVirtual();
+ cout << __PRETTY_FUNCTION__ << " --- END" << endl;
+}
+
+
+void
+Abstract::callPureVirtual()
+{
+ cout << __PRETTY_FUNCTION__ << " --- BEGIN" << endl;
+ this->pureVirtual();
+ cout << __PRETTY_FUNCTION__ << " --- END" << endl;
+}
+
+void
+Abstract::show(PrintFormat format)
+{
+ cout << '<';
+ switch(format) {
+ case Short:
+ cout << this;
+ break;
+ case Verbose:
+ cout << "class " << className() << " | cptr: " << this;
+ cout << ", id: " << m_id;
+ break;
+ case OnlyId:
+ cout << "id: " << m_id;
+ break;
+ case ClassNameAndId:
+ cout << className() << " - id: " << m_id;
+ break;
+ }
+ cout << '>';
+}
+
diff --git a/tests/libsample/abstract.h b/tests/libsample/abstract.h
new file mode 100644
index 00000000..19e3a9db
--- /dev/null
+++ b/tests/libsample/abstract.h
@@ -0,0 +1,37 @@
+#ifndef ABSTRACT_H
+#define ABSTRACT_H
+
+class Abstract
+{
+public:
+ enum PrintFormat {
+ Short,
+ Verbose,
+ OnlyId,
+ ClassNameAndId
+ };
+
+ Abstract(int id = -1);
+ virtual ~Abstract();
+
+ int id() { return m_id; }
+
+ // factory method
+ static Abstract* createObject() { return 0; }
+
+ virtual void pureVirtual() = 0;
+ virtual void unpureVirtual();
+
+ void callPureVirtual();
+ void callUnpureVirtual();
+
+ void show(PrintFormat format = Verbose);
+
+protected:
+ virtual const char* className() { return "Abstract"; }
+
+private:
+ int m_id;
+};
+#endif // ABSTRACT_H
+
diff --git a/tests/libsample/complex.cpp b/tests/libsample/complex.cpp
new file mode 100644
index 00000000..9e93c961
--- /dev/null
+++ b/tests/libsample/complex.cpp
@@ -0,0 +1,27 @@
+#include <iostream>
+#include "complex.h"
+
+using namespace std;
+
+Complex::Complex(double real, double imag)
+ : m_real(real), m_imag(imag)
+{
+ // cout << __PRETTY_FUNCTION__ << "[real=0.0, imag=0.0]" << endl;
+}
+
+Complex
+Complex::operator+(Complex& other)
+{
+ Complex result;
+ result.setReal(m_real + other.real());
+ result.setImaginary(m_imag + other.imag());
+ return result;
+}
+
+void
+Complex::show()
+{
+ cout << "(real: " << m_real << ", imag: " << m_imag << ")";
+}
+
+
diff --git a/tests/libsample/complex.h b/tests/libsample/complex.h
new file mode 100644
index 00000000..f8efb790
--- /dev/null
+++ b/tests/libsample/complex.h
@@ -0,0 +1,25 @@
+#ifndef COMPLEX_H
+#define COMPLEX_H
+
+class Complex
+{
+public:
+ Complex(double real = 0.0, double imag = 0.0);
+ ~Complex() {}
+
+ double real() const { return m_real; }
+ void setReal(double real) { m_real = real; }
+ double imag() const { return m_imag; }
+ void setImaginary(double imag) { m_imag = imag; }
+
+ Complex operator+(Complex& other);
+
+ void show();
+
+private:
+ double m_real;
+ double m_imag;
+};
+
+#endif // COMPLEX_H
+
diff --git a/tests/libsample/derived.cpp b/tests/libsample/derived.cpp
new file mode 100644
index 00000000..9a86a9c9
--- /dev/null
+++ b/tests/libsample/derived.cpp
@@ -0,0 +1,80 @@
+#include <iostream>
+#include "derived.h"
+
+using namespace std;
+
+Derived::Derived(int id) : Abstract(id)
+{
+ cout << __PRETTY_FUNCTION__;
+ show();
+ cout << endl;
+}
+
+Derived::~Derived()
+{
+ cout << __PRETTY_FUNCTION__;
+ show();
+ cout << endl;
+}
+
+Abstract*
+Derived::createObject()
+{
+ static int id = 100;
+ return new Derived(id++);
+}
+
+void
+Derived::pureVirtual()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+}
+
+void
+Derived::unpureVirtual()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+}
+
+bool
+Derived::singleArgument(bool b)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return !b;
+}
+
+double
+Derived::defaultValue(int n)
+{
+ cout << __PRETTY_FUNCTION__ << "[n = 0]" << endl;
+ return ((double) n) + 0.1;
+}
+
+PolymorphicFuncEnum
+Derived::polymorphic(int i, int d)
+{
+ cout << __PRETTY_FUNCTION__ << "[i = 0, d = 0]" << endl;
+ return PolymorphicFunc_ii;
+}
+
+PolymorphicFuncEnum
+Derived::polymorphic(double n)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return PolymorphicFunc_d;
+}
+
+Derived::OtherPolymorphicFuncEnum
+Derived::otherPolymorphic(int a, int b, bool c, double d)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return OtherPolymorphicFunc_iibd;
+}
+
+Derived::OtherPolymorphicFuncEnum
+Derived::otherPolymorphic(int a, double b)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return OtherPolymorphicFunc_id;
+}
+
diff --git a/tests/libsample/derived.h b/tests/libsample/derived.h
new file mode 100644
index 00000000..5efc7c4b
--- /dev/null
+++ b/tests/libsample/derived.h
@@ -0,0 +1,46 @@
+#ifndef DERIVED_H
+#define DERIVED_H
+
+#include "abstract.h"
+
+enum PolymorphicFuncEnum {
+ PolymorphicFunc_ii,
+ PolymorphicFunc_d
+};
+
+class Derived : public Abstract
+{
+public:
+ enum OtherPolymorphicFuncEnum {
+ OtherPolymorphicFunc_iibd,
+ OtherPolymorphicFunc_id
+ };
+
+ Derived(int id = -1);
+ virtual ~Derived();
+ virtual void pureVirtual();
+ virtual void unpureVirtual();
+
+ // factory method
+ static Abstract* createObject();
+
+ // single argument
+ bool singleArgument(bool b);
+
+ // method with default value
+ double defaultValue(int n = 0);
+
+ // overloads
+ PolymorphicFuncEnum polymorphic(int i = 0, int d = 0);
+ PolymorphicFuncEnum polymorphic(double n);
+
+ // more overloads
+ OtherPolymorphicFuncEnum otherPolymorphic(int a, int b, bool c, double d);
+ OtherPolymorphicFuncEnum otherPolymorphic(int a, double b);
+
+protected:
+ const char* getClassName() { return className(); }
+ virtual const char* className() { return "Derived"; }
+};
+#endif // DERIVED_H
+
diff --git a/tests/libsample/functions.cpp b/tests/libsample/functions.cpp
new file mode 100644
index 00000000..c35bc5be
--- /dev/null
+++ b/tests/libsample/functions.cpp
@@ -0,0 +1,85 @@
+#include "functions.h"
+#include <string.h>
+#include <iostream>
+
+using namespace std;
+
+void
+printSomething()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+}
+
+int
+gimmeInt()
+{
+ static int val = 2;
+ val = val * 1.3;
+ return val;
+}
+
+double
+gimmeDouble()
+{
+ static double val = 7.77;
+ val = val * 1.3;
+ return val;
+}
+
+std::list<Complex>
+gimmeComplexList()
+{
+ std::list<Complex> lst;
+ lst.push_back(Complex());
+ lst.push_back(Complex(1.1, 2.2));
+ lst.push_back(Complex(1.3, 2.4));
+ return lst;
+}
+
+Complex
+sumComplexPair(std::pair<Complex, Complex> cpx_pair)
+{
+ return cpx_pair.first + cpx_pair.second;
+}
+
+double
+multiplyPair(std::pair<double, double> pair)
+{
+ return pair.first * pair.second;
+}
+
+int
+countCharacters(const char* text)
+{
+ int count;
+ for(count = 0; text[count] != '\0'; count++)
+ ;
+ return count;
+}
+
+char*
+makeCString()
+{
+ char* string = new char[strlen(__FUNCTION__) + 1];
+ strcpy(string, __FUNCTION__);
+ return string;
+}
+
+const char*
+returnCString()
+{
+ return __PRETTY_FUNCTION__;
+}
+
+GlobalPolyFuncEnum
+polymorphicFunc(int val)
+{
+ return GlobalPolyFunc_i;
+}
+
+GlobalPolyFuncEnum
+polymorphicFunc(double val)
+{
+ return GlobalPolyFunc_d;
+}
+
diff --git a/tests/libsample/functions.h b/tests/libsample/functions.h
new file mode 100644
index 00000000..77b2cb68
--- /dev/null
+++ b/tests/libsample/functions.h
@@ -0,0 +1,36 @@
+#ifndef FUNCTIONS_H
+#define FUNCTIONS_H
+
+#include <list>
+#include <utility>
+#include "complex.h"
+
+enum GlobalEnum {
+ NoThing,
+ FirstThing,
+ SecondThing,
+ ThirdThing
+};
+
+enum GlobalPolyFuncEnum {
+ GlobalPolyFunc_i,
+ GlobalPolyFunc_d
+};
+
+void printSomething();
+int gimmeInt();
+double gimmeDouble();
+double multiplyPair(std::pair<double, double> pair);
+std::list<Complex> gimmeComplexList();
+Complex sumComplexPair(std::pair<Complex, Complex> cpx_pair);
+
+int countCharacters(const char* text);
+char* makeCString();
+const char* returnCString();
+
+// Tests polymorphism on functions (!methods)
+GlobalPolyFuncEnum polymorphicFunc(int val);
+GlobalPolyFuncEnum polymorphicFunc(double val);
+
+#endif // FUNCTIONS_H
+
diff --git a/tests/libsample/implicitconv.cpp b/tests/libsample/implicitconv.cpp
new file mode 100644
index 00000000..902707e1
--- /dev/null
+++ b/tests/libsample/implicitconv.cpp
@@ -0,0 +1,38 @@
+#include "implicitconv.h"
+
+ImplicitConv
+ImplicitConv::implicitConvCommon(ImplicitConv implicit)
+{
+ return implicit;
+}
+
+ImplicitConv
+ImplicitConv::implicitConvDefault(ImplicitConv implicit)
+{
+ return implicit;
+}
+
+ImplicitConv::ICPolymorphicFuncEnum
+ImplicitConv::implicitConvPolymorphism(ImplicitConv implicit, int dummyArg)
+{
+ return ImplicitConv::PolyFunc_Ii;
+}
+
+ImplicitConv::ICPolymorphicFuncEnum
+ImplicitConv::implicitConvPolymorphism(ImplicitConv implicit, bool dummyArg)
+{
+ return ImplicitConv::PolyFunc_Ib;
+}
+
+ImplicitConv::ICPolymorphicFuncEnum
+ImplicitConv::implicitConvPolymorphism(int dummyArg)
+{
+ return ImplicitConv::PolyFunc_i;
+}
+
+ImplicitConv::ICPolymorphicFuncEnum
+ImplicitConv::implicitConvPolymorphism(CtorEnum dummyArg)
+{
+ return ImplicitConv::PolyFunc_C;
+}
+
diff --git a/tests/libsample/implicitconv.h b/tests/libsample/implicitconv.h
new file mode 100644
index 00000000..53815087
--- /dev/null
+++ b/tests/libsample/implicitconv.h
@@ -0,0 +1,44 @@
+#ifndef IMPLICITCONV_H
+#define IMPLICITCONV_H
+
+class ImplicitConv
+{
+public:
+ enum CtorEnum {
+ CtorNone,
+ CtorOne,
+ CtorTwo,
+ CtorThree
+ };
+
+ enum ICPolymorphicFuncEnum {
+ PolyFunc_Ii,
+ PolyFunc_Ib,
+ PolyFunc_i,
+ PolyFunc_C
+ };
+
+ ImplicitConv() : m_ctorEnum(CtorNone), m_objId(-1) {}
+ ImplicitConv(int objId) : m_ctorEnum(CtorOne), m_objId(objId) {}
+ ImplicitConv(CtorEnum ctorEnum) : m_ctorEnum(ctorEnum), m_objId(-1) {}
+ ~ImplicitConv() {}
+
+ CtorEnum ctorEnum() { return m_ctorEnum; }
+ int objId() { return m_objId; }
+
+ static ImplicitConv implicitConvCommon(ImplicitConv implicit);
+
+ static ImplicitConv implicitConvDefault(ImplicitConv implicit = CtorTwo);
+
+ static ICPolymorphicFuncEnum implicitConvPolymorphism(ImplicitConv implicit, int dummyArg);
+ static ICPolymorphicFuncEnum implicitConvPolymorphism(ImplicitConv implicit, bool dummyArg);
+ static ICPolymorphicFuncEnum implicitConvPolymorphism(int dummyArg);
+ static ICPolymorphicFuncEnum implicitConvPolymorphism(CtorEnum dummyArg);
+
+private:
+ CtorEnum m_ctorEnum;
+ int m_objId;
+};
+
+#endif // IMPLICITCONV_H
+
diff --git a/tests/libsample/kindergarten.cpp b/tests/libsample/kindergarten.cpp
new file mode 100644
index 00000000..8332e4fe
--- /dev/null
+++ b/tests/libsample/kindergarten.cpp
@@ -0,0 +1,64 @@
+#include <iostream>
+#include "kindergarten.h"
+
+using namespace std;
+
+KinderGarten::~KinderGarten()
+{
+ cout << __PRETTY_FUNCTION__ << " ---- BEGIN" << endl;
+ killChildren();
+ cout << __PRETTY_FUNCTION__ << " ---- END" << endl;
+}
+
+void
+KinderGarten::addChild(Abstract* child)
+{
+ m_children.push_back(child);
+}
+
+void
+KinderGarten::killChildren()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ while (!m_children.empty()) {
+ m_children.back()->show();
+ cout << endl;
+ delete m_children.back();
+ m_children.pop_back();
+ }
+}
+
+void
+KinderGarten::killChild(Abstract* child)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ if (child) {
+ m_children.remove(child);
+// delete child;
+ }
+}
+
+Abstract*
+KinderGarten::releaseChild(Abstract* child)
+{
+ for(ChildList::iterator child_iter = m_children.begin();
+ child_iter != m_children.end(); child_iter++) {
+ if (child == *child_iter) {
+ m_children.erase(child_iter);
+ return child;
+ }
+ }
+}
+
+void
+KinderGarten::show()
+{
+ cout << "[";
+ for(ChildList::iterator child_iter = m_children.begin();
+ child_iter != m_children.end(); child_iter++) {
+ if (child_iter != m_children.begin())
+ cout << ", ";
+ (*child_iter)->show();
+ }
+ cout << "]";
+}
diff --git a/tests/libsample/kindergarten.h b/tests/libsample/kindergarten.h
new file mode 100644
index 00000000..b0a083dc
--- /dev/null
+++ b/tests/libsample/kindergarten.h
@@ -0,0 +1,29 @@
+#ifndef KINDERGARTEN_H
+#define KINDERGARTEN_H
+
+#include <list>
+#include "abstract.h"
+
+class KinderGarten
+{
+public:
+ typedef std::list<Abstract*> ChildList;
+
+ KinderGarten() {}
+ ~KinderGarten();
+
+ void addChild(Abstract* child);
+ Abstract* releaseChild(Abstract* child);
+ ChildList children() { return m_children; }
+
+ void killChildren();
+ void killChild(Abstract* child);
+
+ void show();
+
+private:
+ ChildList m_children;
+};
+
+#endif // KINDERGARTEN_H
+
diff --git a/tests/libsample/listuser.cpp b/tests/libsample/listuser.cpp
new file mode 100644
index 00000000..0b9a14ff
--- /dev/null
+++ b/tests/libsample/listuser.cpp
@@ -0,0 +1,47 @@
+#include <iostream>
+#include <numeric>
+#include <cstdlib>
+#include "listuser.h"
+
+using namespace std;
+
+std::list<int>
+ListUser::callCreateList()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return createList();
+}
+
+std::list<int>
+ListUser::createList()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ std::list<int> retval;
+ for (int i = 0; i < 4; i++)
+ retval.push_front(rand());
+ return retval;
+}
+
+std::list<Complex>
+ListUser::createComplexList(Complex cpx0, Complex cpx1)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ std::list<Complex> retval;
+ retval.push_back(cpx0);
+ retval.push_back(cpx1);
+ return retval;
+}
+
+double
+ListUser::sumList(std::list<int> vallist)
+{
+ return std::accumulate(vallist.begin(), vallist.end(), 0.0);
+}
+
+double
+ListUser::sumList(std::list<double> vallist)
+{
+ return std::accumulate(vallist.begin(), vallist.end(), 0.0);
+}
+
+
diff --git a/tests/libsample/listuser.h b/tests/libsample/listuser.h
new file mode 100644
index 00000000..c1ea7091
--- /dev/null
+++ b/tests/libsample/listuser.h
@@ -0,0 +1,23 @@
+#ifndef LISTUSER_H
+#define LISTUSER_H
+
+#include <list>
+#include "complex.h"
+
+class ListUser
+{
+public:
+ ListUser() {}
+ ~ListUser() {}
+
+ virtual std::list<int> createList();
+ std::list<int> callCreateList();
+
+ static std::list<Complex> createComplexList(Complex cpx0, Complex cpx1);
+
+ double sumList(std::list<int> vallist);
+ double sumList(std::list<double> vallist);
+};
+
+#endif // LISTUSER_H
+
diff --git a/tests/libsample/main.cpp b/tests/libsample/main.cpp
new file mode 100644
index 00000000..7fc56367
--- /dev/null
+++ b/tests/libsample/main.cpp
@@ -0,0 +1,216 @@
+#include <iostream>
+#include <list>
+#include "abstract.h"
+#include "derived.h"
+#include "kindergarten.h"
+#include "complex.h"
+#include "point.h"
+#include "size.h"
+#include "listuser.h"
+#include "samplenamespace.h"
+
+using namespace std;
+
+int
+main(int argv, char **argc)
+{
+ cout << endl;
+
+ Derived derived;
+
+ cout << endl;
+
+ derived.unpureVirtual();
+ derived.pureVirtual();
+ derived.callPureVirtual();
+
+ cout << endl;
+ Abstract* abs;
+ abs = Abstract::createObject();
+ cout << "Abstract::createObject(): " << abs << endl << endl;
+ delete abs;
+
+ abs = Derived::createObject();
+ cout << "Derived::createObject() : ";
+ abs->show();
+ cout << endl;
+ delete abs;
+ cout << endl;
+
+ abs = Derived::createObject();
+ cout << "Derived::createObject() : ";
+ abs->show();
+ cout << endl;
+ delete abs;
+ cout << endl;
+
+ cout << endl << "-----------------------------------------" << endl;
+
+ KinderGarten kg;
+ Derived* d[] = { 0, 0, 0 };
+
+ for (int i = 0; i < 3; i++) {
+ d[i] = new Derived(i);
+ d[i]->show();
+ cout << endl;
+ kg.addChild(d[i]);
+ }
+
+ kg.show();
+ cout << endl;
+
+ cout << endl << "* kill child ";
+ d[2]->show();
+ cout << " ----------------" << endl;
+ kg.killChild(d[2]);
+ kg.show();
+ cout << endl;
+
+ cout << endl << "* release child ";
+ d[1]->show();
+ cout << " -------------" << endl;
+ Abstract* released = kg.releaseChild(d[1]);
+ cout << "released: ";
+ released->show();
+ cout << endl;
+ kg.show();
+ cout << endl;
+
+ cout << endl << "* kill children ------------------------------------" << endl;
+ kg.killChildren();
+ kg.show();
+ cout << endl << endl;
+
+ cout << "-----------------------------------------" << endl;
+ ListUser lu;
+ cout << "ListUser::createList()" << endl;
+ std::list<int> intlist = lu.createList();
+ for (std::list<int>::iterator it = intlist.begin(); it != intlist.end(); it++) {
+ cout << "* " << *it << endl;
+ }
+
+ cout << "ListUser::createComplexList" << endl;
+ std::list<Complex> cpxlist = ListUser::createComplexList(Complex(1.1, 2.2), Complex(3.3, 4.4));
+ for (std::list<Complex>::iterator it = cpxlist.begin(); it != cpxlist.end(); it++) {
+ cout << "* ";
+ (*it).show();
+ cout << endl;
+ }
+ cout << endl;
+
+ cout << "-----------------------------------------" << endl;
+ cout << "SampleNamespace" << endl;
+
+ cout << "SampleNamespace::RandomNumber: ";
+ cout << SampleNamespace::getNumber(SampleNamespace::RandomNumber);
+ cout << endl;
+ cout << "SampleNamespace::UnixTime: ";
+ cout << SampleNamespace::getNumber(SampleNamespace::UnixTime);
+ cout << endl;
+ double val_d = 1.3;
+ cout << "SampleNamespace::powerOfTwo(" << val_d << "): ";
+ cout << SampleNamespace::powerOfTwo(val_d) << endl;
+ int val_i = 7;
+ cout << "SampleNamespace::powerOfTwo(" << val_i << "): ";
+ cout << SampleNamespace::powerOfTwo(val_i) << endl;
+ cout << endl;
+
+ cout << "-----------------------------------------" << endl;
+ cout << "Point" << endl;
+
+ Point p1(1.1, 2.2);
+ cout << "p1: ";
+ p1.show();
+ cout << endl;
+
+ Point p2(3.4, 5.6);
+ cout << "p2: ";
+ p2.show();
+ cout << endl;
+
+ cout << "p1 + p2 == ";
+ (p1 + p2).show();
+ cout << endl;
+
+ cout << "p1 * 2.0 == ";
+ (p1 * 2.0).show();
+ cout << endl;
+
+ cout << "1.5 * p2 == ";
+ (1.5 * p2).show();
+ cout << endl;
+
+ cout << "p1: ";
+ p1.show();
+ cout << endl << "p2: ";
+ p2.show();
+ cout << endl << "p1 += p2" << endl;
+ p1 += p2;
+ cout << "p1: ";
+ p1.show();
+ cout << endl;
+
+ cout << "p1 == p2 ? " << ((p1 == p2) ? "true" : "false") << endl;
+ cout << "p1 == p1 ? " << ((p1 == p1) ? "true" : "false") << endl;
+ cout << "p2 == p2 ? " << ((p2 == p2) ? "true" : "false") << endl;
+
+ cout << "-----------------------------------------" << endl;
+ cout << "Size" << endl;
+
+ Size s1(2, 2);
+ cout << "s1: ";
+ s1.show();
+ cout << ", area: " << s1.calculateArea();
+ cout << endl;
+
+ Size s2(3, 5);
+ cout << "s2: ";
+ s2.show();
+ cout << ", area: " << s2.calculateArea();
+ cout << endl;
+
+ cout << endl;
+
+ cout << "s1 == s2 ? " << ((s1 == s2) ? "true" : "false") << endl;
+ cout << "s1 != s2 ? " << ((s1 != s2) ? "true" : "false") << endl;
+
+ cout << "s1 < s2 ? " << ((s1 < s2) ? "true" : "false") << endl;
+ cout << "s1 <= s2 ? " << ((s1 <= s2) ? "true" : "false") << endl;
+ cout << "s1 > s2 ? " << ((s1 > s2) ? "true" : "false") << endl;
+ cout << "s1 >= s2 ? " << ((s1 >= s2) ? "true" : "false") << endl;
+
+ cout << "s1 < 10 ? " << ((s1 < 10) ? "true" : "false") << endl;
+ cout << "s1 <= 10 ? " << ((s1 <= 10) ? "true" : "false") << endl;
+ cout << "s1 > 10 ? " << ((s1 > 10) ? "true" : "false") << endl;
+ cout << "s1 >= 10 ? " << ((s1 >= 10) ? "true" : "false") << endl;
+ cout << "s2 < 10 ? " << ((s2 < 10) ? "true" : "false") << endl;
+ cout << "s2 <= 10 ? " << ((s2 <= 10) ? "true" : "false") << endl;
+ cout << "s2 > 10 ? " << ((s2 > 10) ? "true" : "false") << endl;
+ cout << "s2 >= 10 ? " << ((s2 >= 10) ? "true" : "false") << endl;
+ cout << endl;
+
+ cout << "s1: ";
+ s1.show();
+ cout << endl << "s2: ";
+ s2.show();
+ cout << endl << "s1 += s2" << endl;
+ s1 += s2;
+ cout << "s1: ";
+ s1.show();
+ cout << endl;
+
+ cout << endl;
+
+ cout << "s1: ";
+ s1.show();
+ cout << endl << "s1 *= 2.0" << endl;
+ s1 *= 2.0;
+ cout << "s1: ";
+ s1.show();
+ cout << endl;
+
+ cout << endl;
+
+ return 0;
+}
+
diff --git a/tests/libsample/modifications.cpp b/tests/libsample/modifications.cpp
new file mode 100644
index 00000000..68cf6fe6
--- /dev/null
+++ b/tests/libsample/modifications.cpp
@@ -0,0 +1,68 @@
+#include <iostream>
+#include "modifications.h"
+
+using namespace std;
+
+std::pair<double, double>
+Modifications::pointToPair(Point pt, bool* ok)
+{
+ std::pair<double, double> retval(pt.x(), pt.y());
+ *ok = true;
+ return retval;
+}
+
+double
+Modifications::multiplyPointCoordsPlusValue(bool* ok, Point pt, double value)
+{
+ double retval = (pt.x() * pt.y()) + value;
+ *ok = true;
+ return retval;
+}
+
+int
+Modifications::doublePlus(int value, int plus)
+{
+ return (2 * value) + plus;
+}
+
+int
+Modifications::power(int base, int exponent)
+{
+ if (exponent == 0)
+ return 1;
+ int retval = base;
+ for (int i = 1; i < exponent; i++)
+ retval = retval * base;
+ return retval;
+}
+
+int
+Modifications::timesTen(int number)
+{
+ return number * 10;
+}
+
+int
+Modifications::increment(int number)
+{
+ return ++number;
+}
+
+void
+Modifications::exclusiveCppStuff()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+}
+
+int
+Modifications::cppMultiply(int a, int b)
+{
+ return a * b;
+}
+
+const char*
+Modifications::className()
+{
+ return "Modifications";
+}
+
diff --git a/tests/libsample/modifications.h b/tests/libsample/modifications.h
new file mode 100644
index 00000000..79380816
--- /dev/null
+++ b/tests/libsample/modifications.h
@@ -0,0 +1,73 @@
+#ifndef MODIFICATIONS_H
+#define MODIFICATIONS_H
+
+#include <utility>
+#include "point.h"
+
+class Modifications
+{
+public:
+ Modifications() {}
+ ~Modifications() {}
+
+ enum PolymorphicModFunc {
+ PolymorphicNone,
+ Polymorphic_ibid,
+ Polymorphic_ibib,
+ Polymorphic_ibiP,
+ Polymorphic_ibii,
+ Polymorphic_ibPP
+ };
+
+ // those polymorphic methods should be heavily modified
+ // to push the overload decisor to its limits
+ PolymorphicModFunc polymorphic(int a0, bool b0, int c0, double d0) { return Polymorphic_ibid; }
+ PolymorphicModFunc polymorphic(int a1, bool b1, int c1, bool d1) { return Polymorphic_ibib; }
+ PolymorphicModFunc polymorphic(int a2, bool b2, int c2, Point d2) { return Polymorphic_ibiP; }
+ PolymorphicModFunc polymorphic(int a3, bool b3, int c3 = 123, int d3 = 456) { return Polymorphic_ibii; }
+ PolymorphicModFunc polymorphic(int a4, bool b4, Point c4, Point d4) { return Polymorphic_ibPP; }
+
+ // 'ok' must be removed and the return value will be changed
+ // to a tuple (PyObject*) containing the expected result plus
+ // the 'ok' value as a Python boolean
+ std::pair<double, double> pointToPair(Point pt, bool* ok);
+
+ // same as 'pointToPair' except that this time 'ok' is the first argument
+ double multiplyPointCoordsPlusValue(bool* ok, Point pt, double value);
+
+ // completely remove 'plus' from the Python side
+ int doublePlus(int value, int plus = 0);
+
+ // the default value for both arguments must be changed in Python
+ int power(int base = 1, int exponent = 0);
+
+ // in Python set argument default value to 10
+ int timesTen(int number);
+
+ // in Python remove the argument default value
+ int increment(int number = 0);
+
+ // don't export this method to Python
+ void exclusiveCppStuff();
+
+ // change the name of this regular method
+ int cppMultiply(int a, int b);
+
+ // change the name of this virtual method
+ virtual const char* className();
+};
+
+class AbstractModifications : public Modifications
+{
+public:
+ AbstractModifications() {}
+ ~AbstractModifications() {}
+
+ bool invert(bool value) { return !value; }
+
+ // completely remove this method in Python
+ virtual void pointlessPureVirtualMethod() = 0;
+};
+
+#endif // MODIFICATIONS_H
+
diff --git a/tests/libsample/pairuser.cpp b/tests/libsample/pairuser.cpp
new file mode 100644
index 00000000..8983630e
--- /dev/null
+++ b/tests/libsample/pairuser.cpp
@@ -0,0 +1,32 @@
+#include <iostream>
+#include "pairuser.h"
+
+using namespace std;
+
+std::pair<int, int>
+PairUser::callCreatePair()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return createPair();
+}
+
+std::pair<int, int>
+PairUser::createPair()
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return std::pair<int, int>(10, 20);
+}
+
+std::pair<Complex, Complex>
+PairUser::createComplexPair(Complex cpx0, Complex cpx1)
+{
+ cout << __PRETTY_FUNCTION__ << endl;
+ return std::pair<Complex, Complex>(cpx0, cpx1);
+}
+
+double
+PairUser::sumPair(std::pair<int, double> pair)
+{
+ return ((double) pair.first) + pair.second;
+}
+
diff --git a/tests/libsample/pairuser.h b/tests/libsample/pairuser.h
new file mode 100644
index 00000000..27cf7668
--- /dev/null
+++ b/tests/libsample/pairuser.h
@@ -0,0 +1,19 @@
+#ifndef PAIRUSER_H
+#define PAIRUSER_H
+
+#include <utility>
+#include "complex.h"
+
+class PairUser
+{
+public:
+ PairUser() {}
+ ~PairUser() {}
+
+ virtual std::pair<int, int> createPair();
+ std::pair<int, int> callCreatePair();
+ static std::pair<Complex, Complex> createComplexPair(Complex cpx0, Complex cpx1);
+ double sumPair(std::pair<int, double> pair);
+};
+#endif // PAIRUSER_H
+
diff --git a/tests/libsample/point.cpp b/tests/libsample/point.cpp
new file mode 100644
index 00000000..ad816025
--- /dev/null
+++ b/tests/libsample/point.cpp
@@ -0,0 +1,111 @@
+#include <iostream>
+#include "point.h"
+
+using namespace std;
+
+Point::Point(int x, int y) : m_x(x), m_y(y)
+{
+ // cout << __PRETTY_FUNCTION__ << " [x=0, y=0]" << endl;
+}
+
+Point::Point(double x, double y) : m_x(x), m_y(y)
+{
+ // cout << __PRETTY_FUNCTION__ << endl;
+}
+
+void
+Point::show()
+{
+ cout << "(x: " << m_x << ", y: " << m_y << ")";
+}
+
+bool
+Point::operator==(const Point& other)
+{
+ return m_x == other.m_x && m_y == other.m_y;
+}
+
+Point
+Point::operator+(const Point& other)
+{
+ return Point(m_x + other.m_x, m_y + other.m_y);
+}
+
+Point
+Point::operator-(const Point& other)
+{
+ return Point(m_x - other.m_x, m_y - other.m_y);
+}
+
+Point&
+Point::operator+=(Point &other)
+{
+ m_x += other.m_x;
+ m_y += other.m_y;
+ return *this;
+}
+
+Point&
+Point::operator-=(Point &other)
+{
+ m_x -= other.m_x;
+ m_y -= other.m_y;
+ return *this;
+}
+
+Point
+operator*(Point& pt, double mult)
+{
+ return Point(pt.m_x * mult, pt.m_y * mult);
+}
+
+Point
+operator*(Point& pt, int mult)
+{
+ return Point(((int) pt.m_x) * mult, ((int) pt.m_y) * mult);
+}
+
+Point
+operator*(double mult, Point& pt)
+{
+ return Point(pt.m_x * mult, pt.m_y * mult);
+}
+
+Point
+operator*(int mult, Point& pt)
+{
+ return Point(((int) pt.m_x) * mult, ((int) pt.m_y) * mult);
+}
+
+Point
+operator-(const Point& pt)
+{
+ return Point(-pt.m_x, -pt.m_y);
+}
+
+bool
+operator!(const Point& pt)
+{
+ return (pt.m_x == 0.0 && pt.m_y == 0.0);
+}
+
+Complex
+transmutePointIntoComplex(Point point)
+{
+ Complex cpx(point.x(), point.y());
+ // cout << __PRETTY_FUNCTION__ << " ";
+ // point.show();
+ // cout << endl;
+ return cpx;
+}
+
+Point
+transmuteComplexIntoPoint(Complex cpx)
+{
+ Point pt(cpx.real(), cpx.imag());
+ // cout << __PRETTY_FUNCTION__ << " ";
+ // cpx.show();
+ // cout << endl;
+ return pt;
+}
+
diff --git a/tests/libsample/point.h b/tests/libsample/point.h
new file mode 100644
index 00000000..e5ec9c1b
--- /dev/null
+++ b/tests/libsample/point.h
@@ -0,0 +1,51 @@
+#ifndef POINT_H
+#define POINT_H
+
+#include "complex.h"
+#include <utility>
+
+class Point
+{
+public:
+ Point(int x = 0, int y = 0);
+ Point(double x, double y);
+ ~Point() {}
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+
+ bool operator==(const Point& other);
+ Point operator+(const Point& other);
+ Point operator-(const Point& other);
+
+ friend Point operator*(Point& pt, double mult);
+ friend Point operator*(Point& pt, int mult);
+ friend Point operator*(double mult, Point& pt);
+ friend Point operator*(int mult, Point& pt);
+ friend Point operator-(const Point& pt);
+ friend bool operator!(const Point& pt);
+
+ Point& operator+=(Point &other);
+ Point& operator-=(Point &other);
+
+ void show();
+
+private:
+ double m_x;
+ double m_y;
+};
+
+Point operator*(Point& pt, double mult);
+Point operator*(Point& pt, int mult);
+Point operator*(double mult, Point& pt);
+Point operator*(int mult, Point& pt);
+Point operator-(const Point& pt);
+bool operator!(const Point& pt);
+
+Complex transmutePointIntoComplex(Point point);
+Point transmuteComplexIntoPoint(Complex cpx);
+
+Point operator*(Point& pt, double multiplier);
+
+#endif // POINT_H
+
diff --git a/tests/libsample/reference.cpp b/tests/libsample/reference.cpp
new file mode 100644
index 00000000..fb3e78e4
--- /dev/null
+++ b/tests/libsample/reference.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+#include "reference.h"
+
+using namespace std;
+
+void
+Reference::show() const
+{
+ cout << "Reference.objId: " << m_objId;
+}
+
diff --git a/tests/libsample/reference.h b/tests/libsample/reference.h
new file mode 100644
index 00000000..bafd2492
--- /dev/null
+++ b/tests/libsample/reference.h
@@ -0,0 +1,24 @@
+#ifndef REFERENCE_H
+#define REFERENCE_H
+
+class Reference
+{
+public:
+ explicit Reference(int objId = -1)
+ : m_objId(objId) {}
+ ~Reference() {}
+
+ double objId() { return m_objId; }
+ void setObjId(int objId) { m_objId = objId; }
+
+ static int usesReference(Reference& r) { return r.m_objId; }
+ static int usesConstReference(const Reference& r) { return r.m_objId; }
+
+ void show() const;
+
+private:
+ int m_objId;
+};
+
+#endif // REFERENCE_H
+
diff --git a/tests/libsample/samplenamespace.cpp b/tests/libsample/samplenamespace.cpp
new file mode 100644
index 00000000..ebf2ff74
--- /dev/null
+++ b/tests/libsample/samplenamespace.cpp
@@ -0,0 +1,48 @@
+#include <iostream>
+#include <cstdlib>
+#include <time.h>
+#include "samplenamespace.h"
+
+using namespace std;
+
+namespace SampleNamespace
+{
+
+OutValue
+enumInEnumOut(InValue in)
+{
+ OutValue retval;
+ switch(in) {
+ case ZeroIn:
+ retval = ZeroOut;
+ break;
+ case OneIn:
+ retval = OneOut;
+ break;
+ case TwoIn:
+ retval = TwoOut;
+ break;
+ default:
+ retval = (OutValue) -1;
+ }
+ return retval;
+}
+
+int
+getNumber(Option opt)
+{
+ int retval;
+ switch(opt) {
+ case RandomNumber:
+ retval = rand() % 100;
+ break;
+ case UnixTime:
+ retval = (int) time(0);
+ break;
+ default:
+ retval = 0;
+ }
+ return retval;
+}
+
+} // namespace SampleNamespace
diff --git a/tests/libsample/samplenamespace.h b/tests/libsample/samplenamespace.h
new file mode 100644
index 00000000..2c65aeab
--- /dev/null
+++ b/tests/libsample/samplenamespace.h
@@ -0,0 +1,36 @@
+#ifndef SAMPLENAMESPACE_H
+#define SAMPLENAMESPACE_H
+
+namespace SampleNamespace
+{
+
+enum Option {
+ None,
+ RandomNumber,
+ UnixTime
+};
+
+enum InValue {
+ ZeroIn,
+ OneIn,
+ TwoIn
+};
+
+enum OutValue {
+ ZeroOut,
+ OneOut,
+ TwoOut
+};
+
+OutValue enumInEnumOut(InValue in);
+
+int getNumber(Option opt);
+
+inline double powerOfTwo(double num) {
+ return num * num;
+}
+
+} // namespace SampleNamespace
+
+#endif // SAMPLENAMESPACE_H
+
diff --git a/tests/libsample/size.cpp b/tests/libsample/size.cpp
new file mode 100644
index 00000000..63af9c82
--- /dev/null
+++ b/tests/libsample/size.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+#include "size.h"
+
+using namespace std;
+
+void
+Size::show() const
+{
+ cout << "(width: " << m_width << ", height: " << m_height << ")";
+}
+
diff --git a/tests/libsample/size.h b/tests/libsample/size.h
new file mode 100644
index 00000000..48f0d772
--- /dev/null
+++ b/tests/libsample/size.h
@@ -0,0 +1,152 @@
+#ifndef SIZE_H
+#define SIZE_H
+
+class Size
+{
+public:
+ Size(double width = 0.0, double height = 0.0) : m_width(width), m_height(height) {}
+ ~Size() {}
+
+ double width() { return m_width; }
+ void setWidth(double width) { m_width = width; }
+ double height() { return m_height; }
+ void setHeight(double height) { m_height = height; }
+
+ double calculateArea() const { return m_width * m_height; }
+
+ // Comparison Operators
+ inline bool operator==(const Size& other)
+ {
+ return m_width == other.m_width && m_height == other.m_height;
+ }
+
+ inline bool operator<(const Size& other)
+ {
+ return calculateArea() < other.calculateArea();
+ }
+
+ inline bool operator>(const Size& other)
+ {
+ return calculateArea() > other.calculateArea();
+ }
+
+ inline bool operator<=(const Size& other)
+ {
+ return calculateArea() <= other.calculateArea();
+ }
+
+ inline bool operator>=(const Size& other)
+ {
+ return calculateArea() >= other.calculateArea();
+ }
+
+ inline bool operator<(double area) { return calculateArea() < area; }
+ inline bool operator>(double area) { return calculateArea() > area; }
+ inline bool operator<=(double area) { return calculateArea() <= area; }
+ inline bool operator>=(double area) { return calculateArea() >= area; }
+
+ // Arithmetic Operators
+ Size& operator+=(const Size& s)
+ {
+ m_width += s.m_width;
+ m_height += s.m_height;
+ return *this;
+ }
+
+ Size& operator-=(const Size& s)
+ {
+ m_width -= s.m_width;
+ m_height -= s.m_height;
+ return *this;
+ }
+
+ Size& operator*=(double mult)
+ {
+ m_width *= mult;
+ m_height *= mult;
+ return *this;
+ }
+
+ Size& operator/=(double div)
+ {
+ m_width /= div;
+ m_height /= div;
+ return *this;
+ }
+
+ // TODO: add ++size, size++, --size, size--
+
+ // External operators
+ friend inline bool operator!=(const Size&, const Size&);
+ friend inline const Size operator+(const Size&, const Size&);
+ friend inline const Size operator-(const Size&, const Size&);
+ friend inline const Size operator*(const Size&, double);
+ friend inline const Size operator*(double, const Size&);
+ friend inline const Size operator/(const Size&, double);
+
+ friend inline bool operator<(double, const Size&);
+ friend inline bool operator>(double, const Size&);
+ friend inline bool operator<=(double, const Size&);
+ friend inline bool operator>=(double, const Size&);
+
+ void show() const;
+
+private:
+ double m_width;
+ double m_height;
+};
+
+// Comparison Operators
+inline bool operator!=(const Size& s1, const Size& s2)
+{
+ return s1.m_width != s2.m_width || s1.m_height != s2.m_height;
+}
+
+inline bool operator<(double area, const Size& s)
+{
+ return area < s.calculateArea();
+}
+
+inline bool operator>(double area, const Size& s)
+{
+ return area > s.calculateArea();
+}
+
+inline bool operator<=(double area, const Size& s)
+{
+ return area <= s.calculateArea();
+}
+
+inline bool operator>=(double area, const Size& s)
+{
+ return area >= s.calculateArea();
+}
+
+// Arithmetic Operators
+inline const Size operator+(const Size& s1, const Size& s2)
+{
+ return Size(s1.m_width + s2.m_width, s1.m_height + s2.m_height);
+}
+
+inline const Size operator-(const Size& s1, const Size& s2)
+{
+ return Size(s1.m_width - s2.m_width, s1.m_height - s2.m_height);
+}
+
+inline const Size operator*(const Size& s, double mult)
+{
+ return Size(s.m_width * mult, s.m_height * mult);
+}
+
+inline const Size operator*(double mult, const Size& s)
+{
+ return Size(s.m_width * mult, s.m_height * mult);
+}
+
+inline const Size operator/(const Size& s, double div)
+{
+ return Size(s.m_width / div, s.m_height / div);
+}
+
+#endif // SIZE_H
+
diff --git a/tests/run_test.sh b/tests/run_test.sh
new file mode 100755
index 00000000..ed86ea30
--- /dev/null
+++ b/tests/run_test.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+
+# This is a nasty workaround of a CTest limitation
+# of setting the environment variables for the test.
+
+
+LIB_PATH=$LD_LIBRARY_PATH:$1
+PYTHON_PATH=$PYTHONPATH:$2
+PYTHON_EXEC=$3
+TEST_FILE=$4
+
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIB_PATH PYTHONPATH=$PYTHON_PATH $PYTHON_EXEC $TEST_FILE
+
diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt
new file mode 100644
index 00000000..e89d7d76
--- /dev/null
+++ b/tests/samplebinding/CMakeLists.txt
@@ -0,0 +1,44 @@
+project(sample)
+
+set(sample_TYPESYSTEM
+${CMAKE_CURRENT_SOURCE_DIR}/typesystem_sample.xml
+)
+
+set(sample_SRC
+${CMAKE_CURRENT_BINARY_DIR}/sample/abstractmodifications_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/abstract_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/implicitconv_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/listuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/modifications_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pairuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/reference_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp
+)
+
+add_custom_command(OUTPUT ${sample_SRC}
+COMMAND ${CMAKE_BINARY_DIR}/shiboken
+ ${CMAKE_CURRENT_SOURCE_DIR}/global.h
+ --include-paths=${libsample_SOURCE_DIR}
+ --typesystem-paths=${CMAKE_CURRENT_SOURCE_DIR}
+ --output-directory=${CMAKE_CURRENT_BINARY_DIR}
+ ${sample_TYPESYSTEM}
+WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+COMMENT "Running generator for test binding..."
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${PYTHON_INCLUDE_PATH}
+ ${libsample_SOURCE_DIR}
+ ${libshiboken_SOURCE_DIR})
+add_library(sample MODULE ${sample_SRC})
+set_property(TARGET sample PROPERTY PREFIX "")
+target_link_libraries(sample
+ libsample
+ ${PYTHON_LIBRARIES}
+ libshiboken)
+
diff --git a/tests/samplebinding/abstract_test.py b/tests/samplebinding/abstract_test.py
new file mode 100755
index 00000000..9d4c51f2
--- /dev/null
+++ b/tests/samplebinding/abstract_test.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+'''Test cases for Abstract class'''
+
+import sys
+import unittest
+
+from sample import Abstract
+
+class Incomplete(Abstract):
+ def __init__(self):
+ Abstract.__init__(self)
+
+class Concrete(Abstract):
+ def __init__(self):
+ Abstract.__init__(self)
+ self.pure_virtual_called = False
+ self.unpure_virtual_called = False
+
+ def pureVirtual(self):
+ self.pure_virtual_called = True
+
+ def unpureVirtual(self):
+ self.unpure_virtual_called = True
+
+
+class AbstractTest(unittest.TestCase):
+ '''Test case for Abstract class'''
+
+ def testAbstractPureVirtualMethodAvailability(self):
+ '''Test if Abstract class pure virtual method was properly wrapped.'''
+ self.assert_('pureVirtual' in dir(Abstract))
+
+ def testAbstractInstanciation(self):
+ '''Test if instanciation of an abstract class raises the correct exception.'''
+ self.assertRaises(NotImplementedError, Abstract)
+
+ def testUnimplementedPureVirtualMethodCall(self):
+ '''Test if calling a pure virtual method raises the correct exception.'''
+ i = Incomplete()
+ self.assertRaises(NotImplementedError, i.pureVirtual)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if instanciation of an abstract class raises the correct exception.'''
+ i = Concrete()
+ self.assertRaises(NotImplementedError, i.callPureVirtual)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a virtual method is correctly called from C++.'''
+ c = Concrete()
+ c.callUnpureVirtual()
+ self.assert_(c.unpure_virtual_called)
+
+ def testImplementedPureVirtualMethodCall(self):
+ '''Test if a Python override of a pure virtual method is correctly called from C++.'''
+ c = Concrete()
+ c.callPureVirtual()
+ self.assert_(c.pure_virtual_called)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/complex_conversions.h b/tests/samplebinding/complex_conversions.h
new file mode 100644
index 00000000..8caaef03
--- /dev/null
+++ b/tests/samplebinding/complex_conversions.h
@@ -0,0 +1,23 @@
+template<>
+struct Converter<Complex>
+{
+ static PyObject* toPython(ValueHolder<Complex> cpx)
+ {
+ /*
+ fprintf(stderr, "[%s:%d] cpx.real: %f, cpx.imag: %f\n",
+ __PRETTY_FUNCTION__, __LINE__, cpx.value.real(), cpx.value.imag());
+ PyObject* result = PyComplex_FromDoubles(cpx.value.real(), cpx.value.imag());
+ fprintf(stderr, "[%s:%d]", __PRETTY_FUNCTION__, __LINE__);
+ PyObject_Print(result, stderr, 0);
+ fprintf(stderr, "\n");
+ return result;
+ */
+ return PyComplex_FromDoubles(cpx.value.real(), cpx.value.imag());
+ }
+ static Complex toCpp(PyObject* pyobj)
+ {
+ double real = PyComplex_RealAsDouble(pyobj);
+ double imag = PyComplex_ImagAsDouble(pyobj);
+ return Complex(real, imag);
+ }
+};
diff --git a/tests/samplebinding/complex_test.py b/tests/samplebinding/complex_test.py
new file mode 100755
index 00000000..92da6109
--- /dev/null
+++ b/tests/samplebinding/complex_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+
+'''Test cases for Complex class'''
+
+import sys
+import unittest
+
+import sample
+from sample import Point
+
+class ComplexTest(unittest.TestCase):
+ '''Test case for conversions between C++ Complex class to Python complex class'''
+
+ def testFunctionReturningComplexObject(self):
+ '''Test function returning a C++ Complex object.'''
+ cpx = sample.transmutePointIntoComplex(Point(5.0, 2.3))
+ self.assertEqual(cpx, complex(5.0, 2.3))
+
+ def testFunctionReceivingComplexObjectAsArgument(self):
+ '''Test function returning a C++ Complex object.'''
+ pt = sample.transmuteComplexIntoPoint(complex(1.2, 3.4))
+ # these assertions intentionally avoids to test the == operator,
+ # it should have its own test cases.
+ self.assertEqual(pt.x(), 1.2)
+ self.assertEqual(pt.y(), 3.4)
+
+ def testComplexList(self):
+ '''Test list of C++ Complex objects conversion to a list of Python complex objects.'''
+ # the global function gimmeComplexList() is expected to return a list
+ # containing the following Complex values: [0j, 1.1+2.2j, 1.3+2.4j]
+ cpxlist = sample.gimmeComplexList()
+ self.assertEqual(cpxlist, [complex(), complex(1.1, 2.2), complex(1.3, 2.4)])
+
+ def testSumComplexPair(self):
+ '''Test sum of a tuple containing two complex objects.'''
+ cpx1 = complex(1.2, 3.4)
+ cpx2 = complex(5.6, 7.8)
+ self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), cpx1 + cpx2)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/derived_test.py b/tests/samplebinding/derived_test.py
new file mode 100755
index 00000000..22d49470
--- /dev/null
+++ b/tests/samplebinding/derived_test.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+
+'''Test cases for Derived class'''
+
+import sys
+import unittest
+
+import sample
+from sample import Abstract, Derived, PolymorphicFuncEnum
+
+class Deviant(Derived):
+ def __init__(self):
+ Derived.__init__(self)
+ self.pure_virtual_called = False
+ self.unpure_virtual_called = False
+
+ def pureVirtual(self):
+ self.pure_virtual_called = True
+
+ def unpureVirtual(self):
+ self.unpure_virtual_called = True
+
+ def className(self):
+ return 'Deviant'
+
+class DerivedTest(unittest.TestCase):
+ '''Test case for Derived class'''
+
+ def testParentClassMethodsAvailability(self):
+ '''Test if Derived class really inherits its methods from parent.'''
+ inherited_methods = set(['callPureVirtual', 'callUnpureVirtual',
+ 'id_', 'pureVirtual', 'unpureVirtual'])
+ self.assert_(inherited_methods.issubset(dir(Derived)))
+
+ def testPolymorphicMethodCall(self):
+ '''Test if the correct polymorphic method is being called.'''
+ derived = Derived()
+
+ result = derived.polymorphic(1, 2)
+ self.assertEqual(type(result), PolymorphicFuncEnum)
+ self.assertEqual(result, sample.PolymorphicFunc_ii)
+
+ result = derived.polymorphic(3)
+ self.assertEqual(type(result), PolymorphicFuncEnum)
+ self.assertEqual(result, sample.PolymorphicFunc_ii)
+
+ result = derived.polymorphic(4.4)
+ self.assertEqual(type(result), PolymorphicFuncEnum)
+ self.assertEqual(result, sample.PolymorphicFunc_d)
+
+ def testOtherPolymorphicMethodCall(self):
+ '''Another test to check polymorphic method calling, just to double check.'''
+ derived = Derived()
+
+ result = derived.otherPolymorphic(1, 2, True, 3.3)
+ self.assertEqual(type(result), Derived.OtherPolymorphicFuncEnum)
+ self.assertEqual(result, sample.Derived.OtherPolymorphicFunc_iibd)
+
+ result = derived.otherPolymorphic(1, 2.2)
+ self.assertEqual(type(result), Derived.OtherPolymorphicFuncEnum)
+ self.assertEqual(result, Derived.OtherPolymorphicFunc_id)
+
+ def testPolymorphicMethodCallWithDifferentNumericTypes(self):
+ '''Test if the correct polymorphic method accepts a different numeric type as argument.'''
+ derived = Derived()
+ result = derived.polymorphic(1.1, 2.2)
+ self.assertEqual(type(result), PolymorphicFuncEnum)
+ self.assertEqual(result, sample.PolymorphicFunc_ii)
+
+ def testPolymorphicMethodCallWithWrongNumberOfArguments(self):
+ '''Test if a call to a polymorphic method with the wrong number of arguments raises an exception.'''
+ derived = Derived()
+ self.assertRaises(TypeError, lambda : derived.otherPolymorphic(1, 2, True))
+
+ def testReimplementedPureVirtualMethodCall(self):
+ '''Test if a Python override of a implemented pure virtual method is correctly called from C++.'''
+ d = Deviant()
+ d.callPureVirtual()
+ self.assert_(d.pure_virtual_called)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+ d = Deviant()
+ d.callUnpureVirtual()
+ self.assert_(d.unpure_virtual_called)
+
+ def testVirtualMethodCallString(self):
+ '''Test virtual method call returning string.'''
+ d = Derived()
+ self.assertEqual(d.className(), 'Derived')
+ self.assertEqual(d.getClassName(), 'Derived')
+
+ def testReimplementedVirtualMethodCallReturningString(self):
+ '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+ d = Deviant()
+ self.assertEqual(d.className(), 'Deviant')
+ self.assertEqual(d.getClassName(), 'Deviant')
+
+ def testSingleArgument(self):
+ '''Test singleArgument call.'''
+ d = Derived()
+ self.assert_(d.singleArgument(False))
+ self.assert_(not d.singleArgument(True))
+
+ def testMethodCallWithDefaultValue(self):
+ '''Test method call with default value.'''
+ d = Derived()
+ self.assertEqual(d.defaultValue(3), 3.1)
+ self.assertEqual(d.defaultValue(), 0.1)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/enum_test.py b/tests/samplebinding/enum_test.py
new file mode 100755
index 00000000..699adced
--- /dev/null
+++ b/tests/samplebinding/enum_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+'''Test cases for Python representation of C++ enums'''
+
+import sys
+import unittest
+
+from sample import SampleNamespace
+
+class EnumTest(unittest.TestCase):
+ '''Test case for Abstract class'''
+
+ def testPassingIntegerOnEnumArgument(self):
+ '''Test if replacing an enum argument with an integer raises an exception.'''
+ self.assertRaises(TypeError, lambda : SampleNamespace.getNumber(1))
+
+ def testExtendingEnum(self):
+ '''Test if can create new items for an enum declared as extensible on the typesystem file.'''
+ name, value = 'NewItem', 13
+ enumitem = SampleNamespace.Option(name, value)
+ self.assert_(type(enumitem), SampleNamespace.Option)
+ self.assert_(enumitem.name, name)
+ self.assert_(int(enumitem), value)
+
+ def testExtendingNonExtensibleEnum(self):
+ '''Test if trying to create a new enum item for an unextensible enum raises an exception.'''
+ self.assertRaises(TypeError, lambda : SampleNamespace.InValue(13))
+
+ def testEnumConversionToAndFromPython(self):
+ '''Test conversion of enum objects to Python and C++ in both directions.'''
+ enumout = SampleNamespace.enumInEnumOut(SampleNamespace.TwoIn)
+ self.assert_(enumout, SampleNamespace.TwoOut)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/global.h b/tests/samplebinding/global.h
new file mode 100644
index 00000000..b5ae6a8a
--- /dev/null
+++ b/tests/samplebinding/global.h
@@ -0,0 +1,14 @@
+#include "abstract.h"
+#include "derived.h"
+#include "point.h"
+#include "size.h"
+#include "complex.h"
+#include "functions.h"
+#include "kindergarten.h"
+#include "pairuser.h"
+#include "listuser.h"
+#include "samplenamespace.h"
+#include "modifications.h"
+#include "implicitconv.h"
+#include "reference.h"
+
diff --git a/tests/samplebinding/implicitconv_test.py b/tests/samplebinding/implicitconv_test.py
new file mode 100755
index 00000000..30dd870e
--- /dev/null
+++ b/tests/samplebinding/implicitconv_test.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+'''Test cases for implicit conversions'''
+
+import sys
+import unittest
+
+from sample import ImplicitConv
+
+class ImplicitConvTest(unittest.TestCase):
+ '''Test case for implicit conversions'''
+
+ def testImplicitConversions(self):
+ '''Test if polymorphic function call decisor takes implicit conversions into account.'''
+ ic = ImplicitConv.implicitConvCommon(ImplicitConv())
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorNone)
+
+ ic = ImplicitConv.implicitConvCommon(3)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorOne)
+ self.assertEqual(ic.objId(), 3)
+
+ ic = ImplicitConv.implicitConvCommon(ImplicitConv.CtorThree)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorThree)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/list_conversions.h b/tests/samplebinding/list_conversions.h
new file mode 100644
index 00000000..f512f98a
--- /dev/null
+++ b/tests/samplebinding/list_conversions.h
@@ -0,0 +1,29 @@
+template <typename StdList>
+struct Converter_std_list
+{
+ static PyObject* toPython(ValueHolder<StdList> holder)
+ {
+ PyObject* result = PyList_New((int) holder.value.size());
+ typedef typename StdList::iterator IT;
+ IT it;
+ int idx = 0;
+ for (it = holder.value.begin(); it != holder.value.end(); it++) {
+ ValueHolder<typename StdList::value_type> vh(*it);
+ PyList_SET_ITEM(result, idx, Converter<typename StdList::value_type>::toPython(vh));
+ idx++;
+ }
+ return result;
+ }
+ static StdList toCpp(PyObject* pyobj)
+ {
+ StdList result;
+ for (int i = 0; i < PyTuple_GET_SIZE(pyobj); i++) {
+ PyObject* pyItem = PyTuple_GET_ITEM(pyobj, i);
+ result.push_back(Converter<typename StdList::value_type>::toCpp(pyItem));
+ }
+ return result;
+ }
+};
+
+template<typename T>
+struct Converter<std::list<T> > : Converter_std_list<std::list<T> > {};
diff --git a/tests/samplebinding/modifications_test.py b/tests/samplebinding/modifications_test.py
new file mode 100755
index 00000000..33d420f3
--- /dev/null
+++ b/tests/samplebinding/modifications_test.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+
+'''Test cases for method modifications performed as described on typesystem. '''
+
+import sys
+import unittest
+
+from sample import Modifications, Point
+
+class ExtModifications(Modifications):
+ def __init__(self):
+ Modifications.__init__(self)
+
+ def name(self):
+ return 'ExtModifications'
+
+
+class ModificationsTest(unittest.TestCase):
+ '''Test cases for method modifications performed as described on typesystem. '''
+
+ def setUp(self):
+ self.mods = Modifications()
+
+ def tearDown(self):
+ del self.mods
+
+ def testClassMembersAvailability(self):
+ '''Test if Modified class really have the expected members.'''
+ expected_members = set(['PolymorphicModFunc', 'PolymorphicNone',
+ 'Polymorphic_ibiP', 'Polymorphic_ibib',
+ 'Polymorphic_ibid', 'Polymorphic_ibii',
+ 'calculateArea', 'doublePlus', 'increment',
+ 'multiplyPointCoordsPlusValue', 'name',
+ 'pointToPair', 'polymorphic', 'power',
+ 'timesTen'])
+ self.assert_(expected_members.issubset(dir(Modifications)))
+
+ def testRenamedMethodAvailability(self):
+ '''Test if Modification class really have renamed the 'className' virtual method to 'name'.'''
+ self.assert_('className' not in dir(Modifications))
+ self.assert_('name' in dir(Modifications))
+
+ def testReimplementationOfRenamedVirtualMethod(self):
+ '''Test if class inheriting from Modification class have the reimplementation of renamed virtual method called.'''
+ em = ExtModifications()
+ self.assertEqual(self.mods.name(), 'Modifications')
+ self.assertEqual(em.name(), 'ExtModifications')
+
+ def testRegularMethodRenaming(self):
+ '''Test if Modifications::cppMultiply was correctly renamed to calculateArea.'''
+ self.assert_('cppMultiply' not in dir(Modifications))
+ self.assert_('calculateArea' in dir(Modifications))
+ self.assertEqual(self.mods.calculateArea(3, 6), 3 * 6)
+
+ def testRegularMethodRemoval(self):
+ '''Test if 'Modifications::exclusiveCppStuff' was removed from Python bindings.'''
+ self.assert_('exclusiveCppStuff' not in dir(Modifications))
+
+ def testArgumentRemoval(self):
+ '''Test if second argument of Modifications::doublePlus(int, int) was removed.'''
+ self.assertRaises(TypeError, lambda : self.mods.doublePlus(3, 7))
+ self.assertEqual(self.mods.doublePlus(7), 14)
+
+ def testDefaultValueRemoval(self):
+ '''Test if default value was removed from first argument of Modifications::increment(int).'''
+ self.assertRaises(TypeError, self.mods.increment)
+ self.assertEqual(self.mods.increment(7), 8)
+
+ def testDefaultValueReplacement(self):
+ '''Test if default values for both arguments of Modifications::power(int, int) were modified.'''
+ # original default values: int power(int base = 1, int exponent = 0);
+ self.assertNotEqual(self.mods.power(4), 1)
+ # modified default values: int power(int base = 2, int exponent = 1);
+ self.assertEqual(self.mods.power(), 2)
+ self.assertEqual(self.mods.power(3), 3)
+ self.assertEqual(self.mods.power(5, 3), 5**3)
+
+ def testSetNewDefaultValue(self):
+ '''Test if default value was correctly set to 10 for first argument of Modifications::timesTen(int).'''
+ self.assertEqual(self.mods.timesTen(7), 70)
+ self.assertEqual(self.mods.timesTen(), 100)
+
+ def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates1(self):
+ '''Test modifications to method signature and return value using typesystem templates (case 1).'''
+ result, ok = self.mods.pointToPair(Point(2, 5))
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(type(result), tuple)
+ self.assertEqual(len(result), 2)
+ self.assertEqual(type(result[0]), float)
+ self.assertEqual(type(result[1]), float)
+ self.assertEqual(result[0], 2.0)
+ self.assertEqual(result[1], 5.0)
+
+ def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates2(self):
+ '''Test modifications to method signature and return value using typesystem templates (case 2).'''
+ result, ok = self.mods.multiplyPointCoordsPlusValue(Point(2, 5), 4.1)
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(type(result), float)
+ self.assertEqual(result, 14.1)
+
+ def testPolymorphicMethodModifications(self):
+ '''Tests modifications to a polymorphic method'''
+ # polymorphic(int, bool[removed], int, double)
+ self.assertEqual(self.mods.polymorphic(1, 2, 3.1), Modifications.Polymorphic_ibid)
+ # polymorphic(int, bool, int[removed,default=321], int)
+ self.assertEqual(self.mods.polymorphic(1, True, 2), Modifications.Polymorphic_ibii)
+ # the others weren't modified
+ self.assertEqual(self.mods.polymorphic(1, True, 2, False), Modifications.Polymorphic_ibib)
+ self.assertEqual(self.mods.polymorphic(1, False, 2, Point(3, 4)), Modifications.Polymorphic_ibiP)
+ self.assertRaises(TypeError, lambda : self.mods.polymorphic(1, True, Point(2, 3), Point(4, 5)))
+ self.assertEqual(self.mods.poly(1, True, Point(2, 3), Point(4, 5)), Modifications.Polymorphic_ibPP)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/pair_conversions.h b/tests/samplebinding/pair_conversions.h
new file mode 100644
index 00000000..8adf2f6f
--- /dev/null
+++ b/tests/samplebinding/pair_conversions.h
@@ -0,0 +1,25 @@
+template <typename StdPair>
+struct Converter_std_pair
+{
+ static PyObject* toPython(ValueHolder<StdPair> holder)
+ {
+ ValueHolder<typename StdPair::first_type> first(holder.value.first);
+ ValueHolder<typename StdPair::second_type> second(holder.value.second);
+ PyObject* tuple = PyTuple_New(2);
+ PyTuple_SET_ITEM(tuple, 0, Converter<typename StdPair::first_type>::toPython(first));
+ PyTuple_SET_ITEM(tuple, 1, Converter<typename StdPair::second_type>::toPython(second));
+ return tuple;
+ }
+ static StdPair toCpp(PyObject* pyobj)
+ {
+ StdPair result;
+ PyObject* pyFirst = PyTuple_GET_ITEM(pyobj, 0);
+ PyObject* pySecond = PyTuple_GET_ITEM(pyobj, 1);
+ result.first = Converter<typename StdPair::first_type>::toCpp(pyFirst);
+ result.second = Converter<typename StdPair::second_type>::toCpp(pySecond);
+ return result;
+ }
+};
+
+template<typename FT, typename ST>
+struct Converter<std::pair<FT, ST> > : Converter_std_pair<std::pair<FT, ST> > {};
diff --git a/tests/samplebinding/point_test.py b/tests/samplebinding/point_test.py
new file mode 100755
index 00000000..69ef1eef
--- /dev/null
+++ b/tests/samplebinding/point_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+
+'''Test cases for Point class'''
+
+import sys
+import unittest
+
+from sample import Point
+
+class PointTest(unittest.TestCase):
+ '''Test case for Point class, including operator overloads.'''
+
+ def testConstructor(self):
+ '''Test Point class constructor.'''
+ pt = Point(5.0, 2.3)
+ self.assertEqual(pt.x(), 5.0)
+ self.assertEqual(pt.y(), 2.3)
+
+ def testPlusOperator(self):
+ '''Test Point class + operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(0.5, 3.2)
+ self.assertEqual(pt1 + pt2, Point(5.0 + 0.5, 2.3 + 3.2))
+
+ def testEqualOperator(self):
+ '''Test Point class == operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(5.0, 2.3)
+ pt3 = Point(0.5, 3.2)
+ self.assertTrue(pt1 == pt1)
+ self.assertTrue(pt1 == pt2)
+ self.assertFalse(pt1 == pt3)
+
+ def testNotEqualOperator(self):
+ '''Test Point class != operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(5.0, 2.3)
+ self.assertRaises(NotImplementedError, lambda : pt1.__ne__(pt2))
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/reference_test.py b/tests/samplebinding/reference_test.py
new file mode 100755
index 00000000..ed4c5cbc
--- /dev/null
+++ b/tests/samplebinding/reference_test.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+'''Test cases for methods that receive references to objects.'''
+
+import sys
+import unittest
+
+from sample import Reference
+
+class ReferenceTest(unittest.TestCase):
+ '''Test case for methods that receive references to objects.'''
+
+ def testMethodThatReceivesReference(self):
+ '''Test a method that receives a reference to an object as argument.'''
+ objId = 123
+ r = Reference(objId)
+ self.assertEqual(Reference.usesReference(r), objId)
+
+ def testMethodThatReceivesConstReference(self):
+ '''Test a method that receives a const reference to an object as argument.'''
+ objId = 123
+ r = Reference(objId)
+ self.assertEqual(Reference.usesConstReference(r), objId)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/sample_test.py b/tests/samplebinding/sample_test.py
new file mode 100755
index 00000000..9de201a2
--- /dev/null
+++ b/tests/samplebinding/sample_test.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+
+'''Test cases for libsample bindings module'''
+
+import sys
+import unittest
+
+import sample
+
+class ModuleTest(unittest.TestCase):
+ '''Test case for module and global functions'''
+
+ def testModuleMembers(self):
+ '''Test availability of classes, global functions and other members on binding'''
+ expected_members = set(['Abstract', 'Derived', 'ListUser', 'PairUser',
+ 'Point', 'gimmeComplexList', 'gimmeDouble',
+ 'gimmeInt', 'makeCString', 'multiplyPair',
+ 'returnCString', 'transmuteComplexIntoPoint',
+ 'transmutePointIntoComplex', 'sumComplexPair',
+ 'SampleNamespace', 'GlobalEnum', 'NoThing',
+ 'FirstThing', 'SecondThing', 'ThirdThing'])
+ self.assert_(expected_members.issubset(dir(sample)))
+
+ def testAbstractPrintFormatEnum(self):
+ '''Test availability of PrintFormat enum from Abstract class'''
+ enum_members = set(['PrintFormat', 'Short', 'Verbose',
+ 'OnlyId', 'ClassNameAndId'])
+ self.assert_(enum_members.issubset(dir(sample.Abstract)))
+
+ def testSampleNamespaceOptionEnum(self):
+ '''Test availability of Option enum from SampleNamespace namespace'''
+ enum_members = set(['Option', 'None', 'RandomNumber', 'UnixTime'])
+ self.assert_(enum_members.issubset(dir(sample.SampleNamespace)))
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/size_test.py b/tests/samplebinding/size_test.py
new file mode 100755
index 00000000..dcfc9d9d
--- /dev/null
+++ b/tests/samplebinding/size_test.py
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+
+'''Test cases for operator overloads on Size class'''
+
+import sys
+import unittest
+
+from sample import Size
+
+class PointTest(unittest.TestCase):
+ '''Test case for Size class, including operator overloads.'''
+
+ def testConstructor(self):
+ '''Test Size class constructor.'''
+ width, height = (5.0, 2.3)
+ size = Size(width, height)
+ self.assertEqual(size.width(), width)
+ self.assertEqual(size.height(), height)
+ self.assertEqual(size.calculateArea(), width * height)
+
+ def testPlusOperator(self):
+ '''Test Size class + operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertEqual(s1 + s2, Size(5.0 + 0.5, 2.3 + 3.2))
+
+ def testEqualOperator(self):
+ '''Test Size class == operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 == s1)
+ self.assertTrue(s1 == s2)
+ self.assertFalse(s1 == s3)
+
+ def testNotEqualOperator(self):
+ '''Test Size class != operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertFalse(s1 != s1)
+ self.assertFalse(s1 != s2)
+ self.assertTrue(s1 != s3)
+
+ def testMinorEqualOperator(self):
+ '''Test Size class <= operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 <= s1)
+ self.assertTrue(s1 <= s2)
+ self.assertTrue(s3 <= s1)
+ self.assertFalse(s1 <= s3)
+
+ def testMinorOperator(self):
+ '''Test Size class < operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertFalse(s1 < s1)
+ self.assertFalse(s1 < s2)
+ self.assertTrue(s2 < s1)
+
+ def testMajorEqualOperator(self):
+ '''Test Size class >= operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 >= s1)
+ self.assertTrue(s1 >= s2)
+ self.assertTrue(s1 >= s3)
+ self.assertFalse(s3 >= s1)
+
+ def testMajorOperator(self):
+ '''Test Size class > operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertFalse(s1 > s1)
+ self.assertTrue(s1 > s2)
+ self.assertFalse(s2 > s1)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml
new file mode 100644
index 00000000..c049ea9e
--- /dev/null
+++ b/tests/samplebinding/typesystem_sample.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0"?>
+<typesystem package="sample">
+ <primitive-type name="bool"/>
+ <primitive-type name="double"/>
+ <primitive-type name="int"/>
+ <primitive-type name="char"/>
+
+ <primitive-type name="Complex" target-lang-api-name="PyComplex">
+ <conversion-rule file="complex_conversions.h"/>
+ </primitive-type>
+
+ <container-type name="std::pair" type="pair">
+ <conversion-rule file="pair_conversions.h"/>
+ <include file-name="utility" location="global"/>
+ </container-type>
+ <container-type name="std::list" type="list">
+ <conversion-rule file="list_conversions.h"/>
+ <include file-name="list" location="global"/>
+ </container-type>
+
+ <enum-type name="Abstract::PrintFormat"/>
+ <enum-type name="PolymorphicFuncEnum"/>
+ <enum-type name="Derived::OtherPolymorphicFuncEnum"/>
+ <enum-type name="Modifications::PolymorphicModFunc"/>
+ <enum-type name="ImplicitConv::CtorEnum"/>
+ <!-- BUG:
+ renaming the ICPolymorphicFuncEnum to the same name
+ of a global enum causes the generator to confuse the
+ two types.
+ -->
+ <enum-type name="ImplicitConv::ICPolymorphicFuncEnum"/>
+ <enum-type name="SampleNamespace::Option" extensible="yes"/>
+ <enum-type name="SampleNamespace::InValue"/>
+ <enum-type name="SampleNamespace::OutValue"/>
+ <enum-type name="GlobalEnum"/>
+ <enum-type name="GlobalPolyFuncEnum"/>
+
+ <namespace-type name="SampleNamespace"/>
+
+ <object-type name="Abstract">
+ <modify-function signature="id()" rename="id_"/>
+ </object-type>
+
+ <object-type name="Derived"/>
+
+ <template name="boolptr_at_end_fix_beginning">
+ bool __ok__;
+ %0 = ((%TYPE*) ((Shiboken::PyBaseWrapper*) self)->cptr)->
+ %TYPE::%FUNCTION_NAME(%ARGUMENT_NAMES, &amp;__ok__);
+ </template>
+
+ <template name="boolptr_at_start_fix_beginning">
+ bool __ok__;
+ %0 = ((%TYPE*) ((Shiboken::PyBaseWrapper*) self)->cptr)->
+ %TYPE::%FUNCTION_NAME(&amp;__ok__, %ARGUMENT_NAMES);
+ </template>
+
+ <template name="boolptr_fix_end">
+ PyObject* _item_;
+ PyObject* _tuple_ = PyTuple_New(2);
+ _item_ = Shiboken::Converter&lt; %RETURN_TYPE &gt;::toPython(Shiboken::ValueHolder&lt; %RETURN_TYPE &gt;(%0));
+ PyTuple_SET_ITEM(_tuple_, 0, _item_);
+ _item_ = Shiboken::Converter&lt;bool&gt;::toPython(Shiboken::ValueHolder&lt;bool&gt;(__ok__));
+ PyTuple_SET_ITEM(_tuple_, 1, _item_);
+ return _tuple_;
+ </template>
+
+ <object-type name="Modifications">
+
+ <modify-function signature="polymorphic(int, bool, int, double)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <inject-code class="native" position="beginning">
+ %0 = ((%TYPE*) ((Shiboken::PyBaseWrapper*) self)->cptr)->
+ %TYPE::%FUNCTION_NAME(%1, true, %3, %4);
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="polymorphic(int, bool, int, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <replace-default-expression with="321"/>
+ </modify-argument>
+ <!--
+ <modify-argument index="4">
+ <remove-default-expression/>
+ </modify-argument>
+ -->
+ </modify-function>
+
+ <!--
+ this alteration will trigger an interesting
+ compile time error on the binding
+ -->
+ <!--
+ <modify-function signature="polymorphic(int, bool, Point, Point)">
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+ -->
+
+ <!--
+ renaming this signature should remove it from the other
+ polymorphic methods decision tree
+ -->
+ <modify-function signature="polymorphic(int, bool, Point, Point)" rename="poly"/>
+
+ <!--
+ 'ok' must be removed and the return value will be changed
+ to a tuple (PyObject*) containing the expected result plus
+ the 'ok' value as a Python boolean
+ -->
+ <modify-function signature="pointToPair(Point, bool*)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="native" position="beginning">
+ <insert-template name="boolptr_at_end_fix_beginning"/>
+ </inject-code>
+ <inject-code class="native" position="end">
+ <insert-template name="boolptr_fix_end"/>
+ </inject-code>
+ </modify-function>
+
+ <!-- same as 'pointToPair' except that this time 'ok' is the first argument -->
+ <modify-function signature="multiplyPointCoordsPlusValue(bool*, Point, double)">
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="native" position="beginning">
+ <insert-template name="boolptr_at_start_fix_beginning"/>
+ </inject-code>
+ <inject-code class="native" position="end">
+ <insert-template name="boolptr_fix_end"/>
+ </inject-code>
+ </modify-function>
+
+ <!-- completely remove 'plus' from the Python side -->
+ <modify-function signature="doublePlus(int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- the default value for both arguments must be changed in Python -->
+ <modify-function signature="power(int, int)">
+ <modify-argument index="1">
+ <replace-default-expression with="2"/>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-default-expression with="1"/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- in Python set argument default value to 10 -->
+ <modify-function signature="timesTen(int)">
+ <modify-argument index="1">
+ <replace-default-expression with="10"/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- in Python remove the argument default value -->
+ <modify-function signature="increment(int)">
+ <modify-argument index="1">
+ <remove-default-expression/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- don't export this method to Python -->
+ <modify-function signature="exclusiveCppStuff()" remove="all"/>
+
+ <!-- change the name of this regular method -->
+ <modify-function signature="cppMultiply(int, int)" rename="calculateArea"/>
+
+ <!-- change the name of this virtual method -->
+ <modify-function signature="className()" rename="name"/>
+ </object-type>
+
+ <object-type name="AbstractModifications">
+ <!--
+ completely removing the pure virtual method from this
+ class will generate an #error directive.
+ -->
+ <!--
+ <modify-function signature="pointlessPureVirtualMethod()" remove="all"/>
+ -->
+ </object-type>
+
+ <value-type name="Reference"/>
+
+ <value-type name="ImplicitConv"/>
+
+ <value-type name="Point"/>
+ <value-type name="Size"/>
+ <value-type name="PairUser"/>
+ <value-type name="ListUser"/>
+
+ <rejection class="ListUser" function-name="createList()"/>
+ <rejection class="ListUser" function-name="callCreateList()"/>
+ <rejection class="ListUser" function-name="createComplexList(Complex, Complex)"/>
+ <rejection class="ListUser" function-name="sumList(std::list&lt;int&gt;)"/>
+ <rejection class="ListUser" function-name="sumList(std::list&lt;double&gt;)"/>
+
+ <rejection class="" function-name="gimmeComplexList()"/>
+ <rejection class="" function-name="makeCString()"/>
+ <rejection class="" function-name="returnCString()"/>
+</typesystem>
+