KDAB / GammaRay

GammaRay is a tool to poke around in a Qt-application and also to manipulate the application to some extent.
https://www.kdab.com/gammaray
Other
1.61k stars 283 forks source link

Using gammaray without UI possible? #216

Open tobimensch opened 8 years ago

tobimensch commented 8 years ago

Hello,

first of all I must say you have done great work on this tool!

I used gammaray to remove the menubar from qtcreator by setting maximumHeight = 0 in the property editor. (alt+(F|E|B|D|A|T|W|H) shortcuts still work with this method as opposed to setting visible = false )

Obviously I'm not eager to start gammaray everytime just in order to do that. So I was searching for a way to script such changes using gammaray without a UI, and as far as I can see, that isn't yet possible.

Is there some way to achieve this?

Ideally I would like to have a short script like that:

#!/bin/sh
#hypothetic script for toggling menubar on/off in qtcreator

PID=$(ps aux | grep qtcreator | head -n1 | awk '{print $2}')

PROP=$(gammaray --pid $PID --get-property QtCreator.MenuBar.maximumHeight)

if [ "$PROP" == "0" ]
then #back to defaults
    gammaray --pid $PID --unset-property QtCreator.MenuBar.maximumHeight
else
    gammaray --pid $PID --set-property QtCreator.MenuBar.maximumHeight=0
fi
krf commented 8 years ago

While I question your use-case (you should rather try to file a feature request for QtCreator), I think the feature you need indeed could be useful for others.

Marking this as a junior job. This is a self-contained feature which a newcomer could tackle.

tobimensch commented 8 years ago

Well, it would certainly be very good if you could just give a quick guideline as to how this feature could be implemented.

You call this a junior job, a junior will not be familiar with the code base and therefore will have no clue where to start (I started from int main(), but the confusion increased from there), what the relevant classes are, where the right entry point in the code would be for this function and so forth.

I think someone who's familiar with the code, would be able to implement this in 30 minutes (or less).

Btw, I looked at the code 2 weeks ago and found it not exactly obvious, I suppose the ObjectBroker class can be used for this? I haven't found documentation(or @extensive comments in the code) on how the code is structured, what the main classes are and what their interplay with each other is.

Just a quick summary of what would have to be done or what the closest example testcase for this is would help "a junior" a lot. I don't want to read the whole code base just to implement this simple feature.

tfoldi commented 7 years ago

I have the same issue, I am stuck at very beginning:

On client side I am here:

  ClientConnectionManager conMan;
  QObject::connect(&conMan, SIGNAL(disconnected()), QApplication::instance(), SLOT(quit()));
  QObject::connect(&conMan, SIGNAL(persistentConnectionError(QString)), &conMan,
                 SLOT(handlePersistentConnectionError(QString)));
  conMan.connectToHost(serverUrl);

Now the struggle: how can I get QObject handlers of my application (that was executed Contents/MacOS/gammaray --inject-only)? I tried a couple of things but the documentations is not really useful. ObjectBroker::hasObject is always false, ObjectBroker::model("com.kdab.GammaRay.ObjectList") gives zero records. When I execute the UI, everything is there.

If you can just point me how can the client access a remote QObject, that would be just superb and I can proceed with the junior job and add some script language around it.

akreuzkamp commented 7 years ago

Hey tfoldi,

You're approach is correct so far. I do not completely agree with Kevin about this being a good junior job, because from here it's not exactly easy. The most relevant code files to get inspiration about how to get information about objects are: ui/tools/objectinspector/objectinspectorwidget.cpp ui/tools/objectinspector/propertiestab.cpp common/tools/objectinspector/propertiesextensioninterface.h

The issue is, that the client/server protocol is heavily based on models and very strongly bound to the ui at the moment...

What you need to do is:

The better solution would be to refactor the API to better suit that use case, but that's far from being a junior job. Please also note, that the GammaRay API is far from stable and might likely change from version to version (e.g. because we decide to improve it for scriptability ;) ).

tfoldi commented 7 years ago

Thank you, will give a shot next week.

bertcay commented 7 years ago

Hi,

I think I have same request. I'm currently trying to extract all displayed objects in but do not need the full and complete UI. Here is my code,

