» tagged pages
» logout
Trolltech
Return to Trolltech

Trolltech Labs Blogs

(or Cancel)

(Editing anonymously: to be credited for your changes, login or register a new account)

other page actions:

Tags Applied to this Topic

1 person has tagged this page:

Trolltech Wiki Pages

Monday, July 07, 2008

Usage of the QFormLayout

Hi there. Introducing myself, my name is Friedemann Kleint, and I am one of the trolls hacking away at Qt Designer at the Berlin Office.

Today, I would like to draw your attention to the QFormLayout class. This is a special layout class suited to the common descriptive label - control arrangement found in many dialogs. It thas been developed in cooperation between Brisbane, Oslo and Berlin.

A typical form layout looks like this:

QFormLayout example 1

QFormLayout example 2

Note how the layout takes care of the label alignment according to the platform style. By the way, did you know that you can open several previews in different styles in Designer to compare them?

At first sight, QFormLayout looks like an ordinary grid. However, the layout also has policies for wrapping rows when it shrinks. For example, when setting the property rowWrapPolicy to WrapLongRows, we might get:

QFormLayout’s wrapping policy in effect

Let’s first have a look at the code. You might have created a such dialogs using QGridLayout, previously. This required some housekeeping of the current row. This is no longer necessary with QFormLayout using the addRow() convencience function. You don’t have to explicitly create the label, either:

QFormLayout *formLayout = new QFormLayout;
formLayout->addRow("Name", new QLineEdit);

For completeness, there is a setWidget() function which allows you to address single cells. It takes a row parameter and an ItemRole enumeration, which can be one of QFormLayout::LabelRole or QFormLayout::FieldRole.

In Qt Designer, you can create such arrangements as would in the case of a QGridLayout; you place the controls on a form and choose “Lay Out in a Form Layout”.

Hint: If you have existing .ui files containing such 2-column grid layouts and want to migrate them to the form layout, it might be sufficient to just replace the layout element <layout class="QGridLayout" name="gridLayout" ></layout> by something like <layout class="QFormLayout" name="formLayout" ></layout> (after making a backup copy, of course ;-) ).

It is also possible to create arrangements with controls that span the 2 columns. This let’s you add controls with long labels (for example QComboBox) or QGroupBox elements. It can also be used to partition the form layout into sections by using spanning QLabel elements:

A form layout arrangement with spanning labels

In code, you would use the addRow() overload that takes just one QWidget* parameter.

In the upcoming 4.5 release, this functionality will also be available in Designer. Lonesone widgets on a QFormLayout get an active left/right resize handle that let’s you change the span:

Changing the span of a QFormLayout element in Designer

The per-cell API of the QFormLayout uses the SpanningRole enumeration value of ItemRole to handle these rows.

Summarizing, the QFormLayout should be used whereever the typical descriptive label - control arrangement occurs. The dialog will then look correctly on a all platforms.

Saturday, July 05, 2008

Putting QtWebKit to use with Google Maps

Hi there. This is my first blog post, so I guess introductions are in order; My name is Henrik Hartz, and work as a Specialist with Product Management in Troll^W Qt Software. In Product Management I do all kinds of stuff, ranging from working with requirements, specifications, product releases, meeting customers, thinking about the future of Qt, the list goes on.. Recently I’ve had the pleasure of focusing on WebKit.

WebKit is a fantastic technology. Being able to stick web content into your application is simply amazing, there’s just about anything out there you can show! And, a lot of people know HTML, so making use of this to add content to your application enables you to (ab)use your Graphic Designer buddies.

But, WebKit is so much more than just a way to show HTML in your app. You can actually do anything a browser can - and much more! Experimenting with WebKit over the last couple of months I’ve made an example that a lot of people seem to be interested in; Using WebKit to host a Google Maps component.

I wanted to show where our offices are located in the world. So, I started with a simple QStandardItemModel that would read in addresses from a txt file. In the constructor, we read in the text file - using the first field of the comma separated line as the display role, and the rest as the address stored in the UserRole;

QStringList addressLines = address.split(",");

QStandardItem *item = new QStandardItem;
this->insertRow(this->rowCount(),item);

item->setData(addressLines.takeFirst(), Qt::DisplayRole);
item->setData(addressLines.join(",").trimmed(),Qt::UserRole);

With this model in place, we simply set it on the list view of our GUI design (yeah, I like using Qt Designer - it’s fast!);

ui.treeView->setModel(new AddressModel(this));

In the GUI we’ve also placed a web view, which is pointed to a web page under our control. This page shows a Google Maps control. So here is the GUI with the address list and QtWebKit component;

GUI design

This doesn’t do much on it’s own - so we promote the QWebView class to a custom component “Map”, defined by map.h in Qt Designer. This component has some additional services that allow us to update the map, specifically;

void geoCode(const QString &address);

What we want is to update the map based on the entries in the list view when they are clicked. We do this in a slot method connected to the clicked signal of my view. Here we can access the data of the item being clicked, extract the address and ask the map component to geo-code it;

void MainWindow::showItem(const QModelIndex &idx)
{
ui.map->geoCode( idx.data( Qt::UserRole).toString() );
}

The geoCode method will use QtWebKit’s capability of calling JavaScript functions in the web environment. Here we’ll use the Google Maps API to get Google to return a coordinate of the specified address in CSV format, using the asynchronous QNetworkAccessManager::get(const QNetworkRequest &amp;request) API;

