0
votes

Is there any way how to implement dynamical file-resolver for missing Qml components in QmlEngine? How to implement dynamically loading of external resources to QmlEngine?

I can use following snippet to load qml component from any data stream:

QUrl uri(...)
QByteArray data(...);
QQmlComponent::setData(data,uri);

but when passed component refers to another one (not already loaded), QmlEngine stopped because of missing resource.

Is there any event/callback where it is possible to handle such missing resource?

Added use-case scenario:

We're developing some QML visual components. Some components are implemented as .qml files and some as QQuickItem.

For example imagine following situation (it's very simplified):

  • QmlItem "DiagramPoint", implemented in point.qml
  • QmlItem "Line" implemented in line.qml, class is using "DiagramPoint" item
  • QQuickItem (c++) "ConnectedLine" which internally using "Line" object
  • QmlProject which using "ConnectedLine" components.

In case that point.qml and line.qml are located on hdd or stored inside Qt Resources, everything works automatically. But what we would like to achieve is to store these files in encrypted form in our internal .dat file and decode it only on demand.

We're able to decode and load "Line" object from "ConnectedLine" implementation. But in case that "Line" (line.qml) depends on another encrypted file "DiagramPoint" (point.qml), this solution doesn't work.

Another possible solution

Another solution could be to register all decrypted .qml files on application startup and than use it. Something simillar to qmlRegisterType which allows to register c++ QQuickItems to QmlEngine.

Unfortunately none of these methods allow to register Qml snippet from string buffer.

1
Did you have any success with the QQmlAbstractUrlInterceptor? I am also looking for a way to protect my QML code from plagiarism, and I considered the interceptor, but I assumed it only deals with urls, not with resolution of QML types which you use in QML declarative code. I consider a solution where QQmlComponents are created from strings in memory, stored in the binary encrypted, but there doesn't seem to be a way to do that - it is like the QtQuick API was deliberately designed without a way to hide your code, not unless you pay for a commercial license and the QML compiler...dtech
I mean while it is possible to create a QQmlComponent from data, it doesn't seem to be possible to register it as a QML type that can be used in QML sources. In my case different components also depend on each other.dtech
Unfortunately there are too many difficulties when you will try to implement it with this way. Obviously Qt developers prepared all libraries only to single scenario - develop all in opened Qml and inject data from c++. For our purposes we decided to implement all base Qml objects as QQuickItems, register it to QmlEngine and than use Qml only as render engine and decorator for these QQuickItems. It seems to be the only efficient way. All other possibilities are based on creating objects from strings with QQmlComponent::setData but this looks absolutely wrong to me.Ludek Vodicka
In case you will find any other way, could you please send me some sample? I spent tens of hours on internet when searching for reasonable solution but this was the only one. Unfortunately there is so little info about such advanced Qml usage.Ludek Vodicka
I will be posting any progress here stackoverflow.com/questions/34814738/…dtech

1 Answers

1
votes

I'm still a bit unsure about how you would do this, but you might find QQmlAbstractUrlInterceptor useful:

QQmlAbstractUrlInterceptor is an interface which can be used to alter URLs before they are used by the QML engine. This is primarily useful for altering file urls into other file urls, such as selecting different graphical assets for the current platform.

Relative URLs are intercepted after being resolved against the file path of the current QML context. URL interception also occurs after setting the base path for a loaded QML file. This means that the content loaded for that QML file uses the intercepted URL, but inside the file the pre-intercepted URL is used for resolving relative paths. This allows for interception of .qml file loading without needing all paths (or local types) inside intercepted content to insert a different relative path.

Compared to setNetworkAccessManagerFactory, QQmlAbstractUrlInterceptor affects all URLs and paths, including local files and embedded resource files. QQmlAbstractUrlInterceptor is synchronous, and for asynchronous files must return a url with an asynchronous scheme (such as http or a custom scheme handled by your own custom QNetworkAccessManager). You can use a QQmlAbstractUrlInterceptor to change file URLs into networked URLs which are handled by your own custom QNetworkAccessManager.

To implement support for a custom networked scheme, see setNetworkAccessManagerFactory.

It says that its synchronous, so perhaps you could decode the QML files when the URLs are intercepted to ensure that they exist?