ctkVTKConnection.cpp

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Library:   CTK
00004  
00005   Copyright (c) 2010  Kitware Inc.
00006 
00007   Licensed under the Apache License, Version 2.0 (the "License");
00008   you may not use this file except in compliance with the License.
00009   You may obtain a copy of the License at
00010 
00011       http://www.commontk.org/LICENSE
00012 
00013   Unless required by applicable law or agreed to in writing, software
00014   distributed under the License is distributed on an "AS IS" BASIS,
00015   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016   See the License for the specific language governing permissions and
00017   limitations under the License.
00018  
00019 =========================================================================*/
00020 
00021 // Qt includes
00022 #include <QDebug>
00023 #include <QRegExp>
00024 #include <QString>
00025 #include <QTextStream>
00026 
00027 // CTK includes
00028 #include "ctkVTKConnection.h"
00029 
00030 // VTK includes
00031 #include <vtkObject.h>
00032 #include <vtkSmartPointer.h>
00033 #include <vtkCallbackCommand.h>
00034 
00035 //-----------------------------------------------------------------------------
00036 QString convertPointerToString(void* pointer)
00037 {
00038   QString pointerAsString;
00039   QTextStream(&pointerAsString) << pointer;
00040   return pointerAsString;
00041 }
00042 
00043 //-----------------------------------------------------------------------------
00044 class ctkVTKConnectionPrivate: public ctkPrivate<ctkVTKConnection>
00045 {
00046 public:
00047   enum
00048     {
00049     ARG_UNKNOWN = 0,
00050     ARG_VTKOBJECT_AND_VTKOBJECT,
00051     ARG_VTKOBJECT_VOID_ULONG_VOID
00052     };
00053 
00054   typedef ctkVTKConnectionPrivate Self;
00055   ctkVTKConnectionPrivate();
00056   ~ctkVTKConnectionPrivate();
00057 
00058   void connect();
00059   void disconnect();
00060 
00063   static void DoCallback(vtkObject* vtk_obj, unsigned long event,
00064                          void* client_data, void* call_data);
00065 
00068   void Execute(vtkObject* vtk_obj, unsigned long vtk_event, void* client_data, void* call_data);
00069 
00070   vtkSmartPointer<vtkCallbackCommand> Callback;
00071   vtkObject*                          VTKObject;
00072   const QObject*                      QtObject;
00073   unsigned long                       VTKEvent;
00074   QString                             QtSlot;
00075   float                               Priority;
00076   int                                 SlotType;
00077   bool                                Connected;
00078   bool                                Blocked;
00079   QString                             Id;
00080   bool                                AboutToBeDeleted;
00081 };
00082 
00083 //-----------------------------------------------------------------------------
00084 // ctkVTKConnectionPrivate methods
00085 
00086 //-----------------------------------------------------------------------------
00087 ctkVTKConnectionPrivate::ctkVTKConnectionPrivate()
00088 {
00089   this->Callback    = vtkSmartPointer<vtkCallbackCommand>::New();
00090   this->Callback->SetCallback(ctkVTKConnectionPrivate::DoCallback);
00091   this->Callback->SetClientData(this);
00092   this->VTKObject   = 0;
00093   this->QtObject    = 0;
00094   this->VTKEvent    = vtkCommand::NoEvent;
00095   this->Priority    = 0.0;
00096   this->SlotType    = ARG_UNKNOWN;
00097   this->Connected   = false;
00098   this->Blocked     = false;
00099   this->Id          = convertPointerToString(this);
00100   this->AboutToBeDeleted = false;
00101 }
00102 
00103 //-----------------------------------------------------------------------------
00104 ctkVTKConnectionPrivate::~ctkVTKConnectionPrivate()
00105 {
00106   /*
00107   if(this->VTKObject && this->Connected)
00108     {
00109     this->VTKObject->RemoveObserver(this->Callback);
00110     //Qt takes care of disconnecting slots
00111     }
00112   */
00113 
00114 }
00115 
00116 //-----------------------------------------------------------------------------
00117 void ctkVTKConnectionPrivate::connect()
00118 {
00119   CTK_P(ctkVTKConnection);
00120   
00121   if (this->Connected) 
00122     {
00123     qDebug() << "ctkVTKConnection already connected.";
00124     return; 
00125     }
00126 
00127   switch (this->SlotType)
00128     {
00129     case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
00130       QObject::connect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
00131                        this->QtObject, this->QtSlot.toLatin1().data());
00132       break;
00133     case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
00134       QObject::connect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
00135                        this->QtObject, this->QtSlot.toLatin1().data());
00136       break;
00137     default:
00138       Q_ASSERT(false);
00139       qCritical() << "Failed to connect - "
00140                   << "The slot (" << this->QtSlot <<  ") owned by "
00141                   << "QObject(" << this->QtObject->objectName() << ")"
00142                   << " seems to have a wrong signature.";
00143       break;
00144     }
00145 
00146   // Make a connection between this and the vtk object
00147   this->VTKObject->AddObserver(this->VTKEvent, this->Callback, this->Priority);
00148 
00149   // If necessary, observe vtk DeleteEvent
00150   if(this->VTKEvent != vtkCommand::DeleteEvent)
00151     {
00152     this->VTKObject->AddObserver(vtkCommand::DeleteEvent, this->Callback);
00153     }
00154 
00155   // Remove itself from its parent when vtkObject is deleted
00156   QObject::connect(this->QtObject, SIGNAL(destroyed(QObject*)), 
00157                    p, SLOT(deleteConnection()));
00158 
00159   this->Connected = true;
00160 }
00161 
00162 //-----------------------------------------------------------------------------
00163 void ctkVTKConnectionPrivate::disconnect()
00164 {
00165   CTK_P(ctkVTKConnection);
00166   
00167   if (!this->Connected) 
00168     { 
00169     Q_ASSERT(this->Connected);
00170     return; 
00171     }
00172 
00173   this->VTKObject->RemoveObserver(this->Callback);
00174 
00175   switch (this->SlotType)
00176     {
00177     case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
00178       QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
00179                           this->QtObject,this->QtSlot.toLatin1().data());
00180       break;
00181     case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
00182       QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
00183                           this->QtObject, this->QtSlot.toLatin1().data());
00184       break;
00185     default:
00186       Q_ASSERT(false);
00187       qCritical() << "Failed to disconnect - "
00188                   << "The slot (" << this->QtSlot <<  ") owned by "
00189                   << "QObject(" << this->QtObject->objectName() << ")"
00190                   << " seems to have a wrong signature.";
00191       break;
00192     }
00193 
00194   QObject::disconnect(this->QtObject, SIGNAL(destroyed(QObject*)),
00195                       p, SLOT(deleteConnection()));
00196 
00197   this->Connected = false;
00198 }
00199 
00200 //-----------------------------------------------------------------------------
00201 // ctkVTKConnection methods
00202 
00203 //-----------------------------------------------------------------------------
00204 ctkVTKConnection::ctkVTKConnection(QObject* _parent):
00205   Superclass(_parent)
00206 {
00207   CTK_INIT_PRIVATE(ctkVTKConnection);
00208 }
00209 
00210 //-----------------------------------------------------------------------------
00211 ctkVTKConnection::~ctkVTKConnection()
00212 {
00213   this->setEnabled(false);
00214 }
00215 
00216 //-----------------------------------------------------------------------------
00217 CTK_GET_CXX(ctkVTKConnection, QString, id, Id);
00218 
00219 //-----------------------------------------------------------------------------
00220 void ctkVTKConnection::printAdditionalInfo()
00221 {
00222   this->Superclass::dumpObjectInfo();
00223 
00224   CTK_D(ctkVTKConnection);
00225   
00226   qDebug() << "ctkVTKConnection:" << this << endl
00227            << "Id:" << d->Id << endl
00228            << " VTKObject:" << d->VTKObject->GetClassName()
00229              << "(" << d->VTKObject << ")" << endl
00230            << " QtObject:" << d->QtObject << endl
00231            << " VTKEvent:" << d->VTKEvent << endl
00232            << " QtSlot:" << d->QtSlot << endl
00233            << " SlotType:" << d->SlotType << endl
00234            << " Priority:" << d->Priority << endl
00235            << " Connected:" << d->Connected << endl
00236            << " Blocked:" << d->Blocked;
00237 }
00238 
00239 //-----------------------------------------------------------------------------
00240 QString ctkVTKConnection::shortDescription()
00241 {
00242   CTK_D(ctkVTKConnection);
00243   
00244   return Self::shortDescription(d->VTKObject, d->VTKEvent, d->QtObject, d->QtSlot);
00245 }
00246 
00247 //-----------------------------------------------------------------------------
00248 QString ctkVTKConnection::shortDescription(vtkObject* vtk_obj, unsigned long vtk_event,
00249     const QObject* qt_obj, QString qt_slot)
00250 {
00251   QString ret;
00252   QTextStream ts( &ret );
00253   ts << (vtk_obj ? vtk_obj->GetClassName() : "NULL") << " "
00254      << vtk_event << " " << qt_obj << " " << qt_slot;
00255   return ret;
00256 }
00257 
00258 //-----------------------------------------------------------------------------
00259 bool ctkVTKConnection::ValidateParameters(vtkObject* vtk_obj, unsigned long vtk_event,
00260                                         const QObject* qt_obj, QString qt_slot)
00261 {
00262   Q_UNUSED(vtk_event);
00263   if (!vtk_obj)
00264     {
00265     return false;
00266     }
00267   if (!qt_obj)
00268     {
00269     return false;
00270     }
00271   if (qt_slot.isEmpty())
00272     {
00273     return false;
00274     }
00275   return true;
00276 }
00277 
00278 //-----------------------------------------------------------------------------
00279 void ctkVTKConnection::SetParameters(vtkObject* vtk_obj, unsigned long vtk_event,
00280   const QObject* qt_obj, QString qt_slot, float priority)
00281 {
00282   CTK_D(ctkVTKConnection);
00283   
00284   if (!Self::ValidateParameters(vtk_obj, vtk_event, qt_obj, qt_slot)) 
00285     { 
00286     return; 
00287     }
00288 
00289   d->VTKObject = vtk_obj;
00290   d->QtObject = qt_obj;
00291   d->VTKEvent = vtk_event;
00292   d->QtSlot = qt_slot;
00293   d->Priority = priority;
00294 
00295   if (qt_slot.contains(QRegExp(QString("\\( ?vtkObject ?\\* ?, ?vtkObject ?\\* ?\\)"))))
00296     {
00297     d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT;
00298     }
00299   else
00300     {
00301     d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID;
00302     }
00303 }
00304 
00305 //-----------------------------------------------------------------------------
00306 void ctkVTKConnection::setEnabled(bool enable)
00307 {
00308   CTK_D(ctkVTKConnection);
00309   
00310   if (d->Connected == enable)
00311     {
00312     return;
00313     }
00314 
00315   if (enable)
00316     {
00317     d->connect();
00318     }
00319   else
00320     {
00321     d->disconnect();
00322     }
00323 }
00324 
00325 //-----------------------------------------------------------------------------
00326 bool ctkVTKConnection::isEnabled()const
00327 {
00328   CTK_D(const ctkVTKConnection);
00329   return d->Connected;
00330 }
00331 
00332 //-----------------------------------------------------------------------------
00333 void ctkVTKConnection::setBlocked(bool block)
00334 {
00335   CTK_D(ctkVTKConnection);
00336   d->Blocked = block;
00337 }
00338 
00339 //-----------------------------------------------------------------------------
00340 bool ctkVTKConnection::isBlocked()const
00341 {
00342   CTK_D(const ctkVTKConnection);
00343   return d->Blocked;
00344 }
00345 
00346 //-----------------------------------------------------------------------------
00347 bool ctkVTKConnection::isEqual(vtkObject* vtk_obj, unsigned long vtk_event,
00348     const QObject* qt_obj, QString qt_slot)const
00349 {
00350   CTK_D(const ctkVTKConnection);
00351   
00352   if (d->VTKObject != vtk_obj)
00353     {
00354     return false;
00355     }
00356   if (vtk_event != vtkCommand::NoEvent && d->VTKEvent != vtk_event)
00357     {
00358     return false;
00359     }
00360   if (qt_obj && d->QtObject != qt_obj)
00361     {
00362     return false;
00363     }
00364   if (!qt_slot.isEmpty() && 
00365       (QString(d->QtSlot).remove(' ').compare(
00366         QString(qt_slot).remove(' ')) != 0))
00367     {
00368     return false;
00369     }
00370   return true;
00371 }
00372 
00373 //-----------------------------------------------------------------------------
00374 void ctkVTKConnectionPrivate::DoCallback(vtkObject* vtk_obj, unsigned long event,
00375                                  void* client_data, void* call_data)
00376 {
00377   ctkVTKConnectionPrivate* conn = static_cast<ctkVTKConnectionPrivate*>(client_data);
00378   Q_ASSERT(conn);
00379   conn->Execute(vtk_obj, event, client_data, call_data);
00380 }
00381 
00382 //-----------------------------------------------------------------------------
00383 // callback from VTK to emit signal
00384 void ctkVTKConnectionPrivate::Execute(vtkObject* vtk_obj, unsigned long vtk_event,
00385   void* client_data, void* call_data)
00386 {
00387   CTK_P(ctkVTKConnection);
00388   
00389   Q_ASSERT(this->Connected);
00390   if (this->Blocked) 
00391     { 
00392     return; 
00393     }
00394   if (vtk_event == vtkCommand::DeleteEvent)
00395     {
00396     this->AboutToBeDeleted = true;
00397     }
00398 
00399   if(vtk_event != vtkCommand::DeleteEvent ||
00400      (vtk_event == vtkCommand::DeleteEvent && this->VTKEvent == vtkCommand::DeleteEvent))
00401     {
00402     vtkObject* callDataAsVtkObject = 0;
00403     switch (this->SlotType)
00404       {
00405       case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
00406         if (this->VTKEvent == vtk_event)
00407           {
00408           callDataAsVtkObject = reinterpret_cast<vtkObject*>( call_data );
00409           if (!callDataAsVtkObject)
00410             {
00411             qCritical() << "The VTKEvent(" << this->VTKEvent<< ") triggered by vtkObject("
00412               << this->VTKObject->GetClassName() << ") "
00413               << "doesn't return data of type vtkObject." << endl
00414               << "The slot (" << this->QtSlot <<  ") owned by "
00415               << "QObject(" << this->QtObject->objectName() << ")"
00416               << " may be incorrect.";
00417             }
00418           emit p->emitExecute(vtk_obj, callDataAsVtkObject);
00419           }
00420         break;
00421       case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
00422         emit p->emitExecute(vtk_obj, call_data, vtk_event, client_data);
00423         break;
00424       default:
00425         // Should never reach
00426         qCritical() << "Unknown SlotType:" << this->SlotType;
00427         return;
00428         break;
00429       }
00430     }
00431 
00432   if(vtk_event == vtkCommand::DeleteEvent)
00433     {
00434     this->AboutToBeDeleted = false;
00435     p->deleteConnection();
00436     }
00437 }
00438 
00439 void ctkVTKConnection::deleteConnection()
00440 {
00441   CTK_D(ctkVTKConnection);
00442   if (d->AboutToBeDeleted)
00443     {
00444     return;
00445     }
00446   delete this;
00447 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines