rich's blog
Submitted by rich on Thu, 01/14/2010 - 15:39
A topic that I've not mentioned in any of my blog posts is threading, not because I have anything against it, simply because a simple use-case hadn't come up. Today I was coding something easy to describe, where using threads was a good solution, so let's take a look at it.
The problem I needed to solve was to calculate cryptographic hashes of files that could be very large - for example 4 gigabyte DVD isos. As with any graphical application it is very important to ensure that the GUI remains responsive while this work is done. Since the problem involves very little communication between the part of the application calculating the hash, and the rest of the code a worker thread is an ideal solution.
The code that actually does the work is very simple, it uses the handy QCryptographicHash class to do the work (stored in the variable hasher):
HasherThread::HasherThread(QObject *parent) :
QThread(parent)
{
hasher = new QCryptographicHash( QCryptographicHash::Sha1 );
}
void HasherThread::run()
{
QFile f( filename );
if ( !f.open(QIODevice::ReadOnly) ) {
emit error( QString("Unable to open file %1").arg(filename) );
return;
}
hasher->reset();
char buffer[16*1024];
qint64 count;
do {
count = f.read( buffer, sizeof(buffer) );
if ( count == -1 ) {
emit error( QString("Read error") );
break;
}
hasher->addData( buffer, count );
} while( !f.atEnd() );
emit completed( hasher->result().toHex() );
}
The code opens the file to be hashed, then reads through it in 16K chunks which it passes to the hasher. If this code were executed in the application's gui thread then this would cause the interface to freeze until the hash was ready, but the code lives in a class that inherits QThread.
One important feature to note about the code above is that the communication with the rest of the application is via signals (the error and completed signals to be precise). This is very important as it means that when we use the class, we can simply use it like this:
hasherThread = new HasherThread( this );
connect( hasherThread, SIGNAL(error(const QString &)),
ui->resultEdit, SLOT(setText(const QString &)) );
connect( hasherThread, SIGNAL(completed(const QString &)),
ui->resultEdit, SLOT(setText(const QString &)) );
The special thing in the code above, is that we didn't have to do anything special - Qt just solved our inter-thread communication issues for us. What I mean, it that if our code had simply tried to output the result by calling ui->resultEdit->setText() directly then we would be attempting to access the GUI from outside the GUI thread which would most likely cause our application to crash. Instead, since we're using the default type of connections 'AutoConnection', what this means is that Qt will spot if the thread in which a signal is emitted is different from the one in which it is received and handle the necessary synchronisation for us - nice!
Submitted by rich on Tue, 10/20/2009 - 21:15
A feature that has been floating around in a few places but hasn't been a
significant feature in KDE is web slicing. This is the ability to take a piece
of a web page (commonly a div) and render it as a standalone object. It's
useful for stuff like putting a weather forcast on your desktop, watching new
comments on a forum etc. This weekend I made a start on implementing it as
tool for Project Silk.
The first version I wrote was pretty simple - it lets you specify the element
you want rendered, then presents it to the client application as a
QPixmap. This was fairly easy thanks to the new QWebElement API, the core of
the code is as simple as this:
QPixmap Slicer::renderElement( const QString &selector )
{
QWebFrame *frame = d->page->mainFrame();
d->page->setViewportSize( frame->contentsSize() );
QWebElement element = frame->findFirstElement( selector );
if ( element.isNull() )
return QPixmap();
QRect rect = element.geometry();
QPixmap result = QPixmap( rect.size() );
result.fill( Qt::white );
QPainter painter( &result );
painter.translate( -rect.x(), -rect.y() );
frame->render( &painter, QRegion(rect) );
return result;
}
This is enough to let you specify a CSS selector and render it to a pixmap
thanks to the nice API of QWebElement. Doing the same using the DOM API would
be simple enough, but a lot more verbose (and probably less flexible). The
code above was enough for me to make it trivial to write tools that present a
slice of a web page as part of their UI.
As ever in life, some people are never satisfied so a common response was
to ask if I could make it so the slice is interactive. This is a bit of a can of worms
as everyone has their own definition - eg. simply responding to requests from
the page to repaint could be trivially added to the code above and would offer
the same functionality as that I'm told MacOS offers. Rather than try the
half-way solution, I wrote a prototype that actually gives you a fully
interactive slice - eg. you can type into the form elements. It's not
production quality, but it proves the point. You can see the result below:

Around the point I got this working, Kenneth let me know that a commit had
just landed in QtWebkit that would make the earlier version even simpler -
there's now a render() method on QWebElement that does exactly the same thing
my original code did. This is great news, as that solution is the correct one
for a lot of use-cases.
Of course, by this time, I was quite tired but Sebas was still feeling
lively. The result is that 'live slice' code gained support for being embedded
in QGraphicsView overnight using the new QGraphicsWebView. There's a support
class that makes it available as a widget like before, but the implementation
is using this (new in 4.6) class. All in all this means we can nicely
integrate this functionality into apps using QGraphicsView like plasma or
amarok, and into QWidget based apps too.
All in all, a successful couple of days in the stealthy advance of project
silk.
Submitted by rich on Sun, 07/05/2009 - 13:07
One question I've seen come up several times on #qt and qt-interest is how to
add custom (application specific) APIs to those available by default in
QtWebKit. This is actually pretty easy (once you know how) as I'll show
below. This post will show a simple example of how to make an object available
from javascript, including calling methods on the object and returning values
from C++.
There are two things you really need to know in order to perform this
integration, the first is the addToJavaScriptWindowObject() method of
QWebFrame, this allows will make the specified QObject visible from
javascript. The second thing you need to know is that objects published in
this way will vanish each time the javascript window object is cleared -
ie. every time the user navigates to a new page. To prevent this from causing
problems, QWebFrame provides a signal that tells you whenever the object is
cleared allowing you to re-add your custom API. This is actually much simpler
than it sounds!
The core of this is really implemented in two methods in the example, they're
shown below:
void MyApi::setWebView( QWebView *view )
{
QWebPage *page = view->page();
frame = page->mainFrame();
attachObject();
connect( frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(attachObject()) );
}
void MyApi::attachObject()
{
frame->addToJavaScriptWindowObject( QString("MyApi"), this );
}
This code is all that you need in order to make all of the public slots of the
MyApi object visible to javascript. The MyApi class provides two public slots:
public slots:
void doSomething( const QString ¶m );
int doSums( int a, int b );
The first slot simply logs a message to the debug output, the second returns
the sum of its two arguments (yes, slots can return things!). They're called
from javascript like this:
MyApi.doSomething( 'Hello from JS page 2!!!!' );
sum = MyApi.doSums( 2, 3 );
alert( 'C++ says the sum is ' + sum );
And that's all there is to it! You can download the code from http://xmelegance.org/devel/qtwebkitextension.tar.gz.
Submitted by rich on Fri, 04/10/2009 - 17:40
People reading planet will have seen Thomas Zander's post about the new ItemViews framework the Trolls^H^H^HQt Software guys have been working on. It's very experimental right now, but I thought I'd have a quick look. I decided that a fun hack to write would be to take a standard listview that displays a list of URLs (boring!) and write a custom view that instead displays the rendered web page. I only spent a couple of hours on it, so the code is a hack (eg. you need to resize it to get the pages to display once they've loaded) but the results look ok. The whole code for this example comes in under 120 lines.

