1
votes

Consider signal manager that receives the signal, checks for some conditions, and if they are met, transmits signal to slot, discarding signal otherwise:

signal(some args) ---> [manager] ---> slot(some args)

I can implement it for each given set of arguments using QMetaObject::invokeMethod, say for void signal(int) and void slot(int):

.h

class Manager: public QObject
{
    Q_OBJECT
public:
    Manager(QObject* sender,const char* signal, QObject* recv, const char* slot);
private:
    bool isOkToSend();

    QString slotInvokeSyntax;
    QObject *recv;

private slots:
    On_Signal(int);
}

.cpp

Manager::Manager(QObject* sender,const char* signal, QObject* recvIn, const char* slot)
        : slotInvokeSyntax(slot)
        , recv(recvIn)
{
    connect(sender,signal,this,SLOT(On_Signal(int));
    //retrieving method name only
    slotInvokeSyntax.remove(0,1).remove(QRegExp("(*",Qt::CaseSensitive,QRegExp::Wildcard));
} 

Manager::On_Signal(int val)
{
    //invoking slot
    if(isOkToSend())
        QMetaObject::invokeMethod(recv,slotInvokeSyntax.toAscii().constData(),Q_ARG(int,val));
}

I would like to somehow generalize this for signals and slots with generic number/type of arguments - so that manager works on any pairs like signal(QString)-slot(QString), signal(int,int)-slot(int,int), ...

Is there any way to implement this functionality without adding slot for each of the argument types in Manager? In case my approach is in wrong in general, any suggestions on how to implement such manager are welcome!

EDIT

A bit of clarification on what am I trying to implement - I have large system with several possible states consisting of many smaller widgets (or sub-systems) (some sub-systems can also act both as stand-alone applications or as a part of the larger system). I'm trying to implement global observer that intercepts certain ui events (such as buttons clicks, edits in QLineEdit, QDropbox changes, etc.), and either let corresponding slot of the widget to be called, or discards it if desired action interferes with the global state of the system. I would like to do it through intercepting signal since it allows to avoid dependencies between system components and compiling each subsystem as stand-alone library (with observer not being dependent on any other part of the system and thus being put in core library), but I'm open to any other alternatives that will allow me to achieve that!

1

1 Answers

1
votes

FYI, whenever you use something like this:

QString foo;
something(foo.toAscii().constData());

...you are accessing already freed memory because the data pointed to by the QByteArray::constData are valid only until the QByteArray instance lives and is not modified. In your case, the QByteArray is a temporary created by calling foo.toAscii() and is destroyed before the something is called. So this will crash at some point. edit: this does not apply to function calls, see the comments.

To your question -- it would be interesting to know what you're trying to achieve here. The Qt's metatype and metaobject system is indeed a rich one, but abusing it too much might not be the most ellegant way of solving your problem. That said, it's probably fine to use it in this "creative" way with mocked objects, in unit tests etc.

I haven't done this myself and I am not sure whether it's doable without having to touch the q_static_metacall, but it looks like QObject generic signal handler contains an answer to your question.

After Edit:

You said you're looking for a something like a common event bus; the alleged reason is to avoid excess rebuilds when the individual components change. I would not introduce a central interceptor to this architecture. If the toal amount of states is reasonably small, why don't you just let something emit signals upon entering a particular state and have all of your components react to that by enabling/disabling the individual QActions?