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:
But in Qt 5, it seems to have a problem whenever the text contains a slash:
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.
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
.