Search code examples
c++qtruntimeqt-designerqresource

Removing/modifying static Qt resources in run-time


As part of a Qt Designer hacking, I'm interested in removing a resource in runtime (specifically :/trolltech/widgetbox/widgetbox.xml). Refer to the end of the post for more detail about the context.

My obvious (and failed) attempt was:

QFile(":/trolltech/widgetbox/widgetbox.xml").remove();

but it returned an error.

My next attempt was to use Q_CLEANUP_RESOURCE(widgetbox), but the functions it expands to are only available within a private component of Qt Designer (QDesignerComponents).

Another attempt was to clear the content of the file, but it is read-only:

QFile f(":/trolltech/widgetbox/widgetbox.xml");
if (f.open(QFile::WriteOnly)) { ... } // returns false

I've also tried to overwrite it in the Qt resource's filesystem by defining my own :/trolltech/widgetbox/widgetbox.xml. I'm able to open the file but it fails to retrieve data, I guess because it is a duplicate resource (aliasing the resource to an unused name makes the application to print out the content correctly). On the other hand, the list of widgets is presented correctly.

QFile f(":/trolltech/widgetbox/widgetbox.xml");
if (f.open(QFile::ReadOnly)) {
    qDebug() << "{";
    qDebug() << f.readAll(); // shows nothing
    qDebug() << "}";
}

Is there any way to modify/remove/replace a resource file in runtime?


In the case you consider this an XY problem I'll explain the whole context: I'm integrating Qt Designer into my own IDE by making small tweaks to the standalone one. Basically, I've added a compilation flag to generate a dynamic library instead of an executable, and added some options to expose the main window.

In this IDE I want to add an option to avoid the user to use the default widgets and restrict the list to a set of custom ones. The resource I mention is the file containing the list of widgets available in Qt Designer by default. Additional widgets can be easily included via plugins, but I haven't found a way to remove default ones.

One option I have is to make that load optional, but it will produce a cascade of changes through many projects. I'd like to avoid modifying Qt Designer so much.


Solution

  • You are using Qt Designer already, so first of all you should include it in your build, and secondly you will have access to all of its classes - no such thing as a "private" component anymore, it's your code now. Make it work for you!

    Qt resources can be compiled-in or generated in a separate binary. You could put this resource into a separate binary and then easily load and unload it via registerResource/unregisterResource.

    QFile uses a virtual file system based on QAbstractFileEngine. The implementation of QAbstractFileEngineHandler::create acts as a filter and can catch the request and let your file engine handle it if desired. E.g. your file engine could simply fail on open - this is equivalent to deleting the resource.

    Note that since Qt 5 the QAbstractFileEngine is not public anymore and presumably Qt folks are looking at replacing it with something else. To use these APIs, you need to add qt += core-private to your project's qmake file.