Search code examples
c++qtqabstractitemmodelqabstractitemview

How to hyperlink to an item in a QAbstractItemModel?


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.


Solution

  • 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.