void Map::geoCode(const QString &address)
{
QString requestStr( tr("http://maps.google.com/maps/geo?q=%1&amp;output=%2&amp;key=%3")
.arg(address)
.arg("csv")
.arg("GOOGLE_MAPS_KEY") );

manager->get( QNetworkRequest(requestStr) );
}

In another method connected to the QNetworkManager::finished(QNetworkReply*) signal, we parse out the coordinate returned in CSV format from Google, and pass it to a method which updates the map component appropriately;

void Map::loadCoordinates()
{
QStringList scriptStr;
scriptStr
< < "var map = new GMap2(document.getElementById(\"map\"));"
< < "var bounds = new GLatLngBounds;"
< < "var markers = [];"
< < "map.setCenter( new GLatLng(0,0),1 );";

int num=-1;
foreach( QPointF point, coordinates ) {
scriptStr < < QString("markers[%1] = new GMarker(new GLatLng(%2, %3));")
.arg(++num)
.arg(point.x())
.arg(point.y());
}

scriptStr
< < "for( var i=0; i<markers.length; ++i ) {"
< < " bounds.extend(markers[i].getPoint());"
< < " map.addOverlay(markers[i]);"
< < "}"
< < "map.setCenter(bounds.getCenter());";

this->page()->mainFrame()->evaluateJavaScript( scriptStr.join("\n") );
}

In the final call, we tell QtWebKit to evaluate the JavaScript we have synthesized, and the web view updates with the appropriate location;

Qt Software Address book

The snippets shown here are simplified to some extent, but you can find the complete source code here. Please remember to put the HTML for the map component on a server you control - and replace the GOOGLE_MAPS_KEY with your own key (you need to register and bind to a domain for it to work) in both map.cpp and index.html.

Enjoy!

Saturday, July 05, 2008

Let there be color

Time for another fresh example for the Graphics Dojo. This time I present a small tool that does nothing but showing the famous HSV cylinder. To give some realism, subtle blurred reflection is also added but can be easily disabled. Manual full-scene anti-aliasing is provided by the usual multisampling approach. Everything is done using pure QImage per-pixel manipulation along with some tricks, no OpenGL (or even its GLSL) is involved.

HSV Pie

For the code, check it out using:

svn checkout svn://labs.trolltech.com/svn/graphics/dojo/hsvpie

Note that the tool is not optimized for speed (evidenced by lots of setPixel() calls) so there is definitely room for improvement. Some possible further enhancements left as exercises for the readers are interactivity (mouse dragging to change e.g. the depth of the pie) and threaded rendering (so that the application remains responsive, just adapt the Mandelbrot example).

Have some dojo-fun!

Thursday, July 03, 2008

Putting QtWebKit to use with Google Maps

Hi there. This is my first blog post, so I guess introductions are in order; My name is Henrik Hartz, and work as a Specialist with Product Management in Troll^W Qt Software. In Product Management I do all kinds of stuff, ranging from working with requirements, specifications, product releases, meeting customers, thinking about the future of Qt, the list goes on.. Recently I’ve had the pleasure of focusing on WebKit.

WebKit is a fantastic technology. Being able to stick web content into your application is simply amazing, there’s just about anything out there you can show! And, a lot of people know HTML, so making use of this to add content to your application enables you to (ab)use your Graphic Designer buddies.

But, WebKit is so much more than just a way to show HTML in your app. You can actually do anything a browser can - and much more! Experimenting with WebKit over the last couple of months I’ve made an example that a lot of people seem to be interested in; Using WebKit to host a Google Maps component.

I wanted to show where our offices are located in the world. So, I started with a simple QStandardItemModel that would read in addresses from a txt file. In the constructor, we read in the text file - using the first field of the comma separated line as the display role, and the rest as the address stored in the UserRole;

QStringList addressLines = address.split(",");

QStandardItem *item = new QStandardItem;
this->insertRow(this->rowCount(),item);

item->setData(addressLines.takeFirst(), Qt::DisplayRole);
item->setData(addressLines.join(",").trimmed(),Qt::UserRole);

With this model in place, we simply set it on the list view of our GUI design (yeah, I like using Qt Designer - it’s fast!);

ui.treeView->setModel(new AddressModel(this));

In the GUI we’ve also placed a web view, which is pointed to a web page under our control. This page shows a Google Maps control. So here is the GUI with the address list and QtWebKit component;

GUI design

This doesn’t do much on it’s own - so we promote the QWebView class to a custom component “Map”, defined by map.h in Qt Designer. This component has some additional services that allow us to update the map, specifically;

void geoCode(const QString &address);

What we want is to update the map based on the entries in the list view when they are clicked. We do this in a slot method connected to the clicked signal of my view. Here we can access the data of the item being clicked, extract the address and ask the map component to geo-code it;

void MainWindow::showItem(const QModelIndex &idx)
{
ui.map->geoCode( idx.data( Qt::UserRole).toString() );
}

The geoCode method will use QtWebKit’s capability of calling JavaScript functions in the web environment. Here we’ll use the Google Maps API to get Google to return a coordinate of the specified address in CSV format, using the asynchronous QNetworkAccessManager::get(const QNetworkRequest &amp;request) API;

