summaryrefslogtreecommitdiffstats
path: root/doc/src/tutorials
diff options
context:
space:
mode:
Diffstat (limited to 'doc/src/tutorials')
-rw-r--r--doc/src/tutorials/addressbook-fr.qdoc1036
-rw-r--r--doc/src/tutorials/addressbook.qdoc981
-rw-r--r--doc/src/tutorials/modelview.qdoc901
-rw-r--r--doc/src/tutorials/threads.qdoc572
-rw-r--r--doc/src/tutorials/widgets-tutorial.qdoc249
5 files changed, 3739 insertions, 0 deletions
diff --git a/doc/src/tutorials/addressbook-fr.qdoc b/doc/src/tutorials/addressbook-fr.qdoc
new file mode 100644
index 0000000000..7badaeffde
--- /dev/null
+++ b/doc/src/tutorials/addressbook-fr.qdoc
@@ -0,0 +1,1036 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page tutorials-addressbook-fr.html
+
+ \title Tutoriel "Carnet d'adresses"
+ \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt.
+
+ Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur)
+ à l'aide des outils fournis par la plateforme multiplate-forme Qt.
+
+ \image addressbook-tutorial-screenshot.png
+
+ Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies
+ par Qt, tel que:
+
+ \list
+ \o Les Widgets et leur mise en page à l'aide des layouts
+ \o Les signaux et slots
+ \o Les structures de données de collections
+ \o Les entrées/sorties
+ \endlist
+
+ Si c'est votre premier contact avec Qt, lisez \l{How to Learn Qt}{Comment apprendre Qt}
+ si ce n'est déjà fait.
+
+ Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook
+
+ Les chapitres du tutoriel:
+
+ \list 1
+ \o \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur}
+ \o \l{tutorials/addressbook-fr/part2}{Ajouter des adresses}
+ \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments}
+ \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses}
+ \o \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche}
+ \o \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement}
+ \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées}
+ \endlist
+
+ La petite application que nous développerons ici ne possède pas tous les éléments
+ des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base
+ utilisées dans les applications plus complexes.
+
+ Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple
+ "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant
+ les menus et barres d'outils, la barre d'état, etc.
+
+*/
+
+/*!
+ \page tutorials-addressbook-fr-part1.html
+
+ \example tutorials/addressbook-fr/part1
+ \title Carnet d'adresses 1 - Conception de l'interface utilisateur
+
+ La première partie de ce tutoriel traite de la conception d'une interface graphique
+ (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses.
+
+ La première étape dans la création d'applications graphiques est la conception de
+ l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels
+ et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base.
+ Le résultat attendu est illustré par la capture d'écran ci-dessous.
+
+ \image addressbook-tutorial-part1-screenshot.png
+
+ Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel,
+ ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet
+ QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un
+ contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous.
+
+ \image addressbook-tutorial-part1-labeled-screenshot.png
+
+ Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses:
+
+ \list
+ \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook,
+ \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe
+ \c AddressBook
+ \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et
+ une instance de la classe \c AddressBook.
+ \endlist
+
+ \section1 Programmation en Qt - héritage
+
+
+ Lorsque l'on écrit des programmes avec Qt, on a généralement recours à
+ l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités.
+ C'est l'un des concepts fondamentaux de la création de widgets personnalisés
+ ou de collections de widgets. Utiliser l'héritage afin de compléter
+ ou modifier le comportement d'un widget présente les avantages suivants:
+
+ \list
+ \o La possibilité d'implémenter des méthodes virtuelles et des méthodes
+ virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité
+ d'utiliser l'implémentation de la classe mère si besoin est.
+ \o Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe,
+ afin que les autres parties de l'application n'aient pas à se soucier de chacun des
+ widgets qui forment l'interface utilisateur.
+ \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés
+ dans une même application ou bibliothèque, et le code de la classe fille peut être
+ réutilisé dans d'autres projets
+ \endlist
+
+ Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous
+ partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités.
+ La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un
+ widget carnet d'adresses basique.
+
+
+ \section1 La classe AddressBook
+
+ Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de
+ définir la classe \c AddressBook.
+
+ On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer
+ un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe
+ exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que
+ l'internationalisation, bien que nous ne les utilisions pas à ce stade.
+
+ \snippet tutorials/addressbook-fr/part1/addressbook.h class definition
+
+ La classe contient les déclarations de \c nameLine et \c addressText,
+ les instances privées de QLineEdit et QTextEdit mentionnées précédemment.
+ Vous verrez, dans les chapitres à venir que les informations contenues
+ dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes
+ du carnet d'adresses.
+
+ Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser
+ puisque nous n'aurons pas besoin d'y faire référence après leur création.
+ La façon dont Qt gère la parenté des objets est traitée dans la section suivante.
+
+ La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt.
+ Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous
+ permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}.
+
+ Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons
+ passer à l'implémentation du fichier \c addressbook.cpp.
+
+ \section1 Implémentation de la classe AddressBook
+
+ Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent.
+ Par convention, on passe ce paramètre au constructeur de la classe mère.
+ Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile
+ pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent,
+ tous ses enfants seront détruits égalament.
+
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
+
+ à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux
+ QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et
+ \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite
+ de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie
+ la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{<insérer
+ la traduction ici>}, permettant de repérer les objets QString à considérer
+ pour traduire une application. Vous remarquerez, dans les chapitres à venir
+ comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois
+ que l'on utilise une chaîne susceptible d'être traduite.
+
+ Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les
+ agencements ou layouts. Qt fournit trois classes principales de layouts pour
+ contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout.
+
+ \image addressbook-tutorial-part1-labeled-layout.png
+
+ On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière
+ structurée. QGridLayout divise l'espace disponible en une grille, et place les
+ widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne.
+ Le diagramme ci-dessus présente les cellules et la position des widgets, et cette
+ organisation est obtenue à l'aide du code suivant:
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp layout
+
+ On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop
+ comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré
+ verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt,
+ consultez la section \l{Layout Management}.
+
+ Afin d'installer l'objet layout dans un widget, il faut appeler la méthode
+ \l{QWidget::setLayout()}{setLayout()} du widget en question:
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
+
+ Enfin, on initialise le titre du widget à "Simple Address Book"
+
+ \section1 Exécution de l'application
+
+ Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette
+ fonction, on crée une instance de QApplication, \c app. QApplication se charge de
+ des ressources communes à l'ensemble de l'application, tel que les polices de
+ caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements.
+ De ce fait, il y a toujours un objet QApplication dans toute application graphique en Qt.
+
+ \snippet tutorials/addressbook/part1/main.cpp main function
+
+ On construit un nouveau widget \c AddressBook sur la pile et on invoque
+ sa méthode \l{QWidget::show()}{show()} pour l'afficher.
+ Cependant, le widget ne sera pas visible tant que la boucle d'évènements
+ n'aura pas été lancée. On démarre la boucle d'évènements en appelant la
+ méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé
+ par cette méthode est lui même utilisé comme valeur de retour pour la méthode
+ \c main().
+ On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin
+ du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants
+ sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire.
+*/
+
+/*!
+ \page tutorials-addressbook-fr-part2.html
+
+ \example tutorials/addressbook-fr/part2
+ \title Carnet d'adresses 2 - Ajouter des adresses
+
+ La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon
+ d'interactivité.
+
+ \image addressbook-tutorial-part2-add-contact.png
+
+ Nous allons fournir un bouton que l'utilisateur peut
+ cliquer pour ajouter un nouveau contact. Une structure de données est aussi
+ nécessaire afin de pouvoir stocker les contacts en mémoire.
+
+ \section1 Définition de la classe AddressBook
+
+ Maintenant que nous avons mis en place les labels et les champs de saisie,
+ nous ajoutons les boutons pour compléter le processus d'ajout d'un contact.
+ Cela veut dire que notre fichier \c addressbook.h a maintenant trois
+ objets QPushButton et trois slots publics correspondant.
+
+ \snippet tutorials/addressbook/part2/addressbook.h slots
+
+ Un slot est une méthode qui répond à un signal. Nous allons
+ voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}.
+ Pour une explication détaillée du concept de signal et slot, vous pouvez
+ vous référer au document \l{Signals and Slots}.
+
+ Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton
+ sont maintenant inclus dans la déclaration des variables privées, avec
+ \c nameLine et \c addressText du chapitre précédent.
+
+ \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
+
+ Nous avons besoin d'un conteneur pour stocker les contacts du carnet
+ d'adresses, de façon à pouvoir les énumérer et les afficher.
+ Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker
+ des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact
+ est la \e{valeur}.
+
+ \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
+
+ Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress.
+ Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact
+ affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables
+ si l'utilisateur clique sur "Cancel", il est possible de revenir
+ à l'affichage du dernier contact.
+
+ \section1 Implémentation de la classe AddressBook
+
+ Dans le constructeur de \c AddressBook, \c nameLine et
+ \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage
+ mais pas la modification du contact courant.
+
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
+
+ Ensuite, nous instancions les boutons \c addButton, \c submitButton, et
+ \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
+
+ Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()}
+ {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant
+ \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque
+ l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact()
+ décrite plus loin.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
+
+ Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton
+ au slot qui gèrera l'action.
+ L'image ci-dessous illustre ceci:
+
+ \image addressbook-tutorial-part2-signals-and-slots.png
+
+ Ensuite, nous arrangeons proprement les boutons sur la droite du widget
+ AddressBook, et nous utilisons un QVBoxLayout pour les aligner verticalement.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
+
+ La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour
+ assurer que les boutons ne sont pas répartis uniformément, mais regroupés
+ dans la partie supperieure du widget. La figure ci-dessous montre la différence
+ si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas.
+
+ \image addressbook-tutorial-part2-stretch-effects.png
+
+ Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant
+ \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les
+ mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
+
+ Les coordonnées du layout global ressemblent maintenant à ça:
+
+ \image addressbook-tutorial-part2-labeled-layout.png
+
+ Dans la méthode \c addContact(), nous stockons les détails du dernier
+ contact affiché dans \c oldName et \c oldAddress. Ensuite, nous
+ vidons ces champs de saisie et nous désactivons le mode
+ lecture seule. Le focus est placé sur \c nameLine et on affiche
+ \c submitButton et \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp addContact
+
+ La méthode \c submitContact() peut être divisée en trois parties:
+
+ \list 1
+ \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText
+ et les stockons dans des objets QString. Nous les validons pour s'assurer
+ que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie
+ vides; sinon un message est affiché avec QMessageBox pour rappeller à
+ l'utilisateur que les deux champs doivent être complétés.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
+
+ \o Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts
+ existant n'entre en conflit avec le nouveau, nous l'ajoutons à
+ \c contacts et nous affichons un QMessageBox pour informer l'utilisateur
+ que le contact a été ajouté.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
+
+ Si le contact existe déjà, nous affichons un QMessageBox pour informer
+ l'utilisateur du problème.
+ Notre objet \c contacts est basé sur des paires clé-valeur formés par
+ le nom et l'adresse, nous voulons nous assurer que la \e clé est unique.
+
+ \o Une fois que les deux vérifications précédentes ont été traitées,
+ nous restaurons les boutons à leur état normal à l'aide du code
+ suivant:
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
+
+ \endlist
+
+ La capture d'écran ci-dessous montre l'affichage fournit par un objet
+ QMessageBox, utilisé ici pour afficher un message d'information
+ à l'utilisateur:
+
+ \image addressbook-tutorial-part2-add-successful.png
+
+ La méthode \c cancel() restaure les détails du dernier contact, active
+ \c addButton, et cache \c submitButton et \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp cancel
+
+ L'idée générale pour augmenter la flexibilité lors de l'ajout d'un
+ contact est de donner la possiblité de cliquer sur "Add"
+ ou "Cancel" à n'importe quel moment.
+ L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées
+ jusqu'ici:
+
+ \image addressbook-tutorial-part2-add-flowchart.png
+*/
+
+/*!
+ \page tutorials-addressbook-fr-part3.html
+
+ \example tutorials/addressbook-fr/part3
+ \title Carnet d'adresses 3 - Navigation entre les éléments
+
+ L'application "Carnet d'adresses" est maintenant à moitié terminée. Il
+ nous faut maintenant ajouter quelques fonctions pour naviguer entre
+ les contacts. Avant de commencer, il faut se décider sur le type de structure de
+ données le plus approprié pour stocker les contacts.
+
+ Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur,
+ avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur.
+ Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les
+ entrées, quelques améliorations sont nécessaires.
+
+ Nous améliorerons le QMap en le faisant ressembler à une structure de données
+ similaire à une liste liée, où tous les éléments sont connectés, y compris
+ le premier et le dernier élément. La figure ci-dessous illustre cette structure
+ de donnée.
+
+ \image addressbook-tutorial-part3-linkedlist.png
+
+ \section1 Définition de la classe AddressBook
+
+ Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons
+ besoin de deux slots supplémentaires dans notre classe \c AddressBook:
+ \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h:
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation functions
+
+ Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons
+ donc les variables privées \c nextButton et \c previousButton.
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
+
+ \section1 Implémentation de la classe AddressBook
+
+ A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous
+ instancions \c nextButton et \c previousButton et nous les désactivons
+ par défaut. Nous faisons ceci car la navigation ne doit être activée
+ que lorsqu'il y a plus d'un contact dans le carnet d'adresses.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
+
+ Nous connectons alors ces boutons à leur slots respectifs:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
+
+ L'image ci-dessous montre l'interface utilisateur que nous allons créer.
+ Remarquez que cela ressemble de plus en plus à l'interface du programme
+ complet.
+
+ \image addressbook-tutorial-part3-screenshot.png
+
+ Nous suivons les conventions pour les fonctions \c next() et \c previous()
+ en plaçant \c nextButton à droite et \c previousButton à gauche. Pour
+ faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour
+ placer les widgets côte à côte:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
+
+ L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
+
+ La figure ci-dessous montre les systèmes de coordonnées pour les widgets du
+ \c mainLayout.
+ \image addressbook-tutorial-part3-labeled-layout.png
+
+ Dans notre méthode \c addContact(), nous avons desactivé ces boutons
+ pour être sûr que l'utilisateur n'utilise pas la navigation lors de
+ l'ajout d'un contact.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
+
+ Dans notre méthode \c submitContact(), nous activons les boutons de
+ navigation, \c nextButton et \c previousButton, en fonction de la
+ taille de \c contacts. Commen mentionné plus tôt, la navigation n'est
+ activée que si il y a plus d'un contact dans le carnet d'adresses.
+ Les lignes suivantes montrent comment faire cela:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
+
+ Nous incluons aussi ces lignes de code dans le bouton \c cancel().
+
+ Souvenez vous que nous voulons émuler une liste-liée ciruculaire à
+ l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur
+ sur \c contact dans la méthode \c next(), et ensuite:
+
+ \list
+ \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons
+ \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position
+ jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap
+ fonctionne comme une liste circulaire.
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp next() function
+
+ Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts,
+ nous affichons son contenu sur \c nameLine et \c addressText.
+
+ De la même façon, pour la méthode \c previous(), nous obtenons un
+ itérateur sur \c contacts et ensuite:
+
+ \list
+ \o Si l'itérateur est à la fin de \c contacts, on réinitialise
+ l'affichage et on retourne.
+ \o Si l'itérateur est au début de \c contacts, on change sa
+ position jusqu'à la fin
+ \o Ensuite, on décrémente l'itérateur
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
+
+ à nouveau, nous affichons le contenu de l'objet courant dans \c contacts.
+
+*/
+
+/*!
+
+ \page tutorials-addressbook-fr-part4.html
+
+ \example tutorials/addressbook-fr/part4
+ \title Carnet d'Adresses 4 - éditer et supprimer des adresses
+
+
+ Dans ce chapitre, nous verrons comment modifier les données des contacts
+ contenus dans l'application carnet d'adresses.
+
+
+ \image addressbook-tutorial-screenshot.png
+
+ Nous avons maintenant un carnet d'adresses qui ne se contente pas de
+ lister des contacts de façon ordonnée, mais permet également la
+ navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et
+ supprimer, afin que les détails associés à un contact puissent être
+ modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère
+ modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux
+ modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas
+ définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les
+ boutons correspondants manuellement, au prix de multiples redondances dans
+ le code.
+
+ Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles.
+
+ \list
+ \o \c{NavigationMode},
+ \o \c{AddingMode}, et
+ \o \c{EditingMode}.
+ \endlist
+
+ \section1 Définition de la classe AddressBook
+
+ Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode :
+
+ \snippet tutorials/addressbook/part4/addressbook.h Mode enum
+
+ On ajoute également deux nouveaux slots, \c editContact() et
+ \c removeContact(), à notre liste de slots publics.
+
+ \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
+
+ Afin de basculer d'un mode à l'autre, on introduit la méthode
+ \c updateInterface() pour contrôller l'activation et la désactivation de
+ tous les objets QPushButton. On ajoute également deux nouveaux boutons,
+ \c editButton et \c removeButton, pour les fonctions d'édition
+ et de suppression mentionnées plus haut.
+
+ \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.h mode declaration
+
+ Enfin, on déclare \c currentMode pour garder une trace du mode
+ actuellement utilisé.
+
+ \section1 Implémentation de la classe AddressBook
+
+ Il nous faut maintenant implémenter les fonctionnalités de changement de
+ mode de l'application carnet d'adresses. Les boutons \c editButton et
+ \c removeButton sont instanciés et désactivés par défaut, puisque le
+ carnet d'adresses démarre sans aucun contact en mémoire.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
+
+ Ces boutons sont ensuite connectés à leurs slots respectifs,
+ \c editContact() et \c removeContact(), avant d'être ajoutés à
+ \c buttonLayout1.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
+
+ La methode \c editContact() place les anciens détails du contact dans
+ \c oldName et \c oldAddress, avant de basculer vers le mode
+ \c EditingMode. Dans ce mode, les boutons \c submitButton et
+ \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent
+ modifier les détails du contact et cliquer sur l'un de ces deux boutons
+ par la suite.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
+
+ La méthode \c submitContact() a été divisée en deux avec un bloc
+ \c{if-else}. On teste \c currentMode pour voir si le mode courant est
+ \c AddingMode. Si c'est le cas, on procède à l'ajout.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
+
+ Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le
+ cas, on compare \c oldName et \c name. Si le nom a changé, on supprime
+ l'ancien contact de \c contacts et on insère le contact mis a jour.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
+
+ Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à
+ \c address), on met à jour l'adresse du contact. Enfin on règle
+ \c currentMode à \c NavigationMode. C'est une étape importante puisque
+ c'est cela qui réactive tous les boutons désactivés.
+
+ Afin de retirer un contact du carnet d'adresses, on implémente la méthode
+ \c removeContact(). Cette méthode vérifie que le contact est présent dans
+ \c contacts.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
+
+ Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant
+ confirmation de la suppression à l'utilisateur. Une fois la confirmation
+ effectuée, on appelle \c previous(), afin de s'assurer que l'interface
+ utilisateur affiche une autre entrée, et on supprime le contact en
+ utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un
+ souci pratique, on informe l'utilisateur de la suppression par le biais
+ d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette
+ méthode sont représentées ci-dessous.
+
+ \image addressbook-tutorial-part4-remove.png
+
+ \section2 Mise à jour de l'Interface utilisateur
+
+ On a évoqué plus haut la méthode \c updateInterface() comme moyen
+ d'activer et de désactiver les différents boutons de l'interface en
+ fonction du mode. Cette méthode met à jour le mode courant selon
+ l'argument \c mode qui lui est passé, en l'assignant à \c currentMode,
+ avant de tester sa valeur.
+
+ Chacun des boutons est ensuite activé ou désactivé, en fonction du mode.
+ Le code source pour les cas \c AddingMode et \c EditingMode est visible
+ ci-dessous:
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
+
+ Dans le cas de \c NavigationMode, en revanche, des tests conditionnels
+ sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de
+ s'assurer que les boutons \c editButton et \c removeButton ne sont activés
+ que s'il existe au moins un contact dans le carnet d'adresses;
+ \c nextButton et \c previousButton ne sont activés que lorsqu'il existe
+ plus d'un contact dans le carnet d'adresses.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
+
+ En effectuant les opérations de réglage du mode et de mise à jour de
+ l'interface utilisateur au sein de la même méthode, on est à l'abri de
+ l'éventualité où l'interface utilisateur se "désynchronise" de l'état
+ interne de l'application.
+
+*/
+
+/*!
+ \page tutorials-addressbook-fr-part5.html
+
+ \example tutorials/addressbook-fr/part5
+ \title Carnet d'adresse 5 - Ajout d'une fonction de recherche
+
+ Dans ce chapitre, nous allons voir les possibilités pour rechercher
+ des contacts dans le carnet d'adresse.
+
+ \image addressbook-tutorial-part5-screenshot.png
+
+ Plus nous ajoutons des contacts dans l'application, plus
+ il devient difficile de naviguer avec les boutons \e Next et \e Previous.
+ Dans ce cas, une fonction de recherche serait plus efficace pour rechercher
+ les contacts.
+ La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position
+ dans le paneau de bouton.
+
+ Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher
+ une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact.
+ Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour
+ implémenter la class \c FindDialog.
+
+ \section1 Définition de la classe FindDialog
+
+ \image addressbook-tutorial-part5-finddialog.png
+
+ Pour sous-classer QDialog, nous commençons par inclure le header de
+ QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les
+ classes QLineEdit et QPushButton car nous utilisons ces widgets dans
+ notre classe dialogue.
+
+ Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise
+ la macro Q_OBJECT et son constructeur est défini de façon à accepter
+ un QWidget parent, même si cette boîte de dialogue sera affichée dans une
+ fenêtre séparée.
+
+ \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
+
+ Nous définissons la méthode publique \c getFindText() pour être utilisée
+ par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir
+ le texte entré par l'utilisateur. Un slot public, \c findClicked(), est
+ défini pour prendre en charge le texte lorsque l'utilisateur clique sur
+ le bouton \gui Find.
+
+ Finalement, nous définissons les variables privées \c findButton,
+ \c lineEdit et \c findText, qui correspondent respectivement au bouton
+ \gui Find, au champ de texte dans lequel l'utilisateur tape le texte
+ à rechercher, et à une variable interne stockant le texte pour une
+ utilisation ultérieure.
+
+ \section1 Implémentation de la classe FindDialog
+
+ Dans le constructeur de \c FindDialog, nous instancions les objets des
+ variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite
+ un QHBoxLayout pour positionner les widgets.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp constructor
+
+ Nous mettons en place la mise en page et le titre de la fenêtre, et
+ nous connectons les signaux aux slots. Remarquez que le signal
+ \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté
+ à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot
+ \l{QDialog::accept()}{accept()} fourni par le QDialog ferme
+ la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}.
+ Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe
+ \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera
+ expliqué plus loin lorsque nous verrons la méthode \c findContact().
+
+ \image addressbook-tutorial-part5-signals-and-slots.png
+
+ Dans \c findClicked(), nous validons le champ de texte pour nous
+ assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans
+ avoir entré un nom de contact. Ensuite, nous stockons le texte du champ
+ d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le
+ contenu de \c lineEdit et cachons la boîte de dialogue.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
+
+ La variable \c findText a un accesseur publique associé: \c getFindText().
+ Étant donné que nous ne modifions \c findText directement que dans le
+ constructeur et la méthode \c findClicked(), nous ne créons pas
+ de manipulateurs associé à \c getFindText().
+ Puisque \c getFindText() est publique, les classes instanciant et
+ utilisant \c FindDialog peuvent toujours accéder à la chaîne de
+ caractères que l'utilisateur a entré et accepté.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
+
+ \section1 Définition de la classe AddressBook
+
+ Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous
+ incluons \c finddialog.h dans le fichier \c addressbook.h.
+
+ \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
+
+ Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un
+ QPushButton et un slot correspondant. De la même façon, pour la
+ fonctionnalité \gui Find, nous avons \c findButton et \c findContact().
+
+ Le \c findButton est déclaré comme une variable privée et la
+ méthode \c findContact() est déclarée comme un slot public.
+
+ \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
+
+ Finalement, nous déclarons la variable privée \c dialog que nous allons
+ utiliser pour accéder à une instance de \c FindDialog.
+
+ \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
+
+ Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser
+ plus qu'une fois. Utiliser une variable privée nous permet d'y référer
+ à plus d'un endroit dans la classe.
+
+ \section1 Implémentation de la classe AddressBook
+
+ Dans le constructeur de \c AddressBook, nous instancions nos objets privés,
+ \c findbutton et \c findDialog:
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
+
+ Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de
+ \c{findButton} à \c findContact().
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
+
+ Maintenant, tout ce qui manque est le code de notre méthode \c findContact():
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
+
+ Nous commençons par afficher l'instance de \c FindDialog, \c dialog.
+ L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque
+ l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est
+ masquée et le code de retour devient QDialog::Accepted. Ce code de retour
+ vient remplir la condition du premier if.
+
+ Ensuite, nous extrayons le texte que nous utiliserons pour la recherche,
+ il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText()
+ de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous
+ l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour
+ indiquer que la recherche à échouée.
+
+ \image addressbook-tutorial-part5-notfound.png
+*/
+
+/*!
+ \page tutorials-addressbook-part6.html
+
+ \example tutorials/addressbook-fr/part6
+ \title Carnet d'Adresses 6 - Sauvegarde et chargement
+
+ Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que
+ l'on utilise pour écrire les procédures de sauvegarde et chargement pour
+ l'application carnet d'adresses.
+
+ \image addressbook-tutorial-part6-screenshot.png
+
+ Bien que la navigation et la recherche de contacts soient des
+ fonctionnalités importantes, notre carnet d'adresses ne sera pleinement
+ utilisable qu'une fois que l'on pourra sauvegarder les contacts existants
+ et les charger à nouveau par la suite.
+ Qt fournit de nombreuses classes pour gérer les \l{Input/Output and
+ Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une
+ combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream.
+
+ Un objet QFile représente un fichier sur le disque qui peut être lu, et
+ dans lequel on peut écrire. QFile est une classe fille de la classe plus
+ générique QIODevice, qui peut représenter différents types de
+ périphériques.
+
+ Un objet QDataStream est utilisé pour sérialiser des données binaires
+ dans le but de les passer à un QIODevice pour les récupérer dans le
+ futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le
+ flux, avec le périphérique approprié en paramètre, et d'y lire ou
+ écrire.
+
+ \section1 Définition de la classe AddressBook
+
+ On déclare deux slots publics, \c saveToFile() et \c loadFromFile(),
+ ainsi que deux objets QPushButton, \c loadButton et \c saveButton.
+
+ \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
+ \dots
+ \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
+
+ \section1 Implémentation de la classe AddressBook
+
+ Dans notre constructeur, on instancie \c loadButton et \c saveButton.
+ Idéalement, l'interface serait plus conviviale avec des boutons
+ affichant "Load contacts from a file" et "Save contacts to a file". Mais
+ compte tenu de la dimension des autres boutons, on initialise les labels
+ des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une
+ façon simple d'ajouter des info-bulles avec
+ \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon
+ suivante pour nos boutons:
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
+ \dots
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
+
+ Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au
+ layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et
+ nous connectons leurs signaux
+ \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs.
+
+ Pour la sauvegarde, on commence par récupérer le nom de fichier
+ \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une
+ méthode pratique fournie par QFileDialog, qui ouvre une boîte de
+ dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou
+ de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk}
+ correspondent à l'extension choisie pour la sauvegarde des contacts de
+ notre carnet d'adresses.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
+
+ La boîte de dialogue affichée est visible sur la capture d'écran ci-
+ dessous.
+
+ \image addressbook-tutorial-part6-save.png
+
+ Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir
+ de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de
+ QIODevice.
+
+ Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au
+ mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe
+ l'utilisateur avec une QMessageBox.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
+
+ Dans le cas contraire, on instancie un objet QDataStream, \c out, afin
+ d'écrire dans le fichier ouvert. QDataStream nécessite que la même
+ version de flux soit utilisée pour la lecture et l'écriture. On s'assure
+ que c'est le cas en spécifiant explicitement d'utiliser la
+ \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de
+ sérialiser les données vers le fichier \c file.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
+
+ Pour le chargement, on récupère également \c fileName en utilisant
+ QFileDialog::getOpenFileName(). Cette méthode est l'homologue de
+ QFileDialog::getSaveFileName() et affiche également une boîte de
+ dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou
+ de selectionner un fichier \c{.abk} existant, afin de le charger dans le
+ carnet d'adresses.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
+
+ Sous Windows, par exemple, cette méthode affiche une boîte de dialogue
+ native pour la sélection de fichier, comme illustré sur la capture
+ d'écran suivante:
+
+ \image addressbook-tutorial-part6-load.png
+
+ Si \c fileName n'est pas vide, on utilise une fois de plus un objet
+ QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode
+ \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre
+ implémentation de \c saveToFile(), si cette tentative s'avère
+ infructueuse, on en informe l'utilisateur par le biais d'une
+ QMessageBox.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
+
+ Dans le cas contraire, on instancie un objet QDataStream, \c in, en
+ spécifiant la version à utiliser comme précédemment, et on lit les
+ informations sérialisées vers la structure de données \c contacts. Notez
+ qu'on purge \c contacts avant d'y mettre les informations lues afin de
+ simplifier le processus de lecture de fichier. Une façon plus avancée de
+ procéder serait de lire les contacts dans un objet QMap temporaire, et
+ de copier uniquement les contacts n'existant pas encore dans
+ \c contacts.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
+
+ Pour afficher les contacts lus depuis le fichier, on doit d'abord
+ valider les données obtenues afin de s'assurer que le fichier lu
+ contient effectivement des entrées de carnet d'adresses. Si c'est le
+ cas, on affiche le premier contact; sinon on informe l'utilisateur du
+ problème par une QMessageBox. Enfin, on met à jour l'interface afin
+ d'activer et de désactiver les boutons de façon appropriée.
+*/
+
+/*!
+ \page tutorials-addressbook-fr-part7.html
+
+ \example tutorials/addressbook-fr/part7
+ \title Carnet d'adresse 7 - Fonctionnalités avancées
+
+ Ce chapitre couvre quelques fonctionnalités additionnelles qui
+ feront de notre carnet d'adresses une application plus pratique
+ pour une utilisation quotidienne.
+
+ \image addressbook-tutorial-part7-screenshot.png
+
+ Bien que notre application carnet d'adresses soit utile en tant que telle,
+ il serait pratique de pouvoir échanger les contacts avec d'autres applications.
+ Le format vCard est un un format de fichier populaire pour échanger
+ ce type de données.
+ Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre
+ d'exporter des contacts dans des fichiers vCard \c{.vcf}.
+
+ \section1 Définition de la classe AddressBook
+
+ Nous ajoutons un objet QPushButton, \c exportButton, et un slot
+ public correspondant, \c exportAsVCard(), à notre classe \c AddressBook
+ dans le fichier \c addressbook.h.
+
+ \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
+ \dots
+ \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
+
+ \section1 Implémentation de la classe AddressBook
+
+ Dans le constructeur de \c AddressBook, nous connectons le signal
+ \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot
+ \c exportAsVCard().
+ Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable
+ du groupe de boutons sur la droite.
+
+ Dans la méthode \c exportAsVCard(), nous commençons par extraire le
+ nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et
+ \c nameList.
+ Ensuite, nous cherchons la position du premier espace blanc de \c name.
+ Si il y a un espace, nous séparons le nom du contact en \c firstName et
+ \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_").
+ Si il n'y a pas d'espace, nous supposons que le contact ne comprend que
+ le prénom.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
+
+ Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue
+ pour donner la possibilité à l'utilisateur de choisir un emplacement pour
+ le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile
+ pour y écrire.
+
+ Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si
+ cela échoue, nous affichons un QMessageBox pour informer l'utilisateur
+ à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le
+ fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que
+ QDataStream, la classe QTextStream fournit les fonctionnalités pour
+ lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf}
+ généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
+
+ Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD},
+ suivit par \c{VERSION:2.1}.
+ Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise
+ \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact
+ à un nom de famille défini ou non. Si oui, nous utilions les détails de
+ \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu
+ de \c firstName.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
+
+ Nous continuons en écrivant l'adresse du contact. Les points-virgules
+ dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont
+ remplacés par des points-virgules, et les vigules sont remplacées par des espaces.
+ Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse
+ et la balise \c{END:VCARD}.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
+
+ À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur
+ que la vCard a été exportée avec succès.
+
+ \e{vCard est une marque déposée de \l{http://www.imc.org}
+ {Internet Mail Consortium}}.
+*/
diff --git a/doc/src/tutorials/addressbook.qdoc b/doc/src/tutorials/addressbook.qdoc
new file mode 100644
index 0000000000..ec4a4f312c
--- /dev/null
+++ b/doc/src/tutorials/addressbook.qdoc
@@ -0,0 +1,981 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page tutorials-addressbook.html
+
+ \title Address Book Tutorial
+ \brief An introduction to GUI programming, showing how to put together a
+ simple yet fully-functioning application.
+
+ This tutorial is an introduction to GUI programming with the Qt
+ cross-platform framework.
+
+ \image addressbook-tutorial-screenshot.png
+
+ \omit
+ It doesn't cover everything; the emphasis is on teaching the programming
+ philosophy of GUI programming, and Qt's features are introduced as needed.
+ Some commonly used features are never used in this tutorial.
+ \endomit
+
+ In this tutorial, you will learn about some of the basic
+ components of Qt, including:
+
+ \list
+ \o Widgets and layout managers
+ \o Container classes
+ \o Signals and slots
+ \o Input and output devices
+ \endlist
+
+ If you are new to Qt, we recommend reading \l{How to Learn Qt} first.
+
+ Tutorial contents:
+
+ \list 1
+ \o \l{tutorials/addressbook/part1}{Designing the User Interface}
+ \o \l{tutorials/addressbook/part2}{Adding Addresses}
+ \o \l{tutorials/addressbook/part3}{Navigating between Entries}
+ \o \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
+ \o \l{tutorials/addressbook/part5}{Adding a Find Function}
+ \o \l{tutorials/addressbook/part6}{Loading and Saving}
+ \o \l{tutorials/addressbook/part7}{Additional Features}
+ \endlist
+
+ The tutorial source code is located in \c{examples/tutorials/addressbook}.
+
+ Although this little application does not look much like a
+ fully-fledged modern GUI application, it uses many of the basic
+ elements that are used in more complex applications. After you
+ have worked through this tutorial, we recommend reading the
+ \l{mainwindows/application}{Application} example, which presents a
+ small GUI application, with menus, toolbars, a status bar, and so
+ on.
+*/
+
+/*!
+ \page tutorials-addressbook-part1.html
+
+ \example tutorials/addressbook/part1
+ \title Part 1 - Designing the User Interface
+
+ This first part covers the design of the basic graphical user
+ interface (GUI) for our address book application.
+
+ The first step in creating a GUI program is to design the user
+ interface. Here the our goal is to set up the labels and input
+ fields to implement a basic address book. The figure below is a
+ screenshot of the expected output.
+
+ \image addressbook-tutorial-part1-screenshot.png
+
+ We require two QLabel objects, \c nameLabel and \c addressLabel, as well
+ as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
+ object, \c addressText, to enable the user to enter a contact's name and
+ address. The widgets used and their positions are shown in the figure
+ below.
+
+ \image addressbook-tutorial-part1-labeled-screenshot.png
+
+ There are three files used to implement this address book:
+
+ \list
+ \o \c{addressbook.h} - the definition file for the \c AddressBook
+ class,
+ \o \c{addressbook.cpp} - the implementation file for the
+ \c AddressBook class, and
+ \o \c{main.cpp} - the file containing a \c main() function, with
+ an instance of \c AddressBook.
+ \endlist
+
+ \section1 Qt Programming - Subclassing
+
+ When writing Qt programs, we usually subclass Qt objects to add
+ functionality. This is one of the essential concepts behind creating
+ custom widgets or collections of standard widgets. Subclassing to
+ extend or change the behavior of a widget has the following advantages:
+
+ \list
+ \o We can write implementations of virtual or pure virtual functions to
+ obtain exactly what we need, falling back on the base class's implementation
+ when necessary.
+ \o It allows us to encapsulate parts of the user interface within a class,
+ so that the other parts of the application don't need to know about the
+ individual widgets in the user interface.
+ \o The subclass can be used to create multiple custom widgets in the same
+ application or library, and the code for the subclass can be reused in other
+ projects.
+ \endlist
+
+ Since Qt does not provide a specific address book widget, we subclass a
+ standard Qt widget class and add features to it. The \c AddressBook class
+ we create in this tutorial can be reused in situations where a basic address
+ book widget is needed.
+
+ \section1 Defining the AddressBook Class
+
+ The \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} file is
+ used to define the \c AddressBook class.
+
+ We start by defining \c AddressBook as a QWidget subclass and declaring
+ a constructor. We also use the Q_OBJECT macro to indicate that the class
+ uses internationalization and Qt's signals and slots features, even
+ if we do not use all of these features at this stage.
+
+ \snippet tutorials/addressbook/part1/addressbook.h class definition
+
+ The class holds declarations of \c nameLine and \c addressText,
+ the private instances of QLineEdit and QTextEdit mentioned
+ earlier. The data stored in \c nameLine and \c addressText will
+ be needed for many of the address book functions.
+
+ We don't include declarations of the QLabel objects we will use
+ because we will not need to reference them once they have been
+ created. The way Qt tracks the ownership of objects is explained
+ in the next section.
+
+ The Q_OBJECT macro itself implements some of the more advanced features of Qt.
+ For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
+ us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
+
+ We have now completed the \c addressbook.h file and we move on to
+ implement the corresponding \c addressbook.cpp file.
+
+ \section1 Implementing the AddressBook Class
+
+ The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
+ By convention, we pass this parameter to the base class's constructor.
+ This concept of ownership, where a parent can have one or more children,
+ is useful for grouping widgets in Qt. For example, if you delete a parent,
+ all of its children will be deleted as well.
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
+
+ In this constructor, the QLabel objects \c nameLabel and \c
+ addressLabel are instantiated, as well as \c nameLine and \c
+ addressText. The \l{QObject::tr()}{tr()} function returns a
+ translated version of the string, if there is one
+ available. Otherwise it returns the string itself. This function
+ marks its QString parameter as one that should be translated into
+ other languages. It should be used wherever a translatable string
+ appears.
+
+ When programming with Qt, it is useful to know how layouts work.
+ Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
+ and QGridLayout to handle the positioning of widgets.
+
+ \image addressbook-tutorial-part1-labeled-layout.png
+
+ We use a QGridLayout to position our labels and input fields in a
+ structured manner. QGridLayout divides the available space into a grid and
+ places widgets in the cells we specify with row and column numbers. The
+ diagram above shows the layout cells and the position of our widgets, and
+ we specify this arrangement using the following code:
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp layout
+
+ Notice that \c addressLabel is positioned using Qt::AlignTop as an
+ additional argument. This is to make sure it is not vertically centered in
+ cell (1,0). For a basic overview on Qt Layouts, refer to the
+ \l{Layout Management} documentation.
+
+ In order to install the layout object onto the widget, we have to invoke
+ the widget's \l{QWidget::setLayout()}{setLayout()} function:
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
+
+ Lastly, we set the widget's title to "Simple Address Book".
+
+ \section1 Running the Application
+
+ A separate file, \c main.cpp, is used for the \c main() function. Within
+ this function, we instantiate a QApplication object, \c app. QApplication
+ is responsible for various application-wide resources, such as the default
+ font and cursor, and for running an event loop. Hence, there is always one
+ QApplication object in every GUI application using Qt.
+
+ \snippet tutorials/addressbook/part1/main.cpp main function
+
+ We construct a new \c AddressBook widget on the stack and invoke
+ its \l{QWidget::show()}{show()} function to display it.
+ However, the widget will not be shown until the application's event loop
+ is started. We start the event loop by calling the application's
+ \l{QApplication::}{exec()} function; the result returned by this function
+ is used as the return value from the \c main() function. At this point,
+ it becomes apparent why we instanciated \c AddressBook on the stack: It
+ will now go out of scope. Therefore, \c AddressBook and all its child widgets
+ will be deleted, thus preventing memory leaks.
+*/
+
+/*!
+ \page tutorials-addressbook-part2.html
+
+ \example tutorials/addressbook/part2
+ \title Part 2 - Adding Addresses
+
+ The next step in creating the address book is to implement some
+ user interactions.
+
+ \image addressbook-tutorial-part2-add-contact.png
+
+ We will provide a push button that the user can click to add a new contact.
+ Also, some form of data structure is needed to store these contacts in an
+ organized way.
+
+ \section1 Defining the AddressBook Class
+
+ Now that we have the labels and input fields set up, we add push buttons to
+ complete the process of adding a contact. This means that our
+ \c addressbook.h file now has three QPushButton objects declared and three
+ corresponding public slots.
+
+ \snippet tutorials/addressbook/part2/addressbook.h slots
+
+ A slot is a function that responds to a particular signal. We will discuss
+ this concept in further detail when implementing the \c AddressBook class.
+ However, for an overview of Qt's signals and slots concept, you can refer
+ to the \l{Signals and Slots} document.
+
+ Three QPushButton objects (\c addButton, \c submitButton, and
+ \c cancelButton) are now included in our private variable declarations,
+ along with \c nameLine and \c addressText.
+
+ \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
+
+ We need a container to store our address book contacts, so that we can
+ traverse and display them. A QMap object, \c contacts, is used for this
+ purpose as it holds a key-value pair: the contact's name as the \e key,
+ and the contact's address as the \e{value}.
+
+ \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
+
+ We also declare two private QString objects, \c oldName and \c oldAddress.
+ These objects are needed to hold the name and address of the contact that
+ was last displayed, before the user clicked \gui Add. So, when the user clicks
+ \gui Cancel, we can revert to displaying the details of the last contact.
+
+ \section1 Implementing the AddressBook Class
+
+ Within the constructor of \c AddressBook, we set the \c nameLine and
+ \c addressText to read-only, so that we can only display but not edit
+ existing contact details.
+
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
+
+ Then, we instantiate our push buttons: \c addButton, \c submitButton, and
+ \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
+
+ The \c addButton is displayed by invoking the \l{QPushButton::show()}
+ {show()} function, while the \c submitButton and \c cancelButton are
+ hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
+ buttons will only be displayed when the user clicks \gui Add and this is
+ handled by the \c addContact() function discussed below.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
+
+ We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
+ to their respective slots. The figure below illustrates this.
+
+ \image addressbook-tutorial-part2-signals-and-slots.png
+
+ Next, we arrange our push buttons neatly to the right of our address book
+ widget, using a QVBoxLayout to line them up vertically.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
+
+ The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
+ the push buttons are not evenly spaced, but arranged closer to the top of
+ the widget. The figure below shows the difference between using
+ \l{QBoxLayout::addStretch()}{addStretch()} and not using it.
+
+ \image addressbook-tutorial-part2-stretch-effects.png
+
+ We then add \c buttonLayout1 to \c mainLayout, using
+ \l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
+ as \c buttonLayout1 is now a child of \c mainLayout.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
+
+ Our layout coordinates now look like this:
+
+ \image addressbook-tutorial-part2-labeled-layout.png
+
+ In the \c addContact() function, we store the last displayed contact
+ details in \c oldName and \c oldAddress. Then we clear these input
+ fields and turn off the read-only mode. The focus is set on \c nameLine
+ and we display \c submitButton and \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp addContact
+
+ The \c submitContact() function can be divided into three parts:
+
+ \list 1
+ \o We extract the contact's details from \c nameLine and \c addressText
+ and store them in QString objects. We also validate to make sure that the
+ user did not click \gui Submit with empty input fields; otherwise, a
+ QMessageBox is displayed to remind the user for a name and address.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
+
+ \o We then proceed to check if the contact already exists. If it does not
+ exist, we add the contact to \c contacts and we display a QMessageBox to
+ inform the user that the contact has been added.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
+
+ If the contact already exists, again, we display a QMessageBox to inform
+ the user about this, preventing the user from adding duplicate contacts.
+ Our \c contacts object is based on key-value pairs of name and address,
+ hence, we want to ensure that \e key is unique.
+
+ \o Once we have handled both cases mentioned above, we restore the push
+ buttons to their normal state with the following code:
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
+
+ \endlist
+
+ The screenshot below shows the QMessageBox object we use to display
+ information messages to the user.
+
+ \image addressbook-tutorial-part2-add-successful.png
+
+ The \c cancel() function restores the last displayed contact details and
+ enables \c addButton, as well as hides \c submitButton and
+ \c cancelButton.
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp cancel
+
+ The general idea behind adding a contact is to give the user the
+ flexibility to click \gui Submit or \gui Cancel at any time. The flowchart below
+ further explains this concept:
+
+ \image addressbook-tutorial-part2-add-flowchart.png
+*/
+
+/*!
+ \page tutorials-addressbook-part3.html
+
+ \example tutorials/addressbook/part3
+ \title Part 3 - Navigating between Entries
+
+ The address book is now about half complete. We should add the
+ capability to navigate among the contacts, but first we must
+ decide what sort of a data structure we need for containing these
+ contacts.
+
+ In the previous section, we used a QMap of key-value pairs with
+ the contact's name as the \e key, and the contact's address as the
+ \e value. This works well for our case. However, in order to
+ navigate and display each entry, a little bit of enhancement is
+ needed.
+
+ We enhance the QMap by making it replicate a data structure similar to a
+ circularly-linked list, where all elements are connected, including the
+ first element and the last element. The figure below illustrates this data
+ structure.
+
+ \image addressbook-tutorial-part3-linkedlist.png
+
+ \section1 Defining the AddressBook Class
+
+ To add navigation functions to the address book, we must add two
+ more slots to the \c AddressBook class: \c next() and \c
+ previous() to the \c addressbook.h file:
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation functions
+
+ We also require another two QPushButton objects, so we declare \c nextButton
+ and \c previousButton as private variables:
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
+
+ \section1 Implementing the AddressBook Class
+
+ In the \c AddressBook constructor in \c addressbook.cpp, we instantiate
+ \c nextButton and \c previousButton and disable them by default. This is
+ because navigation is only enabled when there is more than one contact
+ in the address book.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
+
+ We then connect these push buttons to their respective slots:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
+
+ The image below is the expected graphical user interface.
+
+ \image addressbook-tutorial-part3-screenshot.png
+
+ We follow basic conventions for \c next() and \c previous() functions by
+ placing the \c nextButton on the right and the \c previousButton on the
+ left. In order to achieve this intuitive layout, we use QHBoxLayout to
+ place the widgets side-by-side:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
+
+ The QHBoxLayout object, \c buttonLayout2, is then added to \c mainLayout.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
+
+ The figure below shows the coordinates of the widgets in \c mainLayout.
+ \image addressbook-tutorial-part3-labeled-layout.png
+
+ Within our \c addContact() function, we have to disable these buttons so
+ that the user does not attempt to navigate while adding a contact.
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
+
+ Also, in our \c submitContact() function, we enable the navigation
+ buttons, \c nextButton and \c previousButton, depending on the size
+ of \c contacts. As mentioned earlier, navigation is only enabled when
+ there is more than one contact in the address book. The following lines
+ of code demonstrates how to do this:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
+
+ We also include these lines of code in the \c cancel() function.
+
+ Recall that we intend to emulate a circularly-linked list with our QMap
+ object, \c contacts. So, in the \c next() function, we obtain an iterator
+ for \c contacts and then:
+
+ \list
+ \o If the iterator is not at the end of \c contacts, we increment it
+ by one.
+ \o If the iterator is at the end of \c contacts, we move it to the
+ beginning of \c contacts. This gives us the illusion that our QMap is
+ working like a circularly-linked list.
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp next() function
+
+ Once we have iterated to the correct object in \c contacts, we display
+ its contents on \c nameLine and \c addressText.
+
+ Similarly, for the \c previous() function, we obtain an iterator for
+ \c contacts and then:
+
+ \list
+ \o If the iterator is at the end of \c contacts, we clear the
+ display and return.
+ \o If the iterator is at the beginning of \c contacts, we move it to
+ the end.
+ \o We then decrement the iterator by one.
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
+
+ Again, we display the contents of the current object in \c contacts.
+
+*/
+
+/*!
+ \page tutorials-addressbook-part4.html
+
+ \example tutorials/addressbook/part4
+ \title Part 4 - Editing and Removing Addresses
+
+ Now we look at ways to modify the contents of contacts stored in
+ the address book.
+
+ \image addressbook-tutorial-screenshot.png
+
+ We now have an address book that not only holds contacts in an
+ organized manner, but also allows navigation. It would be
+ convenient to include edit and remove functions so that a
+ contact's details can be changed when needed. However, this
+ requires a little improvement, in the form of enums. We defined
+ two modes: \c{AddingMode} and \c{NavigationMode}, but they were
+ not defined as enum values. Instead, we enabled and disabled the
+ corresponding buttons manually, resulting in multiple lines of
+ repeated code.
+
+ Here we define the \c Mode enum with three different values:
+
+ \list
+ \o \c{NavigationMode},
+ \o \c{AddingMode}, and
+ \o \c{EditingMode}.
+ \endlist
+
+ \section1 Defining the AddressBook Class
+
+ The \c addressbook.h file is updated to contain the \c Mode enum:
+
+ \snippet tutorials/addressbook/part4/addressbook.h Mode enum
+
+ We also add two new slots, \c editContact() and \c removeContact(), to
+ our current list of public slots.
+
+ \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
+
+ In order to switch between modes, we introduce the \c updateInterface() function
+ to control the enabling and disabling of all QPushButton objects. We also
+ add two new push buttons, \c editButton and \c removeButton, for the edit
+ and remove functions mentioned earlier.
+
+ \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.h mode declaration
+
+ Lastly, we declare \c currentMode to keep track of the enum's current mode.
+
+ \section1 Implementing the AddressBook Class
+
+ We now implement the mode-changing features of the address
+ book. The \c editButton and \c removeButton are instantiated and
+ disabled by default. The address book starts with zero contacts
+ in memory.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
+
+ These buttons are then connected to their respective slots, \c editContact()
+ and \c removeContact(), and we add them to \c buttonLayout1.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
+
+ The \c editContact() function stores the contact's old details in
+ \c oldName and \c oldAddress, before switching the mode to \c EditingMode.
+ In this mode, the \c submitButton and \c cancelButton are both enabled,
+ hence, the user can change the contact's details and click either button.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
+
+ The \c submitContact() function has been divided in two with an \c{if-else}
+ statement. We check \c currentMode to see if it's in \c AddingMode. If it is,
+ we proceed with our adding process.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
+
+ Otherwise, we check to see if \c currentMode is in \c EditingMode. If it
+ is, we compare \c oldName with \c name. If the name has changed, we remove
+ the old contact from \c contacts and insert the newly updated contact.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
+
+ If only the address has changed (i.e., \c oldAddress is not the same as \c address),
+ we update the contact's address. Lastly, we set \c currentMode to
+ \c NavigationMode. This is an important step as it re-enables all the
+ disabled push buttons.
+
+ To remove a contact from the address book, we implement the
+ \c removeContact() function. This function checks to see if the contact
+ exists in \c contacts.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
+
+ If it does, we display a QMessageBox, to confirm the removal with the
+ user. Once the user has confirmed, we call \c previous() to ensure that the
+ user interface shows another contact, and we remove the contact using \l{QMap}'s
+ \l{QMap::remove()}{remove()} function. As a courtesy, we display a QMessageBox
+ to inform the user. Both the message boxes used in this function are shown below:
+
+ \image addressbook-tutorial-part4-remove.png
+
+ \section2 Updating the User Interface
+
+ We mentioned the \c updateInterface() function earlier as a means to
+ enable and disable the push buttons depending on the current mode.
+ The function updates the current mode according to the \c mode argument
+ passed to it, assigning it to \c currentMode before checking its value.
+
+ Each of the push buttons is then enabled or disabled, depending on the
+ current mode. The code for \c AddingMode and \c EditingMode is shown below:
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
+
+ For \c NavigationMode, however, we include conditions within the parameters
+ of the QPushButton::setEnabled() function. This is to ensure that
+ \c editButton and \c removeButton are enabled when there is at least one
+ contact in the address book; \c nextButton and \c previousButton are only
+ enabled when there is more than one contact in the address book.
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
+
+ By setting the mode and updating the user interface in the same
+ function, we avoid the possibility of the user interface getting
+ out of sync with the internal state of the application.
+ */
+
+/*!
+ \page tutorials-addressbook-part5.html
+
+ \example tutorials/addressbook/part5
+ \title Part 5 - Adding a Find Function
+
+ Here we look at ways to locate contacts and addresses in the
+ address book.
+
+ \image addressbook-tutorial-part5-screenshot.png
+
+ As we add contacts to our address book, it becomes tedious to
+ navigate the list with the \e Next and \e Previous buttons. A \e
+ Find function would be more efficient. The screenshot above shows
+ the \e Find button and its position on the panel of buttons.
+
+ When the user clicks on the \e Find button, it is useful to
+ display a dialog that prompts for a contact's name. Qt provides
+ QDialog, which we subclass here to implement a \c FindDialog
+ class.
+
+ \section1 Defining the FindDialog Class
+
+ \image addressbook-tutorial-part5-finddialog.png
+
+ In order to subclass QDialog, we first include the header for QDialog in
+ the \c finddialog.h file. Also, we use forward declaration to declare
+ QLineEdit and QPushButton since we will be using those widgets in our
+ dialog class.
+
+ As in our \c AddressBook class, the \c FindDialog class includes
+ the Q_OBJECT macro and its constructor is defined to accept a parent
+ QWidget, even though the dialog will be opened as a separate window.
+
+ \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
+
+ We define a public function, \c getFindText(), to be used by classes that
+ instantiate \c FindDialog. This function allows these classes to obtain the
+ search string entered by the user. A public slot, \c findClicked(), is also
+ defined to handle the search string when the user clicks the \gui Find
+ button.
+
+ Lastly, we define the private variables, \c findButton, \c lineEdit
+ and \c findText, corresponding to the \gui Find button, the line edit
+ into which the user types the search string, and an internal string
+ used to store the search string for later use.
+
+ \section1 Implementing the FindDialog Class
+
+ Within the constructor of \c FindDialog, we set up the private variables,
+ \c lineEdit, \c findButton and \c findText. We use a QHBoxLayout to
+ position the widgets.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp constructor
+
+ We set the layout and window title, as well as connect the signals to their
+ respective slots. Notice that \c{findButton}'s \l{QPushButton::clicked()}
+ {clicked()} signal is connected to to \c findClicked() and
+ \l{QDialog::accept()}{accept()}. The \l{QDialog::accept()}{accept()} slot
+ provided by QDialog hides the dialog and sets the result code to
+ \l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s
+ \c findContact() function know when the \c FindDialog object has been
+ closed. We will explain this logic in further detail when discussing the
+ \c findContact() function.
+
+ \image addressbook-tutorial-part5-signals-and-slots.png
+
+ In \c findClicked(), we validate \c lineEdit to ensure that the user
+ did not click the \gui Find button without entering a contact's name. Then, we set
+ \c findText to the search string, extracted from \c lineEdit. After that,
+ we clear the contents of \c lineEdit and hide the dialog.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
+
+ The \c findText variable has a public getter function, \c getFindText(),
+ associated with it. Since we only ever set \c findText directly in both the
+ constructor and in the \c findClicked() function, we do not create a
+ setter function to accompany \c getFindText().
+ Because \c getFindText() is public, classes instantiating and using
+ \c FindDialog can always access the search string that the user has
+ entered and accepted.
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
+
+ \section1 Defining the AddressBook Class
+
+ To ensure we can use \c FindDialog from within our \c AddressBook class, we
+ include \c finddialog.h in the \c addressbook.h file.
+
+ \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
+
+ So far, all our address book features have a QPushButton and a
+ corresponding slot. Similarly, for the \gui Find feature we have
+ \c findButton and \c findContact().
+
+ The \c findButton is declared as a private variable and the
+ \c findContact() function is declared as a public slot.
+
+ \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
+
+ Lastly, we declare the private variable, \c dialog, which we will use to
+ refer to an instance of \c FindDialog.
+
+ \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
+
+ Once we have instantiated a dialog, we will want to use it more than once;
+ using a private variable allows us to refer to it from more than one place
+ in the class.
+
+ \section1 Implementing the AddressBook Class
+
+ Within the \c AddressBook class's constructor, we instantiate our private
+ objects, \c findButton and \c findDialog:
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
+
+ Next, we connect the \c{findButton}'s
+ \l{QPushButton::clicked()}{clicked()} signal to \c findContact().
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
+
+ Now all that is left is the code for our \c findContact() function:
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
+
+ We start out by displaying the \c FindDialog instance, \c dialog. This is
+ when the user enters a contact name to look up. Once the user clicks
+ the dialog's \c findButton, the dialog is hidden and the result code is
+ set to QDialog::Accepted. This ensures that
+ our \c if statement is always true.
+
+ We then proceed to extract the search string, which in this case is
+ \c contactName, using \c{FindDialog}'s \c getFindText() function. If the
+ contact exists in our address book, we display it immediately. Otherwise,
+ we display the QMessageBox shown below to indicate that their search
+ failed.
+
+ \image addressbook-tutorial-part5-notfound.png
+*/
+
+/*!
+ \page tutorials-addressbook-part6.html
+
+ \example tutorials/addressbook/part6
+ \title Part 6 - Loading and Saving
+
+ This part covers the Qt file handling features we use to write
+ loading and saving routines for the address book.
+
+ \image addressbook-tutorial-part6-screenshot.png
+
+ Although browsing and searching the contact list are useful
+ features, our address book is not complete until we can save
+ existing contacts and load them again at a later time.
+
+ Qt provides a number of classes for \l{Input/Output and Networking}
+ {input and output}, but we have chosen to use two which are simple to use
+ in combination: QFile and QDataStream.
+
+ A QFile object represents a file on disk that can be read from and written
+ to. QFile is a subclass of the more general QIODevice class which
+ represents many different kinds of devices.
+
+ A QDataStream object is used to serialize binary data so that it can be
+ stored in a QIODevice and retrieved again later. Reading from a QIODevice
+ and writing to it is as simple as opening the stream - with the respective
+ device as a parameter - and reading from or writing to it.
+
+
+ \section1 Defining the AddressBook Class
+
+ We declare two public slots, \c saveToFile() and \c loadFromFile(), as well
+ as two QPushButton objects, \c loadButton and \c saveButton.
+
+ \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
+ \dots
+ \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
+
+ \section1 Implementing the AddressBook Class
+
+ In our constructor, we instantiate \c loadButton and \c saveButton.
+ Ideally, it would be more user-friendly to set the push buttons' labels
+ to "Load contacts from a file" and "Save contacts to a file". However, due
+ to the size of our other push buttons, we set the labels to \gui{Load...}
+ and \gui{Save...}. Fortunately, Qt provides a simple way to set tooltips with
+ \l{QWidget::setToolTip()}{setToolTip()} and we use it in the following way
+ for our push buttons:
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
+ \dots
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
+
+ Although it is not shown here, just like the other features we implemented,
+ we add the push buttons to the layout panel on the right, \c buttonLayout1,
+ and we connect the push buttons' \l{QPushButton::clicked()}{clicked()}
+ signals to their respective slots.
+
+ For the saving feature, we first obtain \c fileName using
+ QFileDialog::getSaveFileName(). This is a convenience function provided
+ by QFileDialog, which pops up a modal file dialog and allows the user to
+ enter a file name or select any existing \c{.abk} file. The \c{.abk} file
+ is our Address Book extension that we create when we save contacts.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
+
+ The file dialog that pops up is displayed in the screenshot below:
+
+ \image addressbook-tutorial-part6-save.png
+
+ If \c fileName is not empty, we create a QFile object, \c file, with
+ \c fileName. QFile works with QDataStream as QFile is a QIODevice.
+
+ Next, we attempt to open the file in \l{QIODevice::}{WriteOnly} mode.
+ If this is unsuccessful, we display a QMessageBox to inform the user.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
+
+ Otherwise, we instantiate a QDataStream object, \c out, to write the open
+ file. QDataStream requires that the same version of the stream is used
+ for reading and writing. We ensure that this is the case by setting the
+ version used to the \l{QDataStream::Qt_4_5}{version introduced with Qt 4.5}
+ before serializing the data to \c file.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
+
+ For the loading feature, we also obtain \c fileName using
+ QFileDialog::getOpenFileName(). This function, the counterpart to
+ QFileDialog::getSaveFileName(), also pops up the modal file dialog and
+ allows the user to enter a file name or select any existing \c{.abk} file
+ to load it into the address book.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
+
+ On Windows, for example, this function pops up a native file dialog, as
+ shown in the following screenshot.
+
+ \image addressbook-tutorial-part6-load.png
+
+ If \c fileName is not empty, again, we use a QFile object, \c file, and
+ attempt to open it in \l{QIODevice::}{ReadOnly} mode. Similar to our
+ implementation of \c saveToFile(), if this attempt is unsuccessful, we
+ display a QMessageBox to inform the user.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
+
+ Otherwise, we instantiate a QDataStream object, \c in, set its version as
+ above and read the serialized data into the \c contacts data structure.
+ The \c contacts object is emptied before data is read into it to simplify
+ the file reading process. A more advanced method would be to read the
+ contacts into a temporary QMap object, and copy over non-duplicate contacts
+ into \c contacts.
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
+
+ To display the contacts that have been read from the file, we must first
+ validate the data obtained to ensure that the file we read from actually
+ contains address book contacts. If it does, we display the first contact;
+ otherwise, we display a QMessageBox to inform the user about the problem.
+ Lastly, we update the interface to enable and disable the push buttons
+ accordingly.
+*/
+
+/*!
+ \page tutorials-addressbook-part7.html
+
+ \example tutorials/addressbook/part7
+ \title Part 7 - Additional Features
+
+ This part covers some additional features that make the address
+ book more convenient for the frequent user.
+
+ \image addressbook-tutorial-part7-screenshot.png
+
+ Although our address book is useful in isolation, it would be
+ better if we could exchange contact data with other applications.
+ The vCard format is a popular file format that can be used for
+ this purpose. Here we extend our address book client to allow
+ contacts to be exported to vCard \c{.vcf} files.
+
+ \section1 Defining the AddressBook Class
+
+ We add a QPushButton object, \c exportButton, and a corresponding public
+ slot, \c exportAsVCard() to our \c AddressBook class in the
+ \c addressbook.h file.
+
+ \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
+ \dots
+ \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
+
+ \section1 Implementing the AddressBook Class
+
+ Within the \c AddressBook constructor, we connect \c{exportButton}'s
+ \l{QPushButton::clicked()}{clicked()} signal to \c exportAsVCard().
+ We also add this button to our \c buttonLayout1, the layout responsible
+ for our panel of buttons on the right.
+
+ In our \c exportAsVCard() function, we start by extracting the contact's
+ name into \c name. We declare \c firstName, \c lastName and \c nameList.
+ Next, we look for the index of the first white space in \c name. If there
+ is a white space, we split the contact's name into \c firstName and
+ \c lastName. Then, we replace the space with an underscore ("_").
+ Alternately, if there is no white space, we assume that the contact only
+ has a first name.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
+
+ As with the \c saveToFile() function, we open a file dialog to let the user
+ choose a location for the file. Using the file name chosen, we create an
+ instance of QFile to write to.
+
+ We attempt to open the file in \l{QIODevice::}{WriteOnly} mode. If this
+ process fails, we display a QMessageBox to inform the user about the
+ problem and return. Otherwise, we pass the file as a parameter to a
+ QTextStream object, \c out. Like QDataStream, the QTextStream class
+ provides functionality to read and write plain text to files. As a result,
+ the \c{.vcf} file generated can be opened for editing in a text editor.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
+
+ We then write out a vCard file with the \c{BEGIN:VCARD} tag, followed by
+ the \c{VERSION:2.1} tag. The contact's name is written with the \c{N:}
+ tag. For the \c{FN:} tag, which fills in the "File as" property of a vCard,
+ we have to check whether the contact has a last name or not. If the contact
+ does, we use the details in \c nameList to fill it. Otherwise, we write
+ \c firstName only.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
+
+ We proceed to write the contact's address. The semicolons in the address
+ are escaped with "\\", the newlines are replaced with semicolons, and the
+ commas are replaced with spaces. Lastly, we write the \c{ADR;HOME:;}
+ tag, followed by \c address and then the \c{END:VCARD} tag.
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
+
+ In the end, a QMessageBox is displayed to inform the user that the vCard
+ has been successfully exported.
+
+ \e{vCard is a trademark of the \l{http://www.imc.org}
+ {Internet Mail Consortium}}.
+*/
diff --git a/doc/src/tutorials/modelview.qdoc b/doc/src/tutorials/modelview.qdoc
new file mode 100644
index 0000000000..efd0ff2efb
--- /dev/null
+++ b/doc/src/tutorials/modelview.qdoc
@@ -0,0 +1,901 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page modelview.html
+ \ingroup tutorials
+ \startpage {index.html}{Qt Reference Documentation}
+
+ \title Model/View Tutorial
+ \brief An introduction to ModelView programming
+
+ Every UI developer should know about ModelView programming and the goal of
+ this tutorial is to provide you with an easily understandable introduction
+ to this topic.
+
+ Table, list and tree widgets are components frequently used in GUIs. There
+ are 2 different ways how these widgets can access their data. The
+ traditional way involves widgets which include internal containers for
+ storing data. This approach is very intuitive, however, in many non-trivial
+ applications, it leads to data synchronization issues.
+ The second approach is model/view programming, in
+ which widgets do not maintain internal data containers. They access external
+ data through a standardized interface and therefore avoid data duplication.
+ This may seem complicated at first, but once you take a closer look, it is
+ not only easy to grasp, but the many benefits of model/view programming also
+ become clearer.
+
+ \image treeview.png
+
+ In the process, we will learn about some basic technologies provided by Qt,
+ such as:
+
+ \list
+ \o The difference between standard and model/view widgets
+ \o Adapters betweeen forms and models
+ \o Developing a simple model/view application
+ \o Predefined models
+ \o Intermediate topics such as:
+ \list
+ \o Tree views
+ \o Selection
+ \o Delegates
+ \o Debugging with model test
+ \endlist
+ \endlist
+
+ You will also learn whether your new application can be written easier with
+ model/view programming or if classic widgets will work just as well.
+
+ This tutorial includes example code for you to edit and integrate into your
+ project. The tutorial's source code is located in Qt's
+ \c examples/tutorials/modelview directory.
+
+ For more detailed information you may also want to look at the
+ \l{model-view-programming.html}{reference documentation}
+
+ If you are completely new to Qt, please read \l{How to Learn Qt} if you
+ have not already done so.
+
+
+ \section1 1. Introduction
+
+ Model/View is a technology used to separate data from views in widgets that
+ handle data sets. Standard widgets are not designed for separating data
+ from views and this is why Qt 4 has two different types of widgets. Both
+ types of widgets look the same, but they interact with data differently.
+
+ \table
+ \row
+ \o Standard widgets use data that is part of the widget.
+ \o \image standardwidget.png
+ \row
+ \o View classes operate on external data (the model)
+ \o \image modelview.png
+ \endtable
+
+ \section2 1.1 Standard Widgets
+
+ Let's have a closer look at a standard table widget. A table widget is a 2D
+ array of the data elements that the user can change. The table widget can be
+ integrated into a program flow by reading and writing the data elements that
+ the table widget provides.
+
+ This method is very intuitive and useful in many applications, but displaying
+ and editing a database table with a standard table widget can be problematic.
+ Two copies of the data have to be coordinated: one outside the
+ widget; one inside the widget. The developer is responsible for
+ synchronizing both versions. Besides this, the tight coupling of presentation and data
+ makes it harder to write unit tests.
+
+ \section2 1.2 Model/View to the Rescue
+
+ Model/view stepped up to provide a solution that uses a more versatile
+ architecture. Model/view eliminates the data consistency problems that may
+ occur with standard widgets. Model/view also makes it easier to use more
+ than one view of the same data because one model can be passed on to many
+ views. The most important difference is that model/view widgets do not store
+ data behind the table cells. In fact, they operate directly from your data.
+ Since view classes do not know your data's structure, you need to provide a
+ wrapper to make your data conform to the QAbstractItemModel interface. A
+ view uses this interface to read from and write to your data. Any instance
+ of a class that implements QAbstractItemModel is said to be a model. Once
+ the view receives a pointer to a model, it will read and display its content
+ and be its editor.
+
+ \section2 1.3 Overview of the Model/View Widgets
+
+ Here is an overview of the model/view widgets and their corresponding
+ standard widgets.
+
+ \table
+ \header
+ \o Widget
+ \o Standard Widget\br
+ (an item based convenience class)
+ \o Model/View View Class\br
+ (for use with external data)
+ \row
+ \o \inlineimage listview.png
+ \o \l QListWidget
+ \o \l QListView
+ \row
+ \o \inlineimage tableview.png
+ \o \l QTableWidget
+ \o \l QTableView
+ \row
+ \o \inlineimage treeview.png
+ \o \l QTreeWidget
+ \o \l QTreeView
+ \row
+ \o \inlineimage columnview.png
+ \o
+ \o \l QColumnView shows a tree as a hierarchy of lists
+ \row
+ \o \inlineimage modelview-combobox.png
+ \o {2, 1} \l QComboBox can work as both a view class and also
+ as a traditional widget
+ \endtable
+
+ \section2 1.4 Using Adapters between Forms and Models
+
+ Having adapters between forms and models can come in handy.
+
+ We can edit data stored in tables directly from within the table itself, but
+ it's much more comfortable to edit data in text fields. There is no direct
+ model/view counterpart that separates data and views for widgets that
+ operate on one value (QLineEdit, QCheckBox ...) instead of a dataset, so we
+ need an adapter in order to connect the form to the source of data.
+
+ \l QDataWidgetMapper is a great solution because it maps form widgets to a
+ table row and makes it very easy to build forms for database tables.
+
+ \image widgetmapper.png
+
+ Another example of an adapter is \l QCompleter. Qt has \l QCompleter for
+ providing auto-completions in Qt widgets such as \l QComboBox and, as shown
+ below, \l QLineEdit. \l QCompleter uses a model as its data source.
+
+ \image qcompleter.png
+
+
+ \section1 2. A Simple Model/View Application
+ If you want to develop a model/view application, where should you start?
+ We recommend starting with a simple example and extending it step-by-step.
+ This makes understanding the architecture a lot easier. Trying to understand
+ the model/view architecture in detail before invoking the IDE has proven
+ to be less convenient for many developers. It is substantially easier to
+ start with a simple model/view application that has demo data. Give it a
+ try! Simply replace the data in the examples below with your own.
+
+ Below are 7 very simple and independent applications that show different
+ sides of model/view programming. The source code can be found inside the
+ \c{examples/tutorials/modelview} directory.
+
+ \section2 2.1 A Read Only Table
+
+ We start with an application that uses a QTableView to show data. We will
+ add editing capabilities later.
+
+ (file source: examples/tutorials/modelview/1_readonly/main.cpp)
+ \snippet examples/tutorials/modelview/1_readonly/main.cpp Quoting ModelView Tutorial
+
+ We have the usual \l {modelview-part2-main-cpp.html}{main()} function:
+
+ Here is the interesting part: We create an instance of MyModel and use
+ \l{QTableView::setModel()}{tableView.setModel(&myModel);} to pass a
+ pointer of it to to \l{QTableView}{tableView}. \l{QTableView}{tableView}
+ will invoke the methods of the pointer it has received to find out two
+ things:
+
+ \list
+ \o How many rows and columns should be displayed.
+ \o What content should be printed into each cell.
+ \endlist
+
+ The model needs some code to respond to this.
+
+ We have a table data set, so let's start with QAbstractTableModel since it
+ is easier to use than the more general QAbstractItemModel.
+
+ (file source: examples/tutorials/modelview/1_readonly/mymodel.h)
+ \snippet examples/tutorials/modelview/1_readonly/mymodel.h Quoting ModelView Tutorial
+
+ QAbstractTableModel requires the implementation of three abstract methods.
+
+ (file source: examples/tutorials/modelview/1_readonly/mymodel.cpp)
+ \snippet examples/tutorials/modelview/1_readonly/mymodel.cpp Quoting ModelView Tutorial
+
+ The number of rows and columns is provided by
+ \l{QAbstractItemModel::rowCount()}{MyModel::rowCount()} and
+ \l{QAbstractItemModel::columnCount()}{MyModel::columnCount()}. When the view
+ has to know what the cell's text is, it calls the method
+ \l{QAbstractItemModel::data()}{MyModel::data()}. Row and column information
+ is specified with parameter \c index and the role is set to
+ \l{Qt::ItemDataRole}{Qt::DisplayRole}. Other roles are covered in the next
+ section. In our example, the data that should be displayed is generated. In
+ a real application, \c MyModel would have a member called \c MyData, which
+ serves as the target for all reading and writing operations.
+
+ This small example demonstrates the passive nature of a model. The model
+ does not know when it will be used or which data is needed. It simply
+ provides data each time the view requests it.
+
+ What happens when the model's data needs to be changed? How does the view
+ realize that data has changed and needs to be read again? The model has to
+ emit a signal that indicates what range of cells has changed. This will be
+ demonstrated in section 2.3.
+
+ \section2 2.2 Extending the Read Only Example with Roles
+
+ In addition to controlling what text the view displays, the model also
+ controls the text's appearance. When we slightly change the model, we get
+ the following result: \image readonlytable_role.png
+
+ In fact, nothing except for the \l{QAbstractItemModel::}{data()} method
+ needs to be changed to set fonts, background colour, alignment and a
+ checkbox.
+ Below is the \l{QAbstractItemModel::data()}{data()} method that produces the
+ result shown above. The difference is that this time we use parameter int
+ role to return different pieces of information depending on its value.
+
+ (file source: examples/tutorials/modelview/2_formatting/mymodel.cpp)
+ \snippet examples/tutorials/modelview/2_formatting/mymodel.cpp Quoting ModelView Tutorial
+
+ Each formatting property will be requested from the model with a separate
+ call to the \l{QAbstractItemModel::data()}{data()} method. The \c role
+ parameter is used to let the model know which property is being requested:
+
+ \table
+ \header
+ \o \l{Qt::ItemDataRole}{enum Qt::ItemDataRole}
+ \o Meaning
+ \o Type
+ \row
+ \o \l{Qt::ItemDataRole}{}Qt::DisplayRole
+ \o text
+ \o QString
+ \row
+ \o \l{Qt::ItemDataRole}{Qt::FontRole}
+ \o font
+ \o QFont
+ \row
+ \o \l{Qt::ItemDataRole}{BackgroundRole}
+ \o brush for the background of the cell
+ \o QBrush
+ \row
+ \o \l{Qt::ItemDataRole}{Qt::TextAlignmentRole}
+ \o text alignment
+ \o \l{Qt::AlignmentFlag}{enum Qt::AlignmentFlag}
+ \row
+ \o {1, 3} \l{Qt::ItemDataRole}{Qt::CheckStateRole}
+ \o {1, 3} suppresses checkboxes with \l{QVariant}{QVariant()},
+
+ sets checkboxes with \l{Qt::CheckState}{Qt::Checked}
+
+ or \l{Qt::CheckState}{Qt::Unchecked}
+ \o {1, 3} \l{Qt::ItemDataRole}{enum Qt::ItemDataRole}
+ \endtable
+
+ Refer to the Qt namespace documentation to learn more about the
+ \l{Qt::ItemDataRole}{Qt::ItemDataRole} enum's capabilities.
+
+ Now we need to determine how using a separated model impacts the
+ application's performance, so let's trace how often the view calls the
+ \l{QAbstractItemModel::}{data()} method. In order to track how often the
+ view calls the model, we have put a debug statement in the
+ \l{QAbstractItemModel::}{data()} method, which logs onto the error output
+ stream. In our small example, \l{QAbstractItemModel::}{data()} will be
+ called 42 times.
+ Each time you hover the cursor over the field,
+ \l{QAbstractItemModel::}{data()} will be called again \mdash 7 times for
+ each cell. That's why it is important to make sure that your data is
+ available when \l{QAbstractItemModel::}{data()} is invoked and expensive
+ lookup operations are cached.
+
+ \section2 2.3 A Clock inside a Table Cell
+
+ \image clock.png
+
+ We still have a read only table, but this time the content changes every
+ second because we are showing the current time.
+
+ (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
+ \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_QVariant
+
+ Something is missing to make the clock tick. We need to tell the view every
+ second that the time has changed and that it needs to be read again. We do
+ this with a timer. In the constructor, we set its interval to 1 second and
+ connect its timeout signal.
+
+ (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
+ \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_a
+
+ Here is the corresponding slot:
+
+ (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
+ \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_b
+
+ We ask the view to read the data in the top left cell again by emitting the
+ \l{QAbstractItemModel::}{dataChanged()} signal. Note that we did not
+ explicitly connect the \l{QAbstractItemModel::}{dataChanged()} signal to the
+ view. This happened automatically when we called \l{QTableView::}{setModel()}.
+
+ \section2 2.4 Setting up Headers for Columns and Rows
+
+ Headers can be hidden via a view method: \c{tableView->verticalHeader()->hide();}
+ \image modelview-header.png
+
+ The header content, however, is set via the model, so we reimplement the
+ \l{QAbstractItemModel::headerData()}{headerData()} method:
+
+ (file source: examples/tutorials/modelview/4_headers/mymodel.cpp)
+ \snippet examples/tutorials/modelview/4_headers/mymodel.cpp quoting mymodel_c
+
+ Note that method \l{QAbstractItemModel::headerData()}{headerData()} also has
+ a parameter role which has the same meaning as in
+ \l{QAbstractItemModel::data()}{MyModel::data()}.
+
+ \section2 2.5 The Minimal Editing Example
+
+ In this example, we are going to build an application that automatically
+ populates a window title with content by repeating values entered into table
+ cells. To be able to access the window title easily we put the QTableView in
+ a QMainWindow.
+
+ The model decides whether editing capabilities are available. We only have
+ to modify the model in order for the available editing capabilities to be
+ enabled. This is done by reimplementing the following virtual methods:
+ \l{QAbstractItemModel::}{setData()} and \l{QAbstractItemModel::}{flags()}.
+
+ (file source: examples/tutorials/modelview/5_edit/mymodel.h)
+ \snippet examples/tutorials/modelview/5_edit/mymodel.h Quoting ModelView Tutorial
+
+ We use \c the two-dimensional array QString \c m_gridData to store our data.
+ This makes \c m_gridData the core of \c MyModel. The rest of \c MyModel acts
+ like a wrapper and adapts \c m_gridData to the QAbstractItemModel
+ interface. We have also introduced the \c editCompleted() signal, which
+ makes it possible to transfer the modified text to the window title.
+
+ (file source: examples/tutorials/modelview/5_edit/mymodel.cpp)
+ \snippet examples/tutorials/modelview/5_edit/mymodel.cpp quoting mymodel_e
+
+ \l{QAbstractItemModel::setData()}{setData()} will be called each time the
+ user edits a cell. The \c index parameter tells us which field has been
+ edited and \c value provides the result of the editing process. The role
+ will always be set to \l Qt::EditRole because our cells only contain text.
+ If a checkbox were present and user permissions are set to allow the
+ checkbox to be selected, calls would also be made with the role set to
+ \l Qt::CheckStateRole.
+
+ (file source: examples/tutorials/modelview/5_edit/mymodel.cpp)
+ \snippet examples/tutorials/modelview/5_edit/mymodel.cpp quoting mymodel_f
+
+ Various properties of a cell can be adjusted with
+ \l{QAbstractItemModel::flags()}{flags()}.
+
+ Returning \l{Qt::ItemFlag}{Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled}
+ is enough to show an editor that a cell can be selected.
+
+ If editing one cell modifies more data than the data in that particular
+ cell, the model must emit a \l{QAbstractItemModel::}{dataChanged()} signal
+ in order for the data that has been changed to be read.
+
+
+ \section1 3. Intermediate Topics
+
+ \section2 3.1 TreeView
+
+ You can convert the example above into an application with a tree view.
+ Simply replace QTableView with QTreeView, which results in a read/write
+ tree. No changes have to be made to the model. The tree won't have any
+ hierarchies because there aren't any hierarchies in the model itself.
+
+ \image dummy_tree.png
+
+ QListView, QTableView and QTreeView all use a model abstraction, which is a
+ merged list, table and tree. This makes it possible to use several different
+ types of view classes from the same model.
+
+ \image list_table_tree.png
+
+ This is how our example model looks so far:
+
+ \image example_model.png
+
+ We want to present a real tree. We have wrapped our data in the examples
+ above in order to make a model. This time we use QStandardItemModel, which
+ is a container for hierarchical data that also implements
+ QAbstractItemModel. To show a tree, QStandardItemModel must be populated
+ with \l{QStandardItem}s, which are able to hold all the standard properties
+ of items like text, fonts, checkboxes or brushes.
+
+ \image tree_2_with_algorithm.png
+
+ (file source: examples/tutorials/modelview/6_treeview/mainwindow.cpp)
+ \snippet examples/tutorials/modelview/6_treeview/mainwindow.cpp Quoting ModelView Tutorial
+
+ We simply instantiate a QStandardItemModel and add a couple of
+ \l{QStandardItem}{QStandardItems} to the constructor. We can then make a
+ hierarchical data structure because a QStandardItem can hold other
+ \l{QStandardItem}{QStandardItems}. Nodes are collapsed and expanded within
+ the view.
+
+ \section2 3.2 Working with Selections
+
+ We want to access a selected item's content in order to output it into the
+ window title together with the hierarchy level.
+
+ \image selection2.png
+
+ So let's create a couple of items:
+
+ (file source: examples/tutorials/modelview/7_selections/mainwindow.cpp)
+ \snippet examples/tutorials/modelview/7_selections/mainwindow.cpp quoting modelview_a
+
+ Views manage selections within a separate selection model, which can be
+ retrieved with the \l{QAbstractItemView::}{selectionModel()} method. We
+ retrieve the selection Model in order to connect a slot to its
+ \l{QAbstractItemView::}{selectionChanged()} signal.
+
+ (file source: examples/tutorials/modelview/7_selections/mainwindow.cpp)
+ \snippet examples/tutorials/modelview/7_selections/mainwindow.cpp quoting modelview_b
+
+ We get the model index that corresponds to the selection by calling
+ \l{QItemSelectionModel::currentIndex()}{treeView->selectionModel()->currentIndex()}
+ and we get the the field's string by using the model index. Then we just
+ calculate the item's \c hierarchyLevel. Top level items do not have parents
+ and the \l{QAbstractItemModel::}{parent()} method will return a default
+ constructed \l{QModelIndex}{QModelIndex()}. This is why we use the
+ \l{QAbstractItemModel::}{parent()} method to iterate to the top level while
+ counting the steps performed during iteration.
+
+ The selection model (as shown above) can be retrieved, but it can also be
+ set with \l{QAbstractItemView}{QAbstractItemView::setSelectionModel}. This
+ is how it's possible to have 3 view classes with synchronised selections
+ because only one instance of a selection model is used. To share a selection
+ model between 3 views use \l{QAbstractItemView::}{selectionModel()} and
+ assign the result to the second and third view class with
+ \l{QAbstractItemView::}{setSelectionModel()}.
+
+ \section2 3.3 Predefined Models
+
+ The typical way to use model/view is to wrap specific data to make it usable
+ with view classes. Qt, however, also provides predefined models for common
+ underlying data structures. If one of the available data structures is
+ suitable for your application, a predefined model can be a good choice.
+
+ \table
+ \row
+ \o QStringListModel
+ \o Stores a list of strings
+ \row
+ \o QStandardItemModel
+ \o Stores arbitrary hierarchical items
+ \row
+ \o QFileSystemModel\br
+ QDirModel
+ \o Encapsulate the local file system
+ \row
+ \o QSqlQueryModel
+ \o Encapsulate an SQL result set
+ \row
+ \o QSqlTableModel
+ \o Encapsulates an SQL table
+ \row
+ \o QSqlRelationalTableModel
+ \o Encapsulates an SQL table with foreign keys
+ \row
+ \o QSortFilterProxyModel
+ \o Sorts and/or filters another model
+
+ \endtable
+
+ \section2 3.4 Delegates
+
+ In all examples so far, data is presented as text or a checkbox in a cell
+ and is edited as text or a checkbox. The component that provides these
+ presentation and editing services is called a \e delegate. We are only just
+ beginning to work with the delegate because the view uses a default
+ delegate. But imagine that we want to have a different editor (e.g., a
+ slider or a drop down list) Or imagine that we want to present data as
+ graphics.
+ Let's take a look at an example called \l{Star Delegate Example}{Star
+ Delegate}, in which stars are used to show a rating:
+
+ \image stardelegate.png
+
+ The view has a \l{QAbstractItemView::}{setItemDelegate()} method that
+ replaces the default delegate and installs a custom delegate.
+ A new delegate can be written by creating a class that inherits from
+ QStyledItemDelegate. In order to write a delegate that displays stars and
+ has no input capabilities, we only need to override 2 methods.
+
+ \code
+ class StarDelegate : public QStyledItemDelegate
+ {
+ Q_OBJECT
+ public:
+ StarDelegate(QWidget *parent = 0);
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ };
+ \endcode
+
+ \l{QStyledItemDelegate::}{paint()} draws stars depending on the content of
+ the underlying data. The data can be looked up by calling
+ \l{QModelIndex::data()}{index.data()}. The delegate's
+ \l{QAbstractItemDelegate::}{sizeHint()} method is used to obtain each
+ star's dimensions, so the the cell will provide enough height and width to
+ accommodate the stars.
+
+ Writing custom delegates is the right choice if you want to show your data
+ with a custom graphical representation inside the grid of the view class. If
+ you want to leave the grid, you would not use a custom delegate but a custom
+ view class.
+
+ Other references to delegates in Qt Documentation:
+
+ \list
+ \o \l{Spin Box Delegate Example}
+ \o \l{QAbstractItemDelegate}{QAbstractItemDelegate Class Reference}
+ \o \l{QSqlRelationalDelegate}{QSqlRelationalDelegate Class Reference}
+ \o \l{QStyledItemDelegate}{QStyledItemDelegate Class Reference}
+ \o \l{QItemDelegate}{QItemDelegate Class Reference}
+ \endlist
+
+
+ \section2 3.5 Debugging with ModelTest
+
+ The passive nature of models provides new challenges for programmers.
+ Inconsistencies in the model can cause the application to crash. Since the
+ model is hit by numerous calls from the view, it is hard to find out which
+ call has crashed the application and which operation has introduced the
+ problem.
+
+ Qt Labs provides software called
+ \l{http://labs.qt.nokia.com/page/Projects/Itemview/Modeltest}{ModelTest},
+ which checks models while your programming is running. Every time the model
+ is changed, ModelTest scans the model and reports errors with an assert.
+ This is especially important for tree models, since their hierarchical
+ nature leaves many possibilities for subtle inconsistencies.
+
+ Unlike view classes, ModelTest uses out of range indexes to test the model.
+ This means your application may crash with ModelTest even if it runs
+ perfectly without it. So you also need to handle all of the indexes that are
+ out of range when using ModelTest.
+
+
+ \section1 4. Good Sources of Additional Information
+
+ \section2 4.1 Books
+
+ Model/View programming is covered quite extensively in the documentation of
+ Qt but also in several good books.
+
+ \list 1
+ \o \bold{C++ GUI Programming with Qt 4} / Jasmin Blanchette, Mark Summerfield,
+ \e{Prentice Hall, 2nd edition}, ISBN 0-13-235416-0. Also available in
+ German: \bold{C++ GUI Programmierung mit Qt 4: Die offizielle Einführung},
+ \e{Addison-Wesley}, ISBN 3-827327-29-6
+ \o \bold{The Book of Qt4, The Art of Building Qt Applications} / Daniel Molkentin,
+ \e{Open Source Press}, ISBN 1-59327-147-6.
+ Translated from \bold{Qt 4, Einführung in die Applikationsentwicklung},
+ \e{Open Source Press}, ISBN 3-937514-12-0.
+ \o \bold{Foundations of Qt Development} / Johan Thelin, \e{Apress}, ISBN 1-59059-831-8.
+ \o \bold{Advanced Qt Programming} / Mark Summerfield, \e{Prentice Hall}, ISBN 0-321-63590-6.
+ This book covers Model/View programming on more than 150 pages.
+ \endlist
+
+ More information about these books is available on the
+ \l{Books about Qt Programming}{Qt Web site}.
+
+ The following list provides an overview of example programs contained in the first three
+ books listed above. Some of them make very good templates for developing similar
+ applications.
+
+ \table
+ \header
+ \o Example name
+ \o View class used
+ \o Model used
+ \o Aspects covered
+ \o
+ \row
+ \o Team Leaders
+ \o QListview
+ \o QStringListModel
+ \o
+ \o Book 1, Chapter 10, Figure 10.6
+ \row
+ \o Directory Viewer
+ \o QTreeView
+ \o QDirModel
+ \o
+ \o Book 1, Chapter 10, Figure 10.7
+ \row
+ \o Color Names
+ \o QListView
+ \o QSortFilterProxyModel
+ applied to QStringListModel
+ \o
+ \o Book 1, Chapter 10, Figure 10.8
+ \row
+ \o Currencies
+ \o QTableView
+ \o custom model based on
+ QAbstractTableModel
+ \o Read only
+ \o Book 1, Chapter 10, Figure 10.10
+ \row
+ \o Cities
+ \o QTableView
+ \o Custom model based on
+ QAbstractTableModel
+ \o Read / write
+ \o Book 1, Chapter 10, Figure 10.12
+ \row
+ \o Boolean Parser
+ \o QTreeView
+ \o Custom model based on
+ QAbstractItemModel
+ \o Read only
+ \o Book 1, Chapter 10, Figure 10.14
+ \row
+ \o Track Editor
+ \o {2, 1} QTableWidget
+ \o Custom delegate providing a custom editor
+ \o Book 1, Chapter 10, Figure 10.15
+
+ \row
+ \o Four directory views
+ \o QListView
+ QTableView
+ QTreeView
+ \o QDirModel
+ \o Demonstrates the use of multiple views
+ \o Book2, Chapter 8.2
+ \row
+ \o Address Book
+ \o QListView
+ QTableView
+ QTreeView
+ \o Custom model based on
+ QAbstractTableModel
+ \o Read / write
+ \o Book2, Chapter 8.4
+ \row
+ \o Address Book with sorting
+ \o
+ \o QProxyModel
+ \o Introducing sort and filter capabilities
+ \o Book2, Chapter 8.5
+ \row
+ \o Address Book
+ with checkboxes
+ \o
+ \o
+ \o Introducing checkboxes in model/view
+ \o Book2, Chapter 8.6
+ \row
+ \o Address Book with transposed grid
+ \o
+ \o Custom proxy Model based on QAbstractProxyModel
+ \o Introducing a custom model
+ \o Book2, Chapter 8.7
+ \row
+ \o Address Book with drag and drop
+ \o
+ \o
+ \o Introducing drag and drop support
+ \o Book2, Chapter 8.8
+ \row
+ \o Address Book with custom editor
+ \o
+ \o
+ \o Introducing custom delegates
+ \o Book2, Chapter 8.9
+ \row
+ \o Views
+ \o QListView
+ QTableView
+ QTreeView
+ \o QStandardItemModel
+ \o Read only
+ \o Book 3, Chapter 5, figure 5-3
+ \row
+ \o Bardelegate
+ \o QTableView
+ \o
+ \o Custom delegate for presentation based on QAbstractItemDelegate
+ \o Book 3, Chapter 5, figure 5-5
+ \row
+ \o Editdelegate
+ \o QTableView
+ \o
+ \o Custom delegate for editing based on QAbstractItemDelegate
+ \o Book 3, Chapter 5, figure 5-6
+ \row
+ \o Singleitemview
+ \o Custom view based on QAbstractItemView
+ \o
+ \o Custom view
+ \o Book 3,
+ Chapter 5,
+ figure 5-7
+ \row
+ \o listmodel
+ \o QTableView
+ \o Custom Model based on QAbstractTableModel
+ \o Read only
+ \o Book 3, Chapter 5, Figure 5-8
+ \row
+ \o treemodel
+ \o QTreeView
+ \o Custom Model based on QAbstractItemModel
+ \o Read only
+ \o Book 3, Chapter 5, Figure 5-10
+ \row
+ \o edit integers
+ \o QListView
+ \o Custom Model based on QAbstractListModel
+ \o Read / write
+ \o Book 3, Chapter 5, Listing 5-37, Figure 5-11
+ \row
+ \o sorting
+ \o QTableView
+ \o QSortFilterProxyModel applied to QStringListModel
+ \o Demonstrates sorting
+ \o Book 3, Chapter 5, Figure 5-12
+ \endtable
+
+
+ \section2 4.2 Qt Documentation
+
+ Qt 4.7 comes with 17 examples and 2 Demonstrations for model/view.
+ The examples can be found on the \l{Item Views Examples} page.
+
+ \table
+ \header
+ \o Example name
+ \o View class used
+ \o Model used
+ \o Aspects covered
+ \row
+ \o Address Book
+ \o QTableView
+ \o QAbstractTableModel
+ QSortFilterProxyModel
+ \o Usage of QSortFilterProxyModel to generate different
+ subsets from one data pool
+ \row
+ \o Basic Sort/Filter Model
+ \o QTreeView
+ \o QStandardItemModel
+ QSortFilterProxyModel
+ \o
+ \row
+ \o Chart
+ \o Custom view
+ \o QStandardItemModel
+ \o Designing custom views that cooperate with selection models
+ \row
+ \o Color Editor Factory
+ \o {2, 1} QTableWidget
+ \o Enhancing the standard delegate with a new custom editor to choose colours
+ \row
+ \o Combo Widget Mapper
+ \o QDataWidgetMapper to map QLineEdit, QTextEdit and QComboBox
+ \o QStandardItemModel
+ \o Shows how a QComboBox can serve as a view class
+ \row
+ \o Custom Sort/Filter Model
+ \o QTreeView
+ \o QStandardItemModel
+ QSortFilterProxyModel
+ \o Subclass QSortFilterProxyModel for advanced sorting and filtering
+ \row
+ \o Dir View
+ \o QTreeView
+ \o QDirModel
+ \o Very small example to demonstrate how to assign a model to a view
+ \row
+ \o Editable Tree Model
+ \o QTreeView
+ \o Custom tree model
+ \o Comprehensive example for working with trees, demonstrates
+ editing cells and tree structure with an underlying custom
+ model
+ \row
+ \o Fetch More
+ \o QListView
+ \o Custom list model
+ \o Dynamically changing model
+ \row
+ \o Frozen Column
+ \o QTableView
+ \o QStandardItemModel
+ \o
+ \row
+ \o Pixelator
+ \o QTableView
+ \o Custom table model
+ \o Implementation of a custom delegate
+ \row
+ \o Puzzle
+ \o QListView
+ \o Custom list model
+ \o Model/view with drag and drop
+ \row
+ \o Simple DOM Model
+ \o QTreeView
+ \o Custom tree model
+ \o Read only example for a custom tree model
+ \row
+ \o Simple Tree Model
+ \o QTreeView
+ \o Custom tree model
+ \o Read only example for a custom tree model
+ \row
+ \o Simple Widget Mapper
+ \o QDataWidgetMapper to map QLineEdit, QTextEdit and QSpinBox
+ \o QStandardItemModel
+ \o Basic QDataWidgetMapper usage
+ \row
+ \o Spin Box Delegate
+ \o QTableView
+ \o QStandardItemModel
+ \o Custom delegate that uses a spin box as a cell editor
+ \row
+ \o Star Delegate
+ \o {2, 1} QTableWidget
+ \o Comprehensive custom delegate example.
+ \endtable
+
+ \l{Qt Demonstrations}{Demonstrations} are similar to examples except that no
+ walkthrough is provided for the code. Demonstrations are typically more
+ feature rich than examples.
+
+ \list
+ \o The \bold Interview demonstration shows the same model and
+ selection being shared between three different views.
+ \o The \bold Spreadsheet demonstration illustrates the use of a
+ table view as a spreadsheet, using custom delegates to render
+ each item according to the type of data it contains.
+ \endlist
+
+ A \l{Model/View Programming}{reference document} for model/view technology
+ is also available.
+*/
+
+/*!
+ \page modelview-part2-main-cpp.html
+ \title main.cpp
+ \quotefile tutorials/modelview/1_readonly/main.cpp
+*/
diff --git a/doc/src/tutorials/threads.qdoc b/doc/src/tutorials/threads.qdoc
new file mode 100644
index 0000000000..2d6a540bf3
--- /dev/null
+++ b/doc/src/tutorials/threads.qdoc
@@ -0,0 +1,572 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page thread-basics.html
+ \ingroup tutorials
+ \startpage {index.html}{Qt Reference Documentation}
+
+ \title Threading Basics
+ \brief An introduction to threads
+
+ \section1 What Are Threads?
+
+ Threads are about doing things in parallel, just like processes. So how do
+ threads differ from processes? While you are making calculations on a
+ spreadsheet, there may also be a media player running on the same desktop
+ playing your favorite song. Here is an example of two processes working in
+ parallel: one running the spreadsheet program; one running a media player.
+ Multitasking is a well known term for this. A closer look at the media
+ player reveals that there are again things going on in parallel within one
+ single process. While the media player is sending music to the audio driver,
+ the user interface with all its bells and whistles is being constantly
+ updated. This is what threads are for \mdash concurrency within one single
+ process.
+
+ So how is concurrency implemented? Parallel work on single core CPUs is an
+ illusion which is somewhat similar to the illusion of moving images in
+ cinema.
+ For processes, the illusion is produced by interrupting the processor's
+ work on one process after a very short time. Then the processor moves on to
+ the next process. In order to switch between processes, the current program
+ counter is saved and the next processor's program counter is loaded. This
+ is not sufficient because the same needs to be done with registers and
+ certain architecture and OS specific data.
+
+ Just as one CPU can power two or more processes, it is also possible to let
+ the CPU run on two different code segments of one single process. When a
+ process starts, it always executes one code segment and therefore the
+ process is said to have one thread. However, the program may decide to
+ start a second thread. Then, two different code sequences are processed
+ simultaneously inside one process. Concurrency is achieved on single core
+ CPUs by repeatedly saving program counters and registers then loading the
+ next thread's program counters and registers. No cooperation from the
+ program is required to cycle between the active threads. A thread may be in
+ any state when the switch to the next thread occurs.
+
+ The current trend in CPU design is to have several cores. A typical
+ single-threaded application can make use of only one core. However, a
+ program with multiple threads can be assigned to multiple cores, making
+ things happen in a truly concurrent way. As a result, distributing work
+ to more than one thread can make a program run much faster on multicore
+ CPUs because additional cores can be used.
+
+ \section2 GUI Thread and Worker Thread
+
+ As mentioned, each program has one thread when it is started. This thread
+ is called the "main thread" (also known as the "GUI thread" in Qt
+ applications). The Qt GUI must run in this thread. All widgets and several
+ related classes, for example QPixmap, don't work in secondary threads.
+ A secondary thread is commonly referred to as a "worker thread" because it
+ is used to offload processing work from the main thread.
+
+ \section2 Simultaneous Access to Data
+
+ Each thread has its own stack, which means each thread has its own call
+ history and local variables. Unlike processes, threads share the same
+ address space. The following diagram shows how the building blocks of
+ threads are located in memory. Program counter and registers of inactive
+ threads are typically kept in kernel space. There is a shared copy of the
+ code and a separate stack for each thread.
+
+ \image threadvisual-example.png "Thread visualization"
+
+ If two threads have a pointer to the same object, it is possible that both
+ threads will access that object at the same time and this can potentially
+ destroy the object's integrity. It's easy to imagine the many things that
+ can go wrong when two methods of the same object are executed
+ simultaneously.
+
+ Sometimes it is necessary to access one object from different threads;
+ for example, when objects living in different threads need to communicate.
+ Since threads use the same address space, it is easier and faster for
+ threads to exchange data than it is for processes. Data does not have to be
+ serialized and copied. Passing pointers is possible, but there must be a
+ strict coordination of what thread touches which object. Simultaneous
+ execution of operations on one object must be prevented. There are several
+ ways of achieving this and some of them are described below.
+
+ So what can be done safely? All objects created in a thread can be used
+ safely within that thread provided that other threads don't have references
+ to them and objects don't have implicit coupling with other threads. Such
+ implicit coupling may happen when data is shared between instances as with
+ static members, singletons or global data. Familiarize yourself with the
+ concept of \l{Reentrancy and Thread-Safety}{thread safe and reentrant}
+ classes and functions.
+
+ \section1 Using Threads
+
+ There are basically two use cases for threads:
+
+ \list
+ \o Make processing faster by making use of multicore processors.
+ \o Keep the GUI thread or other time critical threads responsive by
+ offloading long lasting processing or blocking calls to other threads.
+ \endlist
+
+ \section2 When to Use Alternatives to Threads
+
+ Developers need to be very careful with threads. It is easy to start other
+ threads, but very hard to ensure that all shared data remains consistent.
+ Problems are often hard to find because they may only show up once in a
+ while or only on specific hardware configurations. Before creating threads
+ to solve certain problems, possible alternatives should be considered.
+
+ \table
+ \header
+ \o Alternative
+ \o Comment
+ \row
+ \o QEventLoop::processEvents()
+ \o Calling QEventLoop::processEvents() repeatedly during a
+ time-consuming calculation prevents GUI blocking. However, this
+ solution doesn't scale well because the call to processEvents() may
+ occur too often, or not often enough, depending on hardware.
+ \row
+ \o QTimer
+ \o Background processing can sometimes be done conveniently using a
+ timer to schedule execution of a slot at some point in the future.
+ A timer with an interval of 0 will time out as soon as there are no
+ more events to process.
+ \row
+ \o QSocketNotifier QNetworkAccessManager QIODevice::readyRead()
+ \o This is an alternative to having one or multiple threads, each with
+ a blocking read on a slow network connection. As long as the
+ calculation in response to a chunk of network data can be executed
+ quickly, this reactive design is better than synchronous waiting in
+ threads. Reactive design is less error prone and energy efficient
+ than threading. In many cases there are also performance benefits.
+ \endtable
+
+ In general, it is recommended to only use safe and tested paths and to
+ avoid introducing ad-hoc threading concepts. QtConcurrent provides an easy
+ interface for distributing work to all of the processor's cores. The
+ threading code is completely hidden in the QtConcurrent framework, so you
+ don't have to take care of the details. However, QtConcurrent can't be used
+ when communication with the running thread is needed, and it shouldn't be
+ used to handle blocking operations.
+
+ \section2 Which Qt Thread Technology Should You Use?
+
+ Sometimes you want to do more than just running a method in the context of
+ another thread. You may want to have an object which lives in another
+ thread that provides a service to the GUI thread. Maybe you want another
+ thread to stay alive forever to poll hardware ports and send a signal to
+ the GUI thread when something noteworthy has happened. Qt provides
+ different solutions for developing threaded applications. The right
+ solution depends on the purpose of the new thread as well as on the
+ thread's lifetime.
+
+ \table
+ \header
+ \o Lifetime of thread
+ \o Development task
+ \o Solution
+ \row
+ \o One call
+ \o Run one method within another thread and quit the thread when the
+ method is finished.
+ \o Qt provides different solutions:
+ \list
+ \o Write a function and run it with QtConcurrent::run()
+ \o Derive a class from QRunnable and run it in the global thread
+ pool with QThreadPool::globalInstance()->start()
+ \o Derive a class from QThread, reimplement the QThread::run()
+ method and use QThread::start() to run it.
+ \endlist
+
+ \row
+ \o One call
+ \o Operations are to be performed on all items of a container.
+ Processing should be performed using all available cores. A common
+ example is to produce thumbnails from a list of images.
+ \o QtConcurrent provides the \l{QtConcurrent::}{map()} function for
+ applying operations on every container element,
+ \l{QtConcurrent::}{filter()} for selecting container elements, and
+ the option of specifying a reduce function for combining the
+ remaining elements.
+ \row
+ \o One call
+ \o A long running operation has to be put in another thread. During the
+ course of processing, status information should be sent to the GUI
+ thread.
+ \o Use QThread, reimplement run and emit signals as needed. Connect the
+ signals to the GUI thread's slots using queued signal/slot
+ connections.
+
+ \row
+ \o Permanent
+ \o Have an object living in another thread and let it perform different
+ tasks upon request.
+ This means communication to and from the worker thread is required.
+ \o Derive a class from QObject and implement the necessary slots and
+ signals, move the object to a thread with a running event loop and
+ communicate with the object over queued signal/slot connections.
+ \row
+ \o Permanent
+ \o Have an object living in another thread, let the object perform
+ repeated tasks such as polling a port and enable communication with
+ the GUI thread.
+ \o Same as above but also use a timer in the worker thread to implement
+ polling. However, the best solution for polling is to avoid it
+ completely. Sometimes using QSocketNotifier is an alternative.
+ \endtable
+
+
+ \section1 Qt Thread Basics
+
+ QThread is a very convenient cross platform abstraction of native platform
+ threads. Starting a thread is very simple. Let us look at a short piece of
+ code that generates another thread which says hello in that thread and then
+ exits.
+
+ \snippet examples/tutorials/threads/hellothread/hellothread.h 1
+
+ We derive a class from QThread and reimplement the \l{QThread::}{run()}
+ method.
+
+ \snippet examples/tutorials/threads/hellothread/hellothread.cpp 1
+
+ The run method contains the code that will be run in a separate thread. In
+ this example, a message containing the thread ID will be printed.
+ QThread::start() will call the method in another thread.
+
+ \snippet examples/tutorials/threads/hellothread/main.cpp 1
+
+ To start the thread, our thread object needs to be instantiated. The
+ \l{QThread::}{start()} method creates a new thread and calls the
+ reimplemented \l{QThread::}{run()} method in this new thread. Right after
+ \l{QThread::}{start()} is called, two program counters walk through the
+ program code. The main function starts with only the GUI thread running and
+ it should terminate with only the GUI thread running. Exiting the program
+ when another thread is still busy is a programming error, and therefore,
+ wait is called which blocks the calling thread until the
+ \l{QThread::}{run()} method has completed.
+
+ This is the result of running the code:
+
+ \badcode
+ hello from GUI thread 3079423696
+ hello from worker thread 3076111216
+ \endcode
+
+
+ \section2 QObject and Threads
+
+ A QObject is said to have a \e{thread affinity} or, in other words, that it
+ lives in a certain thread. This means that, at creation time, QObject saves
+ a pointer to the current thread. This information becomes relevant when an
+ event is posted with \l{QCoreApplication::}{postEvent()}. The event will be
+ put in the corresponding thread's event loop. If the thread where the
+ QObject lives doesn't have an event loop, the event will never be delivered.
+
+ To start an event loop, \l{QThread::}{exec()} must be called inside
+ \l{QThread::}{run()}. Thread affinity can be changed using
+ \l{QObject::}{moveToThread()}.
+
+ As mentioned above, developers must always be careful when calling objects'
+ methods from other threads. Thread affinity does not change this situation.
+ Qt documentation marks several methods as thread-safe.
+ \l{QCoreApplication::}{postEvent()} is a noteworthy example. A thread-safe
+ method may be called from different threads simultaneously.
+
+ In cases where there is usually no concurrent access to methods, calling
+ non-thread-safe methods of objects in other threads may work thousands
+ of times before a concurrent access occurs, causing unexpected behavior.
+ Writing test code does not entirely ensure thread correctness, but it is
+ still important.
+ On Linux, Valgrind and Helgrind can help detect threading errors.
+
+ The anatomy of QThread is quite interesting:
+
+ \list
+ \o QThread does not live in the new thread where \l{QThread::}{run()} is
+ executed. It lives in the old thread.
+ \o Most QThread methods are the thread's control interface and are meant to
+ be called from the old thread. Do not move this interface to the newly
+ created thread using \l{QObject::}{moveToThread()}; i.e., calling
+ \l{QObject::moveToThread()}{moveToThread(this)} is regarded as bad
+ practice.
+ \o \l{QThread::}{exec()} and the static methods
+ \l{QThread::}{usleep()}, \l{QThread::}{msleep()},
+ \l{QThread::}{sleep()} are meant to be called from the newly created
+ thread.
+ \o Additional members defined in the QThread subclass are
+ accessible by both threads. The developer is responsible for
+ coordinating access. A typical strategy is to set the members before
+ \l{QThread::}{start()} is called. Once the worker thread is running,
+ the main thread should not touch the additional members anymore. After
+ the worker has terminated, the main thread can access the additional
+ members again. This is a convenient strategy for passing parameters to a
+ thread before it is started as well as for collecting the result once it
+ has terminated.
+ \endlist
+
+ A QObject's parent must always be in the same thread. This has a surprising
+ consequence for objects generated within the \l{QThread::}{run()} method:
+
+ \code
+ void HelloThread::run()
+ {
+ QObject *object1 = new QObject(this); //error, parent must be in the same thread
+ QObject object2; // OK
+ QSharedPointer <QObject> object3(new QObject); // OK
+ }
+ \endcode
+
+ \section2 Using a Mutex to Protect the Integrity of Data
+
+ A mutex is an object that has \l{QMutex::}{lock()} and \l{QMutex::}{unlock()}
+ methods and remembers if it is already locked. A mutex is designed to be
+ called from multiple threads. \l{QMutex::}{lock()} returns immediately if
+ the mutex is not locked. The next call from another thread will find the
+ mutex in a locked state and then \l{QMutex::}{lock()} will block the thread
+ until the other thread calls \l{QMutex::}{unlock()}. This functionality can
+ make sure that a code section will be executed by only one thread at a time.
+
+ The following line sketches how a mutex can be used to make a method
+ thread-safe:
+
+ \code
+ void Worker::work()
+ {
+ this->mutex.lock(); // first thread can pass, other threads will be blocked here
+ doWork();
+ this->mutex.unlock();
+ }
+ \endcode
+
+ What happens if one thread does not unlock a mutex? The result can be a
+ frozen application. In the example above, an exception might be thrown and
+ \c{mutex.unlock()} will never be reached. To prevent problems like this,
+ QMutexLocker should be used.
+
+ \code
+ void Worker::work()
+ {
+ QMutexLocker locker(&mutex); // Locks the mutex and unlocks when locker exits the scope
+ doWork();
+ }
+ \endcode
+
+ This looks easy, but mutexes introduce a new class of problems: deadlocks.
+ A deadlock happens when a thread waits for a mutex to become unlocked, but
+ the mutex remains locked because the owning thread is waiting for the first
+ thread to unlock it. The result is a frozen application. Mutexes can be
+ used to make a method thread safe. Most Qt methods aren't thread safe
+ because there is always a performance penalty when using mutexes.
+
+ It isn't always possible to lock and unlock a mutex in a method. Sometimes
+ the need to lock spans several calls. For example, modifying a container
+ with an iterator requires a sequence of several calls which should not be
+ interrupted by other threads. In such a scenario, locking can be achieved
+ with a mutex that is kept outside of the object to be manipulated. With an
+ external mutex, the duration of locking can be adjusted to the needs of the
+ operation. One disadvantage is that external mutexes aid locking, but do
+ not enforce it because users of the object may forget to use it.
+
+ \section2 Using the Event Loop to Prevent Data Corruption
+
+ The event loops of Qt are a very valuable tool for inter-thread
+ communication. Every thread may have its own event loop. A safe way of
+ calling a slot in another thread is by placing that call in another
+ thread's event loop. This ensures that the target object finishes the
+ method that is currently running before another method is started.
+
+ So how is it possible to put a method invocation in an event loop? Qt has
+ two ways of doing this. One way is via queued signal-slot connections; the
+ other way is to post an event with QCoreApplication::postEvent(). A queued
+ signal-slot connection is a signal slot connection that is executed
+ asynchronously. The internal implementation is based on posted events. The
+ arguments of the signal are put into the event loop and the signal method
+ returns immediately.
+
+ The connected slot will be executed at a time which depends on what else is
+ in the event loop.
+
+ Communication via the event loop eliminates the deadlock problem we face
+ when using mutexes. This is why we recommend using the event loop rather
+ than locking an object using a mutex.
+
+ \section2 Dealing with Asynchronous Execution
+
+ One way to obtain a worker thread's result is by waiting for the thread
+ to terminate. In many cases, however, a blocking wait isn't acceptable. The
+ alternative to a blocking wait are asynchronous result deliveries with
+ either posted events or queued signals and slots. This generates a certain
+ overhead because an operation's result does not appear on the next source
+ line, but in a slot located somewhere else in the source file. Qt
+ developers are used to working with this kind of asynchronous behavior
+ because it is much similar to the kind of event-driven programming used in
+ GUI applications.
+
+ \section1 Examples
+
+ This tutorial comes with examples for Qt's three basic ways of working with
+ threads. Two more examples show how to communicate with a running thread
+ and how a QObject can be placed in another thread, providing service to the
+ main thread.
+
+ \list
+ \o Using QThread as shown \l{Qt thread basics}{above}
+ \o \l{Example 1: Using the Thread Pool}{Using the global QThreadPool}
+ \o \l{Example 2: Using QtConcurrent}{Using QtConcurrent}
+ \o \l{Example 3: Clock}{Communication with the GUI thread}
+ \o \l{Example 4: A Permanent Thread}{A permanent QObject in another thread
+ provides service to the main thread}
+ \endlist
+
+ The following examples can all be compiled and run independently. The source can
+ be found in the examples directory: examples/tutorials/threads/
+
+ \section2 Example 1: Using the Thread Pool
+
+ Creating and destroying threads frequently can be expensive. To avoid the
+ cost of thread creation, a thread pool can be used. A thread pool is a
+ place where threads can be parked and fetched. We can write the same
+ "hello thread" program as \l{Qt Thread Basics}{above} using the global
+ thread pool. We derive a class from QRunnable. The code we want to run in
+ another thread needs to be placed in the reimplemented QRunnable::run()
+ method.
+
+ \snippet examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp 1
+
+ We instantiate Work in main(), locate the global thread pool and use the
+ QThreadPool::start() method. Now the thread pool runs our worker in another
+ thread. Using the thread pool has a performance advantage because threads
+ are not destroyed after they have finished running. They are kept in a pool
+ and wait to be used again later.
+
+ \section2 Example 2: Using QtConcurrent
+
+ \snippet examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp 1
+
+ We write a global function hello() to implement the work. QtConcurrent::run()
+ is used to run the function in another thread. The result is a QFuture.
+ QFuture provides a method called \l{QFuture::}{waitForFinished()}, which
+ blocks until the calculation is completed. The real power of QtConcurrent
+ becomes visible when data can be made available in a container. QtConcurrent
+ provides several functions that are able to process itemized data on all
+ available cores simultaneously. The use of QtConcurrent is very similar to
+ applying an STL algorithm to an STL container.
+ \l{examples-threadandconcurrent.html}{QtConcurrent Map} is a very short and
+ clear example about how a container of images can be scaled on all available
+ cores. The image scaling example uses the blocking variants of the functions
+ used. For every blocking function there is also a non-blocking, asynchronous
+ counterpart. Getting results asynchronously is implemented with QFuture and
+ QFutureWatcher.
+
+ \section2 Example 3: Clock
+
+ \image thread_clock.png "clock"
+
+ We want to produce a clock application. The application has a GUI and a
+ worker thread. The worker thread checks every 10 milliseconds what time it
+ is. If the formatted time has changed, the result will be sent to the GUI
+ thread where it is displayed.
+
+ Of course, this is an overly complicated way of designing a clock and,
+ actually, a separate thread is unnecessary. We would be better off placing
+ the timer in the main thread because the calculation made in the timer slot
+ is very short-lived. This example is purely for instructional use and shows
+ how to communicate from a worker thread to a GUI thread. Note that
+ communication in this direction is easy. We only need to add a signal
+ to QThread and make a queued signal/slot connection to the main thread.
+ Communication from the GUI to the worker thread is shown in the next
+ example.
+
+ \snippet examples/tutorials/threads/clock/main.cpp 1
+
+ We've connected the \c clockThread with the label. The connection must be a
+ queued signal-slot connection because we want to put the call in the event
+ loop.
+
+ \snippet examples/tutorials/threads/clock/clockthread.h 1
+
+ We have derived a class from QThread and declared the \c sendTime() signal.
+
+ \snippet examples/tutorials/threads/clock/clockthread.cpp 1
+
+ The trickiest part of this example is that the timer is connected to its
+ slot via a direct connection. A default connection would produce a queued
+ signal-slot connection because the connected objects live in different
+ threads; remember that QThread does not live in the thread it creates.
+
+ Still it is safe to access ClockThread::timerHit() from the worker thread
+ because ClockThread::timerHit() is private and only touches local variables
+ and a private member that isn't touched by public methods.
+ QDateTime::currentDateTime() isn't marked as thread-safe in Qt
+ documentation, however we can get away with using it in this small
+ example because we know that the QDateTime::currentDateTime() static
+ method isn't used in any other threads.
+
+ \section2 Example 4: A Permanent Thread
+
+ This example shows how it is possible to have a QObject in a worker thread
+ that accepts requests from the GUI thread, does polling using a timer and
+ continuously reports results back to the GUI thread. The actual work
+ including the polling must be implemented in a class derived from QObject.
+ We have called this class \c WorkerObject in the code shown below. The
+ thread-specific code is hidden in a class called \c Thread, derived from
+ QThread.
+ \c Thread has two additional public members. The \c launchWorker() member
+ takes the worker object and moves it to another thread with a started event
+ loop.
+ The call blocks for a very short moment until the thread creation operation
+ is completed, allowing the worker object to be used again on the next line.
+ The \c Thread class's code is short but somewhat involved, so we only show
+ how to use the class.
+
+ \snippet examples/tutorials/threads/movedobject/main.cpp 1
+
+ QMetaObject::invokeMethod() calls a slot via the event loop. The worker
+ object's methods should not be called directly after the object has been
+ moved to another thread. We let the worker thread do some work and polling,
+ and use a timer to shut the application down after 3 seconds. Shutting the
+ worker down needs some care. We call \c{Thread::stop()} to exit the event
+ loop. We wait for the thread to terminate and, after this has occurred, we
+ delete the worker.
+
+ \section1 Digging Deeper
+
+ Threading is a very complicated subject. Qt offers more classes for
+ threading than we have presented in this tutorial. The following materials
+ can help you go into the subject in more depth:
+
+ \list
+ \o Good video tutorials about threads with Qt can be found in the material
+ from the \l{Training Day at Qt Developer Days 2009}.
+ \o The \l{Thread Support in Qt} document is a good starting point into
+ the reference documentation.
+ \o Qt comes with several additional examples for
+ \l{Threading and Concurrent Programming Examples}{QThread and QtConcurrent}.
+ \o Several good books describe how to work with Qt threads. The most
+ extensive coverage can be found in \e{Advanced Qt Programming} by Mark
+ Summerfield, Prentice Hall - roughly 70 of 500 pages cover QThread and
+ QtConcurrent.
+ \endlist
+*/
diff --git a/doc/src/tutorials/widgets-tutorial.qdoc b/doc/src/tutorials/widgets-tutorial.qdoc
new file mode 100644
index 0000000000..4877339348
--- /dev/null
+++ b/doc/src/tutorials/widgets-tutorial.qdoc
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page widgets-tutorial.html
+ \ingroup tutorials
+ \title Widgets Tutorial
+ \brief This tutorial covers basic usage of widgets and layouts, showing how
+ they are used to build GUI applications.
+
+ \section1 Introduction
+
+ Widgets are the basic building blocks for graphical user interface
+ (GUI) applications built with Qt. Each GUI component (e.g.
+ buttons, labels, text editor) is a \l{QWidget}{widget} that is
+ placed somewhere within a user interface window, or is displayed
+ as an independent window. Each type of widge is provided by a
+ subclass of QWidget, which is itself a subclass of QObject.
+
+ QWidget is not an abstract class. It can be used as a container
+ for other widgets, and it can be subclassed with minimal effort to
+ create new, custom widgets. QWidget is often used to create a
+ window inside which other \l{QWidget}s are placed.
+
+ As with \l{QObject}s, \l{QWidget}s can be created with parent
+ objects to indicate ownership, ensuring that objects are deleted
+ when they are no longer used. With widgets, these parent-child
+ relationships have an additional meaning: Each child widget is
+ displayed within the screen area occupied by its parent widget.
+ This means that when you delete a window widget, all the child
+ widgets it contains are also deleted.
+
+ \section1 Writing a main Function
+
+ Many of the GUI examples provided with Qt follow the pattern of
+ having a \c{main.cpp} file, which contains the standard code to
+ initialize the application, plus any number of other source/header
+ files that contain the application logic and custom GUI components.
+
+ A typical \c main() function in \c{main.cpp} looks like this:
+
+ \snippet doc/src/snippets/widgets-tutorial/template.cpp main.cpp body
+
+ First, a QApplication object is constructed, which can be
+ configured with arguments passed in from the command line. After
+ the widgets have been created and shown, QApplication::exec() is
+ called to start Qt's event loop. Control passes to Qt until this
+ function returns. Finally, \c{main()} returns the value returned
+ by QApplication::exec().
+
+ \section1 Simple widget examples
+
+ Each of theses simple widget examples is written entirely within
+ the \c main() function.
+
+ \list
+ \o \l {tutorials/widgets/toplevel} {Creating a window}
+
+ \o \l {tutorials/widgets/childwidget} {Creating child widgets}
+
+ \o \l {tutorials/widgets/windowlayout} {Using layouts}
+
+ \o \l {tutorials/widgets/nestedlayouts} {Nested layouts}
+ \endlist
+
+ \section1 Real world widget examples
+
+ In these \l{Widget examples} {more advanced examples}, the code
+ that creates the widgets and layouts is stored in other files. For
+ example, the GUI for a main window may be created in the
+ constructor of a QMainWindow subclass.
+
+ \section1 Building The Examples
+
+ If you installed a binary package to get Qt, or if you compiled Qt
+ yourself, the examples described in this tutorial should already
+ be built and ready to run. If you wish to modify and recompile
+ them, follow these steps:
+
+ \list 1
+
+ \o From a command prompt, enter the directory containing the
+ example you have modified.
+
+ \o Type \c qmake and press \key{Return}. If this doesn't work,
+ make sure that the executable is on your path, or enter its
+ full location.
+
+ \o On Linux/Unix and Mac OS X, type \c make and press
+ \key{Return}; on Windows with Visual Studio, type \c nmake and
+ press \key{Return}.
+
+ \endlist
+
+ An executable file is created in the current directory. On
+ Windows, this file may be located in a \c debug or \c release
+ subdirectory. You can run this executable to see the example code
+ at work.
+*/
+
+/*!
+ \example tutorials/widgets/toplevel
+ \title Widgets Tutorial - Creating a Window
+
+ If a widget is created without a parent, it is treated as a window, or
+ \e{top-level widget}, when it is shown. Since it has no parent object to
+ ensure that it is deleted when no longer needed, it is up to the
+ developer to keep track of the top-level widgets in an application.
+
+ In the following example, we use QWidget to create and show a window with
+ a default size:
+
+ \div {class="qt-code"}
+ \table
+ \row
+ \o \snippet tutorials/widgets/toplevel/main.cpp main program
+ \o \inlineimage widgets-tutorial-toplevel.png
+ \endtable
+ \enddiv
+
+ To create a real GUI, we need to place widgets inside the window. To do
+ this, we pass a QWidget instance to a widget's constructor, as we will
+ demonstrate in the next part of this tutorial.
+
+*/
+
+/*!
+ \example tutorials/widgets/childwidget
+ \title Widgets Tutorial - Child Widgets
+
+ We can add a child widget to the window created in the previous example by
+ passing \c window as the parent to its constructor. In this case, we add a
+ button to the window and place it in a specific location:
+
+ \div {class="qt-code"}
+ \table
+ \row
+ \o \snippet tutorials/widgets/childwidget/main.cpp main program
+ \o \inlineimage widgets-tutorial-childwidget.png
+ \endtable
+ \enddiv
+
+ The button is now a child of the window and will be deleted when the
+ window is destroyed. Note that hiding or closing the window does not
+ automatically destroy it. It will be destroyed when the example exits.
+*/
+
+/*!
+ \example tutorials/widgets/windowlayout
+ \title Widgets Tutorial - Using Layouts
+
+ Usually, child widgets are arranged inside a window using layout objects
+ rather than by specifying positions and sizes explicitly. Here, we
+ construct a label and line edit widget that we would like to arrange
+ side-by-side.
+
+ \div {class="qt-code"}
+ \table
+ \row
+ \o \snippet tutorials/widgets/windowlayout/main.cpp main program
+ \o \inlineimage widgets-tutorial-windowlayout.png
+ \endtable
+ \enddiv
+
+ The \c layout object we construct manages the positions and sizes of
+ widgets supplied to it with the \l{QHBoxLayout::}{addWidget()} function.
+ The layout itself is supplied to the window itself in the call to
+ \l{QWidget::}{setLayout()}. Layouts are only visible through the effects
+ they have on the widgets (and other layouts) they are responsible for
+ managing.
+
+ In the example above, the ownership of each widget is not immediately
+ clear. Since we construct the widgets and the layout without parent
+ objects, we would expect to see an empty window and two separate windows
+ containing a label and a line edit. However, when we tell the layout to
+ manage the label and line edit and set the layout on the window, both the
+ widgets and the layout itself are ''reparented'' to become children of
+ the window.
+*/
+
+/*!
+ \example tutorials/widgets/nestedlayouts
+ \title Widgets Tutorial - Nested Layouts
+
+ Just as widgets can contain other widgets, layouts can be used to provide
+ different levels of grouping for widgets. Here, we want to display a
+ label alongside a line edit at the top of a window, above a table view
+ showing the results of a query.
+
+ We achieve this by creating two layouts: \c{queryLayout} is a QHBoxLayout
+ that contains QLabel and QLineEdit widgets placed side-by-side;
+ \c{mainLayout} is a QVBoxLayout that contains \c{queryLayout} and a
+ QTableView arranged vertically.
+
+ \div {class="qt-code"}
+ \table
+ \row
+ \o \snippet tutorials/widgets/nestedlayouts/main.cpp first part
+ \snippet tutorials/widgets/nestedlayouts/main.cpp last part
+ \o \inlineimage widgets-tutorial-nestedlayouts.png
+ \endtable
+ \enddiv
+
+ Note that we call the \c{mainLayout}'s \l{QBoxLayout::}{addLayout()}
+ function to insert the \c{queryLayout} above the \c{resultView} table.
+
+ We have omitted the code that sets up the model containing the data shown
+ by the QTableView widget, \c resultView. For completeness, we show this below.
+
+ As well as QHBoxLayout and QVBoxLayout, Qt also provides QGridLayout
+ and QFormLayout classes to help with more complex user interfaces.
+ These can be seen if you run \l{Qt Designer}.
+
+ \section1 Setting up the Model
+
+ In the code above, we did not show where the table's data came from
+ because we wanted to concentrate on the use of layouts. Here, we see
+ that the model holds a number of items corresponding to rows, each of
+ which is set up to contain data for two columns.
+
+ \snippet tutorials/widgets/nestedlayouts/main.cpp set up the model
+
+ The use of models and views is covered in the
+ \l{Item Views Examples} and in the \l{Model/View Programming} overview.
+*/