Kent
Qt
Labs
Posted by Kent
 in Qt, Labs
 on Friday, January 30, 2009 @ 18:05

Hopefully there won’t be a public outcry when I claim that most Qt applications can be described as “a set of objects that interact with eachother over a period of time”. It’s the job of Qt to provide APIs that support this process. Today I’d like to focus on the “over a period of time” part.

Whereas class diagrams describe structure, state diagrams describe behavior. This is what a state diagram for a simple checkbox might look like:

In an object-oriented language like C++, there’s usually a one-to-one mapping between the elements of a class diagram and the code — classes are a fundamental part of the language, after all. With state diagrams there isn’t any such direct correspondence, though; they’re foreign tongue.

For “trivial” things (like a checkbox) you can quickly code something that works, of course, without using any concepts from state diagrams directly. However, because of the nature of event-driven programs (most Qt applications are), it’s very easy to end up with a bunch of if- and switch-statements that try to determine what the application should do at each point. Because the state of the application is implicit (just a bunch of variables), it soon gets difficult to understand what’s going on, which cases you’ve covered and which you haven’t. And don’t ever try to change or add something because that’ll just break everything.

The alternative to the ad hoc implementations of state machines described above is to rely on a framework to help you out. To this end, we’re working on a State Machine Framework that makes Qt speak the language of state diagrams; it lets you construct state graphs and execute them. The goal is to enable applications to have a cleaner separation between control flow and actual useful work. It’s pretty much an event loop with a control flow mechanism on top.

The framework integrates deeply with Qt’s event system, signals and slots, and property system. By making it a core technology in Qt, the threshold for starting to use it should be very low, so that as many applications as possible can benefit from it. Inside Qt this framework is being used in conjunction with the new Animations Framework to provide animated transitions. Since the State Machine framework implements the algorithm defined by SCXML, we also aim to make it the backend of Qt SCXML.

OK, time to implement our first state machine. Consider the following state diagram:

Every time the button button is clicked, the state machine transitions to another state, and button’s text property is changed to reflect which state the machine is now in. Here’s how it can be implemented using the Qt State Machine API:

#include <QtGui>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QPushButton button;

    QStateMachine machine;

    QState *s1 = new QState(machine.rootState());
    s1->setPropertyOnEntry(&button, “text”, “In s1″);

    QState *s2 = new QState(machine.rootState());
    s2->setPropertyOnEntry(&button, “text”, “In s2″);

    QState *s3 = new QState(machine.rootState());
    s3->setPropertyOnEntry(&button, “text”, “In s3″);

    s1->addTransition(&button, SIGNAL(clicked()), s2);
    s2->addTransition(&button, SIGNAL(clicked()), s3);
    s3->addTransition(&button, SIGNAL(clicked()), s1);

    button.resize(200, 200);
    button.show();

    machine.setInitialState(s1);
    machine.start();

    return app.exec();
}

You can have a slot get called whenever a state is entered; or you can subclass Q(Abstract)State and do whatever you like. There’s a mechanism for having transitions based on events (e.g. mousePress). You can have composite (nested) states, parallel states… It’s pretty powerful stuff. Oh yeah, in case I forgot to mention, I’m pretty excited about this! :D If I had to pick, this is the one thing I’ve felt was missing since I started using Qt. Death to spaghetti code, long live control abstractions.

The State Machine Framework is part of the Qt Kinetic project. You’ll find it in the kinetic-animations branch of the Qt Kinetic repository. Have fun, and let us know what you think.

Sebastian Pipping
Labs
 in Labs
 on Friday, January 30, 2009 @ 17:02

More or less everybody is using simple Regular Expressions from time to time, may it be through grep, url_rewrite or QRegExp. Most people seem to stick to a basic set of regex features: alternation, character classes, greedy quantifiers, capturing, grouping and zero-width assertions (e.g. anchors). However, some people, myself included, expect more from a regex engine.

