Home > Back-end >  Strange behavior of QTableView with text containing slashes
Strange behavior of QTableView with text containing slashes

Time:08-18

We recently ported a project from Qt 4.8 to Qt 5.15 (Qt 6 isn't an option for us yet due to dependencies).

We're finding that all our QTableViews behave strangely when an item's text contains slashes. Here is a small program that demonstrates 2 issues:

#include <QTableWidget>
#include <QAbstractItemModel>
#include <QApplication>
#include <QDebug>


int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    QTableWidget tbl;
    tbl.setTextElideMode(Qt::ElideLeft);
    tbl.setColumnCount(2);
    tbl.setRowCount(argc-1);
    for (int i = 1; i < argc;   i)
    {
        tbl.setItem( i-1, 0, new QTableWidgetItem(QString::number(i)) );
        tbl.setItem( i-1, 1, new QTableWidgetItem(argv[i]) );
    }
    tbl.show();
    
    auto* pModel = tbl.model();
    QString qstrMatch = "*single*file*";
    QModelIndexList lst = pModel->match(pModel->index(0,1), Qt::DisplayRole, qstrMatch, -1, Qt::MatchWildcard);
    qDebug() << lst.size() << "results";
    for (const QModelIndex& idx : lst)
    {
        qDebug() << argv[1 idx.row()];
    }

    return app.exec();
}

Suppose we run this program with the following 4 strings:

/path/to/design/patterns/singleton_file.txt
/path/to/design/patterns/observer_file.txt
just_single_name_file_no_path.txt
drill a single 1/4 inch hole then file here

1) Text elision

In Qt 4, the Qt::ElideLeft is honored in all cases:

enter image description here

But in Qt 5, it seems to have a problem whenever the text contains a slash:

enter image description here

A colleague noticed that one table was still working as expected, and found that the thing it did differently was to use a custom delegate. Sure enough, simply doing tbl.setItemDelegate(new QItemDelegate) on other tables fixes the issue for them as well. But this doesn't seem to make any sense.

2) Text matching

In Qt 4, the call to the match function does return 3 results as expected. In Qt 5, it only returns only 1 result - for the string not containing a slash.

Implementing the search with our own loop by using a QRegExp with Wildcard syntax works as expected, though.


enter image description here

So the "..." is not for "horizontal" text width elision but for "vertical" word wrapped truncation. The solution is to simply use: setWordWrap(false) on the QTableView.

The reason that using QItemDelegate made a difference appears to be that its implementation does simple elision before word wrapping, whereas QStyledItemDelegate (the default) first wraps and then only elides lines having very long words that could not be wrapped. (It's not clear which part of this was done differently in Qt 4: Possibly slashes were not considered as valid word boundaries for wrapping.)

2) Text matching

The underlying difference is in the QAbstractItemModel::match function: using a QRegExp with Wildcard syntax earlier vs. QRegularExpression::wildcardToRegularExpression now. As the documentation of the latter function states:

The transformation is targeting file path globbing, which means in particular that path separators receive special treatment.

This means that the text of every item is treated as a file path, where each * can match only within one single path component - it cannot span across slashes (it translates to something like [^/]* not just .*). So the wildcard pattern would need to have a particular number of slashes and stars in order to match the text.

So the only solution (if we choose to use QAbstractItemModel::match instead of rolling our own loops) appears to be to write our own wildcardToRegularExpression implementation that doesn't assume that the wildcards are being used for file paths, and hence does not treat path separators specially, and then use the Qt::RegularExpression match flag. Such a function would also be needed in other places where use of the now deprecated QRegExp with Wildcard syntax needs to be replaced with QRegularExpression.

  • Related