Browse Source

Merge branch 'improve-pythonqt-support'

* improve-pythonqt-support:
  Review initialization process of PythonManager
  Add comment into ctkMacroWrapPythonQt.cmake
  Rename python package "ctkqt" into "qt"
  Use provided "vtk" python package instead custom one "ctkvtk"
  ctkMacroWrapPythonQt internally includes ctkMacroSetPaths
  ctkMacroCompilePythonScript internally includes ctkMacroParseArguments
  Test checking if slot, qinvokable and qproperty are correctly wrapped
  Added test to ctkSimplePythonShell
  ctkSimplePythonShell: CTK wrapped library automatically initialized
  Added python package "ctk", "ctkvtk" and "ctkqt"
  Improve ctkMacroCompilePythonScript
  Added option CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK
  Added option CTK_LIB_Scripting/Python/Core_PYTHONQT_WRAP_QTCORE
  Improve ctkMacroCompilePythonScript
Jean-Christophe Fillion-Robin 14 years ago
parent
commit
62a27384af
40 changed files with 987 additions and 108 deletions
  1. 64 4
      Applications/ctkSimplePythonShell/CMakeLists.txt
  2. 17 0
      Applications/ctkSimplePythonShell/Python/CMakeLists.txt
  3. 9 0
      Applications/ctkSimplePythonShell/Python/ctkSimplePythonShell.py
  4. 1 0
      Applications/ctkSimplePythonShell/Testing/CMakeLists.txt
  5. 31 0
      Applications/ctkSimplePythonShell/Testing/Python/CMakeLists.txt
  6. 13 0
      Applications/ctkSimplePythonShell/Testing/Python/ctkWidgetsTest.py
  7. 41 0
      Applications/ctkSimplePythonShell/Testing/Python/derivedQWidgetTest.py
  8. 52 0
      Applications/ctkSimplePythonShell/Testing/Python/vtkPythonSmoke.py
  9. 10 0
      Applications/ctkSimplePythonShell/Testing/Python/wrappedQInvokableTest.py
  10. 11 0
      Applications/ctkSimplePythonShell/Testing/Python/wrappedQPropertyTest.py
  11. 10 0
      Applications/ctkSimplePythonShell/Testing/Python/wrappedSlotTest.py
  12. 17 0
      Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKQInvokableTest.py
  13. 17 0
      Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKSlotTest.py
  14. 0 55
      Applications/ctkSimplePythonShell/ctkSimplePythonManager.cpp
  15. 118 0
      Applications/ctkSimplePythonShell/ctkSimplePythonManager.cpp.in
  16. 1 0
      Applications/ctkSimplePythonShell/ctkSimplePythonManager.h
  17. 8 0
      Applications/ctkSimplePythonShell/ctkSimplePythonShellConfigure.h.in
  18. 70 0
      Applications/ctkSimplePythonShell/ctkSimplePythonShellMain.cpp
  19. 27 0
      Applications/ctkSimplePythonShell/ctkTestWrappedQInvokable.h
  20. 29 0
      Applications/ctkSimplePythonShell/ctkTestWrappedQListOfVTKObject.h
  21. 31 0
      Applications/ctkSimplePythonShell/ctkTestWrappedQProperty.h
  22. 29 0
      Applications/ctkSimplePythonShell/ctkTestWrappedSlot.h
  23. 44 0
      Applications/ctkSimplePythonShell/ctkTestWrappedVTKQInvokable.h
  24. 45 0
      Applications/ctkSimplePythonShell/ctkTestWrappedVTKSlot.h
  25. 1 0
      Applications/ctkSimplePythonShell/target_libraries.cmake
  26. 100 24
      CMake/ctkMacroCompilePythonScript.cmake
  27. 3 0
      CMake/ctkMacroWrapPythonQt.cmake
  28. 10 2
      CMakeExternals/PythonQt.cmake
  29. 12 3
      CMakeExternals/VTK.cmake
  30. 18 8
      CMakeLists.txt
  31. 14 4
      Libs/Scripting/Python/Core/CMakeLists.txt
  32. 44 0
      Libs/Scripting/Python/Core/Python/CMakeLists.txt
  33. 13 0
      Libs/Scripting/Python/Core/Python/ctk/__init__.py.in
  34. 24 0
      Libs/Scripting/Python/Core/Python/qt/__init__.py
  35. 26 1
      Libs/Scripting/Python/Core/ctkAbstractPythonManager.cpp
  36. 19 5
      Libs/Scripting/Python/Core/ctkAbstractPythonManager.h
  37. 1 0
      Libs/Scripting/Python/Core/ctkScriptingPythonCoreConfigure.h.in
  38. 2 0
      Libs/Scripting/Python/Core/ctk_library_options.cmake
  39. 3 0
      Libs/Scripting/Python/Widgets/CMakeLists.txt
  40. 2 2
      SuperBuild.cmake

+ 64 - 4
Applications/ctkSimplePythonShell/CMakeLists.txt

@@ -1,22 +1,49 @@
 PROJECT(ctkSimplePythonShell)
 
 #
+# 3rd party dependencies
+#
+INCLUDE(${VTK_USE_FILE})
+
+#
 # See CTK/CMake/ctkMacroBuildApp.cmake for details
 #
 
 SET(KIT_SRCS
-  ctkSimplePythonManager.cpp
+  ${CMAKE_CURRENT_BINARY_DIR}/ctkSimplePythonManager.cpp
   ctkSimplePythonManager.h
   ctkSimplePythonQtDecorators.h
   ctkSimplePythonShellMain.cpp
+  ctkTestWrappedQProperty.h
+  ctkTestWrappedQInvokable.h
+  ctkTestWrappedSlot.h
 )
 
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  LIST(APPEND KIT_SRCS
+    ctkTestWrappedQListOfVTKObject.h
+    ctkTestWrappedVTKSlot.h
+    ctkTestWrappedVTKQInvokable.h
+    )
+ENDIF()
+
 # Headers that should run through moc
 SET(KIT_MOC_SRCS
   ctkSimplePythonManager.h
   ctkSimplePythonQtDecorators.h
+  ctkTestWrappedQProperty.h
+  ctkTestWrappedQInvokable.h
+  ctkTestWrappedSlot.h
   )
 
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  LIST(APPEND KIT_MOC_SRCS
+    ctkTestWrappedQListOfVTKObject.h
+    ctkTestWrappedVTKSlot.h
+    ctkTestWrappedVTKQInvokable.h
+    )
+ENDIF()
+
 # UI files
 SET(KIT_UI_FORMS
 )
