0

Qt versions used: 4.7.1 and 4.8

I store hierarchical data as nodes in a model that is derived from QAbstractItemModel. I have a QTreeView in my application GUI to display the hierarchical data. (The data being hierarchical may not be essential for this question; the general problem I have applies to any kind of data in any model and view.)

I have a textbox (a QPlainTextEdit widget, but that is not essential) in my application GUI that displays a hyperlink. When the user clicks on the hyperlink, I can intercept that and obtain the URL of the hyperlink. So far, so good.

When I intercept that hyperlink, I am going to make the QTreeView navigate to a particular node, expanding its parents as needed so that the user can see it.

The URL of the hyperlink will be in format that lets me know a node is being asked for, and will contain identifying information about that particular node. For example:

<a href="node://something">Click me to see node A</a>

So, the question is: What is the something that can identify that particular node, and that can be encoded as a text string?

I have been reading about QPersistentModelIndex. It sounds like a reasonable thing to start with. At the time I format the hyperlink, I would definitely know the QModelIndex of the particular node, and can construct a QPersistentModelIndex from it. But I am getting lost on how to convert that to a string, and then later convert the string back to a QModelIndex from which I can deduce the particular node.

Any suggestions are appreciated.

Mike Finch
  • 746
  • 1
  • 7
  • 20

2 Answers2

2

You could declare a custom data role in your model, and for each of your items set a unique value for this role.

//MyModel.h
class MyModel : public QAbstractItemModel
{
    enum MyRoles {
         UrlRole = Qt::UserRole
    };
    // (...)
}

//MyModel.cpp
QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == UrlRole)
    {
        return "uniqueUrl"; //Up to you to decide what you return here
    }
    // (...)
}

Then when performing your search, simply use your model's match function to match your unique string and take the first index from the list.

QModelIndex MyDialog::getIndexForUrl(QString myUrl)
{
    QModelIndex index = QModelIndex();
    QModelIndexList resultList = ui->treeView->model()->match(QModelIndex(),
        MyModel::UrlRole, "uniqueUrl", 1, Qt::MatchFixedString | Qt::MatchCaseSensitive);

    if (!resultList.empty())
    {
        index = resultList.first();
    }
    return index;
}

You may need to adjust the flags and the start index depending on how you defined your model.

Cendolt
  • 228
  • 3
  • 10
  • 1
    Thank you, @Cendolt. That is an excellent idea. I did not know about the `QAbstractItemModel::match()` method. Your example will likely work as-is for flat data model. For a hierarchical tree-like data model, I needed a few tweaks, which I will post in a separate answer. – Mike Finch Apr 25 '19 at 15:08
1

Using QAbstractItemModel::match() to search for items in the data model via a custom data role, as suggested by @Cendolt, is an excellent idea. I was able to use that idea without having to override match() in my custom data model.

The parameters I provide to QAbstractItemModel::match() are a little different, though. In combination with the rest of @Cendolt's example, the following works for my situation.

QAbstractItemModel * pModel = ...;

// Start searching from the root of the tree.
QModelIndex startIndex = pModel->index( 0, 0 );

QModelIndexList results = p->match(
  startIndex,
  MyModel::UrlRole,
  "uniqueUrl",
  1,
  Qt::MatchRecursive );

Valid start index

Specifying a starting QModelIndex with zeros for the row and column is essential to make the search proceed at all. When I used a default constructed QModelIndex, the search never called my model's data() method. I believe that is because the default constructed QModelIndex has -1 for the row and column, which makes it an invalid index. In the code for QAbstractItemModel::match() ({Qt dir}\src\corelib\kernel\qabstractitemmodel.cpp), notice that it skips calling data() if the index is invalid.

Match flags

Specifically for hierarchical data, using the Qt::MatchRecursive flag is essential. Otherwise, the search does not crawl into child nodes.

Mike Finch
  • 746
  • 1
  • 7
  • 20