A few weeks before I started working at Qt Software Berlin (Trolltech at that time) I wrote a mail to qt-interest asking for extension of QRegExp by

  • Lookbehind
  • ^ and $ match for each newline, not only string start/end
  • Dot-matches-newline switch
  • Callback input (matching text from sources unlike “plain arrays”)

I knew there were existing libraries that could do that, though Boost.Regex actually does a lot more. As a side project, I started working on a Qt wrapper around Boost.Regex so I could directly feed it with QStrings. Boost.Regex is templated and works with wchar_t, char and more but cannot work with QChar directly. It works with ushort though and QChar more or less is a ushort.

It’s incomplete, but I did not want it to gather more dust. Maybe this is what a few people have been hoping for just like I did back then. So I’m releasing it on Qt Labs now. Download the sources from here:

http://labs.trolltech.com/gitweb?p=qtboostregex;a=summary

Please note you need bcp (Boost Copy) which you install through

$ sudo apt-get install bcp

on Debian-based Systems.

Stuff to do include:

  • try to move Boost.Regex “further inside”
  • upgrade to a more recent Boost.Regex (e.g. to fix a GCC 4.3.x compile error)

What’s interesting to note is that QtBoostRegex outperforms QRegExp for some cases, for some QRegExp is the clear winner. For details please see ./examples/test holding a small test suite.

Besides the extra features on the regex language level this wrapper also allows to search non-array input. What does that mean? Usually a regex engine iterates over an array of characters or the structure wrapping these characters. Boost.Regex offers an extra layer of abstraction that we use to wrap an arbitrary non-array structure (e.g. a list of lines holding a document inside a text editor) inside a bidirectional iterator (I called feeder) here. The code contains an example of such an iterator wrapping a QStringList: StringListRegexFeeder. Please have a look at the ./examples/simple folder to see how it’s used.

To prepare the Boost.Regex sources please check out the script ./extract_boost_regex.sh. Without running that “qmake && make” will not succeed.

To summarize my post:

  • QtBoostRegex is a Qt wrapper around Boost.Regex
  • Boost.Regex is more powerful than QRegExp but slower in some cases
  • QtBoostRegex is not finished yet, I will keep working on it as time permits

Have a nice day, Sebastian

Thomas Zander
KDE
News
Posted by Thomas Zander
 in KDE, News
 on Thursday, January 29, 2009 @ 12:33

If you read any KDE news you will have heard that there was a KDE conference last week in the Americas called Camp KDE. The yearly KDE conference in Europe has sparked interest on the other side of the ocean. With a growing community all over the Americas the idea for having a local conference makes a lot of sense. At QtSoftware we naturally like this, and so we made sure several Trolls traveled to the Caribbean and joined in on the fun.

I talked about locations of Akademy (the European KDE conference) on various occasions. One suggestion we had was to do it way up in Sweden when there was expected to be 2 meters of snow and temperatures that would keep even the most adventurous geek inside. The idea here, naturally, is that with such conditions you will do more actual coding and hacking and less wasting of time on other things.
I’m so happy this never happened since I see that the opposite is even more productive. Geeks going to Jamaica, with sun, beach and parties, are still just geeks. I don’t think I’ve seen any geek spent a long time sunbathing. After not very long of relaxing on the beach, swimming in the ocean geekyness returned. We had BOFs while swimming, programming on the beach and lots of discussions about Qt / KDE coding.

In the end we actually did quite some work; you can find lots of pictures of people leaning over laptops on flickr and Alexandra Leisse who is also with both KDE and QtSoftware had the presence of mind to bring a video-camera. Have fun watching geeks on the beach ;) here

mkalinow
Qt
KDE
Posted by mkalinow
 in Qt, KDE
 on Wednesday, January 28, 2009 @ 08:09

Ah, it’s once again one of these articles about this wicked embedded platform Windows CE you think?
Nope, not this time. It is still about Windows though :)

As the KDE4.2 release is out and basically everyone talks about it, I got interested myself as well. Being a Windows user myself, I figured that it might be complicated to test this out. But actually there is a project out there, which is exactly targetting people like me: KDE on Windows.

