Thursday 25 November 2010

Putting spaces in the name of a Qt for Symbian application

Just thought I'd share this solution for a problem that I came across, whilst writing a Qt app for Symbian devices.

The problem was that I was trying to give my app a name with spaces in, as it looks unprofessional having underscores or using CamelCase for the name that would appear below your application icon on a phone.
This cannot cimply be done by putting a name with spaces as the argument to the "TARGET = ..." line of your .pro file as Qt is not expecting this, nor does putting the name in quotation marks work.

The solution I used is from this bug report http://bugreports.qt.nokia.com/browse/QTBUG-14280?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel (whilst this blog entry doesn't really add much to the suggested work around in the bug report, i'm hoping that by writing it up in different words, someone may find the solution faster). As the bug report says, this problem is going to be fixed in Qt 4.7.2, but as of posting this you can only use Qt 4.6.3 to publish to Ovi Store so a workaround is currently required.

Firstly you should set the TARGET in your pro file to be a useful description without spaces but we are going to overwrite the application name everywhere it appears to the end user so it doesn't really matter what the TARGET name is.
Secondly you should add the following lines to the .pro file for your project:

customHeader.pkg_prerules = "$${LITERAL_HASH}{\"Your app name here\"},($$TARGET.UID3),$$replace(VERSION,"\.",",")"
DEPLOYMENT += customHeader

Replacing "Your app name here" with your app name but keeping the quotation marks as they are in the above code.
Secondly you should create a new file in your project directory with a name of your choosing, I call mine "forceName.loc" so it is clear what it's responsiblity is. Inside this file you should put the lines:

#ifdef LANGUAGE_SC
#define STRING_r_short_caption "Your app name"
#define STRING_r_caption "Your app name"
#else
#define STRING_r_short_caption "Your app name"
#define STRING_r_caption "Your app name"
#endif

Again replacing "Your app name" with the appropriate text, leaving the quotation marks as they are.
Finally in order to get your application to use this file whilst building, you should add the following lines to your .pro file:

fix_loc.commands = $${_PRO_FILE_PWD_}/forceName.loc $${_PRO_FILE_PWD_}/$$basename(TARGET).loc
symbian-abld: fix_loc.commands = $$replace(fix_loc.commands,/,\\)
fix_loc.commands = $$QMAKE_COPY $$fix_loc.commands
QMAKE_EXTRA_TARGETS += fix_loc
PRE_TARGETDEPS += fix_loc

where "forceName.loc" should be replaced by whatever name you used for the file and the rest should be left as it is.

I hope this manages to help someone.

Monday 15 November 2010

In praise of QTimer->start(0)

The situation: In Qt I have to get some data ready in an application but it doesn't all need to be ready at the start so I want to get some to begin with and then continue getting the rest in the background without freezing the UI. Also I need to be able to stop this data getting for when I want to run a high precision timer with high accuracy.

First attempted solution: Subclassing QThread (though this is not recommended, see http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/).
Basically in this case, i make the run method of a QThread subclass do a little piece of the data processing. There are 2 disadvantages to this method, firstly, it has a large overhead creating a whole thread and secondly you also have to implement your own pause and resume functions as QThread does not come with these.

The used solution: Write a slot that performs a single part of the data processing, connect it to the timeout() slot of a QTimer and then call QTimer->start(0) where the 0 is a special value to QTimer indicating that it should only fire when the application is idle (see http://doc.trolltech.com/4.6/qtimer.html#interval-prop). This method also makes pausing and resuming very very simple as to pause you just need to call QTimer->stop() and then to start again call QTimer->start(0).

This solution works ridiculously well in my application and the ease of pausing and resuming really is a treat.