void Map::geoCode(const QString &address)
{
QString requestStr( tr("http://maps.google.com/maps/geo?q=%1&amp;output=%2&amp;key=%3")
.arg(address)
.arg("csv")
.arg("GOOGLE_MAPS_KEY") );

manager->get( QNetworkRequest(requestStr) );
}

In another method connected to the QNetworkManager::finished(QNetworkReply*) signal, we parse out the coordinate returned in CSV format from Google, and pass it to a method which updates the map component appropriately;

void Map::loadCoordinates()
{
QStringList scriptStr;
scriptStr
< < "var map = new GMap2(document.getElementById(\"map\"));"
< < "var bounds = new GLatLngBounds;"
< < "var markers = [];"
< < "map.setCenter( new GLatLng(0,0),1 );";

int num=-1;
foreach( QPointF point, coordinates ) {
scriptStr < < QString("markers[%1] = new GMarker(new GLatLng(%2, %3));")
.arg(++num)
.arg(point.x())
.arg(point.y());
}

scriptStr
< < "for( var i=0; i<markers.length; ++i ) {"
< < " bounds.extend(markers[i].getPoint());"
< < " map.addOverlay(markers[i]);"
< < "}"
< < "map.setCenter(bounds.getCenter());";

this->page()->mainFrame()->evaluateJavaScript( scriptStr.join("\n") );
}

In the final call, we tell QtWebKit to evaluate the JavaScript we have synthesized, and the web view updates with the appropriate location;

Qt Software Address book

The snippets shown here are simplified to some extent, but you can find the complete source code here. Please remember to put the HTML for the map component on a server you control - and replace the GOOGLE_MAPS_KEY with your own key (you need to register and bind to a domain for it to work) in both map.cpp and index.html.

Enjoy!

Wednesday, July 02, 2008

Some QTabBar & QTabWidget love

After 4.4.0 was out I set aside some time to go though the feature requests for QTabBar & QTabWidget. After making a list of the most voted for suggestions I have implemented some features that will be in 4.5.0 that should make some developers happy.

In the past ten years the tab widget has gone from being something you see in a settings dialog to the widget that is the central widget of QMainWindow for many applications. Trying to use QTabWidget in the main window as it is in 4.4.0 has a number of shortcomings. One big issue is that if you maximize your application and move your mouse to the far right and try to scroll it wont because the mouse is actually over the 2px frame and not the scrollbar. I present for your enjoyment QTabWidget::documentMode which will only put the frame on the top with the tabs. Another very annoying problem for QTabWidget was that if you wanted to add a context menu or handle any event in the tab bar area you had to subclass both QTabBar and QTabWidget because the empty area was actually owned by QTabWidget and the tab bar widget was only as big as the tabs. Document mode will cause the tab bar widget to take up the entire space above the tab widget which will simplify a lot of code.

Looking around at what features people have implemented in their subclasses of QTabBar many have added some sort of hack to be able to either put a widget on a tab or the ability to paint a button. Doing this right, QTabBar now has a function QTabBar::setTabButton to let you put a widget on the left or right hand side of each tab. Taking this one step further there is also a convenience property
QTabBar::tabsClosable that when enabled will automatically add a close button to each tab. The close button it painted by the style using PE_IndicatorTabClose. When the close button is pressed the signal tabCloseRequested is emitted. Note that the location of the close button is also determined by the style so you can not guarantee that it will always be on the right hand side and the side with the close button should be determined by a call to the style with SH_TabBar_CloseButtonPosition. Custom styles that paint tabs themselves needs to be updated to take into account the space needed for buttons (see QStyleOptionTabV3).

When a tab is closed rather then always selecting the tab to the right there is now a
QTabBar::selectionBehaviorOnRemove property to decide which tab should be selected. The three included values are left, right and the last selected tab.

Another highly requested feature is support for the ability to move tabs. There is even a number of patches floating around out there that add many different moving schemes. A moveTab function was added, but taking it to the next level the property movable has been added which lets you drag the tabs around and as you pass over tabs they slide to their new position (i.e. animated sexiness).

Because animations are hard to describe I made a short video. In the video I first add a QTabWidget to a QMainWindow, turn on document mode, closeable tabs, and the moveable property. Then I preview it in plastique and drag around a few tabs. I start out using cleanlooks so it picks up the Gtk close button and then in plastique you can see it using the default button.

Lastly for applications running in OS X when using document mode the style paints the entire tab bar to match those tabbed applications like Safari and Terminal that are found on OS X. Below is a screenshots of a QTabWidget in a QMainWindow with a QWebView. With OS X it is very clear that the tab widget now goes to the edge of the screen.

osxstyletabbar.png

Hope you all enjoy it. Some of the patches are already in Qt main, but you can find all of these in tonight’s snapshots. Let me know if you notice any issues with the new features.

Saturday, June 28, 2008

Bloom effect

If you play games like Rainbox Six: Vegas or watch movies like Elephant Dream, you will notice the use of the so-called Bloom effect. In fact, Vegas is so bright and surrealist that this game becomes known for its Bloom overuse.

In this Graphics Dojo example, I would like to show how to render an image with the Bloom effect. This extends the previous example from Zack on making real-time glow effect. The technique: create a copy of the image, blur it, increase its brightness and then combine with the original image with a certain composition mode and opacity. Since a picture is worth a 2^10 words, I will let the following screenshot (click to enlarge) speaks for itself.

Bloom effect with Qt