After using the default installer and playing around, I tried out to manually build this thing. By default it uses Qt 4.4.3, but I wanted to go with our repository. Getting some help from the community on #kde-windows at freenode (special thanks to SaroEngels), I managed to let the KDE trunk run against the current Qt 4.5 version.

Now you are probably screaming “Screenshots! Pictures! Videos!” and here you go:

Ariya Hidayat
Graphics Dojo
Posted by Ariya Hidayat
 in Graphics Dojo
 on Monday, January 26, 2009 @ 09:57

In this era of digital photography, thumbnail preview is probably one of the most important features in any photo management software. Imagine if you have to flip through thousands of pictures, without being able to see the thumbnail previews. It would be a complete waste of time. Ideally the thumbnail preview is taken from what is stored in those JPEGs. However, suppose that you want larger or smaller previews, how to do that? With Qt, we can utilize QImage::scaled() function:

QImage result = img.scaled(200, 150, Qt::IgnoreAspectRatio, Qt::FastTransformation);

This gives a very fast downscaling, however the result is perhaps not so satisfactory because the resizing is only using the nearest-neighborhood method. For extra filtering, use the following instead:

QImage result = img.scaled(200, 150, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

Due to Qt::SmoothTransformation, the thumbnail has a better quality. The drawback is that it is very slow compared to the previous Qt::FastTransformation.

A trick known to almost every graphics programmer out there is this one:

QImage result = img.scaled(400, 300).scaled(200, 150, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

The first scaling is using Qt::FastTransformation (we do not need to specify it explicity, it is the default) to twice our target size. This is of course very fast. The second scaling does some smoothing for the final result.

Another obvious and better alternative is of course:

QImage result = img.scaled(800, 600).scaled(200, 150, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

which is essentially the same, only now we scale to four times the target size first.

So basically we “cheat” by not really scaling and filtering the whole image. This will speed up thumbnail generation process significantly. But don’t be surprised when I say that we can still make it even more faster. The trick? Use the previously discussed faster halfscaling method! The following chart shows the overall performance comparison (longer is better), take it with a grain of salt:

“Cheat scaling” is apparently very fast. This lies in the fact that it processes ARGB components at once (see the blog entry on fast image halfscaling) at the expense of less-precise low bits. The numbers represent the iterations for every 10e12 CPU ticks in order to resize a 10-megapixel image to 200×150 pixels. As you can see, the improvement is clearly obvious, though you may get less speed-up if the original and target size are not that extreme. You could probably push the performance further by falling back to processor-specific vector operations, e.g. SSE on modern Intel CPU.

How about the quality? Check the example at Graphics Dojo repository under the subdirectory thumbview. After building and running it, drag an image (from file manager or web browser) and drop it there. Please try a very big image, i.e. exercise the program with pictures from a fairly modern digital camera. The screenshot looks something this:

Press 1, 2, or 3 to change the scaling method for the bottom right image. To compare the quality between Qt::SmoothTransformation and cheat scaling method, you can flip using 2 and 3 quickly. Are you able to spot the difference? You’d be the judge!

Of course this cheat scaling method is not a silver bullet, nor it is a replacement for Qt::SmoothTransformation. For our specific case, namely creating a small preview of a very large, relatively patternless digital picture in ARGB32 format, the trick works well.

kkoehne
Test
Posted by kkoehne
 in Test
 on Friday, January 23, 2009 @ 14:09

Qt provides a whole lot of ways to iterate over a QList: You can use STL like iterators, Java like iterators, use the foreach macro or access the list elements via their index. Personally I fell in love with foreach from the first day, but it was not long that somebody remarked “foreach is slow” and that I should use STL const iterators …

With the new benchmarking extensions of QTestLib (Morten already blogged about them), it’s really easy to finally sort this out :-) . We will iterate over a QStringList with 100.000 elements (imagine you want to make a locale aware search or something alike, we will not modify the list), and compare numerous ways of iterating.

The test

Here is complete source code of the benchmark:

#include <QtCore/QStringList>
#include <assert.h>
#include <qtest.h>

class tst_iteration : public QObject
{
    Q_OBJECT
public:
    enum IterationType {
        Foreach,
        ForeachConstRef,
        Java,
        Stl,
        StlConst,
        IndexAt
    };

private slots:
    void qStringList_data() {
        QTest::addColumn<QStringList>("list");
        QTest::addColumn<IterationType>("type");

        QStringList list;
        for (int m = 100000; m >= 0; --m)
            list < < QString::number(m);

        QTest::newRow("index based") << list << IndexAt;
        QTest::newRow("Java") << list << Java;
        QTest::newRow("STL") << list << Stl;
        QTest::newRow("STL (const iterators)") << list << StlConst;
        QTest::newRow("foreach") << list << Foreach;
        QTest::newRow("foreach (const references)") << list << ForeachConstRef;
    }

The qStringList_data() method defines the test data for each test run: Each run will use the same list with 100.000 elements in it, but use a different type of loop.

    void qStringList() {
        QFETCH(QStringList, list);
        QFETCH(IterationType, type);

        int dummy = 0;

        switch (type) {
        case IndexAt:
            QBENCHMARK {
                const int listSize = list.size();
                for (int i = 0; i < listSize; ++i)
                    dummy += list.at(i).size();
            }
            break;
        case Java:
            QBENCHMARK {
                QListIterator iter(list);
                while (iter.hasNext())
                    dummy += (iter.next()).size();
            }
            break;
        case Stl:
            QBENCHMARK {
                QStringList::iterator iter = list.begin();
                const QStringList::iterator end = list.end();
                for (; iter != end; ++iter)
                    dummy += (*iter).size();
            }
            break;
        case StlConst:
            QBENCHMARK {
                QStringList::const_iterator iter = list.constBegin();
                const QStringList::const_iterator end = list.constEnd();
                for (; iter != end; ++iter) {
                    dummy += (*iter).size();
                }
            }
            break;
        case Foreach:
            QBENCHMARK {
                foreach (QString s, list) {
                    dummy += s.size();
                }
            }
            break;
        case ForeachConstRef:
            QBENCHMARK {
                foreach (const QString &s, list)
                    dummy += s.size();
            }
            break;
        default:
            break;
        }
        assert(dummy);
    }

Note that I access the size() of each list element. This “side effect” prevents the compiler from being too clever and optimizing the whole loop away :)

Just for the sake of completeness here is the rest of the file:

}; // class tst_iteration

Q_DECLARE_METATYPE(tst_iteration::IterationType);

QTEST_MAIN(tst_iteration)

#include "main.moc"

Results

The benchmarking library allows you to run the same tests with different “backends”: That is, you can let it measure the actual time, use the callgrind module of valgrind to measure cache misses or use the CPU ticks. For details see Morten’s post. Here are the results for measuring the actual time on my developer machine (2Core Intel, Ubuntu32, gcc 4.3.2):

RESULT : tst_iteration::qStringList():"index based":
     0.32 msec per iteration (total: 21, iterations: 64)
RESULT : tst_iteration::qStringList():"Java":
     0.39 msec per iteration (total: 25, iterations: 64)
RESULT : tst_iteration::qStringList():"STL":
     0.39 msec per iteration (total: 25, iterations: 64)
RESULT : tst_iteration::qStringList():"STL (const iterators)":
     0.35 msec per iteration (total: 23, iterations: 64)
RESULT : tst_iteration::qStringList():"foreach":
     3.3 msec per iteration (total: 27, iterations: 8 )
RESULT : tst_iteration::qStringList():"foreach (const references)":
     0.40 msec per iteration (total: 26, iterations: 64)

Aside from the first simple foreach, all ways of iterating do not really differ performance wise. But why is the foreach without references so much slower? Well, in this case a new QString object is created inside the loop. It doesn’t detach (it’s still a shallow copy), but since we are not doing that much else in the loop, this makes a difference by a factor of 10!

Bottom line: If you - like me - value the readability of foreach, you should probably get used to writing foreach (const Type &, list) (that is, whenever you do not alter the value). Otherwise the different styles of iterating do not really differ performance wise. Whatever you do in the loop body will in most cases have a much larger impact :)

