Browse Source

ENH: Added VTK to CTK-Superbuild and also added class ctkVTKObject, ctkVTKConnection and ctkVTKObjectEventsObserver.

Also added corresponding tests
Jean-Christophe Fillion-Robin 15 years ago
parent
commit
f8da0d3f1e

+ 2 - 0
CMakeLists.txt

@@ -186,6 +186,8 @@ SET(CTK_LIBS
   Widgets
   Widgets
   DICOM/Core
   DICOM/Core
   DICOM/Widgets
   DICOM/Widgets
+  Visualization/VTK/Core
+  #Visualization/VTK/widgets
   Visualization/XIP
   Visualization/XIP
   )
   )
 
 

+ 0 - 0
Libs/Visualization/VTK/CMakeLists.txt


+ 75 - 0
Libs/Visualization/VTK/Core/CMakeLists.txt

@@ -0,0 +1,75 @@
+PROJECT(CTKVisualizationVTKCore)
+
+#
+# 3rd party dependencies
+#
+
+FIND_PACKAGE(VTK)
+# TODO In case VTK is passed directly using VTK_DIR, check expected options
+IF(NOT VTK_FOUND)
+  MESSAGE(FATAL_ERROR "error: VTK package is required to build ${PROJECT_NAME}")
+ENDIF()
+INCLUDE(${VTK_USE_FILE})
+
+#
+# See CTK/CMake/ctkMacroBuildQtLib.cmake for details
+#
+
+SET(KIT_export_directive "CTK_VISUALIZATION_VTK_CORE_EXPORT")
+
+# Additional directories to include
+SET(KIT_include_directories
+  )
+  
+# Source files
+SET(KIT_SRCS
+  ctkVTKConnection.cpp
+  ctkVTKConnection.h
+  ctkVTKObject.h
+  ctkVTKObjectEventsObserver.cpp
+  ctkVTKObjectEventsObserver.h
+  )
+
+# Headers that should run through moc
+SET(KIT_MOC_SRCS
+  ctkVTKConnection.h
+  ctkVTKObjectEventsObserver.h
+  )
+
+# UI files
+SET(KIT_UI_FORMS
+)
+
+# Resources
+SET(KIT_resources
+)
+
+# Set VTK_LIBRARIES variable
+SET(VTK_LIBRARIES
+  vtkCommon
+  QVTK
+  )
+
+# Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
+# The following macro will read the target libraries from the file 'target_libraries.cmake'
+ctkMacroGetTargetLibraries(KIT_target_libraries)
+
+ctkMacroBuildQtLib(
+  NAME ${PROJECT_NAME}
+  EXPORT_DIRECTIVE ${KIT_export_directive}
+  INCLUDE_DIRECTORIES ${KIT_include_directories}
+  SRCS ${KIT_SRCS}
+  MOC_SRCS ${KIT_MOC_SRCS}
+  UI_FORMS ${KIT_UI_FORMS}
+  TARGET_LIBRARIES ${KIT_target_libraries}
+  RESOURCES ${KIT_resources}
+  LIBRARY_TYPE ${CTK_LIBRARY_MODE}
+  )
+
+# Plugins
+#ADD_SUBDIRECTORY(Plugins)
+
+# Testing
+IF(BUILD_TESTING)
+  ADD_SUBDIRECTORY(Testing)
+ENDIF(BUILD_TESTING)

+ 1 - 0
Libs/Visualization/VTK/Core/Testing/CMakeLists.txt

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

+ 51 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/CMakeLists.txt

@@ -0,0 +1,51 @@
+SET(KIT ${PROJECT_NAME})
+
+#
+# Pre-requisites
+#
+
+INCLUDE_DIRECTORIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+  
+# Create ctkVTKObjectTestHelper source list
+
+SET(KIT_HELPER_SRCS
+  ctkVTKObjectTestHelper.cpp
+  )
+
+QT4_WRAP_CPP(KIT_HELPER_SRCS ctkVTKObjectTestHelper.h)
+
+#
+# Tests
+#
+
+CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cpp
+  ctkVTKObjectTest1.cpp
+  #EXTRA_INCLUDE TestingMacros.h
+  )
+
+SET (TestsToRun ${Tests})
+REMOVE (TestsToRun ${KIT}CppTests.cpp)
+
+SET(LIBRARY_NAME ${PROJECT_NAME})
+
+ADD_EXECUTABLE(${KIT}CppTests ${Tests} ${KIT_HELPER_SRCS})
+TARGET_LINK_LIBRARIES(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES})
+
+SET( KIT_TESTS ${CXX_TEST_PATH}/${KIT}CppTests)
+IF(WIN32)
+  SET(KIT_TESTS ${CXX_TEST_PATH}/${CMAKE_BUILD_TYPE}/${KIT}CppTests)
+ENDIF(WIN32)
+
+MACRO( SIMPLE_TEST  TESTNAME )
+  ADD_TEST( ${TESTNAME} ${KIT_TESTS} ${TESTNAME} )
+  SET_PROPERTY(TEST ${TESTNAME} PROPERTY LABELS ${PROJECT_NAME})
+ENDMACRO( SIMPLE_TEST  )
+
+#
+# Add Tests
+#
+
+SIMPLE_TEST( ctkVTKObjectTest1 )

+ 22 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/ctkVTKObjectTest1.cpp

@@ -0,0 +1,22 @@
+
+// Qt includes
+#include <QApplication>
+
+// CTKVTK includes
+#include "ctkVTKObjectTestHelper.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+int ctkVTKObjectTest1( int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+
+  ctkVTKObjectTest objectTest;
+  if (!objectTest.test())
+    {
+    return EXIT_FAILURE;
+    }
+  return EXIT_SUCCESS;
+}

+ 252 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/ctkVTKObjectTestHelper.cpp

