// @(#)root/base:$Name: $:$Id: TQObject.cxx,v 1.36 2003/05/15 18:01:56 rdm Exp $
// Author: Valeriy Onuchin & Fons Rademakers 15/10/2000
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// This is the ROOT implementation of the Qt object communication //
// mechanism (see also http://www.troll.no/qt/metaobjects.html) //
// //
// Signals and slots are used for communication between objects. //
// When an object has changed in some way that might be interesting //
// for the outside world, it emits a signal to tell whoever is //
// listening. All slots that are connected to this signal will be //
// activated (called). It is even possible to connect a signal //
// directly to another signal (this will emit the second signal //
// immediately whenever the first is emitted.) There is no limitation //
// on the number of slots that can be connected to a signal. //
// The slots will be activated in the order they were connected //
// to the signal. This mechanism allows objects to be easily reused, //
// because the object that emits a signal does not need to know //
// to which objects the signals are connected. //
// Together, signals and slots make up a powerfull component //
// programming mechanism. //
// //
// This implementation is provided by //
// Valeriy Onuchin (onuchin@sirius.ihep.su). //
// //
//////////////////////////////////////////////////////////////////////////
//***************************** Signals *****************************
//___________________________________________________________________
//
// Destroyed()
//
// Signal emitted when object is destroyed.
// This signal could be connected to some garbage-collector object.
//
//___________________________________________________________________
//
// ChangedBy(const char *method_name)
//
// This signal is emitted when some important data members of
// the object were changed. method_name parameter can be used
// as an identifier of the modifier method.
//
//___________________________________________________________________
//
// Message(const char *msg)
//
// General purpose message signal
//
/////////////////////////////////////////////////////////////////////
#include "TQObject.h"
#include "TQConnection.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TMethod.h"
#include "TBaseClass.h"
#include "TDataType.h"
#include "TInterpreter.h"
#include "TClass.h"
#include "TError.h"
#include "G__ci.h"
#include "Api.h"
#include "Riostream.h"
#include "RQ_OBJECT.h"
#include "TVirtualMutex.h"
#ifdef HAVE_CONFIG
#include "config.h"
#endif
void *gTQSender; // A pointer to the object that sent the last signal.
// Getting access to the sender might be practical
// when many signals are connected to a single slot.
ClassImpQ(TQObject)
ClassImpQ(TQObjSender)
ClassImpQ(TQClass)
/////////////////// internal use static functions ///////////////////
//______________________________________________________________________________
static char *ResolveTypes(const char *method)
{
// Resolve any typedefs in the method signature. For example:
// func(Float_t,Int_t) becomes func(float,int).
// The returned string must be deleted by the user.
if (!method || !*method) return 0;
char *str = new char[strlen(method)+1];
if (str) strcpy(str, method);
TString res;
char *s = strtok(str, "(");
res = s;
res += "(";
Bool_t first = kTRUE;
while ((s = strtok(0, ",)"))) {
char *s1, s2 = 0;
if ((s1 = strchr(s, '*'))) {
*s1 = 0;
s2 = '*';
}
if (!s1 && (s1 = strchr(s, '&'))) {
*s1 = 0;
s2 = '&';
}
TDataType *dt = gROOT->GetType(s);
if (s1) *s1 = s2;
if (!first) res += ",";
if (dt) {
res += dt->GetFullTypeName();
if (s1) res += s1;
} else
res += s;
first = kFALSE;
}
res += ")";
delete [] str;
str = new char[res.Length()+1];
strcpy(str, res.Data());
return str;
}
//______________________________________________________________________________
static char *CompressName(const char *method_name)
{
// Removes "const" words and blanks from full (with prototype)
// method name.
//
// Example: CompressName(" Draw(const char *, const char *,
// Option_t * , Int_t , Int_t)")
//
// Returns the string "Draw(char*,char*,char*,int,int)"
// The returned string must be deleted by the user.
if (!method_name || !*method_name) return 0;
char *str = new char[strlen(method_name)+1];
if (str) strcpy(str, method_name);
char *tmp = str;
// substitute "const" with white spaces
while ((tmp = strstr(tmp,"const"))) {
for (int i = 0; i < 5; i++) *(tmp+i) = ' ';
}
tmp = str;
char *s;
s = str;
Bool_t quote = kFALSE;
while (*tmp) {
if (*tmp == '"')
quote = quote ? kFALSE : kTRUE;
if (*tmp != ' ' || quote)
*s++ = *tmp;
tmp++;
}
*s = '0';
s = ResolveTypes(str);
delete [] str;
return s;
}
//______________________________________________________________________________
static TMethod *GetMethodWithPrototype(TClass *cl, const char *method,
const char *proto, Int_t &nargs)
{
// Almost the same as TClass::GetMethodWithPrototype().
nargs = 0;
if (!gInterpreter) return 0;
R__LOCKGUARD(gCINTMutex);
Long_t faddr = 0;
if (!cl->IsLoaded()) {
// interpreted class
G__MethodInfo meth;
long offset;
if (cl->GetClassInfo())
meth = cl->GetClassInfo()->GetMethod(method, proto, &offset);
if (meth.IsValid()) {
nargs = meth.NArg();
return (TMethod *) -1;
}
return 0;
} else {
faddr = (Long_t)gInterpreter->GetInterfaceMethodWithPrototype(cl, method,
proto);
if (!faddr) return 0;
}
TMethod *m;
TIter next_method(cl->GetListOfMethods());
// Look for a method in this class
while ((m = (TMethod *) next_method())) {
if (faddr == (Long_t)m->InterfaceMethod()) {
nargs = m->GetNargs();
return m;
}
}
TIter next_base(cl->GetListOfBases());
TBaseClass *base;
// loop over all base classes
while ((base = (TBaseClass *)next_base())) {
TClass *c;
if ((c = base->GetClassPointer())) {
if ((m = GetMethodWithPrototype(c, method, proto, nargs))) return m;
}
}
return 0;
}
//______________________________________________________________________________
static TMethod *GetMethod(TClass *cl, const char *method, const char *params)
{
// Almost the same as TClass::GetMethod().
if (!gInterpreter) return 0;
R__LOCKGUARD(gCINTMutex);
Long_t faddr = 0;
if (!cl->IsLoaded()) {
// interpreted class
G__CallFunc func;
long offset;
func.SetFunc(cl->GetClassInfo(), method, params, &offset);
if (func.IsValid())
return (TMethod *) -1;
return 0;
} else {
faddr = (Long_t)gInterpreter->GetInterfaceMethod(cl, method, params);
if (!faddr) return 0;
}
TMethod *m;
TIter next_method(cl->GetListOfMethods());
// Look for a method in this class
while ((m = (TMethod *) next_method())) {
if (faddr == (Long_t)m->InterfaceMethod()) return m;
}
TIter next_base(cl->GetListOfBases());
TBaseClass *base;
// loop over all base classes
while ((base = (TBaseClass *)next_base())) {
TClass *c;
if ((c = base->GetClassPointer())) {
if ((m = GetMethod(c,method,params))) return m;
}
}
return 0;
}
//______________________________________________________________________________
Int_t TQObject::CheckConnectArgs(TQObject *sender,
TClass *sender_class, const char *signal,
TClass *receiver_class, const char *slot)
{
// Checking of consitency of sender/receiver methods/arguments.
// Returns -1 on error, otherwise number or arguments of signal function.
// Static method.
char *signal_method = new char[strlen(signal)+1];
if (signal_method) strcpy(signal_method, signal);
char *signal_proto;
char *tmp;
if ((signal_proto = strchr(signal_method,'('))) {
// substitute first '(' symbol with '0'
*signal_proto++ = '0';
// substitute last ')' symbol with '0'
if ((tmp = strrchr(signal_proto,')'))) *tmp = '0';
}
if (!signal_proto) signal_proto = (char*)""; // avoid zero strings
// if delegation object TQObjSender is used get the real sender class
if (sender && sender_class == TQObjSender::Class()) {
sender_class = gROOT->GetClass(sender->GetSenderClassName());
if (!sender_class) {
::Error("TQObject::CheckConnectArgs", "for signal/slot consistencyn"
"checking need to specify class name as argument to "
"RQ_OBJECT macro");
delete [] signal_method;
return -1;
}
}
Int_t nargs;
TMethod *signalMethod = GetMethodWithPrototype(sender_class,
signal_method,
signal_proto,
nargs);
if (!signalMethod) {
::Error("TQObject::CheckConnectArgs", "signal %s::%s(%s) does not exist",
sender_class->GetName(), signal_method, signal_proto);
delete [] signal_method;
return -1;
}
Int_t nsigargs = nargs;
#if defined(CHECK_COMMENT_STRING)
const char *comment = 0;
if (signalMethod != (TMethod *) -1) // -1 in case of interpreted class
comment = signalMethod->GetCommentString();
if (!comment || !strlen(comment) || strstr(comment,"*SIGNAL")){
::Error("TQObject::CheckConnectArgs",
"signal %s::%s(%s), to declare signal use comment //*SIGNAL*",
sender_class->GetName(), signal_method, signal_proto);
delete [] signal_method;
return -1;
}
#endif
// cleaning
delete [] signal_method;
char *slot_method = new char[strlen(slot)+1];
if (slot_method) strcpy(slot_method, slot);
char *slot_proto;
char *slot_params = 0;
if ((slot_proto = strchr(slot_method,'('))) {
// substitute first '(' symbol with '0'
*slot_proto++ = '0';
// substitute last ')' symbol with '0'
if ((tmp = strrchr(slot_proto,')'))) *tmp = '0';
}
if (!slot_proto) slot_proto = (char*)""; // avoid zero strings
if ((slot_params = strchr(slot_proto,'='))) *slot_params = ' ';
TFunction *slotMethod = 0;
if (!receiver_class) {
// case of slot_method is compiled/intrepreted function
slotMethod = (TFunction*)gROOT->GetListOfGlobalFunctions(kTRUE)->
FindObject(slot_method);
} else {
slotMethod = !slot_params ?
GetMethodWithPrototype(receiver_class,
slot_method,
slot_proto,
nargs) :
GetMethod(receiver_class,
slot_method, slot_params);
}
if (!slotMethod) {
if (!slot_params) {
::Error("TQObject::CheckConnectArgs", "slot %s(%s) does not exist",
receiver_class ? Form("%s::%s", receiver_class->GetName(),
slot_method) : slot_method, slot_proto);
} else {
::Error("TQObject::CheckConnectArgs", "slot %s(%s) does not exist",
receiver_class ? Form("%s::%s", receiver_class->GetName(),
slot_method) : slot_method, slot_params);
}
delete [] slot_method;
return -1;
}
#if defined(CHECK_ARGS_NUMBER)
if (slotMethod != (TMethod *) -1 && slotMethod->GetNargsOpt() >= 0 &&
nsigargs < (slotMethod->GetNargs() - slotMethod->GetNargsOpt())) {
::Error("TQObject::CheckConnectArgs",
"inconsistency in numbers of arguments");
delete [] slot_method;
return -1;
}
#endif
// cleaning
delete [] slot_method;
return nsigargs;
}
////////////////////////////////////////////////////////////////////////////////
// //
// TQConnectionList is the named list of connections, //
// see also TQConnection class. //
// //
////////////////////////////////////////////////////////////////////////////////
class TQConnectionList : public TList {
private:
Int_t fSignalArgs; // number of arguments in signal function
public:
TQConnectionList(const char *name, Int_t nsigargs) : TList()
{ fName = name; fSignalArgs = nsigargs; }
virtual ~TQConnectionList();
Bool_t Disconnect(void *receiver=0, const char *slot_name=0);
Int_t GetNargs() const { return fSignalArgs; }
void ls(Option_t *option = "") const;
void Print(Option_t *option = "") const;
};
//______________________________________________________________________________
TQConnectionList::~TQConnectionList()
{
// Destructor.
TIter next(this);
TQConnection *connection;
while ((connection = (TQConnection*)next())) {
// remove this from feed back reference list
connection->Remove(this);
if (connection->IsEmpty()) delete connection;
}
Clear("nodelete");
}
//______________________________________________________________________________
Bool_t TQConnectionList::Disconnect(void *receiver, const char *slot_name)
{
// Remove connection from the list. For more info see
// TQObject::Disconnect()
TQConnection *connection = 0;
Bool_t return_value = kFALSE;
TObjLink *lnk = FirstLink();
TObjLink *savlnk; // savlnk is used when link is deleted
while (lnk) {
connection = (TQConnection*)lnk->GetObject();
const char *name = connection->GetName();
void *obj = connection->GetReceiver();
if (!slot_name || !strlen(slot_name)
|| !strcmp(name,slot_name)) {
if (!receiver || (receiver == obj)) {
return_value = kTRUE;
savlnk = lnk->Next(); // keep next link ..
Remove(lnk);
lnk = savlnk; // current link == saved ...
connection->Remove(this); // remove back reference
if (connection->IsEmpty()) SafeDelete(connection);
continue; // .. continue from saved link
}
}
lnk = lnk->Next();
}
return return_value;
}
//______________________________________________________________________________
void TQConnectionList::ls(Option_t *option) const
{
// List signal name and list all connections in this signal list.
cout << "TQConnectionList:" << "t" << GetName() << endl;
((TQConnectionList*)this)->ForEach(TQConnection,Print)(option);
}
//______________________________________________________________________________
void TQConnectionList::Print(Option_t *) const
{
// Print signal name.
cout << "TQConnectionList:" << "t" << GetName() << endl;
}
//______________________________________________________________________________
TQObject::TQObject()
{
// TQObject Constructor.
// Comment:
// - In order to minimize memory allocation fListOfSignals and
// fListOfConnections are allocated only if it is neccesary
// - When fListOfSignals/fListOfConnections are empty they will
// be deleted
fListOfSignals = 0;
fListOfConnections = 0;
}
//______________________________________________________________________________
TQObject::~TQObject()
{
// TQObject Destructor.
// - delete all connections and signal list
if (!gROOT) return;
Destroyed(); // emit "Destroyed()" signal
if (fListOfSignals) {
fListOfSignals->Delete();
SafeDelete(fListOfSignals); // delete list of signals
}
// loop over all connections and remove references to this object
if (fListOfConnections) {
TIter next_connection(fListOfConnections);
TQConnection *connection;
while ((connection = (TQConnection*)next_connection())) {
TIter next_list(connection);
TQConnectionList *list;
while ((list = (TQConnectionList*)next_list())) {
list->Remove(connection);
if (list->IsEmpty()) SafeDelete(list);
}
}
SafeDelete(fListOfConnections);
}
}
//______________________________________________________________________________
TList *TQObject::GetListOfClassSignals() const
{
// Returns pointer to list of signals of this class.
TQClass *qcl = 0;
qcl = dynamic_cast<TQClass*>(IsA());
return qcl ? qcl->fListOfSignals : 0; //!!
}
//______________________________________________________________________________
void TQObject::HighPriority(const char *signal_name, const char *slot_name)
{
// 1. If slot_name = 0 => makes signal defined by the signal_name
// to be the first in the fListOfSignals, this decreases
// the time for lookup.
// 2. If slot_name != 0 => makes slot defined by the slot_name
// to be executed first when signal_name is emitted.
TQConnectionList *clist = 0;
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName()))
break;
}
if (!clist) return; // not found
if (!slot_name) { // update list of signal lists
fListOfSignals->Remove(clist); // remove and add first
fListOfSignals->AddFirst(clist);
return;
} else { // slot_name != 0 , update signal list
TQConnection *con = 0;
TIter next_con(clist);
while ((con = (TQConnection*)next_con())) {
if (!strcmp(slot_name,con->GetName()))
break;
}
if (!con) return; // not found
clist->Remove(con); // remove and add as first
clist->AddFirst(con);
}
}
//______________________________________________________________________________
void TQObject::LowPriority(const char *signal_name, const char *slot_name)
{
// 1. If slot_name = 0 => makes signal defined by the signal_name
// to be the last in the fListOfSignals, this increase the time
// for lookup.
// 2. If slot_name != 0 => makes slot defined by the slot_name
// to be executed last when signal_name is emitted.
TQConnectionList *clist = 0;
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName()))
break;
}
if (!clist) return;
if (!slot_name) {
fListOfSignals->Remove(clist); // remove and add first
fListOfSignals->AddLast(clist);
return;
} else { // slot_name != 0 , update signal list
TQConnection *con = 0;
TIter next_con(clist);
while ((con = (TQConnection*)next_con())) {
if (!strcmp(slot_name,con->GetName())) break;
}
if (!con) return;
clist->Remove(con); // remove and add as last
clist->AddLast(con);
}
}
//______________________________________________________________________________
Bool_t TQObject::HasConnection(const char *signal_name) const
{
// Return true if there is any object connected to this signal.
// Only checks for object signals.
if (!fListOfSignals)
return kFALSE;
register TQConnectionList *clist = 0;
char *signal = CompressName(signal_name);
// check object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal, clist->GetName())) {
delete [] signal;
return kTRUE;
}
}
delete [] signal;
return kFALSE;
}
//______________________________________________________________________________
Int_t TQObject::NumberOfSignals() const
{
// Return number of signals for this object.
if (fListOfSignals)
return fListOfSignals->GetSize();
return 0;
}
//______________________________________________________________________________
Int_t TQObject::NumberOfConnections() const
{
// Return number of connections for this object.
if (fListOfConnections)
return fListOfConnections->GetSize();
return 0;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal_name)
{
// Acitvate signal without args
// Example:
// theButton->Emit("Clicked()");
TList *slist = GetListOfClassSignals();
if (!slist && !fListOfSignals)
return;
gTQSender = GetSender();
register TQConnectionList *clist = 0;
register TQConnection *connection = 0;
char *signal = CompressName(signal_name);
// execute class signals
if (slist) {
TIter nextcl_list(slist);
while ((clist = (TQConnectionList*)nextcl_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (clist) {
TIter nextcl(clist);
while ((connection = (TQConnection*)nextcl())) {
connection->ExecuteMethod();
}
}
}
if (!fListOfSignals) {
delete [] signal;
return;
}
// execute object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (!clist) {
delete [] signal;
return;
}
TIter next(clist);
while ((connection = (TQConnection*)next())) {
connection->ExecuteMethod();
}
delete [] signal;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal_name, Long_t param)
{
// Activate signal with single parameter
// Example:
// theButton->Emit("Clicked(int)",id)
TList *slist = GetListOfClassSignals();
if (!slist && !fListOfSignals)
return;
gTQSender = GetSender();
register TQConnectionList *clist = 0;
register TQConnection *connection = 0;
char *signal = CompressName(signal_name);
// execute class signals
if (slist) {
TIter nextcl_list(slist);
while ((clist = (TQConnectionList*)nextcl_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (clist) {
TIter nextcl(clist);
while ((connection = (TQConnection*)nextcl())) {
connection->ExecuteMethod(param);
}
}
}
if (!fListOfSignals) {
delete [] signal;
return;
}
// execute object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (!clist) {
delete [] signal;
return;
}
TIter next(clist);
while ((connection = (TQConnection*)next())) {
connection->ExecuteMethod(param);
}
delete [] signal;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal_name, Double_t param)
{
// Activate signal with single parameter.
TList *slist = GetListOfClassSignals();
if (!slist && !fListOfSignals)
return;
gTQSender = GetSender();
register TQConnectionList *clist = 0;
register TQConnection *connection = 0;
char *signal = CompressName(signal_name);
// execute class signals
if (slist) {
TIter nextcl_list(slist);
while ((clist = (TQConnectionList*)nextcl_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (clist) {
TIter nextcl(clist);
while ((connection = (TQConnection*)nextcl())) {
connection->ExecuteMethod(param);
}
}
}
if (!fListOfSignals) {
delete [] signal;
return;
}
// execute object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (!clist) {
delete [] signal;
return;
}
TIter next(clist);
while ((connection = (TQConnection*)next())) {
connection->ExecuteMethod(param);
}
delete [] signal;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal_name, const char *params)
{
// Activate signal with parameter text string.
// Example:
// myObject->Emit("Error(char*)","Fatal error");
TList *slist = GetListOfClassSignals();
if (!slist && !fListOfSignals)
return;
gTQSender = GetSender();
register TQConnectionList *clist = 0;
register TQConnection *connection = 0;
char *signal = CompressName(signal_name);
// execute class signals
if (slist) {
TIter nextcl_list(slist);
while ((clist = (TQConnectionList*)nextcl_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (clist) {
TIter nextcl(clist);
while ((connection = (TQConnection*)nextcl())) {
connection->ExecuteMethod(params);
}
}
}
if (!fListOfSignals) {
delete [] signal;
return;
}
// execute object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (!clist) {
delete [] signal;
return;
}
TIter next(clist);
while ((connection = (TQConnection*)next())) {
connection->ExecuteMethod(params);
}
delete [] signal;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal_name, Long_t *paramArr)
{
// Emit a signal with a varying number of arguments,
// paramArr is an array of the parameters.
// Note: any parameter should be converted to long type.
// Example:
// TQObject *processor; // data processor
// TH1F *hist; // filled with processor results
//
// processor->Connect("Evaluated(Float_t,Float_t)",
// "TH1F",hist,"Fill12(Axis_t,Axis_t)");
//
// Long_t args[2];
// args[0] = (Long_t)processor->GetValue(1);
// args[1] = (Long_t)processor->GetValue(2);
//
// processor->Emit("Evaluated(Float_t,Float_t)",args);
TList *slist = GetListOfClassSignals();
if (!slist && !fListOfSignals)
return;
gTQSender = GetSender();
register TQConnectionList *clist = 0;
register TQConnection *connection = 0;
char *signal = CompressName(signal_name);
// execute class signals
if (slist) {
TIter nextcl_list(slist);
while ((clist = (TQConnectionList*)nextcl_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (clist) {
TIter nextcl(clist);
while ((connection = (TQConnection*)nextcl())) {
connection->ExecuteMethod(paramArr, clist->GetNargs());
}
}
}
if (!fListOfSignals) {
delete [] signal;
return;
}
// execute object signals
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal,clist->GetName())) break;
}
if (!clist) {
delete [] signal;
return;
}
TIter next(clist);
while ((connection = (TQConnection*)next())) {
connection->ExecuteMethod(paramArr, clist->GetNargs());
}
delete [] signal;
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal, Long64_t param)
{
// Emit a signal with a Long64_t argument.
Long_t args[1];
args[0] = (Long_t) (¶m);
Emit(signal, args);
}
//______________________________________________________________________________
void TQObject::Emit(const char *signal, ULong64_t param)
{
// Emit a signal with a ULong64_t argument.
Long_t args[1];
args[0] = (Long_t) (¶m);
Emit(signal, args);
}
//______________________________________________________________________________
Bool_t TQObject::ConnectToClass(TQObject *sender,
const char *signal,
TClass *cl,
void *receiver,
const char *slot)
{
// Create connection between sender and receiver.
// Receiver class needs to have a dictionary.
// sender should be TQObject
if (!sender->IsA()->InheritsFrom(TQObject::Class()))
return kFALSE;
// remove "const" and strip blanks
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
// check consitency of signal/slot methods/args
Int_t nsigargs;
if ((nsigargs = CheckConnectArgs(sender, sender->IsA(), signal_name, cl, slot_name)) == -1)
return kFALSE;
if (!sender->fListOfSignals)
sender->fListOfSignals = new TList();
TQConnectionList *clist=0;
TIter next_list(sender->fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName())) break;
}
if (!clist) {
clist = new TQConnectionList(signal_name, nsigargs);
sender->fListOfSignals->Add(clist);
}
TIter next(clist);
TQConnection *connection = 0;
while ((connection = (TQConnection*)next())) {
if (!strcmp(slot_name,connection->GetName()) &&
(receiver == connection->GetReceiver())) break;
}
if (!connection)
connection = new TQConnection(cl, receiver, slot_name);
// check to prevent multiple entries
if (!clist->FindObject(connection)) {
clist->Add(connection);
if (!connection->FindObject(clist)) connection->Add(clist);
sender->Connected(signal_name);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return kTRUE;
}
//______________________________________________________________________________
Bool_t TQObject::ConnectToClass(const char *class_name,
const char *signal,
TClass *cl,
void *receiver,
const char *slot)
{
// This method allows to make connection from any object
// of the same class to the receiver object.
// Receiver class needs to have a dictionary.
TClass *sender = gROOT->GetClass(class_name);
// sender class should be TQObject (i.e. TQClass)
if (!sender || !sender->IsA()->InheritsFrom(TQObject::Class()))
return kFALSE;
TList *slist = ((TQClass*)sender)->fListOfSignals;
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
// check consitency of signal/slot methods/args
Int_t nsigargs;
if ((nsigargs = CheckConnectArgs(0, sender, signal_name, cl, slot_name)) == -1)
return kFALSE;
TQConnectionList *clist = 0;
if (!slist)
((TQClass*)sender)->fListOfSignals = slist = new TList();
TIter next_list(slist);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName())) break;
}
if (!clist) {
clist = new TQConnectionList(signal_name, nsigargs);
slist->Add(clist);
}
TQConnection *connection = 0;
TIter next(clist);
while ((connection = (TQConnection*)next())) {
if (!strcmp(slot_name,connection->GetName()) &&
(receiver == connection->GetReceiver())) break;
}
if (!connection)
connection = new TQConnection(cl, receiver, slot_name);
// check to prevent multiple entries
if (!clist->FindObject(connection)) {
clist->Add(connection);
if (!connection->FindObject(clist)) connection->Add(clist);
((TQClass*)sender)->Connected(signal_name);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return kTRUE;
}
//______________________________________________________________________________
Bool_t TQObject::Connect(TQObject *sender,
const char *signal,
const char *cl,
void *receiver,
const char *slot)
{
// Create connection between sender and receiver.
// Signal and slot string must have a form:
// "Draw(char*, Option_t* ,Int_t)"
// All blanks and "const" words will be removed,
//
// cl != 0 - class name, it can be class with or
// without dictionary, e.g interpreted class.
// Example:
// TGButton *myButton;
// TH2F *myHist;
//
// TQObject::Connect(myButton,"Clicked()",
// "TH2F", myHist,"Draw(Option_t*)");
//
// cl == 0 - corresponds to function (interpereted or global)
// the name of the function is defined by the slot string,
// parameter receiver should be 0.
// Example:
// TGButton *myButton;
// TH2F *myHist;
//
// TQObject::Connect(myButton,"Clicked()",
// 0, 0,"hsimple()");
//
// Warning:
// If receiver is class not derived from TQObject and going to be
// deleted, disconnect all connections to this receiver.
// In case of class derived from TQObject it is done automatically.
if (cl) {
TClass *rcv_cl = gROOT->GetClass(cl);
if (rcv_cl) return ConnectToClass(sender, signal, rcv_cl, receiver, slot);
}
// the following is the case of receiver class without dictionary
// e.g. interpreted class or function.
// sender should be TQObject
if (!sender->IsA()->InheritsFrom(TQObject::Class()))
return kFALSE;
// remove "const" and strip blanks
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
// check consitency of signal/slot methods/args
Int_t nsigargs;
if ((nsigargs = CheckConnectArgs(sender, sender->IsA(), signal_name, 0, slot_name)) == -1)
return kFALSE;
if (!sender->fListOfSignals) sender->fListOfSignals = new TList();
TQConnectionList *clist = 0;
TIter next_list(sender->fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName())) break;
}
if (!clist) {
clist = new TQConnectionList(signal_name, nsigargs);
sender->fListOfSignals->Add(clist);
}
TQConnection *connection = 0;
TIter next(clist);
while ((connection = (TQConnection*)next())) {
if (!strcmp(slot_name,connection->GetName()) &&
(receiver == connection->GetReceiver())) break;
}
if (!connection)
connection = new TQConnection(cl, receiver, slot_name);
// check to prevent multiple entries
if (!clist->FindObject(connection)) {
clist->Add(connection);
if (!connection->FindObject(clist)) connection->Add(clist);
sender->Connected(signal_name);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return kTRUE;
}
//______________________________________________________________________________
Bool_t TQObject::Connect(const char *class_name,
const char *signal,
const char *cl,
void *receiver,
const char *slot)
{
// This method allows to make a connection from any object
// of the same class to a single slot.
// Signal and slot string must have a form:
// "Draw(char*, Option_t* ,Int_t)"
// All blanks and "const" words will be removed,
//
// cl != 0 - class name, it can be class with or
// without dictionary, e.g interpreted class.
// Example:
// TGButton *myButton;
// TH2F *myHist;
//
// TQObject::Connect("TGButton", "Clicked()",
// "TH2F", myHist, "Draw(Option_t*)");
//
// cl == 0 - corresponds to function (interpereted or global)
// the name of the function is defined by the slot string,
// parameter receiver should be 0.
// Example:
// TGButton *myButton;
// TH2F *myHist;
//
// TQObject::Connect("TGButton", "Clicked()",
// 0, 0, "hsimple()");
//
// Warning:
// If receiver class not derived from TQObject and going to be
// deleted, disconnect all connections to this receiver.
// In case of class derived from TQObject it is done automatically.
if (cl) {
TClass *rcv_cl = gROOT->GetClass(cl);
if (rcv_cl) return ConnectToClass(class_name, signal, rcv_cl, receiver,
slot);
}
// the following is case of receiver class without dictionary
// e.g. interpreted class or function.
TClass *sender = gROOT->GetClass(class_name);
// sender class should be TQObject (i.e. TQClass)
if (!sender || !sender->IsA()->InheritsFrom(TQObject::Class()))
return kFALSE;
TList *slist = ((TQClass*)sender)->fListOfSignals;
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
// check consitency of signal/slot methods/args
Int_t nsigargs;
if ((nsigargs = CheckConnectArgs(0, sender, signal_name, 0, slot_name)) == -1)
return kFALSE;
TQConnectionList *clist = 0;
if (!slist) {
slist = ((TQClass*)sender)->fListOfSignals = new TList();
}
TIter next_list(slist);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName())) break;
}
if (!clist) {
clist = new TQConnectionList(signal_name, nsigargs);
slist->Add(clist);
}
TQConnection *connection = 0;
TIter next(clist);
while ((connection = (TQConnection*)next())) {
if (!strcmp(slot_name,connection->GetName()) &&
(receiver == connection->GetReceiver())) break;
}
if (!connection)
connection = new TQConnection(cl, receiver, slot_name);
// check to prevent multiple entries
if (!clist->FindObject(connection)) {
clist->Add(connection);
if (!connection->FindObject(clist)) connection->Add(clist);
((TQClass*)sender)->Connected(signal_name);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return kTRUE;
}
//______________________________________________________________________________
Bool_t TQObject::Connect(const char *signal,
const char *receiver_class,
void *receiver,
const char *slot)
{
// Non-static method is used to connect from the signal
// of this object to the receiver slot.
//
// Warning! No check on consistency of sender/receiver
// classes/methods.
//
// This method makes possible to have connection/signals from
// interpreted class. See also RQ_OBJECT.h.
// remove "const" and strip blanks
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
// check consitency of signal/slot methods/args
TClass *cl = 0;
if (receiver_class)
cl = gROOT->GetClass(receiver_class);
Int_t nsigargs;
if ((nsigargs = CheckConnectArgs(this, IsA(), signal_name, cl, slot_name)) == -1)
return kFALSE;
if (!fListOfSignals) fListOfSignals = new TList();
TQConnectionList *clist = 0;
TIter next_list(fListOfSignals);
while ((clist = (TQConnectionList*)next_list())) {
if (!strcmp(signal_name,clist->GetName())) break;
}
if (!clist) {
clist = new TQConnectionList(signal_name, nsigargs);
fListOfSignals->Add(clist);
}
TIter next(clist);
TQConnection *connection = 0;
while ((connection = (TQConnection*)next())) {
if (!strcmp(slot_name,connection->GetName()) &&
(receiver == connection->GetReceiver())) break;
}
if (!connection)
connection = new TQConnection(receiver_class, receiver, slot_name);
// check to prevent multiple entries
if (!clist->FindObject(connection)) {
clist->Add(connection);
if (!connection->FindObject(clist)) connection->Add(clist);
Connected(signal_name);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return kTRUE;
}
//______________________________________________________________________________
Bool_t TQObject::Disconnect(TQObject *sender,
const char *signal,
void *receiver,
const char *slot)
{
// Disconnects signal in object sender from slot_method in
// object receiver. For objects derived from TQObject signal-slot
// connection is removed when either of the objects involved
// are destroyed.
//
// Disconnect() is typically used in three ways, as the following
// examples shows:
//
// - Disconnect everything connected to an object's signals:
// Disconnect(myObject);
// - Disconnect everything connected to a signal:
// Disconnect(myObject, "mySignal()");
// - Disconnect a specific receiver:
// Disconnect(myObject, 0, myReceiver, 0);
//
// 0 may be used as a wildcard in three of the four arguments,
// meaning "any signal", "any receiving object" or
// "any slot in the receiving object", respectively.
//
// The sender has no default and may never be 0
// (you cannot disconnect signals from more than one object).
//
// If signal is 0, it disconnects receiver and slot_method
// from any signal. If not, only the specified signal is
// disconnected.
//
// If receiver is 0, it disconnects anything connected to signal.
// If not, slots in objects other than receiver are not
// disconnected
//
// If slot_method is 0, it disconnects anything that is connected
// to receiver. If not, only slots named slot_method will be
// disconnected, and all other slots are left alone.
// The slot_method must be 0 if receiver is left out, so you
// cannot disconnect a specifically-named slot on all objects.
Bool_t return_value = kFALSE;
Bool_t next_return = kFALSE;
if (!sender->GetListOfSignals()) return kFALSE;
char *signal_name = CompressName(signal);
char *slot_name = CompressName(slot);
TQConnectionList *slist = 0;
TIter next_signal(sender->GetListOfSignals());
while ((slist = (TQConnectionList*)next_signal())) {
if (!signal_name) { // disconnect all signals
next_return = slist->Disconnect(receiver,slot_name);
return_value = return_value || next_return;
if (slist->IsEmpty()) {
sender->GetListOfSignals()->Remove(slist);
SafeDelete(slist); // delete empty list
}
} else if (signal && !strcmp(signal_name,slist->GetName())) {
next_return = slist->Disconnect(receiver,slot_name);
return_value = return_value || next_return;
if (slist->IsEmpty()) {
sender->GetListOfSignals()->Remove(slist);
SafeDelete(slist); // delete empty list
break;
}
}
}
if (sender->GetListOfSignals() && sender->GetListOfSignals()->IsEmpty()) {
SafeDelete(sender->fListOfSignals);
}
// cleaning
if (signal_name) { delete [] signal_name; signal_name = 0; }
if (slot_name) { delete [] slot_name; slot_name = 0; }
return return_value;
}
//______________________________________________________________________________
Bool_t TQObject::Disconnect(const char *class_name,
const char *signal,
void *receiver,
const char *slot)
{
// Disconnects "class signal". The class is defined by class_name.
// See also Connect(class_name,signal,receiver,slot).
TClass *sender = gROOT->GetClass(class_name);
// sender should be TQClass (which derives from TQObject)
if (!sender->IsA()->InheritsFrom(TQObject::Class()))
return kFALSE;
TQClass *qcl = (TQClass*)sender; // cast TClass to TQClass
return Disconnect(qcl, signal, receiver, slot);
}
//______________________________________________________________________________
Bool_t TQObject::Disconnect(const char *signal,
void *receiver,
const char *slot)
{
// Disconnects signal of this object from slot of receiver.
// Equivalent to Disconnect(this, signal, receiver, slot)
return Disconnect(this, signal, receiver, slot);
}
//______________________________________________________________________________
void TQObject::Streamer(TBuffer &R__b)
{
// Stream an object of class TQObject.
if (R__b.IsReading()) {
// nothing to read
} else {
// nothing to write
}
}
//______________________________________________________________________________
void TQObject::LoadRQ_OBJECT()
{
// Load RQ_OBJECT.h which contains the #define RQ_OBJECT needed to
// let interpreted classes connect to signals of compiled classes.
#if !defined(R__ACC) && !defined(__DECCXX_VER)
G__load_text(RQ_OBJECT_STRING);
#else
// Work around for aCC Error 131: "base/src/TQObject.cxx", line 1467 # The
// string literal created with the '#' operator is too long.
// Idem for cxx on Alpha/TRUE64
char rqh[128];
# ifdef ROOTINCDIR
sprintf(rqh, "%s/RQ_OBJECT.h", ROOTINCDIR);
# else
sprintf(rqh, "%s/include/RQ_OBJECT.h", gSystem->Getenv("ROOTSYS"));
# endif
if (!gSystem->AccessPathName(rqh, kReadPermission))
G__loadfile(rqh);
else
Warning("TQObject::LoadRQ_OBJECT", "%s not found", rqh);
#endif
}
// Global function which simplifies making connection in interpreted
// ROOT session
//
// ConnectCINT - connects to interpreter(CINT) command
//______________________________________________________________________________
Bool_t ConnectCINT(TQObject *sender, const char *signal, const char *slot)
{
TString str = "ProcessLine(=";
str += '"';
str += slot;
str += '"';
str += ")";
return TQObject::Connect(sender, signal, "TInterpreter",
gInterpreter, str.Data());
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.