I. L'article original▲
Cet article est la traduction de l'article Internal representation de Witold Wysota.
II. Travailler sur un arbre▲
La première chose à faire est de créer l'infrastructure nécessaire pour opérer sur la structure et sa hiérarchie. Comme on veut une structure arborescente, chaque nœud doit stocker une liste de ses enfants et un pointeur au nœud parent, ainsi que quelques méthodes.
QwwGLModelNode *_parent; // parent item
QList<QwwGLModelNode> _children; // child items
void setParent(QwwGLModelNode*); // set as parent
QwwGLModelNode* parent() const; // get the parent
const QList<QwwGLModelNode>& children() const; // get list of children
int addChild(QwwGLModelNode*); // add a childIl est aussi pratique de récupérer un enfant particulier et de savoir combien d'ancêtres il a (il sera donc plus facile, a posteriori, de fournir le nombre de lignes pour les index).
QwwGLModelNode* child(uint n); // return a child
uint row(); // return row numberFinalement, il est bon d'être à même de créer des items et, pour simplifier, on va fournir une manière de créer l'arbre en même temps.
QwwGLModelNode(QwwGLModelNode *p=0); // create itemIII. Les données spécifiques à GLModel▲
Après ça, on peut ajouter toutes les choses que l'on veut explicitement pour le modèle de données - le type des items et ses attributs, identifiés par des noms. Aussi, des accesseurs en écriture et en lecture doivent être implémentés.
QwwGLModelType _type; // item type
QMap<QString> _attributes; // attribute list
QwwGLModelType type() const; // get the type
void setType(QwwGLModelType); // set a type
void setAttribute(const QString &name, // set an attribute
const QVariant &value);
QVariant attribute(const QString &name); // get a single attribute
const QMap<QString> &attributes() const; // get attribute listL'implémentation de ces méthodes est triviale et ne sera donc pas commentée.
IV. La classe QwwGLModelNode▲
Au final, on obtient une classe du genre :
class QwwGLModelNode {
public:
QwwGLModelNode(QwwGLModelNode *p=0) {
setParent(p);
if(p)
_parent->addChild(this);
}
~QwwGLModelNode(){
qDeleteAll(_children); // delete all child items
}
QwwGLModelNode *child(uint n) {
return _children.at(n);
}
uint row(){
Q_ASSERT(_parent); // make sure we have a parent
return _parent->children().indexOf(this);
}
void setParent(QwwGLModelNode *p) {
_parent = p;
}
QwwGLModelNode* parent() const {
return _parent;
}
const QList<QwwGLModelNode*>& children() const {
return _children;
}
int addChild(QwwGLModelNode *ch) {
_children << ch;
return _children.size()-1;
}
QwwGLModelType type() const {
return _type;
}
void setType(QwwGLModelType t) {
_type = t;
}
void setAttribute(const QString &name, const QVariant &value) {
_attributes[name] = value;
}
QVariant attribute(const QString &name) {
if(!_attributes.contains(name)) // if attribute doesn't exist
return QVariant(); // return an empty value
return _attributes[name];
}
const QMap<QString> &attributes() const {
return _attributes;
}
private:
QwwGLModelNode *_parent;
QList<QwwGLModelNode*> _children;
QwwGLModelType _type;
QMap<QString> _attributes;
};V. Types d'items▲
Maintenant, il faut décider comment créer les différents items. Il y a deux approches possibles. La première est de fournir des méthodes pour créer les différents types d'item et, en utilisant les méthodes existantes, remplir les données requises. L'autre est de dériver le nœud pour créer autant de classes enfant que de types d'item à utiliser. Une méthode plus rapide se passe de cette dérivation, mais les méthodes virtuelles pourraient se révéler très utiles plus tard, en fonction de ce qu'on veut faire avec le modèle. Comme ceci n'est qu'un exemple, évitons de créer trop de classes.
VI. Tests▲
Maintenant, on devrait pouvoir compiler et tester la classe. Un simple main() devrait faire l'affaire.
typedef int QwwGLModelType;
#include "qwwglmodelnode.h"
int main(){
QwwGLModelNode *n = new QwwGLModelNode();
for(int i=0;i<10;i++){
QwwGLModelNode *cn = new QwwGLModelNode(n);
for(int i=0;i<3;i++){
new QwwGLModelNode(cn);
}
}
delete n;
return 0;
}Si tout se passe bien, le code devrait compiler et se lancer sans de souci.
La prochaine fois, on décrira la manière d'implémenter la partie de lecture du modèle lui-même. À ce point, on pourra le voir en action.
VII. Remerciements▲
Merci à Louis du Verdier et à Claude Leloup pour leur relecture !