@@ -0,0 +1,252 @@
+
+// Qt includes
+#include <QDebug>
+#include <QApplication>
+
+// CTKVTK includes
+#include "ctkVTKObjectTestHelper.h"
+
+// VTK includes
+#include <vtkObject.h>
+
+//------------------------------------------------------------------------------
+class ctkVTKObjectTestPrivate : public ctkPrivate<ctkVTKObjectTest>
+{
+public:
+  ctkVTKObjectTestPrivate();
+  int PublicSlotCalled ;
+  int ProtectedSlotCalled;
+  int PrivateSlotCalled;
+};
+
+//------------------------------------------------------------------------------
+ctkVTKObjectTestPrivate::ctkVTKObjectTestPrivate()
+{
+  this->PublicSlotCalled = 0;
+  this->ProtectedSlotCalled = 0;
+  this->PrivateSlotCalled = 0;
+}
+
+//------------------------------------------------------------------------------
+ctkVTKObjectTest::ctkVTKObjectTest()
+{
+  CTK_INIT_PRIVATE(ctkVTKObjectTest);
+}
+
+//------------------------------------------------------------------------------
+bool ctkVTKObjectTest::test()
+{
+  CTK_D(ctkVTKObjectTest);
+  // should do nothing but shouldn't fail neither
+  qDebug() << "The following can generate error message.";
+  qDebug() << "Disconnect:";
+  this->qvtkDisconnect(0, static_cast<unsigned long>(-1), this, SLOT(onVTKObjectModifiedPublic()));
+  qDebug() << "Connect:";
+  QString connection = this->qvtkConnect(0, static_cast<unsigned long>(-1), this, SLOT(onVTKObjectModifiedPublic()));
+  if (!connection.isEmpty())
+    {
+    qDebug() << "ctkVTKObject::qvtkConnect() failed: "<< connection;
+    return false;
+    }
+  qDebug() << "Reconnect:";
+  connection = this->qvtkReconnect(0, 0, static_cast<unsigned long>(-1), this, SLOT(onVTKObjectModifiedPublic()));
+  if (!connection.isEmpty())
+    {
+    qDebug() << "ctkVTKObject::qvtkReconnect() failed: "<< connection;
+    return false;
+    }
+  qDebug() << "End of possible error messages.";
+  
+  vtkObject* object = vtkObject::New();
+
+  connection = this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                                 this, SLOT(onVTKObjectModifiedPublic()));
+  if (connection.isEmpty() || object->GetReferenceCount() != 1)
+    {
+    qDebug() << "ctkVTKObject::qvtkConnect() failed: "<< connection;
+    return false;
+    }
+
+  object->Modified();
+
+  if (d->PublicSlotCalled != 1)
+    {
+    qDebug() << "qvtkConnect failed";
+    return false;
+    }
+  
+  this->resetSlotCalls();
+  // should do nothing...
+  connection = this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                                 this, SLOT(onVTKObjectModifiedPublic()));
+  if (!connection.isEmpty())
+    {
+    qDebug() << __LINE__ << "ctkVTKObject::qvtkConnect() failed: "<< connection;
+    return false;
+    }
+
+  object->Modified();
+  
+  if (d->PublicSlotCalled != 1)
+    {
+    qDebug() << __LINE__ << "qvtkConnect failed";
+    return false;
+    }
+
+  this->resetSlotCalls();
+
+  this->qvtkDisconnect(object, vtkCommand::WarningEvent, 
+                       this, SLOT(onVTKObjectModifiedPublic()));
+  object->Modified();
+
+  if (d->PublicSlotCalled != 1)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnect failed" << d->PublicSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  this->qvtkDisconnect(object, vtkCommand::ModifiedEvent, 
+                       this, SLOT(onVTKObjectModifiedPublic()));
+  QCoreApplication::instance()->processEvents();
+  object->Modified();
+
+  if (d->PublicSlotCalled != 0)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnect failed" << d->PublicSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+  
+  // Set a new connection (protected)
+  connection = this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                                 this, SLOT( onVTKObjectModifiedProtected ( ) ));
+  if (connection.isEmpty())
+    {
+    qDebug() << __LINE__ << "ctkVTKObject::qvtkConnect() failed: "<< connection;
+    return false;
+    }
+
+  object->Modified();
+  
+  if (d->ProtectedSlotCalled != 1)
+    {
+    qDebug() << __LINE__ << "ctkVTKObject::qvtkConnect failed" << d->ProtectedSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  // remove the connection using flags, 0 means any event, qt object or slot
+  this->qvtkDisconnect(object, vtkCommand::NoEvent, 0, 0);
+  object->Modified();
+
+  if (d->ProtectedSlotCalled != 0)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnect failed" << d->ProtectedSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  // Set new connections
+  this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                    this, SLOT(onVTKObjectModifiedProtected()));
+  this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                    this, SLOT(onVTKObjectModifiedPrivate()));
+  object->Modified();
+  if (d->ProtectedSlotCalled != 1 || 
+      d->PrivateSlotCalled != 1)
+    {
+    qDebug() << __LINE__ << "qvtkConnect failed" 
+             << d->ProtectedSlotCalled 
+             << d->PrivateSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  // remove the connection using flags, 0 means any event, qt object or slot
+  this->qvtkDisconnect(object, vtkCommand::ModifiedEvent, this, 0);
+  object->Modified();
+  if (d->ProtectedSlotCalled != 0 || d->PrivateSlotCalled != 0)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnect failed" 
+             << d->ProtectedSlotCalled
+             << d->PrivateSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  // Set new connections
+  this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                    this, SLOT(onVTKObjectModifiedPublic ()));
+  this->qvtkConnect(object, vtkCommand::WarningEvent, 
+                    this, SLOT(onVTKObjectModifiedPublic( )));
+  int disconnected = this->qvtkDisconnect(object, vtkCommand::NoEvent, 
+                                          this, SLOT(onVTKObjectModifiedPublic() ));
+  if (disconnected != 2)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnect failed" << disconnected;
+    return false;
+    }
+
+  object->InvokeEvent(vtkCommand::ModifiedEvent, 0);
+  object->InvokeEvent(vtkCommand::WarningEvent, 0);
+
+  if (d->PublicSlotCalled != 0)
+    {
+    qDebug() << __LINE__ << "qvtkConnect failed" 
+             << d->PublicSlotCalled;
+    return false;
+    }
+  this->resetSlotCalls();
+
+  disconnected = this->qvtkDisconnectAll();
+  if (disconnected != 0)
+    {
+    qDebug() << __LINE__ << "qvtkDisconnectAll failed" << disconnected;
+    return false;
+    }
+  this->qvtkConnect(object, vtkCommand::ModifiedEvent, 
+                    this, SLOT(deleteConnection()));
+  object->InvokeEvent(vtkCommand::ModifiedEvent, 0);
+
+  object->Delete();
+  
+  return true;
+}
+
+//------------------------------------------------------------------------------
+void ctkVTKObjectTest::resetSlotCalls()
+{
+  CTK_D(ctkVTKObjectTest);
+  d->PublicSlotCalled = 0;
+  d->ProtectedSlotCalled = 0;
+  d->PrivateSlotCalled = 0;
+}
+
+//------------------------------------------------------------------------------
+void ctkVTKObjectTest::onVTKObjectModifiedPublic()
+{
+  qDebug() << __FUNCTION__;
+  ctk_d()->PublicSlotCalled = true;
+}
+
+//------------------------------------------------------------------------------
+void ctkVTKObjectTest::deleteConnection()
+{
+  qDebug() << __FUNCTION__;
+  this->qvtkDisconnect(0, vtkCommand::NoEvent, 0, 0);
+}
+
+//------------------------------------------------------------------------------
+void ctkVTKObjectTest::onVTKObjectModifiedProtected()
+{
+  qDebug() << __FUNCTION__;
+  ctk_d()->ProtectedSlotCalled = true;
+}
+
+//------------------------------------------------------------------------------
+void ctkVTKObjectTest::onVTKObjectModifiedPrivate()
+{
+  qDebug() << __FUNCTION__;
+  ctk_d()->PrivateSlotCalled = true;
+}

