Table of Contents
Thoughts on porting to Qt4/KDE4
Work so far
Structuring the work
Four sorts of work here:
We can also reasonably expect to have some developers (particularly occasional contributors or newer arrivals) wanting to commit fixes and small features while the Qt4 work is going on.
Major subjects to consider
Our CMake build system should continue to work, but will need a lot of updating to handle different header locations and to avoid getting mixed up between Qt3/KDE3 and Qt4/KDE4 headers. I personally have never had KDE4 headers installed on any of my machines at all yet, so I've no idea where they go or what they look like.
It would be great if someone could take on the task of updating the CMake files so as to build with entirely “v4” instead of “v3” headers, libraries, moc etc – perhaps in the qt4-mechanised branch so we can test it as we test any mechanical updates.
One of our goals should be that no translator should have to rewrite a single word as a result of this port.
Qt4 has a different translation file format from the one we use (it's a .ts file, and it's XML) with different tools; KDE4 uses an enhanced version of the same format, with updated tools.
KDE3 to KDE4
Porting KDE3 → 4 there are some big changes in i18n. I don't see any indication that this would break existing .po files, but it's a lot of work for us. i18n is replaced with i18n, i18nc, i18np, i18ncp, and ki18n, and the .arg() methods are no longer used. That looks interesting.
Plural call is renamed to i18np and does away with %n placeholder, all being numbered instead:
i18np("One image in album %2", "%1 images in album %2", n, albumName);
KDE3 to Qt4
As far as switching to QT4, if ts2po and po2ts actually work reliably, they could serve to convert our existing files to the new format, and convert them back, in order to allow translators to continue to use their familiar tools in the familiar way.
(Alexandre: [I did] a po2ts migration back in Scribus 1.0.x days. It was fairly easy to do this, but in the end the hierarchy that TS files usually have (a branch for each dialog) was not recreated, so I had to run lupdate and then use the Ctrl+1 key combination to manually put everything in place. I fail to find package that has po2ts for qt4 in Ubuntu, so I cannot test it again.)
The process of swapping i18n() for tr() looks like a lot of work in itself though. It doesn't look like a simple s/i18n/tr/g job at all. We may have difficulties bringing all the i18n stuff up to KDE4 too (although there is a Perl script to do a partial conversion, which ought to help considerably,) but the QT4 route definitely seems to involve even more difficulties. As near as I can tell, the i18n stuff just works thanks to KDE, and we don't have to find and load the translation files manually in main.cpp or elsewhere, or futz with any of the rest of this hands-on stuff QT requires to make translations work.
Plural handling for Qt4 is described at http://doc.trolltech.com/qq/qq19-plurals.html – again, a change from what we've been using, but capable enough.
At a glance, it looks like KBabel can handle the QT stuff, but not vice versa. The most recent linguist-qt4 I have doesn't know what to do with .po files, but the most recent KBabel I have does apparently know how to handle .ts files.
COMMENTS: Either option looks evil, but if we're definitely allowing KDE classes in, I'm (dmm) just more comfortable with the i18n option for no really specific and highly justifiable reason. tr() just seems comparatively lame.
KDE4 moves to D-BUS, which is conceptually similar. But my radical suggestion here is to drop the sequencer process altogether. Bring it into a single process, as a separate thread.
Lose the proxying/forwarding classes from src/sound etc, including the whole of MappedStudio.cpp (an overengineered set of classes never really used for their intended purpose). Replace with a simple set of container classes.
Keep MappedEvent, and keep the SegmentMmapper etc on both sides, writing into memory buffers of fixed-layout objects – the difference is simply that the memory buffers are not shared or file-backed any more.
Rename MappedComposition to something less suggestive of an actual composition, but keep it.
Lose MappedInstrument and MappedDevice. Make the sequencer use the main studio classes directly (with mutex as appropriate).
Calling directly from one thread's domain to another is fine for simple accessors etc, but of course we would still need to schedule requests for play, stop etc to ensure they're carried out in the correct thread.
Advantages: Code that stands more chance of being understood by other programmers. Opens more possibilities for tighter integration, e.g. reading and writing tempo maps from the sequencer, or fixing the problems we have with adding and deleting devices, without ludicrous amounts of pain.
Disadvantages: More possibilities for threading-related bugs. Crashing sequencer crashes the GUI too.
Widget and dialog layouts
The Qt widget hierarchy and layout classes have changed somewhat for Qt4. The standard form has become a bit longer in terms of lines of code, though each line is simpler.
e.g. we do quite a bit of things like
QGroupBox *groupBox = new QGroupBox(1, Horizontal, i18n("Group"), parent); QHBox *hbox = new QHBox(groupBox); QLabel *label = new QLabel(i18n("Thing:"), hbox);
The more usual way to write this now would be:
QGroupBox *groupBox = new QGroupBox(i18n("Group")); // or tr() or whatever QHBoxLayout *layout = new QHBoxLayout; groupBox->setLayout(layout); QLabel *label = new QLabel(i18n("Thing:")); layout->addWidget(label);
Also, we use
QGridLayout::addMultiCellWidget(w, a, b, c, d, align);
an awful lot. This has changed to effectively
QGridLayout::addWidget(w, a, c, b - a + 1, d - c + 1, align);
The old and new APIs are (respectively)
QGridLayout::addMultiCellWidget(w, fromrow, torow, fromcol, tocol, align); QGridLayout::addWidget(w, fromrow, fromcol, rowspan, colspan, align);
The new API is better, but it's going to be a tricky one. It might just about be scriptable.
Qt4 object constructors no longer have a “name” argument (which used to appear optionally at the end of the constructor arguments in Qt3). It wasn't very useful even in Qt3 and we probably haven't used it all that much overall, but I bet there are some classes that will be using it disproportionately heavily.
The main segment canvas is a widget, which should be straightforward to port.
The matrix currently uses QCanvas. Guillaume embarked on an experimental revision of this for the Qt4 QGraphicsView (in SVN at trunk/experiments/matrix4). This builds into a separate application with just a matrix in it. In my opinion it's not all that promising – it displays, but operations like rubberbanding are slow and zooming is buggy. I personally think it would be better to convert the matrix to a widget like the segment canvas (only much, much simpler), because I think there would be payoffs in terms of performance and control over display that justified the change.
The notation view also uses QCanvas, and it may be better as a QGraphicsView because the layout model is much more complex than the matrix. I think we should embark on the most literal possible translation from QCanvas and items to QGraphicsView/QGraphicsScene and see where it gets us.
It might not be unreasonable to remove Rosegarden's native printing altogether – perhaps this is the moment at which we decide that Lilypond-only is better.
1) Native printing is a mirror of what's on the screen, and there are dozens of bitchy layout problems on-screen that go right to the page. Like the horrible slurs, top of the list.
2) LilyPond export is damn reliable thanks to Heikki.
3) Native printing makes gigantic graphics, and my printer takes hours to digest just one page of this stuff. Native printing is totally useless with my printer unless I use a different, lower-resolution print driver that also reduces the quality to crap. I realize this is just me, not the rest of the world, but native printing is pure evil to me, and I wouldn't miss it a bit.
1) There are still a few things LilyPond does not export at all. Pedal marks (FIXED), ottavas (FIXED), C vs. 4/4 per user preference (FIXED),
2) The whole rosegarden-lilypondview thing is still rather fragile, and we never have done an adequate job of coming up with some way to make sure users have the right helper applications in place.
3) One of the reasons I work here is because it used to be (and maybe still is) the case that NoteEdit (now Canorus) could only print with external help, whereas Rosegarden could just print and be done with it. (Similar feelings about their old dependency on the TSE3 library.) That impression was formed long ago in a different age when everything worked more poorly than it does now, but I still have a little nostalgia for the idea that we can do our own printing in house.
It's probably a lot more sensible just to ditch it though, and focus attention on the remaining LilyPond edge cases that still allow a user to draw X on the screen but force him to print Y. (One such that springs to mind is http://sourceforge.net/tracker/index.php?func=detail&aid=1560372&group_id=4932&atid=104932)
Qt4 includes a help module starting in Qt4.4 (http://doc.trolltech.com/4.4/qthelp.html). I haven't tried to use it. I think the help is expected to be represented as a set of HTML files. I'm a bit suspicious about how far the Qt classes actually get you – I don't really want to be firing up “Qt Assistant” as a help browser – we want to either have desktop integration (i.e. use the same help browser as KDE, or even a standard web browser) or have our own built-in help window (which it seems can be done without too much trouble using QTextBrowser).
An unknown: What does KDE4 do with help? Research needed!
I'm no great fan of the KDE3 help window; half the time it doesn't even show up for users. A less well-specified, but more tightly integrated with the application, help system might be no bad thing. It does beg more questions about translation support though.
To which Michael replies… Translation of the manual isn't much of an issue, because the only language that's up to date in any meaningful way, AFAIK, is English anyway. It would be interesting to see if we could use this as an opportunity to make it easier for the manual to get translated along the way. It's currently a gigantic pain in the ass. As far as that goes, I wouldn't much object to converting the whole thing to HTML or something, and doing away with the Docbook. Docbook can offer lots of cool things, but we don't really care, and it's off-putting. We've recently had two different people run away screaming after looking at the source for the manual.
I totally agree about losing Docbook. (Chris)
And then (Michael) we have the complication of someone having taken it under her wing to face lift the thing, and who has agreed to take it upon herself (Shelagh) to wrestle with the evil Docbook syntax for the furtherment of all humankind and stuff. If KDE4 uses Docbook still, we might ought to just leave well enough alone. (Shelagh) Hey I don't care what you use for the manual, I'd still be happy to do the documentation whatever evil markup you decide to use.
I should check into this. I currently have KDE4 installed and runnable, but I'm only looking at the -4 apps from my -3 desktop, rather than actually suffering with the whole experience. (And many of the apps, if not most, are totally broken in this environment, incidentally.) (I haven't tried the 4.1 beta yet either. I think it's 4.1 isn't it? I'm waiting for it to get out of beta before I mess with it at all.)
I have to say this entire overriding issue is almost enough to send me to Windows or, to Guillaume's great delight, OS-X at this point. Of course I'm still here because I took a 66% pay cut and I'm having to liquidate my life to try to keep out of bankruptcy court, so on the other hand, beer free software is good software.
Breakdown of individual classes
The notes here contain discussion about how our uses of these classes might be ported to “pure” Qt4. Generally I'm not mentioning porting to KDE4 except in cases where “pure” Qt4 looks hard to do.
It may be worth aiming at “mostly Qt4 and cutting back our dependency on KDE a bit”, rather than going either “pure Qt4” or “the whole hog with KDE4”.
Note that Trolltech took the very sensible decision to change the function name or make an incompatible prototype for each function whose behaviour had significantly changed between Qt3 and 4. This means you can easily identify the code you need to work on because it doesn't compile; there's very little risk of having it compile and then later discovering that doesn't work.