The image on the left side is the original, whereas the right one shows the result of applying Bloom. As you can see, there are few sliders where you can tweak the parameter to achieve the effect that suits your taste. Different composition modes can give (not so radically) different results as well, just play around with it.

How to get it? Just do “svn checkout svn://labs.trolltech.com/svn/graphics/dojo/bloom” followed by the usual “cd bloom && qmake && make && ./bloom”. Once the main window shows up, you can also change the image by using drag-and-drop from a file on your disk or even a link from the web browser (e.g. straight from your Flickr gallery). Have fun!

Friday, June 27, 2008

Accelerate your widgets with OpenGL

To breathe some new life into the graphics dojo, here’s an example of how to put widgets on top of an OpenGL scene using QGraphicsView. By leveraging the synergy (tounge in cheek) of the OpenGL module and graphics view’s in 4.4 new widget capabilities, the long lacking feature of putting widgets in OpenGL becomes possible. All that’s needed is to set a QGLWidget as viewport on the graphics view, override QGraphicsScene::drawBackground() to do the OpenGL rendering, and add widgets and other graphics items to the graphics scene as usual. The result can be seen in the screenshot below, which shows a simple obj-model viewer application written in just a couple of hundred lines of code:

Widgets on top of an OpenGL scene

The source code is available by “svn checkout svn://labs.trolltech.com/svn/graphics/dojo/modelviewer”. Have fun!

Friday, June 27, 2008

it’s official

In case you missed it, it is now official
Trolltech merges with Nokia

But do not be scared, my open source friends. This means that Qt and Qtopia will continue to be developed, and have even wider recognition that it is the greatest cross platform GUI toolkit on the planet.

More info here

I am sure there will be more press releases coming soon, so I won’t comment on anything else that might happen. But I can say this, this merger is a two way street. i.e. Nokia wants to learn from Trolltech and Trolltech can learn from Nokia.

What I wonder, is if Nokia can make a rubber boot for my phone. After all, it has been fairly rainy here in Brisbane this year.

Remember, “Trolltech has benefited greatly from the feedback the community has been providing while using Qt to develop free software. We respect the symbiotic relationship Qt has with the community and we wish to continue and enhance this relationship.”

So, keep on hackin’ Qt, Qtopia and Kde hackers, there’s good things around the corner!!

Friday, June 27, 2008

Flying High in the Friendly Skies

It’s time to pack up and go to WWDC again. This will be my 5th visit to Moscone West and I’m hoping for a bit more of a “relaxing” time than last year. We’ll see how it goes -)

One of the fun things though is to meet the various Qt users out there and see what they are doing. Don’t be afraid to come up and say “Hi.” Feel free to ask for my business card as well. Since it’s the last time I’ll be representing Trolltech at WWDC before we become Nokia, these business cards are sure to become collector’s items. Plus it’s a better fate then me just tossing them all in the recycling bin.

Also bring all your questions and concerns about the Cocoa port, it’ll be a great time to discuss things.

Hope to see you there!

Friday, June 27, 2008

Second Cocoa Alpha Released

Well, just in time for WWDC, we have decided to put another alpha release of Cocoa out today. Even though we have had snapshots available for a while and we still are a long way from being complete, we thought it might be nice to let others give it a shot. In addition we also are providing a 64-bit binary version, we would have had 32-bit in as well, but ran into an issue when building, so there is only 64-bit available. These will replace any other Qt binary package, so handle with care.

Here’s what I can remember that has changed since the last alpha:

  • QWidget::setMask() works
  • Drag and drop now works
  • support for sheets and drawers
  • A new way of working with dialogs (QDialog::open()) that makes it easier to make
    window-modal dialogs (sheets) on all platforms, specialized versions available for
    QFileDialog, QColorDialog, and QFontDialog.
  • Contains changes that are part of Qt 4.4.0.
  • QTKit backend for Phonon (partial support).
  • Tablet support
  • Preliminary support for unified toolbars.
  • The package should build in run and both 32- and 64-bit.
  • Fixes for mouse event handling and popups
  • Fixes for positioning windows on screen

What’s not working and we are aware of them (some of these are still from the last alpha, but weren’t mentioned then, but they are still broken). Most we plan on fixing (or in the case of NSApplication, minimizing chances of that happening).

  • Widgets that use QFocusFrame for displaying the focus halo will not be “clickable,” but you can still interact with them with the keyboard. This includes widgets like QLineEdit, QTreeView, QSpinBox, etc. If you need to test things, you can temporarily set the Qt::WA_MacShowFocusRect attribute
  • Networking
  • Accessibility
  • Input Methods
  • Most keyboard shortcuts do not work
  • Designer will not run with all its plugins, even with plugins removed, it will not work properly. Please use a released version of Designer to edit your forms.
  • Widgets that contain a QFontComboBox will currently take a long time to show the first time.
  • We are using a NSApplication subclass for tablet events and a NSApplication delegate for handling some events. If combining this with an application that already has an NSApplication subclass, you will not get all tablet proximity events, if you are using an NSApplication delegate, Qt will not be able to use its delegate and some events like window activates may not be delivered as QEvents.

So, in between all the other Mac-related buzz, don’t be (too) afraid to give this alpha a download and see how it goes.

Friday, June 27, 2008

Qt Jambi 4.4.0 Released!