@@ -25,6 +52,12 @@ SET(KIT_UI_FORMS
 SET(KIT_resources
 )
 
+# Set VTK_LIBRARIES variable
+SET(VTK_LIBRARIES
+  vtkCommon
+  vtkFiltering
+  )
+
 # Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
 # The following macro will read the target libraries from the file 'target_libraries.cmake'
 ctkMacroGetTargetLibraries(KIT_target_libraries)
@@ -36,10 +69,35 @@ CONFIGURE_FILE(
   )
   
 IF(CTK_WRAP_PYTHONQT_LIGHT OR CTK_WRAP_PYTHONQT_FULL)
-  LIST(APPEND KIT_target_libraries CTKCorePythonQt)
-  LIST(APPEND KIT_target_libraries CTKWidgetsPythonQt)
+
+  # Update list of target libraries with the list of available PythonQt libraries
+  # and set variables holding list of pythonqt initialization method
+  SET(CTK_PYTHONQT_INITIALIZATION_METHOD_DEFINITION)
+  SET(CTK_PYTHONQT_INITIALIZATION_METHOD_CALL)
+
+  FOREACH(lib ${CTK_LIBS})
+    ctkFunctionExtractOptionNameAndValue(${lib} lib_name lib_value)
+    IF(${CTK_LIB_${lib_name}})
+      STRING(REPLACE "/" "" lib_name_no_slash ${lib_name})
+
+      LIST(APPEND KIT_target_libraries CTK${lib_name_no_slash}PythonQt)
+
+      SET(CTK_PYTHONQT_INITIALIZATION_METHOD_DEFINITION
+        "${CTK_PYTHONQT_INITIALIZATION_METHOD_DEFINITION}
+void PythonQt_init_org_commontk_CTK${lib_name_no_slash}(PyObject*);")
+
+      SET(CTK_PYTHONQT_INITIALIZATION_METHOD_CALL
+        "${CTK_PYTHONQT_INITIALIZATION_METHOD_CALL}
+PythonQt_init_org_commontk_CTK${lib_name_no_slash}(0);")
+    ENDIF()
+  ENDFOREACH()
 ENDIF()
 
+CONFIGURE_FILE(
+  ctkSimplePythonManager.cpp.in
+  ${CMAKE_CURRENT_BINARY_DIR}/ctkSimplePythonManager.cpp
+  )
+
 ctkMacroBuildApp(
   NAME ${PROJECT_NAME}
   SRCS ${KIT_SRCS}
@@ -49,7 +107,9 @@ ctkMacroBuildApp(
   RESOURCES ${KIT_resources}
   )
 
+ADD_SUBDIRECTORY(Python)
+
 # Testing
 IF(BUILD_TESTING)
-#   ADD_SUBDIRECTORY(Testing)
+  ADD_SUBDIRECTORY(Testing)
 ENDIF(BUILD_TESTING)

+ 17 - 0
Applications/ctkSimplePythonShell/Python/CMakeLists.txt

@@ -0,0 +1,17 @@
+
+
+SET(KIT_PYTHON_SCRIPTS
+  ctkSimplePythonShell
+  )
+  
+SET(KIT_PYTHON_RESOURCES
+  )
+  
+ctkMacroCompilePythonScript(
+  TARGET_NAME ${PROJECT_NAME}
+  SCRIPTS "${KIT_PYTHON_SCRIPTS}"
+  RESOURCES "${KIT_PYTHON_RESOURCES}"
+  DESTINATION_DIR ${CTK_BINARY_DIR}/bin/Python
+  INSTALL_DIR ${CTK_INSTALL_BIN_DIR}
+  )
+  

+ 9 - 0
Applications/ctkSimplePythonShell/Python/ctkSimplePythonShell.py

@@ -0,0 +1,9 @@
+
+def app():
+  return _ctkSimplePythonShellInstance
+  
+def quit():
+  exit()
+    
+def exit():
+  app().quit()

+ 1 - 0
Applications/ctkSimplePythonShell/Testing/CMakeLists.txt

@@ -0,0 +1 @@
+ADD_SUBDIRECTORY(Python)

+ 31 - 0
Applications/ctkSimplePythonShell/Testing/Python/CMakeLists.txt

@@ -0,0 +1,31 @@
+
+SET(KIT_TESTS ${CPP_TEST_PATH}/ctkSimplePythonShell)
+
+SET(SCRIPTS
+  derivedQWidgetTest.py
+  wrappedQInvokableTest.py
+  wrappedQPropertyTest.py
+  wrappedSlotTest.py
+  )
+
+IF(CTK_LIB_Widgets)
+  LIST(APPEND SCRIPTS ctkWidgetsTest.py)
+ENDIF()
+
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  LIST(APPEND SCRIPTS
+    vtkPythonSmoke.py
+    wrappedVTKQInvokableTest.py
+    wrappedVTKSlotTest.py
+    )
+ENDIF()
+
+
+MACRO(SIMPLE_TEST_WITH_SCRIPT SCRIPT)
+  GET_FILENAME_COMPONENT(TESTNAME ${SCRIPT} NAME_WE)
+  ADD_TEST(ctkSimplePythonShell_${TESTNAME} ${KIT_TESTS} ${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT})
+ENDMACRO()
+
+FOREACH(s ${SCRIPTS})
+  SIMPLE_TEST_WITH_SCRIPT(${s})
+ENDFOREACH()

+ 13 - 0
Applications/ctkSimplePythonShell/Testing/Python/ctkWidgetsTest.py

@@ -0,0 +1,13 @@
+
+from ctk import *
+from qt import QTimer
+
+w = ctkMatrixWidget()
+w.show()
+
+if not _ctkPythonShellInstance.isInteractive:
+  #QTimer().singleShot(0, app(), SLOT('quit()'))
+  t = QTimer()
+  t.setInterval(250)
+  t.connect('timeout()', app(), 'quit()')
+  t.start()

+ 41 - 0
Applications/ctkSimplePythonShell/Testing/Python/derivedQWidgetTest.py

@@ -0,0 +1,41 @@
+
+from qt import *
+
+class ExampleWidget(QWidget):
+  def __init__(self, parent=None):
+    QWidget.__init__(self, parent)
+
+    self.setGeometry(300, 300, 250, 150)
+    self.setWindowTitle('Example Widget')
+    
+    layout = QHBoxLayout(self)
+    
+    checkbox = QCheckBox('Shell Visibility', self)
+    layout.addWidget(checkbox);
+    checkbox.setChecked(True)
+    checkbox.connect('toggled(bool)', _ctkPythonShellInstance, 'setVisible(bool)')
+    
+    self.button = QPushButton('Quit', self)
+    layout.addWidget(self.button);
+    QObject.connect(self.button, SIGNAL('clicked()'), app(), SLOT('quit()'))
+    
+    self.center()
+
+  def center(self):
+    screen = QDesktopWidget().screenGeometry()
+    size =  self.geometry
+    self.move((screen.width() - size.width())/2, (screen.height() - size.height())/2)
+    
+w = ExampleWidget()
+w.show()
+
+if not _ctkPythonShellInstance.isInteractive:
+  #QTimer().singleShot(0, app(), SLOT('quit()'))
+  t = QTimer()
+  t.setInterval(250)
+  t.connect('timeout()', app(), 'quit()')
+  t.start()
+  
+  
+
+

+ 52 - 0
Applications/ctkSimplePythonShell/Testing/Python/vtkPythonSmoke.py

@@ -0,0 +1,52 @@
+
+#
+# Copied from VTK/Common/Testing/Python/PythonSmoke.py
+#
+
+import sys
+
+try:
+  import vtk
+
+except:
+  print "Cannot import vtk"
+  sys.exit(1)
+try:
+  print dir(vtk)
+except:
+  print "Cannot print dir(vtk)"
+  sys.exit(1)
+
+try:
+  try:
+    try:
+      o = vtk.vtkLineWidget()
+      print "Using Hybrid"
+    except:
+      o = vtk.vtkActor()
+      print "Using Rendering"
+  except:
+    o = vtk.vtkObject()
+    print "Using Common"
+except:
+  print "Cannot create vtkObject"
+  sys.exit(1)
+
+try:
+  print o
+  print "Reference count: %d" % o.GetReferenceCount()
+  print "Class name: %s" % o.GetClassName()
+except:
+  print "Cannot print object"
+  sys.exit(1)
+
+try:
+  b = vtk.vtkObject()
+  d = b.SafeDownCast(o)
+  print b, d
+except:
+  print "Cannot downcast"
+  sys.exit(1)
+
+sys.exit(0)
+

+ 10 - 0
Applications/ctkSimplePythonShell/Testing/Python/wrappedQInvokableTest.py

@@ -0,0 +1,10 @@
+import sys
+
+if (_testWrappedQInvokableInstance.value() != 0):
+  sys.exit(1)
+  
+_testWrappedQInvokableInstance.setValue(74)
+if (_testWrappedQInvokableInstance.value() != 74):
+  sys.exit(1)
+  
+sys.exit(0)

+ 11 - 0
Applications/ctkSimplePythonShell/Testing/Python/wrappedQPropertyTest.py

@@ -0,0 +1,11 @@
+
+import sys
+
+if (_testWrappedQPropertyInstance.Value != 0):
+  sys.exit(1)
+  
+_testWrappedQPropertyInstance.Value = 74
+if (_testWrappedQPropertyInstance.Value != 74):
+  sys.exit(1)
+  
+sys.exit(0)

+ 10 - 0
Applications/ctkSimplePythonShell/Testing/Python/wrappedSlotTest.py

@@ -0,0 +1,10 @@
+import sys
+
+if (_testWrappedSlotInstance.value() != 0):
+  sys.exit(1)
+  
+_testWrappedSlotInstance.setValue(74)
+if (_testWrappedSlotInstance.value() != 74):
+  sys.exit(1)
+  
+sys.exit(0)

+ 17 - 0
Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKQInvokableTest.py

@@ -0,0 +1,17 @@
+
+import sys
+
+# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent 
+# call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
+# PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
+from vtk import *
+
+t = _testWrappedVTKQInvokableInstance.getTable()
+print t.GetClassName()
+
+t2 = vtkTable()
+_testWrappedVTKQInvokableInstance.setTable(t2)
+if _testWrappedVTKQInvokableInstance.getTable() != t2:
+  sys.exit(1)
+  
+sys.exit(0)

+ 17 - 0
Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKSlotTest.py

@@ -0,0 +1,17 @@
+
+import sys
+
+# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent 
+# call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
+# PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
+from vtk import *
+
+t = _testWrappedVTKSlotInstance.getTable()
+print t.GetClassName()
+
+t2 = vtkTable()
+_testWrappedVTKSlotInstance.setTable(t2)
+if _testWrappedVTKSlotInstance.getTable() != t2:
+  sys.exit(1)
+  
+sys.exit(0)

+ 0 - 55
Applications/ctkSimplePythonShell/ctkSimplePythonManager.cpp

@@ -1,55 +0,0 @@
-
-// PythonQT includes
-#include <PythonQt.h>
-
-// CTK includes
-#include "ctkSimplePythonManager.h"
-#include "ctkSimplePythonQtDecorators.h"
-
-#include "ctkScriptingPythonCoreConfigure.h" // For CTK_WRAP_PYTHONQT_{LIGHT, FULL}
-
-#if defined(CTK_WRAP_PYTHONQT_LIGHT) || defined(CTK_WRAP_PYTHONQT_FULL)
-// PythonQt wrapper initialization methods
-void PythonQt_init_org_commontk_CTKCore(PyObject*);
-void PythonQt_init_org_commontk_CTKWidgets(PyObject*);
-#endif
-
-//-----------------------------------------------------------------------------
-ctkSimplePythonManager::ctkSimplePythonManager(QObject* _parent) : Superclass(_parent)
-{
-
-}
-
-//-----------------------------------------------------------------------------
-ctkSimplePythonManager::~ctkSimplePythonManager()
-{
-}
-
-//-----------------------------------------------------------------------------
-QStringList ctkSimplePythonManager::pythonPaths()
-{  
-  QStringList paths;  
-  
-  return paths; 
-}
-
-//-----------------------------------------------------------------------------
-void ctkSimplePythonManager::preInitialization()
-{
-  Superclass::preInitialization();
-
-#if defined(CTK_WRAP_PYTHONQT_LIGHT) || defined(CTK_WRAP_PYTHONQT_FULL)
-  // Initialize wrappers
-  PythonQt_init_org_commontk_CTKCore(0);
-  PythonQt_init_org_commontk_CTKWidgets(0);
-#endif
-
-  // Register decorators
-  this->registerPythonQtDecorator(new ctkSimplePythonQtDecorators(this));  
-  
-  // Add object to python interpreter context
-  //this->addObjectToPythonMain("_qSlicerCoreApplicationInstance", app);
-
-  // Evaluate application script
-  //this->executeFile(app->slicerHome() + "/bin/Python/slicer/slicerqt.py");
-}

+ 118 - 0
Applications/ctkSimplePythonShell/ctkSimplePythonManager.cpp.in

@@ -0,0 +1,118 @@
+
+// QT includes
+#include <QFile>
+#include <QFileInfo>
+#include <QApplication>
+
+// PythonQT includes
+#include <PythonQt.h>
+
+// CTK includes
+#include "ctkSimplePythonManager.h"
+#include "ctkSimplePythonQtDecorators.h"
+
+#include "ctkSimplePythonShellConfigure.h" // For CTK_WRAP_PYTHONQT_{LIGHT, FULL}
+
+#if defined(CTK_WRAP_PYTHONQT_LIGHT) || defined(CTK_WRAP_PYTHONQT_FULL)
+// PythonQt wrapper initialization methods
+@CTK_PYTHONQT_INITIALIZATION_METHOD_DEFINITION@
+#endif
+
+#ifdef CTK_WRAP_PYTHONQT_USE_VTK
+# if defined(CMAKE_INTDIR)
+#  define VTK_PYTHON_LIBRARY_DIR VTK_PYTHON_LIBRARY_DIR_BUILD "/" CMAKE_INTDIR
+# else
+#  define VTK_PYTHON_LIBRARY_DIR VTK_PYTHON_LIBRARY_DIR_BUILD
+# endif
+#endif
+
+//-----------------------------------------------------------------------------
+ctkSimplePythonManager::ctkSimplePythonManager(QObject* _parent) : Superclass(_parent)
+{
+}
+
+//-----------------------------------------------------------------------------
+ctkSimplePythonManager::~ctkSimplePythonManager()
+{
+}
+
+//-----------------------------------------------------------------------------
+QStringList ctkSimplePythonManager::pythonPaths()
+{  
+  QStringList paths;
+  paths << Superclass::pythonPaths();
+
+  QString self_dir = QFileInfo(qApp->applicationFilePath()).absolutePath();
+
+  QString ctk_python_dir = self_dir;
+  #if defined(CMAKE_INTDIR)
+    ctk_python_dir.append("/..");
+  #endif
+  ctk_python_dir.append("/Python");
+  paths << QFileInfo(ctk_python_dir).absoluteFilePath();
+
+#ifdef CTK_WRAP_PYTHONQT_USE_VTK
+
+  // Try to put the VTK python module location in sys.path.
+  QString vtk_build_dir = "/../../CMakeExternals/Build/VTK/Wrapping/Python";
+  bool found_vtk = false;
+  QString vtk_package_dir = self_dir;
+
+#if defined(CMAKE_INTDIR)
+  vtk_package_dir.append("/..");
+#endif
+  vtk_package_dir.append(vtk_build_dir);
+  QFileInfo fi(vtk_package_dir);
+  vtk_package_dir = fi.absoluteFilePath();
+  if (fi.isDir())
+    {
+    // This executable is running from the build tree.  Prepend the
+    // library directory and package directory to the search path.
+    paths << vtk_package_dir;
+    paths << VTK_PYTHON_LIBRARY_DIR;
+    found_vtk = true;
+    }
+
+  Q_ASSERT(found_vtk);
+  if (!found_vtk)
+    {
+    // TODO Handle case when the application is started from an installed tree
+    }
+#endif
+  
+  return paths;
+}
+
+//-----------------------------------------------------------------------------
+void ctkSimplePythonManager::preInitialization()
+{
+  Superclass::preInitialization();
+
+#if defined(CTK_WRAP_PYTHONQT_LIGHT) || defined(CTK_WRAP_PYTHONQT_FULL)
+  // Initialize wrappers
+  @CTK_PYTHONQT_INITIALIZATION_METHOD_CALL@
+#endif
+
+  // Register decorators
+  this->registerPythonQtDecorator(new ctkSimplePythonQtDecorators(this));  
+  
+  // Add object to python interpreter context
+  this->addObjectToPythonMain("_ctkSimplePythonShellInstance", qApp);
+}
+
+//-----------------------------------------------------------------------------
+void ctkSimplePythonManager::executeInitializationScripts()
+{
+  QString self_dir = QFileInfo(qApp->applicationFilePath()).absolutePath();
+
+  QString initFile = self_dir;
+  #if defined(CMAKE_INTDIR)
+  initFile.append("/..");
+  #endif
+  initFile.append("/Python/ctkSimplePythonShell.py");
+
+  Q_ASSERT(QFile::exists(initFile));
+
+  // Evaluate application script
+  this->executeFile(initFile);
+}

+ 1 - 0
Applications/ctkSimplePythonShell/ctkSimplePythonManager.h

@@ -19,6 +19,7 @@ protected:
 
   virtual QStringList pythonPaths();
   virtual void preInitialization();
+  virtual void executeInitializationScripts();
 
 };
 

+ 8 - 0
Applications/ctkSimplePythonShell/ctkSimplePythonShellConfigure.h.in

@@ -9,5 +9,13 @@
 #cmakedefine CTK_WRAP_PYTHONQT_LIGHT
 #cmakedefine CTK_WRAP_PYTHONQT_FULL
 
+//#define CTK_PYTHON_LIBRARY_DIR_BUILD "@LIBRARY_OUTPUT_DIRECTORY@"
+
+#cmakedefine CTK_WRAP_PYTHONQT_USE_VTK
+
+#ifdef CTK_WRAP_PYTHONQT_USE_VTK
+# define VTK_PYTHON_LIBRARY_DIR_BUILD "@VTK_DIR@/bin"
+#endif
+
 #endif
 

+ 70 - 0
Applications/ctkSimplePythonShell/ctkSimplePythonShellMain.cpp

@@ -1,15 +1,56 @@
 
 // Qt includes
 #include <QApplication>
+#include <QTextStream>
 
 // CTK includes
 #include <ctkPythonShell.h>
+#include <ctkCommandLineParser.h>
 
 #include "ctkSimplePythonManager.h"
+#include "ctkTestWrappedQProperty.h"
+#include "ctkTestWrappedQInvokable.h"
+#include "ctkTestWrappedSlot.h"
+#include "ctkSimplePythonShellConfigure.h" // For CTK_WRAP_PYTHONQT_USE_VTK
+
+#ifdef CTK_WRAP_PYTHONQT_USE_VTK
+# include "ctkTestWrappedQListOfVTKObject.h"
+# include "ctkTestWrappedVTKSlot.h"
+# include "ctkTestWrappedVTKQInvokable.h"
+#endif
 
 int main(int argc, char** argv)
 {
   QApplication app(argc, argv);
+
+  ctkCommandLineParser parser;
+  // Use Unix-style argument names
+  parser.setArgumentPrefix("--", "-");
+
+  // Add command line argument names
+  parser.addArgument("help", "h", QVariant::Bool, "Print usage information and exit.");
+  parser.addArgument("interactive", "I", QVariant::Bool, "Enable interactive mode");
+
+  // Parse the command line arguments
+  bool ok = false;
+  QHash<QString, QVariant> parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok);
+  if (!ok)
+  {
+    QTextStream(stderr, QIODevice::WriteOnly) << "Error parsing arguments: "
+                                              << parser.errorString() << "\n";
+    return EXIT_FAILURE;
+  }
+
+  // Show a help message
+  if (parsedArgs.contains("help") || parsedArgs.contains("h"))
+  {
+    QTextStream(stdout, QIODevice::WriteOnly) << "ctkSimplePythonShell\n"
+          << "Usage\n\n"
+          << "  ctkSimplePythonShell [options] [<path-to-python-script> ...]\n\n"
+          << "Options\n"
+          << parser.helpText();
+    return EXIT_SUCCESS;
+  }
   
   ctkSimplePythonManager pythonManager;
   
@@ -17,6 +58,35 @@ int main(int argc, char** argv)
   shell.setAttribute(Qt::WA_QuitOnClose, true);
   shell.resize(600, 280);
   shell.show();
+
+  shell.setProperty("isInteractive", parsedArgs.contains("interactive"));
+
+  pythonManager.addObjectToPythonMain("_ctkPythonShellInstance", &shell);
+
+  ctkTestWrappedQProperty testWrappedQProperty;
+  pythonManager.addObjectToPythonMain("_testWrappedQPropertyInstance", &testWrappedQProperty);
+
+  ctkTestWrappedQInvokable testWrappedQInvokable;
+  pythonManager.addObjectToPythonMain("_testWrappedQInvokableInstance", &testWrappedQInvokable);
+
+  ctkTestWrappedSlot testWrappedSlot;
+  pythonManager.addObjectToPythonMain("_testWrappedSlotInstance", &testWrappedSlot);
+
+#ifdef CTK_WRAP_PYTHONQT_USE_VTK
+  ctkTestWrappedVTKQInvokable testWrappedVTKQInvokable;
+  pythonManager.addObjectToPythonMain("_testWrappedVTKQInvokableInstance", &testWrappedVTKQInvokable);
+
+  ctkTestWrappedVTKSlot testWrappedVTKSlot;
+  pythonManager.addObjectToPythonMain("_testWrappedVTKSlotInstance", &testWrappedVTKSlot);
+
+  ctkTestWrappedQListOfVTKObject testWrappedQListOfVTKObject;
+  pythonManager.addObjectToPythonMain("_testWrappedQListOfVTKObjectInstance", &testWrappedQListOfVTKObject);
+#endif
+
+  foreach(const QString& script, parser.unparsedArguments())
+    {
+    pythonManager.executeFile(script);
+    }
   
   return app.exec();
 }

+ 27 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedQInvokable.h

@@ -0,0 +1,27 @@
+
+
+#ifndef __ctkTestWrappedQInvokable_h
+#define __ctkTestWrappedQInvokable_h
+
+// Qt includes
+#include <QObject>
+
+class ctkTestWrappedQInvokable : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkTestWrappedQInvokable(QObject * newParent = 0) : QObject(newParent)
+    {
+    this->Value = 0;
+    }
+
+  /// Example of method wrapped using Q_INVOKABLE
+  Q_INVOKABLE int value() const { return this->Value; }
+  Q_INVOKABLE void setValue(int newValue){ this->Value = newValue; }
+
+private:
+  int        Value;
+};
+
+#endif

+ 29 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedQListOfVTKObject.h

@@ -0,0 +1,29 @@
+
+
+#ifndef __ctkTestWrappedQListOfVTKObject_h
+#define __ctkTestWrappedQListOfVTKObject_h
+
+// Qt includes
+#include <QObject>
+#include <QList>
+
+// VTK includes
+#include <vtkTable.h>
+
+class ctkTestWrappedQListOfVTKObject : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkTestWrappedQListOfVTKObject(QObject * newParent = 0) : QObject(newParent)
+    {
+    }
+
+  /// Example ot slot accepting a VTK object as parameter
+  Q_INVOKABLE int numberOfElementInList(const QList<vtkTable*>& listOfTable)
+    {
+    return listOfTable.count();
+    }
+};
+
+#endif

