~ubuntu-branches/ubuntu/karmic/kradio/karmic

« back to all changes in this revision

Viewing changes to kradio3/src/include/interfaces.h

  • Committer: Bazaar Package Importer
  • Author(s): Marc 'HE' Brockschmidt
  • Date: 2008-03-16 19:00:02 UTC
  • mfrom: (3.1.2 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080316190002-sdjqu8cahhx7c6tk
Tags: 0.1.1.1~20061112-3.1
* Non-maintainer upload.
* Fix gcc-4.3 FTBFS, patch by Kibi (Closes: #455390)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          interfaces.h  -  description
 
3
                             -------------------
 
4
    begin                : Fre Feb 28 2003
 
5
    copyright            : (C) 2003 by Martin Witte
 
6
    email                : witte@kawo1.rwth-aachen.de
 
7
 ***************************************************************************/
 
8
 
 
9
/***************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
 
 
18
#ifndef KRADIO_INTERFACES_H
 
19
#define KRADIO_INTERFACES_H
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <qptrlist.h>
 
26
#include <qmap.h>
 
27
#include <kdebug.h>
 
28
#include <typeinfo>
 
29
 
 
30
/*
 
31
/////////////////////////////////////////////////////////////////////////////
 
32
 
 
33
   Interfaces - Our Concept
 
34
 
 
35
   Without connection management an interface can be defined easily as empty
 
36
   abstract C++-Class. But that's not what we want.
 
37
 
 
38
   Our interfaces also provide connection management. Thus each interface has
 
39
   exactly one matching counterpart, the complementary interface (cmplIF).
 
40
   Therefore connecting two objects that have matching interfaces can be
 
41
   automated.
 
42
 
 
43
   Our interfaces have to be able to support the following "functions":
 
44
 
 
45
   - send and receive messages (e.g. notifications, commands, ...) to
 
46
     all connected interfaces. These functions do not need a return value,
 
47
     but in some cases the sender might want to know if anyone has received
 
48
     his message. Thus a boolean return value should indicate if the message
 
49
     was handled or ignored.
 
50
 
 
51
   - query for information on connected interfaces / answer queries. These
 
52
     functions usually have a return value. A query is only executed on the
 
53
     "current" or - if not selected - the first or only connection.
 
54
 
 
55
/////////////////////////////////////////////////////////////////////////////
 
56
 
 
57
   Why are we not using QT signal/slots?
 
58
 
 
59
   First the idea of using qt for connecting interfaces is very nice, as the
 
60
   signal/slot model is well known and hopefully properly implemented.
 
61
 
 
62
   But there are some problems:
 
63
 
 
64
   - Signals/slots do not support return values, except "call by reference".
 
65
     To provide queries or a delivery feedback for messages, wrapper functions
 
66
     would have been necessary.
 
67
 
 
68
   - Qt does not support multiple inheritance of QObjects. Thus even signals
 
69
     have to be declared abstract by the interface though the (later)
 
70
     implementation is already known.
 
71
 
 
72
     Those functions have to be declared as signals in the interface
 
73
     implementation (derived from QObject) though the implementation does not
 
74
     want to worry about these signals.
 
75
 
 
76
   - Qt does connect functions (signals/slots) and not interfaces. These
 
77
     functions have to be connected separately. By that it is possible to
 
78
     forget to connect signals/slots of that interfaces.
 
79
 
 
80
   - Aggregation of multiple interface implementations (each one is an QObject)
 
81
     is not possible because qt does not allow multiple inheritance of QObjects
 
82
 
 
83
/////////////////////////////////////////////////////////////////////////////
 
84
 
 
85
   What about our own solution?
 
86
 
 
87
   Well, it eliminates at least the qt-problems explained above. But first we
 
88
   need a common mechanism to manage interface connections. This functionality
 
89
   can be provided by a common base class "InterfaceBase". It stores all
 
90
   connected interfaces in a list of InterfaceBase pointers, e.g. QPtrList.
 
91
 
 
92
   With this approach we would have some problems:
 
93
 
 
94
   - When calling a function of a connected interface a slow dynamic_cast
 
95
     is necessary to upcast the stored InterfaceBase pointer to the
 
96
     apropriate type.
 
97
 
 
98
   - Multiple inheritance of InterfaceBase must not be virtual. Otherwise
 
99
     interface connection management is mixed between interfaces.
 
100
     (well, virtual inheritance is usually no real issue, but worth a hint;-)
 
101
 
 
102
   To avoid these problems, InterfaceBase is a template with two parameters,
 
103
   thisIF (IF = interface) and cmplIF (complementary IF). With that
 
104
   information the base class for an interface is capable to handle
 
105
   connections with the correct type information. Additionally some pseudo
 
106
   types are declared (thisInterface, cmplInterface, IFList, IFIterator) to
 
107
   make easy-to-use macros for messages and queries possible.
 
108
 
 
109
/////////////////////////////////////////////////////////////////////////////
 
110
 
 
111
   How do I use it ?   - Declarations
 
112
 
 
113
   First you have to declare the two matching interface-classes as unkown
 
114
   classes, because both their names are used in the class declarations.
 
115
   Afterwards you can declare both classes as class derived from
 
116
   InterfaceBase.
 
117
 
 
118
       class Interface;
 
119
       class ComplementaryInterface;
 
120
 
 
121
       class Interface : public InterfaceBase<Interface, ComplementaryInterface>
 
122
       {
 
123
           ...
 
124
       };
 
125
 
 
126
       class ComplementaryInterface : public InterfaceBase<ComplementaryInterface, Interface>
 
127
       {
 
128
           ...
 
129
       };
 
130
 
 
131
   With macro abbreviation:
 
132
 
 
133
       INTERFACE(Interface, ComplementaryInterface)
 
134
       {
 
135
       };
 
136
 
 
137
       INTERFACE(ComplementaryInterface, Interface)
 
138
       {
 
139
       };
 
140
 
 
141
 
 
142
   In order to receive/send Messages or query/answer queries we have to declare
 
143
   special methods:
 
144
 
 
145
   - sending Messages
 
146
 
 
147
     Declare a virtual constant method with return value "int" and the desired
 
148
     parameters. The return value will indicate how many receivers have handled
 
149
     the message:
 
150
 
 
151
         virtual bool  SendingMessages(int any_or_non_param) const;
 
152
 
 
153
     Abbreviation by macros:
 
154
 
 
155
          IF_SENDER(    SendingMessages(int any_or_non_param)   )
 
156
 
 
157
 
 
158
   - receiving Messages
 
159
 
 
160
     Declare an abstract Method with return value "bool", and the desired
 
161
     paramters. The return value indicates wether the message was handled or not:
 
162
 
 
163
         virtual bool  ReceivingMessages(int any_or_non_param) = 0;
 
164
 
 
165
     Abbreviation by macros:
 
166
 
 
167
          IF_RECEIVER(  ReceivingMessages(int any_or_non_param)   )
 
168
 
 
169
 
 
170
     The method has to be implemented by a derived class. The current item of the
 
171
     receivers conntions list is set to the sender.
 
172
 
 
173
 
 
174
   - querying queries
 
175
 
 
176
     Declare a virtual constant method with the desired return value and
 
177
     parameters:
 
178
 
 
179
          virtual int   QueryingQueries(int another_param) const;
 
180
 
 
181
     Abbreviation by macros:
 
182
 
 
183
         IF_QUERY(     int QueryingQueries(int another_param)        )
 
184
 
 
185
 
 
186
   - answering queries
 
187
 
 
188
     Declare an abstract Method with return value void, and the desired
 
189
     paramters:
 
190
 
 
191
         virtual void  AnsweringQueries(int another_param) = 0;
 
192
 
 
193
     Abbreviation by macros:
 
194
 
 
195
          IF_ANSWER(    AnsweringQueries(int another_param)   )
 
196
 
 
197
     The method has to be implemented by a derived class. The current item of the
 
198
     receivers conntions list is set to the sender.
 
199
 
 
200
 
 
201
   At last a note on maxConnections. This member is set on initialization by
 
202
   the constructor and thus can be set in a derived class in it's own
 
203
   constructor. Negative values are interpreted as "unlimited".
 
204
 
 
205
 
 
206
/////////////////////////////////////////////////////////////////////////////
 
207
 
 
208
   How do I use it ?   - Implementations
 
209
 
 
210
   Because we do not have a MOC as Qt does, we have to implement our sending
 
211
   or querying methods by hand. But this minor disadvantage should be
 
212
   considered as less important than the fact, that this implementation is
 
213
   done where it belongs to. Especially because there are easy to use macros
 
214
   to do this:
 
215
 
 
216
   int   ComplementaryInterface::SendingMessages(int any_or_non_param) const
 
217
   {
 
218
       IF_SEND_MESSAGE( ReceivingMessages(any_or_non_param)  )
 
219
       // macro includes "return #receivers"
 
220
   }
 
221
 
 
222
   int   ComplementaryInterface::QueryingQueries(int another_param) const
 
223
   {
 
224
       IF_SEND_QUERY( AnsweringQuery(another_param), (int)"default return value" )
 
225
   }
 
226
 
 
227
 
 
228
   Even shorter:
 
229
 
 
230
   IF_IMPL_SENDER(  ComplementaryInterface::QueryingQueries(int param),
 
231
                    AnsweringQueries(param)
 
232
                 )
 
233
 
 
234
   IF_IMPL_QUERY(  int ComplementaryInterface::SendingMessages(int param),
 
235
                   ReceivingMessages(param),
 
236
                   (int)"default return value"
 
237
                )
 
238
 
 
239
/////////////////////////////////////////////////////////////////////////////
 
240
 
 
241
   How do I use it ?   - Disconnect/Connect notifications
 
242
 
 
243
 
 
244
   Usually the virtual methods notifyDisconnect(ed) or notifyConnect(ed)
 
245
   will be called within connect/disconnect methods.
 
246
 
 
247
   As constructors and destructors are not able to call virtual methods
 
248
   of derived classes, there are two possible problems:
 
249
 
 
250
   * Constructors: Calling a connect method in a constructor will not result
 
251
     in a connect notification of any derived class. Thus do not use connect
 
252
     calls in contructors if any derived class hast to receive all
 
253
     connect/disconnect notifications.
 
254
 
 
255
   * Destructors: If connections are still present if the interface destructor
 
256
     is called, it will only call its own empty noticedisconnect method. That
 
257
     shouldn't be a big problem as the derived class is already gone and
 
258
     doesn't have any interest in this notification any more. But it might be
 
259
     possible that the connected object wants to call a function of the just
 
260
     destroyed derived class. That is not possible. Dynamic casts to the
 
261
     derived class will return NULL. Do not try to call methods of this class
 
262
     by use of cached pointers.
 
263
 
 
264
 
 
265
 
 
266
/////////////////////////////////////////////////////////////////////////////
 
267
 
 
268
   Extending and Aggregating Interfaces
 
269
 
 
270
   Our interfaces must be extended by aggregation. The reason is that
 
271
   otherwise we would have the same problems as with a common base class
 
272
   for connection management. Each interface extensions is an normal
 
273
   interface on its own.
 
274
 
 
275
   Example:
 
276
 
 
277
   class I_AM_FM_Radio : public IRadioBase,
 
278
                         public IRadioFrequencyExtension,
 
279
                         public IRadioSeekExtension
 
280
   {
 
281
       ...
 
282
   };
 
283
 
 
284
   To guarantee, that connection management continues to work, we have to overwrite
 
285
   the connect and disconnect methods:
 
286
 
 
287
     virtual bool I_AM_FM_Radio::connect (Interface *i) {
 
288
         IRadioBase::connect(i);
 
289
         IFrequencyExtension::connect(i);
 
290
         ISeekExtension::connect(i);
 
291
     }
 
292
 
 
293
     virtual bool I_AM_FM_Radio::disconnect (Interface *i) {
 
294
         IRadioBase::disconnect(i);
 
295
         IFrequencyExtension::disconnect(i);
 
296
         ISeekExtension::disconnect(i);
 
297
     }
 
298
 
 
299
*/
 
300
 
 
301
 
 
302
/////////////////////////////////////////////////////////////////////////////
 
303
 
 
304
// a polymorphic and *virtual* base class so that we can make use of
 
305
// dynamic_casts in connect/disconnect and to be able to merge
 
306
// connect/disconnect methods to one single function in case of multiple
 
307
// inheritance
 
308
 
 
309
class Interface
 
310
{
 
311
public:
 
312
    Interface () {}
 
313
    virtual ~Interface() {}
 
314
 
 
315
    virtual bool     connectI   (Interface *) { return false; }
 
316
    virtual bool     disconnectI(Interface *) { return false; }
 
317
 
 
318
    // "Interface &"-Versions for convienience, not virtual, only "Interface*"
 
319
    // versions have to / may  be overwritten in case of multiple inheritance
 
320
    bool     connectI   (Interface &i) { return connectI    (&i); }
 
321
    bool     disconnectI(Interface &i) { return disconnectI (&i); }
 
322
};
 
323
 
 
324
/////////////////////////////////////////////////////////////////////////////
 
325
 
 
326
template <class thisIF, class cmplIF>
 
327
class InterfaceBase : virtual public Interface
 
328
{
 
329
private:
 
330
    typedef InterfaceBase<thisIF, cmplIF>  thisClass;
 
331
    typedef InterfaceBase<cmplIF, thisIF>  cmplClass;
 
332
 
 
333
//    friend class cmplClass; // necessary for connects (to keep number of different connect functions low)
 
334
 
 
335
public:
 
336
 
 
337
    typedef thisIF                    thisInterface;
 
338
    typedef cmplIF                    cmplInterface;
 
339
 
 
340
    typedef QPtrList<cmplIF>          IFList;
 
341
    typedef QPtrListIterator<cmplIF>  IFIterator;
 
342
 
 
343
    typedef thisClass BaseClass;
 
344
 
 
345
public :
 
346
    InterfaceBase (int maxIConnections = -1);
 
347
    virtual ~InterfaceBase ();
 
348
 
 
349
    // duplicate connects will add no more entries to connection list
 
350
    virtual bool     connectI(Interface *i);
 
351
    virtual bool     disconnectI(Interface *i);
 
352
 
 
353
protected:
 
354
    virtual void     disconnectAllI();
 
355
 
 
356
 
 
357
public:
 
358
 
 
359
    // It might be compfortable to derived Interfaces to get an argument
 
360
    // of the Interface class, but that part of the object might
 
361
    // already be destroyed. Thus it is necessary to evaluate the additional
 
362
    // pointer_valid argument. A null pointer is not transmitted, as the
 
363
    // pointer value might be needed to clean up some references in derived
 
364
    // classes
 
365
    virtual void     noticeConnectI     (cmplInterface *, bool /*pointer_valid*/) {}
 
366
    virtual void     noticeConnectedI   (cmplInterface *, bool /*pointer_valid*/) {}
 
367
    virtual void     noticeDisconnectI  (cmplInterface *, bool /*pointer_valid*/);
 
368
    virtual void     noticeDisconnectedI(cmplInterface *, bool /*pointer_valid*/) {}
 
369
 
 
370
    virtual bool     isIConnectionFree() const;
 
371
    virtual unsigned connectedI()        const { return iConnections.count(); }
 
372
 
 
373
    thisIF *initThisInterfacePointer();
 
374
    thisIF *getThisInterfacePointer()     const { return me; }
 
375
    bool    isThisInterfacePointerValid() const { return me_valid; }
 
376
    bool    hasConnectionTo(cmplInterface *other) const { return iConnections.containsRef(other); }
 
377
    void    appendConnectionTo(cmplInterface *other)    { iConnections.append(other); }
 
378
    void    removeConnectionTo(cmplInterface *other)    { iConnections.removeRef(other); }
 
379
 
 
380
protected :
 
381
 
 
382
    IFList iConnections;
 
383
    int    maxIConnections;
 
384
 
 
385
 // functions for individually selectable callbacks
 
386
protected:
 
387
    bool addListener   (const cmplInterface *i, QPtrList<cmplInterface> &list);
 
388
    void removeListener(const cmplInterface *i, QPtrList<cmplInterface> &list);
 
389
    void removeListener(const cmplInterface *i);
 
390
 
 
391
    QMap<const cmplInterface *, QPtrList<QPtrList<cmplInterface> > >  m_FineListeners;
 
392
 
 
393
private:
 
394
    thisInterface *me;
 
395
    bool           me_valid;
 
396
};
 
397
 
 
398
 
 
399
// macros for interface declaration
 
400
 
 
401
#define INTERFACE(IF, cmplIF) \
 
402
    class IF; \
 
403
    class cmplIF; \
 
404
    class IF : public InterfaceBase<IF, cmplIF> \
 
405
 
 
406
#define IF_CON_DESTRUCTOR(IF, n) \
 
407
    IF() : BaseClass((n)) {} \
 
408
    virtual ~IF() { }
 
409
 
 
410
// macros to make sending messages or queries easier
 
411
 
 
412
 
 
413
// debug util
 
414
#ifdef DEBUG
 
415
    #include <iostream>
 
416
    using namespace std;
 
417
    #define IF_QUERY_DEBUG \
 
418
        if (iConnections.count() > 1) { \
 
419
            kdDebug() << "class " << typeid(this).name() << ": using IF_QUERY with #connections > 1\n"; \
 
420
        }
 
421
#else
 
422
    #define IF_QUERY_DEBUG
 
423
#endif
 
424
 
 
425
 
 
426
 
 
427
// messages
 
428
 
 
429
#define SENDERS   protected
 
430
#define RECEIVERS public
 
431
 
 
432
#define IF_SENDER(decl) \
 
433
        virtual int decl const;
 
434
 
 
435
#define IF_SEND_MESSAGE(call) \
 
436
        int ____n = 0; \
 
437
        for (IFIterator i(iConnections); i.current(); ++i) {   \
 
438
            if (i.current()->call ) ++____n; \
 
439
        }  \
 
440
        return ____n;
 
441
 
 
442
#define IF_IMPL_SENDER(decl, call) \
 
443
        int decl const \
 
444
        { \
 
445
            IF_SEND_MESSAGE(call) \
 
446
        }
 
447
 
 
448
#define IF_RECEIVER(decl) \
 
449
        virtual bool decl = 0;
 
450
 
 
451
#define IF_RECEIVER_EMPTY(decl) \
 
452
        virtual bool decl { return false; }
 
453
 
 
454
// queries
 
455
 
 
456
#define ANSWERS public
 
457
#define QUERIES protected
 
458
 
 
459
#define IF_QUERY(decl) \
 
460
        virtual decl const;
 
461
 
 
462
#define IF_SEND_QUERY(call, default) \
 
463
        cmplInterface *o = IFIterator(iConnections).current(); \
 
464
        if (o) { \
 
465
            IF_QUERY_DEBUG \
 
466
            return o->call; \
 
467
        } else { \
 
468
            return default; \
 
469
        } \
 
470
 
 
471
#define IF_IMPL_QUERY(decl, call, default) \
 
472
        decl const { \
 
473
            IF_SEND_QUERY(call, default) \
 
474
        }
 
475
 
 
476
#define IF_ANSWER(decl) \
 
477
        virtual decl = 0;
 
478
 
 
479
 
 
480
 
 
481
 
 
482
/////////////////////////////////////////////////////////////////////////////
 
483
// MACROS for individually selectable callbacks
 
484
/////////////////////////////////////////////////////////////////////////////
 
485
 
 
486
 
 
487
#define IF_SENDER_FINE(name, param) \
 
488
protected: \
 
489
    int  name param const; \
 
490
public: \
 
491
    bool register4_##name  (cmplInterface *); \
 
492
    void unregister4_##name(cmplInterface *); \
 
493
private: \
 
494
    QPtrList<cmplInterface> m_Listeners_##name;\
 
495
 
 
496
 
 
497
#define IF_SEND_MESSAGE_FINE(name, params, call) \
 
498
        int ____n = 0; \
 
499
        for (QPtrListIterator<cmplInterface> ____it(m_Listeners_##name); ____it.current(); ++____it) {   \
 
500
            if (____it.current()->call ) ++____n; \
 
501
        }  \
 
502
        return ____n;
 
503
 
 
504
#define IF_IMPL_SENDER_FINE(class, name, param, call) \
 
505
    int class::name param const { \
 
506
        IF_SEND_MESSAGE_FINE(name, param, call) \
 
507
    } \
 
508
    \
 
509
    bool class::register4_##name(cmplInterface *i) {   \
 
510
        return addListener(i, m_Listeners_##name); \
 
511
    } \
 
512
    void class::unregister4_##name(cmplInterface *i) {   \
 
513
        m_Listeners_##name.remove(i);             \
 
514
    }
 
515
 
 
516
 
 
517
/////////////////////////////////////////////////////////////////////////////
 
518
 
 
519
 
 
520
template <class thisIF, class cmplIF>
 
521
InterfaceBase<thisIF, cmplIF>::InterfaceBase(int _maxIConnections)
 
522
  : maxIConnections(_maxIConnections),
 
523
    me(NULL),
 
524
    me_valid(false)
 
525
{
 
526
}
 
527
 
 
528
 
 
529
template <class thisIF, class cmplIF>
 
530
InterfaceBase<thisIF, cmplIF>::~InterfaceBase()
 
531
{
 
532
    me_valid = false;
 
533
    // In this state the derived interfaces may already be destroyed
 
534
    // so that dereferencing cached upcasted me-pointers in noticeDisconnect(ed)
 
535
    // will fail.
 
536
    // Thus we must ensure that disconnectAll() is called in the (upper) thisIF
 
537
    // destructor, not here (see macro IF_CON_DESTRUCTOR).
 
538
    // If this has not taken place (i.e. the programmer forgot to do so)
 
539
    // we can only warn, clear our list now and hope that nothing
 
540
    // more bad will happen
 
541
 
 
542
    if (iConnections.count() > 0) {
 
543
        thisClass::disconnectAllI();
 
544
    }
 
545
}
 
546
 
 
547
 
 
548
template <class thisIF, class cmplIF>
 
549
bool InterfaceBase<thisIF, cmplIF>::isIConnectionFree () const
 
550
{
 
551
    int m = maxIConnections;
 
552
    return  (m < 0) || (iConnections.count() < (unsigned) m);
 
553
}
 
554
 
 
555
template <class thisIF, class cmplIF>
 
556
thisIF *InterfaceBase<thisIF, cmplIF>::initThisInterfacePointer()
 
557
{
 
558
    if (!me) me = dynamic_cast<thisIF*>(this);
 
559
    me_valid = me != NULL;
 
560
    return me;
 
561
}
 
562
 
 
563
template <class thisIF, class cmplIF>
 
564
bool InterfaceBase<thisIF, cmplIF>::connectI (Interface *__i)
 
565
{
 
566
    // cache upcasted pointer, especially important for disconnects
 
567
    // where already destructed derived parts cannot be reached with dynamic casts
 
568
    initThisInterfacePointer();
 
569
 
 
570
    // same with the other interface
 
571
    cmplClass *_i = dynamic_cast<cmplClass*>(__i);
 
572
    if (!_i) {
 
573
        return false;
 
574
    }
 
575
 
 
576
    cmplIF    *i = _i->initThisInterfacePointer();
 
577
 
 
578
    if (i && me) {
 
579
        bool i_connected  = iConnections.containsRef(i);
 
580
        bool me_connected = i->hasConnectionTo(me);
 
581
 
 
582
        if (i_connected || me_connected) {
 
583
            return true;
 
584
        } else if (isIConnectionFree() && i->isIConnectionFree()) {
 
585
 
 
586
            noticeConnectI(i, i != NULL);
 
587
            _i->noticeConnectI(me, me != NULL);
 
588
 
 
589
            if (!i_connected)
 
590
                appendConnectionTo(i);
 
591
            if (!me_connected)
 
592
                _i->appendConnectionTo(me);
 
593
 
 
594
            noticeConnectedI(i, i != NULL);
 
595
            _i->noticeConnectedI(me, me != NULL);
 
596
 
 
597
            return true;
 
598
        } else {
 
599
            return false;
 
600
        }
 
601
    }
 
602
    return false;
 
603
}
 
604
 
 
605
 
 
606
 
 
607
template <class thisIF, class cmplIF>
 
608
bool InterfaceBase<thisIF, cmplIF>::disconnectI (Interface *__i)
 
609
{
 
610
    cmplClass *_i = dynamic_cast<cmplClass*>(__i);
 
611
 
 
612
    // use cache to find pointer in connections list
 
613
    cmplIF *i = _i ? _i->getThisInterfacePointer() : NULL;
 
614
 
 
615
    // The cached me pointer might already point to an destroyed
 
616
    // object. We must use it only for identifying the entry in
 
617
    // connections list
 
618
 
 
619
    if (i && _i) {
 
620
        if (me_valid)
 
621
            noticeDisconnectI(i, _i->isThisInterfacePointerValid());
 
622
    }
 
623
 
 
624
    if (me && _i) {
 
625
        if (_i->isThisInterfacePointerValid())
 
626
            _i->noticeDisconnectI(me, me_valid);
 
627
    }
 
628
 
 
629
    if (i && hasConnectionTo(i)) {
 
630
        removeListener(i);
 
631
        removeConnectionTo(i);
 
632
    }
 
633
 
 
634
    if (me && i && i->hasConnectionTo(me))
 
635
        i->removeConnectionTo(me);
 
636
 
 
637
    if (me_valid && i && _i)
 
638
        noticeDisconnectedI(i, _i->isThisInterfacePointerValid());
 
639
    if (_i && _i->isThisInterfacePointerValid() && me)
 
640
        _i->noticeDisconnectedI(me, me_valid);
 
641
 
 
642
    return true;
 
643
}
 
644
 
 
645
 
 
646
template <class thisIF, class cmplIF>
 
647
void InterfaceBase<thisIF, cmplIF>::noticeDisconnectI(cmplInterface *i, bool /*pointer_valid*/)
 
648
{
 
649
    removeListener(i);
 
650
}
 
651
 
 
652
 
 
653
template <class thisIF, class cmplIF>
 
654
void InterfaceBase<thisIF, cmplIF>::disconnectAllI()
 
655
{
 
656
    IFList tmp = iConnections;
 
657
    for (IFIterator it(tmp); it.current(); ++it) {
 
658
        /* Do not call virtual methods if I'm in the contstructor!
 
659
           Actually this should be ensured by the compiler generated
 
660
           code and virtual method tables, but unfortunately some compilers
 
661
           seem to ignore this in some situations.
 
662
         */
 
663
        if (me_valid)
 
664
            disconnectI(it.current());
 
665
        else
 
666
            thisClass::disconnectI(it.current());
 
667
    }
 
668
}
 
669
 
 
670
 
 
671
 
 
672
 
 
673
template <class thisIF, class cmplIF>
 
674
bool InterfaceBase<thisIF, cmplIF>::addListener(const cmplInterface *i, QPtrList<cmplInterface> &list)
 
675
{
 
676
    if (iConnections.containsRef(i) && !list.contains(i)) {
 
677
        list.append(i);
 
678
        m_FineListeners[i].append(&list);
 
679
        return true;
 
680
    } else {
 
681
        return false;
 
682
    }
 
683
}
 
684
 
 
685
 
 
686
template <class thisIF, class cmplIF>
 
687
void InterfaceBase<thisIF, cmplIF>::removeListener(const cmplInterface *i, QPtrList<cmplInterface> &list)
 
688
{
 
689
    list.remove(i);
 
690
    if (m_FineListeners.contains(i))
 
691
        m_FineListeners[i].remove(&list);
 
692
}
 
693
 
 
694
 
 
695
template <class thisIF, class cmplIF>
 
696
void InterfaceBase<thisIF, cmplIF>::removeListener(const cmplInterface *i)
 
697
{
 
698
    if (m_FineListeners.contains(i)) {
 
699
        QPtrList<QPtrList<cmplInterface> >        &list = m_FineListeners[i];
 
700
        QPtrListIterator<QPtrList<cmplInterface> > it(list);
 
701
        for (; it.current(); ++it) {
 
702
            (*it)->remove(i);
 
703
        }
 
704
    }
 
705
    m_FineListeners.remove(i);
 
706
}
 
707
 
 
708
 
 
709
 
 
710
 
 
711
 
 
712
 
 
713
 
 
714
#endif