So the time is finally here. Qt 4.4.0 was released a few weeks ago and as promised Qt Jambi is right behind. A lot of effort has gone into this one, in addition to supporting all the new Qt features, like Phonon, Webkit, Widgets in Graphics View, XQuery and Qt Concurrent, we also have a seriously improved deployment system, JDBC support and a compile-time checked signal-slot approach for the paranoid. Its a good time to be a Java developer I tell yah! We already mentioned all the featuers in the Qt Jambi 4.4.0 Preview Blog so we won’t repeat ourselves here… (There is a danger in linking to eskils blog, as it links to others again, which again links to others, which in the end proves to be a fairly complex graph, but then again… we are engineers and like that kind of stuff)

Under the cover we’ve also done quite some work. We also did an overhaul of the garbage collection and memory management subsystem and hopefully ironed out all the bumps and dents. We’ve also done some work on the build system, so that our users that build from source have a bit more substantial buildsystem to work with. Previously it was a complex install document, which has been replaced by a simple ant command which just does it all… I was very happy to see that the deployment system & ANT build scripts works well enough for the webstart to look like a plain, normal webstart app:

<resources>
<j2se version="1.5+"/>
<jar href="qtjambi-examples-4.4.0_01.jar"/>
<jar href="qtjambi-4.4.0_01.jar"/>
</resources>

<resources os="Windows" arch="x86">
<j2se version="1.5+"/>
<jar href="qtjambi-win32-msvc2005-4.4.0_01.jar"/>
</resources>

No magic nativejar or anything like that, just the qtjambi-win32-msvc2005-4.4.0_01.jar in the classpath and that is enough to load it, jpeg and svg plugins and all. The good thing is that the files included in the webstart are produced directly by the ant script with all dependencies etc set up properly… (well… almost properly, it took us an evening last week to get it really working, but now it works properly). Because of the fixes to memory management and deployment Eskil and I got these offical diplomas:

Absolutely last load issue fixed and Last memory managment bug

So, what more is there to say… Try the webstart with its new demos, download the packages and start hacking!

-
The Qt Jambi Team

Friday, June 27, 2008

Testing typography

As many of you know, I’m an OpenDocument fan, I love working on making KOffice rock, which is something I do at every opportunity. The work I do is mostly outside of the KOffice repository nowadays and others are picking up the slack. One really cool development is that I found some people willing to put some corporate funding into making our ODF compliance rock!

If you want to write some software and you want to maintain it for various years the best way to do this is to have regular testing in place to ensure that with further development the features you released in a previous release didn’t break. This is a common practice and the quality of your release is directly linked to the amount of testing you do. In the open source world the many users tend to work as testers, which is a concept that generally works pretty well. A much better solution is to have auto-tests. This is basically a program that does a certain task and checks the outcome for the expected values.

In KOffice we are working on improving out ODF compliance by first writing a test, and then making sure that the feature gets implemented. Before committing all tests ever written are ran and only when all of them (still) pass we can say the new feature is done. It should become obvious to anyone reading this that writing new software like this will create better software that is easier to maintain over time. Especially in open source where new people come and go on a regular basis.

I’m therefor extremely happy to report that Girish Ramakrishnan has so far created and made passing 51 61 OpenDocument Format loading tests. This in effect means we have lots of ODF features we researched what they should do (by reading the ISO specification) and then make sure we actually do that. Now and years from now they will do what they are meant to do.

The features we are testing are, for example, lists. That a document that is meant to have a numbered list with any sort of complex numbering load and show correctly. But sometimes we have some quite different test, things that KOffice never did before. In that case new features have to be added to KOffice. One such feature is the dropcaps. This is a feature that people that write newspaper style documents will love. Let me show a screenshot which explains it best. )

For this new feature we have yet to add some dialogs to configure this, so to try it out I started OOo and loaded the odt doc in KWord. Which I admit is a pretty cool way to show how far we have come in the interoperability area D

Update; updated number of passing tests.

Friday, June 27, 2008

bye bye Trolltech…

Well,
This is my last post as a Trolltech employee. I have worked for Trolltech Pty Ltd, in Australia. since 2003. I can proudly say I helped Qtopia become more open, and fully GPL. It’s been a short 5 or so years, I have seen the Brisbane office grow from around 14 people to around 50, found my wife, had a son and daughter. A lot has happened in the past years. Ran ‘make’ more times that I want to think about. Got Qtopia running on all the devices I could. Yelled and complained and praised till I was blue in the face.

Tomorrow (Tuesday), I will be employed by Nokia, doing the same things I did today (well, maybe the day after next, tomorrow is the obigitory write-off “1st day”, BBQ and beer drinking).

It will be a challenging year ahead, I am sure both Nokia and Trolltech ^H^H^H^H^H^H^H^H Qt Software have things to learn from one another. I am personally wishing Trolltech’s seeds of open source will blossom Nokia into a greater thing.

So tonight, while I am unemployed, am going to live it up! and… uh… well… write some code (having small kids really saps your energy) and get more familiar with scratchbox2. (which thankfully uses a real cross toolchain).

I feel it is a bit like Christmas… So, if you talk to a Troll today, shake his/her hand and tell him/her thanks for making the world a more peaceful place.

Friday, June 27, 2008

hello Nokia!

New Nokia Sign

Well,
I start work for a different company today, namely Nokia. Perhaps you have heard of them? No? Well, they used to make rubber boots but now make phones. Lot’s of them. They have a few employees. Lot’s of them. and now, a few more, thanks to the (more or less) peaceful assimilation of Trolltech.