Client *myClient = new Client(this);
QUrl myUrl;
myUrl.setScheme("tcp");
myUrl.setHost("xxx.xxx.xx.xx");
myUrl.setPort(11732);
myClient->connectToHost(myUrl, 0);

auto objectModel = ObjectBroker::model(QStringLiteral("com.kdab.GammaRay.ObjectInspectorTree"));
auto selModel = ObjectBroker::selectionModel(objectModel);
QAbstractItemModel *propertyModel = ObjectBroker::model("com.kdab.GammaRay.ObjectInspector.properties");

connect(objectModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
        this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));

--> SLOT is never called. --> I have this as output : ... Cannot dispatch message 29 - no handler registered. Receiver: com.kdab.GammaRay.SignalMonitorInterface/1.0, address 13 cannot call method clock on unknown object of name com.kdab.GammaRay.SignalMonitorInterface/1.0 with address 13 - did you forget to register it? Cannot dispatch message 29 - no handler registered. Receiver: com.kdab.GammaRay.SignalMonitorInterface/1.0, address 13 cannot call method clock on unknown object of name com.kdab.GammaRay.SignalMonitorInterface/1.0 with address 13 - did you forget to register it? Cannot dispatch message 29 - no handler registered. Receiver: com.kdab.GammaRay.SignalMonitorInterface/1.0, address 13 ...

What sort of attach or broker am I missing ? I just need to navigate against all object.

Thanks bertrand

vkrause commented 7 years ago

The models are lazily populated, so unless you call rowCount() and data() on them, it wont actually load any content by itself, therefore your slot is never called.

bertcay commented 7 years ago

Thanks for reply,

Code is now :

qInfo() << "BEFORE";
Client *myClient = new Client(this);
QUrl myUrl;
myUrl.setScheme("tcp");
myUrl.setHost("192.168.0.13");
myUrl.setPort(11732);
myClient->connectToHost(myUrl, 0);
auto objectModel = ObjectBroker::model(QStringLiteral("com.kdab.GammaRay.ObjectInspectorTree"));
auto selModel = ObjectBroker::selectionModel(objectModel);
QAbstractItemModel *propertyModel = ObjectBroker::model("com.kdab.GammaRay.ObjectInspector.properties");

qInfo() << "BEFORE rowCount";
objectModel->rowCount();

qInfo() << "BEFORE data";
objectModel->data(objectModel->index(0, 0), Qt::DisplayRole);

qInfo() << "BEFORE connect";
connect(objectModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
        this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));

qInfo() << "AFTER";

--> got a segmentation fault when executing rowCount() objectModel should be empty.

bertcay commented 7 years ago

Excuse me but don't you have a simple sample allowing me to browse the list of object without having a UI. Thanks Bertrand

tobimensch commented 7 years ago

I'm also still interested in this.

bertcay commented 7 years ago

Well, I've been able to correctly list all the MessageStatisticsModel by constructing my model once client connected. That was great. By changing the model to a NetworkInterfaceModel I'm now able to list all the network interfaces instead of the messagestatistics. Great ! ... just had to change the type of my model oO : auto objectModel = ObjectBroker::model(QStringLiteral("com.kdab.GammaRay.NetworkInterfaceModel")); --> objectModel is now NetworkInterfaceModel instead of MessageStatisticsModel (I'm not talking about the String "com.kdab.GammaRay.NetworkInterfaceModel" but just the type of objectModel) I don't know where is the magic here ! ...

That's great ! that was just for test. Just to understand how to retrieve another model than ModelStatisticsModel. But it is executed locally oO. Indeed network interfaces are the one of the client host and not the one of server host. --> I'm well connected to the remote server ... Endpoint singleton shouldn't manage all transactions to go through the network if connected to a remote server ?

tobimensch commented 7 years ago

@bertcay Can you provide the code please?

tobimensch commented 7 years ago

Any news on this front?

Guitronic commented 2 months ago

1/ In version 3.1, if the model "com.kdab.GammaRay.ObjectInspector.properties" is not attached to a view it is never filled: model.rowCount() = 0 Is this normal?

2/ When it is attached to a view, the QAbstractItemModel::dataChanged signal is called each time the data() method is accessed. I think this is a bug.