CmdrMoozy
CmdrMoozy

Reputation: 3941

Qt 5 QPlainTextEdit highlighting current line fails after "undo"

I'm working on a simple text editor program using Qt5. My editor component is a subclass of QPlainTextEdit, and for some of the basic functionality I've stolen some code from this Qt demo program. The two pieces of functionality that seem to be interfering with each other are the code to highlight the current line of the editor (which is connected to the text edit's cursorPositionChanged() signal, just like the demo shows):

QList<QTextEdit::ExtraSelection> es;
QTextEdit::ExtraSelection selection;

selection.format.setBackground(currentLineHighlight);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);

selection.cursor = textCursor();
selection.cursor.clearSelection();

es.append(selection);
setExtraSelections(es);

And the code I have written to do the very common "indent all of the lines when you hit tab while having multiple lines selected" thing:

QTextCursor curs = textCursor();

if(!curs.hasSelection())
    return;

// Get the first and count of lines to indent.

int spos = curs.anchor(), epos = curs.position();

if(spos > epos)
{
    int hold = spos;
    spos = epos;
    epos = hold;
}

curs.setPosition(spos, QTextCursor::MoveAnchor);
int sblock = curs.block().blockNumber();

curs.setPosition(epos, QTextCursor::MoveAnchor);
int eblock = curs.block().blockNumber();

// Do the indent.

curs.setPosition(spos, QTextCursor::MoveAnchor);

curs.beginEditBlock();

for(int i = 0; i <= (eblock - sblock); ++i)
{
    curs.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);

    curs.insertText("\t");

    curs.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor);
}

curs.endEditBlock();

// Set our cursor's selection to span all of the involved lines.

curs.setPosition(spos, QTextCursor::MoveAnchor);
curs.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);

while(curs.block().blockNumber() < eblock)
{
    curs.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
}

curs.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);

setTextCursor(curs);

Both of these functions work well - at least most of the time. There seems to be a weird bug involving these two when I do the following:

  1. Select a few lines, and hit tab, which indents them all as I expect.
  2. Undo that operation.

At this point, on the last line of the set of lines which were indented, the line highlight doesn't extend all the way across the editor like it normally does - it only extends to the end of the line. If I move my cursor to the end of that line and then hit "Enter," it resolves the problem.

I've tried several things to try to diagnose this problem, including trying to move the cursor and/or anchor around instead of just calling clearSelection() in the highlight function, and trying to examine / iterate through the QTextBlocks which make up the editor's document to try to find some discrepancy, but at this point I am at a loss. I simply can't make this code behave the way I expect.

I have discovered that the line which now renders incorrectly can be "fixed" but either adding any characters to that line, or by resizing the window.

Also, this bug still occurs if I remove the setTextCursor call at the end of my indent function.

These two things lead me to believe that this bug has nothing to do with either the text cursor or the contents of the document, so at this point I'm leaning towards considering it a bug in Qt's rendering of extra selections.

Does anyone see where I've gone wrong?

Upvotes: 1

Views: 1490

Answers (1)

CmdrMoozy
CmdrMoozy

Reputation: 3941

This is actually a bug in Qt, not a problem with the code in the OP. See QTBUG-30051 - QTextCursor and beginEditBlock breaks layout.

Upvotes: 1

Related Questions