
When embarking on the implementation of the Futubra client for Symbian, I did not doubt that Qt Quick was chosen as the framework for implementing the user interface of the application. Thanks to his reactive data binding, it becomes possible to implement the presentation layer using advanced architectural design patterns, in particular, Model-View-ViewModel. However, Qt Quick in its “bare” form has a very scanty set of basic elements from which it is proposed to assemble more complex ones: buttons, input fields, and so on. Bearing in mind what a lot of time was spent on their implementation when creating the user interface on the past project, I immediately abandoned the idea of ​​doing it myself and turned my attention to the Qt Quick Components library. Under the cut is a description of how I managed to expand the boundaries of its applicability and “get” for the platform S60 5th edition.
The Qt Quick Components library is a collection of Qt Quick plugins that implement a wide range of widgets on top of QML. One of the main features of the library is its cross-platform. There is a
desktop version for Windows, Mac OS, KDE and GNOME, as well as variations for the smaller brothers in the face of Symbian, Maemo and MeeGo. Of course, due to the peculiarities of the platforms, screen resolutions and Design Guidelines, the versions have some differences, but it is quite realistic to create about 80% of the QML code for, say, Windows and Symbian. An equally important feature of the library is the native view of the widgets it contains for each of the platforms.
When I started researching the library version documentation for Symbian, I immediately ran into bad news. In accordance with the Qt Quick Components
documentation, only Symbian ^ 3, Symbian Anna and Nokia Belle are supported for modern Symbian ^ 3. As for the popularity of Nokia’s first-generation touchscreen smartphones in our country, such as the 5800 XpressMusic, 5228, etc., I also needed to support the S60 5th edition platform. There was only one thing left - at your own peril and risk of porting the library to this operating system too. The experience was successful, and
here I published the full source code of a demo application using my own version of Qt Quick Components. Further, only the most difficult porting moments, mainly related to qmake programming, are illustrated.
')
Unloading
It is important to note here that it is necessary to pump out exactly the 1.0 branch - it works practically out of the box. Later versions of the 1.1.x library have “heavy” dependencies on the Symbian SDK in the form of header files and libraries that are missing from the S60 5th edition SDK. You can get the source code either as an archive by
reference , or by using the appropriate Git command:
git clone git://gitorious.org/qt-components/qt-components.git -b 1.0-symbian
Shamanim
Despite the fact that the Qt documentation provides a detailed example of creating plugins, a very difficult part is left behind the brackets associated with setting up the configuration * .pro and * .pri project files (hereinafter, just scripts). So, the scripts created by Qt Creator by default do not contain mechanisms for creating an installer containing Qt Quick plugins. One of the features of installing applications on Symbian is that all executable files and dynamic libraries must be placed in the C: \ sys \ bin directory, while Windows does not regulate the location of these. As a result, it is very easy to come to a situation where the file structures resulting from the installation of the application for the emulator and the device will be significantly different, which will lead to the search for the subtle installer bugs specific to each of the platforms. My main idea when developing scripts was to ensure that they equally installed the application on both Windows and Symbian. We proceed to their consideration.
/config.pri isEmpty(APP_SOURCE_TREE): APP_SOURCE_TREE = $$PWD isEmpty(APP_INSTALL_LIBS): APP_INSTALL_LIBS = $$APP_SOURCE_TREE/lib isEmpty(APP_INSTALL_ROOT): APP_INSTALL_ROOT = $$APP_SOURCE_TREE/install isEmpty(APP_INSTALL_BINS): APP_INSTALL_BINS = $$APP_INSTALL_ROOT/sys/bin isEmpty(APP_INSTALL_IMPORTS): APP_INSTALL_IMPORTS = $$APP_INSTALL_ROOT/resource/demo/imports isEmpty(APP_INSTALL_RESOURCES): APP_INSTALL_RESOURCES = $$APP_INSTALL_ROOT/resource/apps/demo symbian {
The config.pri file defines all environment variables used in other scripts. With the help of $$ PWD, the path to the root of the project is determined, while the remaining paths are determined relative to it. When the project is built, the install daddy will be created in its root, which is a prototype of the C: drive on the device. In the same way as in it, the project will be decomposed and on the device.
For brevity, we consider the plug-in scripts using the simplest of them, components. Each plugin has a pri-file and a pro-file of the same name. The first describes the properties of the plugin used to create the installer, the second the properties used to build the actual library.
/src/3rdparty/qt-components/components/components.pri QT_COMPONENTS_PLUGIN.source_path = \ src/3rdparty/qt-components/components QT_COMPONENTS_PLUGIN.imports_path = \ Qt/labs/components QT_COMPONENTS_PLUGIN.target = \ $$qtLibraryTarget(embedded_qt_components_plugin) QT_COMPONENTS_PLUGIN.qml_files += \ qmldir \ Checkable.qml \ CheckableGroup.qml \ CheckableGroup.js APP_PLUGINS += QT_COMPONENTS_PLUGIN
The properties of the fields in the structure describing the plugin have the following meanings:
The relative import paths of the one-to-one Qt Quick Components collected match the one for the original plug-ins on the device. Abstraction of qml-files from the knowledge of the nature of the plug-ins with which they work allows you to safely switch between them in assemblies for the S60 5th edition and modern Symbian. In the last line of the pri-file, we add the components plugin to the APP_PLUGINS array of plug-ins installed on the device.
/src/3rdparty/qt-components/components/components.pro include(../../../../config.pri) include(components.pri) TARGETPATH = $$QT_COMPONENTS_PLUGIN.imports_path TEMPLATE = lib TARGET = $$QT_COMPONENTS_PLUGIN.target INCLUDEPATH += $$PWD $$PWD/models CONFIG += qt plugin QT += declarative network script DEFINES += QT_BUILD_COMPONENTS_LIB QML_FILES += $$QT_COMPONENTS_PLUGIN.qml_files symbian { TARGET.EPOCALLOWDLLDATA = 1 TARGET.CAPABILITY += $$APP_CAPABILITY TARGET.UID3 = 0xE1E604E2 } HEADERS += qglobalenums.h SOURCES += plugin.cpp include(kernel/kernel.pri) include(models/models.pri) include(../../../../install.pri)
The paired pro file at the very beginning includes config.pri to take advantage of all environment variables, for example APP_CAPABILITY. The use of the latter is due to the Symbian security system, which insists that the access level of the dynamic libraries used by the executable file is not lower than the access level of the file itself. In order not to bother with this, it is easiest to give the same CAPABILITY to all plugins and exe-shnik.
We get
Below is the configuration file that brings all the plugins together. In it, we include the pri-files of all Qt Quick Components plug-ins and form directives for generating files with instructions for creating an installer for Symbian.
src / app / gui / gui.pro include(../../../config.pri) include(../../3rdparty/qt-components/components/components.pri) include(../../3rdparty/qt-components/symbian/symbian.pri) include(../../3rdparty/qt-components/symbian/extras/extras.pri) CONFIG += qt mobility QT += core declarative network TARGET = EmbeddedComponents DESTDIR = $$APP_INSTALL_BINS
And finally, how to connect the imports in the application itself.
src / app / gui / application.cpp QDeclarativeView *Application::buildRootView() { QScopedPointer<QDeclarativeView> view(new QDeclarativeView()); QObject::connect(view->engine(), SIGNAL(quit()), view.data(), SLOT(close())); view->setResizeMode(QDeclarativeView::SizeRootObjectToView); view->engine()->addImportPath(QLatin1String("../../resource/demo/imports")); view->setSource(QUrl("qrc:/layout/main.qml")); return view.take(); }
In accordance with the environment variables that we defined, the application itself was installed in / sys / bin, and the plugins in / resource / demo / imports of the same disk. From here we get the path that needs to be specified in the addImportPath function of the QDeclarativeEngine.
Instead of conclusion
An application created with the help of the hand-assembled Qt Quick Components is almost indistinguishable from the similar one assembled with their original version. This gave rise to a funny misunderstanding by the QA Team at the Nokia Store. They didn’t want to publish the application for a long time, reproaching me for allegedly using real Qt Quick Components, but for some reason I don’t declare dependence on them in the installer. Here is their comment:
Jerry (VC-Signing) (Thu, 03 May 2012 18:41:30 +0000)
Dear Publisher
Your app uses Qt Quick Components for Symbian, but your app. Please add the dependency and rebuild your app.
I managed to deal with this problem only by building an application for modern Symbian using original plugins. In view of the fact that it is impossible to physically do the same for the S60 5th edition, Nokia Store employees did not insist on its presence in the application installer for this platform. And finally, let me remind you once again that the source code of the demo application with its own version of Qt Quick Components is available
here .
Pavel Osipov,
Developer official Futubra for Symbian