|
FEB
23
2012
|
Calligra Words: undo/redo frameworkAs C.Boemann already said, we met at my place for two days in order to fix some serious issues we had with the undo/redo framework in Calligra Words (and Stage for that matter). The undo/redo framework is something I wrote when I first started contributing to KOffice about 3 years ago. I have to say that I was not really looking forward having to jump into this stuff again. I am not such a masochist and the memories I have of writing this are not ones of an easy glide. To summarise a bit (more detailed description bellow for the hard hearted): we use Qt Scribe framework for our document. When an edition is done on a QTextDocument, it emits a signal telling that an undo/redo action was added on the QTextDocument internal undoStack. The application listens to this signal and can create an undo action on its stack to match QTextDocument's internal one. So we sat with Boemann thinking how to solve that problem. In the end we only needed to add, instead of a single head command member in the framework, a stack of head commands. Overall, I had a really good time coding with C.Boemann, who is not only a very talented coder but also somebody I really appreciate. It is amazing to see what we achieved in those just two days. A bit more details: As I said, we use QTextDocuments to hold the data of one text frame (text shapes). This document is edited through a specific handler: a KoTextEditor. This editor is not only responsible for editing the QTextDocument but also to listen to the QTextDocument's undoCommandAdded signal and keep our application's stack in sync. In addition to this, there are two special cases in editing QTextDocument: inserting text and deleting text. These two actions only trigger a signal on the first edit. Any subsequent compatible edit is "merged" into the original edit command and will not trigger a signal. Inserting text and deleting are therefore open ended actions, as far as our framework is concerned. In order to handle this, a sort of state machine is used. The KoTextEditor can be in a NoOp, KeyPress, Delete, Format or Custom state. Furthermore, for each signal received from the QTextDocument, we create a "dummy" UndoTextCommand, whose sole purpose is to call QTextDocument::undo or QTextDocument::redo. These commands need to be parented to a command which we push on our application's stack. This head command will call undo or redo on all its children when the user press undo or redo in the application. I will not enter into more details here, if you are interested in the whole gory logic of this, you can look at the code in calligra/libs/kotext/KoTextEditor_undo.cpp (which for now lies in the text_undo_munichsprint git branch). The code has now been pretty well documented, something I had not done before. That's it for today. Once again, I ask from as much of you to try our next test release, specifically the undo/redo framework, so that we can ensure that we release a really good stable Calligra Words. |
|

Comments
Nice read.
Nice read. Thanks for the insight in Calligra's undo/redo framework :)
thanks
Thanks for blogging and for the kind words which you know I reciprocate. It was really fun and rewarding work we did.
Why not move away from the
Why not move away from the Scribe/QTextDocument framework completely?
Clearly it was never developed with the use-case of a full-featured high-precision word processor in mind.
The Qt developers clearly intended it only for simple text editor apps, or generic info boxes and rich text fields in normal GUI apps.
Its not just this "undo" mess which you are now forced to fix with complicated workarounds.
Remember how many years it took to fix "ugly fonts" bug, because it relied on upstream patch for Scribe framework being accepted by Nokia/Qt Project?
How many similar problems will open up in future, which you will again be forced to either fix with workarounds involving additional layers of abstraction (and therefore code duplication and performance loss) or wait for several years again for upstream patches to go into Qt?
Wouldn't it, for the long-term benefit, make sense to fork QTextDocument and make it a clean, specialized text handling framework optimized for the advanced usecases needed in Calligra?
Every other office suite on the planet has a custom, specialized text handling framework.
Do you really think Calligra can get away with relying on a simple, generic text framework provided by a general-purpose GUI-toolkit?
Re: Why not move away...
This is a very valid question, actually.
Well, to start with our topic here (the undo/redo framework), there is a two step answer:
- the first is the one of the short term (ie. Calligra 2.4) problem we had to solve: there was simply not enough time to go as deep as this. One might wonder, why wasn't it done before?
Well, QTextDocument's undo/redo takes care of quite a lot actually. all formatting, deletions,... At the time I first wrote KOffice's undo/redo framework (3 years back), this very question actually came naturally. But our requirements for the undo/redo framework were not as advanced back then. It just looked like a higher price to actually having to re-implement all these low level undo/redo stuff.
- now, for the future: well, it indeed seems like the framework could be much simpler if designed from the ground up with our use case in mind. However, QTextDocument's internal undo/redo is very tied up into it. I am not sure really how much it would cost us (design and then maintenance) to supersede it inside QTextDocument. That question would however probably raise again if our updated framework prove too limited or not resilient enough in the future.
For your more general remark about forking QTextDocument, and eventual future similar problems. Well, there are actually some already identified similar problems in sight. We have a problem with tabulations together with text direction, and we have a missing feature which affect the change tracking framework.
Both are actually quite big and we are evaluating how best to proceed further.
All in all, this question is actually never really far from the table.
Thanks for your interest,
PierreSt