LinuxMCE is an open-source home automation platform based upon Kubuntu. It originated as a closed source commercial offering that was eventually open-sourced by PlutoHome Inc. Its goal was to integrate all aspects of the home into one unified user interface. As technology and design paradigms have changed, the user interface has not, leading to the examination of new GUI development avenues. In this talk, I will explore what it takes to take a project like this, from an old ui paradigm to a new one:qt / QML
Getting Started Gather your resources Users, Developers Docs Original design documents. It is key to try and develop a knowledge-base for insights into the existing architecture. Knowing why something was done a certain way can be a great boost when porting feature sets to a new ui technology. Know what the basic application goals are and seek to make sure this functionality is ported over. Users dont always know when something is new, but they always notice when something is gone.
Working with the API Figure out what it is you need and how you need it How does the api interaction work? Does it fit into the architecture of the new application? If not, how best to make it work? When dealing with creating a new application on top of an existing api, data structures and methods of communication are the first thing that should be investigated. Are the existing methods compatible with the new Qt / QML application? Is there room for improvement. Are alternate methods availible. The constraints of every system differ, and this is why exploring all options is an important, if time consuming, step.
In data driven applications, Qt already has many container classes to utilize for data QAbstractListmodel / QAbstractItemModel / QML Listmodel QList<QObject*> QMap And more! Working with the API Investigate what type will be the best match for the source they are coming from.
Subclassing QObject Benefits Can save time by not needing to write new classes. Signals and slots become available from legacy api. More flexibility Drawbacks / Pitfalls Diamond inheritance problems Could break api for legacy applications
Subclassing QObject Example: Main application class qorbiter_command : public Command_Impl,public QObject Example: Qml plugin for providing media over the network is a C++ plugin. class qmediaplayer_command : public Command_Impl, public QObject In Both instances, it was necessary to avoid a diamond inheritance problem, so I by examining the base classes, I was able to subclass QObject, giving it all the power of Qt.
Explore the different methods of connecting the two pieces together. Dont stop at what seems to be the 1st working solution, but explore different methods and compare the effectiveness of each. Options include Plumbing and more Plumbing Passing the api object by reference to the application Connecting data, commands, and events by signals and slots Other considerations when deciding this include: Who needs access to the api? The main superclass, or its members also? Will there be the need for direct communication. Should the super-class be split into other classes for more flexiblity?
Visual Theming Styling the application, and how you plan to do it is an important architectural decision. Will it support one style or multiple? Will these styles only originate from the developers, or will users be able to customize the look and feel as well? These are important questions, because they will ultimately decide how you create, work with, and deploy qml files.
Visual Theming QtObject{ id:aeonstyle } objectname: "orbiter_style" //skin description property string skincreator: "Jason Richardson (aka merkur2k)" property string skinname: "Aeon" property string skindir: "aeon" property string skindescription: "Inspired by the XBMC skin of the same name" property string skinversion: "1.0" property string skinvariation: "Desktop 720p" property string maincolor: "aliceblue" property string accentcolor: "lightsteelblue"
Visual Theming When employing a theming engine that allows the dynamic manipulation of the styles, its key to remember a few things: Its generally wise to create a fallback page that loads in the case of an unrecoverable QML error. Instead of the user looking at a white screen, they should get input that allows them to report it back to you. Layout a template that includes some form of metadata on the theme itself. In building and deploying for multiple architectures or versions, utilize the Project.pro file to customize your deployment files / current QML files.
Visual Theming Create a library of standard api handlers or interfaces, and encourage designers to utilize it. Its a lot easier to add a custom component to an element rather than setting up the mouse area, remembering what function to call, and then adding the parameters. In most cases, data is coming from a datamodel and the parameter names and such are defined in advance. Creating a set of standard components simplifies the functional part of things MouseArea{ anchors.fill:parent onclicked:myslot(param, param2) } MySlotHandler{} is a component based on the mouse area with the params pre-filled in. A user just need to instantiate it to give the button or listview cell life.
Client / Server Conversations In the case of dealing with a system that requires interaction with a remote server / datasource, its a wise idea to try and implement the communication part in a manner that doesnt block the GUI. Web based datasources operate asynchronously. You can request data and it will be processed without blocking the main thread, and thusly the gui. C++ datasources however do not make asynchronous calls unless you implement an architecture capable of that. Utilizing QThread can be immensely helpful here, allowing the server object to go at its own (hopefully not to slow!) pace.
Qt Class Roll Call Some of the Qt Classes utilized in the LinuxMCE application are: QDeclarativeView / QQuickView QApplication / QCoreApplication QTcpServer QTcpSocket QRegExp QDataStream QList<QObject*> QMap QNetworkManager QObject QAbstractImageProvider / QQmlImageProvider OpenGl Phonon / QtMultimedia Webkit QFile, QDir QProcess QAbstractListmodel
Media Integration Media integration can be one of the more complex points of integration of a new user interface. With many ways to consume media from a technical standpoint, planning this integration is key. Will media be incorporated directly into my application What are the capabilities of my target platform Will I need windowing control to place playback windows in the right locations? How am i interacting with the media sources, catalog? How can i abstract the source / catalog integration to make it easier for designers to utilize?
Media Integration { pcell= it->second; const char *ppath = pcell->getimagepath(); filepath = QString::fromUtf8(pPath); fk_file = pcell->getvalue(); celltitle = QString::fromUtf8(pCell->m_Text); index = pdatagridtable->covertcolrowtype(it->first).first; if (ppath ) { cellimg = getfilefordg(ppath); } else { cellimg.load(":/icons/icon.png"); } emit additem(new griditem(fk_file, celltitle, filepath, index, cellimg)); }
Finishing up Converting a legacy application that utilizes and older ui technology can be quite the undertaking. But with a planned, measured approach, it can be done expeditiously, and done well. Find as many original system designers as you can Spend time examining the existing architecture, and where your new application can fit in This includes the API For web based api's _should_ be less of a challenge For other methods, don't be afraid to experiment with sub-classing QObject Plan your QML architecture from the start. Decide if you are going to use multiple styles, or one