+ 31 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedQProperty.h

@@ -0,0 +1,31 @@
+
+
+#ifndef __ctkTestWrappedQProperty_h
+#define __ctkTestWrappedQProperty_h
+
+// Qt includes
+#include <QObject>
+
+class ctkTestWrappedQProperty : public QObject
+{
+  Q_OBJECT
+
+  Q_PROPERTY(int Value READ value WRITE setValue);
+
+public:
+
+  ctkTestWrappedQProperty(QObject * newParent = 0) : QObject(newParent)
+    {
+    this->Value = 0;
+    }
+
+  /// Example of property declared using Q_PROPERTY
+  /// Using Q_PROPERTY is enough to expose them, it's not required to declare them as slot
+  int value() const { return this->Value; }
+  void setValue(int newValue){ this->Value = newValue; }
+
+private:
+  int        Value;
+};
+
+#endif

+ 29 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedSlot.h

@@ -0,0 +1,29 @@
+
+
+#ifndef __ctkTestWrappedSlot_h
+#define __ctkTestWrappedSlot_h
+
+// Qt includes
+#include <QObject>
+
+class ctkTestWrappedSlot : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  ctkTestWrappedSlot(QObject * newParent = 0) : QObject(newParent)
+    {
+    this->Value = 0;
+    }
+
+public slots:
+
+  int value() const { return this->Value; }
+  void setValue(int newValue){ this->Value = newValue; }
+
+private:
+  int        Value;
+};
+
+#endif

