How to process & export rich text in Qt

As a freelance Software Engineer, I get the chance to work on a vast set of technologies. For one of my clients, I often need to implement features in a C++ backend using the Qt framework.

If Qt makes lots of things easy with its built-in modules, sometimes it's unexpectedly hard to achieve something you thought would be trivial.
I just had an example of it for rich text processing. So let's dive in and see how you can iterate over rich text in Qt and export text and formatting information in a json.

Exporting rich text from Qt, your options

  1. Build your own HTML parser to handle the rich text.
    • pro: flexible
    • con: so flexible you're likely to have bug reports filled every week due to an unexpected input (:
  2. Use a QTextDocument and its setHtml method.
    • pro: handles the HTML processing for you.
    • con: requires to be familiar with QTextDocument sub-classes.

Dissecting the QTextDocument class

Extract from the Qt Doc, source: https://doc.qt.io/qt-5/qtextblock.html
_Extract from the Qt doc, source: https://doc.qt.io/qt-5/qtextblock.html

In a nutshell:

The tricky part is that formatting options are disseminated among the QTextBlock and the QTextFragment classes.

For example, you'll find alignment information (whether the text should be displayed on the left, right, center, or justified) in the format class of the QTextBlock. To be exact, you'll find this information in the QTextBlockFormat class, accessible from the QTextBlock.blockFormat() method.

On the other hand, if you want to know whether a portion of text is in italics, you'll have to look at the QTextFragment level. The styling class for the QTexFragment is the QTextCharFormat, accessible from the QTextFragment.charFormat() method.

C++ code snippet

For iterating over a rich text document and recovering text and formatting options in a json.

QJsonDocument exportRichTextToJson(QString myRichTextToProcess) {

    // 1. Make a document out of the rich text to enable programatic access to the document
    QTextDocument document;
    document.setHtml(myRichTextToProcess);
    if (document.isEmpty())
        return QJsonObject{};

    QJsonObject jsonObject;
    QJsonArray fragments;

    // 2. Iterate over the documents' blocks
    for (QTextBlock block = document.begin(); block != document.end(); block = block.next()) {
        QTextBlock::iterator frag;
        for (frag = block.begin(); !(frag.atEnd()); ++frag) {
            QJsonObject fragment;

            // Recover block level formatting options
            fragment["alignment"] = getBlockAlignment(block);  // custom function, returns `left`, `right`, `center`, or `justify`
            QTextFragment currentFragment = frag.fragment();

            if (currentFragment.isValid()) {                        
                fragment["text"] = currentFragment.text();

            // Recover fragment level formatting options                                
            const auto charFormat = currentFragment.charFormat();
            fragment["italics"] = charFormat.fontItalic();
            fragment["bold"] = isCharBold(charFormat);
            fragment["fontSize"] = charFormat.fontPointSize();
            fragments.append(fragment);
            }
        }
    }
    jsonObject["fragments"] = fragments;
    return jsonObject;
}

You'll only receive email when they publish something new.

More from Cpt. Kobra