+ 47 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/ctkVTKObjectTestHelper.h

@@ -0,0 +1,47 @@
+#ifndef __ctkVTKObjectTestHelper_h
+#define __ctkVTKObjectTestHelper_h
+
+// Qt includes
+#include <QObject>
+
+// CTK includes
+#include <ctkPimpl.h>
+
+// CTKVTK includes
+#include "ctkVTKObject.h"
+
+class ctkVTKObjectTestPrivate;
+
+class ctkVTKObjectTest: public QObject
+{
+  Q_OBJECT
+  QVTK_OBJECT
+public:
+  ctkVTKObjectTest();
+
+  bool test();
+
+  bool isPublicSlotCalled()const;
+  bool isProtectedSlotCalled()const;
+  bool isPrivateSlotCalled()const;
+
+  void resetSlotCalls();
+
+public slots:
+  void onVTKObjectModifiedPublic();
+  void deleteConnection();
+
+protected slots:
+  void onVTKObjectModifiedProtected();
+
+private slots:
+  void onVTKObjectModifiedPrivate();
+
+signals:
+  void signalEmitted();
+
+private:
+  CTK_DECLARE_PRIVATE(ctkVTKObjectTest);
+};
+
+#endif

+ 427 - 0
Libs/Visualization/VTK/Core/ctkVTKConnection.cpp

