Remove references to "How to Learn Qt", since that is in qtdoc repo.
[profile/ivi/qtbase.git] / src / widgets / doc / src / addressbook-fr.qdoc
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the documentation of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** GNU Free Documentation License
10 ** Alternatively, this file may be used under the terms of the GNU Free
11 ** Documentation License version 1.3 as published by the Free Software
12 ** Foundation and appearing in the file included in the packaging of
13 ** this file.
14 **
15 ** Other Usage
16 ** Alternatively, this file may be used in accordance with the terms
17 ** and conditions contained in a signed written agreement between you
18 ** and Nokia.
19 **
20 **
21 **
22 **
23 **
24 ** $QT_END_LICENSE$
25 **
26 ****************************************************************************/
27
28 /*!
29     \page tutorials-addressbook-fr.html
30
31     \title Tutoriel "Carnet d'adresses"
32     \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt.
33
34     Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur)
35     à l'aide des outils fournis par la plateforme multiplate-forme Qt.
36
37     \image addressbook-tutorial-screenshot.png
38
39     Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies 
40     par Qt, tel que:
41
42     \list
43     \li Les Widgets et leur mise en page à l'aide des layouts
44     \li Les signaux et slots
45     \li Les structures de données de collections
46     \li Les entrées/sorties
47     \endlist
48
49     Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook
50
51     Les chapitres du tutoriel:
52
53     \list 1
54     \li \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur}
55     \li \l{tutorials/addressbook-fr/part2}{Ajouter des adresses}
56     \li \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments}
57     \li \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses}
58     \li \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche}
59     \li \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement}
60     \li \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées}
61     \endlist
62
63     La petite application que nous développerons ici ne possède pas tous les éléments
64     des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base
65     utilisées dans les applications plus complexes.
66
67     Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple
68     "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant
69     les menus et barres d'outils, la barre d'état, etc.
70
71 */
72
73 /*!
74     \page tutorials-addressbook-fr-part1.html
75
76     \example tutorials/addressbook-fr/part1
77     \title Carnet d'adresses 1 - Conception de l'interface utilisateur
78
79     La première partie de ce tutoriel traite de la conception d'une interface graphique
80     (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses.
81
82     La première étape dans la création d'applications graphiques est la conception de
83     l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels
84     et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base.
85     Le résultat attendu est illustré par la capture d'écran ci-dessous.
86
87     \image addressbook-tutorial-part1-screenshot.png
88
89     Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel,
90     ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet
91     QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un
92     contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous.
93
94     \image addressbook-tutorial-part1-labeled-screenshot.png
95
96     Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses:
97
98     \list
99         \li \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook,
100         \li \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe
101             \c AddressBook
102         \li \c{main.cpp} - le fichier qui contient la méthode \c main() , et
103         une instance de la classe \c AddressBook.
104     \endlist
105
106     \section1 Programmation en Qt - héritage
107
108
109     Lorsque l'on écrit des programmes avec Qt, on a généralement recours à
110     l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités.
111     C'est l'un des concepts fondamentaux de la création de widgets personnalisés
112     ou de collections de widgets. Utiliser l'héritage afin de compléter
113     ou modifier le comportement d'un widget présente les avantages suivants:
114
115     \list
116     \li La possibilité d'implémenter des méthodes virtuelles et des méthodes
117     virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité
118     d'utiliser l'implémentation de la classe mère si besoin est.
119     \li Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe,
120     afin que les autres parties de l'application n'aient pas à se soucier de chacun des
121     widgets qui forment l'interface utilisateur.
122     \li La classe fille peut être utilisée pour créer de nombreux widgets personnalisés
123     dans une même application ou bibliothèque, et le code de la classe fille peut être
124     réutilisé dans d'autres projets
125     \endlist
126
127     Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous 
128     partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités.
129     La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un
130     widget carnet d'adresses basique.
131
132
133     \section1 La classe AddressBook
134
135     Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de
136     définir la classe \c AddressBook.
137
138     On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer
139     un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe
140     exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que
141     l'internationalisation, bien que nous ne les utilisions pas à ce stade.
142
143     \snippet tutorials/addressbook-fr/part1/addressbook.h class definition
144
145     La classe contient les déclarations de \c nameLine et \c addressText,
146     les instances privées de QLineEdit et QTextEdit mentionnées précédemment.
147     Vous verrez, dans les chapitres à venir que les informations contenues
148     dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes
149     du carnet d'adresses.
150
151     Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser 
152     puisque nous n'aurons pas besoin d'y faire référence après leur création.
153     La façon dont Qt gère la parenté des objets est traitée dans la section suivante.
154
155     La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt.
156     Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous 
157     permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}.
158
159     Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons
160     passer à l'implémentation du fichier \c addressbook.cpp.
161
162     \section1 Implémentation de la classe AddressBook
163
164     Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent.
165     Par convention, on passe ce paramètre au constructeur de la classe mère.
166     Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile
167     pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent,
168     tous ses enfants seront détruits égalament.
169
170
171     \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
172
173     à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux
174     QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et
175     \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite
176     de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie
177     la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{<insérer
178     la traduction ici>}, permettant de repérer les objets QString à considérer
179     pour traduire une application. Vous remarquerez, dans les chapitres à venir
180     comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois
181     que l'on utilise une chaîne susceptible d'être traduite.
182
183     Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les
184     agencements ou layouts. Qt fournit trois classes principales de layouts pour
185     contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout.
186
187     \image addressbook-tutorial-part1-labeled-layout.png
188
189     On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière
190     structurée. QGridLayout divise l'espace disponible en une grille, et place les
191     widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne.
192     Le diagramme ci-dessus présente les cellules et la position des widgets, et cette
193     organisation est obtenue à l'aide du code suivant:
194
195     \snippet tutorials/addressbook/part1/addressbook.cpp layout
196
197     On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop
198     comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré
199     verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt,
200     consultez la section \l{Layout Management}.
201
202     Afin d'installer l'objet layout dans un widget, il faut appeler la méthode
203     \l{QWidget::setLayout()}{setLayout()} du widget en question:
204
205     \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
206
207     Enfin, on initialise le titre du widget à "Simple Address Book"
208
209     \section1 Exécution de l'application
210
211     Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette
212     fonction, on crée une instance de QApplication, \c app. QApplication se charge de
213     des ressources communes à l'ensemble de l'application, tel que les polices de
214     caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements.
215     De ce fait, il y a toujours un objet QApplication dans toute application graphique en Qt.
216
217     \snippet tutorials/addressbook/part1/main.cpp main function
218
219     On construit un nouveau widget \c AddressBook sur la pile et on invoque
220     sa méthode \l{QWidget::show()}{show()} pour l'afficher.
221     Cependant, le widget ne sera pas visible tant que la boucle d'évènements
222     n'aura pas été lancée. On démarre la boucle d'évènements en appelant la
223     méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé
224     par cette méthode est lui même utilisé comme valeur de retour pour la méthode
225     \c main().
226     On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin
227     du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants
228     sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire.
229 */
230
231 /*!
232     \page tutorials-addressbook-fr-part2.html
233
234     \example tutorials/addressbook-fr/part2
235     \title Carnet d'adresses 2 - Ajouter des adresses
236
237     La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon
238     d'interactivité.
239
240     \image addressbook-tutorial-part2-add-contact.png
241
242     Nous allons fournir un bouton que l'utilisateur peut
243     cliquer pour ajouter un nouveau contact. Une structure de données est aussi
244     nécessaire afin de pouvoir stocker les contacts en mémoire.
245
246     \section1 Définition de la classe AddressBook
247
248     Maintenant que nous avons mis en place les labels et les champs de saisie,
249     nous ajoutons les boutons pour compléter le processus d'ajout d'un contact.
250     Cela veut dire que notre fichier \c addressbook.h a maintenant trois
251     objets QPushButton et trois slots publics correspondant.
252
253     \snippet tutorials/addressbook/part2/addressbook.h slots
254
255     Un slot est une méthode qui répond à un signal. Nous allons
256     voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}.
257     Pour une explication détaillée du concept de signal et slot, vous pouvez
258     vous référer au document \l{Signals and Slots}.
259
260     Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton
261     sont maintenant inclus dans la déclaration des variables privées, avec
262     \c nameLine et \c addressText du chapitre précédent.
263
264     \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
265
266     Nous avons besoin d'un conteneur pour stocker les contacts du carnet
267     d'adresses, de façon à pouvoir les énumérer et les afficher.
268     Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker
269     des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact
270     est la \e{valeur}.
271
272     \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
273
274     Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress.
275     Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact
276     affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables
277     si l'utilisateur clique sur "Cancel", il est possible de revenir
278     à l'affichage du dernier contact.
279
280     \section1 Implémentation de la classe AddressBook
281
282     Dans le constructeur de \c AddressBook, \c nameLine et
283     \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage
284     mais pas la modification du contact courant.
285
286     \dots
287     \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
288     \dots
289     \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
290
291     Ensuite, nous instancions les boutons \c addButton, \c submitButton, et
292     \c cancelButton.
293
294     \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
295
296     Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()}
297     {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant
298     \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque 
299     l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact()
300     décrite plus loin.
301
302     \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
303
304     Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton 
305     au slot qui gèrera l'action.
306     L'image ci-dessous illustre ceci:
307
308     \image addressbook-tutorial-part2-signals-and-slots.png
309
310     Ensuite, nous arrangeons proprement les boutons sur la droite du widget
311     AddressBook, et nous utilisons un QVBoxLayout pour les aligner verticalement.
312
313     \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
314
315     La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour
316     assurer que les boutons ne sont pas répartis uniformément, mais regroupés
317     dans la partie supperieure du widget. La figure ci-dessous montre la différence
318     si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas.
319
320     \image addressbook-tutorial-part2-stretch-effects.png
321
322     Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant
323     \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les
324     mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout.
325
326     \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
327
328     Les coordonnées du layout global ressemblent maintenant à ça:
329
330     \image addressbook-tutorial-part2-labeled-layout.png
331
332     Dans la méthode \c addContact(), nous stockons les détails du dernier
333     contact affiché dans \c oldName et \c oldAddress. Ensuite, nous
334     vidons ces champs de saisie et nous désactivons le mode
335     lecture seule. Le focus est placé sur \c nameLine et on affiche
336     \c submitButton et \c cancelButton.
337
338     \snippet tutorials/addressbook/part2/addressbook.cpp addContact
339
340     La méthode \c submitContact() peut être divisée en trois parties:
341
342     \list 1
343     \li Nous extrayons les détails du contact depuis \c nameLine et \c addressText
344     et les stockons dans des objets QString. Nous les validons pour s'assurer
345     que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie
346     vides; sinon un message est affiché avec QMessageBox pour rappeller à
347     l'utilisateur que les deux champs doivent être complétés.
348
349     \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
350
351     \li Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts
352     existant n'entre en conflit avec le nouveau, nous l'ajoutons à
353     \c contacts et nous affichons un QMessageBox pour informer l'utilisateur
354     que le contact a été ajouté.
355
356     \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
357
358     Si le contact existe déjà, nous affichons un QMessageBox pour informer
359     l'utilisateur du problème.
360     Notre objet \c contacts est basé sur des paires clé-valeur formés par
361     le nom et l'adresse, nous voulons nous assurer que la \e clé est unique.
362
363     \li Une fois que les deux vérifications précédentes ont été traitées,
364     nous restaurons les boutons à leur état normal à l'aide du code
365     suivant:
366
367     \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
368
369     \endlist
370
371     La capture d'écran ci-dessous montre l'affichage fournit par un objet
372     QMessageBox, utilisé ici pour afficher un message d'information
373     à l'utilisateur:
374
375     \image addressbook-tutorial-part2-add-successful.png
376
377     La méthode \c cancel() restaure les détails du dernier contact, active
378     \c addButton, et cache \c submitButton et \c cancelButton.
379
380     \snippet tutorials/addressbook/part2/addressbook.cpp cancel
381
382     L'idée générale pour augmenter la flexibilité lors de l'ajout d'un 
383     contact est de donner la possiblité de cliquer sur "Add" 
384     ou "Cancel" à n'importe quel moment.
385     L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées
386     jusqu'ici:
387
388     \image addressbook-tutorial-part2-add-flowchart.png
389 */
390
391 /*!
392     \page tutorials-addressbook-fr-part3.html
393
394     \example tutorials/addressbook-fr/part3
395     \title Carnet d'adresses 3 - Navigation entre les éléments
396
397     L'application "Carnet d'adresses" est maintenant à moitié terminée. Il
398     nous faut maintenant ajouter quelques fonctions pour naviguer entre
399     les contacts. Avant de commencer, il faut se décider sur le type de structure de
400     données le plus approprié pour stocker les contacts.
401
402     Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur,
403     avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur.
404     Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les
405     entrées, quelques améliorations sont nécessaires.
406
407     Nous améliorerons le QMap en le faisant ressembler à une structure de données
408     similaire à une liste liée, où tous les éléments sont connectés, y compris
409     le premier et le dernier élément. La figure ci-dessous illustre cette structure
410     de donnée.
411
412     \image addressbook-tutorial-part3-linkedlist.png
413
414     \section1 Définition de la classe AddressBook
415
416     Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons
417     besoin de deux slots supplémentaires dans notre classe \c AddressBook:
418     \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h:
419
420     \snippet tutorials/addressbook/part3/addressbook.h navigation functions
421
422     Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons
423     donc les variables privées \c nextButton et \c previousButton.
424
425     \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
426
427     \section1 Implémentation de la classe AddressBook
428
429     A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous
430     instancions \c nextButton et \c previousButton et nous les désactivons
431     par défaut. Nous faisons ceci car la navigation ne doit être activée
432     que lorsqu'il y a plus d'un contact dans le carnet d'adresses.
433
434     \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
435
436     Nous connectons alors ces boutons à leur slots respectifs:
437
438     \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
439
440     L'image ci-dessous montre l'interface utilisateur que nous allons créer.
441     Remarquez que cela ressemble de plus en plus à l'interface du programme
442     complet.
443
444     \image addressbook-tutorial-part3-screenshot.png
445
446     Nous suivons les conventions pour les fonctions \c next() et \c previous()
447     en plaçant \c nextButton à droite et \c previousButton à gauche. Pour
448     faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour
449     placer les widgets côte à côte:
450
451     \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
452
453     L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout.
454
455     \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
456
457     La figure ci-dessous montre les systèmes de coordonnées pour les widgets du
458     \c mainLayout.
459     \image addressbook-tutorial-part3-labeled-layout.png
460
461     Dans notre méthode \c addContact(), nous avons desactivé ces boutons 
462     pour être sûr que l'utilisateur n'utilise pas la navigation lors de 
463     l'ajout d'un contact.
464
465     \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
466
467     Dans notre méthode \c submitContact(), nous activons les boutons de
468     navigation, \c nextButton et \c previousButton, en fonction de la
469     taille de \c contacts. Commen mentionné plus tôt, la navigation n'est 
470     activée que si il y a plus d'un contact dans le carnet d'adresses.
471     Les lignes suivantes montrent comment faire cela:
472
473     \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
474
475     Nous incluons aussi ces lignes de code dans le bouton \c cancel().
476
477     Souvenez vous que nous voulons émuler une liste-liée ciruculaire à
478     l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur 
479     sur \c contact dans la méthode \c next(), et ensuite:
480
481     \list
482         \li Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons
483         \li Si l'itérateur est à la fin de \c contacts, nous changeons sa position
484         jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap 
485         fonctionne comme une liste circulaire.
486     \endlist
487
488     \snippet tutorials/addressbook/part3/addressbook.cpp next() function
489
490     Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts,
491     nous affichons son contenu sur \c nameLine et \c addressText.
492
493     De la même façon, pour la méthode \c previous(), nous obtenons un 
494     itérateur sur \c contacts et ensuite:
495
496     \list
497         \li Si l'itérateur est à la fin de \c contacts, on réinitialise
498            l'affichage et on retourne.
499         \li Si l'itérateur est au début de \c contacts, on change sa
500            position jusqu'à la fin
501         \li Ensuite, on décrémente l'itérateur
502     \endlist
503
504     \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
505
506     à nouveau, nous affichons le contenu de l'objet courant dans \c contacts.
507
508 */
509
510 /*!
511
512     \page tutorials-addressbook-fr-part4.html
513
514     \example tutorials/addressbook-fr/part4
515     \title Carnet d'Adresses 4 - éditer et supprimer des adresses
516
517
518     Dans ce chapitre, nous verrons comment modifier les données des contacts
519     contenus dans l'application carnet d'adresses.
520
521
522     \image addressbook-tutorial-screenshot.png
523
524     Nous avons maintenant un carnet d'adresses qui ne se contente pas de
525     lister des contacts de façon ordonnée, mais permet également la 
526     navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et
527     supprimer, afin que les détails associés à un contact puissent être
528     modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère
529     modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux
530     modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas
531     définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les
532     boutons correspondants manuellement, au prix de multiples redondances dans
533     le code.
534
535     Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles.
536
537     \list
538         \li \c{NavigationMode},
539         \li \c{AddingMode}, et
540         \li \c{EditingMode}.
541     \endlist
542
543     \section1 Définition de la classe AddressBook
544
545     Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode :
546
547     \snippet tutorials/addressbook/part4/addressbook.h Mode enum
548
549     On ajoute également deux nouveaux slots, \c editContact() et
550     \c removeContact(), à notre liste de slots publics.
551
552     \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
553
554     Afin de basculer d'un mode à l'autre, on introduit la méthode
555     \c updateInterface() pour contrôller l'activation et la désactivation de
556     tous les objets QPushButton. On ajoute également deux nouveaux boutons,
557     \c editButton et \c removeButton, pour les fonctions d'édition
558     et de suppression mentionnées plus haut.
559
560     \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
561     \dots
562     \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
563     \dots
564     \snippet tutorials/addressbook/part4/addressbook.h mode declaration
565
566     Enfin, on déclare \c currentMode pour garder une trace du mode 
567     actuellement utilisé.
568
569     \section1 Implémentation de la classe AddressBook
570
571     Il nous faut maintenant implémenter les fonctionnalités de changement de
572     mode de l'application carnet d'adresses. Les boutons \c editButton et
573     \c removeButton sont instanciés et désactivés par défaut, puisque le
574     carnet d'adresses démarre sans aucun contact en mémoire.
575
576     \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
577
578     Ces boutons sont ensuite connectés à leurs slots respectifs,
579     \c editContact() et \c removeContact(), avant d'être ajoutés à
580     \c buttonLayout1.
581
582     \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
583     \dots
584     \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
585
586     La methode \c editContact() place les anciens détails du contact dans
587     \c oldName et \c oldAddress, avant de basculer vers le mode
588     \c EditingMode. Dans ce mode, les boutons \c submitButton et
589     \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent
590     modifier les détails du contact et cliquer sur l'un de ces deux boutons
591     par la suite.
592
593     \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
594
595     La méthode \c submitContact() a été divisée en deux avec un bloc
596     \c{if-else}. On teste \c currentMode pour voir si le mode courant est
597     \c AddingMode. Si c'est le cas, on procède à l'ajout.
598
599     \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
600     \dots
601     \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
602
603     Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le
604     cas, on compare \c oldName et \c name. Si le nom a changé, on supprime
605     l'ancien contact de \c contacts et on insère le contact mis a jour.
606
607     \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
608
609     Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à
610     \c address), on met à jour l'adresse du contact. Enfin on règle
611     \c currentMode à \c NavigationMode. C'est une étape importante puisque
612     c'est cela qui réactive tous les boutons désactivés.
613
614     Afin de retirer un contact du carnet d'adresses, on implémente la méthode
615     \c removeContact(). Cette méthode vérifie que le contact est présent dans
616     \c contacts.
617
618     \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
619
620     Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant
621     confirmation de la suppression à l'utilisateur. Une fois la confirmation
622     effectuée, on appelle \c previous(), afin de s'assurer que l'interface
623     utilisateur affiche une autre entrée, et on supprime le contact en
624     utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un
625     souci pratique, on informe l'utilisateur de la suppression par le biais
626     d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette
627     méthode sont représentées ci-dessous.
628
629     \image addressbook-tutorial-part4-remove.png
630
631     \section2 Mise à jour de l'Interface utilisateur
632
633     On a évoqué plus haut la méthode \c updateInterface() comme moyen
634     d'activer et de désactiver les différents boutons de l'interface en
635     fonction du mode. Cette méthode met à jour le mode courant selon
636     l'argument \c mode qui lui est passé, en l'assignant à \c currentMode,
637     avant de tester sa valeur.
638
639     Chacun des boutons est ensuite activé ou désactivé, en fonction du mode.
640     Le code source pour les cas \c AddingMode et \c EditingMode est visible 
641     ci-dessous:
642
643     \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
644
645     Dans le cas de \c NavigationMode, en revanche, des tests conditionnels
646     sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de
647     s'assurer que les boutons \c editButton et \c removeButton ne sont activés
648     que s'il existe au moins un contact dans le carnet d'adresses;
649     \c nextButton et \c previousButton ne sont activés que lorsqu'il existe
650     plus d'un contact dans le carnet d'adresses.
651
652     \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
653
654     En effectuant les opérations de réglage du mode et de mise à jour de
655     l'interface utilisateur au sein de la même méthode, on est à l'abri de
656     l'éventualité où l'interface utilisateur se "désynchronise" de l'état
657     interne de l'application.
658
659 */
660
661 /*!
662     \page tutorials-addressbook-fr-part5.html
663
664     \example tutorials/addressbook-fr/part5
665     \title Carnet d'adresse 5 - Ajout d'une fonction de recherche
666
667     Dans ce chapitre, nous allons voir les possibilités pour rechercher
668     des contacts dans le carnet d'adresse.
669
670     \image addressbook-tutorial-part5-screenshot.png
671
672     Plus nous ajoutons des contacts dans l'application, plus
673     il devient difficile de naviguer avec les boutons \e Next et \e Previous.
674     Dans ce cas, une fonction de recherche serait plus efficace pour rechercher
675     les contacts.
676     La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position
677     dans le paneau de bouton.
678
679     Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher
680     une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact.
681     Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour
682     implémenter la class \c FindDialog.
683
684     \section1 Définition de la classe FindDialog
685
686     \image addressbook-tutorial-part5-finddialog.png
687
688     Pour sous-classer QDialog, nous commençons par inclure le header de
689     QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les
690     classes QLineEdit et QPushButton car nous utilisons ces widgets dans
691     notre classe dialogue.
692
693     Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise
694     la macro Q_OBJECT et son constructeur est défini de façon à accepter
695     un QWidget parent, même si cette boîte de dialogue sera affichée dans une
696     fenêtre séparée.
697
698     \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
699
700     Nous définissons la méthode publique \c getFindText() pour être utilisée
701     par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir
702     le texte entré par l'utilisateur. Un slot public, \c findClicked(), est
703     défini pour prendre en charge le texte lorsque l'utilisateur clique sur
704     le bouton \uicontrol Find.
705
706     Finalement, nous définissons les variables privées \c findButton,
707     \c lineEdit et \c findText, qui correspondent respectivement au bouton
708     \uicontrol Find, au champ de texte dans lequel l'utilisateur tape le texte
709     à rechercher, et à une variable interne stockant le texte pour une
710     utilisation ultérieure.
711
712     \section1 Implémentation de la classe FindDialog
713
714     Dans le constructeur de \c FindDialog, nous instancions les objets des
715     variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite
716     un QHBoxLayout pour positionner les widgets.
717
718     \snippet tutorials/addressbook/part5/finddialog.cpp constructor
719
720     Nous mettons en place la mise en page et le titre de la fenêtre, et
721     nous connectons les signaux aux slots. Remarquez que le signal
722     \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté
723     à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot
724     \l{QDialog::accept()}{accept()} fourni par le QDialog ferme
725     la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}.
726     Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe
727     \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera
728     expliqué plus loin lorsque nous verrons la méthode \c findContact().
729
730     \image addressbook-tutorial-part5-signals-and-slots.png
731
732     Dans \c findClicked(), nous validons le champ de texte pour nous
733     assurer que l'utilisateur n'a pas cliqué sur le bouton \uicontrol Find sans
734     avoir entré un nom de contact. Ensuite, nous stockons le texte du champ
735     d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le
736     contenu de \c lineEdit et cachons la boîte de dialogue.
737
738     \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
739
740     La variable \c findText a un accesseur publique associé: \c getFindText().
741     Étant donné que nous ne modifions \c findText directement que dans le
742     constructeur et la méthode \c findClicked(), nous ne créons pas
743     de manipulateurs associé à \c getFindText().
744     Puisque \c getFindText() est publique, les classes instanciant et
745     utilisant \c FindDialog peuvent toujours accéder à la chaîne de
746     caractères que l'utilisateur a entré et accepté.
747
748     \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
749
750     \section1 Définition de la classe AddressBook
751
752     Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous
753     incluons \c finddialog.h dans le fichier \c addressbook.h.
754
755     \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
756
757     Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un
758     QPushButton et un slot correspondant. De la même façon, pour la
759     fonctionnalité \uicontrol Find, nous avons \c findButton et \c findContact().
760
761     Le \c findButton est déclaré comme une variable privée et la
762     méthode \c findContact() est déclarée comme un slot public.
763
764     \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
765     \dots
766     \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
767
768     Finalement, nous déclarons la variable privée \c dialog que nous allons
769     utiliser pour accéder à une instance de \c FindDialog.
770
771     \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
772
773     Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser
774     plus qu'une fois. Utiliser une variable privée nous permet d'y référer
775     à plus d'un endroit dans la classe.
776
777     \section1 Implémentation de la classe AddressBook
778
779     Dans le constructeur de \c AddressBook, nous instancions nos objets privés,
780     \c findbutton et \c findDialog:
781
782     \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
783     \dots
784     \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
785
786     Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de
787     \c{findButton} à \c findContact().
788
789     \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
790
791     Maintenant, tout ce qui manque est le code de notre méthode \c findContact():
792
793     \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
794
795     Nous commençons par afficher l'instance de \c FindDialog, \c dialog.
796     L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque
797     l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est
798     masquée et le code de retour devient QDialog::Accepted. Ce code de retour
799     vient remplir la condition du premier if.
800
801     Ensuite, nous extrayons le texte que nous utiliserons pour la recherche,
802     il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText()
803     de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous
804     l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour
805     indiquer que la recherche à échouée.
806
807     \image addressbook-tutorial-part5-notfound.png
808 */
809
810 /*!
811     \page tutorials-addressbook-part6.html
812
813     \example tutorials/addressbook-fr/part6
814     \title Carnet d'Adresses 6 - Sauvegarde et chargement
815
816     Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que
817     l'on utilise pour écrire les procédures de sauvegarde et chargement pour
818     l'application carnet d'adresses.
819
820     \image addressbook-tutorial-part6-screenshot.png
821
822     Bien que la navigation et la recherche de contacts soient des
823     fonctionnalités importantes, notre carnet d'adresses ne sera pleinement
824     utilisable qu'une fois que l'on pourra sauvegarder les contacts existants
825     et les charger à nouveau par la suite.
826     Qt fournit de nombreuses classes pour gérer les \l{Input/Output and
827     Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une
828     combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream.
829
830     Un objet QFile représente un fichier sur le disque qui peut être lu, et
831     dans lequel on peut écrire. QFile est une classe fille de la classe plus
832     générique QIODevice, qui peut représenter différents types de
833     périphériques.
834
835     Un objet QDataStream est utilisé pour sérialiser des données binaires
836     dans le but de les passer à un QIODevice pour les récupérer dans le
837     futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le
838     flux, avec le périphérique approprié en paramètre, et d'y lire ou
839     écrire.
840
841     \section1 Définition de la classe AddressBook
842
843     On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), 
844     ainsi que deux objets QPushButton, \c loadButton et \c saveButton.
845
846     \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
847     \dots
848     \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
849
850     \section1 Implémentation de la classe AddressBook
851
852     Dans notre constructeur, on instancie \c loadButton et \c saveButton.
853     Idéalement, l'interface serait plus conviviale avec des boutons
854     affichant "Load contacts from a file" et "Save contacts to a file". Mais
855     compte tenu de la dimension des autres boutons, on initialise les labels
856     des boutons à \uicontrol{Load...} et \uicontrol{Save...}. Heureusement, Qt offre une
857     façon simple d'ajouter des info-bulles avec
858     \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon
859     suivante pour nos boutons:
860
861     \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
862     \dots
863     \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
864
865     Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au
866     layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et 
867     nous connectons leurs signaux
868     \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs.
869
870     Pour la sauvegarde, on commence par récupérer le nom de fichier 
871     \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une
872     méthode pratique fournie par QFileDialog, qui ouvre une boîte de
873     dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou
874     de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk}
875     correspondent à l'extension choisie pour la sauvegarde des contacts de
876     notre carnet d'adresses.
877
878     \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
879
880     La boîte de dialogue affichée est visible sur la capture d'écran ci-
881     dessous.
882
883     \image addressbook-tutorial-part6-save.png
884
885     Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir
886     de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de
887     QIODevice.
888
889     Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au
890     mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe
891     l'utilisateur avec une QMessageBox.
892
893     \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
894
895     Dans le cas contraire, on instancie un objet QDataStream, \c out, afin
896     d'écrire dans le fichier ouvert. QDataStream nécessite que la même
897     version de flux soit utilisée pour la lecture et l'écriture. On s'assure
898     que c'est le cas en spécifiant explicitement d'utiliser la
899     \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de
900     sérialiser les données vers le fichier \c file.
901
902     \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
903
904     Pour le chargement, on récupère également \c fileName en utilisant
905     QFileDialog::getOpenFileName(). Cette méthode est l'homologue de
906     QFileDialog::getSaveFileName() et affiche également une boîte de
907     dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou
908     de selectionner un fichier \c{.abk} existant, afin de le charger dans le
909     carnet d'adresses.
910
911     \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
912
913     Sous Windows, par exemple, cette méthode affiche une boîte de dialogue
914     native pour la sélection de fichier, comme illustré sur la capture
915     d'écran suivante:
916
917     \image addressbook-tutorial-part6-load.png
918
919     Si \c fileName n'est pas vide, on utilise une fois de plus un objet
920     QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode
921     \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre
922     implémentation de \c saveToFile(), si cette tentative s'avère
923     infructueuse, on en informe l'utilisateur par le biais d'une
924     QMessageBox.
925
926     \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
927
928     Dans le cas contraire, on instancie un objet QDataStream, \c in, en
929     spécifiant la version à utiliser comme précédemment, et on lit les
930     informations sérialisées vers la structure de données \c contacts. Notez
931     qu'on purge \c contacts avant d'y mettre les informations lues afin de
932     simplifier le processus de lecture de fichier. Une façon plus avancée de
933     procéder serait de lire les contacts dans un objet QMap temporaire, et
934     de copier uniquement les contacts n'existant pas encore dans
935     \c contacts.
936
937     \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
938
939     Pour afficher les contacts lus depuis le fichier, on doit d'abord
940     valider les données obtenues afin de s'assurer que le fichier lu
941     contient effectivement des entrées de carnet d'adresses. Si c'est le
942     cas, on affiche le premier contact; sinon on informe l'utilisateur du
943     problème par une QMessageBox. Enfin, on met à jour l'interface afin
944     d'activer et de désactiver les boutons de façon appropriée.
945 */
946
947 /*!
948     \page tutorials-addressbook-fr-part7.html
949
950     \example tutorials/addressbook-fr/part7
951     \title Carnet d'adresse 7 - Fonctionnalités avancées
952
953     Ce chapitre couvre quelques fonctionnalités additionnelles qui
954     feront de notre carnet d'adresses une application plus pratique
955     pour une utilisation quotidienne.
956
957     \image addressbook-tutorial-part7-screenshot.png
958
959     Bien que notre application carnet d'adresses soit utile en tant que telle,
960     il serait pratique de pouvoir échanger les contacts avec d'autres applications.
961     Le format vCard est un un format de fichier populaire pour échanger
962     ce type de données.
963     Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre
964     d'exporter des contacts dans des fichiers vCard \c{.vcf}.
965
966     \section1 Définition de la classe AddressBook
967
968     Nous ajoutons un objet QPushButton, \c exportButton, et un slot
969     public correspondant, \c exportAsVCard(), à notre classe \c AddressBook 
970     dans le fichier \c addressbook.h.
971
972     \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
973     \dots
974     \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
975
976     \section1 Implémentation de la classe AddressBook
977
978     Dans le constructeur de \c AddressBook, nous connectons le signal
979     \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot
980     \c exportAsVCard().
981     Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable
982     du groupe de boutons sur la droite.
983
984     Dans la méthode \c exportAsVCard(), nous commençons par extraire le
985     nom du contact dans \c name. Nous déclarons \c firstname, \c lastName et
986     \c nameList.
987     Ensuite, nous cherchons la position du premier espace blanc de \c name.
988     Si il y a un espace, nous séparons le nom du contact en \c firstName et
989     \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_").
990     Si il n'y a pas d'espace, nous supposons que le contact ne comprend que
991     le prénom.
992
993     \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
994
995     Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue
996     pour donner la possibilité à l'utilisateur de choisir un emplacement pour
997     le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile
998     pour y écrire.
999
1000     Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si
1001     cela échoue, nous affichons un QMessageBox pour informer l'utilisateur
1002     à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le
1003     fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que
1004     QDataStream, la classe QTextStream fournit les fonctionnalités pour 
1005     lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf}
1006     généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte.
1007
1008     \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
1009
1010     Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD},
1011     suivit par \c{VERSION:2.1}.
1012     Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise
1013     \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact
1014     à un nom de famille défini ou non. Si oui, nous utilions les détails de
1015     \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu
1016     de \c firstName.
1017  
1018     \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
1019
1020     Nous continuons en écrivant l'adresse du contact. Les points-virgules
1021     dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont
1022     remplacés par des points-virgules, et les vigules sont remplacées par des espaces.
1023     Finalement nous écrivons les balises  \c{ADR;HOME:;} suivies par l'adresse
1024     et la balise \c{END:VCARD}.
1025
1026     \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
1027
1028     À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur
1029     que la vCard a été exportée avec succès. 
1030
1031     \e{vCard est une marque déposée de \l{http://www.imc.org}
1032     {Internet Mail Consortium}}.
1033 */