0
votes

I need to create a QML application with pages of items that are defined by a xml file. The xml must be parsed in C++. Each page of items will be a StackView page containing a ListView of the items. Each item on a page has several values defining text, colour, size, etc.

As a start, my DOM model creation is based on the Qt Simple DOM Model Example. The model is wrapped with a QAbstractItemModel. I've exposed the C++ model to QML using the rootContext->setContextProperty. I'm struggling with splitting the data between the StackView pages. I assume that I need to assign the different levels of the hierarchical model(page parent and item children) to different UserRoles in order to filter them to the QML views but I'm struggling to find any suitable examples of how to go about this.

So my question is:

Can you show me an example of assigning UserRoles to a C++ DOM Model and the associated data method for returning the item data by UserRole and hierarchical level?

or

Am I going in the wrong direction and there's a better way to achieve this?

1
Why using xml ? QML files is structured document in text file like XML, you can't use it directly ? If you want to use xml, why don't you use XmlListModel QML item to read your XML directly in QML ?gbdivers
@Guillaume Additional functionality required later on includes validation of the defining file on load against a schema and modification and write of the file. Therefore a DOM model seems like the best fit - XmlListModel provides a read-only model.Lucky Eddie

1 Answers

0
votes

OK, I've now got this going. After some more playing I decided to select the data by xml Node name - I used "Page" & "Item". If anyone else is looking at hierarchical models in C++ and views in QML the other key requirement I found to implementing a solution is the QML DelegateModel (formally VisualDataModel). Here are the snippets that directly answer the questions...

From DomModel.h

public:

    enum menuRoles
    {
        PageNumberRole = Qt::UserRole + 1,
        PageNameRole,
        ItemNumberRole,
        ItemNameRole
    };

...

QVariant data(const QModelIndex &index, int role) const;

...

protected:
    QHash<int, QByteArray> roleNames() const;

From DomModel.cpp

QVariant DomModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    else
    {
        DomItem *item = static_cast<DomItem*>(index.internalPointer());
        QDomNode node = item->node();
        if(node.nodeName() == "Page")
        {
            switch (role)
            {
            case PageNumberRole:
                return node.attributes().namedItem("number").nodeValue();
                break;

            case PageNameRole:
                return node.attributes().namedItem("name").nodeValue();
                break;

            default:
                return QVariant();
                break;
            }
        }
        else if(node.nodeName() == "Item")
        {
            switch (role)
            {
            case ItemNumberRole:
                return node.attributes().namedItem("number").nodeValue();
                break;

            case ItemNameRole:
                return node.attributes().namedItem("name").nodeValue();
                break;

            default:
                return QVariant();
                break;
            }
        }
        else
            return QVariant();
    }
}

...

QHash<int, QByteArray> DomModel::roleNames() const
{
    // This tells the subscribing views what data roles are available
    // Any changes must be reflected in the DomModel::data function
    QHash<int, QByteArray> roles;
    roles[PageNumberRole] = "pageNumber";
    roles[PageNameRole] = "pageName";
    roles[ItemNumberRole] = "itemNumber";
    roles[ItemNameRole] = "itemName";
    return roles;
}