Выбрать главу

01 void RegExpModeclass="underline" :setRootNode(Node *node)

02 {

03 delete rootNode;

04 rootNode = node;

05 reset();

06 }

При установке новой корневой вершины мы начинаем с удаления предыдущей корневой вершины (и всех ее дочерних вершин). Затем мы устанавливаем новое значение для корневой вершины и вызываем функцию reset() для уведомления всех представлений о необходимости обновления отображаемых данных всеми видимыми элементами.

01 QModelIndex RegExpModeclass="underline" :index(int row, int column,

02 const QModelIndex &parent) const

03 {

04 if (!rootNode)

05 return QModelIndex();

06 Node *parentNode = nodeFromIndex(parent);

07 return createIndex(row, column, parentNode->children[row]);

08 }

Функция index() класса QAbstractItemModel переопределяется. Она всегда вызывается, когда в модели или в представлении требуется создать индекс QModelIndex для конкретного дочернего элемента (или для элемента самого верхнего уровня, если parent имеет недействительное значение QModelIndex). В табличных и списковых моделях нам не требуется переопределять эту функцию, потому что обычно оказываются достаточным реализации по умолчанию моделей QAbstractListModel и QАЬstractTableModel.

В нашей реализации index(), если не задано дерево грамматического разбора, мы возвращаем недействительный индекс QModelIndex. В противном случае мы создаем QModelIndex с заданными строкой, столбцом и Node * для запрошенного дочернего элемента. В иерархических моделях знание строки и столбца элемента относительно своего родителя оказывается недостаточным для уникальной идентификации элемента; мы должны также знать, кто является его родителем. Для этого можно хранить в QModelIndex указатель на внутреннюю вершину. В объекте QModelIndex кроме номеров строк и столбцов допускается хранение указателя void * или значения типа int.

Указатель Node * на дочерний элемент можно получить из списка дочерних элементов children родительской вершины. Указатель на родительскую вершину извлекается из индекса модели parent, используя закрытую функцию nodeFromIndex():

01 Node *RegExpModeclass="underline" :nodeFromIndex(

02 const QModelIndex &index) const

03 {

04 if (index.isValid()) {

05 return static_cast<Node *>(index.internalPointer());

06 } else {

07 return rootNode;

07 }

Функция nodeFromIndex() приводит тип void * заданного индекса в тип Node * или возвращает указатель на корневую вершину, если индекс недостоверен, поскольку недостоверный индекс модели используется для представления корня модели.

01 int RegExpModeclass="underline" :rowCount(const QModelIndex

02 &parent) const

03 {

04 Node *parentNode = nodeFromlndex(parent);

05 if (!parentNode)

06 return 0;

07 return parentNode->children.count();

08 }

Число строк для заданного элемента определяется просто количеством дочерних элементов.

01 int RegExpModeclass="underline" :columnCount(const QModelIndex &

02 /* родительский элемент */) const

03 {

04 return 2;

05 }

Число столбцов фиксировано и равно 2. Первый столбец содержит типы вершин; второй столбец содержит значения вершин.

01 QModelIndex RegExpModeclass="underline" :parent(const QModelIndex

02 &child) const

03 {

04 Node*node = nodeFromIndex(child);

05 if (!node)

06 return QModelIndex();

07 Node *parentNode = node->parent;

08 if (!parentNode)

09 return QModelIndex();

10 Node *grandparentNode = parentNode->parent;

11 if (!grandparentNode)

12 return QModelIndex();

13 int row = grandparentNode->children.indexOf(parentNode);

14 return createIndex(row, child.column(), parentNode);

15 }

Получить QModelIndex родительского элемента из дочернего немного сложнее, чем найти дочерний элемент родителя. Можно легко получить родительскую вершину, применяя сначала функцию nodeFromIndex() и поднимаясь затем вверх с помощью указателя на родительский элемент, но для получения номера строки (позиции родительской верщины в соответствующем списке дочерних вершин) мы должны перейти к родителю родительского элемента и найти в его списке дочерних элементов значение индекса первого родителя (родителя исходной дочерней вершины).