identifying signal senders
-
@JonB said in identifying signal senders:
This is the issue? To identify which QNetworkReply belongs to which QNetworkAccessManager::get(const QNetworkRequest &request) at a later date when processing the QNetworkReply?
Sort of (this issue is tough to explain)...I can easily enough associate the reply with the get, but I'm not sure how to go about knowing to which model the reply should be forwarded.
Thinking about this a little more, it's probably better to ascertain the source of the request at the point of the request, rather than after the reply comes in. I guess I could add another parameter to my signals to the manager:
class MessageMgr : public QObject { public slots: void sendGet(QString message); // my current way void sendGet(QString message, QString model); // an alternative
When a module emits a send request, it would include a string containing its name. This would be entered into a hash, with the NetworkReply * as the key, and the model name as the value.
When the reply comes back, the message manager would look up the model in the hash, and add it to the signal that the reply came back. The signal would then go to each model, which would check for a name match before attempting to process.
This sounds like it would work, but it's hardly elegant. A variant on this theme would be to have separate signals for each model, but that's also really a hack.
I'm beginning to wonder if perhaps the signal/slot mechanism isn't the best way to approach this (a traditional callback method would actually work better in this case), but I'm not sure what to do.
I'll think a little about your subclassing ideas.
-
@mzimmers
I don't understand your complications. If you don't want hashes and strings and lookups I said you could always just store theQAbstractItemModel *
, or whateverModel *
, to access the model directly. Only you know what is and is not available to you in your code. -
@JonB I suppose that's an option. Of course, each model would have to have the same handler signature, but that's probably best practices anyway. I suppose I could take it a step further, and pass a pointer to the handler function instead of the entire object?
-
Return the QNetworkReply from MessageMgr::sendGet(), connect the appropriate model slot to QNetworkReply::finished(), and eliminate the intermediary handling of the reply.
Another alternative is QNetworkRequest::setOriginatingObject() and QNetworkReply::originatingObject().
-
@mzimmers said in identifying signal senders:
@SGaist right, but it's the same problem -- what do I do with it? How do I go from knowing the sender to invoking a method in the sender class?
Again, I don't understand. I wrote earlier for this suggestion:
Subclassing
QNetworkRequest
could allow you add aQAbstractItemModel *
to directly identify the data model.So you would have a pointer to the model as a
QAbstractItemModel *
. On which you can call (QAbstractItemModel
) methods directly. Or if your models share some other common interface you could derive them fromYourModelBase
and pass that as parameter to be able to call its methods. Or you could useqobject_cast<SpecificModelType *>
to test their type and call specific model methods.Or the approaches @jeremy_k mentions. Using
QNetworkRequest::setOriginatingObject(someModel)
saves subclassing if you don't want to do that, but it's the same approach. His direct connection offinished
signal could be used if you do not actually want/need the manager to see/handle the replies.One way or another you can either have the models send an identifier for themselves to the manager, which then routes replies to the model from that, or you can have the manager return the
QNetworkReply *
fromQNetworkAccessManager::get()
to the model and that puts e.g. a slot onQNetworkReply::finished()
to its own code. -
@JonB said in identifying signal senders:
His direct connection of
finished
signal could be usedif you do not actually want/need the manager to see/handle the replies.The struck-out portion is inaccurate. The manager can view the reply status via any of the const methods, or read content via QIODevice::peek() without interfering with later connections to the finished or readyRead signals.
-
@jeremy_k
Yes, but that's not what's meant. It's a question of whether the OP wants the replies routed through the manager, possibly to choose whether to send on to the models or to ignore/not do so, or whether the model receives thefinished
regardless and acts on it. I said "could" be used if OP does not want manager to see/handle the replies, not that it would preclude the manager seeing the responses as you wrote. As you said, not attaching thefinished()
signal to the model to "eliminate the intermediary handling of the reply" means that it will be attached and handled by the manager as "intermediary". Depends what the OP wants, -
@JonB said in identifying signal senders:
@jeremy_k
Yes, but that's not what's meant. It's a question of whether the OP wants the replies routed through the manager, possibly to choose whether to send on to the models or to ignore/not do so, or whether the model receives thefinished
regardless and acts on it. I said "could" be used if OP does not want manager to see/handle the replies, not that it would preclude the manager seeing the responses as you wrote. As you said, not attaching thefinished()
signal to the model to "eliminate the intermediary handling of the reply" means that it will be handled by the manager as "intermediary".Fair enough. I had interpreted "see/handle" as non-exclusive.
To me, a manager that inhibits what the model sees from a successful request is acting as part of the model. HTTP and QNetworkReply has error codes to indicate lack of success. -
Feels like the issue has little to do with the network request.
The issue is that the manager doesn't keep state.
So, if model X makes a request to the manager which is then forwarded to get an async reply. What you want to do is to ignore the fact on how its implemented and simply do what all async APIs do. Create a new QObject that emits a signal when its got a data update.
So what you see, as an example API, networkmanger::get() do, they return an object with a bunch of signals.
What you want to do is make you message-manager do the same. This means it needs to keep state. Which means it needs to route messages only back to the object it actually owns. An equivalent to the NetworkReply, maybe called SignalManagerReply...
The fact that the message-manager itself uses the network manager privately is a nice parallel you can probably use to mirror the workflows.
Edit; oh, and want to add that your initial statement of a 'model' asking he signal-manager something is breaking the model-view-controller design. You need a controller to handle an async API like the signalmanager would have (as a result of it using networkmanager).
Such a controller-style class is where the SignalManagerReply is used.
-
M mzimmers has marked this topic as solved on