Am I worried? A bit. The management structure at Nokia is overbearing, not like Trolltech’s lean and mean machine. I doubt I will see the CEO of Nokia getting drunk and wrestling with engineers any time soon. I doubt I will ever be called to a meeting with him to pick my brain about community matters, much less even get an email from him. I liked that about Trolltech. The openness, the friendliness.
Hopefully my boss will stop wearing his shoes so much. He used to go barefoot a lot more than he does now. I liked that about him.

Today, I start work for Nokia, sitting in the same desk (I hope), loging into the same machines (I hope), and continuing my work from yesterday (except today is the BBQ beer fest.. wweeeeeeeeeee!), on the Qtopia SDK, on the n8×0 and Neo devices. I still get to work with the greatest multi licensed cross platform toolkit ever - Qt. I get to use the greatest and Kool Desktop Environment - blackboxqt! heh and also - KDE.

Best of all - I get a new phone and some Nokia schwag.

I, for one, welcome our new Nokia overlords!

Friday, June 27, 2008

Introducing doxygen2qthelp: Create .qch files from Doxygen. Finally.

Intro

Hello! I have something to show you. I’ve been working on a tool that teams up with Doxygen to produce .qch files (Qt Compressed Help) for use with Qt Assistant from your code documentation - a feature that has been asked for repeatedly since 2003 ([1][2][3]..). In this post I will introduce doxygen2qthelp, the answer to your request.

Download

You can grab the current code from our Subversion repository like this:

$ svn co svn://labs.trolltech.com/svn/documentation/doxygen2qthelp

Building

I should mention doxygen2qthelp requires a Qt version later than 4.4.0, which at the moment means a snapshot of 2008-04-24 or later.

Background

Doxygen has been able to produce .chm files (Compressed HTML) from properly documented code. To be precise Doxygen does not create the .chm files itself: instead it produces a bunch of files that are used to instruct the Microsoft® HTML Help Compiler (hhc.exe). These three files contain the table of contens (file index.hhc), the list of keywords appearing in the index (file index.hhk), and a project description (file index.hhp). The former two of these are written in some form of "perverted HTML". What doxygen2qthelp does: take these files, parse through the soup, and create a ready-to-go .qch file for viewing in Qt Assistant. Alternatively, a fine-control .qhp file (Qt Help Project) can be produced.

Usage

Let’s say you were the author of the QWT library and you felt like shipping .qch files of your documentation. What would you do? Let’s first look at a manual approach, and see what we can automate after.

  1. Enable Microsoft® HTML Help output
    First you need to tell Doxygen to generate HTML Help output. To do that you enable GENERATE_HTMLHELP

    GENERATE_HTMLHELP = YES

    in the Doxyfile. Without HHC_LOCATION being set Doxygen will just produced the index.hh* files and not try to call the Help Compiler from Microsoft®. That’s just how we like it, especially on our Linux Machine.

  2. Run Doxygen
    If everything went smoothly we should have both HTML documentation and the index.hh* in doc/html/ .
  3. Run doxygen2qthelp
    Now doxygen2qthelp comes into play. Invoke it from the QWT source folder like this:

    $ doxygen2qthelp --namespace=net.sourceforge.qwt --folder=qwt-5.0.2 doc/html/index.hhp qwt-5.0.2-doc.qch

    Alternatively you could also write this calls information into an .ini file and invoke it like this:

    $ doxygen2qthelp --config qwt.ini

    -- qwt.ini --
    Namespace = net.sourceforge.qwt
    VirtualFolder = qwt-5.0.2
    InputFilename = doc/html/index.hhp
    OutputFilename = qwt-5.0.2-doc.qch

  4. Enjoy
    Open the documentation in Qt Assistant, preferrably a version from Qt 4.4.0 or later configured to use Webkit in Assistant (./configure -assistant-webkit). Without Webkit parts of the Doxygen HTML will look quite messy.

Automation

Wouldn’t it be cool if we could teach Doxygen to call doxygen2qthelp for us? Good news: I wrote a patch against Doxygen 1.5.6 for you (see doxygen_patch folder). Dimitri van Heesch and I planned to integrate that patch upstream for one of the next Doxygen releases.

  1. Apply the patch and rebuild Doxygen
  2. Add a few lines to the Doxyfile:
    ## Paths Relative to the 'html' folder!
    GENERATE_HTMLHELP = YES
    DOXYGEN2QTHELP_LOCATION = doxygen2qthelp
    QTHELP_CONFIG = ../qwt.ini
    QTHELP_FILE = ../qwt-5.0.2-doc.qch
  3. Run Doxygen

That’s it - a single call to Doxygen can now produce .qch files.

Final words

Please report any bugs you might find through the Trolltech Bug tracker. Feedback is also welcome. Thank you!

Friday, June 27, 2008

QtWebKit and Gutenbrowser

After many moons, I have started to work again on my personal project, Gutenbrowser. It is in need of much maintenance and love.

Since Qt finally has a good webview, QWebView, I can finally start working towards version 1.0! With very little work, gutenbrowser can now show Gutenberg Project etexts that come with images.

Since I have a macmini at home, I can distribute Mac binaries, as well as Windows and a few Linux embedded devices (Openmoko Neo and possibly Nokia’s n8×0’s Qtopia )
and with the help of Petter Reinholdtsen, fix a few bugs and be in the standard Debian distribution.

