Commit 78154b1a authored by Ken Martin's avatar Ken Martin
Browse files

new callbacks and multiple Tcl interp support

parent 3fb45bb9
......@@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "vtkObject.h"
#include "vtkDebugLeaks.h"
#include "vtkCommand.h"
// Initialize static member that controls warning display
static int vtkObjectGlobalWarningDisplay = 1;
......@@ -93,7 +95,7 @@ vtkObject::vtkObject()
this->Modified(); // Insures modified time > than any other time
// initial reference count = 1 and reference counting on.
this->ReferenceCount = 1;
this->DeleteMethod = NULL;
this->SubjectHelper = NULL;
}
// Delete a vtk object. This method should always be used to delete an object
......@@ -104,27 +106,6 @@ void vtkObject::Delete()
this->UnRegister((vtkObject *)NULL);
}
vtkObject::~vtkObject()
{
vtkDebugMacro(<< "Destructing!");
// warn user if reference counting is on and the object is being referenced
// by another object
if ( this->ReferenceCount > 0)
{
vtkErrorMacro(<< "Trying to delete object with non-zero reference count.");
}
}
void vtkObject::SetDeleteMethod(void (*f)(void *))
{
if (f != this->DeleteMethod)
{
this->DeleteMethod = f;
this->Modified();
}
}
// Return the modification for this object.
unsigned long int vtkObject::GetMTime()
{
......@@ -150,15 +131,6 @@ void vtkObject::PrintHeader(ostream& os, vtkIndent indent)
void vtkObject::PrintSelf(ostream& os, vtkIndent indent)
{
os << indent << "Debug: " << (this->Debug ? "On\n" : "Off\n");
if ( this->DeleteMethod )
{
os << indent << "Delete Method defined\n";
}
else
{
os << indent <<"No Delete Method\n";
}
os << indent << "Modified Time: " << this->GetMTime() << "\n";
os << indent << "Reference Count: " << this->ReferenceCount << "\n";
}
......@@ -252,10 +224,7 @@ void vtkObject::UnRegister(vtkObject* o)
vtkDebugLeaks::DestructClass(this->GetClassName());
#endif
// invoke the delete method
if ( this->DeleteMethod )
{
(*this->DeleteMethod)(this);
}
this->InvokeEvent(vtkCommand::DeleteEvent,NULL);
delete this;
}
}
......@@ -280,4 +249,235 @@ vtkObject *vtkObject::SafeDownCast(vtkObject *o)
}
//
// define the SubjectHelper class and implement the Add/Remove methods
//
class vtkObserver
{
public:
vtkObserver()
{Event = 0; Next = NULL; Command = NULL; Tag = 0;};
~vtkObserver();
vtkCommand *Command;
unsigned long Event;
unsigned long Tag;
vtkObserver *Next;
};
vtkObserver::~vtkObserver()
{
delete this->Command;
}
class vtkSubjectHelper
{
public:
vtkSubjectHelper() {this->Start = NULL; this->End = NULL; this->Count = 1;};
~vtkSubjectHelper();
unsigned long AddObserver(unsigned long event, vtkCommand *cmd);
void RemoveObserver(unsigned long tag);
void InvokeEvent(unsigned long event, void *callData, vtkObject *self);
vtkCommand *GetCommand(unsigned long tag);
int HasObserver(unsigned long event);
protected:
vtkObserver *Start;
vtkObserver *End;
unsigned long Count;
};
vtkSubjectHelper::~vtkSubjectHelper()
{
vtkObserver *elem = this->Start;
vtkObserver *next;
while (elem)
{
next = elem->Next;
delete elem;
elem = next;
}
this->Start = NULL;
this->End = NULL;
}
unsigned long vtkSubjectHelper::
AddObserver(unsigned long event, vtkCommand *cmd)
{
vtkObserver *elem;
elem = new vtkObserver;
if (!this->Start)
{
this->Start = elem;
}
else
{
this->End->Next = elem;
}
this->End = elem;
elem->Event = event;
elem->Command = cmd;
elem->Next = NULL;
elem->Tag = this->Count;
this->Count++;
return elem->Tag;
}
void vtkSubjectHelper::RemoveObserver(unsigned long tag)
{
vtkObserver *elem;
vtkObserver *prev;
vtkObserver *next;
elem = this->Start;
prev = NULL;
while (elem)
{
if (elem->Tag == tag)
{
if (prev)
{
prev->Next = elem->Next;
next = prev->Next;
}
else
{
this->Start = elem->Next;
next = this->Start;
}
if (elem == this->End)
{
this->End = prev;
}
delete elem;
elem = next;
}
else
{
prev = elem;
elem = elem->Next;
}
}
}
int vtkSubjectHelper::HasObserver(unsigned long event)
{
vtkObserver *elem = this->Start;
while (elem)
{
if (elem->Event == event)
{
return 1;
}
elem = elem->Next;
}
return 0;
}
void vtkSubjectHelper::InvokeEvent(unsigned long event, void *callData,
vtkObject *self)
{
vtkObserver *elem = this->Start;
vtkObserver *next;
while (elem)
{
// store the next pointer because elem could disappear due to Command
next = elem->Next;
if (elem->Event == event)
{
elem->Command->Execute(self,callData);
}
elem = next;
}
}
vtkCommand *vtkSubjectHelper::GetCommand(unsigned long tag)
{
vtkObserver *elem = this->Start;
while (elem)
{
if (elem->Tag == tag)
{
return elem->Command;
}
elem = elem->Next;
}
return NULL;
}
unsigned long vtkObject::AddObserver(unsigned long event, vtkCommand *cmd)
{
if (!this->SubjectHelper)
{
this->SubjectHelper = new vtkSubjectHelper;
}
return this->SubjectHelper->AddObserver(event,cmd);
}
unsigned long vtkObject::AddObserver(const char *event,vtkCommand *cmd)
{
return this->AddObserver(vtkCommand::GetEventIdFromString(event), cmd);
}
vtkCommand *vtkObject::GetCommand(unsigned long tag)
{
if (this->SubjectHelper)
{
return this->SubjectHelper->GetCommand(tag);
}
return NULL;
}
void vtkObject::RemoveObserver(unsigned long tag)
{
if (this->SubjectHelper)
{
this->SubjectHelper->RemoveObserver(tag);
}
}
void vtkObject::InvokeEvent(unsigned long event, void *callData)
{
if (this->SubjectHelper)
{
this->SubjectHelper->InvokeEvent(event,callData, this);
}
}
void vtkObject::InvokeEvent(const char *event, void *callData)
{
this->InvokeEvent(vtkCommand::GetEventIdFromString(event), callData);
}
int vtkObject::HasObserver(unsigned long event)
{
if (this->SubjectHelper)
{
return this->SubjectHelper->HasObserver(event);
}
return 0;
}
int vtkObject::HasObserver(const char *event)
{
return this->HasObserver(vtkCommand::GetEventIdFromString(event));
}
vtkObject::~vtkObject()
{
vtkDebugMacro(<< "Destructing!");
// warn user if reference counting is on and the object is being referenced
// by another object
if ( this->ReferenceCount > 0)
{
vtkErrorMacro(<< "Trying to delete object with non-zero reference count.");
}
delete this->SubjectHelper;
this->SubjectHelper = NULL;
}
......@@ -69,6 +69,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "vtkTimeStamp.h"
#include "vtkSetGet.h"
class vtkSubjectHelper;
class vtkCommand;
class VTK_EXPORT vtkObject
{
public:
......@@ -184,13 +187,22 @@ public:
// Sets the reference count (use with care)
void SetReferenceCount(int);
//BTX
// Description:
// A callback for when the destructor is called. Scripting
// languages use this to know when a C++ object has been freed.
// This is not intended for any use other than scripting.
void SetDeleteMethod(void (*f)(void *));
// Allow people to add/remove/invoke observers (callbacks) to any VTK object
// This is an implementation of the subject/observer design pattern. An
// observer is added by specifying an event to respond to and a vtkCommand
// to execute. It returns an unsigned long tag which can be used later to
// remove the event or retrieve the command.
//BTX
unsigned long AddObserver(unsigned long event, vtkCommand *);
unsigned long AddObserver(const char *event, vtkCommand *);
vtkCommand *GetCommand(unsigned long tag);
void InvokeEvent(unsigned long event, void *callData);
void InvokeEvent(const char *event, void *callData);
//ETX
void RemoveObserver(unsigned long tag);
int HasObserver(unsigned long event);
int HasObserver(const char *event);
protected:
vtkObject();
......@@ -201,7 +213,7 @@ protected:
unsigned char Debug; // Enable debug messages
vtkTimeStamp MTime; // Keep track of modification time
int ReferenceCount; // Number of uses of this object by other objects
void (*DeleteMethod)(void *);
vtkSubjectHelper *SubjectHelper;
private:
//BTX
......
......@@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "vtkProcessObject.h"
#include "vtkObjectFactory.h"
#include "vtkCommand.h"
//-------------------------------------------------------------------------
vtkProcessObject* vtkProcessObject::New()
......@@ -58,15 +59,9 @@ vtkProcessObject* vtkProcessObject::New()
// Instantiate object with no start, end, or progress methods.
vtkProcessObject::vtkProcessObject()
{
this->StartMethod = NULL;
this->StartMethodArgDelete = NULL;
this->StartMethodArg = NULL;
this->ProgressMethod = NULL;
this->ProgressMethodArgDelete = NULL;
this->ProgressMethodArg = NULL;
this->EndMethod = NULL;
this->EndMethodArgDelete = NULL;
this->EndMethodArg = NULL;
this->StartTag = 0;
this->ProgressTag = 0;
this->EndTag = 0;
this->AbortExecute = 0;
this->Progress = 0.0;
this->ProgressText = NULL;
......@@ -80,19 +75,6 @@ vtkProcessObject::vtkProcessObject()
// Destructor for the vtkProcessObject class
vtkProcessObject::~vtkProcessObject()
{
if ((this->StartMethodArg)&&(this->StartMethodArgDelete))
{
(*this->StartMethodArgDelete)(this->StartMethodArg);
}
if ((this->ProgressMethodArg)&&(this->ProgressMethodArgDelete))
{
(*this->ProgressMethodArgDelete)(this->ProgressMethodArg);
}
if ((this->EndMethodArg)&&(this->EndMethodArgDelete))
{
(*this->EndMethodArgDelete)(this->EndMethodArg);
}
int idx;
for (idx = 0; idx < this->NumberOfInputs; ++idx)
......@@ -309,10 +291,7 @@ void vtkProcessObject::SetNthInput(int idx, vtkDataObject *input)
void vtkProcessObject::UpdateProgress(float amount)
{
this->Progress = amount;
if ( this->ProgressMethod )
{
(*this->ProgressMethod)(this->ProgressMethodArg);
}
this->InvokeEvent(vtkCommand::StartEvent,(void *)&amount);
}
void vtkProcessObject::SetProgressText(char *text)
......@@ -328,79 +307,64 @@ char *vtkProcessObject::GetProgressText(void)
// Specify function to be called before object executes.
void vtkProcessObject::SetStartMethod(void (*f)(void *), void *arg)
{
if ( f != this->StartMethod || arg != this->StartMethodArg )
{
// delete the current arg if there is one and a delete meth
if ((this->StartMethodArg)&&(this->StartMethodArgDelete))
{
(*this->StartMethodArgDelete)(this->StartMethodArg);
}
this->StartMethod = f;
this->StartMethodArg = arg;
this->Modified();
}
vtkOldStyleCallbackCommand *cbc = new vtkOldStyleCallbackCommand;
cbc->Callback = f;
cbc->ClientData = arg;
this->RemoveObserver(this->StartTag);
this->StartTag = this->AddObserver(vtkCommand::StartEvent,cbc);
}
// Specify function to be called to show progress of filter
void vtkProcessObject::SetProgressMethod(void (*f)(void *), void *arg)
{
if ( f != this->ProgressMethod || arg != this->ProgressMethodArg )
{
// delete the current arg if there is one and a delete meth
if ((this->ProgressMethodArg)&&(this->ProgressMethodArgDelete))
{
(*this->ProgressMethodArgDelete)(this->ProgressMethodArg);
}
this->ProgressMethod = f;
this->ProgressMethodArg = arg;
this->Modified();
}
vtkOldStyleCallbackCommand *cbc = new vtkOldStyleCallbackCommand;
cbc->Callback = f;
cbc->ClientData = arg;
this->RemoveObserver(this->ProgressTag);
this->ProgressTag = this->AddObserver(vtkCommand::ProgressEvent,cbc);
}
// Specify function to be called after object executes.
void vtkProcessObject::SetEndMethod(void (*f)(void *), void *arg)
{
if ( f != this->EndMethod || arg != this->EndMethodArg )
{
// delete the current arg if there is one and a delete meth
if ((this->EndMethodArg)&&(this->EndMethodArgDelete))
{
(*this->EndMethodArgDelete)(this->EndMethodArg);
}
this->EndMethod = f;
this->EndMethodArg = arg;
this->Modified();
}
vtkOldStyleCallbackCommand *cbc = new vtkOldStyleCallbackCommand;
cbc->Callback = f;
cbc->ClientData = arg;
this->RemoveObserver(this->EndTag);
this->EndTag = this->AddObserver(vtkCommand::EndEvent,cbc);
}
// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetStartMethodArgDelete(void (*f)(void *))
{
if ( f != this->StartMethodArgDelete)
vtkOldStyleCallbackCommand *cmd =
(vtkOldStyleCallbackCommand *)this->GetCommand(this->StartTag);
if (cmd)
{
this->StartMethodArgDelete = f;
this->Modified();
cmd->SetClientDataDeleteCallback(f);
}
}
// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetProgressMethodArgDelete(void (*f)(void *))
{
if ( f != this->ProgressMethodArgDelete)
vtkOldStyleCallbackCommand *cmd =
(vtkOldStyleCallbackCommand *)this->GetCommand(this->ProgressTag);
if (cmd)
{
this->ProgressMethodArgDelete = f;
this->Modified();
cmd->SetClientDataDeleteCallback(f);
}
}
// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetEndMethodArgDelete(void (*f)(void *))
{
if ( f != this->EndMethodArgDelete)
vtkOldStyleCallbackCommand *cmd =
(vtkOldStyleCallbackCommand *)this->GetCommand(this->EndTag);
if (cmd)
{
this->EndMethodArgDelete = f;
this->Modified();
cmd->SetClientDataDeleteCallback(f);
}
}
......@@ -416,7 +380,6 @@ void vtkProcessObject::RemoveAllInputs()
this->Inputs[idx] = NULL;
}
}
delete [] this->Inputs;
this->Inputs = NULL;
this->NumberOfInputs = 0;
......@@ -535,33 +498,6 @@ void vtkProcessObject::PrintSelf(ostream& os, vtkIndent indent)
os << indent <<"No Inputs\n";
}
if ( this->StartMethod )
{
os << indent << "Start Method defined\n";
}
else
{
os << indent <<"No Start Method\n";
}
if ( this->ProgressMethod )
{
os << indent << "Progress Method defined\n";
}
else
{
os << indent << "No Progress Method\n";
}
if ( this->EndMethod )
{
os << indent << "End Method defined\n";
}
else
{
os << indent << "No End Method\n";
}
os << indent << "AbortExecute: " << (this->AbortExecute ? "On\n" : "Off\n");
os << indent << "Progress: " << this->Progress << "\n";
}
......@@ -165,15 +165,9 @@ protected:
void operator=(const vtkProcessObject&) {};
// Progress/Update handling
void (*StartMethod)(void *);
void (*StartMethodArgDelete)(void *);
void *StartMethodArg;
void (*ProgressMethod)(void *);
void *ProgressMethodArg;
void (*ProgressMethodArgDelete)(void *);
void (*EndMethod)(void *);
void (*EndMethodArgDelete)(void *);
void *EndMethodArg;
unsigned long StartTag;
unsigned long ProgressTag;
unsigned long EndTag;
float Progress;
char *ProgressText;
......
......@@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "vtkSource.h"
#include "vtkDataObject.h"
#include "vtkObjectFactory.h"
#include "vtkCommand.h"
//----------------------------------------------------------------------------
......@@ -372,10 +372,7 @@ void vtkSource::UpdateData(vtkDataObject *vtkNotUsed(output))
}
// If there is a start method, call it
if ( this->StartMethod )
{
(*this->StartMethod)(this->StartMethodArg);
}
this->InvokeEvent(vtkCommand::StartEvent,NULL);
// Execute this object - we have not aborted yet, and our progress
// before we start to execute is 0.0.
......@@ -398,10 +395,7 @@ void vtkSource::UpdateData(vtkDataObject *vtkNotUsed(output))
}
// Call the end method, if there is one
if ( this->EndMethod )
{
(*this->EndMethod)(this->EndMethodArg);
}
this->InvokeEvent(vtkCommand::EndEvent,NULL);
// Now we have to mark the data as up to data.
for (idx = 0; idx < this->NumberOfOutputs; ++idx)
......
......@@ -527,27 +527,14 @@ void stuffitTcl(FILE *fp, CPcmakerDlg *vals)
{
fprintf(fp,"int vtkCommand(ClientData cd, Tcl_Interp *interp,\n int argc, char *argv[]);\n");
// claw: I am adding this so c++ can evaluate strings.
fprintf(fp,"\nTcl_Interp *vtkGlobalTclInterp;\n");
fprintf(fp,"\n__declspec( dllexport) Tcl_HashTable vtkInstanceLookup;\n");
fprintf(fp,"__declspec( dllexport) Tcl_HashTable vtkPointerLookup;\n");
fprintf(fp,"__declspec( dllexport) Tcl_HashTable vtkCommandLookup;\n");
}
else
{
fprintf(fp,"\nextern Tcl_HashTable vtkInstanceLookup;\n");
fprintf(fp,"extern Tcl_HashTable vtkPointerLookup;\n");