+ 44 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedVTKQInvokable.h

@@ -0,0 +1,44 @@
+#ifndef __ctkTestWrappedVTKQInvokable_h
+#define __ctkTestWrappedVTKQInvokable_h
+
+// Qt includes
+#include <QObject>
+
+// VTK includes
+#include <vtkTable.h>
+
+class ctkTestWrappedVTKQInvokable : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkTestWrappedVTKQInvokable(QObject * newParent = 0) : QObject(newParent)
+    {
+    this->MyTable = vtkTable::New();
+    }
+    
+  virtual ~ctkTestWrappedVTKQInvokable()
+    {
+    this->MyTable->Delete();
+    }
+
+  /// Example of 'invokable' returning a VTK object
+  /// Declaring a method as invokable allows to add it to the MetaObject system
+  /// \note When a method returns a value, we tend to use Q_INVOKABLE
+  /// instead of declaring a slot.
+  Q_INVOKABLE vtkTable * getTable() const
+    {
+    return this->MyTable;
+    }
+
+  /// Example of 'invokable' accepting a VTK object as parameter
+  Q_INVOKABLE void setTable(vtkTable * newTable)
+    {
+    this->MyTable = newTable;
+    }
+
+private:
+  vtkTable * MyTable;
+};
+
+#endif

+ 45 - 0
Applications/ctkSimplePythonShell/ctkTestWrappedVTKSlot.h

@@ -0,0 +1,45 @@
+
+
+#ifndef __ctkTestWrappedVTKSlot_h
+#define __ctkTestWrappedVTKSlot_h
+
+// Qt includes
+#include <QObject>
+
+// VTK includes
+#include <vtkTable.h>
+
+class ctkTestWrappedVTKSlot : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkTestWrappedVTKSlot(QObject * newParent = 0) : QObject(newParent)
+    {
+    this->MyTable = vtkTable::New();
+    }
+    
+  virtual ~ctkTestWrappedVTKSlot()
+    {
+    this->MyTable->Delete();
+    }
+
+public slots:
+
+  /// Example of slot returning a VTK object
+  vtkTable* getTable() const
+    {
+    return this->MyTable;
+    }
+
+  /// Example ot slot accepting a VTK object as parameter
+  void setTable(vtkTable * newTable)
+    {
+    this->MyTable = newTable;
+    }
+
+private:
+  vtkTable * MyTable;
+};
+
+#endif

+ 1 - 0
Applications/ctkSimplePythonShell/target_libraries.cmake

@@ -5,5 +5,6 @@
 # 
 
 SET(target_libraries
+  VTK_LIBRARIES
   CTKScriptingPythonWidgets
   )

+ 100 - 24
CMake/ctkMacroCompilePythonScript.cmake

@@ -5,49 +5,125 @@
 #          ParaView/VTK/Wrapping/Python/CMakeLists.txt
 #
 
-MACRO(ctkMacroCompilePythonScript kit_name python_source_files dest_dir)
+INCLUDE(${CTK_CMAKE_DIR}/ctkMacroParseArguments.cmake)
 
+MACRO(ctkMacroCompilePythonScript)
+  ctkMacroParseArguments(MY
+    "TARGET_NAME;SCRIPTS;RESOURCES;DESTINATION_DIR;INSTALL_DIR"
+    ""
+    ${ARGN}
+    )
+  
   FIND_PACKAGE(PythonInterp REQUIRED)
+  FIND_PACKAGE(PythonLibs REQUIRED)
+
+  # Extract python lib path
+  get_filename_component(PYTHON_LIBRARY_PATH ${PYTHON_LIBRARY} PATH)
   
-  SET(copied_python_files)
+  # Sanity checks
+  FOREACH(varname TARGET_NAME SCRIPTS DESTINATION_DIR;INSTALL_DIR)
+    IF(NOT DEFINED MY_${varname})
+      MESSAGE(SEND_ERROR "${varname} is mandatory")
+    ENDIF()
+  ENDFOREACH()
   
-  FOREACH(file ${python_source_files})
-    GET_FILENAME_COMPONENT(file_we "${CMAKE_CURRENT_SOURCE_DIR}/${file}" NAME_WE)
-    SET(src "${CMAKE_CURRENT_SOURCE_DIR}/${file_we}.py")
-    SET(tgt "${dest_dir}/${file_we}.py")
+  set(copied_files)
+  set(copied_python_files)
+  FOREACH(file ${MY_SCRIPTS})
+    # Append "py" extension if needed
+    get_filename_component(file_ext ${file} EXT)
+    IF(NOT "${file_ext}" MATCHES "py")
+      SET(file "${file}.py")
+    ENDIF()
+
+    SET(src "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
+    SET(tgt "${MY_DESTINATION_DIR}/${file}")
+    IF(IS_ABSOLUTE ${file})
+      SET(src ${file})
+      file(RELATIVE_PATH tgt_file ${CMAKE_CURRENT_BINARY_DIR} ${file})
+      SET(tgt "${MY_DESTINATION_DIR}/${tgt_file}")
+    ENDIF()
+
     SET(copied_python_files ${copied_python_files} ${tgt})
+    SET(copied_files ${copied_files} ${tgt})
     ADD_CUSTOM_COMMAND(DEPENDS ${src}
                         COMMAND ${CMAKE_COMMAND} -E copy ${src} ${tgt}
                         OUTPUT ${tgt}
-                        COMMENT "Copying ${file_we}")
+                        COMMENT "Copying python script: ${file}.py")
   ENDFOREACH()