Update: Rerunning the benchmark on Windows 32 bit with a Visual Studio 2005 compiler (release build) actually shows more severe differences in runtime performance:

RESULT : tst_iteration::qStringList():"index based":
      0.12 msec per iteration (total: 32, iterations: 256)
RESULT : tst_iteration::qStringList():"Java":
      0.24 msec per iteration (total: 31, iterations: 128)
RESULT : tst_iteration::qStringList():"STL":
      0.18 msec per iteration (total: 47, iterations: 256)
RESULT : tst_iteration::qStringList():"STL (const iterators)":
      0.18 msec per iteration (total: 47, iterations: 256)
RESULT : tst_iteration::qStringList():"foreach":
      3.8 msec per iteration (total: 31, iterations: 8)
RESULT : tst_iteration::qStringList():"foreach (const references)":
      0.48 msec per iteration (total: 31, iterations: 64)

MSVC seems to be having problems optimizing the template code away …

Ariya Hidayat
Graphics Dojo
Posted by Ariya Hidayat
 in Graphics Dojo
 on Tuesday, January 20, 2009 @ 10:37

In digital systems, an N-bit adder can be implemented by N-1 full-adders and one half-adder. When accumulating numbers, carry save adder is an interesting alternative since it is faster. As explained somewhere else already, the same technique is also useful if we want the average of 16-bit numbers encoded in 32-bit numbers. Or, for all that matters, 8-bit in 32-bit. This of course fits nicely as we average two colors in ARGB color space, where each component takes 8 bits. The code is as simple as (0xfefefefe is there to mask out the bit not to overflow and falsify the next 8-bit):