So, that's my hack in response to Thomas's challenge, who's next?
Here's an updated version that correctly updates the items when the page is loaded without requiring a resize.
And now version 3 that disables the scrollbars in the previews making things look a lot nicer.
Submitted by rich on Sun, 01/11/2009 - 12:42
I spent a little time yesterday working on a class that provides
a wrapper around the MediaWiki API. It makes quite a nice example
of how the QNetworkAccessManager API can be combined with
QXmlStreamReader to quickly access web services. The code, as you'll
see, is very simple.
First lets take a look at the constructor and the data members. We
specify the path to the api.php file of the wiki we want to query,
and setup the network access manager.
struct MediaWikiPrivate { QStringList results; QUrl apiUrl; QNetworkAccessManager *manager; int maxItems; };
MediaWiki::MediaWiki( QObject *parent ) : QObject( parent ) { d = new MediaWikiPrivate; d->apiUrl = QUrl("http://en.wikipedia.org/w/api.php"); d->manager = new QNetworkAccessManager( this ); d->maxItems = 10; connect( d->manager, SIGNAL(finished(QNetworkReply*)), SLOT(finished(QNetworkReply *)) ); }
People using the class can ask us to perform a search by calling
the search() method with the term they want to look for. Again,
the code is simple.
void MediaWiki::search( const QString &searchTerm ) { QUrl url = d->apiUrl; url.addQueryItem( QString("action"), QString("query") ); url.addQueryItem( QString("format"), QString("xml") ); url.addQueryItem( QString("list"), QString("search") ); url.addQueryItem( QString("srsearch"), searchTerm ); url.addQueryItem( QString("srlimit"), QString::number(d->maxItems) );
qDebug() << "Constructed search URL" << url;
d->manager->get( QNetworkRequest(url) ); }
We use the addQueryItem() method of QUrl to construct our search, by
specifying each of the options we need. Finally, we launch the request
by calling the get() method of QNetworkAccessManager.
Once the network request is completed, our finished() slot is called.
We check the status to see if the request succeeded then pass the
reply to the processSearchResult() method. Note that QNetworkReply
is a subclass of QIODevice which makes it very easy for us to work
with.
void MediaWiki::finished( QNetworkReply *reply ) { if ( reply->error() != QNetworkReply::NoError ) { qDebug() << "Request failed, " << reply->errorString(); emit finished(false); return; }
qDebug() << "Request succeeded"; bool ok = processSearchResult( reply ); emit finished( ok ); }
bool MediaWiki::processSearchResult( QIODevice *source ) { d->results.clear();
QXmlStreamReader reader( source ); while ( !reader.atEnd() ) { QXmlStreamReader::TokenType tokenType = reader.readNext(); // qDebug() << "Token" << int(tokenType); if ( tokenType == QXmlStreamReader::StartElement ) { if ( reader.name() == QString("p") ) { QXmlStreamAttributes attrs = reader.attributes(); //qDebug() << "Found page" << attrs.value( QString("title") ); d->results << attrs.value( QString("title") ).toString(); } } else if ( tokenType == QXmlStreamReader::Invalid ) return false; }
qDebug() << "Results" << d->results; return true; }
To parse the XML returned by the wiki, we use QXmlStreamReader. We're only
interested in elements that look like this:
<p ns="0" title="Qt (toolkit)" />
So we locate those when we see a StartElement token, then extract the title
attribute. Once this process is complete, we have a list of all the pages
matching the query and emit our finished() signal.
To test the code I've written a small wrapper that lets you enter a term,
then searches online when you press return. The code queries wikipedia right
now, but simply by changing the setApiUrl() call you can tell it to search
techbase. I've left that code in place but commented out so people can try it.
In future, this code could be used as a KRunner plugin, as part of an IDE,
or more generally anywhere else where someone wants to query a wiki in their
application. The full example can be downloaded from
http://xmelegance.org/devel/mediawiki/wikiviewer.tar.bz2. Enjoy.
Submitted by rich on Mon, 09/29/2008 - 20:59
Just watched a very clever advert for the new iphone.
- It's a manual, it shows you how to download (and buy) new apps.
- It's very short, just one feature
- User ends up having fun - playing game, and then call from a guy
- Interupting you in the middle of the game is presented as a feature!
- Slogan about this changing everything (not sure how it's supposed to do so)
The advert seems well put together, but I wonder if we couldn't create something similar regarding KDE features?
Submitted by rich on Thu, 08/14/2008 - 15:15
As you've seen from all the stores on the dot and on planetkde this week has seen all the KDE
developers gathering in Mechelen in Belgium. The organisation this year has
been excellent - even the network (usually the achilles heel of KDE
conferences) has worked from day one.
As well as the usual socialising, talks and BoF sessions there has also been a
lot of coding. I've focussed on ksnapshot and plasma, KSnapshot gained a few
minor changes:
- KSnapshot will now record the window title in the image if you've chosen
to capture the window decorations. Hopefully this should be useful to indexers
like strigi.
- I've fixed the 'not saving settings' bug - it looks like kdelibs changed
behaviour.
- I've increased the JPEG quality setting a little so screen shots look nicer.
- Tackat has persuaded me to look into writing a simple post processing app
so that you can easily apply effects like screenie before you upload your pics
to the dot.
The work on plasma was again to do with scripting, I first of all got the code
that was broken by the API changes fixed - this meant that the spinning
squares demo now works again. I then got the scripting support for the new
widget api working. You can see this in action in the screenshot below which
shows a calculator written in javascript using the plama widgets next to the
current C++ calculator.

This isn't quite ready to commit because the actual calculator logic is a bit
broken, but it shows that the widget support is nearly ready. In order to make
it easy to test this, I finished the implementation of package uninstalling in
plasma libs so that you can now use the plasmapkg tool to easily install and
remove scripted plasmoids.
I've done a little work on a few other things, but they're not quite ready
yet, so I'll save them for another post.
Submitted by rich on Mon, 04/14/2008 - 21:06
This is the draft design for a new widget API for plasma, it will be appearing on techbase later, but here's what we're thinking.
General Notes
The intention of this API is to provide a very simple way for users to create
plasma applets. The API can be used both for scripting and from C++. For the
simple javascript API, this API will be all that is provided allowing us to
run untrusted applets as they will not have access to any dangerous
facilities.
From C++ or more advanced scripting APIs (such as the 'full' Javascript
bindings) you can gain access to a pointer to the underlying Qt widget
contained within the QGraphicsProxy allowing you to access all of its
methods. For most simple uses however, this should be unnecessary as you can
do most of the customisation using the Qt stylesheet facilities.
All widgets have a stylesheet, which is a string property containing a Qt
stylesheet. This allows for simple but powerful configuration of the widgets -
for example you can configure the alignment of the text in the label using the
text-align property, or the font using the font property. Using this you can
do some extremely advanced interfaces without having to learn how Qt works.
A nice side effect of the way this API is defined is that it is possible to
implement the simple widget API inside a web browser using HTML, javascript
and HTML stylesheets to provide the implementation.
API Reference
Label
Constructors
Properties
- Widget parent
- String text
- String image
- String stylesheet
- QWidget nativeWidget
Note that the image property is a string and specifies the name of the
image within the plasmoid package. The image can be either a bitmap (in any
supported format) or an SVG image.
PushButton
Constructors
Properties
- Widget parent
- String text
- String image
- String stylesheet
- QWidget nativeWidget
Signals
CheckBox
Properties
- Widget parent
- String text
- String image
- String stylesheet
- bool checked
- QWidget nativeWidget
Signals
RadioButton
Properties
- Widget parent
- String text
- String image
- String stylesheet
- bool checked
- QWidget nativeWidget
Signals
Note that a RadioButton must exist within a ButtonGroup, the group box ensures
that only one radio button is set at any one time.
Widgets To Do
- WebContent
- GroupBox
- ButtonGroup
- ComboBox
- LineEdit
- TextEdit
- Meter
- Graph
- Throbber
- Simplified versions of the QGraphicsLayout classes
Non-Widgets To Do
Submitted by rich on Sat, 04/12/2008 - 08:17
After a day's work at the Plasma sprint, there's already quite a lot of news
to report. After a lot of trawling through log files, I was able to fix the
problem that was preventing the Plasma binding plugin from loading. In the end
it was something simple (as usual) namely that the method that allows the
plugin to load was not being compiled into the module since it was missing
from the generated .pri file. Once this was fixed, it was simply a matter of
changing the name of the extension we load from 'qt.plasma' to
'org.kde.plasma' to match a fix in the generator and we had a successfully
loading set of bindings.
Lots of thanks are due to Kent Hansen of Troll Tech
for this - not only did he write the binding generator and the type system for
the Qt bindings, he also fixed up the one for plasma. Oh, and if that wasn't
enough he's even figured out the bug that has been preventing the generated
code from having anti-aliasing enabled.
In order to test that these bindings worked properly, I wanted to create a
small demo that exercised the script engine code, the Qt bindings and the
plasma bindings in the same plasmoid. My initial attempt worked ok, but didn't
look very good (though it had the advantage of requiring only a tiny amount of
code). Instead, I'll show a slightly more complex example that looks prettier.

Obviously, you can't see the animation in the screenshot, but this shows four
squares spinning around a common axis at different speeds and changing
colour. Ok, it's not the best piece of graphic design you've ever seen but it
does illustrate that the crucial facilities are in place.
In addition to the coding, we also spent some time today going over the
results Seele obtained from her interviews with some of the developers. We
were looking at the user populations we are currently supporting well, but
more importantly at those that we could potentially encourage to adopt KDE and
Plasma to consider how we can improve the facilities we offer for them
too. Before anyone gets hot under the collar, this doesn't mean ripping out
functionality to 'dumb down' the interface, in fact a lot of the suggestions
were more about how we can improve the interface consistency.
Following this discussion we did some more coding and also broke down into
smaller groups so we could continue to plan for our inevitable world
domination.
Submitted by rich on Mon, 03/24/2008 - 13:43
As some of you may have seen, Kent has released the QtScript binding generator on Troll Tech labs. I've been playing with the code for a bit, and as with KJSEmbed one of the first tests was to make sure you could use it to write a simple web browser. Kent recently added support for QUiLoader to the bindings and as a result, I can use the QWebView designer plugin to make things simple. The result is a basic web browser in less than 10 lines of javascript:
var loader = new QUiLoader(null);
var file = new QFile("browser.ui");
file.open(QIODevice.OpenMode(QIODevice.ReadOnly, QIODevice.Text));
var web = loader.load(file,null);
web.show();
QCoreApplication.exec();
There's also a very simple designer ui file that just contains the web view and a layout. Here's the obligatory screenshot:

|