+
+  IF(DEFINED MY_RESOURCES)
+    FOREACH(file ${MY_RESOURCES})
+      SET(src "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
+      SET(tgt "${MY_DESTINATION_DIR}/${file}")
+      SET(copied_files ${copied_files} ${tgt})
+      ADD_CUSTOM_COMMAND(DEPENDS ${src}
+                          COMMAND ${CMAKE_COMMAND} -E copy ${src} ${tgt}
+                          OUTPUT ${tgt}
+                          COMMENT "Copying python resource: ${file}")
+    ENDFOREACH()
+
+    ADD_CUSTOM_TARGET(Copy${MY_TARGET_NAME}PythonFiles
+                      ALL
+                      DEPENDS ${copied_files})
+  ENDIF()
+                    
   
   # Byte compile the Python files.
-  SET(compile_all_script "${CMAKE_CURRENT_BINARY_DIR}/compile_all_${kit_name}.py")
+  SET(compile_all_script "${CMAKE_CURRENT_BINARY_DIR}/compile_${MY_TARGET_NAME}_python_scripts.py")
   
-  # Based on paraview/VTK/Wrapping/Python/compile_all_vtk.py.in
+  # Generate compile_${MY_TARGET_NAME}_python_scripts.py
   FILE(WRITE ${compile_all_script} "
-\# Auto-generated
+#
+# Generated by ctkMacroCompilePythonScript CMAKE macro
+#
+
+# Based on paraview/VTK/Wrapping/Python/compile_all_vtk.py.in
+
 import compileall
-compileall.compile_dir('${dest_dir}')
-file = open('${CMAKE_CURRENT_BINARY_DIR}/${kit_name}_python_compile_complete', 'w')
+compileall.compile_dir('@MY_DESTINATION_DIR@')
+file = open('@CMAKE_CURRENT_BINARY_DIR@/python_compile_@MY_TARGET_NAME@_complete', 'w')
 file.write('Done')
 ")
 
+  # Configure cmake script associated with the custom command
+  # required to properly update the library path with PYTHON_LIBRARY_PATH
+  SET(compile_all_cmake_script "${CMAKE_CURRENT_BINARY_DIR}/compile_${MY_TARGET_NAME}_python_scripts.cmake")
+  FILE(WRITE ${compile_all_cmake_script} "
+#
+# Generated by ctkMacroCompilePythonScript CMAKE macro
+#
+
+IF(WIN32)
+    SET(ENV{PATH} \"@PYTHON_LIBRARY_PATH@;\$ENV{PATH}\")
+ELSEIF(APPLE)
+  SET(ENV{DYLD_LIBRARY_PATH} \"@PYTHON_LIBRARY_PATH@:\$ENV{DYLD_LIBRARY_PATH}\")
+ELSE()
+  SET(ENV{LD_LIBRARY_PATH} \"@PYTHON_LIBRARY_PATH@:\$ENV{LD_LIBRARY_PATH}\")
+ENDIF()
+
+EXECUTE_PROCESS(
+  COMMAND \"@PYTHON_EXECUTABLE@\" \"@compile_all_script@\"
+  )
+")
+
   ADD_CUSTOM_COMMAND(
-    COMMAND ${PYTHON_EXECUTABLE} ${compile_all_script}
+    COMMAND ${CMAKE_COMMAND} -P ${compile_all_cmake_script}
     DEPENDS ${copied_python_files}  ${compile_all_script}
-    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${kit_name}_python_compile_complete"
-    COMMENT "Compiling ${kit_name} python files"
+    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/python_compile_${MY_TARGET_NAME}_complete"
+    COMMENT "Compiling python scripts: ${MY_TARGET_NAME}"
     )
-  
-  ADD_CUSTOM_TARGET(${kit_name}_pyc ALL
-    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${kit_name}_python_compile_complete")
-
-
-  # Install the slicer python module directory
-  #INSTALL(DIRECTORY "${Slicer3_BINARY_DIR}/bin/Python"
-  #  DESTINATION "${Slicer3_INSTALL_BIN_DIR}" COMPONENT Runtime
-  #  USE_SOURCE_PERMISSIONS)
 
+  ADD_CUSTOM_TARGET(Compile${MY_TARGET_NAME}PythonFiles ALL
+    DEPENDS 
+      ${CMAKE_CURRENT_BINARY_DIR}/python_compile_${MY_TARGET_NAME}_complete
+      ${compile_all_script}
+      )   
+  
+  # Install python module directory
+  INSTALL(DIRECTORY "${MY_DESTINATION_DIR}"
+    DESTINATION "${MY_INSTALL_DIR}" COMPONENT Runtime
+    USE_SOURCE_PERMISSIONS)
+       
 ENDMACRO()
+

+ 3 - 0
CMake/ctkMacroWrapPythonQt.cmake

@@ -63,6 +63,8 @@ FUNCTION(ctkMacroWrapPythonQt_log msg)
   FILE(APPEND "${CMAKE_CURRENT_BINARY_DIR}/ctkMacroWrapPythonQt_log.txt" "${msg}\n")
 ENDFUNCTION()
 
+INCLUDE(${CTK_CMAKE_DIR}/ctkMacroSetPaths.cmake)
+
 #
 # Convenient function allowing to invoke re.search(regex, string) using the given interpreter.
 # Note that is_matching will be set to True if there is a match
@@ -190,6 +192,7 @@ MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W
     
     IF(NOT skip_wrapping)
       # Skip wrapping if object has a virtual pure method 
+      # "x3b" is the unicode for semicolon
       SET(regex "virtual[\\w\\n\\s\\*\\(\\)]+\\=[\\s\\n]*(0|NULL)[\\s\\n]*\\x3b")
       ctkMacroWrapPythonQt_reSearchFile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH}
                                         ${regex} ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} is_matching)

+ 10 - 2
CMakeExternals/PythonQt.cmake

@@ -20,9 +20,17 @@ IF(${add_project})
   IF(NOT DEFINED PYTHONQT_INSTALL_DIR)
   #   MESSAGE(STATUS "Adding project:${proj}")
     
-    # Generate ep_PythonQt_args
     SET(ep_PythonQt_args)
-    foreach(qtlib gui network opengl sql svg uitools webkit xml xmlpatterns)
+    
+    # Should PythonQt use VTK 
+    IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+      LIST(APPEND proj_DEPENDENCIES VTK)
+      LIST(APPEND ep_PythonQt_args -DVTK_DIR:PATH=${VTK_DIR})
+    ENDIF()
+    LIST(APPEND ep_PythonQt_args -DPythonQt_USE_VTK:BOOL=${CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK})
+    
+    # Enable Qt libraries PythonQt wrapping if required
+    foreach(qtlib core gui network opengl sql svg uitools webkit xml xmlpatterns)
       STRING(TOUPPER ${qtlib} qtlib_uppercase)
       LIST(APPEND ep_PythonQt_args -DPythonQt_Wrap_Qt${qtlib}:BOOL=${CTK_LIB_Scripting/Python/Core_PYTHONQT_WRAP_QT${qtlib_uppercase}})
     endforeach()

+ 12 - 3
CMakeExternals/VTK.cmake

@@ -3,7 +3,7 @@
 #
 SET (VTK_DEPENDS)
 ctkMacroShouldAddExternalProject(VTK_LIBRARIES add_project)
-IF(${add_project})
+IF(${add_project} OR CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
   # Sanity checks
   IF(DEFINED VTK_DIR AND NOT EXISTS ${VTK_DIR})
     MESSAGE(FATAL_ERROR "VTK_DIR variable is defined but corresponds to non-existing directory")
@@ -13,7 +13,15 @@ IF(${add_project})
   
   SET(additional_vtk_cmakevars )
   IF(MINGW)
-    SET(additional_vtk_cmakevars "-DCMAKE_USE_PTHREADS:BOOL=OFF")
+    LIST(APPEND additional_vtk_cmakevars -DCMAKE_USE_PTHREADS:BOOL=OFF)
+  ENDIF()
+  
+  IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+    LIST(APPEND additional_vtk_cmakevars
+      -DPYTHON_EXECUTABLE:PATH=${PYTHON_EXECUTABLE}
+      -DPYTHON_LIBRARIES:FILEPATH=${PYTHON_LIBRARIES}
+      -DPYTHON_DEBUG_LIBRARIES:FILEPATH=${PYTHON_DEBUG_LIBRARIES}
+      )
   ENDIF()
 
   SET(proj VTK)
@@ -32,7 +40,8 @@ IF(${add_project})
         ${ep_common_args}
         ${additional_vtk_cmakevars}
         -DVTK_WRAP_TCL:BOOL=OFF
-        -DVTK_WRAP_PYTHON:BOOL=OFF
+        -DVTK_USE_TK:BOOL=OFF
+        -DVTK_WRAP_PYTHON:BOOL=${CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK}
         -DVTK_WRAP_JAVA:BOOL=OFF
         -DBUILD_SHARED_LIBS:BOOL=ON 
         -DDESIRED_QT_VERSION:STRING=4

+ 18 - 8
CMakeLists.txt

@@ -133,6 +133,10 @@ SET(CTK_WRAPPED_LIBRARIES_PYTHONQT CACHE INTERNAL "CTK libraries wrapped using P
 SET(CTK_LIBRARIES CACHE INTERNAL "CTK libraries" FORCE)
 SET(CTK_PLUGIN_LIBRARIES CACHE INTERNAL "CTK plugins" FORCE)
 
+# Used by CTKGenerateCTKConfig.cmake and also used to reference script from other scripts
+SET(CTK_CMAKE_DIR ${CTK_SOURCE_DIR}/CMake)
+SET(CTK_CMAKE_UTILITIES_DIR ${CTK_SOURCE_DIR}/Utilities/CMake)
+
 #-----------------------------------------------------------------------------
 # CMake Function(s) and Macro(s)
 #
@@ -157,10 +161,6 @@ INCLUDE(CMake/ctkMacroGeneratePluginResourceFile.cmake)
 INCLUDE(CMake/ctkFunctionCheckCompilerFlags.cmake)
 INCLUDE(CMake/ctkFunctionGetIncludeDirs.cmake)
 
-# Used by CTKGenerateCTKConfig.cmake
-SET(CTK_CMAKE_DIR ${CTK_SOURCE_DIR}/CMake)
-SET(CTK_CMAKE_UTILITIES_DIR ${CTK_SOURCE_DIR}/Utilities/CMake)
-
 #-----------------------------------------------------------------------------
 # Testing
 #
@@ -447,7 +447,11 @@ ctkMacroValidateBuildOptions("${CTK_BINARY_DIR}" "${DGraph_EXECUTABLE}" "${targe
 IF(CTK_LIB_Scripting/Python/Core)
   find_package(PythonInterp)
   IF(NOT PYTHONINTERP_FOUND)
-    MESSAGE(SEND_ERROR "PYTHON_EXECUTABLE not specified or inexistent when CTK_LIB_Scripting is enabled")
+    MESSAGE(SEND_ERROR "PYTHON_EXECUTABLE variable should be set to build CTK_LIB_Scripting/Python")
+  ENDIF()
+  FIND_PACKAGE(PythonLibs)
+  IF(NOT PYTHONLIBS_FOUND)
+    MESSAGE(FATAL_ERROR "PYTHON_LIBRARIES and PYTHON_INCLUDE_DIRS should be set to build CTK_LIB_Scripting/Python")
   ENDIF()
   OPTION(CTK_WRAP_PYTHONQT_FULL "Wrap CTK classes using Qt meta-object system into Python language" OFF)
   OPTION(CTK_WRAP_PYTHONQT_LIGHT "Wrap CTK classes using Qt meta-object system into Python language" OFF)
@@ -481,9 +485,8 @@ IF(RESULT_VAR)
   MESSAGE(FATAL_ERROR "Failed to obtain list of target ordered topologically.\n${RESULT_VAR}\n${CTK_BINARY_DIR}\n${error}")
 ENDIF()
 
-
 # Convert 'CTEST_PROJECT_SUBPROJECTS_OUTPUT' to a list
-STRING(REPLACE " " "\\;" CTEST_PROJECT_SUBPROJECTS ${CTEST_PROJECT_SUBPROJECTS_OUTPUT})
+STRING(REPLACE " " "\\;" CTEST_PROJECT_SUBPROJECTS "${CTEST_PROJECT_SUBPROJECTS_OUTPUT}")
 SET(CTEST_PROJECT_SUBPROJECTS ${CTEST_PROJECT_SUBPROJECTS})
 
 # If the list of subproject is empty, let's at least build CTKCore
@@ -518,7 +521,7 @@ ENDIF()
 FOREACH(_external_target ${EXTERNAL_TARGETS})
   IF(${_external_target}_FIND_PACKAGE_CMD)
     #MESSAGE("Calling FIND_PACKAGE(${${_external_target}_FIND_PACKAGE_CMD})")
-    FIND_PACKAGE(${${_external_target}_FIND_PACKAGE_CMD})
+    FIND_PACKAGE(${${_external_target}_FIND_PACKAGE_CMD} REQUIRED)
   ENDIF()
 ENDFOREACH()
 
@@ -542,6 +545,13 @@ FOREACH(_external_target ${EXTERNAL_TARGETS})
   ENDIF()
 ENDFOREACH()
 
+# Since PYTHONQT_USE_VTK library option can be enabled independently of
+# Visualization/VTK/Core, let's make sure VTK has been properly discovered
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  FIND_PACKAGE(VTK REQUIRED)
+ENDIF()
+SET(CTK_WRAP_PYTHONQT_USE_VTK ${CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK})
+
 #-----------------------------------------------------------------------------
 # CTK_SUPERBUILD_BINARY_DIR
 

+ 14 - 4
Libs/Scripting/Python/Core/CMakeLists.txt

@@ -1,5 +1,11 @@
 PROJECT(CTKScriptingPythonCore)
 
+#
+# 3rd party dependencies
+#
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  INCLUDE(${VTK_USE_FILE})
+ENDIF()
 
 #
 # See CTK/CMake/ctkMacroBuildLib.cmake for details
@@ -30,14 +36,11 @@ SET(KIT_resources
 #
 # Configure file describing which Qt modules are wrapped
 #
-FOREACH(qtlib GUI NETWORK OPENGL SQL SVG UITOOLS WEBKIT XML XMLPATTERNS)
+FOREACH(qtlib CORE GUI NETWORK OPENGL SQL SVG UITOOLS WEBKIT XML XMLPATTERNS)
   SET(CTK_PYTHONQT_WRAP_QT${qtlib} ${CTK_LIB_Scripting/Python/Core_PYTHONQT_WRAP_QT${qtlib}})
   #message(CTK_LIB_Scripting/Python/Core_PYTHONQT_WRAP_QT${qtlib}:${CTK_LIB_Scripting/Python/Core_PYTHONQT_WRAP_QT${qtlib}})
 ENDFOREACH()
 
-# TODO Ideally a file named ctkScripingPythonWidgetsConfigure.h should
-# also be configured, this file should deal with Qt Module depending only on QtGui
-
 CONFIGURE_FILE(
   ctkScriptingPythonCoreConfigure.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/ctkScriptingPythonCoreConfigure.h
@@ -47,6 +50,11 @@ CONFIGURE_FILE(
 # The following macro will read the target libraries from the file 'target_libraries.cmake'
 ctkMacroGetTargetLibraries(KIT_target_libraries)
 
+# Link against vtkPython if required
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  LIST(APPEND KIT_target_libraries vtkPythonCore)
+ENDIF()
+
 ctkMacroBuildLib(
   NAME ${PROJECT_NAME}
   EXPORT_DIRECTIVE ${KIT_export_directive}
@@ -61,6 +69,8 @@ ctkMacroBuildLib(
 # Plugins
 #ADD_SUBDIRECTORY(Plugins)
 
+ADD_SUBDIRECTORY(Python)
+
 # Testing
 IF(BUILD_TESTING)
   #ADD_SUBDIRECTORY(Testing)

+ 44 - 0
Libs/Scripting/Python/Core/Python/CMakeLists.txt

@@ -0,0 +1,44 @@
+
+
+SET(KIT_PYTHON_SCRIPTS
+  qt/__init__
+  )
+  
+#IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+#  LIST(APPEND KIT_PYTHON_SCRIPTS ctkvtk/__init__)
+#ENDIF()
+
+IF(CTK_WRAP_PYTHONQT_LIGHT OR CTK_WRAP_PYTHONQT_FULL)
+
+  # Configure variable CTK_PYTHON_WRAPPED_LIBRARIES that will contain
+  # the comma separated list of package to load
+  SET(CTK_PYTHON_WRAPPED_LIBRARIES)
+  FOREACH(lib ${CTK_LIBS})
+    ctkFunctionExtractOptionNameAndValue(${lib} lib_name lib_value)
+    IF(${CTK_LIB_${lib_name}})
+      STRING(REPLACE "/" "" lib_name_no_slash ${lib_name})
+      SET(lib_name_no_slash "'${lib_name_no_slash}'") # Add single quotes
+      SET(CTK_PYTHON_WRAPPED_LIBRARIES "${lib_name_no_slash}, ${CTK_PYTHON_WRAPPED_LIBRARIES}")
+    ENDIF()
+  ENDFOREACH()
+
+  CONFIGURE_FILE(
+    ctk/__init__.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/ctk/__init__.py
+    @ONLY
+    )
+
+  LIST(APPEND KIT_PYTHON_SCRIPTS ${CMAKE_CURRENT_BINARY_DIR}/ctk/__init__.py)
+ENDIF()
+
+SET(KIT_PYTHON_RESOURCES
+  )
+
+ctkMacroCompilePythonScript(
+  TARGET_NAME ${PROJECT_NAME}
+  SCRIPTS "${KIT_PYTHON_SCRIPTS}"
+  RESOURCES "${KIT_PYTHON_RESOURCES}"
+  DESTINATION_DIR ${CTK_BINARY_DIR}/bin/Python
+  INSTALL_DIR ${CTK_INSTALL_BIN_DIR}
+  )
+  

+ 13 - 0
Libs/Scripting/Python/Core/Python/ctk/__init__.py.in

@@ -0,0 +1,13 @@
+""" This module loads all the classes from the wrapped CTK libraries into
+its namespace."""
+
+__kits_to_load = [ @CTK_PYTHON_WRAPPED_LIBRARIES@ ]
+
+for kit in __kits_to_load:
+  try:
+    exec "from PythonQt.CTK%s import *" % (kit)
+  except ImportError as detail:
+    print detail
+   
+# Removing things the user shouldn't have to see.
+del __kits_to_load

+ 24 - 0
Libs/Scripting/Python/Core/Python/qt/__init__.py

@@ -0,0 +1,24 @@
+""" This module loads all the classes from the wrapped Qt libraries into
+its namespace."""
+
+__kits_to_load = [
+'Core',
+'Gui', 
+'Network', 
+'OpenGL', 
+'Sql',
+'Svg',
+'UiTools',
+'WebKit',
+'Xml', 
+'XmlPatterns'
+]
+
+for kit in __kits_to_load:
+   try:
+     exec "from PythonQt.Qt%s import *" % (kit)
+   except ImportError as detail:
+     print detail
+   
+# Removing things the user shouldn't have to see.
+del __kits_to_load

+ 26 - 1
Libs/Scripting/Python/Core/ctkAbstractPythonManager.cpp

@@ -39,6 +39,10 @@
 #pragma GCC diagnostic ignored "-Wold-style-cast"
 #endif
 
+#ifdef CTK_PYTHONQT_WRAP_QTCORE
+void PythonQt_init_QtCore(PyObject*);
+#endif
+
 #ifdef CTK_PYTHONQT_WRAP_QTGUI
 void PythonQt_init_QtGui(PyObject*);
 #endif
@@ -78,7 +82,7 @@ void PythonQt_init_QtXmlPatterns(PyObject*);
 //-----------------------------------------------------------------------------
 ctkAbstractPythonManager::ctkAbstractPythonManager(QObject* _parent) : Superclass(_parent)
 {
-
+  this->InitFunction = 0;
 }
 
 //-----------------------------------------------------------------------------
@@ -121,6 +125,10 @@ void ctkAbstractPythonManager::initPythonQt()
   this->connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)),
                 SLOT(printStderr(const QString&)));
   
+  #ifdef CTK_PYTHONQT_WRAP_QTCORE
+  PythonQt_init_QtCore(0);
+  #endif
+  
   #ifdef CTK_PYTHONQT_WRAP_QTGUI
   PythonQt_init_QtGui(0);
   #endif
@@ -167,7 +175,13 @@ void ctkAbstractPythonManager::initPythonQt()
   _mainContext.evalScript(initCode.join("\n"));
 
   this->preInitialization();
+  if (this->InitFunction)
+    {
+    (*this->InitFunction)();
+    }
+  emit this->pythonPreInitialized();
 
+  this->executeInitializationScripts();
   emit this->pythonInitialized();
 }
 
@@ -183,6 +197,11 @@ void ctkAbstractPythonManager::preInitialization()
 }
 
 //-----------------------------------------------------------------------------
+void ctkAbstractPythonManager::executeInitializationScripts()
+{
+}
+
+//-----------------------------------------------------------------------------
 void ctkAbstractPythonManager::registerPythonQtDecorator(QObject* decorator)
 {
   PythonQt::self()->addDecorators(decorator);
@@ -223,6 +242,12 @@ void ctkAbstractPythonManager::executeFile(const QString& filename)
 }
 
 //-----------------------------------------------------------------------------
+void ctkAbstractPythonManager::setInitializationFunction(void (*initFunction)())
+{
+  this->InitFunction = initFunction;
+}
+
+//-----------------------------------------------------------------------------
 void ctkAbstractPythonManager::addObjectToPythonMain(const QString& name, QObject* obj)
 {
   PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();

+ 19 - 5
Libs/Scripting/Python/Core/ctkAbstractPythonManager.h

@@ -46,25 +46,31 @@ public:
   void registerClassForPythonQt(const QMetaObject* metaobject);
   void registerCPPClassForPythonQt(const char* name);
 
-  ///
   /// Execute a python of python code (can be multiple lines separated with newline)
   /// and return the result as a QVariant.
   QVariant executeString(const QString& code);
 
-  ///
   /// Gets the value of the variable looking in the __main__ module.
   /// If the variable is not found returns a default initialized QVariant.
   QVariant getVariable(const QString& varName);
 
-  ///
   /// Execute a python script with the given filename.
   void executeFile(const QString& filename);
 
+  /// Set function that is initialized after preInitialization and before executeInitializationScripts
+  /// \sa preInitialization executeInitializationScripts
+  void setInitializationFunction(void (*initFunction)());
+
 signals:
 
-  ///
-  /// This signal is emitted after python is initialized.  Observers can listen
+  /// This signal is emitted after python is pre-initialized. Observers can listen
   /// for this signal to handle additional initialization steps.
+  /// \sa preInitialization
+  void pythonPreInitialized();
+
+  /// This signal is emitted after python is initialized and scripts are executed
+  /// \sa preInitialization
+  /// \sa executeScripts
   void pythonInitialized();
 
 protected slots:
@@ -76,7 +82,15 @@ protected:
   void initPythonQt();
 
   virtual QStringList     pythonPaths();
+
+  /// Overload this function to load Decorator and pythonQt wrapper at initialization time
   virtual void            preInitialization();
 
+  /// Overload this function to execute script at initialization time
+  virtual void            executeInitializationScripts();
+
+private:
+  void (*InitFunction)();
+
 };
 #endif

+ 1 - 0
Libs/Scripting/Python/Core/ctkScriptingPythonCoreConfigure.h.in

@@ -6,6 +6,7 @@
 /// Here is where system computed values get stored
 ///
 
+#cmakedefine CTK_PYTHONQT_WRAP_QTCORE
 #cmakedefine CTK_PYTHONQT_WRAP_QTGUI
 #cmakedefine CTK_PYTHONQT_WRAP_QTNETWORK
 #cmakedefine CTK_PYTHONQT_WRAP_QTOPENGL

+ 2 - 0
Libs/Scripting/Python/Core/ctk_library_options.cmake

@@ -6,6 +6,8 @@
 #
 
 SET(ctk_library_options
+  PYTHONQT_USE_VTK:OFF
+  PYTHONQT_WRAP_QTCORE:OFF
   PYTHONQT_WRAP_QTGUI:OFF
   PYTHONQT_WRAP_QTNETWORK:OFF
   PYTHONQT_WRAP_QTOPENGL:OFF

+ 3 - 0
Libs/Scripting/Python/Widgets/CMakeLists.txt

@@ -3,6 +3,9 @@ PROJECT(CTKScriptingPythonWidgets)
 #
 # 3rd party dependencies
 #
+IF(CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
+  INCLUDE(${VTK_USE_FILE})
+ENDIF()
 
 #
 # See CTK/CMake/ctkMacroBuildLib.cmake for details

+ 2 - 2
SuperBuild.cmake

@@ -108,12 +108,13 @@ ctkMacroGetAllNonCTKTargetLibraries("${ALL_TARGET_LIBRARIES}" NON_CTK_DEPENDENCI
 #
 
 #-----------------------------------------------------------------------------
-# ExternalProjects
+# ExternalProjects - Project should be topologically ordered
 #
 SET(external_projects
   CTKData
   Log4Qt
   KWStyle
+  VTK
   PythonQt
   PythonQtGenerator # Should be added after PythonQt - See comment in CMakeExternals/PythonQtGenerator.cmake
   DCMTK
@@ -121,7 +122,6 @@ SET(external_projects
   QtMobility
   QtSOAP
   OpenIGTLink
-  VTK
   XIP
   )