For those that do not know of the Gutenberg Project, there are over 25,000 free books available!

Friday, June 27, 2008

Wide Finding

The Wide Finder Project is an informal parallel programming competition where the task is to compute web site statistcs from a 218-million line access log. Each entry will be benchmarked on a Sun T2000 with support for 32 hardware threads, giving lots of opportunities for parallel processing.

What makes this really interesting is that the project is not only about performance, but rather about writing code that scales to many CPU cores with as little extra programmer effort as possible. Some results are already in, with OCaml currently in the lead performance-wise.

Each log line looks something like this:

www.example.com - - [17/Jun/2007:21:37:17 -0700] “GET /ongoing/ongoing.atom HTTP/1.1″ 304 - - “-” “Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4

Eager to bring the performance lead back to C++ where it belongs I started out writing my own implementation using QtConcurrent and the other Qt APIs. Briefly explained, the code uses QtConcurrent::mappedReduced to multi-thread the code, and then QByteArray::split() twice to iterate over each word in each line. The current version computes the number of hits for each page.

Results: (parsing 100K lines on an 8-core 2.8 GHz Mac Pro)

1 Thread
real 0m2.283s
user 0m1.141s
sys 0m0.249s

2 Threads:
real 0m1.446s
user 0m1.853s
sys 0m0.271s

1.6X speedup.. not too bad.

4 Threads:
real 0m3.186s
user 0m10.643s
sys 0m0.407s

1 second slower that the single-threaded version.. this does not bode well.

8 Threads:
real 0m7.000s
user 0m46.922s
sys 0m0.724s

Seven seconds! We get a nice linear scaling of the run-time as we increase the number of threads, but unfortunately in the wrong direction. The program us spending a lot of user time doing something though, so let’s run it through Shark and see what’s going on:

spinlock.png

80% in a spin-lock used by malloc/free. But who is calling malloc that much?

spinlock-split.png

Aha.. QByteArray::split(). While being a very convenient API, split() was clearly not designed for heavy parsing like this. Still, I’d like a less catastrophic impact on the run-time when adding threads, even if the program really is calling malloc/free to often. Let’s try with the ptmalloc memory allocator instead:

8 Threads:
real 0m0.908s
user 0m3.784s
sys 0m0.533s

ptmalloc is used in GNU/Linux though the GNU C library and scales much better on multicore systems. The program itself still does not scale beyond 4 threads, but it does not get significantly worse either when adding threads. I guess it’s debatable whether or not this is qualifies as a bug in the Darwin memory allocator, but at least ptmalloc shows that it is possible to do better.

That’s all for now ) For the next installment I’ll try to get better scaling, at the expense of increasing the developer effort.

Monday, June 02, 2008

Bringing Web Inspector to Linux

For web developers, when it comes to debugging the web applications, tools like Firebug for Firefox, Safari Web Inspector and the recently introduced Opera Dragonfly can be handy and very useful. These kinds of tools offers the possibility to trace the DOM, verify the corresponding (computed) CSS, check network usage and resource loading performance, debug JavaScript, etc.

As for the Web Inspector (which is technically a WebKit feature), it is written in HTML/CSS/JavaScript except for the rather small platform-specific InspectorClient code. As Holger has mentioned before, with QtWebKit it is very easy to bring WebInspector into any QtWebKit-based browser, such as the Demo Browser (shipped with Qt 4.4) or its successor Arora. Since these browsers are available on several platforms, it also means now you can use Web Inspector on Linux (*). Using either the Demo Browser or Arora, just open the menu Tools, Enable Web Inspector and you are ready. After loading any web site, right click on the web page to find the menu item Inspect that will launch the Web Inspector.

The screenshot below gives the unsurprising proof of Web Inspector on Linux (click to enlarge):

Web Inspector on Linux

In the example, I was trying to find out the potential slow-down in SpeedCrunch website. It was easy to spot that the Slideshow JavaScript (slideshow.js) takes around 200 ms. If this particular JavaScript code can be deferred, the web page would have been 200 ms faster.

What about other WebKit-based application? If your application is using QtWebKit, it is almost trivial to enable the Web Inspector. You can use the action available from QWebView::pageAction or trigger it directly using QWebView::triggerPageAction, in both cases passing QWebPage::InspectElement as the action. Easy enough, isn’t it?

Happy inspecting!

(*) Before, it is only possible if you run Safari under Wine

Friday, May 30, 2008

Decoration items, light and shadow effects

I’m studying how we can add light and shadow to widgets and items. I want to hear what you think :-). So I’ll just throw out my ideas and see what happens.

Light and shadow are special effects that follow and decorate items, and affect how they are rendered, at the same time as they’re a bit different from regular items / subitems, or subwidgets. For both light and shadow effects, there’s sometimes a need to render outside the item’s boundaries and blend into surroundings. For widgets, we then need to do something to break out of the box model… to make that happen. For inside-widget light effects, we’re limited to what we can do inside paintEvent() or inside the paint() function. I don’t know about you, but I think both light and shadow effects should be primary citizens of the scene graph, which essentially means they are also items. Stack-above / always-on-top (overlays) or stack-below / always-below items (underlays?).

Here’s a flash video showing a sample of what I’m working on. This is based on Graphics View.

