You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
715 lines
22 KiB
715 lines
22 KiB
/***************************************************************************
|
|
interfaces.h - description
|
|
-------------------
|
|
begin : Fre Feb 28 2003
|
|
copyright : (C) 2003 by Martin Witte
|
|
email : witte@kawo1.rwth-aachen.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifndef KRADIO_INTERFACES_H
|
|
#define KRADIO_INTERFACES_H
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <tqptrlist.h>
|
|
#include <tqmap.h>
|
|
#include <kdebug.h>
|
|
#include <typeinfo>
|
|
|
|
/*
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
Interfaces - Our Concept
|
|
|
|
Without connection management an interface can be defined easily as empty
|
|
abstract C++-Class. But that's not what we want.
|
|
|
|
Our interfaces also provide connection management. Thus each interface has
|
|
exactly one matching counterpart, the complementary interface (cmplIF).
|
|
Therefore connecting two objects that have matching interfaces can be
|
|
automated.
|
|
|
|
Our interfaces have to be able to support the following "functions":
|
|
|
|
- send and receive messages (e.g. notifications, commands, ...) to
|
|
all connected interfaces. These functions do not need a return value,
|
|
but in some cases the sender might want to know if anyone has received
|
|
his message. Thus a boolean return value should indicate if the message
|
|
was handled or ignored.
|
|
|
|
- query for information on connected interfaces / answer queries. These
|
|
functions usually have a return value. A query is only executed on the
|
|
"current" or - if not selected - the first or only connection.
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
Why are we not using TQt signal/slots?
|
|
|
|
First the idea of using tqt for connecting interfaces is very nice, as the
|
|
signal/slot model is well known and hopefully properly implemented.
|
|
|
|
But there are some problems:
|
|
|
|
- Signals/slots do not support return values, except "call by reference".
|
|
To provide queries or a delivery feedback for messages, wrapper functions
|
|
would have been necessary.
|
|
|
|
- TQt does not support multiple inheritance of TQObjects. Thus even signals
|
|
have to be declared abstract by the interface though the (later)
|
|
implementation is already known.
|
|
|
|
Those functions have to be declared as signals in the interface
|
|
implementation (derived from TQObject) though the implementation does not
|
|
want to worry about these signals.
|
|
|
|
- TQt does connect functions (signals/slots) and not interfaces. These
|
|
functions have to be connected separately. By that it is possible to
|
|
forget to connect signals/slots of that interfaces.
|
|
|
|
- Aggregation of multiple interface implementations (each one is an TQObject)
|
|
is not possible because tqt does not allow multiple inheritance of TQObjects
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
What about our own solution?
|
|
|
|
Well, it eliminates at least the tqt-problems explained above. But first we
|
|
need a common mechanism to manage interface connections. This functionality
|
|
can be provided by a common base class "InterfaceBase". It stores all
|
|
connected interfaces in a list of InterfaceBase pointers, e.g. TQPtrList.
|
|
|
|
With this approach we would have some problems:
|
|
|
|
- When calling a function of a connected interface a slow dynamic_cast
|
|
is necessary to upcast the stored InterfaceBase pointer to the
|
|
apropriate type.
|
|
|
|
- Multiple inheritance of InterfaceBase must not be virtual. Otherwise
|
|
interface connection management is mixed between interfaces.
|
|
(well, virtual inheritance is usually no real issue, but worth a hint;-)
|
|
|
|
To avoid these problems, InterfaceBase is a template with two parameters,
|
|
thisIF (IF = interface) and cmplIF (complementary IF). With that
|
|
information the base class for an interface is capable to handle
|
|
connections with the correct type information. Additionally some pseudo
|
|
types are declared (thisInterface, cmplInterface, IFList, IFIterator) to
|
|
make easy-to-use macros for messages and queries possible.
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
How do I use it ? - Declarations
|
|
|
|
First you have to declare the two matching interface-classes as unkown
|
|
classes, because both their names are used in the class declarations.
|
|
Afterwards you can declare both classes as class derived from
|
|
InterfaceBase.
|
|
|
|
class Interface;
|
|
class ComplementaryInterface;
|
|
|
|
class Interface : public InterfaceBase<Interface, ComplementaryInterface>
|
|
{
|
|
...
|
|
};
|
|
|
|
class ComplementaryInterface : public InterfaceBase<ComplementaryInterface, Interface>
|
|
{
|
|
...
|
|
};
|
|
|
|
With macro abbreviation:
|
|
|
|
INTERFACE(Interface, ComplementaryInterface)
|
|
{
|
|
};
|
|
|
|
INTERFACE(ComplementaryInterface, Interface)
|
|
{
|
|
};
|
|
|
|
|
|
In order to receive/send Messages or query/answer queries we have to declare
|
|
special methods:
|
|
|
|
- sending Messages
|
|
|
|
Declare a virtual constant method with return value "int" and the desired
|
|
parameters. The return value will indicate how many receivers have handled
|
|
the message:
|
|
|
|
virtual bool SendingMessages(int any_or_non_param) const;
|
|
|
|
Abbreviation by macros:
|
|
|
|
IF_SENDER( SendingMessages(int any_or_non_param) )
|
|
|
|
|
|
- receiving Messages
|
|
|
|
Declare an abstract Method with return value "bool", and the desired
|
|
paramters. The return value indicates wether the message was handled or not:
|
|
|
|
virtual bool ReceivingMessages(int any_or_non_param) = 0;
|
|
|
|
Abbreviation by macros:
|
|
|
|
IF_RECEIVER( ReceivingMessages(int any_or_non_param) )
|
|
|
|
|
|
The method has to be implemented by a derived class. The current item of the
|
|
receivers conntions list is set to the sender.
|
|
|
|
|
|
- querying queries
|
|
|
|
Declare a virtual constant method with the desired return value and
|
|
parameters:
|
|
|
|
virtual int QueryingQueries(int another_param) const;
|
|
|
|
Abbreviation by macros:
|
|
|
|
IF_QUERY( int QueryingQueries(int another_param) )
|
|
|
|
|
|
- answering queries
|
|
|
|
Declare an abstract Method with return value void, and the desired
|
|
paramters:
|
|
|
|
virtual void AnsweringQueries(int another_param) = 0;
|
|
|
|
Abbreviation by macros:
|
|
|
|
IF_ANSWER( AnsweringQueries(int another_param) )
|
|
|
|
The method has to be implemented by a derived class. The current item of the
|
|
receivers conntions list is set to the sender.
|
|
|
|
|
|
At last a note on maxConnections. This member is set on initialization by
|
|
the constructor and thus can be set in a derived class in it's own
|
|
constructor. Negative values are interpreted as "unlimited".
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
How do I use it ? - Implementations
|
|
|
|
Because we do not have a MOC as TQt does, we have to implement our sending
|
|
or querying methods by hand. But this minor disadvantage should be
|
|
considered as less important than the fact, that this implementation is
|
|
done where it belongs to. Especially because there are easy to use macros
|
|
to do this:
|
|
|
|
int ComplementaryInterface::SendingMessages(int any_or_non_param) const
|
|
{
|
|
IF_SEND_MESSAGE( ReceivingMessages(any_or_non_param) )
|
|
// macro includes "return #receivers"
|
|
}
|
|
|
|
int ComplementaryInterface::QueryingQueries(int another_param) const
|
|
{
|
|
IF_SEND_QUERY( AnsweringQuery(another_param), (int)"default return value" )
|
|
}
|
|
|
|
|
|
Even shorter:
|
|
|
|
IF_IMPL_SENDER( ComplementaryInterface::QueryingQueries(int param),
|
|
AnsweringQueries(param)
|
|
)
|
|
|
|
IF_IMPL_QUERY( int ComplementaryInterface::SendingMessages(int param),
|
|
ReceivingMessages(param),
|
|
(int)"default return value"
|
|
)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
How do I use it ? - Disconnect/Connect notifications
|
|
|
|
|
|
Usually the virtual methods notifyDisconnect(ed) or notifyConnect(ed)
|
|
will be called within connect/disconnect methods.
|
|
|
|
As constructors and destructors are not able to call virtual methods
|
|
of derived classes, there are two possible problems:
|
|
|
|
* Constructors: Calling a connect method in a constructor will not result
|
|
in a connect notification of any derived class. Thus do not use connect
|
|
calls in contructors if any derived class hast to receive all
|
|
connect/disconnect notifications.
|
|
|
|
* Destructors: If connections are still present if the interface destructor
|
|
is called, it will only call its own empty noticedisconnect method. That
|
|
shouldn't be a big problem as the derived class is already gone and
|
|
doesn't have any interest in this notification any more. But it might be
|
|
possible that the connected object wants to call a function of the just
|
|
destroyed derived class. That is not possible. Dynamic casts to the
|
|
derived class will return NULL. Do not try to call methods of this class
|
|
by use of cached pointers.
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
Extending and Aggregating Interfaces
|
|
|
|
Our interfaces must be extended by aggregation. The reason is that
|
|
otherwise we would have the same problems as with a common base class
|
|
for connection management. Each interface extensions is an normal
|
|
interface on its own.
|
|
|
|
Example:
|
|
|
|
class I_AM_FM_Radio : public IRadioBase,
|
|
public IRadioFrequencyExtension,
|
|
public IRadioSeekExtension
|
|
{
|
|
...
|
|
};
|
|
|
|
To guarantee, that connection management continues to work, we have to overwrite
|
|
the connect and disconnect methods:
|
|
|
|
virtual bool I_AM_FM_Radio::connect (Interface *i) {
|
|
IRadioBase::connect(i);
|
|
IFrequencyExtension::connect(i);
|
|
ISeekExtension::connect(i);
|
|
}
|
|
|
|
virtual bool I_AM_FM_Radio::disconnect (Interface *i) {
|
|
IRadioBase::disconnect(i);
|
|
IFrequencyExtension::disconnect(i);
|
|
ISeekExtension::disconnect(i);
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// a polymorphic and *virtual* base class so that we can make use of
|
|
// dynamic_casts in connect/disconnect and to be able to merge
|
|
// connect/disconnect methods to one single function in case of multiple
|
|
// inheritance
|
|
|
|
class Interface
|
|
{
|
|
public:
|
|
Interface () {}
|
|
virtual ~Interface() {}
|
|
|
|
virtual bool connectI (Interface *) { return false; }
|
|
virtual bool disconnectI(Interface *) { return false; }
|
|
|
|
// "Interface &"-Versions for convienience, not virtual, only "Interface*"
|
|
// versions have to / may be overwritten in case of multiple inheritance
|
|
bool connectI (Interface &i) { return connectI (&i); }
|
|
bool disconnectI(Interface &i) { return disconnectI (&i); }
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class thisIF, class cmplIF>
|
|
class InterfaceBase : virtual public Interface
|
|
{
|
|
private:
|
|
typedef InterfaceBase<thisIF, cmplIF> thisClass;
|
|
typedef InterfaceBase<cmplIF, thisIF> cmplClass;
|
|
|
|
// friend class cmplClass; // necessary for connects (to keep number of different connect functions low)
|
|
|
|
public:
|
|
|
|
typedef thisIF thisInterface;
|
|
typedef cmplIF cmplInterface;
|
|
|
|
typedef TQPtrList<cmplIF> IFList;
|
|
typedef TQPtrListIterator<cmplIF> IFIterator;
|
|
|
|
typedef thisClass BaseClass;
|
|
|
|
public :
|
|
InterfaceBase (int maxIConnections = -1);
|
|
virtual ~InterfaceBase ();
|
|
|
|
// duplicate connects will add no more entries to connection list
|
|
virtual bool connectI(Interface *i);
|
|
virtual bool disconnectI(Interface *i);
|
|
|
|
protected:
|
|
virtual void disconnectAllI();
|
|
|
|
|
|
public:
|
|
|
|
// It might be compfortable to derived Interfaces to get an argument
|
|
// of the Interface class, but that part of the object might
|
|
// already be destroyed. Thus it is necessary to evaluate the additional
|
|
// pointer_valid argument. A null pointer is not transmitted, as the
|
|
// pointer value might be needed to clean up some references in derived
|
|
// classes
|
|
virtual void noticeConnectI (cmplInterface *, bool /*pointer_valid*/) {}
|
|
virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/) {}
|
|
virtual void noticeDisconnectI (cmplInterface *, bool /*pointer_valid*/);
|
|
virtual void noticeDisconnectedI(cmplInterface *, bool /*pointer_valid*/) {}
|
|
|
|
virtual bool isIConnectionFree() const;
|
|
virtual unsigned connectedI() const { return iConnections.count(); }
|
|
|
|
thisIF *initThisInterfacePointer();
|
|
thisIF *getThisInterfacePointer() const { return me; }
|
|
bool isThisInterfacePointerValid() const { return me_valid; }
|
|
bool hasConnectionTo(cmplInterface *other) const { return iConnections.containsRef(other); }
|
|
void appendConnectionTo(cmplInterface *other) { iConnections.append(other); }
|
|
void removeConnectionTo(cmplInterface *other) { iConnections.removeRef(other); }
|
|
|
|
protected :
|
|
|
|
IFList iConnections;
|
|
int maxIConnections;
|
|
|
|
// functions for individually selectable callbacks
|
|
protected:
|
|
bool addListener (const cmplInterface *i, TQPtrList<cmplInterface> &list);
|
|
void removeListener(const cmplInterface *i, TQPtrList<cmplInterface> &list);
|
|
void removeListener(const cmplInterface *i);
|
|
|
|
TQMap<const cmplInterface *, TQPtrList<TQPtrList<cmplInterface> > > m_FineListeners;
|
|
|
|
private:
|
|
thisInterface *me;
|
|
bool me_valid;
|
|
};
|
|
|
|
|
|
// macros for interface declaration
|
|
|
|
#define INTERFACE(IF, cmplIF) \
|
|
class IF; \
|
|
class cmplIF; \
|
|
class KDE_EXPORT IF : public InterfaceBase<IF, cmplIF> \
|
|
|
|
#define IF_CON_DESTRUCTOR(IF, n) \
|
|
IF() : BaseClass((n)) {} \
|
|
virtual ~IF() { }
|
|
|
|
// macros to make sending messages or queries easier
|
|
|
|
|
|
// debug util
|
|
#ifdef DEBUG
|
|
#include <iostream>
|
|
using namespace std;
|
|
#define IF_QUERY_DEBUG \
|
|
if (iConnections.count() > 1) { \
|
|
kdDebug() << "class " << typeid(this).name() << ": using IF_QUERY with #connections > 1\n"; \
|
|
}
|
|
#else
|
|
#define IF_QUERY_DEBUG
|
|
#endif
|
|
|
|
|
|
|
|
// messages
|
|
|
|
#define SENDERS protected
|
|
#define RECEIVERS public
|
|
|
|
#define IF_SENDER(decl) \
|
|
virtual int decl const;
|
|
|
|
#define IF_SEND_MESSAGE(call) \
|
|
int ____n = 0; \
|
|
for (IFIterator i(iConnections); i.current(); ++i) { \
|
|
if (i.current()->call ) ++____n; \
|
|
} \
|
|
return ____n;
|
|
|
|
#define IF_IMPL_SENDER(decl, call) \
|
|
int decl const \
|
|
{ \
|
|
IF_SEND_MESSAGE(call) \
|
|
}
|
|
|
|
#define IF_RECEIVER(decl) \
|
|
virtual bool decl = 0;
|
|
|
|
#define IF_RECEIVER_EMPTY(decl) \
|
|
virtual bool decl { return false; }
|
|
|
|
// queries
|
|
|
|
#define ANSWERS public
|
|
#define QUERIES protected
|
|
|
|
#define IF_QUERY(decl) \
|
|
virtual decl const;
|
|
|
|
#define IF_SEND_QUERY(call, default) \
|
|
cmplInterface *o = IFIterator(iConnections).current(); \
|
|
if (o) { \
|
|
IF_QUERY_DEBUG \
|
|
return o->call; \
|
|
} else { \
|
|
return default; \
|
|
} \
|
|
|
|
#define IF_IMPL_QUERY(decl, call, default) \
|
|
decl const { \
|
|
IF_SEND_QUERY(call, default) \
|
|
}
|
|
|
|
#define IF_ANSWER(decl) \
|
|
virtual decl = 0;
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MACROS for individually selectable callbacks
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#define IF_SENDER_FINE(name, param) \
|
|
protected: \
|
|
int name param const; \
|
|
public: \
|
|
bool register4_##name (cmplInterface *); \
|
|
void unregister4_##name(cmplInterface *); \
|
|
private: \
|
|
TQPtrList<cmplInterface> m_Listeners_##name;\
|
|
|
|
|
|
#define IF_SEND_MESSAGE_FINE(name, params, call) \
|
|
int ____n = 0; \
|
|
for (TQPtrListIterator<cmplInterface> ____it(m_Listeners_##name); ____it.current(); ++____it) { \
|
|
if (____it.current()->call ) ++____n; \
|
|
} \
|
|
return ____n;
|
|
|
|
#define IF_IMPL_SENDER_FINE(class, name, param, call) \
|
|
int class::name param const { \
|
|
IF_SEND_MESSAGE_FINE(name, param, call) \
|
|
} \
|
|
\
|
|
bool class::register4_##name(cmplInterface *i) { \
|
|
return addListener(i, m_Listeners_##name); \
|
|
} \
|
|
void class::unregister4_##name(cmplInterface *i) { \
|
|
m_Listeners_##name.remove(i); \
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
InterfaceBase<thisIF, cmplIF>::InterfaceBase(int _maxIConnections)
|
|
: maxIConnections(_maxIConnections),
|
|
me(NULL),
|
|
me_valid(false)
|
|
{
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
InterfaceBase<thisIF, cmplIF>::~InterfaceBase()
|
|
{
|
|
me_valid = false;
|
|
// In this state the derived interfaces may already be destroyed
|
|
// so that dereferencing cached upcasted me-pointers in noticeDisconnect(ed)
|
|
// will fail.
|
|
// Thus we must ensure that disconnectAll() is called in the (upper) thisIF
|
|
// destructor, not here (see macro IF_CON_DESTRUCTOR).
|
|
// If this has not taken place (i.e. the programmer forgot to do so)
|
|
// we can only warn, clear our list now and hope that nothing
|
|
// more bad will happen
|
|
|
|
if (iConnections.count() > 0) {
|
|
thisClass::disconnectAllI();
|
|
}
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
bool InterfaceBase<thisIF, cmplIF>::isIConnectionFree () const
|
|
{
|
|
int m = maxIConnections;
|
|
return (m < 0) || (iConnections.count() < (unsigned) m);
|
|
}
|
|
|
|
template <class thisIF, class cmplIF>
|
|
thisIF *InterfaceBase<thisIF, cmplIF>::initThisInterfacePointer()
|
|
{
|
|
if (!me) me = dynamic_cast<thisIF*>(this);
|
|
me_valid = me != NULL;
|
|
return me;
|
|
}
|
|
|
|
template <class thisIF, class cmplIF>
|
|
bool InterfaceBase<thisIF, cmplIF>::connectI (Interface *__i)
|
|
{
|
|
// cache upcasted pointer, especially important for disconnects
|
|
// where already destructed derived parts cannot be reached with dynamic casts
|
|
initThisInterfacePointer();
|
|
|
|
// same with the other interface
|
|
cmplClass *_i = dynamic_cast<cmplClass*>(__i);
|
|
if (!_i) {
|
|
return false;
|
|
}
|
|
|
|
cmplIF *i = _i->initThisInterfacePointer();
|
|
|
|
if (i && me) {
|
|
bool i_connected = iConnections.containsRef(i);
|
|
bool me_connected = i->hasConnectionTo(me);
|
|
|
|
if (i_connected || me_connected) {
|
|
return true;
|
|
} else if (isIConnectionFree() && i->isIConnectionFree()) {
|
|
|
|
noticeConnectI(i, i != NULL);
|
|
_i->noticeConnectI(me, me != NULL);
|
|
|
|
if (!i_connected)
|
|
appendConnectionTo(i);
|
|
if (!me_connected)
|
|
_i->appendConnectionTo(me);
|
|
|
|
noticeConnectedI(i, i != NULL);
|
|
_i->noticeConnectedI(me, me != NULL);
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
bool InterfaceBase<thisIF, cmplIF>::disconnectI (Interface *__i)
|
|
{
|
|
cmplClass *_i = dynamic_cast<cmplClass*>(__i);
|
|
|
|
// use cache to find pointer in connections list
|
|
cmplIF *i = _i ? _i->getThisInterfacePointer() : NULL;
|
|
|
|
// The cached me pointer might already point to an destroyed
|
|
// object. We must use it only for identifying the entry in
|
|
// connections list
|
|
|
|
if (i && _i) {
|
|
if (me_valid)
|
|
noticeDisconnectI(i, _i->isThisInterfacePointerValid());
|
|
}
|
|
|
|
if (me && _i) {
|
|
if (_i->isThisInterfacePointerValid())
|
|
_i->noticeDisconnectI(me, me_valid);
|
|
}
|
|
|
|
if (i && hasConnectionTo(i)) {
|
|
removeListener(i);
|
|
removeConnectionTo(i);
|
|
}
|
|
|
|
if (me && i && i->hasConnectionTo(me))
|
|
i->removeConnectionTo(me);
|
|
|
|
if (me_valid && i && _i)
|
|
noticeDisconnectedI(i, _i->isThisInterfacePointerValid());
|
|
if (_i && _i->isThisInterfacePointerValid() && me)
|
|
_i->noticeDisconnectedI(me, me_valid);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
void InterfaceBase<thisIF, cmplIF>::noticeDisconnectI(cmplInterface *i, bool /*pointer_valid*/)
|
|
{
|
|
removeListener(i);
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
void InterfaceBase<thisIF, cmplIF>::disconnectAllI()
|
|
{
|
|
IFList tmp = iConnections;
|
|
for (IFIterator it(tmp); it.current(); ++it) {
|
|
/* Do not call virtual methods if I'm in the contstructor!
|
|
Actually this should be ensured by the compiler generated
|
|
code and virtual method tables, but unfortunately some compilers
|
|
seem to ignore this in some situations.
|
|
*/
|
|
if (me_valid)
|
|
disconnectI(it.current());
|
|
else
|
|
thisClass::disconnectI(it.current());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
bool InterfaceBase<thisIF, cmplIF>::addListener(const cmplInterface *i, TQPtrList<cmplInterface> &list)
|
|
{
|
|
if (iConnections.containsRef(i) && !list.contains(i)) {
|
|
list.append(i);
|
|
m_FineListeners[i].append(&list);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
void InterfaceBase<thisIF, cmplIF>::removeListener(const cmplInterface *i, TQPtrList<cmplInterface> &list)
|
|
{
|
|
list.remove(i);
|
|
if (m_FineListeners.contains(i))
|
|
m_FineListeners[i].remove(&list);
|
|
}
|
|
|
|
|
|
template <class thisIF, class cmplIF>
|
|
void InterfaceBase<thisIF, cmplIF>::removeListener(const cmplInterface *i)
|
|
{
|
|
if (m_FineListeners.contains(i)) {
|
|
TQPtrList<TQPtrList<cmplInterface> > &list = m_FineListeners[i];
|
|
TQPtrListIterator<TQPtrList<cmplInterface> > it(list);
|
|
for (; it.current(); ++it) {
|
|
(*it)->remove(i);
|
|
}
|
|
}
|
|
m_FineListeners.remove(i);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|