quint32 avg = (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);

This is faster to compute, rather than taking the alpha, red, green, and blue of the first and second colors, average each component invidually, and then combine them again to find the final result, like the messy lines below:

quint32 avg = qRgba((qRed(c1) + qRed(c2))     >> 1,
                    (qGreen(c1) + qGreen(c2)) >> 1,
                    (qBlue(c1) + qBlue(c2))   >> 1,
                    (qAlpha(c1) + qAlpha(c2)) >> 1);

But how fast is faster? I decided to write an example that uses the above mentioned trick to speed up downscaling an image to half its original size. Usually you do this using QImage::scaled() function. If you pass Qt::SmoothTransformation as the transformation mode for this function, then halfscaling the image is the same as taking every 2×2 pixels, average their color values, and use the result as the final color. On the other hand, Qt::FastTransformation will just sample one of those 4 pixels. Surely it means that it is faster (the name implies that), however the lack of box filter there also means the quality is not as good as using Qt::SmoothTransformation. Here comes the trick of ARGB32 pixel averaging, which allows us to write QImage halfSized(const QImage&) that is really really fast compared to QImage::scaled() with Qt::SmoothTransformation, but still give the same visual quality. Using the new benchmark feature in our beloved test framework, here is the speed comparison (longer is better).

"Normal" refers to scaling with Qt::SmoothTransformation, whereas "Optimized" is our custom halfSized() function. The numbers represent the iterations for every 10e12 CPU ticks in order to halfscale a 10-megapixel image. As you can see, the improvement is about an order of magnitude. Impressed?

The code is still fresh at Graphics Dojo repository under the subdirectory halfscale. Take a look and have a try. Do not forget also the catches: potential round-off error and even columns and/or rows. If you can get away with the loss of up to two bits and cutting one last (or in the middle) vertical and horizontal pixels, then this halfSized() function is your new friend.

Now carefully examine following screenshot. Just like other previous examples, you can always drag and drop an image from the file manager or web browser. For this one, I used Gianni’s Urban solitude picture (Creative Commons NC ND). As you can see, when you stick with FastTransformation, there are jagged lines and some effect like Moire patterns in the downscaled image. This problem disappear when you use SmoothTransformation. In addition, the optimized half scaling method presented here gives a result just like when you use SmoothTransformation.

