Wednesday, July 16, 2014

Monday, July 14, 2014

Vacation thoughts - old bug dead in new design

Too busy doing vacation stuff to think much about PPQT but one idea did occur in a quiet moment: that under the new design I sketched in the prior post, an old and difficult bug will no longer matter.

PPQT uses a list of QTextCursor objects to track the start of each logical page of scanned text. This is an important function. It enables me to display the correct scan image as the user moves the cursor. It enables auto-generation of page-marker text, as for HTML conversion.

When a book is first opened, the list is set up by recognizing the PGDP page separator lines. Later, the user deletes those lines, but a QTextCursor doesn't care, it just keeps pointing between character A, at the end of page A, and character B, the first letter of page B, and is automatically updated by QTextEdit as characters are added and deleted (and moved, which is a sequence of delete and add).

It all works perfectly except for a major bug. If a text insertion or deletion spans the position of a QTextCursor, the position is changed to the end of the inserted or deleted text. This is arguable correct. But if the user then Undoes that change, the cursor's position is not restored. QTextCursor values are not saved on the undo/redo stack. (Here's the bug report I filed.)

Changing text that spans a page boundary is unusual in normal editing but common in one case: paragraph reflow for the ASCII conversion. A paragraph may well span a page boundary. In V.1, the reflow logic has a lot of code to notice this case and preserve the page boundary cursor, so that after all the lines of the old paragraph are replaced in one operation by the lines of the reformatted paragraph, the boundary cursor is fixed up to point between the same characters A and B as before.

But if the user then undoes the reflow, the boundary cursor jumps to the end of the restored, original paragraph and points to the wrong place. The page image no longer flips when it should. Users are encouraged to test-reflow paragraphs, tables, poems, etc., and to ctl-Z the reflow if the result is not good. Which pretty much guarantees that many page boundary cursors will not survive the ASCII conversion step (or the HTML conversion, which is similar).

I've put some thought into this and never saw a way to fix it. I've thought about, and meant to experiment with, customizing the Undo/Redo classes, possibly storing an affected cursor's position in the stacked element (sorry, can't be bothered to look up its class name just now) and fixing it during a redo. But there are a lot of questions, such as, when does QTextEdit update the affected cursors' positions, before or after stacking an undo element?

Then I realized, under the translator scheme I outlined previously, the whole issue goes away. ASCII reflow is part of "translating" from DP markup to a different markup, the PG etext format. Under the new design, this will never be done ad-hoc or section by section. It will always be done as a complete translation of the DP text producing a new file in a new edit tab. The DP text is not affected and its page cursors are still good. The only kind of "undo" the user can have, is to just close the new book without saving it, and translate again.

So I can stop worrying about maintaining page cursors over reflow. I do have to worry about passing page boundary information to a "translator" function, so the new, reformatted book can have its own unique table of page boundary cursors, but I think I know how to do that.

Not sorry to see an old bug die.