The scene consists of 150 elliptoid items with shadows, and one light source that’s flying over it. It’s a bit psychedelic; anyone who loves colliding mice will love this. ;-) Haha.

Let’s start with shadows. In 2D, shadows can be pretty simple. Shadows can be thought of as transformed filled outlines of an object with a dark semitransparent fill and possibly fuzzy/blurred edges, stacked below the object itself. It has an offset, and/or an angle. The offset can be fixed for all items, or relative to one or more light sources. Ideally two shadows on top of each other don’t make a darker shadow, rather they blend with each other along the edges. Exact shadows are expensive to do accurately, and in many cases they’re completely pointless because they’re hard to see in the first place; at least the types of shadows we foresee being used in 2D / 2.5D UIs… Extreme shadows are cool but useless, subtle shadows, however, to me, are/can be beautiful. There seems to be a “market” for simple stupid fast shadows (e.g., bounding rect / bounding region based), pretty good medium-speed shadows (e.g., shape based), and custom shadows. And possibly perfect shadows (e.g., based on paint()) but I don’t really think that market is very big :-)).

As for how shadows are stacked, the easiest way is to just say that an item with a shadow always renders the shadow before itself. This works fine for most cases. But as soon as sibling items come close, and one’s shadow renders on top of the other, it starts looking wrong.

Sibling Shadows 1 Sibling Shadows 2
Take 1: Sibling shadow overlaps Take 2: Sibling shadows behind both

It would be nice if I could set a shadow on our favorite “Drag And Drop Robot” without having lower leg shadows cast on the upper legs, or a shadow from the left leg draw on top of the right leg. I can see the need for both, but what would the API look like? And how would the items be stacked? My solution right now is to add a special flag to QGraphicsItem called QGraphicsItem::ItemStacksBehindParent (the child and its children are behind the parent), which is certainly one step on the way.

The other thing is how the shadow is placed. I don’t know about you, but I hate it how some presentation tools rotate the shadow relative to the item when you rotate and item that has a shadow on it. A picture says more than a thousand words:

Shadow follows item transform Shadow transform relative to scene
No -( Shadow follows item. Yes! Shadow follows scene :-)).

It’s a bit complicated though because you want the shadow to follow the item, but you wants its offset to be done scene-relative. Turns out it’s just that the item’s local transform is prepended to instead of appended to the parent item’s scene transform. So I added a flag for that: QGraphicsItem::ItemBeforeSceneTransform. Btw this is just research, it’s not in Qt snapshots or anything.

Now light effects come in many different shapes and colors. Light can affect shadows, or it can just add a glow to an item. Light is typically represented by an abstract member of the scene, to which you can calculate distance and angle and apply a suitable effect to your item, or the background, and so on. In styling, we usually fake light big-time by just applying light and dark effects to our button bevels, or use pixmaps that look shiny and sparkly. Which, of course, is in many cases much faster than doing “correct lighting”. I recall once Zack Rusin and I were talking crap, I don’t know who brought it up but if the whole UI was a complex detailed 3D scene graph, lighting could come by itself (I think the discussion started with why buttons in RTL mode don’t have shadows cast as if the sun shine from the upper right).

For blend effects it’s also necessary to apply aftereffects that combine the source and destination. That can be done in two ways - either just via an offscreen buffer, or directly onto the destination device / framebuffer / or so. If we want blend effects I think we need some type of shader integration. Let’s not digress though.

So, ball in your court. What are your thoughts about light and shadow?

Thursday, May 29, 2008

Qt 4.3.5: Two steps back and one step forward

Earlier this month, we released the single, largest release of Qt since the 4.0.0 release two years ago. Qt 4.4.0 is the result of 10 months of hard work by the Trolls, including numerous distractions. And while it’s being digested by our clients and users, we’re working on Qt 4.4.1, which will include fixes for bugs that were already known at the time of the 4.4.0 release, as well as some that people have reported.

In the meantime, we take two steps back, to the 4.3.x series, and then one step forward: we’re releasing today Qt version 4.3.5. This release is meant for those who cannot upgrade to Qt 4.4.0 yet, but need fixes for some important issues. All of the changes done for 4.3.5 will be present in 4.4.1 and some are even part of 4.4.0 already.

This is the first time ever we’re doing a public release of the previous minor series. In the past, we’ve always stopped development of the previous minor series when the next one came out. Sure, we’ve done security fixes when needed and Trolltech Support continued to support clients using them, but we’ve never made a public release. So this is news for us too. -)

One of the main reasons that made us decide to release 4.3.5 was the sheer size of the 4.4.0 upgrade. Many customers are scared to take the leap. Not that 4.4.0 is a bad release — no, far from it, all indications so far are that it is a great release. (At least, the Trolltech head of Support hasn’t tried to kill me yet for it!) But nonetheless, we decided we would reassert our commitment to all clients and users despite all distractions, by providing them with one more 4.3 release.

If this proves to be a good thing, we may repeat it for the 4.4.x branch when Qt 4.5.0 is released, although we’re not expecting anything as groundbreaking for that release as 4.4.0 was. We also have two or three bugfixes up our sleeves in the 4.3 branch, which may lead to a 4.3.6 release if necessary.

Including the pictures of the Qt developer team again, since a few more people have been patched in.

Oslo team Berlin team
Oslo team Berlin team
Page 1 | Next >>
Username:
Password:
(or Cancel)