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