@@ -0,0 +1,427 @@
+// Qt includes
+#include <QDebug>
+#include <QRegExp>
+#include <QString>
+#include <QTextStream>
+
+// CTKVTK includes
+#include "ctkVTKConnection.h"
+
+// VTK includes
+#include <vtkObject.h>
+#include <vtkSmartPointer.h>
+#include <vtkCallbackCommand.h>
+
+//-----------------------------------------------------------------------------
+QString convertPointerToString(void* pointer)
+{
+  QString pointerAsString;
+  QTextStream(&pointerAsString) << pointer;
+  return pointerAsString;
+}
+
+//-----------------------------------------------------------------------------
+class ctkVTKConnectionPrivate: public ctkPrivate<ctkVTKConnection>
+{
+public:
+  enum
+    {
+    ARG_UNKNOWN = 0,
+    ARG_VTKOBJECT_AND_VTKOBJECT,
+    ARG_VTKOBJECT_VOID_ULONG_VOID
+    };
+
+  typedef ctkVTKConnectionPrivate Self;
+  ctkVTKConnectionPrivate();
+  ~ctkVTKConnectionPrivate();
+
+  void connect();
+  void disconnect();
+
+  /// 
+  /// VTK Callback
+  static void DoCallback(vtkObject* vtk_obj, unsigned long event,
+                         void* client_data, void* call_data);
+
+  /// 
+  /// Called by 'DoCallback' to emit signal
+  void Execute(vtkObject* vtk_obj, unsigned long vtk_event, void* client_data, void* call_data);
+
+  vtkSmartPointer<vtkCallbackCommand> Callback;
+  vtkObject*                          VTKObject;
+  const QObject*                      QtObject;
+  unsigned long                       VTKEvent;
+  QString                             QtSlot;
+  float                               Priority;
+  int                                 SlotType;
+  bool                                Connected;
+  bool                                Blocked;
+  QString                             Id;
+  bool                                AboutToBeDeleted;
+};
+
+//-----------------------------------------------------------------------------
+// ctkVTKConnectionPrivate methods
+
+//-----------------------------------------------------------------------------
+ctkVTKConnectionPrivate::ctkVTKConnectionPrivate()
+{
+  this->Callback    = vtkSmartPointer<vtkCallbackCommand>::New();
+  this->Callback->SetCallback(ctkVTKConnectionPrivate::DoCallback);
+  this->Callback->SetClientData(this);
+  this->VTKObject   = 0;
+  this->QtObject    = 0;
+  this->VTKEvent    = vtkCommand::NoEvent;
+  this->Priority    = 0.0;
+  this->SlotType    = ARG_UNKNOWN;
+  this->Connected   = false;
+  this->Blocked     = false;
+  this->Id          = convertPointerToString(this);
+  this->AboutToBeDeleted = false;
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKConnectionPrivate::~ctkVTKConnectionPrivate()
+{
+  /*
+  if(this->VTKObject && this->Connected)
+    {
+    this->VTKObject->RemoveObserver(this->Callback);
+    //Qt takes care of disconnecting slots
+    }
+  */
+
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnectionPrivate::connect()
+{
+  CTK_P(ctkVTKConnection);
+  
+  if (this->Connected) 
+    {
+    qDebug() << "ctkVTKConnection already connected.";
+    return; 
+    }
+
+  switch (this->SlotType)
+    {
+    case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
+      QObject::connect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
+                       this->QtObject, this->QtSlot.toLatin1().data());
+      break;
+    case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
+      QObject::connect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
+                       this->QtObject, this->QtSlot.toLatin1().data());
+      break;
+    default:
+      Q_ASSERT(false);
+      qCritical() << "Failed to connect - "
+                  << "The slot (" << this->QtSlot <<  ") owned by "
+                  << "QObject(" << this->QtObject->objectName() << ")"
+                  << " seems to have a wrong signature.";
+      break;
+    }
+
+  // Make a connection between this and the vtk object
+  this->VTKObject->AddObserver(this->VTKEvent, this->Callback, this->Priority);
+
+  // If necessary, observe vtk DeleteEvent
+  if(this->VTKEvent != vtkCommand::DeleteEvent)
+    {
+    this->VTKObject->AddObserver(vtkCommand::DeleteEvent, this->Callback);
+    }
+
+  // Remove itself from its parent when vtkObject is deleted
+  QObject::connect(this->QtObject, SIGNAL(destroyed(QObject*)), 
+                   p, SLOT(deleteConnection()));
+
+  this->Connected = true;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnectionPrivate::disconnect()
+{
+  CTK_P(ctkVTKConnection);
+  
+  if (!this->Connected) 
+    { 
+    Q_ASSERT(this->Connected);
+    return; 
+    }
+
+  this->VTKObject->RemoveObserver(this->Callback);
+
+  switch (this->SlotType)
+    {
+    case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
+      QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
+                          this->QtObject,this->QtSlot.toLatin1().data());
+      break;
+    case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
+      QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
+                          this->QtObject, this->QtSlot.toLatin1().data());
+      break;
+    default:
+      Q_ASSERT(false);
+      qCritical() << "Failed to disconnect - "
+                  << "The slot (" << this->QtSlot <<  ") owned by "
+                  << "QObject(" << this->QtObject->objectName() << ")"
+                  << " seems to have a wrong signature.";
+      break;
+    }
+
+  QObject::disconnect(this->QtObject, SIGNAL(destroyed(QObject*)),
+                      p, SLOT(deleteConnection()));
+
+  this->Connected = false;
+}
+
+//-----------------------------------------------------------------------------
+// ctkVTKConnection methods
+
+//-----------------------------------------------------------------------------
+ctkVTKConnection::ctkVTKConnection(QObject* _parent):
+  Superclass(_parent)
+{
+  CTK_INIT_PRIVATE(ctkVTKConnection);
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKConnection::~ctkVTKConnection()
+{
+  this->setEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+CTK_GET_CXX(ctkVTKConnection, QString, id, Id);
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnection::printAdditionalInfo()
+{
+  this->Superclass::dumpObjectInfo();
+
+  CTK_D(ctkVTKConnection);
+  
+  qDebug() << "ctkVTKConnection:" << this << endl
+           << "Id:" << d->Id << endl
+           << " VTKObject:" << d->VTKObject->GetClassName()
+             << "(" << d->VTKObject << ")" << endl
+           << " QtObject:" << d->QtObject << endl
+           << " VTKEvent:" << d->VTKEvent << endl
+           << " QtSlot:" << d->QtSlot << endl
+           << " SlotType:" << d->SlotType << endl
+           << " Priority:" << d->Priority << endl
+           << " Connected:" << d->Connected << endl
+           << " Blocked:" << d->Blocked;
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKConnection::shortDescription()
+{
+  CTK_D(ctkVTKConnection);
+  
+  return Self::shortDescription(d->VTKObject, d->VTKEvent, d->QtObject, d->QtSlot);
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKConnection::shortDescription(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, QString qt_slot)
+{
+  QString ret;
+  QTextStream ts( &ret );
+  ts << (vtk_obj ? vtk_obj->GetClassName() : "NULL") << " "
+     << vtk_event << " " << qt_obj << " " << qt_slot;
+  return ret;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKConnection::ValidateParameters(vtkObject* vtk_obj, unsigned long vtk_event,
+                                        const QObject* qt_obj, QString qt_slot)
+{
+  Q_UNUSED(vtk_event);
+  if (!vtk_obj)
+    {
+    return false;
+    }
+  if (!qt_obj)
+    {
+    return false;
+    }
+  if (qt_slot.isEmpty())
+    {
+    return false;
+    }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnection::SetParameters(vtkObject* vtk_obj, unsigned long vtk_event,
+  const QObject* qt_obj, QString qt_slot, float priority)
+{
+  CTK_D(ctkVTKConnection);
+  
+  if (!Self::ValidateParameters(vtk_obj, vtk_event, qt_obj, qt_slot)) 
+    { 
+    return; 
+    }
+
+  d->VTKObject = vtk_obj;
+  d->QtObject = qt_obj;
+  d->VTKEvent = vtk_event;
+  d->QtSlot = qt_slot;
+  d->Priority = priority;
+
+  if (qt_slot.contains(QRegExp(QString("\\( ?vtkObject ?\\* ?, ?vtkObject ?\\* ?\\)"))))
+    {
+    d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT;
+    }
+  else
+    {
+    d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnection::setEnabled(bool enable)
+{
+  CTK_D(ctkVTKConnection);
+  
+  if (d->Connected == enable)
+    {
+    return;
+    }
+
+  if (enable)
+    {
+    d->connect();
+    }
+  else
+    {
+    d->disconnect();
+    }
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKConnection::isEnabled()const
+{
+  CTK_D(const ctkVTKConnection);
+  return d->Connected;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnection::setBlocked(bool block)
+{
+  CTK_D(ctkVTKConnection);
+  d->Blocked = block;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKConnection::isBlocked()const
+{
+  CTK_D(const ctkVTKConnection);
+  return d->Blocked;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKConnection::isEqual(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, QString qt_slot)const
+{
+  CTK_D(const ctkVTKConnection);
+  
+  if (d->VTKObject != vtk_obj)
+    {
+    return false;
+    }
+  if (vtk_event != vtkCommand::NoEvent && d->VTKEvent != vtk_event)
+    {
+    return false;
+    }
+  if (qt_obj && d->QtObject != qt_obj)
+    {
+    return false;
+    }
+  if (!qt_slot.isEmpty() && 
+      (QString(d->QtSlot).remove(' ').compare(
+        QString(qt_slot).remove(' ')) != 0))
+    {
+    return false;
+    }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKConnectionPrivate::DoCallback(vtkObject* vtk_obj, unsigned long event,
+                                 void* client_data, void* call_data)
+{
+  ctkVTKConnectionPrivate* conn = static_cast<ctkVTKConnectionPrivate*>(client_data);
+  Q_ASSERT(conn);
+  conn->Execute(vtk_obj, event, client_data, call_data);
+}
+
+//-----------------------------------------------------------------------------
+// callback from VTK to emit signal
+void ctkVTKConnectionPrivate::Execute(vtkObject* vtk_obj, unsigned long vtk_event,
+  void* client_data, void* call_data)
+{
+  CTK_P(ctkVTKConnection);
+  
+  Q_ASSERT(this->Connected);
+  if (this->Blocked) 
+    { 
+    return; 
+    }
+  if (vtk_event == vtkCommand::DeleteEvent)
+    {
+    this->AboutToBeDeleted = true;
+    }
+
+  if(vtk_event != vtkCommand::DeleteEvent ||
+     (vtk_event == vtkCommand::DeleteEvent && this->VTKEvent == vtkCommand::DeleteEvent))
+    {
+    vtkObject* callDataAsVtkObject = 0;
+    switch (this->SlotType)
+      {
+      case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
+        if (this->VTKEvent == vtk_event)
+          {
+          callDataAsVtkObject = reinterpret_cast<vtkObject*>( call_data );
+          if (!callDataAsVtkObject)
+            {
+            qCritical() << "The VTKEvent(" << this->VTKEvent<< ") triggered by vtkObject("
+              << this->VTKObject->GetClassName() << ") "
+              << "doesn't return data of type vtkObject." << endl
+              << "The slot (" << this->QtSlot <<  ") owned by "
+              << "QObject(" << this->QtObject->objectName() << ")"
+              << " may be incorrect.";
+            }
+          emit p->emitExecute(vtk_obj, callDataAsVtkObject);
+          }
+        break;
+      case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
+        emit p->emitExecute(vtk_obj, call_data, vtk_event, client_data);
+        break;
+      default:
+        // Should never reach
+        qCritical() << "Unknown SlotType:" << this->SlotType;
+        return;
+        break;
+      }
+    }
+
+  if(vtk_event == vtkCommand::DeleteEvent)
+    {
+    this->AboutToBeDeleted = false;
+    p->deleteConnection();
+    }
+}
+
+void ctkVTKConnection::deleteConnection()
+{
+  CTK_D(ctkVTKConnection);
+  if (d->AboutToBeDeleted)
+    {
+    return;
+    }
+  delete this;
+}

+ 83 - 0
Libs/Visualization/VTK/Core/ctkVTKConnection.h

@@ -0,0 +1,83 @@
+#ifndef __ctkVTKConnection_h
+#define __ctkVTKConnection_h
+
+// Qt includes
+#include <QObject>
+#include <QVector>
+
+// CTK includes
+#include <ctkPimpl.h>
+
+#include "CTKVisualizationVTKCoreExport.h"
+
+class vtkObject;
+class ctkVTKConnectionPrivate;
+
+class CTK_VISUALIZATION_VTK_CORE_EXPORT ctkVTKConnection : public QObject
+{
+Q_OBJECT
+
+public:
+  typedef QObject Superclass;
+  explicit ctkVTKConnection(QObject* parent);
+
+  /// 
+  virtual void printAdditionalInfo();
+  QString shortDescription();
+  static QString shortDescription(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, QString qt_slot = "");
+
+  /// 
+  void SetParameters(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, QString qt_slot, float priority);
+
+  /// 
+  /// Check the validity of the parameters. Parameters must be valid to add 
+  /// a connection
+  static bool ValidateParameters(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, QString qt_slot);
+
+  /// 
+  /// Actually do the connection. Parameters must have been set prior to it
+  /// Disconnecting (enable = false) removes the connection.
+  void setEnabled(bool enable);
+  bool isEnabled()const;
+
+  /// 
+  /// Temporarilly block any signals/slots. If the event is fired, the slot
+  /// won't be called. You can restore the connection by calling SetBlocked
+  /// with block = false.
+  void setBlocked(bool block);
+  bool isBlocked()const;
+
+  /// 
+  bool isEqual(vtkObject* vtk_obj, unsigned long vtk_event,
+               const QObject* qt_obj, QString qt_slot)const;
+
+  /// 
+  /// Return a string uniquely identifying the connection within the current process
+  QString id()const;
+public slots:
+  ///
+  /// Safe deletion
+  void deleteConnection();
+
+signals:
+  /// 
+  /// The qt signal emited by the VTK Callback
+  /// The signal corresponding to the slot will be emited
+  void emitExecute(vtkObject* caller, vtkObject* call_data);
+
+  /// Note: even if the signal has a signature with 4 args, you can
+  /// connect it to a slot with less arguments as long as the types of the 
+  /// argument are matching:
+  /// connect(obj1,SIGNAL(signalFunc(A,B,C,D)),obj2,SLOT(slotFunc(A)));
+  void emitExecute(vtkObject* caller, void* call_data, unsigned long vtk_event, void* client_data);
+protected:
+  virtual ~ctkVTKConnection();
+
+private:
+  CTK_DECLARE_PRIVATE(ctkVTKConnection);
+};
+
+#endif

+ 107 - 0
Libs/Visualization/VTK/Core/ctkVTKObject.h

@@ -0,0 +1,107 @@
+#ifndef __ctkVTKObject_h
+#define __ctkVTKObject_h
+
+/// ctkVTK includes
+#include "ctkVTKObjectEventsObserver.h"
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_ADD_CONNECTION_METHOD                               \
+QString qvtkConnect(vtkObject* vtk_obj, unsigned long vtk_event,        \
+                    const QObject* qt_obj, const char* qt_slot,         \
+                    float priority = 0.0)                               \
+{                                                                       \
+  return MyQVTK.addConnection(vtk_obj, vtk_event,                       \
+                              qt_obj, qt_slot, priority);               \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_RECONNECT_METHOD                                    \
+QString qvtkReconnect(vtkObject* old_vtk_obj, vtkObject* vtk_obj,       \
+                      unsigned long vtk_event, const QObject* qt_obj,   \
+                      const char* qt_slot, float priority = 0.0)        \
+{                                                                       \
+  return MyQVTK.addConnection(old_vtk_obj, vtk_obj, vtk_event,          \
+                              qt_obj, qt_slot, priority);               \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_RECONNECT_METHOD_2                                  \
+QString qvtkReconnect(vtkObject* vtk_obj,                               \
+                      unsigned long vtk_event, const QObject* qt_obj,   \
+                      const char* qt_slot, float priority = 0.0)        \
+{                                                                       \
+  return MyQVTK.reconnection(vtk_obj, vtk_event,                        \
+                             qt_obj, qt_slot, priority);                \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_REMOVE_CONNECTION_METHOD                            \
+int qvtkDisconnect(vtkObject* vtk_obj, unsigned long vtk_event,         \
+  const QObject* qt_obj, const char* qt_slot)                           \
+{                                                                       \
+  return MyQVTK.removeConnection(vtk_obj, vtk_event,                    \
+    qt_obj, qt_slot);                                                   \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_REMOVEALL_CONNECTION_METHOD                         \
+int qvtkDisconnectAll()                                                 \
+{                                                                       \
+  return MyQVTK.removeAllConnections();                                 \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_BLOCK_CONNECTION_METHOD                              \
+void qvtkBlock(vtkObject* vtk_obj, unsigned long vtk_event,              \
+  const QObject* qt_obj)                                                 \
+{                                                                        \
+  MyQVTK.blockConnection(true, vtk_obj, vtk_event, qt_obj);              \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_BLOCK_CONNECTION_METHOD2                             \
+void qvtkBlock(const QString& id, bool blocked)                          \
+{                                                                        \
+  MyQVTK.blockConnection(id, blocked);                                   \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_BLOCKALL_CONNECTION_METHOD                          \
+void qvtkBlockAll()                                                     \
+{                                                                       \
+  MyQVTK.blockAllConnections(true);                                     \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_UNBLOCK_CONNECTION_METHOD                             \
+void qvtkUnblock(vtkObject* vtk_obj, unsigned long vtk_event,             \
+  const QObject* qt_obj)                                                  \
+{                                                                         \
+  MyQVTK.blockConnection(false, vtk_obj, vtk_event, qt_obj);              \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT_UNBLOCKALL_CONNECTION_METHOD                        \
+void qvtkUnblockAll()                                                   \
+{                                                                       \
+  MyQVTK.blockAllConnections(false);                                    \
+}
+
+//-----------------------------------------------------------------------------
+#define QVTK_OBJECT                                \
+protected:                                         \
+  QVTK_OBJECT_ADD_CONNECTION_METHOD                \
+  QVTK_OBJECT_RECONNECT_METHOD                     \
+  QVTK_OBJECT_RECONNECT_METHOD_2                   \
+  QVTK_OBJECT_REMOVE_CONNECTION_METHOD             \
+  QVTK_OBJECT_REMOVEALL_CONNECTION_METHOD          \
+  QVTK_OBJECT_BLOCK_CONNECTION_METHOD              \
+  QVTK_OBJECT_BLOCK_CONNECTION_METHOD2             \
+  QVTK_OBJECT_UNBLOCK_CONNECTION_METHOD            \
+  QVTK_OBJECT_BLOCKALL_CONNECTION_METHOD           \
+  QVTK_OBJECT_UNBLOCKALL_CONNECTION_METHOD         \
+private:                                           \
+  ctkVTKObjectEventsObserver MyQVTK;
+
+
+#endif

+ 306 - 0
Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.cpp

@@ -0,0 +1,306 @@
+
+// Qt includes
+#include <QStringList>
+#include <QVariant>
+#include <QList>
+#include <QHash>
+#include <QDebug>
+
+// CTK includes
+#include "ctkVTKObjectEventsObserver.h"
+#include "ctkVTKConnection.h"
+
+// VTK includes
+#include "vtkObject.h"
+#include "vtkSmartPointer.h"
+
+//-----------------------------------------------------------------------------
+class ctkVTKObjectEventsObserverPrivate: public ctkPrivate<ctkVTKObjectEventsObserver>
+{
+public:
+  ctkVTKObjectEventsObserverPrivate();
+
+  /// 
+  /// Check if a connection has already been added
+  bool containsConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot);
+
+  /// 
+  /// Return a reference toward the corresponding connection or 0 if doesn't exist
+  ctkVTKConnection* findConnection(const QString& id);
+
+  /// 
+  /// Return a reference toward the corresponding connection or 0 if doesn't exist
+  ctkVTKConnection* findConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot);
+
+  /// 
+  /// Return all the references that match the given parameters
+  QList<ctkVTKConnection*> findConnections(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot);
+  
+  inline QList<ctkVTKConnection*> connections()const
+  {
+    return ctk_p()->findChildren<ctkVTKConnection*>();
+  }
+  
+  bool                            AllEnabled;
+  bool                            AllBlocked;
+};
+
+//-----------------------------------------------------------------------------
+// ctkVTKObjectEventsObserver methods
+
+//-----------------------------------------------------------------------------
+ctkVTKObjectEventsObserver::ctkVTKObjectEventsObserver(QObject* _parent):Superclass(_parent)
+{
+  CTK_INIT_PRIVATE(ctkVTKObjectEventsObserver);
+  this->setProperty("QVTK_OBJECT", true);
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKObjectEventsObserver::printAdditionalInfo()
+{
+  this->Superclass::dumpObjectInfo();
+  CTK_D(ctkVTKObjectEventsObserver);
+  qDebug() << "ctkVTKObjectEventsObserver:" << this << endl
+           << " AllEnabled:" << d->AllEnabled << endl
+           << " AllBlocked:" << d->AllBlocked << endl
+           << " Parent:" << (this->parent()?this->parent()->objectName():"NULL") << endl
+           << " Connection count:" << d->connections().count();
+
+  // Loop through all connection
+  foreach (ctkVTKConnection* connection, d->connections())
+    {
+    connection->printAdditionalInfo();
+    }
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKObjectEventsObserver::allEnabled()const
+{
+  return ctk_d()->AllEnabled;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKObjectEventsObserver::setAllEnabled(bool enable)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+  // FIXME: maybe a particular module has been enabled/disabled
+  if (d->AllEnabled == enable) 
+    { 
+    return; 
+    }
+  // Loop through VTKQtConnections to enable/disable
+  foreach(ctkVTKConnection* connection, d->connections())
+    {
+    connection->setEnabled(enable);
+    }
+  d->AllEnabled = enable;
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKObjectEventsObserver::addConnection(vtkObject* old_vtk_obj, vtkObject* vtk_obj,
+  unsigned long vtk_event, const QObject* qt_obj, const char* qt_slot, float priority)
+{
+  QString connectionId; 
+  if (old_vtk_obj)
+    {
+    // Check that old_object and new_object are the same type
+    if (vtk_obj && !vtk_obj->IsA(old_vtk_obj->GetClassName()))
+      {
+      qCritical() << "Old vtkObject (type:" << old_vtk_obj->GetClassName() << ") to disconnect and "
+                  << "the new VtkObject (type:" << vtk_obj->GetClassName() << ") to connect"
+                  << "should have the same type.";
+      return connectionId;
+      }
+    // Disconnect old vtkObject
+    this->removeConnection(old_vtk_obj, vtk_event, qt_obj, qt_slot);
+    }
+  if (vtk_obj)
+    {
+    connectionId = this->addConnection(vtk_obj, vtk_event, qt_obj, qt_slot, priority);
+    }
+  return connectionId; 
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKObjectEventsObserver::reconnection(vtkObject* vtk_obj,
+  unsigned long vtk_event, const QObject* qt_obj, 
+  const char* qt_slot, float priority)
+{
+  QString connectionId; 
+  this->removeConnection(0, vtk_event, qt_obj, qt_slot);
+  if (vtk_obj)
+    {
+    connectionId = this->addConnection(vtk_obj, vtk_event, qt_obj, qt_slot, priority);
+    }
+  return connectionId; 
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKObjectEventsObserver::addConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+  const QObject* qt_obj, const char* qt_slot, float priority)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+  if (!ctkVTKConnection::ValidateParameters(vtk_obj, vtk_event, qt_obj, qt_slot))
+    {
+    qDebug() << "ctkVTKObjectEventsObserver::addConnection(...) - Invalid parameters - "
+             << ctkVTKConnection::shortDescription(vtk_obj, vtk_event, qt_obj, qt_slot);
+    return QString();
+    }
+
+  // Check if such event is already observed
+  if (d->containsConnection(vtk_obj, vtk_event, qt_obj, qt_slot))
+    {
+    qWarning() << "ctkVTKObjectEventsObserver::addConnection - [vtkObject:"
+               << vtk_obj->GetClassName()
+               << ", event:" << vtk_event << "]"
+               << " is already connected with [qObject:" << qt_obj->objectName()
+               << ", slot:" << qt_slot << "]";
+    return QString();
+    }
+
+  // Instantiate a new connection, set its parameters and add it to the list
+  ctkVTKConnection * connection = new ctkVTKConnection(this);
+  connection->SetParameters(vtk_obj, vtk_event, qt_obj, qt_slot, priority);
+
+  // If required, establish connection
+  connection->setEnabled(d->AllEnabled);
+  connection->setBlocked(d->AllBlocked);
+
+  return connection->id();
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKObjectEventsObserver::blockAllConnections(bool block)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+  this->printAdditionalInfo();
+  if (d->AllBlocked == block) { return; }
+
+  foreach (ctkVTKConnection* connection, d->connections())
+    {
+    connection->setBlocked(block);
+    }
+  d->AllBlocked = block;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKObjectEventsObserver::blockConnection(const QString& id, bool blocked)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+  ctkVTKConnection* connection = d->findConnection(id);
+  if (connection == 0)
+    {
+    return;
+    }
+  connection->setBlocked(blocked);
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKObjectEventsObserver::blockConnection(bool block, vtkObject* vtk_obj,
+  unsigned long vtk_event, const QObject* qt_obj)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+  if (!vtk_obj)
+    {
+    qDebug() << "ctkVTKObjectEventsObserver::blockConnectionRecursive"
+             << "- Failed to " << (block?"block":"unblock") <<" connection"
+             << "- vtkObject is NULL";
+    return 0;
+    }
+  QList<ctkVTKConnection*> connections =
+    d->findConnections(vtk_obj, vtk_event, qt_obj, 0);
+  foreach (ctkVTKConnection* connection, connections)
+    {
+    connection->setBlocked(block);
+    }
+  return connections.size();
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKObjectEventsObserver::removeConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot)
+{
+  CTK_D(ctkVTKObjectEventsObserver);
+
+  QList<ctkVTKConnection*> connections =
+    d->findConnections(vtk_obj, vtk_event, qt_obj, qt_slot);
+  
+  foreach (ctkVTKConnection* connection, connections)
+    {
+    connection->deleteConnection();
+    }
+  return connections.count();
+}
+
+//-----------------------------------------------------------------------------
+// ctkVTKObjectEventsObserverPrivate methods
+
+//-----------------------------------------------------------------------------
+ctkVTKObjectEventsObserverPrivate::ctkVTKObjectEventsObserverPrivate()
+{
+  this->AllEnabled = true;
+  this->AllBlocked = false;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKObjectEventsObserverPrivate::containsConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+  const QObject* qt_obj, const char* qt_slot)
+{
+  return (this->findConnection(vtk_obj, vtk_event, qt_obj, qt_slot) != 0);
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKConnection*
+ctkVTKObjectEventsObserverPrivate::findConnection(const QString& id)
+{
+  foreach(ctkVTKConnection* connection, this->connections())
+    {
+    if (connection->id() == id)
+      {
+      return connection;
+      }
+    }
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKConnection*
+ctkVTKObjectEventsObserverPrivate::findConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+                                         const QObject* qt_obj, const char* qt_slot)
+{
+  QList<ctkVTKConnection*> foundConnections =
+    this->findConnections(vtk_obj, vtk_event, qt_obj, qt_slot);
+
+  return foundConnections.size() ? foundConnections[0] : 0;
+}
+
+//-----------------------------------------------------------------------------
+QList<ctkVTKConnection*>
+ctkVTKObjectEventsObserverPrivate::findConnections(
+  vtkObject* vtk_obj, unsigned long vtk_event,
+  const QObject* qt_obj, const char* qt_slot)
+{
+  bool all_info = true;
+  if(qt_slot == NULL || qt_obj == NULL || vtk_event == vtkCommand::NoEvent)
+    {
+    all_info = false;
+    }
+
+  QList<ctkVTKConnection*> foundConnections;
+  // Loop through all connection
+  foreach (ctkVTKConnection* connection, this->connections())
+    {
+    if (connection->isEqual(vtk_obj, vtk_event, qt_obj, qt_slot)) 
+      {
+      foundConnections.append(connection); 
+      if (all_info)
+        {
+        break;
+        }
+      }
+    }
+  return foundConnections;
+}

+ 84 - 0
Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.h

@@ -0,0 +1,84 @@
+#ifndef __ctkVTKObjectEventsObserver_h
+#define __ctkVTKObjectEventsObserver_h
+
+/// CTK includes
+#include <ctkPimpl.h>
+
+/// Qt includes
+#include <QObject>
+#include <QList>
+#include <QString>
+
+/// VTK includes
+#include <vtkCommand.h>
+
+#include "CTKVisualizationVTKCoreExport.h"
+
+class ctkVTKConnection;
+class vtkObject;
+class ctkVTKObjectEventsObserverPrivate;
+
+class CTK_VISUALIZATION_VTK_CORE_EXPORT ctkVTKObjectEventsObserver : public QObject
+{
+Q_OBJECT
+
+public:
+  typedef QObject Superclass;
+  explicit ctkVTKObjectEventsObserver(QObject* parent = 0);
+  virtual ~ctkVTKObjectEventsObserver(){}
+
+  virtual void printAdditionalInfo();
+
+  /// 
+  /// Enable / Disable all ctkVTKConnections
+  void setAllEnabled( bool enable );
+  bool allEnabled()const;
+
+  /// 
+  /// Add a connection, an Id allowing to uniquely identify the connection is also returned
+  QString addConnection(vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot, float priority = 0.0);
+
+  ///
+  /// Utility function that remove a connection on old_vtk_obj and add a connection
+  /// to vtk_obj (same event, object, slot, priority)
+  QString addConnection(vtkObject* old_vtk_obj, vtkObject* vtk_obj, unsigned long vtk_event,
+    const QObject* qt_obj, const char* qt_slot, float priority = 0.0);
+
+  ///
+  /// Utility function that remove a connection on old_vtk_obj and add a connection
+  /// to vtk_obj (same event, object, slot, priority)
+  QString reconnection(vtkObject* vtk_obj, unsigned long vtk_event,
+                       const QObject* qt_obj, const char* qt_slot, 
+                       float priority = 0.0);
+
+  /// 
+  /// Remove a connection
+  int removeConnection(vtkObject* vtk_obj, unsigned long vtk_event = vtkCommand::NoEvent,
+                       const QObject* qt_obj = 0, const char* qt_slot = 0);
+
+  /// 
+  /// Remove all the connections
+  inline int removeAllConnections();
+
+  ///
+  /// Temporarilly block all the connection
+  void blockAllConnections(bool block);
+  
+  /// 
+  /// Block/Unblock a connection.
+  int blockConnection(bool block, vtkObject* vtk_obj,
+                      unsigned long vtk_event, const QObject* qt_obj);
+  void blockConnection(const QString& id, bool blocked);
+
+private:
+  CTK_DECLARE_PRIVATE(ctkVTKObjectEventsObserver);
+
+};
+
+int ctkVTKObjectEventsObserver::removeAllConnections()
+{
+  return this->removeConnection(0);
+}
+
+#endif

+ 10 - 0
Libs/Visualization/VTK/Core/target_libraries.cmake

@@ -0,0 +1,10 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK libraries
+#
+
+SET(target_libraries
+  VTK_LIBRARIES
+  CTKCore
+  )

+ 33 - 0
SuperBuild.cmake

@@ -7,6 +7,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION ${cmake_version_required})
 # CTK_KWSTYLE_EXECUTABLE
 # CTK_KWSTYLE_EXECUTABLE
 # DCMTK_DIR
 # DCMTK_DIR
 # QT_QMAKE_EXECUTABLE
 # QT_QMAKE_EXECUTABLE
+# VTK_DIR
 #
 #
 
 
 #-----------------------------------------------------------------------------
 #-----------------------------------------------------------------------------
@@ -227,6 +228,36 @@ IF(${add_project})
 ENDIF()
 ENDIF()
 
 
 #-----------------------------------------------------------------------------
 #-----------------------------------------------------------------------------
+# VTK
+#
+SET (VTK_DEPENDS)
+ctkMacroShouldAddExternalProject(VTK_LIBRARIES add_project)
+IF(${add_project})
+  IF(NOT DEFINED VTK_DIR)
+    SET(proj VTK)
+    MESSAGE(STATUS "Adding project:${proj}")
+    SET(VTK_DEPENDS ${proj})
+    ExternalProject_Add(${proj}
+      GIT_REPOSITORY git://vtk.org/VTK.git
+      INSTALL_COMMAND ""
+      CMAKE_GENERATOR ${gen}
+      CMAKE_ARGS
+        ${ep_common_args}
+        -DVTK_WRAP_TCL:BOOL=OFF
+        -DVTK_WRAP_PYTHON:BOOL=OFF
+        -DVTK_WRAP_JAVA:BOOL=OFF
+        -DBUILD_SHARED_LIBS:BOOL=ON 
+        -DDESIRED_QT_VERSION:STRING=4
+        -DVTK_USE_GUISUPPORT:BOOL=ON
+        -DVTK_USE_QVTK_QTOPENGL:BOOL=ON
+        -DVTK_USE_QT:BOOL=ON
+        -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
+      )
+    SET(VTK_DIR ${ep_build_dir}/${proj})
+  ENDIF()
+ENDIF()
+
+#-----------------------------------------------------------------------------
 # XIP
 # XIP
 #
 #
 SET (XIP_DEPENDS)
 SET (XIP_DEPENDS)
@@ -263,6 +294,7 @@ ExternalProject_Add(${proj}
     ${PythonQt_DEPENDS}
     ${PythonQt_DEPENDS}
     ${ZMQ_DEPENDS}
     ${ZMQ_DEPENDS}
     ${OpenIGTLink_DEPENDS}
     ${OpenIGTLink_DEPENDS}
+    ${VTK_DEPENDS}
     ${XIP_DEPENDS}
     ${XIP_DEPENDS}
 )
 )
 
 
@@ -333,6 +365,7 @@ ExternalProject_Add(${proj}
     -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
     -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
     -DCTK_KWSTYLE_EXECUTABLE:FILEPATH=${CTK_KWSTYLE_EXECUTABLE}
     -DCTK_KWSTYLE_EXECUTABLE:FILEPATH=${CTK_KWSTYLE_EXECUTABLE}
     -DDCMTK_DIR:PATH=${DCMTK_DIR} # FindDCMTK expects DCMTK_DIR
     -DDCMTK_DIR:PATH=${DCMTK_DIR} # FindDCMTK expects DCMTK_DIR
+    -DVTK_DIR:PATH=${VTK_DIR} # FindVTK expects VTK_DIR
   SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
   SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
   BINARY_DIR ${CMAKE_BINARY_DIR}/CTK-build
   BINARY_DIR ${CMAKE_BINARY_DIR}/CTK-build
   BUILD_COMMAND ""
   BUILD_COMMAND ""