If you start to ask why all this halfscaling seems to be important at all, just watch this blog and see what will come next. Hint: you might guess it already if you were at my last DevDays talk.

Sebastian Pipping
Documentation
doxygen2qthelp
 in Documentation, doxygen2qthelp
 on Thursday, January 15, 2009 @ 13:37

In June 2008, I wrote about doxygen2qthelp and how to create Assistant-viewable content, i.e., Qt Compressed Help .qch files, from Doxygen. In this post, I would like to further elaborate on showing Doxygen generated documentation in Qt Assistant.

Later, I collaborated with Doxygen’s head developer, Dimitri van Heesch. As a result, Doxygen 1.5.7.1 introduced direct support for .qhp and indirect support for .qch (through qhelpgenerator). However, this did not work perfectly, but the Subversion repository contained a fix soon after.

The recently released Qt Quarterly 28 has an article that explains how to make Doxygen generate .qch and .qhp files for you, out of the box. This article is
titled “HTML Files and Help Projects” and is freely available online.

Doxygen 1.5.8 has now been released and it contains this fix. I’m aware that a few days have passed since December 27th, but I believe this news is still new for some.

So, to sum up:

That’s it, have a nice day.

Ariya Hidayat
WebKit
Graphics Dojo
Posted by Ariya Hidayat
 in WebKit, Graphics Dojo
 on Thursday, January 15, 2009 @ 09:24

One nice feature of WebKit that has been integrated into Qt 4.5 is the support for full page zoom. It means that you would be able to scale the whole page and not only to make the text smaller or large. You can experience this already with the demo web browser if you grab Qt 4.5 beta. Go to a web site and use the View menu to actually zoom in and out everything, including the embedded image. This is achieved with a new property: QWebView’s zoomFactor. Whether the zooming is applied to both the text and images or only to the text can be tweaked via the appropriate QWebSettings.

Along with this, I show a new example of capturing a web page. This is actually a request, as an alternative improvement to the web thumbnail example which has been shown before. Using it is as easy as:

webcapture www.trolltech.com 50 trolltech.png

The code will run both with Qt 4.4 and 4.5. Under Qt 4.4, it will grab the contents of the page (www.trolltech.com), render it to an image, and then scale the image accoding to the zoom factor (50, in percent) that you specify, and finally save it to a file (trolltech.png). With Qt 4.5 however, it will set the zoom factor before rendering the page to the image, effectively skipping the need for the scaling process in the end. Both approaches have advantages and disadvantages. For zoom factors less than 100%, the scaling approach usually gives a much better result. However, it is more expensive since we always need an image (for the buffer) as large as the page size. Think of a really long page like Google News or Digg. On the other hand, for an obvious reason, image scaling will not work well for zoom factors more than 100%.

If you want an extra exercise, do the following. Modify the capture tool so that it uses the image scaling method for zoom factors less than 100% and full-page zoom when the zoom factor is more than 100%. That likely gives the optimal result.

Another potential use case for such a tool is to perform a quick visual check of web pages at different viewport size, for example when they are viewed in mobile devices. While most desktop and laptop stick to at least 1024 pixels wide monitor these days, many mobile phones are still using QVGA (320×240) and HVGA (320×480) screen. You can pass the viewport width as the fourth argument to webcapture. Shown below (click to get the larger version) is the mobile version of BBC Technology section rendered in three different widths: 240, 320, and 480, respectively. As you can see, the page still looks nice even if the screen is not that wide.

The code is available from our brand new git repository for Graphics Dojo under the subdirectory webcapture. If you did a clone before, you just need an update. Otherwise just do the following:

git clone git://labs.trolltech.com/GraphicsDojo

This example also demonstrates the often asked question: how do I know the height of a web page given the width? You might want to know this if you need to display the page without the scroll bars (which implies a viewport as large as the contents). The steps are as follows: load the page, disable the scroll bars, set the viewport size to a sensible one (only the width here matters), and then get the contents size. If you test this trick to e.g. Google News, you will get 768 as the height of the viewport but 3161 from the contents height. Thus, this gives you something like heightForWidth() function.

