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 child
Il 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 number
Finalement, 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 item
III. 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 list
L'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 !