Important: Please read the Qt Code of Conduct -

Replace private iterator QTextDocumentLayout

  • After my previous post Custom documentLayout for QTextDocument, I have worked my way through the private QTextDocumentLayout. I renamed it to TextDocumentLayout, added widgets-private, gui-private and core-private to my pro.file and am currently working on excluding the private parts by replacing them with non-private alternatives. Now I've got stuck on the following:

    QTextFrame::Iterator TextDocumentLayoutPrivate::frameIteratorForTextPosition(int position) const
        QTextFrame *rootFrame = document->rootFrame(); //-> replacement for docPrivate->rootFrame();
        const QTextDocumentPrivate::BlockMap &map = docPrivate->blockMap();
        const int begin = map.findNode(rootFrame->firstPosition());
        const int end = map.findNode(rootFrame->lastPosition()+1);
        const int block = map.findNode(position);
        const int blockPos = map.position(block);
        QTextFrame::iterator it(rootFrame, block, begin, end);
        QTextFrame *containingFrame = frameAt(blockPos);
        if (containingFrame != rootFrame) {
            while (containingFrame->parentFrame() != rootFrame) {
                containingFrame = containingFrame->parentFrame();
   = containingFrame;
            it.cb = 0;
        return it;

    QTextFrame::iterator it(rootFrame, block, begin, end), = containingFrame and it.cb = 0 won't work, because they are all private. Even though I've include the widgets-private etc, these still can't be accessed directly.

    Recreating the iterator did not work either, because I cannot cast my iterator to QTextFrame::Iterator.

    So I'm trying to find a way around it, but therefore I have to understand it first. So far I have the following:

    rootFrame       = the rootframe of the textdocument
    begin           = the first position inside the rootframe
    end             = the last position +1 inside the rootframe
    block           = the textblock for the current textposition
    blockPos        = the position of the textblock
    it              = the iterator which has to be returned
    containingFrame = the textframe that contains the textblock

    Next, if the containingFrame is not the same as the rootFrame, it will enter a loop until the containingFrame is the direct child of rootFrame. After that is set to containingFrame. it.cb is set to 0. After that the variables in the iterator should have the following values (the red ones).

    QTextFrame::iterator::iterator(QTextFrame *frame, int block, int begin, int end)
        f = frame;    //->rootFrame
        b = begin;    //->first position inside rootFrame
        e = end;      //->last position + 1 inside rootFrame
        cf = [0];     //->containingFrame
        cb = [block]; //->0

    Now, how can I return a valid iterator which has the same effect as the mentioned private implementation?

    Or if someone has a better idea how to recreate the QTextDocumentLayout, all hints are welcome!