summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/doc.pri11
-rw-r--r--doc/src/legal/3rdparty.qdoc12
-rw-r--r--doc/src/legal/licenses.qdoc16
-rw-r--r--doc/src/legal/trademarks.qdoc2
-rw-r--r--doc/src/tutorials/addressbook-fr.qdoc816
-rw-r--r--doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc96
-rw-r--r--doc/src/zh_CN/getting-started/tutorials.qdoc100
-rw-r--r--doc/src/zh_CN/tutorials/addressbook.qdoc673
-rw-r--r--doc/src/zh_CN/tutorials/widgets-tutorial.qdoc244
-rw-r--r--tools/qdoc3/config.cpp4
-rw-r--r--tools/qdoc3/config.h3
-rw-r--r--tools/qdoc3/cppcodeparser.cpp12
-rw-r--r--tools/qdoc3/doc.cpp3
-rw-r--r--tools/qdoc3/htmlgenerator.cpp137
-rw-r--r--tools/qdoc3/htmlgenerator.h3
-rw-r--r--tools/qdoc3/linguistgenerator.cpp4
-rw-r--r--tools/qdoc3/pagegenerator.cpp2
-rw-r--r--tools/qdoc3/pagegenerator.h6
-rw-r--r--tools/qdoc3/qsakernelparser.cpp6
-rw-r--r--tools/qdoc3/qscodeparser.cpp6
-rw-r--r--tools/qdoc3/test/qt-api-only_zh_CN.qdocconf30
-rw-r--r--tools/qdoc3/test/qt-build-docs.qdocconf16
-rw-r--r--tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf92
-rw-r--r--tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf25
-rw-r--r--tools/qdoc3/test/qt.qdocconf11
-rw-r--r--tools/qdoc3/tokenizer.cpp25
-rw-r--r--tools/qdoc3/tokenizer.h9
27 files changed, 1844 insertions, 520 deletions
diff --git a/doc/doc.pri b/doc/doc.pri
index 463c447..ccbef1a 100644
--- a/doc/doc.pri
+++ b/doc/doc.pri
@@ -30,8 +30,14 @@ QT_DOCUMENTATION = ($$QDOC qt-api-only.qdocconf assistant.qdocconf designer.qdoc
$$GENERATOR doc-build/html-qmake/qmake.qhp -o doc/qch/qmake.qch \
)
+QT_ZH_CN_DOCUMENTATION = ($$QDOC qt-api-only_zh_CN.qdocconf) && \
+ (cd $$QT_BUILD_TREE && \
+ $$GENERATOR doc-build/html-qt_zh_CN/qt.qhp -o doc/qch/qt_zh_CN.qch \
+ )
+
win32-g++:isEmpty(QMAKE_SH) {
QT_DOCUMENTATION = $$replace(QT_DOCUMENTATION, "/", "\\\\")
+ QT_ZH_CN_DOCUMENTATION = $$replace(QT_ZH_CN_DOCUMENTATION, "/", "\\\\")
}
# Build rules:
@@ -42,6 +48,9 @@ qch_docs.depends += sub-tools
docs.depends = adp_docs qch_docs
+docs_zh_CN.depends = docs
+docs_zh_CN.commands = $$QT_ZH_CN_DOCUMENTATION
+
# Install rules
htmldocs.files = $$QT_BUILD_TREE/doc/html
htmldocs.path = $$[QT_INSTALL_DOCS]
@@ -54,5 +63,5 @@ qchdocs.CONFIG += no_check_exist
docimages.files = $$QT_BUILD_TREE/doc/src/images
docimages.path = $$[QT_INSTALL_DOCS]/src
-QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs
+QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs docs_zh_CN
INSTALLS += htmldocs qchdocs docimages
diff --git a/doc/src/legal/3rdparty.qdoc b/doc/src/legal/3rdparty.qdoc
index b710449..bb2effa 100644
--- a/doc/src/legal/3rdparty.qdoc
+++ b/doc/src/legal/3rdparty.qdoc
@@ -116,9 +116,9 @@
\hr
- Copyright (C) 2004,2007  Red Hat, Inc.\br
- Copyright (C) 1998-2004  David Turner and Werner Lemberg\br
- Copyright (C) 2006  Behdad Esfahbod\br
+ Copyright (C) 2004,2007  Red Hat, Inc.\br
+ Copyright (C) 1998-2004  David Turner and Werner Lemberg\br
+ Copyright (C) 2006  Behdad Esfahbod\br
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
This is part of HarfBuzz, an OpenType Layout engine library.
@@ -137,7 +137,7 @@
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
@@ -323,7 +323,7 @@
duplicated in all such forms and that any documentation,
advertising materials, and other materials related to such
distribution and use acknowledge that the software was developed
- by the University of California, Berkeley.  The name of the
+ by the University of California, Berkeley.  The name of the
University may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
@@ -364,7 +364,7 @@
documentation for such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
diff --git a/doc/src/legal/licenses.qdoc b/doc/src/legal/licenses.qdoc
index 9e680a6..344ebd4 100644
--- a/doc/src/legal/licenses.qdoc
+++ b/doc/src/legal/licenses.qdoc
@@ -276,14 +276,14 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:\br
-     * Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.\br
-     * Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.\br
-     * Neither the name of Research In Motion Limited nor the
-       names of its contributors may be used to endorse or promote products
-       derived from this software without specific prior written permission.
+     * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.\br
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.\br
+     * Neither the name of Research In Motion Limited nor the
+       names of its contributors may be used to endorse or promote products
+       derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Research In Motion Limited ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
diff --git a/doc/src/legal/trademarks.qdoc b/doc/src/legal/trademarks.qdoc
index a7b5764..23d0cf6 100644
--- a/doc/src/legal/trademarks.qdoc
+++ b/doc/src/legal/trademarks.qdoc
@@ -47,7 +47,7 @@
\brief Information about trademarks owned by Nokia and other organisations.
Nokia, the Nokia logo, Qt, and the Qt logo are trademarks of Nokia
-  Corporation and/or its subsidiaries in Finland and other countries.
+  Corporation and/or its subsidiaries in Finland and other countries.
\list
\o Intel, Intel Inside (logos), MMX and Pentium are \reg trademarks of
diff --git a/doc/src/tutorials/addressbook-fr.qdoc b/doc/src/tutorials/addressbook-fr.qdoc
index d3bd1ca..98c44a3 100644
--- a/doc/src/tutorials/addressbook-fr.qdoc
+++ b/doc/src/tutorials/addressbook-fr.qdoc
@@ -47,47 +47,47 @@
\nextpage {tutorials/addressbook-fr/part1}{Chapitre 1}
\title Tutoriel "Carnet d'adresses"
- \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt.
+ \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.
+ 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
+ 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 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
+ \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.
+ si ce n'est déjà fait.
- Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook
+ 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/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}
+ \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
+ 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.
+ 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.
+ 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.
*/
@@ -98,156 +98,156 @@
\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
+ 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.
+ 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.
+ 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:
+ 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
+ \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
+ \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
+ \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:
+ 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 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
+ 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
+ \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
+ 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.
+ 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.
+ 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
+ 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.
+ 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.
+ 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()}.
+ 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.
+ 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
+ \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.
+ 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.
+ à 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.
+ 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:
+ 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,
+ 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
+ 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"
+ Enfin, on initialise le titre du widget à "Simple Address Book"
- \section1 Exécution de l'application
+ \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.
+ 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
+ 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
+ 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.
+ sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire.
*/
/*!
@@ -258,53 +258,53 @@
\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é.
+ 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.
+ 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
+ \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.
+ 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}.
+ 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.
+ 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
+ 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
+ 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.
+ à l'affichage du dernier contact.
- \section1 Implémentation de la classe AddressBook
+ \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
+ \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage
mais pas la modification du contact courant.
\dots
@@ -317,16 +317,16 @@
\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.
+ 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.
+ au slot qui gèrera l'action.
L'image ci-dessous illustre ceci:
\image addressbook-tutorial-part2-signals-and-slots.png
@@ -336,77 +336,77 @@
\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.
+ 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
+ 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:
+ 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
+ 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:
+ 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
+ \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.
+ 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 à
+ \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é.
+ 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.
+ 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
+ \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:
+ 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
+ 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
+ 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
@@ -418,118 +418,118 @@
\contentspage {Tutoriel "Carnet d'adresses"}{Sommaire}
\nextpage {tutorials/addressbook-fr/part4}{Chapitre 4}
\example tutorials/addressbook-fr/part3
- \title Carnet d'adresses 3 - Navigation entre les éléments
+ \title Carnet d'adresses 3 - Navigation entre les éléments
- L'application "Carnet d'adresses" est maintenant à moitié terminée. Il
+ 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.
+ 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.
+ 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.
+ 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.
+ 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
+ \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:
+ 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.
+ 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
+ \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
+ 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:
+ 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
+ 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
+ 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:
+ 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.
+ 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
+ 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
+ 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
+ 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.
+ 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:
+ 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
+ \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,
+ 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:
+ 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
+ \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
+ \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.
+ à nouveau, nous affichons le contenu de l'objet courant dans \c contacts.
*/
@@ -540,27 +540,27 @@
\contentspage {Tutoriel "Carnet d'adresses"}{Sommaire}
\nextpage {tutorials/addressbook-fr/part5}{Chapitre 5}
\example tutorials/addressbook-fr/part4
- \title Carnet d'Adresses 4 - éditer et supprimer des adresses
+ \title Carnet d'Adresses 4 - éditer et supprimer des adresses
- Dans ce chapitre, nous verrons comment modifier les données des contacts
+ 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
+ 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.
+ Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles.
\list
\o \c{NavigationMode},
@@ -568,22 +568,22 @@
\o \c{EditingMode}.
\endlist
- \section1 Définition de la classe AddressBook
+ \section1 Définition de la classe AddressBook
- Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode :
+ 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.
+ 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.
+ 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
@@ -591,97 +591,97 @@
\dots
\snippet tutorials/addressbook/part4/addressbook.h mode declaration
- Enfin, on déclare \c currentMode pour garder une trace du mode
- actuellement utilisé.
+ Enfin, on déclare \c currentMode pour garder une trace du mode
+ actuellement utilisé.
- \section1 Implémentation de la classe AddressBook
+ \section1 Implémentation de la classe AddressBook
- Il nous faut maintenant implémenter les fonctionnalités de changement de
+ 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.
+ \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 à
+ 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
+ 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
+ \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
+ 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.
+ \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.
+ 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.
+ 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
+ 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
+ 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.
+ 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
+ \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,
+ 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.
+ 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
+ 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
+ \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
+ 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.
*/
@@ -694,7 +694,7 @@
\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
+ Dans ce chapitre, nous allons voir les possibilités pour rechercher
des contacts dans le carnet d'adresse.
\image addressbook-tutorial-part5-screenshot.png
@@ -703,110 +703,110 @@
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
+ 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.
+ 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.
+ implémenter la class \c FindDialog.
- \section1 Définition de la classe 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
+ 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.
+ 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
+ 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 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,
+ 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.
+ à rechercher, et à une variable interne stockant le texte pour une
+ utilisation ultérieure.
- \section1 Implémentation de la classe FindDialog
+ \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
+ 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 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{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().
+ 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.
+ 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().
+ 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é.
+ 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
+ \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().
+ 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.
+ 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.
+ 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.
+ 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
+ \section1 Implémentation de la classe AddressBook
- Dans le constructeur de \c AddressBook, nous instancions nos objets privés,
+ 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
@@ -814,25 +814,25 @@
\snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de
- \c{findButton} à \c findContact().
+ \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():
+ 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
+ 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()
+ 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.
+ indiquer que la recherche à échouée.
\image addressbook-tutorial-part5-notfound.png
*/
@@ -845,49 +845,49 @@
\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
+ 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
+ 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.
+ 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 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.
+ 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
+ \section1 Définition de la classe AddressBook
- On déclare deux slots publics, \c saveToFile() et \c loadFromFile(),
+ 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
+ \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
+ 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
+ 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
@@ -895,85 +895,85 @@
\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
+ 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.
+ \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs.
- Pour la sauvegarde, on commence par récupérer le nom de fichier
+ 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
+ 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
+ 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-
+ 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
+ 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
+ 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
+ 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.
+ 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
+ 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:
+ 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
+ \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
+ 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
+ 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
+ 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.
+ 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.
*/
/*!
@@ -981,86 +981,86 @@
\previouspage {tutorials/addressbook-fr/part6}{Chapitre 6}
\contentspage {Tutoriel "Carnet d'adresses"}{Sommaire}
\example tutorials/addressbook-fr/part7
- \title Carnet d'adresse 7 - Fonctionnalités avancées
+ \title Carnet d'adresse 7 - Fonctionnalités avancées
- Ce chapitre couvre quelques fonctionnalités additionnelles qui
+ 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
+ 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
+ \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
+ 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
+ \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
+ 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
+ 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 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.
+ 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.
+ 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.
+ 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},
+ 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
+ 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
+ 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.
+ À 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}
+ \e{vCard est une marque déposée de \l{http://www.imc.org}
{Internet Mail Consortium}}.
*/
diff --git a/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc
new file mode 100644
index 0000000..1c2f56b
--- /dev/null
+++ b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page how-to-learn-qt.html
+ \title 如何学习 Qt
+ \brief Links to guides and resources for learning Qt.
+ \nextpage 教程
+
+ \section1 Getting Started
+
+ 我们å‡å®šæ‚¨å·²äº†è§£ C++, 并将用于 Qt å¼€å‘。有关将 Qt 与其他编程语言一起使用的更多信æ¯ï¼Œè¯·å‚è§ \l{Qt website}{Qt 网站}。
+
+ 如果你想仅使用 C++ 编程, ä¸ä½¿ç”¨ä»»ä½•è®¾è®¡å·¥å…·è€Œä»…使用代ç è®¾è®¡ç”¨æˆ·ç•Œé¢ï¼Œè¯·è§‚看\l{教程}。这些教程是为您了解 Qt 编程é‡èº«å®šåšçš„,并侧é‡äºŽç¼–写å¯ç”¨ä»£ç ï¼Œè€Œå¹¶éžåŠŸèƒ½ç®€ä»‹ã€‚
+
+ 如果您想使用设计工具æ¥è®¾è®¡ç”¨æˆ·ç•Œé¢ï¼Œåˆ™è‡³å°‘è¦é˜…读 \l{Qt Designer manual}{Qt 设计者手册}çš„å‰å‡ ç« ã€‚
+
+ 现在您已ç»ç¼–写了一些å°åž‹å¯ç”¨çš„应用程åºï¼Œå¹¶å¯¹ Qt 编程有更加广泛的了解。您å¯ä»¥ç›´æŽ¥ç€æ‰‹åšè‡ªå·±çš„项目,但我们建议您阅读以下一些关键简介以加深您对 Qt 的了解:\l{Qt Object Model}Qt 对象模型}å’Œ\l{Signals and Slots}{ä¿¡å·å’Œæ§½}。
+
+ \beginfloatleft
+ \inlineimage qtdemo-small.png
+ \endfloat
+
+ \section1 了解概况
+
+ 在这个阶段,我们建议您æµè§ˆä¸€ä¸‹\l{All Overviews and HOWTOs}{简介},然åŽé˜…读与您项目相关的章节。您å¯èƒ½è¿˜ä¼šå‘现,æµè§ˆä¸Žæ‚¨é¡¹ç›®ç±»ä¼¼çš„\l{Qt Examples}{示例}çš„æºä»£ç ä¹Ÿä¼šå¯¹æ‚¨æœ‰æ‰€å¸®åŠ©ã€‚由于 Qt æºä»£ç å·²é¢å‘公众开放,您也å¯é˜…读 Qt æºä»£ç ã€‚
+
+ 如果您è¿è¡Œ\l{Examples and Demos Launcher}{示例和演示å¯åŠ¨ç¨‹åº},您就会看到许多正在使用的 Qt widget。
+
+ \l{Qt Widget Gallery} 还按照在ä¸åŒæ”¯æŒå¹³å°ä¸Šçš„使用风格æ供了精选 Qt widget 简介。
+ \clearfloat
+
+ \section1 Books and Learning Materials
+
+ Qt 附带大é‡æ–‡æ¡£ï¼Œå¹¶å…¨æ–‡å¸¦æœ‰è¶…文本交å‰å¼•ç”¨ï¼Œå¯è½»æ¾åœ°ç‚¹å‡»äº†è§£è‡ªå·±æƒ³çŸ¥é“的内容。您使用最多的文档å¯èƒ½æ˜¯ \l{index.html}{API 引用}。æ¯ä¸ªé“¾æŽ¥éƒ½æ供了æµè§ˆ API 引用的ä¸åŒæ–¹å¼ï¼Œæ‚¨å¯æ¯ä¸ªéƒ½å°è¯•ä¸€ä¸‹ï¼Œçœ‹å“ªä¸ªæ›´é€‚åˆè‡ªå·±ã€‚您还å¯ä»¥å°è¯• \l{Qt Assistant}ï¼Œè¿™æ˜¯éš Qt 附带的工具,å¯è®¿é—®å…¨éƒ¨ Qt API,并æ供全文本æœç´¢åŠŸèƒ½ã€‚
+
+ 有大é‡çš„书ç±æ˜¯å…³äºŽ Qt 编程的。有关 Qt 书ç±çš„完整列表。
+ We recommend the official Qt book,
+ \l{http://www.amazon.com/gp/product/0132354160/ref=ase_trolltech/}{C++
+ GUI Programming with Qt 4, Second Edition} (ISBN 0-13-235416-0).
+ 本书从 "Hello Qt" 到高级功能(如多线程ã€2D å’Œ 3D 图形ã€ç½‘络ã€å†…容视图类与 XML),全é¢è¯¦å®žåœ°è¯´æ˜Žäº† Qt 编程。(第一版基于 Qt 4.1,å¯\l{http://www.qtrac.eu/C++-GUI-Programming-with-Qt-4-1st-ed.zip}{在线}获得。)
+
+ 包括ä¸åŒè¯­è¨€çš„翻译版本,请å‚è§\l{Books about Qt Programming}{有关 Qt 编程的书ç±}。
+
+ å¦ä¸€ä¸ªæœ‰å…³å®žä¾‹ä»£ç å’Œ Qt 功能说明的有用资æºå°±æ˜¯å­˜æ¡£çš„ \l{Qt Quarterly}{Qt 季讯}文章,季讯是为 Qt 用户æ供的新闻时讯。
+
+ 有关特定 Qt 模å—和其他指å—的文档,请å‚è§\l{All Overviews and HOWTOs}。
+
+ \section1 Further Reading
+
+ Qt has an active and helpful user community who communicate using
+ the \l{Qt Mailing Lists}{qt-interest} mailing list, the \l{Qt Centre}
+ Web site, and a number of other community Web sites and Weblogs.
+ In addition, many Qt developers are active members of the
+ \l{KDE}{KDE community}.
+
+ ç¥æ‚¨å¥½è¿å¹¶ä¸”学习愉快ï¼
+*/
diff --git a/doc/src/zh_CN/getting-started/tutorials.qdoc b/doc/src/zh_CN/getting-started/tutorials.qdoc
new file mode 100644
index 0000000..dc371d8
--- /dev/null
+++ b/doc/src/zh_CN/getting-started/tutorials.qdoc
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page tutorials.html
+ \title 教程
+
+ \contentspage 如何学习 Qt
+
+ \brief Tutorials, guides and overviews to help you learn Qt.
+
+ A collection of tutorials and "walkthrough" guides are provided with Qt to
+ help new users get started with Qt development. These documents cover a
+ range of topics, from basic use of widgets to step-by-step tutorials that
+ show how an application is put together.
+
+ \table
+ \row
+ \o{2,1} \l{Widgets 教程}{\bold Widgets}
+ \o{2,1} \l{地å€ç°¿æ•™ç¨‹}{\bold {地å€ç°¿}}
+ \row
+ \o \image widget-examples.png Widgets
+ \o
+ A beginner's guide to getting started with widgets and layouts to create
+ GUI applications.
+
+ \o \image addressbook-tutorial.png 地å€ç°¿
+ \o
+ A seven part guide to creating a fully-functioning address book
+ application. This tutorial is also available with
+ \l{Tutoriel "Carnet d'adresses"}{French explanation}.
+
+ \row
+ \o{2,1} \l{A Quick Start to Qt Designer}{\bold{Qt Designer}}
+ \o{2,1} \l{Qt Linguist Manual: Programmers#Tutorials}{\bold {Qt Linguist}}
+ \row
+ \o \image designer-examples.png QtDesigner
+ \o
+ A quick guide through \QD showing the basic steps to create a
+ form with this interactive tool.
+
+ \o \image linguist-examples.png QtLinguist
+ \o
+ A guided tour through the translations process, explaining the
+ tools provided for developers, translators and release managers.
+
+ \row
+ \o{2,1} \l{QTestLib Tutorial}{\bold QTestLib}
+ \o{2,1} \l{qmake Tutorial}{\bold qmake}
+ \row
+ \o{2,1}
+ This tutorial gives a short introduction to how to use some of the
+ features of Qt's unit-testing framework, QTestLib. It is divided into
+ four chapters.
+
+ \o{2,1}
+ This tutorial teaches you how to use \c qmake. We recommend that
+ you read the \l{qmake Manual}{qmake user guide} after completing
+ this tutorial.
+
+ \endtable
+*/
diff --git a/doc/src/zh_CN/tutorials/addressbook.qdoc b/doc/src/zh_CN/tutorials/addressbook.qdoc
new file mode 100644
index 0000000..72349af
--- /dev/null
+++ b/doc/src/zh_CN/tutorials/addressbook.qdoc
@@ -0,0 +1,673 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** 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
+
+ \startpage {index.html}{Qt Reference Documentation}
+ \contentspage 教程
+ \nextpage {tutorials/addressbook/part1}{第一章}
+
+ \title 地å€ç°¿æ•™ç¨‹
+ \brief 本教程介ç»äº†ä½¿ç”¨ Qt 跨平å°æ¡†æž¶çš„ GUI 编程。
+
+ 本教程介ç»äº†ä½¿ç”¨ Qt 跨平å°æ¡†æž¶çš„ GUI 编程。
+
+ \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
+
+ 在学习过程中,我们将了解部分 Qt 基本技术,如
+
+ \list
+ \o Widget 和布局管ç†å™¨
+ \o 容器类
+ \o ä¿¡å·å’Œæ§½
+ \o 输入和输出设备
+ \endlist
+
+ 如果您完全ä¸äº†è§£ Qt,请阅读\l{How to Learn Qt}{如何学习 Qt}(如果您还未阅读)。
+
+ 教程的æºä»£ç ä½äºŽ Qt çš„ \c examples/tutorials/addressbook 目录下。
+
+ 教程章节:
+
+ \list 1
+ \o \l{tutorials/addressbook/part1}{设计用户界é¢}
+ \o \l{tutorials/addressbook/part2}{添加地å€}
+ \o \l{tutorials/addressbook/part3}{æµè§ˆåœ°å€ç°¿æ¡ç›®}
+ \o \l{tutorials/addressbook/part4}{编辑和删除地å€}
+ \o \l{tutorials/addressbook/part5}{添加查找功能}
+ \o \l{tutorials/addressbook/part6}{加载和ä¿å­˜}
+ \o \l{tutorials/addressbook/part7}{附加功能}
+ \endlist
+
+ 虽然这个å°åž‹åº”用程åºçœ‹èµ·æ¥å¹¶ä¸è±¡ä¸€ä¸ªæˆç†Ÿçš„现代 GUI 应用程åºï¼Œä½†å®ƒä½¿ç”¨å¤šç§ç”¨äºŽæ›´å¤æ‚应用程åºçš„基本技术。在您完æˆå­¦ä¹ ä¹‹åŽï¼Œæˆ‘们建议您查看一下\l{mainwindows/application}{应用程åº}示例,它æ供带有èœå•ã€å·¥å…·æ ã€çŠ¶æ€æ ç­‰é¡¹ç›®çš„å°åž‹ GUI 应用程åºã€‚
+*/
+
+/*!
+ \page tutorials-addressbook-part1.html
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part2}{第二章}
+ \example tutorials/addressbook/part1
+ \title 地å€ç°¿ 1 — 设计用户界é¢
+
+ 本教程的第一部分讲述了用于地å€ç°¿åº”用程åºçš„åŸºæœ¬å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 的设计。
+
+ 创建 GUI 程åºçš„第一步就是设计用户界é¢ã€‚在本章中,我们的目标是设置应用基本地å€ç°¿åº”用程åºæ‰€éœ€çš„标签和输入字段。下图为期望输出的å±å¹•æˆªå›¾ã€‚
+
+ \image addressbook-tutorial-part1-screenshot.png
+
+ 我们需è¦ä½¿ç”¨ä¸¤ä¸ª QLabel 对象:\c nameLabel å’Œ \c addressLabel,以åŠä¸¤ä¸ªè¾“入字段:QLineEdit 对象 \c nameLine å’Œ QTextEdit
+ 对象 \c addressText,这样用户æ‰èƒ½è¾“å…¥è”系人的姓å和地å€ã€‚使用的 widget åŠå…¶ä½ç½®å¦‚下图所示。
+
+ \image addressbook-tutorial-part1-labeled-screenshot.png
+
+ è¦åº”用地å€ç°¿éœ€ä½¿ç”¨ä¸‰ä¸ªæ–‡ä»¶ï¼š
+
+ \list
+ \o \c{addressbook.h} — AddressBook 类的定义文件,
+ \o \c{addressbook.cpp} — AddressBook 类的执行文件,以åŠ
+ \o \c{main.cpp} — åŒ…å« \c main() 函数并带有 AddressBook 实例的文件。
+ \endlist
+
+ \section1 Qt 编程 — 使用å­ç±»
+
+ 在编写 Qt 程åºæ—¶ï¼Œæˆ‘们通常使用 Qt 对象å­ç±»æ¥æ·»åŠ åŠŸèƒ½ã€‚这是创建定制 widget 或标准 widget 集åˆçš„基本概念之一。使用å­ç±»æ‰©å±•æˆ–æ”¹å˜ widget çš„æ“作具有以下优势:
+
+ \list
+ \o 我们å¯ä»¥ç¼–写虚函数或纯虚函数应用,以得到我们确切所需的功能,并在需è¦æ—¶å†ä½¿ç”¨åŸºæœ¬çš„类应用。
+ \o 这样我们就å¯ä»¥åœ¨ç±»ä¸­å°è£…部分用户界é¢ï¼Œåº”用程åºçš„其他部分也就无需了解用户界é¢ä¸­å•ç‹¬ä½¿ç”¨çš„ widget。
+ \o å¯ä½¿ç”¨å­ç±»åœ¨åŒä¸€åº”用程åºæˆ–库中创建多个定制 widget,这样å­ç±»çš„代ç å¯åœ¨å…¶ä»–项目é‡å¤ä½¿ç”¨ã€‚
+ \endlist
+
+ 由于 Qt 未æ供特定的地å€ç°¿ widget,我们在标准的 Qt widget 类中使用å­ç±»ï¼Œç„¶åŽæ·»åŠ åŠŸèƒ½ã€‚我们在本教程中创建的 \c AddressBook 类在需è¦ä½¿ç”¨åŸºæœ¬åœ°å€ç°¿ widget 的情况下å¯é‡å¤ä½¿ç”¨ã€‚
+
+ \section1 定义 AddressBook 类
+
+ \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} 文件用于定义 \c AddressBook 类。
+
+ 我们从定义 \c AddressBook 为 QWidget å­ç±»å’Œå£°æ˜Žæž„造器开始入手。我们还使用 Q_OBJECT å®è¡¨æ˜Žè¯¥ç±»ä½¿ç”¨å›½é™…化功能与 Qt ä¿¡å·å’Œæ§½åŠŸèƒ½ï¼Œå³ä½¿åœ¨æœ¬é˜¶æ®µä¸ä¼šç”¨åˆ°æ‰€æœ‰è¿™äº›åŠŸèƒ½ã€‚
+
+ \snippet tutorials/addressbook/part1/addressbook.h class definition
+
+ 该类包å«äº† \c nameLine å’Œ \c addressText 的声明ã€ä¸Šæ–‡æ到的 QLineEdit å’Œ QTextEdit çš„ç§æœ‰å®žä¾‹ã€‚在以åŽç« èŠ‚中,您会看到储存在 \c nameLine å’Œ \c addressText 中的数æ®åœ¨åœ°å€ç°¿çš„许多功能中都会用到。
+
+ 我们ä¸å¿…包å«è¦ä½¿ç”¨çš„ QLabel 对象的声明,这是因为在创建这些对象åŽæˆ‘们ä¸å¿…对其进行引用。在下一部分中,我们会说明 Qt 记录对象所属关系的方å¼ã€‚
+
+ Q_OBJECT å®æœ¬èº«åº”用了部分更高级的 Qt 功能。 我们暂时把 Q_OBJECT å®ç†è§£ä¸ºä½¿ç”¨ \l{QObject::}{tr()} å’Œ \l{QObject::}{connect()} 函数的快æ·æ–¹å¼ï¼Œè¿™ç§ç†è§£å¯¹æˆ‘们的学习更有用。
+
+ æˆ‘ä»¬çŽ°å·²å®Œæˆ \c addressbook.h 文件,接下æ¥æˆ‘们æ¥æ‰§è¡Œå¯¹åº”çš„ \c addressbook.cpp 文件。
+
+ \section1 应用 AddressBook 类
+
+ \c AddressBook 的构造器接收 QWidget å‚æ•° \a parent。按惯例,我们将å‚数传递给基本类的构造器。这ç§çˆ¶é¡¹å¯æœ‰ä¸€ä¸ªæˆ–多个å­é¡¹çš„所属概念对 Qt 中的 widget 分组å分有用。例如,如果删除父项,也会删除其所有å­é¡¹ã€‚
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
+
+ 在该构造器中,我们声明并通过实例æ¥è¡¨ç¤ºä¸¤ä¸ªå±€éƒ¨ QLabel 对象 \c nameLabel å’Œ \c addressLabelï¼Œä»¥åŠ \c nameLine å’Œ \c addressText。如果字符串已进行转æ¢ï¼Œåˆ™ \l{QObject::tr()}{tr()} 函数返回已转æ¢çš„字符串,å¦åˆ™è¿”回字符串本身。我们å¯ä»¥å°†æ­¤å‡½æ•°ç†è§£ \c{<insert translation here>} 标识æ¥æ ‡è®°è¦è¿›è¡Œè½¬æ¢ QString 对象。在以åŽç« èŠ‚å’Œ \l{Qt Examples} 中,您会看到åªè¦ä½¿ç”¨äº†å¯è½¬æ¢çš„字符串就是使用该函数。
+
+ 使用 Qt 编程时,了解布局是如何起作用的会对您很有帮助。Qt æ供三个主è¦å¸ƒå±€ç±» QHBoxLayoutã€QVBoxLayout å’Œ QGridLayout æ¥å¤„ç† widget çš„ä½ç½®ã€‚
+
+ \image addressbook-tutorial-part1-labeled-layout.png
+
+ 我们使用 QGridLayout 以结构化的方å¼æ”¾ç½®æ ‡ç­¾å’Œè¾“入字段。QGridLayout å°†å¯ç”¨ç©ºé—´åˆ†ä¸ºç½‘格,并将 widget 放置在指定了行列å·çš„å•å…ƒæ ¼ä¸­ã€‚上é¢çš„图表显示了布局å•å…ƒæ ¼å’Œ widget çš„ä½ç½®ã€‚我们通过以下代ç æŒ‡å®šè¿™ç§æŽ’列方å¼ï¼š
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp layout
+
+ 请注æ„,\c addressLabel 是使用作为附加å‚æ•°çš„ Qt::AlignTop æ¥æŽ’放ä½ç½®ã€‚è¿™å¯ç¡®ä¿å…¶ä¸ä¼šçºµå‘放置在å•å…ƒæ ¼ (1,0) 中央。有关 Qt 布局的基本简介,请å‚è§\l{Layout Management}{布局类}文档。
+
+ è¦åœ¨ widget 上安装布局对象,必须调用 widget çš„ \l{QWidget::setLayout()}{setLayout()} 函数:
+
+ \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
+
+ 最åŽï¼Œæˆ‘们将 widget 标题设置为“简å•åœ°å€ç°¿â€ã€‚
+
+ \section1 è¿è¡Œåº”用程åº
+
+ \c main() 函数使用å•ç‹¬çš„文件 \c main.cpp。在该函数中,我们实例化了 QApplication 对象 \c app。QApplication 负责管ç†å¤šç§åº”用范围的资æºï¼ˆå¦‚默认字体和光标),以åŠè¿è¡Œäº‹ä»¶å¾ªçŽ¯ã€‚因此,在æ¯ä¸ªä½¿ç”¨ Qt çš„ GUI 应用程åºä¸­éƒ½ä¼šæœ‰ä¸€ä¸ª QApplication 对象。
+
+ \snippet tutorials/addressbook/part1/main.cpp main function
+
+ 我们使用 new 关键字在堆中构造一个新的 \c AddressBook widget,然åŽè°ƒç”¨ \l{QWidget::show()}{show()} 函数对其进行显示。ä¸è¿‡ï¼Œè¯¥ widget åªæœ‰åœ¨åº”用程åºäº‹ä»¶å¾ªçŽ¯å¼€å§‹æ—¶æ‰ä¼šæ˜¾ç¤ºã€‚我们通过调用应用程åºçš„ \l{QApplication::}{exec()} 函数开始事件循环。该函数返回的结果作为 \c main() 函数的返回值。
+*/
+
+/*!
+ \page tutorials-addressbook-part2.html
+ \previouspage 地å€ç°¿ 1 — 设计用户界é¢
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part3}{第三章}
+ \example tutorials/addressbook/part2
+ \title 地å€ç°¿ 2 — 添加地å€
+
+ 创建基本地å€ç°¿åº”用程åºçš„下一步是添加少许用户互动æ“作。
+
+ \image addressbook-tutorial-part2-add-contact.png
+
+ 我们将æ供一个按钮,用户å¯ç‚¹å‡»è¯¥æŒ‰é’®æ¥æ·»åŠ æ–°è”系人。此外,还需è¦å¯¹æ•°æ®ç»“构进行é™å®šï¼Œä»¥ä¾¿æœ‰åºåœ°å‚¨å­˜è¿™äº›è”系人。
+
+ \section1 定义 AddressBook 类
+
+ 由于已ç»è®¾ç½®äº†æ ‡ç­¾å’Œè¾“入字段,我们åªéœ€æ·»åŠ æŒ‰é’®å°±å¯å®Œæˆæ·»åŠ è”系人这一步骤。也就是说,在 \c addressbook.h 文件中已ç»å£°æ˜Žäº†ä¸‰ä¸ª QPushButton 对象和三个对应的公共槽。
+
+ \snippet tutorials/addressbook/part2/addressbook.h slots
+
+ 槽是对特殊信å·è¿›è¡Œå“应的函数。我们将在应用 \c AddressBook 类时进一步详细说明这一概念。如需有关 Qt ä¿¡å·å’Œæ§½æ¦‚念的简介,请å‚è§\l{Signals and Slots}{ä¿¡å·å’Œæ§½}文档。
+
+ 三个 QPushButton 对象分别是 \c addButtonã€\c submitButton å’Œ \c cancelButton,已与è¦åœ¨ä¸Šä¸€ç« ä¸­è¯´æ˜Žçš„ \c nameLine å’Œ \c addressText 一åŒåŒ…å«åœ¨ç§æœ‰å˜é‡å£°æ˜Žä¸­ã€‚
+
+ \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
+
+ 我们需è¦ä¸€ä¸ªå®¹å™¨æ¥å‚¨å­˜åœ°å€ç°¿è”系人,这样æ‰èƒ½æœç´¢å’Œæ˜¾ç¤ºè”系人。QMap 对象 \c contacts å°±å¯å®žçŽ°æ­¤åŠŸèƒ½ï¼Œå› ä¸ºå…¶å¸¦æœ‰ä¸€ä¸ªé”®-值对:è”系人姓å作为键,而è”系人地å€ä½œä¸º\e{值}。
+
+ \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
+
+ 我们还会声明两个ç§æœ‰ QString 对象:\c oldName å’Œ \c oldAddress。这些对象用æ¥ä¿ç•™åœ¨ç”¨æˆ·ç‚¹å‡»\gui{添加}时最åŽæ˜¾ç¤ºçš„è”系人姓å和地å€ã€‚这样,当用户点击\gui{å–消}时,我们就å¯ä»¥è¿”回至上一个è”系人的详细信æ¯ã€‚
+
+ \section1 应用 AddressBook 类
+
+ 在 \c AddressBook 构造器中,我们将 \c nameLine å’Œ \c addressText 设置为åªè¯»ï¼Œè¿™æ ·å°±å¯ä»…显示而ä¸å¿…编辑现有è”系人的详细信æ¯ã€‚
+
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
+ \dots
+ \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
+
+ 然åŽï¼Œæˆ‘们实例化以下按钮:\c addButtonã€\c submitButton å’Œ \c cancelButton。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
+
+ 显示 \c addButton 是通过调用 \l{QPushButton::show()}{show()} 函数实现的,而éšè— \c submitButton å’Œ \c cancelButton 则需调用 \l{QPushButton::hide()}{hide()}。这两个按钮仅当用户点击\gui{添加}æ—¶æ‰ä¼šæ˜¾ç¤ºï¼Œè€Œæ­¤æ“作是通过在下文中说明的\c addContact() 函数处ç†çš„。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
+
+ 我们将按钮的 \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。下é¢çš„图表说明了此过程。
+
+ \image addressbook-tutorial-part2-signals-and-slots.png
+
+ 接下æ¥ï¼Œæˆ‘们将按钮整é½çš„排列在地å€ç°¿ widget çš„å³ä¾§ï¼Œä½¿ç”¨ QVBoxLayout 将其进行纵å‘排列。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
+
+ \l{QBoxLayout::addStretch()}{addStretch()} 函数用æ¥ç¡®ä¿æŒ‰é’®å¹¶ä¸æ˜¯é‡‡ç”¨å‡åŒ€é—´éš”排列的,而是更é è¿‘ widget 的顶部。下图显示了是å¦ä½¿ç”¨ \l{QBoxLayout::addStretch()}{addStretch()} 的差别。
+
+ \image addressbook-tutorial-part2-stretch-effects.png
+
+ 然åŽï¼Œæˆ‘们使用 \l{QGridLayout::addLayout()}{addLayout()} å°† \c buttonLayout1 增加至 \c mainLayout。 这样我们就有了嵌套布局,因为 \c buttonLayout1 现在是 \c mainLayout çš„å­é¡¹ã€‚
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
+
+ 布局å标显示如下:
+
+ \image addressbook-tutorial-part2-labeled-layout.png
+
+ 在 \c addContact() 函数中,我们使用 \c oldName å’Œ \c oldAddress 储存最åŽæ˜¾ç¤ºçš„è”系人详细信æ¯ã€‚然åŽï¼Œæˆ‘们清空这些输入字段并关闭åªè¯»æ¨¡å¼ã€‚输入焦点设置在 \c nameLine,显示 \c submitButton å’Œ \c cancelButton。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp addContact
+
+ \c submitContact() 函数å¯åˆ†ä¸ºä¸‰ä¸ªéƒ¨åˆ†ï¼š
+
+ \list 1
+ \o 我们从 \c nameLine å’Œ \c addressText æå–è”系人的详细信æ¯ï¼Œç„¶åŽå°†å…¶å‚¨å­˜åœ¨ QString 对象中。我们还è¦éªŒè¯ç¡®ä¿ç”¨æˆ·æ²¡æœ‰åœ¨è¾“入字段为空时点击\gui{æ交},å¦åˆ™ï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户输入姓å和地å€ã€‚
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
+
+ \o 我们接ç€ç»§ç»­æ£€æŸ¥æ˜¯å¦è”系人已存在。如果ä¸å­˜åœ¨ï¼Œå°†è”系人添加至 \c contacts,然åŽæ˜¾ç¤º QMessageBox æ示用户已添加è”系人。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
+
+ 如果è”系人已存在,还是会显示 QMessageBox 以æ示用户,以å…添加é‡å¤çš„è”系人。由于 \c contacts 对象是基于姓å地å€çš„é”®-值对,因此è¦ç¡®ä¿é”®å”¯ä¸€ã€‚
+
+ \o 在处ç†äº†ä¸Šè¿°ä¸¤ç§æƒ…况åŽï¼Œä½¿ç”¨ä»¥ä¸‹ä»£ç å°†æŒ‰é’®æ¢å¤ä¸ºæ­£å¸¸çŠ¶æ€ï¼š
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
+
+ \endlist
+
+ 下é¢çš„å±å¹•æˆªå›¾æ˜¾ç¤ºäº†ç”¨äºŽå‘用户显示æ示信æ¯çš„ QMessageBox 对象。
+
+ \image addressbook-tutorial-part2-add-successful.png
+
+ \c cancel() 函数æ¢å¤ä¸Šæ¬¡æ˜¾ç¤ºçš„è”系人详细信æ¯ï¼Œå¹¶å¯ç”¨ \c addButton,还会éšè— \c submitButton å’Œ
+ \c cancelButton。
+
+ \snippet tutorials/addressbook/part2/addressbook.cpp cancel
+
+ 添加è”系人的总体æ€æƒ³å°±æ˜¯æ高用户æ“作的çµæ´»æ€§ï¼Œå¯åœ¨ä»»ä½•æ—¶å€™ç‚¹å‡»\gui{æ交}或\gui{å–消}。下é¢çš„æµç¨‹å›¾è¯¦ç»†è¯´æ˜Žäº†æ­¤æ¦‚念:
+
+ \image addressbook-tutorial-part2-add-flowchart.png
+*/
+
+/*!
+ \page tutorials-addressbook-part3.html
+ \previouspage 地å€ç°¿ 2 — 添加地å€
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part4}{第四章}
+ \example tutorials/addressbook/part3
+ \title 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›®
+
+ 构建地å€ç°¿åº”用程åºçŽ°å·²è¿›å±•è¿‡åŠã€‚我们需è¦å¢žåŠ ä¸€äº›å‡½æ•°ï¼Œä»¥ä¾¿æµè§ˆè”系人。但首先è¦å†³å®šé‡‡ç”¨ä½•ç§æ•°æ®ç»“æž„æ–¹å¼æ¥å‚¨å­˜è¿™äº›è”系人。
+
+ 在第二章中,我们使用了 QMap é”®-值对,å³è”系人姓å作为\e{é”®},而è”系人地å€ä½œä¸º\e{值}。这ç§æ–¹å¼å¾ˆé€‚åˆæˆ‘们的实例。ä¸è¿‡ï¼Œè¦æµè§ˆå’Œæ˜¾ç¤ºæ¯ä¸ªæ¡ç›®ï¼Œè¿˜éœ€è¦è¿›è¡Œä¸€äº›æ”¹è¿›ã€‚
+
+ 我们改进 QMap çš„æ–¹å¼æ˜¯ï¼Œå°†æ•°æ®ç»“构替æ¢ä¸ºç±»ä¼¼å¾ªçŽ¯é“¾æŽ¥çš„列表,其中所有元素都是相互关è”的,包括第一个元素和最åŽä¸€ä¸ªå…ƒç´ ã€‚下图图解说明了该数æ®ç»“构。
+
+ \image addressbook-tutorial-part3-linkedlist.png
+
+ \section1 定义 AddressBook 类
+
+ è¦ç»™åœ°å€ç°¿åº”用程åºå¢žåŠ æµè§ˆåŠŸèƒ½ï¼Œæˆ‘们需è¦ä¸º \c AddressBook ç±»å†å¢žåŠ ä¸¤ä¸ªå‡½æ•°ï¼š\c next() å’Œ \c previous()。将这两个函数添加到 \c addressbook.h 文件中:
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation functions
+
+ 我们还需è¦ä½¿ç”¨å…¶ä»–两个 QPushButton 对象,因此将 \c nextButton å’Œ \c previousButton 声明为ç§æœ‰å˜é‡ï¼š
+
+ \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
+
+ \section1 应用 AddressBook 类
+
+ 在 \c AddressBook çš„ \c addressbook.cpp 构造器中,我们实例化 \c nextButton å’Œ \c previousButton,并且这两项默认为ç¦ç”¨ã€‚这是因为仅当地å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨æµè§ˆåŠŸèƒ½ã€‚
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
+
+ 然åŽï¼Œæˆ‘们将这两个按钮与其相应的槽关è”:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
+
+ 下图å³ä¸ºé¢„期的图形用户界é¢ã€‚请注æ„,该用户界é¢å·²å¾ˆæŽ¥è¿‘应用程åºæœ€ç»ˆçš„æ ·å­ã€‚
+
+ \image addressbook-tutorial-part3-screenshot.png
+
+ 我们按照 \c next() å’Œ \c previous() 函数的基本规范,将 \c nextButton 放置在å³ä¾§ï¼Œè€Œ \c previousButton 放置在左侧。为了使布局更加直观,我们使用 QHBoxLayout å°† widget 并排放置:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
+
+ 然åŽï¼Œå°† QHBoxLayout 对象 \c buttonLayout2 增加至 \c mainLayout。
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
+
+ 下图显示了 widget 在 \c mainLayout 中的åæ ‡ä½ç½®ã€‚
+
+ \image addressbook-tutorial-part3-labeled-layout.png
+
+ 在 \c addContact() 函数中,我们必须ç¦ç”¨è¿™å‡ ä¸ªæŒ‰é’®ï¼Œè¿™æ ·ç”¨æˆ·å°±ä¸ä¼šåœ¨å¢žåŠ è”系人时å°è¯•è¿›è¡Œæµè§ˆã€‚
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
+
+ 此外,在 \c submitContact() 函数中,我们å¯ç”¨äº†æµè§ˆæŒ‰é’® \c nextButton å’Œ \c previousButton,这å–决于 \c contacts 的多少。如上文所述,æµè§ˆåŠŸèƒ½ä»…在地å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨ã€‚以下代ç è¡Œè¯´æ˜Žäº†å¦‚何实现此功能:
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
+
+ 我们还在 \c cancel() 函数中加入这几行代ç ã€‚
+
+ 记得我们曾使用 QMap 对象 \c contacts 模拟了一个循环链接的列表。因此,在 \c next() å‡½æ•°ä¸­ï¼Œæˆ‘ä»¬èŽ·å– \c contacts 的迭代器,然åŽæ‰§è¡Œä»¥ä¸‹æ“作:
+
+ \list
+ \o 如果迭代器未达到 \c contacts 结尾,就会增加一。
+ \o 如果迭代器已达到 \c contacts 的结尾,就移至 \c contacts 的起始ä½ç½®ã€‚这给人感觉 QMap å°±åƒæ˜¯ä¸€ä¸ªå¾ªçŽ¯é“¾æŽ¥çš„列表。
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp next() function
+
+ 一旦在 \c contacts 中循环至正确的对象,就会通过 \c nameLine 和 \c addressText 显示对象的内容。
+
+ åŒæ ·ï¼Œåœ¨ \c previous() å‡½æ•°ä¸­ï¼Œæˆ‘ä»¬èŽ·å– \c contacts 的迭代器,然åŽæ‰§è¡Œä»¥ä¸‹æ“作:
+
+ \list
+ \o 如果迭代器达到 \c contacts 的结尾,就清除显示内容,然åŽè¿”回。
+ \o 如果迭代器在 \c contacts 的起始ä½ç½®ï¼Œå°±å°†å…¶ç§»è‡³ç»“尾。
+ \o 然åŽï¼Œå°†è¿­ä»£å™¨å‡ä¸€ã€‚
+ \endlist
+
+ \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
+
+ 接ç€ï¼Œé‡æ–°æ˜¾ç¤º \c contacts 中当å‰å¯¹è±¡çš„内容。
+*/
+
+/*!
+ \page tutorials-addressbook-part4.html
+ \previouspage 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›®
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part5}{第五章}
+ \example tutorials/addressbook/part4
+ \title 地å€ç°¿ 4 — 编辑和删除地å€
+
+ 在本章中,我们将了解如何修改储存在地å€ç°¿åº”用程åºä¸­çš„è”系人的内容。
+
+ \image addressbook-tutorial-screenshot.png
+
+ 现有的地å€ç°¿ä¸ä»…å¯ä»¥äº•äº•æœ‰æ¡åœ°å‚¨å­˜è”系人,还å¯è¿›è¡Œæµè§ˆã€‚å†æ·»åŠ ä¸Šç¼–辑和删除功能,以便在需è¦æ—¶æ›´æ”¹è”系人的详细信æ¯ï¼Œè¿™æ ·æ›´æ˜“于使用。ä¸è¿‡ï¼Œè¿˜éœ€ä½¿ç”¨ enum 类型进行一些改进。在å‰å‡ ç« ä¸­ï¼Œæˆ‘们使用以下两ç§æ¨¡å¼ï¼š\c{AddingMode} å’Œ \c{NavigationMode}。但是,他们并未定义为 enum。我们是采用手动方å¼å¯ç”¨å’Œç¦ç”¨ç›¸åº”的按钮,这就导致有多行é‡å¤çš„代ç ã€‚
+
+ 在本章中,我们定义带有以下三ç§ä¸åŒå€¼çš„ \c{Mode} enum 类型:
+
+ \list
+ \o \c{NavigationMode}ã€
+ \o \c{AddingMode} 和
+ \o \c{EditingMode}。
+ \endlist
+
+ \section1 定义 AddressBook 类
+
+ \c addressbook.h æ–‡ä»¶å·²æ›´æ–°ä¸ºåŒ…å« Mode \c enum 类型:
+
+ \snippet tutorials/addressbook/part4/addressbook.h Mode enum
+
+ 我们还è¦å‘当å‰çš„公有槽列表增加两个新槽:\c editContact() å’Œ \c removeContact()。
+
+ \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
+
+ 为了在模å¼é—´åˆ‡æ¢ï¼Œæˆ‘们引入了 \c updateInterface() 函数æ¥æŽ§åˆ¶æ‰€æœ‰ QPushButton 对象的å¯ç”¨å’Œç¦ç”¨ã€‚è¦å®žçŽ°ä¸Šæ–‡æåŠçš„编辑和删除功能,我们还è¦å¢žåŠ ä¸¤ä¸ªæ–°æŒ‰é’®ï¼š\c editButton å’Œ \c removeButton。
+
+ \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
+
+ 最åŽï¼Œæˆ‘们声明 \c currentMode æ¥è·Ÿè¸ª enum 的当å‰æ¨¡å¼ã€‚
+
+ \section1 应用 AddressBook 类
+
+ 我们现在必须应用地å€ç°¿åº”用程åºçš„模å¼æ›´æ”¹åŠŸèƒ½ã€‚\c editButton å’Œ \c removeButton 已实例化并默认为ç¦ç”¨ï¼Œè¿™æ˜¯å› ä¸ºåœ°å€ç°¿å¯åŠ¨æ—¶åœ¨å†…存中没有è”系人。
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
+
+ 这些按钮会与其相应的槽 \c editContact() å’Œ \c removeContact() å…³è”,然åŽæˆ‘们将其添加至 \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
+
+ 在将模å¼åˆ‡æ¢åˆ° \c EditingMode 之å‰ï¼Œ\c editContact() 函数使用 \c oldName å’Œ \c oldAddress 储存è”系人旧的详细信æ¯ã€‚ 在该模å¼ä¸‹ï¼Œ\c submitButton å’Œ \c cancelButton å‡å·²å¯ç”¨ï¼Œè¿™æ ·ç”¨æˆ·å°±å¯ä»¥æ›´æ”¹è”系人的详细信æ¯å¹¶å¯ç‚¹å‡»ä»»ä½•ä¸€ä¸ªæŒ‰é’®ã€‚
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
+
+ \c submitContact() 函数已被 \c{if-else} 语å¥åˆ†ä¸ºä¸¤éƒ¨åˆ†ã€‚我们查看 \c currentMode 是å¦åœ¨ \c AddingMode 模å¼ä¸‹ã€‚如果是,我们继续添加æ“作。
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
+ \dots
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
+
+ å¦åˆ™ï¼Œæˆ‘们查看 \c currentMode 是å¦åœ¨ \c EditingMode 模å¼ä¸‹ã€‚如果是,我们比较 \c oldName å’Œ \c name。如果姓å已更改,我们从 \c contacts 中删除旧的è”系人并æ’入已更新的è”系人。
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
+
+ 如果仅更改了地å€ï¼ˆä¾‹å¦‚ \c oldAddress 与 \c address ä¸åŒï¼‰ï¼Œæˆ‘们就更新è”系人的地å€ã€‚最åŽï¼Œæˆ‘们将 \c currentMode 设置为 \c NavigationMode。这一步至关é‡è¦ï¼Œå› ä¸ºå®ƒä¼šé‡æ–°å¯ç”¨æ‰€æœ‰å·²ç¦ç”¨çš„按钮。
+
+ è¦ä»Žåœ°å€ç°¿ä¸­åˆ é™¤è”系人,我们采用 \c removeContact() 函数。该函数查看 \c contacts 中是å¦åŒ…å«è¯¥è”系人。
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
+
+ 如果有,我们显示 QMessageBox,确认用户的删除æ“作。一旦用户确认æ“作,我们调用 \c previous() ç¡®ä¿ç”¨æˆ·ç•Œé¢æ˜¾ç¤ºå…¶ä»–è”系人,然åŽæˆ‘们使用 QMap çš„ \l{QMap::remove()}{remove()} 函数删除已已确认的è”系人。出于好æ„,我们会显示 QMessageBox æ示用户。在该函数中使用两ç§ä¿¡æ¯æ¡†æ˜¾ç¤ºå¦‚下:
+
+ \image addressbook-tutorial-part4-remove.png
+
+ \section2 更新用户界é¢
+
+ 我们在上文æ到 \c updateInterface() 函数,它å¯æ ¹æ®å½“å‰çš„模å¼å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚该函数会根æ®ä¼ é€’给它的 \c mode å‚数更新当å‰çš„模å¼ï¼Œåœ¨æ ¡éªŒå€¼ä¹‹å‰å°†å‚数分é…ç»™ \c currentMode。
+
+ 这样,æ¯ä¸ªæŒ‰é’®å°±æ ¹æ®å½“å‰çš„模å¼è¿›è¡Œå¯ç”¨æˆ–ç¦ç”¨ã€‚\c AddingMode å’Œ \c EditingMode 的代ç æ˜¾ç¤ºå¦‚下:
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
+
+ ä¸è¿‡å¯¹äºŽ \c NavigationMode,我们在 QPushButton::setEnabled() 函数的å‚数中加入了æ¡ä»¶ã€‚这样å¯ç¡®ä¿ \c editButton å’Œ \c removeButton 在地å€ç°¿ä¸­è‡³å°‘有一个è”系人的情况下å¯ç”¨ï¼Œè€Œ \c nextButton å’Œ \c previousButton 仅在地å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰å¯ç”¨ã€‚
+
+ \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
+
+ 通过在åŒä¸€å‡½æ•°ä¸­è®¾ç½®æ¨¡å¼å’Œæ›´æ–°ç”¨æˆ·ç•Œé¢ï¼Œæˆ‘们å¯ä»¥é¿å…用户界é¢ä¸Žåº”用程åºå†…部状æ€ä¸åŒæ­¥çš„å¯èƒ½æ€§ã€‚
+*/
+
+/*!
+ \page tutorials-addressbook-part5.html
+ \previouspage 地å€ç°¿ 4 — 编辑和删除地å€
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part6}{第六章}
+ \example tutorials/addressbook/part5
+ \title 地å€ç°¿ 5 — 添加查找功能
+
+ 在本章中,我们将了解如何在地å€ç°¿åº”用程åºä¸­å®šä½è”系人和地å€ã€‚
+
+ \image addressbook-tutorial-part5-screenshot.png
+
+ éšç€æˆ‘们ä¸æ–­ä¸ºåœ°å€ç°¿åº”用程åºæ·»åŠ è”系人,使用下一个和上一个按钮æµè§ˆè”系人就会å˜å¾—很ç¹ç。在这ç§æƒ…况下,使用查找函数查找è”系人就会更加有效。上é¢çš„å±å¹•æˆªå›¾æ˜¾ç¤ºäº†æŸ¥æ‰¾æŒ‰é’®åŠå…¶åœ¨æŒ‰é’®é¢æ¿ä¸Šçš„ä½ç½®ã€‚
+
+ 当用户点击查找按钮时,有必è¦æ˜¾ç¤ºä¸€ä¸ªå¯¹è¯æ¡†ï¼Œç”¨æˆ·å¯åœ¨å…¶ä¸­è¾“å…¥è”系人的姓å。Qt æ供了 QDialog(我们会在本章中将其用作å­ç±»ï¼‰ï¼Œå¯ä½¿ç”¨ \c FindDialog 类。
+
+ \section1 定义 FindDialog 类
+
+ \image addressbook-tutorial-part5-finddialog.png
+
+ è¦ä½¿ç”¨ QDialog çš„å­ç±»ï¼Œæˆ‘们首先è¦åœ¨ \c finddialog.h 文件中声明 QDialog 的头信æ¯ã€‚此外,我们还使用å‘å‰ (forward) 声明æ¥å£°æ˜Ž QLineEdit å’Œ QPushButton,这样我们就能在对è¯æ¡†ç±»ä¸­ä½¿ç”¨è¿™äº› widget。
+
+ 因为在 \c AddressBook 类中,\c FindDialog 类包å«äº† Q_OBJECT å®ï¼Œå¹¶ä¸”其构造器已定义为接收父级 QWidget,å³ä½¿å¯¹è¯æ¡†ä»¥å•ç‹¬çš„窗å£æ–¹å¼æ‰“开。
+
+ \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
+
+ 我们定义了公有函数 \c getFindText(),供实例化 \c FindDialog 的类使用,这样这些类å¯ä»¥èŽ·å–用户输入的文本。公有槽 \c findClicked() 定义为在用户点击\gui{查找}按钮时处ç†æœç´¢å­—符串。
+
+ 最åŽï¼Œæˆ‘们定义ç§æœ‰å˜é‡ \c findButtonã€\c lineEdit å’Œ \c findText,分别对应\gui{查找}按钮ã€ç”¨æˆ·è¾“å…¥æœç´¢å­—符串的行编辑框和储存æœç´¢å­—符串供ç¨åŽä½¿ç”¨çš„内部字符串。
+
+ \section1 应用 FindDialog 类
+
+ 在 \c FindDialog 的构造器中,我们设置ç§æœ‰å˜é‡ \c lineEditã€\c findButton å’Œ \c findText。使用 QHBoxLayout 放置 widget。
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp constructor
+
+ 我们设定布局和窗å£æ ‡é¢˜ï¼Œå¹¶å°†ä¿¡å·ä¸Žå…¶å„自的槽关è”。请注æ„,\c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·å·²ä¸Ž \c findClicked() å’Œ \l{QDialog::accept()}{accept()} å…³è”。QDialog æ供的 \l{QDialog::accept()}{accept()} 槽会éšè—对è¯æ¡†å¹¶å°†ç»“果代ç è®¾ç½®ä¸º \l{QDialog::}{Accepted}。我们使用该函数有助于 \c AddressBook çš„ \c findContact() 函数知晓 \c FindDialog 对象关闭的时间。我们在讨论 \c findContact() 函数时将对该函数åšè¿›ä¸€æ­¥è¯´æ˜Žã€‚
+
+ \image addressbook-tutorial-part5-signals-and-slots.png
+
+ 在 \c findClicked() ä¸­ï¼Œæˆ‘ä»¬éªŒè¯ \c lineEdit 以确ä¿ç”¨æˆ·æ²¡æœ‰åœ¨å°šæœªè¾“å…¥è”系人姓å时就点击\gui{查找}按钮。然åŽï¼Œæˆ‘们将 \c findText 设置为从 \c lineEdit æå–çš„æœç´¢å­—符串。之åŽï¼Œæˆ‘们清空 \c lineEdit 的内容并éšè—对è¯æ¡†ã€‚
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
+
+ \c findText å˜é‡å·²æœ‰å…¬æœ‰ getter 函数 \c getFindText() 与其相关è”。既然我们仅在构造器和 \c findClicked() 函数中直接设定了 \c findText, 我们就ä¸åœ¨åˆ›å»º \c getFindText() çš„åŒæ—¶å†åˆ›å»º setter 函数。由于 \c getFindText() 是公有的,实例化和使用 \c FindDialog çš„ç±»å¯å§‹ç»ˆè¯»å–用户已输入并确认的æœç´¢å­—符串。
+
+ \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
+
+ \section1 定义 AddressBook 类
+
+ è¦ç¡®ä¿æˆ‘们å¯ä½¿ç”¨ \c AddressBook 类中的 \c FindDialog,我们è¦åœ¨ \c addressbook.h æ–‡ä»¶ä¸­åŒ…å« \c finddialog.h。
+
+ \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
+
+ 至此,所有地å€ç°¿åŠŸèƒ½éƒ½æœ‰äº† QPushButton 和对应的槽。åŒæ ·ï¼Œ\gui{Find} 功能有 \c findButton å’Œ \c findContact()。
+
+ \c findButton 声明为ç§æœ‰å˜é‡ï¼Œè€Œ \c findContact() 函数声明为公有槽。
+
+ \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
+
+ 最åŽï¼Œæˆ‘们声明ç§æœ‰å˜é‡ \c dialog,用于引用 \c FindDialog 的实例。
+
+ \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
+
+ 在实例化对è¯æ¡†åŽï¼Œæˆ‘们å¯èƒ½ä¼šå¯¹å…¶è¿›è¡Œå¤šæ¬¡ä½¿ç”¨ã€‚使用ç§æœ‰å˜é‡å¯åœ¨ç±»ä¸­ä¸åŒä½ç½®å¯¹å…¶è¿›è¡Œå¤šæ¬¡å¼•ç”¨ã€‚
+
+ \section1 应用 AddressBook 类
+
+ 在 \c AddressBook 类的构造器中,实例化ç§æœ‰å¯¹è±¡ \c findButton å’Œ \c findDialog:
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
+ \dots
+ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
+
+ 接下æ¥ï¼Œå°† \c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Ž \c findContact() å…³è”。
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
+
+ 现在唯一è¦å®Œæˆçš„就是 \c findContact() 函数的编ç ï¼š
+
+ \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
+
+ 我们从显示 \c FindDialog 的实例 \c dialog 开始入手。这时用户开始输入è”系人姓å进行查找。用户点击对è¯æ¡†çš„ \c findButton åŽï¼Œå¯¹è¯æ¡†ä¼šéšè—,并且结果代ç è®¾ç½®ä¸º QDialog::Accepted.这样就确ä¿äº† \c if 语å¥å§‹ç»ˆä¸ºçœŸã€‚
+
+ 然åŽï¼Œæˆ‘们就开始使用 \c FindDialog çš„ \c getFindText() 函数æå–æœç´¢å­—符串,这个字符串也就是本例中的 \c contactName。如果地å€ç°¿ä¸­æœ‰è”系人,就立å³æ˜¾ç¤ºè¯¥è”系人。å¦åˆ™ï¼Œæ˜¾ç¤ºå¦‚下所示的 QMessageBox 表明æœç´¢å¤±è´¥ã€‚
+
+ \image addressbook-tutorial-part5-notfound.png
+*/
+
+/*!
+ \page tutorials-addressbook-part6.html
+ \previouspage 地å€ç°¿ 5 — 添加查找功能
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \nextpage {tutorials/addressbook/part7}{第七章}
+ \example tutorials/addressbook/part6
+ \title 地å€ç°¿ 6 — 加载和ä¿å­˜
+
+ 本章æ述了用于编写地å€ç°¿åº”用程åºçš„加载和ä¿å­˜ç¨‹åºæ‰€ä½¿ç”¨çš„ Qt 文件处ç†åŠŸèƒ½ã€‚
+
+ \image addressbook-tutorial-part6-screenshot.png
+
+ 虽然æµè§ˆå’Œæœç´¢è”系人是éžå¸¸å®žç”¨çš„功能,但åªæœ‰åœ¨å¯ä»¥ä¿å­˜çŽ°æœ‰è”系人并å¯ä»¥åœ¨ä»¥åŽåŠ è½½çš„å‰æ下地å€ç°¿æ‰çœŸæ­£å®Œå…¨å¯ç”¨ã€‚Qt æ供大é‡ç”¨äºŽ\l{Input/Output and Networking}{输入和输出}的类,但我们åªé€‰æ‹©ä¸¤ä¸ªæ˜“于åˆå¹¶ä½¿ç”¨çš„类:QFile å’Œ QDataStream。
+
+ QFile 对象表示ç£ç›˜ä¸Šå¯è¯»å–和写入的文件。QFile 是代表多ç§ä¸åŒè®¾å¤‡ä¸”应用更广的 QIODevice 类的å­ç±»ã€‚
+
+ QDataStream 对象用于按顺åºæŽ’列二进制数æ®ï¼Œä»¥ä¾¿å‚¨å­˜åœ¨ QIODevice 中并供以åŽæ£€ç´¢ã€‚读å–或写入 QIODevice 就如åŒæ‰“开数æ®æµï¼Œç„¶åŽè¯»å–或写入一样简å•ï¼Œåªæ˜¯å‚数为ä¸åŒçš„设备。
+
+
+ \section1 定义 AddressBook 类
+
+ 我们声明两个公有槽 \c saveToFile() å’Œ \c loadFromFile(),以åŠä¸¤ä¸ª QPushButton 对象 \c loadButton å’Œ \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 应用 AddressBook 类
+
+ 在构造器中,我们实例化 \c loadButton å’Œ \c saveButton。ç†æƒ³æƒ…况下,将按钮标签设置为“从文件加载è”系人â€å’Œâ€œå°†è”系人ä¿å­˜è‡³æ–‡ä»¶â€ä¼šæ›´æ–¹ä¾¿ç”¨æˆ·ä½¿ç”¨ã€‚ä¸è¿‡ï¼Œç”±äºŽå…¶ä»–按钮的大å°é™åˆ¶ï¼Œæˆ‘们将标签设置为\gui{加载...}å’Œ\gui{ä¿å­˜...}。幸è¿çš„是,Qt æ供了使用 \l{QWidget::setToolTip()}{setToolTip()} æ¥è®¾ç½®å·¥å…·æ示的简å•æ–¹å¼ï¼Œæˆ‘们å¯é€šè¿‡å¦‚下方å¼å°†å…¶ç”¨äºŽæŒ‰é’®ï¼š
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
+ \dots
+ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
+
+ 虽然此处没有显示,但与其他应用的功能一样,我们在å³ä¾§çš„布局é¢æ¿ \c button1Layout 上添加按钮,然åŽå°†æŒ‰é’®çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。
+
+ 至于ä¿å­˜åŠŸèƒ½ï¼Œæˆ‘们首先使用 QFileDialog::getSaveFileName() èŽ·å– \c fileName。 这是 QFileDialog æ供的一个便æ·åŠŸèƒ½ï¼Œå¯å¼¹å‡ºæ ·å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…许用户输入文件å或选择现有的 \c{.abk} 文件。\c{.abk} 文件是ä¿å­˜è”系人时创建的地å€ç°¿æ‰©å±•å。
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
+
+ 弹出的文件对è¯æ¡†å±å¹•æˆªå›¾æ˜¾ç¤ºå¦‚下:
+
+ \image addressbook-tutorial-part6-save.png
+
+ 如果 \c fileName ä¸ä¸ºç©ºï¼Œæˆ‘们就使用 \c fileName 创建 QFile 对象 \c file。 QFile 与 QDataStream 一åŒä½¿ç”¨ï¼Œè¿™æ˜¯å› ä¸ºQFile 是 QIODevice。
+
+ 接下æ¥ï¼Œæˆ‘们å°è¯•ä»¥ \l{QIODevice::}{WriteOnly} 模å¼æ‰“开文件。如果未能打开,会显示 QMessageBox æ示用户。
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
+
+ å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c out,以写入打开的文件。QDataStream è¦æ±‚读写æ“作需使用相åŒç‰ˆæœ¬çš„æ•°æ®æµã€‚在将数æ®æŒ‰é¡ºåºå†™å…¥ \c file 之å‰ï¼Œå°†ä½¿ç”¨çš„版本设置为\l{QDataStream::Qt_4_5}{采用 Qt 4.5 的版本}å°±å¯ç¡®ä¿ç‰ˆæœ¬ç›¸åŒã€‚
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
+
+ 至于加载功能,我们也是使用 QFileDialog::getOpenFileName() èŽ·å– \c fileName。该函数与 QFileDialog::getSaveFileName() 相对应,也是弹出样å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…许用户输入文件å或选择现有的 \c{.abk} 文件加载到地å€ç°¿ä¸­ã€‚
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
+
+ 例如,在 Windows 上,该函数弹出本地文件对è¯æ¡†ï¼Œå¦‚以下å±å¹•æˆªå›¾æ‰€ç¤ºã€‚
+
+ \image addressbook-tutorial-part6-load.png
+
+ 如果 \c fileName ä¸ä¸ºç©ºï¼Œè¿˜æ˜¯ä½¿ç”¨ QFile 对象 \c file,然åŽå°è¯•åœ¨ \l{QIODevice::}{ReadOnly} 模å¼ä¸‹æ‰“开文件。与 \c saveToFile() 的应用方å¼ç±»ä¼¼ï¼Œå¦‚æžœå°è¯•å¤±è´¥ï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户。
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
+
+ å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c in,按上文所述设置其版本,然åŽå°†æŒ‰é¡ºåºæŽ’列的数æ®è¯»å…¥ \c contacts æ•°æ®ç»“构。请注æ„,在将数æ®è¯»å…¥ä¹‹å‰æ¸…空 \c contacts å¯ç®€åŒ–文件读å–过程。更高级的方法是将è”系人读å–至临时 QMap 对象,然åŽä»…å¤åˆ¶ \c contacts 中ä¸å­˜åœ¨çš„è”系人。
+
+ \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
+
+ è¦æ˜¾ç¤ºä»Žæ–‡ä»¶ä¸­è¯»å–çš„è”系人,必须è¦å…ˆéªŒè¯èŽ·å–çš„æ•°æ®ï¼Œä»¥ç¡®ä¿è¯»å–的文件实际包å«åœ°å€ç°¿è”系人。如果为真,显示第一个è”系人,å¦åˆ™æ˜¾ç¤º QMessageBox æ示出现问题。最åŽï¼Œæˆ‘们更新界é¢ä»¥ç›¸åº”地å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚
+*/
+
+/*!
+ \page tutorials-addressbook-part7.html
+ \previouspage 地å€ç°¿ 6 — 加载和ä¿å­˜
+ \contentspage {地å€ç°¿æ•™ç¨‹}{目录}
+ \example tutorials/addressbook/part7
+ \title 地å€ç°¿ 7 — 附加功能
+
+ 本章讲述了部分å¯ä½¿åœ°å€ç°¿åº”用程åºæ—¥å¸¸ä½¿ç”¨æ›´åŠ ä¾¿æ·çš„附加功能。
+
+ \image addressbook-tutorial-part7-screenshot.png
+
+ 虽然地å€ç°¿åº”用程åºå…¶è‡ªèº«åŠŸèƒ½å·²ç»å¾ˆå®žç”¨ï¼Œä½†æ˜¯å¦‚æžœå¯å’Œå…¶ä»–应用程åºäº’æ¢è”系人数æ®å°±ä¼šæ›´åŠ æœ‰ç›Šã€‚vCard æ ¼å¼æ˜¯ä¸€ç§æµè¡Œçš„文件格å¼ï¼Œå°±å¯ç”¨äºŽæ­¤ç›®çš„。在本章中,我们会扩展地å€ç°¿å®¢æˆ·ç«¯ï¼Œå¯å°†è”系人导出到 vCard \c{.vcf} 文件中。
+
+ \section1 定义 AddressBook 类
+
+ 我们在 \c addressbook.h 文件的 \c AddressBook 类中添加 QPushButton 对象 \c exportButton 以åŠå¯¹åº”的公有槽 \c exportAsVCard()。
+
+ \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
+ \dots
+ \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
+
+ \section1 应用 AddressBook 类
+
+ 在 \c AddressBook 构造器中,我们将 \c exportButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·è¿žæŽ¥è‡³ \c exportAsVCard()。我们还会将该按钮添加至 \c buttonLayout1,它是负责å³ä¾§æŒ‰é’®é¢æ¿çš„布局类。
+
+ 在 \c exportAsVCard() 函数中,我们从æå– \c name 中è”系人姓å开始入手。我们声明 \c firstNameã€\c lastName å’Œ \c nameList。接下æ¥ï¼Œæˆ‘们查找 \c name 中第一处空白的索引。如果有空白,就将è”系人的姓å分隔为 \c firstName å’Œ lastName。然åŽï¼Œå°†ç©ºç™½æ›¿æ¢ä¸ºä¸‹åˆ’线 ("_")。或者,如果没有空白,就认定è”系人åªæœ‰å字。
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
+
+ 至于 \c saveToFile() 函数,会打开文件对è¯æ¡†ï¼Œè®©ç”¨æˆ·é€‰æ‹©æ–‡ä»¶çš„ä½ç½®ã€‚通过选择的文件å称,我们创建è¦å†™å…¥çš„ QFile 实例。
+
+ 我们å°è¯•ä»¥ \l{QIODevice::}{WriteOnly} 模å¼æ‰“开文件。如果æ“作失败,会显示 QMessageBox æ示用户出现问题并返回。å¦åˆ™ï¼Œå°†æ–‡ä»¶ä½œä¸ºå‚数传递给 QTextStream 对象 \c out。与 QDataStream 类似,QTextStream ç±»æ供了读å–纯文本和将其写入到文件的功能。因此,所生æˆçš„ \c{.vcf} 文件å¯ä»¥åœ¨æ–‡æœ¬ç¼–辑器中打开进行编辑。
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
+
+ 然åŽï¼Œæˆ‘们写出ä¾æ¬¡å¸¦æœ‰ \c{BEGIN:VCARD} å’Œ \c{VERSION:2.1} 标记的 vCard 文件。è”系人的姓å使用 \c{N:} 标记写入。至于写入 vCard “File asâ€å±žæ€§çš„ FN: 标记,我们必须è¦æŸ¥çœ‹æ˜¯å¦è”系人带有姓。如果è”系人有姓,就使用 \c nameList 中的详细信æ¯å¡«å…¥è¯¥æ ‡è®°ã€‚å¦åˆ™ï¼Œä»…写入 \c firstName。
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
+
+ 我们继续写入è”系人的地å€ã€‚地å€ä¸­çš„分å·ä½¿ç”¨ "\\" 进行转义,新行使用分å·è¿›è¡Œæ›¿æ¢ï¼Œè€Œé€—å·ä½¿ç”¨ç©ºç™½è¿›è¡Œæ›¿æ¢ã€‚最åŽï¼Œæˆ‘们ä¾æ¬¡å†™å…¥ \c{ADR;HOME:;}ã€\c address å’Œ \c{END:VCARD} 标记。
+
+ \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
+
+ 最åŽï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户已æˆåŠŸå¯¼å‡º vCard。
+
+ \e{vCard 是 \l{http://www.imc.org}{Internet Mail Consortium} 的商标}。
+*/
diff --git a/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc
new file mode 100644
index 0000000..90ef4f3
--- /dev/null
+++ b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** 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
+ \title Widgets 教程
+ \brief This tutorial covers basic usage of widgets and layouts, showing how
+ they are used to build GUI applications.
+
+ \startpage {index.html}{Qt Reference Documentation}
+ \contentspage 教程
+ \nextpage {Widgets 教程 — 创建窗å£}
+
+
+ \section1 简介
+
+ Widget 是使用 Qt ç¼–å†™çš„å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 应用程åºçš„基本生æˆå—。æ¯ä¸ª GUI 组件,如按钮ã€æ ‡ç­¾æˆ–文本编辑器,都是一个 widget ,并å¯ä»¥æ”¾ç½®åœ¨çŽ°æœ‰çš„用户界é¢ä¸­æˆ–作为å•ç‹¬çš„窗å£æ˜¾ç¤ºã€‚æ¯ç§ç±»åž‹çš„组件都是由 QWidget 的特殊å­ç±»æ供的,而 QWidget 自身åˆæ˜¯ QObject çš„å­ç±»ã€‚
+
+ QWidget ä¸æ˜¯ä¸€ä¸ªæŠ½è±¡ç±»ï¼›å®ƒå¯ç”¨ä½œå…¶ä»– widget 的容器,并很容易作为å­ç±»ä½¿ç”¨æ¥åˆ›å»ºå®šåˆ¶ widget。它ç»å¸¸ç”¨æ¥åˆ›å»ºæ”¾ç½®å…¶ä»– widget 的窗å£ã€‚
+
+ 至于 QObject,å¯ä½¿ç”¨çˆ¶å¯¹è±¡åˆ›å»º widget 以表明其所属关系,这å¯ç¡®ä¿åˆ é™¤ä¸å†ä½¿ç”¨çš„对象。使用 widget,这些父å­å…³ç³»å°±æœ‰äº†æ›´å¤šçš„æ„义:æ¯ä¸ªå­ç±»éƒ½æ˜¾ç¤ºåœ¨å…¶çˆ¶çº§æ‰€æ‹¥æœ‰çš„å±å¹•åŒºåŸŸå†…。也就是说,当删除窗å£æ—¶ï¼Œå…¶åŒ…å«çš„所有 widget 也都自动删除。
+
+ \section1 Writing a main Function
+
+ Many of the GUI examples in Qt follow the pattern of having a \c{main.cpp}
+ file containing code to initialize the application, and a number of other
+ source and header files containing the application logic and custom GUI
+ components.
+
+ A typical \c main() function, written in \c{main.cpp}, looks like this:
+
+ \snippet doc/src/snippets/widgets-tutorial/template.cpp main.cpp body
+
+ We first construct a QApplication object which is configured using any
+ arguments passed in from the command line. After any widgets have been
+ created and shown, we call QApplication::exec() to start Qt's event loop.
+ Control passes to Qt until this function returns, at which point we return
+ the value we obtain from this function.
+
+ In each part of this tutorial, we provide an example that is written
+ entirely within a \c main() function. In more sophisticated examples, the
+ code to set up widgets and layouts is written in other parts of the
+ example. For example, the GUI for a main window may be set up in the
+ constructor of a QMainWindow subclass.
+
+ The \l{Widgets examples} are a good place to look for
+ more complex and complete examples and applications.
+
+ \section1 Building Examples and Tutorials
+
+ If you obtained a binary package of Qt or compiled it yourself, the
+ examples described in this tutorial should already be ready to run.
+ However, if you may wish to modify them and recompile them, you need to
+ perform the following steps:
+
+ \list 1
+ \o At the command line, enter the directory containing the example you
+ wish to recompile.
+ \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 should have been created within the current directory.
+ On Windows, this file may be located within a \c debug or \c release
+ subdirectory. You can run this file to see the example code at work.
+*/
+
+/*!
+ \page widgets-tutorial-toplevel.html
+ \contentspage {Widgets 教程}{目录}
+ \previouspage {Widgets 教程}
+ \nextpage {Widgets 教程 — Child Widgets}
+ \example tutorials/widgets/toplevel
+ \title Widgets 教程 — 创建窗å£
+
+ 如果 widget 未使用父级进行创建,则在显示时视为窗å£æˆ–\e{顶层 widget}。由于顶层 widget 没有父级对象类æ¥ç¡®ä¿åœ¨å…¶ä¸å†ä½¿ç”¨æ—¶å°±åˆ é™¤ï¼Œå› æ­¤éœ€è¦å¼€å‘人员在应用程åºä¸­å¯¹å…¶è¿›è¡Œè·Ÿè¸ªã€‚
+
+ 在下例中,我们使用 QWidget 创建和显示具有默认大å°çš„窗å£ï¼š
+
+ \raw HTML
+ <table align="left" width="100%">
+ <tr class="qt-code"><td>
+ \endraw
+ \snippet tutorials/widgets/toplevel/main.cpp main program
+ \raw HTML
+ </td><td align="right">
+ \endraw
+ \inlineimage widgets-tutorial-toplevel.png
+ \raw HTML
+ </td></tr>
+ </table>
+ \endraw
+
+ 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.
+*/
+
+/*!
+ \page widgets-tutorial-childwidget.html
+ \contentspage {Widgets 教程}{目录}
+ \previouspage {Widgets 教程 — 创建窗å£}
+ \nextpage {Widgets 教程 — 使用布局}
+ \example tutorials/widgets/childwidget
+ \title Widgets 教程 — Child Widgets
+
+ 我们å¯ä»¥é€šè¿‡å°† \c window 作为父级传递给其构造器æ¥å‘窗å£æ·»åŠ å­ widget。在这ç§æƒ…况下,我们å‘窗å£æ·»åŠ æŒ‰é’®å¹¶å°†å…¶æ”¾ç½®åœ¨ç‰¹å®šä½ç½®ï¼š
+
+ \raw HTML
+ <table align="left" width="100%">
+ <tr class="qt-code"><td>
+ \endraw
+ \snippet tutorials/widgets/childwidget/main.cpp main program
+ \raw HTML
+ </td><td align="right">
+ \endraw
+ \inlineimage widgets-tutorial-childwidget.png
+ \raw HTML
+ </td></tr>
+ </table>
+ \endraw
+
+ 该按钮现在为窗å£çš„å­é¡¹ï¼Œå¹¶åœ¨åˆ é™¤çª—å£æ—¶ä¸€åŒåˆ é™¤ã€‚请注æ„,éšè—或关闭窗å£ä¸ä¼šè‡ªåŠ¨åˆ é™¤è¯¥æŒ‰é’®ã€‚
+*/
+
+/*!
+ \page widgets-tutorial-windowlayout.html
+ \contentspage {Widgets 教程}{目录}
+ \previouspage {Widgets 教程 — Child Widgets}
+ \nextpage {Widgets 教程 — Nested Layouts}
+ \example tutorials/widgets/windowlayout
+ \title Widgets 教程 — 使用布局
+
+ é€šå¸¸ï¼Œå­ widget 是通过使用布局对象在窗å£ä¸­è¿›è¡ŒæŽ’列,而ä¸æ˜¯é€šè¿‡æŒ‡å®šä½ç½®å’Œå¤§å°è¿›è¡ŒæŽ’列。在此处,我们构造è¦å¹¶æŽ’排列的标签和行编辑框 widget。
+
+ \raw HTML
+ <table align="left" width="100%">
+ <tr class="qt-code"><td>
+ \endraw
+ \snippet tutorials/widgets/windowlayout/main.cpp main program
+ \raw HTML
+ </td><td align="right">
+ \endraw
+ \inlineimage widgets-tutorial-windowlayout.png
+ \raw HTML
+ </td></tr>
+ </table>
+ \endraw
+
+ 我们构造的布局对象管ç†é€šè¿‡ \l{QHBoxLayout::}{addWidget()} 函数æ供的 widget çš„ä½ç½®å’Œå¤§å°ã€‚布局本身是通过调用 \l{QWidget::}{setLayout()} æ供给窗å£çš„。布局仅å¯é€šè¿‡å…¶å¯¹æ‰€ç®¡ç†çš„ widget(和其他布局)的效果æ‰å¯æ˜¾ç¤ºã€‚
+
+ 在上文示例中,æ¯ä¸ª widget 的所属关系并ä¸æ˜Žæ˜¾ã€‚由于我们未使用父级对象构造 widget 和布局,我们会看到一个空窗å£å’Œä¸¤ä¸ªåŒ…å«äº†æ ‡ç­¾ä¸Žè¡Œç¼–辑框的窗å£ã€‚ä¸è¿‡ï¼Œå¦‚果我们告知布局æ¥ç®¡ç†æ ‡ç­¾å’Œè¡Œç¼–辑框,并在窗å£ä¸­è®¾ç½®å¸ƒå±€ï¼Œä¸¤ä¸ª widget 与布局本身就都会æˆä¸ºçª—å£çš„å­é¡¹ã€‚
+*/
+
+/*!
+ \page widgets-tutorial-nestedlayouts.html
+ \contentspage {Widgets 教程}{目录}
+ \previouspage {Widgets 教程 — 使用布局}
+ \example tutorials/widgets/nestedlayouts
+ \title Widgets 教程 — Nested Layouts
+
+ 由于 widget å¯åŒ…å«å…¶ä»– widget,布局å¯ç”¨æ¥æ供按ä¸åŒå±‚次分组的 widget。这里,我们è¦åœ¨æ˜¾ç¤ºæŸ¥è¯¢ç»“果的表视图上方ã€çª—å£é¡¶éƒ¨çš„行编辑框æ—,显示一个标签。
+
+ 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.
+
+ \raw HTML
+ <table align="left" width="100%">
+ <tr class="qt-code"><td>
+ \endraw
+ \snippet tutorials/widgets/nestedlayouts/main.cpp first part
+ \snippet tutorials/widgets/nestedlayouts/main.cpp last part
+ \raw HTML
+ </td><td align="right">
+ \endraw
+ \inlineimage widgets-tutorial-nestedlayouts.png
+ \raw HTML
+ </td></tr>
+ </table>
+ \endraw
+
+ 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.
+
+ 除了 QHBoxLayout å’Œ QVBoxLayout,Qt 还æ供了 QGridLayout å’Œ QFormLayout ç±»æ¥å助实现更å¤æ‚的用户界é¢ã€‚
+ 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.
+*/
diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp
index f62ec24..acb1576 100644
--- a/tools/qdoc3/config.cpp
+++ b/tools/qdoc3/config.cpp
@@ -671,7 +671,9 @@ void Config::load(Location location, const QString& fileName)
location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString()));
}
- QString text = fin.readAll();
+ QTextStream stream(&fin);
+ stream.setCodec("UTF-8");
+ QString text = stream.readAll();
text += QLatin1String("\n\n");
text += QChar('\0');
fin.close();
diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h
index 5e7e6f1..6f23469 100644
--- a/tools/qdoc3/config.h
+++ b/tools/qdoc3/config.h
@@ -140,8 +140,10 @@ class Config
#define CONFIG_INDEXES "indexes"
#define CONFIG_LANGUAGE "language"
#define CONFIG_MACRO "macro"
+#define CONFIG_NATURALLANGUAGE "naturallanguage"
#define CONFIG_OBSOLETELINKS "obsoletelinks"
#define CONFIG_OUTPUTDIR "outputdir"
+#define CONFIG_OUTPUTENCODING "outputencoding"
#define CONFIG_OUTPUTLANGUAGE "outputlanguage"
#define CONFIG_OUTPUTFORMATS "outputformats"
#define CONFIG_PROJECT "project"
@@ -150,6 +152,7 @@ class Config
#define CONFIG_SLOW "slow"
#define CONFIG_SHOWINTERNAL "showinternal"
#define CONFIG_SOURCEDIRS "sourcedirs"
+#define CONFIG_SOURCEENCODING "sourceencoding"
#define CONFIG_SOURCES "sources"
#define CONFIG_SPURIOUS "spurious"
#define CONFIG_STYLESHEETS "stylesheets"
diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp
index 7d08c77..c8655a4 100644
--- a/tools/qdoc3/cppcodeparser.cpp
+++ b/tools/qdoc3/cppcodeparser.cpp
@@ -281,8 +281,8 @@ void CppCodeParser::parseHeaderFile(const Location& location,
const QString& filePath,
Tree *tree)
{
- FILE *in = fopen(QFile::encodeName(filePath), "r");
- if (!in) {
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
location.error(tr("Cannot open C++ header file '%1'").arg(filePath));
return;
}
@@ -295,7 +295,7 @@ void CppCodeParser::parseHeaderFile(const Location& location,
matchDeclList(tree->root());
if (!fileTokenizer.version().isEmpty())
tree->setVersion(fileTokenizer.version());
- fclose(in);
+ in.close();
if (fileLocation.fileName() == "qiterator.h")
parseQiteratorDotH(location, filePath);
@@ -312,8 +312,8 @@ void CppCodeParser::parseSourceFile(const Location& location,
const QString& filePath,
Tree *tree)
{
- FILE *in = fopen(QFile::encodeName(filePath), "r");
- if (!in) {
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno)));
return;
}
@@ -325,7 +325,7 @@ void CppCodeParser::parseSourceFile(const Location& location,
readToken();
usedNamespaces.clear();
matchDocsAndStuff();
- fclose(in);
+ in.close();
}
/*!
diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp
index 17a6efd..ad4cdde 100644
--- a/tools/qdoc3/doc.cpp
+++ b/tools/qdoc3/doc.cpp
@@ -3056,7 +3056,8 @@ QString Doc::canonicalTitle(const QString &title)
slurping = true;
}
else {
- // !alnum && slurping -> nothin
+ result += title[i];
+ lastAlnum = result.size();
}
}
result.truncate(lastAlnum);
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp
index 15386f1..15afd7d 100644
--- a/tools/qdoc3/htmlgenerator.cpp
+++ b/tools/qdoc3/htmlgenerator.cpp
@@ -54,6 +54,7 @@
#include <qdebug.h>
#include <qlist.h>
#include <qiterator.h>
+#include <qtextcodec.h>
QT_BEGIN_NAMESPACE
@@ -266,6 +267,15 @@ void HtmlGenerator::initializeGenerator(const Config &config)
projectUrl = config.getString(CONFIG_URL);
+ outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
+ if (outputEncoding.isEmpty())
+ outputEncoding = QLatin1String("ISO-8859-1");
+ outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
+
+ naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE);
+ if (naturalLanguage.isEmpty())
+ naturalLanguage = QLatin1String("en");
+
QSet<QString> editionNames = config.subVars(CONFIG_EDITION);
QSet<QString>::ConstIterator edition = editionNames.begin();
while (edition != editionNames.end()) {
@@ -431,11 +441,11 @@ int HtmlGenerator::generateAtom(const Atom *atom,
endLink();
}
else {
- out() << protect(atom->string());
+ out() << protectEnc(atom->string());
}
}
else {
- out() << protect(atom->string());
+ out() << protectEnc(atom->string());
}
break;
case Atom::BaseName:
@@ -483,7 +493,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
case Atom::C:
out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE];
if (inLink) {
- out() << protect(plainCode(atom->string()));
+ out() << protectEnc(plainCode(atom->string()));
}
else {
out() << highlightedCode(atom->string(), marker, relative);
@@ -516,7 +526,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
// fallthrough
case Atom::CodeBad:
out() << "<pre><font color=\"#404040\">"
- << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string()))))
+ << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))))
<< "</font></pre>\n";
break;
case Atom::FootnoteLeft:
@@ -768,7 +778,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
out() << "<a name=\""
<< Doc::canonicalTitle((*s).name)
<< "\"></a>\n";
- out() << "<h3>" << protect((*s).name) << "</h3>\n";
+ out() << "<h3>" << protectEnc((*s).name) << "</h3>\n";
if (idx == Class)
generateCompactList(0, marker, ncmap.value(), QString("Q"));
else if (idx == MemberFunction) {
@@ -792,7 +802,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
<< linkForNode(pmap.key(), 0)
<< "\">";
QStringList pieces = fullName(pmap.key(), 0, marker).split("::");
- out() << protect(pieces.last());
+ out() << protectEnc(pieces.last());
out() << "</a>" << ":</p>\n";
generateSection(nlist, 0, marker, CodeMarker::Summary);
@@ -820,12 +830,12 @@ int HtmlGenerator::generateAtom(const Atom *atom,
out() << "<p align=\"center\">";
if (fileName.isEmpty()) {
out() << "<font color=\"red\">[Missing image "
- << protect(atom->string()) << "]</font>";
+ << protectEnc(atom->string()) << "]</font>";
}
else {
- out() << "<img src=\"" << protect(fileName) << "\"";
+ out() << "<img src=\"" << protectEnc(fileName) << "\"";
if (!text.isEmpty())
- out() << " alt=\"" << protect(text) << "\"";
+ out() << " alt=\"" << protectEnc(text) << "\"";
out() << " />";
helpProjectWriter->addExtraFile(fileName);
}
@@ -923,7 +933,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
// ### Trenton
out() << "<tr><td valign=\"top\"><tt>"
- << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(),
+ << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),
relative)))
<< "</tt></td><td align=\"center\" valign=\"top\">";
@@ -936,7 +946,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
if (itemValue.isEmpty())
out() << "?";
else
- out() << "<tt>" << protect(itemValue) << "</tt>";
+ out() << "<tt>" << protectEnc(itemValue) << "</tt>";
skipAhead = 1;
}
@@ -1052,7 +1062,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
generateLink(atom, relative, marker);
}
else {
- out() << protect(atom->string());
+ out() << protectEnc(atom->string());
}
break;
case Atom::TableLeft:
@@ -1166,7 +1176,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
out() << "<font color=\"red\"><b>&lt;Missing HTML&gt;</b></font>";
break;
case Atom::UnknownCommand:
- out() << "<font color=\"red\"><b><code>\\" << protect(atom->string())
+ out() << "<font color=\"red\"><b><code>\\" << protectEnc(atom->string())
<< "</code></b></font>";
break;
#ifdef QDOC_QML
@@ -1295,7 +1305,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
out() << "<a name=\""
<< registerRef((*s).name.toLower())
<< "\"></a>\n";
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateSection(s->members, inner, marker, CodeMarker::Summary);
}
if (!s->reimpMembers.isEmpty()) {
@@ -1304,7 +1314,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
out() << "<a name=\""
<< registerRef(name.toLower())
<< "\"></a>\n";
- out() << "<h2>" << protect(name) << "</h2>\n";
+ out() << "<h2>" << protectEnc(name) << "</h2>\n";
generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
}
@@ -1343,7 +1353,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
s = sections.begin();
while (s != sections.end()) {
out() << "<hr />\n";
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.begin();
while (m != (*s).members.end()) {
@@ -1518,7 +1528,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
s = sections.begin();
while (s != sections.end()) {
out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n";
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateQmlSummary(*s,fake,marker);
++s;
}
@@ -1534,7 +1544,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
s = sections.begin();
while (s != sections.end()) {
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.begin();
while (m != (*s).members.end()) {
generateDetailedQmlMember(*m, fake, marker);
@@ -1554,7 +1564,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
s = sections.begin();
while (s != sections.end()) {
out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n";
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateSectionList(*s, fake, marker, CodeMarker::Summary);
++s;
}
@@ -1583,7 +1593,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
s = sections.begin();
while (s != sections.end()) {
out() << "<hr />\n";
- out() << "<h2>" << protect((*s).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.begin();
while (m != (*s).members.end()) {
@@ -1629,11 +1639,11 @@ void HtmlGenerator::generateHeader(const QString& title,
CodeMarker *marker,
bool mainPage)
{
- out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
+ out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding);
out() << "<!DOCTYPE html\n"
- " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n";
+ " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n";
+ out() << QString("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%1\" lang=\"%1\">\n").arg(naturalLanguage);
QString shortVersion;
if ((project != "Qtopia") && (project != "Qt Extended")) {
@@ -1653,7 +1663,9 @@ void HtmlGenerator::generateHeader(const QString& title,
}
out() << "<head>\n"
- " <title>" << shortVersion << protect(title) << "</title>\n";
+ " <title>" << shortVersion << protectEnc(title) << "</title>\n";
+ out() << QString("<meta http-equiv=\"Content-type\" content=\"text/html; charset=%1\" />").arg(outputEncoding);
+
if (!style.isEmpty())
out() << " <style type=\"text/css\">" << style << "</style>\n";
@@ -1662,8 +1674,8 @@ void HtmlGenerator::generateHeader(const QString& title,
QMapIterator<QString, QString> i(metaMap);
while (i.hasNext()) {
i.next();
- out() << " <meta name=\"" << protect(i.key()) << "\" contents=\""
- << protect(i.value()) << "\" />\n";
+ out() << " <meta name=\"" << protectEnc(i.key()) << "\" contents=\""
+ << protectEnc(i.value()) << "\" />\n";
}
}
@@ -1687,9 +1699,9 @@ void HtmlGenerator::generateHeader(const QString& title,
navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">";
if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
- navigationLinks += protect(anchorPair.second);
+ navigationLinks += protectEnc(anchorPair.second);
else
- navigationLinks += protect(linkPair.second);
+ navigationLinks += protectEnc(linkPair.second);
navigationLinks += "</a>]\n";
}
if (node->links().contains(Node::ContentsLink)) {
@@ -1705,9 +1717,9 @@ void HtmlGenerator::generateHeader(const QString& title,
navigationLinks += "[<a href=\"" + anchorPair.first + "\">";
if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
- navigationLinks += protect(anchorPair.second);
+ navigationLinks += protectEnc(anchorPair.second);
else
- navigationLinks += protect(linkPair.second);
+ navigationLinks += protectEnc(linkPair.second);
navigationLinks += "</a>]\n";
}
if (node->links().contains(Node::NextLink)) {
@@ -1723,9 +1735,9 @@ void HtmlGenerator::generateHeader(const QString& title,
navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">";
if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
- navigationLinks += protect(anchorPair.second);
+ navigationLinks += protectEnc(anchorPair.second);
else
- navigationLinks += protect(linkPair.second);
+ navigationLinks += protectEnc(linkPair.second);
navigationLinks += "</a>]\n";
}
if (node->links().contains(Node::IndexLink)) {
@@ -1776,7 +1788,7 @@ void HtmlGenerator::generateTitle(const QString& title,
const Node *relative,
CodeMarker *marker)
{
- out() << "<h1 class=\"title\">" << protect(title);
+ out() << "<h1 class=\"title\">" << protectEnc(title);
if (!subTitle.isEmpty()) {
out() << "<br />";
if (subTitleSize == SmallSubTitle)
@@ -2014,18 +2026,18 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
out() << "<p><ul><li><a href=\""
<< linkForNode(inner, 0) << "\">"
- << protect(inner->name())
+ << protectEnc(inner->name())
<< " class reference</a></li></ul></p>\n";
for (i = 0; i < sections.size(); ++i) {
- out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
}
sections = marker->sections(inner, CodeMarker::Detailed, status);
for (i = 0; i < sections.size(); ++i) {
out() << "<hr />\n";
- out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n";
+ out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
NodeList::ConstIterator m = sections.at(i).members.begin();
while (m != sections.at(i).members.end()) {
@@ -2118,7 +2130,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative,
}
else {
out() << "<td>";
- out() << protect(node->doc().briefText().toString());
+ out() << protectEnc(node->doc().briefText().toString());
out() << "</td>";
}
out() << "</tr>\n";
@@ -2320,7 +2332,7 @@ void HtmlGenerator::generateCompactList(const Node *relative,
<< linkForNode(it.value(), relative)
<< "\">";
QStringList pieces = fullName(it.value(), relative, marker).split("::");
- out() << protect(pieces.last());
+ out() << protectEnc(pieces.last());
out() << "</a>";
if (pieces.size() > 1) {
out() << " (";
@@ -2362,7 +2374,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative,
#else
out() << "<p>";
#endif
- out() << protect(f.key()) << ":";
+ out() << protectEnc(f.key()) << ":";
currentLetter = f.key()[0].unicode();
while (islower(currentLetter) && currentLetter >= nextLetter) {
@@ -2416,7 +2428,7 @@ void HtmlGenerator::generateLegaleseList(const Node *relative,
QString marked = marker->markedUpSynopsis(node, relative, style);
QRegExp templateTag("(<[^@>]*>)");
if (marked.indexOf(templateTag) != -1) {
- QString contents = protect(marked.mid(templateTag.pos(1),
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
templateTag.cap(1).length()));
marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
contents);
@@ -2455,7 +2467,7 @@ void HtmlGenerator::generateQmlItem(const Node *node,
QString marked = marker->markedUpQmlItem(node,summary);
QRegExp templateTag("(<[^@>]*>)");
if (marked.indexOf(templateTag) != -1) {
- QString contents = protect(marked.mid(templateTag.pos(1),
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
templateTag.cap(1).length()));
marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
contents);
@@ -2561,7 +2573,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
const FakeNode *groupNode = groupTitlesMap[groupTitle];
out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg(
linkForNode(groupNode, relative)).arg(
- protect(groupNode->fullTitle()));
+ protectEnc(groupNode->fullTitle()));
if (fakeNodeMap[groupNode].count() == 0)
continue;
@@ -2573,7 +2585,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
if (title.startsWith("The "))
title.remove(0, 4);
out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"
- << protect(title) << "</a></li>\n";
+ << protectEnc(title) << "</a></li>\n";
}
out() << "</ul>\n";
}
@@ -2587,7 +2599,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
if (title.startsWith("The "))
title.remove(0, 4);
out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"
- << protect(title) << "</a></li>\n";
+ << protectEnc(title) << "</a></li>\n";
}
out() << "</ul>\n";
}
@@ -2750,7 +2762,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section,
}
out() << " inherited from <a href=\"" << fileName((*p).first)
<< "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">"
- << protect(marker->plainFullName((*p).first, relative))
+ << protectEnc(marker->plainFullName((*p).first, relative))
<< "</a></li>\n";
++p;
}
@@ -2765,7 +2777,7 @@ void HtmlGenerator::generateSynopsis(const Node *node,
QString marked = marker->markedUpSynopsis(node, relative, style);
QRegExp templateTag("(<[^@>]*>)");
if (marked.indexOf(templateTag) != -1) {
- QString contents = protect(marked.mid(templateTag.pos(1),
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
templateTag.cap(1).length()));
marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
contents);
@@ -3034,7 +3046,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section,
}
out() << " inherited from <a href=\"" << fileName((*p).first)
<< "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">"
- << protect(marker->plainFullName((*p).first, relative))
+ << protectEnc(marker->plainFullName((*p).first, relative))
<< "</a></li>\n";
++p;
}
@@ -3048,7 +3060,7 @@ void HtmlGenerator::generateSynopsis(const Node *node,
QString marked = marker->markedUpSynopsis(node, relative, style);
QRegExp templateTag("(<[^@>]*>)");
if (marked.indexOf(templateTag) != -1) {
- QString contents = protect(marked.mid(templateTag.pos(1),
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
templateTag.cap(1).length()));
marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
contents);
@@ -3246,7 +3258,7 @@ void HtmlGenerator::generateLink(const Atom* atom,
if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {
// hack for C++: move () outside of link
int k = funcLeftParen.pos(1);
- out() << protect(atom->string().left(k));
+ out() << protectEnc(atom->string().left(k));
if (link.isEmpty()) {
if (showBrokenLinks)
out() << "</i>";
@@ -3254,7 +3266,7 @@ void HtmlGenerator::generateLink(const Atom* atom,
out() << "</a>";
}
inLink = false;
- out() << protect(atom->string().mid(k));
+ out() << protectEnc(atom->string().mid(k));
} else if (marker->recognizeLanguage("Java")) {
// hack for Java: remove () and use <tt> when appropriate
bool func = atom->string().endsWith("()");
@@ -3262,13 +3274,13 @@ void HtmlGenerator::generateLink(const Atom* atom,
if (tt)
out() << "<tt>";
if (func) {
- out() << protect(atom->string().left(atom->string().length() - 2));
+ out() << protectEnc(atom->string().left(atom->string().length() - 2));
} else {
- out() << protect(atom->string());
+ out() << protectEnc(atom->string());
}
out() << "</tt>";
} else {
- out() << protect(atom->string());
+ out() << protectEnc(atom->string());
}
}
@@ -3342,7 +3354,12 @@ QString HtmlGenerator::registerRef(const QString& ref)
return clean;
}
-QString HtmlGenerator::protect(const QString& string)
+QString HtmlGenerator::protectEnc(const QString &string)
+{
+ return protect(string, outputEncoding);
+}
+
+QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding)
{
#define APPEND(x) \
if (html.isEmpty()) { \
@@ -3365,7 +3382,7 @@ QString HtmlGenerator::protect(const QString& string)
APPEND("&gt;");
} else if (ch == QLatin1Char('"')) {
APPEND("&quot;");
- } else if (ch.unicode() > 0x007F
+ } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F)
|| (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))
|| (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
// we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
@@ -3495,7 +3512,7 @@ QString HtmlGenerator::refForNode(const Node *node)
ref = node->name() + "-var";
break;
case Node::Target:
- return protect(node->name());
+ return protectEnc(node->name());
}
return registerRef(ref);
}
@@ -3569,7 +3586,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode,
}
}
out() << "\">";
- out() << protect(fullName(apparentNode, relative, marker));
+ out() << protectEnc(fullName(apparentNode, relative, marker));
out() << "</a>";
}
@@ -3630,12 +3647,12 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
else if (node->type() == Node::Enum) {
const EnumNode *enume = static_cast<const EnumNode *>(node);
if (enume->flagsType()) {
- out() << "<p>The " << protect(enume->flagsType()->name())
+ out() << "<p>The " << protectEnc(enume->flagsType()->name())
<< " type is a typedef for "
<< "<a href=\"qflags.html\">QFlags</a>&lt;"
- << protect(enume->name())
+ << protectEnc(enume->name())
<< "&gt;. It stores an OR combination of "
- << protect(enume->name())
+ << protectEnc(enume->name())
<< " values.</p>\n";
}
}
diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h
index 19a7c78..5ed26e0 100644
--- a/tools/qdoc3/htmlgenerator.h
+++ b/tools/qdoc3/htmlgenerator.h
@@ -104,7 +104,8 @@ class HtmlGenerator : public PageGenerator
virtual QString format();
virtual void generateTree(const Tree *tree, CodeMarker *marker);
- static QString protect(const QString& string);
+ QString protectEnc(const QString &string);
+ static QString protect(const QString &string, const QString &encoding = "ISO-8859-1");
static QString cleanRef(const QString& ref);
static QString sinceTitle(int i) { return sinceTitles[i]; }
diff --git a/tools/qdoc3/linguistgenerator.cpp b/tools/qdoc3/linguistgenerator.cpp
index d1bd22d..21678e0 100644
--- a/tools/qdoc3/linguistgenerator.cpp
+++ b/tools/qdoc3/linguistgenerator.cpp
@@ -89,7 +89,7 @@ QString LinguistGenerator::fileExtension(const Node * /* node */)
void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker *marker)
{
- out().setCodec("utf-8");
+ out().setCodec("UTF-8");
QDomDocument document("TS");
QDomElement documentElement = document.createElement("TS");
@@ -100,7 +100,7 @@ void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker
documentElement.appendChild(element);
QDomProcessingInstruction process = document.createProcessingInstruction(
- "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("utf-8"));
+ "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("UTF-8"));
document.appendChild(process);
document.appendChild(documentElement);
diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp
index 07edcc4..bc73eb0 100644
--- a/tools/qdoc3/pagegenerator.cpp
+++ b/tools/qdoc3/pagegenerator.cpp
@@ -177,7 +177,7 @@ void PageGenerator::beginSubPage(const Location& location,
location.fatal(tr("Cannot open output file '%1'")
.arg(outFile->fileName()));
QTextStream *out = new QTextStream(outFile);
- out->setCodec("ISO-8859-1");
+ out->setCodec(outputCodec);
outStreamStack.push(out);
}
diff --git a/tools/qdoc3/pagegenerator.h b/tools/qdoc3/pagegenerator.h
index db24edd..20a6c3c 100644
--- a/tools/qdoc3/pagegenerator.h
+++ b/tools/qdoc3/pagegenerator.h
@@ -54,6 +54,8 @@
QT_BEGIN_NAMESPACE
+class QTextCodec;
+
class ClassNode;
class InnerNode;
class NamespaceNode;
@@ -76,6 +78,10 @@ class PageGenerator : public Generator
virtual void generateInnerNode(const InnerNode *node, CodeMarker *marker);
QTextStream& out();
+ QString naturalLanguage;
+ QString outputEncoding;
+ QTextCodec *outputCodec;
+
private:
QStack<QTextStream *> outStreamStack;
};
diff --git a/tools/qdoc3/qsakernelparser.cpp b/tools/qdoc3/qsakernelparser.cpp
index 9320a17..8f12eda 100644
--- a/tools/qdoc3/qsakernelparser.cpp
+++ b/tools/qdoc3/qsakernelparser.cpp
@@ -70,8 +70,8 @@ void QsaKernelParser::parseSourceFile( const Location& location,
const QString& filePath,
Tree * /* tree */ )
{
- FILE *in = fopen( QFile::encodeName(filePath), "r" );
- if ( in == 0 ) {
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
location.error( tr("Cannot open QSA kernel file '%1'").arg(filePath) );
return;
}
@@ -171,7 +171,7 @@ void QsaKernelParser::parseSourceFile( const Location& location,
readToken();
}
}
- fclose( in );
+ in.close();
}
void QsaKernelParser::doneParsingSourceFiles( Tree * /* tree */ )
diff --git a/tools/qdoc3/qscodeparser.cpp b/tools/qdoc3/qscodeparser.cpp
index 8b3bc98..3b8bc1a 100644
--- a/tools/qdoc3/qscodeparser.cpp
+++ b/tools/qdoc3/qscodeparser.cpp
@@ -151,8 +151,8 @@ void QsCodeParser::parseHeaderFile(const Location& location,
{
qsTre = tree;
- FILE *in = fopen(QFile::encodeName(filePath), "r");
- if (in == 0) {
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
location.error(tr("Cannot open Qt Script class list '%1'")
.arg(filePath));
return;
@@ -175,7 +175,7 @@ void QsCodeParser::parseHeaderFile(const Location& location,
}
tok = fileTokenizer.getToken();
}
- fclose(in);
+ in.close();
}
void QsCodeParser::parseSourceFile(const Location& location,
diff --git a/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf
new file mode 100644
index 0000000..c722ee8
--- /dev/null
+++ b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf
@@ -0,0 +1,30 @@
+include(qt-build-docs_zh_CN.qdocconf)
+
+# Ensures that the generated index contains a URL that can be used by the
+# tools documentation (assistant.qdocconf, designer.qdocconf, linguist.qdocconf,
+# qmake.qdocconf).
+
+url = ./
+
+# Ensures that the documentation for the tools is not included in the generated
+# .qhp file.
+
+qhp.Qt.excluded += $QT_SOURCE_TREE/doc/src/development/assistant-manual.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/simpletextviewer.qdoc \
+ $QT_SOURCE_TREE/doc/src/development/designer-manual.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/calculatorbuilder.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/calculatorform.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/customwidgetplugin.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/taskmenuextension.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/containerextension.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/worldtimeclockbuilder.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/worldtimeclockplugin.qdoc \
+ $QT_SOURCE_TREE/doc/src/internationalization/linguist-manual.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/hellotr.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/arrowpad.qdoc \
+ $QT_SOURCE_TREE/doc/src/examples/trollprint.qdoc \
+ $QT_SOURCE_TREE/doc/src/development/qmake-manual.qdoc
+
+outputdir = $QT_BUILD_TREE/doc-build/html-qt_zh_CN
+tagfile = $QT_BUILD_TREE/doc-build/html-qt_zh_CN/qt.tags
+base = file:$QT_BUILD_TREE/doc-build/html-qt_zh_CN
diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf
index e8595f6..4f1ae5d 100644
--- a/tools/qdoc3/test/qt-build-docs.qdocconf
+++ b/tools/qdoc3/test/qt-build-docs.qdocconf
@@ -8,9 +8,13 @@ project = Qt
description = Qt Reference Documentation
url = http://qt.nokia.com/doc/4.7
-edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \
- QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \
- QtDesigner QtAssistant QAxContainer Phonon \
+sourceencoding = UTF-8
+outputencoding = UTF-8
+naturallanguage = en_US
+
+edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \
+ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \
+ Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \
QAxServer QtUiTools QtTest QtDBus
edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest
@@ -90,11 +94,13 @@ excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \
$QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \
$QT_SOURCE_TREE/src/3rdparty/wintab \
$QT_SOURCE_TREE/src/3rdparty/zlib \
- $QT_SOURCE_TREE/doc/src/snippets \
$QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \
$QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \
$QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \
- $QT_SOURCE_TREE/src/3rdparty/phonon/waveout
+ $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/waveout \
+ $QT_SOURCE_TREE/doc/src/snippets \
+ $QT_SOURCE_TREE/doc/src/zh_CN
sources.fileextensions = "*.cpp *.qdoc *.mm"
examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp"
diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf
new file mode 100644
index 0000000..18b72a1
--- /dev/null
+++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf
@@ -0,0 +1,92 @@
+include(compat.qdocconf)
+include(macros.qdocconf)
+include(qt-cpp-ignore.qdocconf)
+include(qt-html-templates_zh_CN.qdocconf)
+include(qt-defines.qdocconf)
+
+project = Qt
+description = Qt Reference Documentation
+url = http://qt.nokia.com/doc/zh_CN/4.7
+
+sourceencoding = UTF-8
+outputencoding = UTF-8
+naturallanguage = zh-Hans
+
+indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index
+
+edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \
+ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \
+ Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \
+ QAxServer QtUiTools QtTest QtDBus
+
+edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest
+edition.DesktopLight.groups = -graphicsview-api
+
+qhp.projects = Qt
+
+qhp.Qt.file = qt.qhp
+qhp.Qt.namespace = com.trolltech.qt.470
+qhp.Qt.virtualFolder = qdoc
+qhp.Qt.title = 教程
+qhp.Qt.indexTitle = 教程
+qhp.Qt.selectors = fake:example
+
+qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN
+qhp.Qt.customFilters.Qt.name = Qt 4.7.0
+qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0
+
+# Files not referenced in any qdoc file (last four are needed by qtdemo)
+# See also extraimages.HTML
+qhp.Qt.extraFiles = classic.css \
+ images/qt-logo.png \
+ images/taskmenuextension-example.png \
+ images/coloreditorfactoryimage.png \
+ images/dynamiclayouts-example.png \
+ images/stylesheet-coffee-plastique.png
+
+language = Cpp
+
+sourcedirs = $QT_SOURCE_TREE/doc/src/zh_CN
+
+excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \
+ $QT_SOURCE_TREE/src/3rdparty/des \
+ $QT_SOURCE_TREE/src/3rdparty/freetype \
+ $QT_SOURCE_TREE/src/3rdparty/harfbuzz \
+ $QT_SOURCE_TREE/src/3rdparty/kdebase \
+ $QT_SOURCE_TREE/src/3rdparty/libjpeg \
+ $QT_SOURCE_TREE/src/3rdparty/libmng \
+ $QT_SOURCE_TREE/src/3rdparty/libpng \
+ $QT_SOURCE_TREE/src/3rdparty/libtiff \
+ $QT_SOURCE_TREE/src/3rdparty/md4 \
+ $QT_SOURCE_TREE/src/3rdparty/md5 \
+ $QT_SOURCE_TREE/src/3rdparty/patches \
+ $QT_SOURCE_TREE/src/3rdparty/sha1 \
+ $QT_SOURCE_TREE/src/3rdparty/sqlite \
+ $QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore \
+ $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \
+ $QT_SOURCE_TREE/src/3rdparty/wintab \
+ $QT_SOURCE_TREE/src/3rdparty/zlib \
+ $QT_SOURCE_TREE/doc/src/snippets \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \
+ $QT_SOURCE_TREE/src/3rdparty/phonon/waveout
+
+sources.fileextensions = "*.cpp *.qdoc *.mm"
+examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp"
+examples.imageextensions = "*.png"
+
+exampledirs = $QT_SOURCE_TREE/doc/src \
+ $QT_SOURCE_TREE/examples \
+ $QT_SOURCE_TREE/examples/tutorials \
+ $QT_SOURCE_TREE \
+ $QT_SOURCE_TREE/qmake/examples \
+ $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs
+imagedirs = $QT_SOURCE_TREE/doc/src/images \
+ $QT_SOURCE_TREE/examples
+outputdir = $QT_BUILD_TREE/doc/html_zh_CN
+tagfile = $QT_BUILD_TREE/doc/html_zh_CN/qt.tags
+base = file:$QT_BUILD_TREE/doc/html_zh_CN
+
+HTML.generatemacrefs = "true"
diff --git a/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf
new file mode 100644
index 0000000..5fb68cf
--- /dev/null
+++ b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf
@@ -0,0 +1,25 @@
+HTML.stylesheets = classic.css
+HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \
+ "<tr>\n" \
+ "<td align=\"left\" valign=\"top\" width=\"32\">" \
+ "<a href=\"http://qt.nokia.com/\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \
+ "</td>\n" \
+ "<td width=\"1\">&nbsp;&nbsp;</td>" \
+ "<td class=\"postheader\" valign=\"center\">" \
+ "<a href=\"http://qt.nokia.com/doc/4.7/index.html\">" \
+ "<font color=\"#004faf\">主页</font></a>&nbsp;&middot;" \
+ " <a href=\"http://qt.nokia.com/doc/4.7/classes.html\">" \
+ "<font color=\"#004faf\">所有类</font></a>&nbsp;&middot;" \
+ " <a href=\"http://qt.nokia.com/doc/4.7/functions.html\">" \
+ "<font color=\"#004faf\">所有函数</font></a>&nbsp;&middot;" \
+ " <a href=\"http://qt.nokia.com/doc/4.7/overviews.html\">" \
+ "<font color=\"#004faf\">简介</font></a>" \
+ "</td>" \
+ "</tr></table>"
+
+HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
+ "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
+ "<td width=\"40%\" align=\"left\">版æƒæ‰€æœ‰ &copy; 2010 诺基亚公å¸å’Œ/或其å­å…¬å¸</td>\n" \
+ "<td width=\"20%\" align=\"center\"><a href=\"trademarks.html\">商标</a></td>\n" \
+ "<td width=\"40%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \
+ "</tr></table></div></address>"
diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf
index a066021..1039c18 100644
--- a/tools/qdoc3/test/qt.qdocconf
+++ b/tools/qdoc3/test/qt.qdocconf
@@ -10,9 +10,13 @@ version = %VERSION%
description = Qt Reference Documentation
url = http://qt.nokia.com/doc/4.7
+sourceencoding = UTF-8
+outputencoding = UTF-8
+naturallanguage = en_US
+
edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \
QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \
- Qt3Support QtHelp QtDesigner QAxContainer Phonon \
+ Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \
QAxServer QtUiTools QtTest QtDBus
edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest
edition.DesktopLight.groups = -graphicsview-api
@@ -91,12 +95,13 @@ excludedirs = $QTDIR/src/3rdparty/clucene \
$QTDIR/src/3rdparty/webkit/WebCore \
$QTDIR/src/3rdparty/wintab \
$QTDIR/src/3rdparty/zlib \
- $QTDIR/doc/src/snippets \
$QTDIR/src/3rdparty/phonon/gstreamer \
$QTDIR/src/3rdparty/phonon/ds9 \
$QTDIR/src/3rdparty/phonon/qt7 \
$QTDIR/src/3rdparty/phonon/mmf \
- $QTDIR/src/3rdparty/phonon/waveout
+ $QTDIR/src/3rdparty/phonon/waveout \
+ $QTDIR/doc/src/snippets \
+ $QTDIR/doc/src/zh_CN
sources.fileextensions = "*.cpp *.qdoc *.mm"
examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp"
diff --git a/tools/qdoc3/tokenizer.cpp b/tools/qdoc3/tokenizer.cpp
index b391759..7c10de6 100644
--- a/tools/qdoc3/tokenizer.cpp
+++ b/tools/qdoc3/tokenizer.cpp
@@ -47,6 +47,7 @@
#include <qhash.h>
#include <qregexp.h>
#include <qstring.h>
+#include <qtextcodec.h>
#include <ctype.h>
#include <string.h>
@@ -97,6 +98,8 @@ static QRegExp *definedX = 0;
static QRegExp *defines = 0;
static QRegExp *falsehoods = 0;
+static QTextCodec *sourceCodec = 0;
+
/*
This function is a perfect hash function for the 37 keywords of C99
(with a hash table size of 512). It should perform well on our
@@ -118,13 +121,10 @@ static void insertKwordIntoHash(const char *s, int number)
kwordHashTable[k] = number;
}
-Tokenizer::Tokenizer(const Location& loc, FILE *in)
+Tokenizer::Tokenizer(const Location& loc, QFile &in)
{
init();
- QFile file;
- file.open(in, QIODevice::ReadOnly);
- yyIn = file.readAll();
- file.close();
+ yyIn = in.readAll();
yyPos = 0;
start(loc);
}
@@ -483,6 +483,11 @@ void Tokenizer::initialize(const Config &config)
{
QString versionSym = config.getString(CONFIG_VERSIONSYM);
+ QString sourceEncoding = config.getString(CONFIG_SOURCEENCODING);
+ if (sourceEncoding.isEmpty())
+ sourceEncoding = QLatin1String("ISO-8859-1");
+ sourceCodec = QTextCodec::codecForName(sourceEncoding.toLocal8Bit());
+
comment = new QRegExp("/(?:\\*.*\\*/|/.*\n|/[^\n]*$)");
comment->setMinimal(true);
versionX = new QRegExp("$cannot possibly match^");
@@ -750,4 +755,14 @@ bool Tokenizer::isTrue(const QString &condition)
return !falsehoods->exactMatch(t);
}
+QString Tokenizer::lexeme() const
+{
+ return sourceCodec->toUnicode(yyLex);
+}
+
+QString Tokenizer::previousLexeme() const
+{
+ return sourceCodec->toUnicode(yyPrevLex);
+}
+
QT_END_NAMESPACE
diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h
index 519cffb..f55d2ef 100644
--- a/tools/qdoc3/tokenizer.h
+++ b/tools/qdoc3/tokenizer.h
@@ -46,11 +46,10 @@
#ifndef TOKENIZER_H
#define TOKENIZER_H
+#include <qfile.h>
#include <qstack.h>
#include <qstring.h>
-#include <stdio.h>
-
#include "location.h"
QT_BEGIN_NAMESPACE
@@ -99,7 +98,7 @@ class Tokenizer
{
public:
Tokenizer(const Location& loc, const QByteArray &in);
- Tokenizer(const Location& loc, FILE *in);
+ Tokenizer(const Location& loc, QFile &file);
~Tokenizer();
@@ -108,8 +107,8 @@ class Tokenizer
bool parsingFnOrMacro() const { return parsingMacro; }
const Location &location() const { return yyTokLoc; }
- QString previousLexeme() const { return QString(yyPrevLex); }
- QString lexeme() const { return QString(yyLex); }
+ QString previousLexeme() const;
+ QString lexeme() const;
QString version() const { return yyVersion; }
int braceDepth() const { return yyBraceDepth; }
int parenDepth() const { return yyParenDepth; }