Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTextCursor and html tables



  • I have a very strange problem with an existing Qt5.10 Applciation and QTextCursor.

    In the application, we have a text input area where the user can paste text from antwhere (word doc, web pages .. etc).

    We also need to sanatize this pasted text before the appliction can accept it.

    Part of this sanatization requires us to use a cursor to go through the document - this is required. But certain users of the application have reported hangs in the app when certain rich text gets pasted. We have narrowed the text that causes the to an odd sequence - and empty table followed by text.

    Let me give an example

    #include "qtguiapplication1.h"
    
    #include <QTextEdit>
    #include <QTextDocument>
    #include <QTextDocumentFragment>
    #include <QTextCursor>
    
    
    QtGuiApplication1::QtGuiApplication1(QWidget *parent)
        : QMainWindow(parent)
    {
        ui.setupUi(this);
    
        QTextEdit textEdit{};
    
        const std::string sourceMimeDataInHtmlFormat = R"(
                    <html>
                       <body>
                          <table>
                                <tr>
                                   <td>
                                   </td>
                                </tr>
                          </table>
                          foo
                       </body>
                    </html>
                )";
    
    
        QString testHtml = QString::fromStdString(sourceMimeDataInHtmlFormat);
        textEdit.insertHtml(testHtml);
    
        QTextCursor cursor{};
        while ((cursor = textEdit.document()->find("foo")) != QTextCursor{})
        {
            cursor.select(QTextCursor::BlockUnderCursor);
            cursor.removeSelectedText();
        }
    }
    

    So as you can see, sourceMimeDataInHtmlFormat is a simple table with an empty cell followed by the word "foo"
    The simple while loop gets stuck in an infinite loop with the above code.

    If the table cell contains text .... any text, the problem doesn't happen! While loop behaves as expected.

    Any idea what could be the problem here?



  • Also tried it on Qt5.15 and the problem is there as well!


  • Lifetime Qt Champion

    Hi
    It seems it's not able to select as its not a block for it.
    So BlockUnderCursor fails to select the text and it can find it over and over.
    (checked with qDebug() << "sel:" << cursor.selectedText(); )

    so if you do LineUnderCursor instead.

    QTextCursor cursor{};
    while ((cursor = ui->textEdit->document()->find("foo")) != QTextCursor{})
    {
    cursor.select(QTextCursor::LineUnderCursor);
    cursor.removeSelectedText();
    qDebug() << "this" << cursor.selectedText();
    }

    it works.

    So it seems the empty table somehow makes BlockUnderCursor fail
    but im not sure why exactly.



  • Thanks @mrjj - that has somewhat solved it.

    It seems that cursor.select(QTextCursor::LineUnderCursor) behaves slightly different to cursor.select(QTextCursor::BlockUnderCursor) for certain input types.
    But it certainly helps me. So thanks again.

    This is what I have now:

        QTextEdit textEdit{};
    
        const std::string sourceMimeDataInHtmlFormat = R"(
                    <html>
                       <body>
                          <table>
                                <tr>
                                   <td>
                                   </td>
                                </tr>
                          </table>
                          <p>foo</p>
                          <p>bar</p>
                          <p>foo</p>
                          <p>bar</p>
                       </body>
                    </html>
                )";
    
    
        QString testHtml = QString::fromStdString(sourceMimeDataInHtmlFormat);
        textEdit.insertHtml(testHtml);
    
        QTextCursor cursor{};
    
        QTextCursor::SelectionType selectionType = QTextCursor::BlockUnderCursor;
        while ((cursor = textEdit.document()->find("foo")) != QTextCursor{})
        {
            cursor.select(selectionType);
            if (cursor.selectedText().isEmpty())
            {
                // We can get stuck in this while loop forever for certain types of HTML.
                // Change the selection type for the next time through the loop so we are sure to select the text
                selectionType = QTextCursor::LineUnderCursor;
            }
            else
            {
                selectionType = QTextCursor::BlockUnderCursor;
            }
            cursor.removeSelectedText();
        }
    
    ```

  • Lifetime Qt Champion

    @Mise
    Hi
    hopefully there wont be inputs where LineUnderCursor will eat too much :)


Log in to reply