Happy capturing!

Andreas
Qt
Graphics View
Posted by Andreas
 in Qt, Graphics View
 on Wednesday, January 14, 2009 @ 14:34

There are a few problems left to solve for how Qt’s widgets are embedded inside a QGraphicsScene. Each problem is a bit tricky, at least I think so. I’ll list a few and try to explain.

1) Mapping between global coordinates and scene/item coordinates.

QWidget can map its local coordinates to and from global (desktop) coordinates. This is useful for positioning popups or other windows relative to the widget (since window positions are always defined in global coordinates). It’s also useful for ensuring that something is close to the mouse cursor. There’s basically many use cases for global coordinates, and mapping to and from them. For some event handlers, Qt does this for you automatically, such as QWidget::mousePressEvent().


void Widget::mousePressEvent(QMouseEvent *event)
{
QMenu menu;
menu.add…
menu.add…
menu.add…
menu.exec(mapToGlobal(event->pos()));
// or simply menu.exec(event->globalPos());
}

Now the problem. One vanilla Qt widget can only appear in one spot, one desktop. In Graphics View, it can appear in several places (e.g., in the chip demo). This means QCursor::pos() can mean different things to a widget, and in particular, QWidget::mapToGlobal() and QWidget::mapFromGlobal(). What do these functions really mean to a widget that is embedded inside a QGraphicsProxyWidget? Why does Graphics View support multiple views again? :-P It’s clear that with only one view, this problem is trivial to solve. What would you expect for the above mouse handler if the widget is embedded in a multi-view application?

It’s likely that when a widget wants to map to and from global coordinates, then it’s as a response to either key or mouse input, and it’s likely that the correct view has input focus. So QWidget::mapToGlobal() could mean: map to the desktop of the single view if there’s only one, or the active input view, if any. If there are several views but none qualify, pick the one closest to the cursor? If not, map to scene. (Yup, you may have two views, each on a different desktop. It’s a corner case, its importance depending on which parts are important in any particular project.) Behind each unhandled corner-case lies a pool of subtle bugs.

QWidget::mapToGlobal() could just mean “map to/from scene”. While consistent, this is also completely useless… QWidget::mapTo/FromGlobal are almost exclusively called from inside a widget that’s otherwise unaware of Graphics View. The result is expected to be in desktop coordinates, and the mapping relative to the widget.

2) To embed or not to embed.

If you embed a widget, its child windows and popups are also embedded. This makes sense sometimes, otherwise not. It’s nice to be able to scale your whole UI to get resolution independence, and also see that your popups and file dialogs are scaled. If you don’t want to scale the windows; just scale the rest of the UI, you can pass 0 for the parent of the window. That’s if you’re in control. If you’re not, widgets like QComboBox will open a popup whose parent is the QComboBox itself, and the popup is embedded automatically. You have no choice. :-P

It’s clear from our users’ feedback, and from the Plasma team in KDE, that sometimes you want this and sometimes you don’t.

So what do we do? We could add a widget attribute that you could set on a widget, that ensures that it never auto-embeds any of its subwindows. In retrospect, perhaps this flag should have been the default, or rather that there was a flag that you could set that prevents this from happening. We also have the option of adding this as an option to QGraphicsProxyWidget; proxy->setAutoEmbedChildWindows(false).

But then there’s the case where a widget just never should be embedded, regardless of its parent. Examples may be tooltips, drag icons, and whatsthis-labels. Should it be the widget’s responsibility to “tag itself” for never being embedded (Qt::WA_DontEmbedInGraphicsView), or is also this an option controlled by the embedder?

I’m sure the answers will pop up one of these days. ;-) Maybe you have some ideas you could share?

(Btw, the fact that embedded popups/windows aren’t constrained to fit inside the viewport is a bug that’s still not closed, but hopefully soon will be.)



© 2008 Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
All other trademarks are property of their respective owners.