Page suivante Page précédente Table des matières
KAppWizard, l'Assistant d'Application KDE, vous aide à commencer à travailler sur de nouveaux projets avec KDevelop. Ainsi, tous vos projets seront d'abord créés par l'assistant ; ensuite, vous pourrez commencer à les construire et à étendre le squelette de code source déjà fourni. KAppWizard vous permet aussi de choisir entre plusieurs types de projets selon les objectifs de votre projet :
Dans ce chapitre, nous allons voir comment KAppWizard peut être appelé et ce qui doit être fait pour générer un projet d'application KDE. Ce sera aussi la première étape de notre tour d'horizon, où nous créerons la version initiale d'un projet d'exemple. Pour tous les types de projets, les étapes sont globalement les mêmes, certaines options pouvant juste être disponibles ou non.
Pour débuter votre première application KDE, ouvrez KDevelop. Sélectionnez ensuite "Nouveau..." dans le menu "Projet". KAppWizard démarre et vous voyez sur la première page une arborescence contenant les types de projets. Quand un type de projet est sélectionné, vous voyez un aperçu de l'apparence qu'aura l'application après le processus de construction. Choisissez le sous-arbre KDE, type Normal. Appuyez ensuite sur le bouton "Suivant" en bas de la première page de l'assistant. Cela vous mènera à la page suivante où vous devrez définir les options générales du projet.
Pour notre application exemple, nous choisissons KScribble
comme nom de projet ;
vous devez donc le saisir dans le champ "Nom du projet". Sélectionnez ensuite le dossier
où vous voulez construire votre projet ; le dossier par défaut est votre dossier
utilisateur. Vous pouvez saisir le chemin manuellement ou vous pouvez appuyer sur
le bouton à droite pour sélectionner le dossier dans une boîte de dialogue.
Ensuite, vous devez saisir le numéro de version. Pour la première version, définissez
le à 0.1
. Il est habituel de numéroter les nouvelles applications qui sont en
cours de développement avec un numéro de sortie inférieur à 1, et comme la version
initiale contiendra uniquement l'architecture standard, nous appelerons cette version 0.1.
Enfin, ajoutez votre nom dans le champ "Auteur" et votre adresse de courrier électronique. Vous pouvez laisser tels quels (valeurs par défaut) les autres paramètres.
Pour obtenir des informations sur toutes les autres options, vous pouvez faire un clic droit sur les options et vous obtiendrez une fenêtre d'aide rapide décrivant le but de cette option.
Ces options sont :
Maintenant, nous allons passer à la page suivante en appuyant à nouveau sur le bouton "Suivant" pour définir le modèle des fichiers d'en-têtes de votre projet.
La page de modèle des fichiers d'en-tête vous permet d'ajouter automatiquement, dans vos fichiers d'en-tête, un préambule contenant le nom du fichier, la date de construction, l'année du copyright ainsi que votre nom et votre adresse électronique. Vous n'avez pas à convertir ces parties en majuscule car KAppWizard le fait automatiquement et enregistre le modèle de ce projet pour l'utiliser lors de la création de nouveaux fichiers.
La seconde partie du modèle d'en-tête par défaut contient des informations sur la licence. Par défaut, votre projet est placé sous la Licence Publique Générale GNU GPL qui est aussi incluse dans le paquetage. Cette licence est utilisée pour protéger votre code source contre toute personne qui copierait seulement les sources pour son usage personnel. La Licence Publique Générale, qui vous offre cette licence gratuitement et protège vos droits en tant qu'auteur, est habituelle pour la distribution le logiciels libres. Pour obtenir plus d'informations sur cette licence, vous devriez consulter ultérieurement le fichier COPYING dans le répertoire de base de votre nouveau projet, qui est une copie de la GPL et est déjà distribué avec votre application.
Cependant, vous pouvez choisir une autre licence ou un autre modèle d'en-tête que vous utilisez déjà pour vos projets. Dans ce cas, vous pouvez éditer directement le modèle donné par défaut. Pour cela, le modèle apparaît dans une fenêtre d'édition. Pour effacer la page par défaut, sélectionnez "Nouveau" ; pour utiliser un autre modèle, choisissez "Chargement..." qui vous permet de choisir le fichier de modèle.
Quand vous avez terminé, allez à la page suivante en appuyant sur "Suivant". C'est la page de modèle pour vos fichiers sources, elles est globalement identique à la page de modèle d'en-tête. La seule différence est que ce modèle est utilisé pour vos fichiers d'implantation.
Maintenant que vous avez défini toutes les options de KScribble, sélectionnez "Suivant" et appuyez sur le bouton "Créer" au bas de la fenêtre de l'assistant. Si ce bouton n'est pas disponible, vous n'avez pas défini toutes les options correctement. Pour corriger une erreur, revenez en arrière dans l'assistant en appuyant sur "Précédent".
Ensuite, vous allez voir ce que fait KAppWizard - il copie tous les modèles dans le dossier de votre projet et crée le nouveau projet. Lorsque KAppWizard a terminé, le bouton "Annuler" se change en un bouton "Quitter" pour sortir de l'assistant. Après cette dernière étape, vous avez terminé la création d'un nouveau projet. Ensuite, KDevelop le charge et l'affichage de l'arborescence vous permet de naviguer à travers les fichiers et les classes du projet.
Dans la section suivante, nous discuterons de la construction et de l'exécution de votre première version de KScribble, ainsi que de l'organisation du code source.
Après la génération du projet, nous allons d'abord faire un petit tour dans le code source pour avoir une vision globale de la façon dont fonctionne l'architecture de l'application. Cela ne nous fera pas vraiment avancer mais il peut être utile de savoir où effectuer les modifications dans les prochaines étapes. Lorsque vous ouvrez la page LFV (Logical File Viewer) de la vue arborescente, vous voyez des dossiers qui contiennent déjà des fichiers du projet utiles au développeur. Les deux premiers dossiers sont "En-têtes" et "Sources". Évidemment, le dossier En-têtes contient tous les fichiers d'en-tête et le dossier Sources tous les codes sources. Les autres dossiers ne nous intéressent pas pour l'instant, nous y reviendrons plus tard pour voir ce qu'ils contiennent. Les deux dossiers contiennent donc les fichiers suivants :
En-têtes :
make
fait grâce aux messages qu'il donne :
1 Making all in docs
2 make[1]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs'
3 Making all in en
4 make[2]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs/en'
5 make[2]: Nothing to be done for `all'.
6 make[2]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs/en'
7 make[2]:
Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs'
8 make[2]: Nothing to be done for `all-am'.
9 make[2]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs'
10 make[1]: Leaving directory
`/home/rnolden/Tutorial/kscribble1/kscribble/docs'
11 make[1]: Entering
directory `/home/rnolden/Tutorial/kscribble1/kscribble'
12 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include
-I/usr/X11R6/include -O0 -g -Wall -c kscribbleview.cpp
13 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include
-I/usr/X11R6/include -O0 -g -Wall -c kscribbledoc.cpp
14 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include
-I/usr/X11R6/include -O0 -g -Wall -c kscribble.cpp
15 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include
-I/usr/X11R6/include -O0 -g -Wall -c main.cpp
16 /usr/bin/moc ./kscribble.h -o kscribble.moc.cpp
17 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include
-I/usr/X11R6/include -O0 -g -Wall -c kscribble.moc.cpp
18 /usr/bin/moc ./kscribbledoc.h -o kscribbledoc.moc.cpp
19 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include
-I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c
kscribbledoc.moc.cpp
20 /usr/bin/moc ./kscribbleview.h -o kscribbleview.moc.cpp
21 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include
-I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c
kscribbleview.moc.cpp
22 /bin/sh ../libtool --silent --mode=link g++ -O0
-g -Wall -o kscribble -L/opt/kde/lib -L/usr/X11R6/lib -rpath /opt/kde/lib
-rpath /usr/X11R6/lib kscribbleview.o kscribbledoc.o kscribble.o
main.o kscribble.moc.o kscribbledoc.moc.o kscribbleview.moc.o -lkfile -lkfm
-lkdeui -lkdecore -lqt -lXext -lX11
23 make[1]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble'
Comme vous le constatez, nous avons mis des numéros au début de chaque ligne qui
n'apparaissent pas dans les messages ; c'est juste pour simplifier la
description de ce qui s'est passé pendant la construction. D'abord, make
travaille récursivement. Cela signifie qu'il débute dans le dossier où il a
été appelé, entre d'abord dans les sous-dossiers, retourne et traite le
dossier suivant. À la fin, le dossier où il a été lancé est traité et
make
termine. C'est pourquoi make
est lancé dans le dossier
principal du projet qui contient les sources. Aux lignes 1 et 2, vous voyez
que le processus make
entre dans le dossier docs
, puis dans le
sous-dossier en
. Comme il n'y a rien à faire, il quitte ces dossiers
jusqu'à revenir au répertoire source kscribble
à la ligne 11. Ensuite, le
vrai travail commence : make
appele le compilateur, ici g++
, pour
compiler le fichier source kscribbleview.cpp
. La macro
-DHAVE_CONFIG_H
indique que le fichier config.h
doit être utilisé. Ce
fichier, qui contient des macros spécifiques à chaque plate-forme et à
l'application, est situé dans le dossier principal du projet. Les commandes
-I
qui suivent ajoutent un chemin vers des fichiers d'inclusion (NdT :
appelés aussi "includes") où g++
pourra trouver les "includes" dont il a
besoin. Ces chemins sont le dossier courant, le dossier principal du projet
(avec -I..
) et le chemin des includes pour les fichiers d'en-tête de KDE,
Qt et X11. Les dossiers de ces fichiers d'includes sont déterminés par
le script configure
et définis dans les Makefiles, c'est pourquoi le
compilateur sait où ils sont situés. Enfin, -O0
définit l'optimisation à
zéro (aucune optimisation), -g
active le déboguage, -Wall
définit
les avertissements du compilateur à all
et -c
dit au compilateur de
produire un fichier objet intermédiaire, c'est-à-dire seulement compiler le
fichier.
Cela est aussi fait pour les autres fichiers sources de notre
projet aux lignes 13-15. Évidemment, nos sources sont compilées mais au lieu
de lier (NdT : opération réalisée par l'éditeur de liens) les fichiers objets
intermédiaires des sources pour en faire un exécutable, nous voyons d'autres
commandes. À la ligne 16, vous voyez que le programe "moc" est appelé pour
traiter le fichier d'en-tête kscribble.h
qui génère le fichier
kscribble.moc.cpp
. Ensuite, à la ligne 17, le fichier source est aussi
compilé. La même chose se passe pour les autres fichiers d'en-tête du projet
jusqu'à la ligne 21. En fait, comme la boîte à outils Qt contient le
mécanisme signal/slot mais reste une implantation C++, vous utilisez des
mots-clés comme les déclarations signals:
et slots:
dans vos classes
qui ne sont pas, à l'origine, dans le langage C++. Cela vous permet de faire
facilement communiquer les objets qui héritent de la classe QObject
,
évitant ainsi l'utilisation des traditionnels pointeurs sur les fonctions de
callback. Aussi, l'application nécessite les sources qui implantent cette
fonctionnalité et c'est pour cela que moc
est appelé. Moc est le
Compilateur de Méta Objet (NdT : Moc signifie littéralement Meta Object
Compiler) de la boîte à outils Qt et construit l'implantation des
mécanismes de signal et de slot en analysant le fichier d'en-tête et en
générant un fichier source qui doit être compilé dans le binaire. Comme
KDevelop utilise automoc
pour déterminer quels fichiers doivent être
traités, vous n'avez pas besoin de vous préoccuper des appels à moc
et au
compilateur C++ pour les fichiers générés par moc. Souvenez-vous seulement des
règles qui permettent à une classe d'utiliser le mécanisme de signal et de
slot de QObject
ou toute classe qui hérite de QObject
elle-même,
vous devez aussi inclure la macro Q_OBJECT
(sans point-vigule !) au début
de la déclaration de la classe et la déclaration des signaux et des slots.
Enfin, votre binaire est construit par le compilateur. Le binaire
généré est appelé kscribble
, l'éditeur de liens inclut le chemin vers KDE
et vers les bibliothèques de X11 et lie les sources avec les bibliothèques
kfile, kfm, kdeui, kdecore, qt, Xext
et X11
. Ensuite, c'est terminé
et make se termine.
Pour décrire le concept de fonctionnement d'une application KDE, nous allons d'abord regarder précisément le squelette de sources déjà fourni par l'Assistant d'Application. Comme nous l'avons déjà vu, nous avons un ensemble de sources et de fichiers d'en-tête qui constituent le code initial de l'application et la rendent prête à être exécutée. De ce fait, la plus simple façon d'expliquer le code est de suivre l'implantation ligne par ligne, comme il est traité durant l'exécution du programme jusqu'à ce qu'il entre dans la boucle d'événements principale et soit prêt à accepter les entrées de l'utilisateur. Ensuite, nous regarderons les fonctionnalités qui permettent les interactions avec l'utilisateur et comment certaines choses fonctionnent. C'est probablement la meilleure façon d'expliquer l'architecture et comme elle est similaire pour presque toutes les applications KDE, cela vous permettra de lire plus facilement le code source d'autres projets. En plus, vous apprendrez quoi et où changer dans le code pour faire en sorte que vos applications se comportent comme prévu.
main()
Comme l'application commence son exécution en entrant dans la fonction main()
,
ce sera aussi notre point de départ pour examiner le code. La fonction
main()
de KScribble est implantée dans le fichier main.cpp
et
peut également être trouvée grâce au Navigateur de Classe en sélectionnant le
sous-dossier "Fonctions" du dossier "Globaux" :
1 #include "kscribble.h"
2
3 int main(int argc, char* argv[]) {
4 KApplication app(argc,argv,"KScribble");
5
6 if (app.isRestored())
7 {
8 RESTORE(KScribbleApp);
9 }
10 else
11 {
12 KScribbleApp* kscribble = new KScribbleApp;
13 kscribble->show();
14 if(argc > 1){
15 kscribble->openFile(argv[1]);
16 }
17 }
18 return app.exec();
19 }
La première chose qui se passe généralement est la création d'un objet
KApplication
qui
reçoit le nom de notre application KScribble comme troisième paramètre.
Lors de la création d'une nouvelle KApplication
, une nouvelle
instance de KConfig
est également créée, permettant d'accéder au
fichier de configuration $HOME/.kde/share/config/appname + rc qui contient
toutes les informations que nous voulons utiliser lors du lancement des
fenêtres de l'application. Le nom passé au constructeur de app
sera
utilisé plus tard comme titre de la fenêtre. Ici, le code est un petit peu
différent du code d'exemple donné précédemment pour convertir une application
Qt en une application KDE. Une fois que l'objet KApplication
est présent, nous testons si l'application est démarrée par le gestionnaire de
sessions de kwm
ou manuellement par l'utilisateur. Cela est déterminé en
appelant isRestored()
sur l'objet app
qui retourne true
pour
la gestion de sessions et false
pour un lancement manuel. Comme la
gestion des sessions est une fonctionnalité importante des applications
KDE et largement utilisée par l'architecture mais plus longue à expliquer,
nous allons d'abord continuer par la section else{}
; ensuite, nous y
reviendrons et expliquerons la fonctionnalité de gestion des sessions dans une
étape ultérieure.
La section else{}
crée maintenant une instance de la classe
KScribbleApp
à la ligne 12. Cet objet est appelé pour s'afficher à la
ligne 13, comme d'habitude ; la ligne 14 détermine si un argument a été passé
à la ligne de commande et, comme c'est souvent le nom d'un fichier, appelle
l'objet kscribble
pour l'ouvrir avec openFile()
. Remarquez que
nous n'avons pas appelé la méthode setTopWidget(kscribble)
pour notre
application - c'est déjà fait par la classe dont hérite KScribbleApp
.
Maintenant, nous allons regarder notre objet KScribbleApp
- qu'est-ce que
c'est et que fournit-il déjà ? La seule chose que nous savons jusqu'à
maintenant, c'est que ça doit être un Widget pour représenter l'interface
utilisateur dans la fenêtre pricipale. Allons dans l'implantation de la classe
KScribbleApp
qui se trouve dans le fichier kscribble.cpp
ou par un
clic sur l'icône de classe dans le Navigateur de Classe. L'instance est créée
par le constructeur. D'abord, nous voyons qu'elle hérite de la classe
KTMainWindow
qui fait partie de la bibliothèque kdeui
. Cette
classe hérite elle-même de QWidget
donc, comme d'habitude, nous
avons un widget normal comme fenêtre de plus haut niveau (NdT : top-level
window). KTMainWindow
contient beaucoup de fonctionnalités qui sont
utilisées par la classe KScribbleApp
. Elle fournit une barre de menus,
une barre d'outils, une barre d'état et le support de la gestion de
sessions. La seule chose que nous ayons à faire en dérivant de
KTMainWindow
est de créer tous les objets dont nous avons besoin et
de créer un autre widget qui sera géré par notre instance de
KTMainWindow
comme vue principale au centre de la fenêtre ;
habituellement, c'est ici que l'utilisateur travaille comme une vue d'édition
de texte.
Regardons le code du constructeur et voyons comment l'instance est créée :
1 KScribbleApp::KScribbleApp()
2 {
3 config=kapp->getConfig();
4
5
6 ///////////////////////////////////////////////////////////////////
7 // call inits to invoke all other construction parts
8 initMenuBar();
9 initToolBar();
10 initStatusBar();
11 initKeyAccel();
12 initDocument();
13 initView();
14
15 readOptions();
16
17
///////////////////////////////////////////////////////////////////
18 //disable menu and toolbar items at startup
19 disableCommand(ID_FILE_SAVE);
20 disableCommand(ID_FILE_SAVE_AS);
21 disableCommand(ID_FILE_PRINT);
22
23 disableCommand(ID_EDIT_CUT);
24 disableCommand(ID_EDIT_COPY);
25 disableCommand(ID_EDIT_PASTE);
26 }
Nous voyons que notre instance de
KConfig
pointe maintenant vers la configuration de l'application
donc nous pourrons travailler avec les entrées du fichier de configuration
ultérieurement. Ensuite, tous les composants requis par l'application sont
créés par les fonctions membres correspondantes, spécifiquement à notre fenêtre
principale :
Enfin, nous désactivons certaines commandes que l'utilisateur peut activer car elles ne doivent pas être disponibles dans l'état courant de l'application. Comme nous avons maintenant un aperçu global de la façon dont est créée la fenêtre de l'application, nous allons regarder en détail comment les éléments de l'interface utilisateur sont construits par les méthodes ci-dessus.
Comme nous l'avons vu au-dessus, la barre de menus de KScribble est
créée par la méthode
initMenuBar()
. En fait, nous créons un ensemble de QPopupMenu
s
qui apparaissent si l'utilisateur sélectionne une entrée de menu. Ensuite,
nous les insérons dans la barre de menus et nous les connectons aux entrées.
D'abord, nous créons notre recent_file_menu
qui contiendra les noms des 5
derniers fichiers ouverts. Nous devons le faire en premier car ce menu est
inséré dans le file_menu
. Ensuite, nous ajoutons directement la connexion
- nous récupérons juste le signal qui est émis par l'entrée de menu avec son
numéro d'entrée et appelons slotFileOpenRecent( int )
, qui ouvre ensuite
le bon fichier de la liste des fichiers récemment ouverts.
Ensuite, nous créons notre menu "Fichier". C'est le menu qui sera visible dans la barre de menus. Les actions standards sont ensuite insérées une par une dans le menu popup - d'abord, les commandes pour créer un nouveau fichier, ouvrir un fichier, fermer un fichier... et enfin "E&xit" pour fermer l'application. Toutes les entrées de menu doivent être créées dans l'ordre dans lequel elles apparaîtront ensuite donc nous devons rester vigilants sur ce que nous voulons mettre et à quelle place. À titre d'exemple, regardons les entrées suivantes :
file_menu->insertItem(Icon("fileopen.xpm"), i18n("&Open..."), ID_FILE_OPEN );
file_menu->insertItem(i18n("Open &recent"), recent_files_menu, ID_FILE_OPEN_RECENT );
La première ligne insère une entrée "Open...". Comme nous voulons qu'elle ait une icône,
nous utilisons la méthode insertItem()
avec le nom de l'icône. Pour comprendre le
processus de chargement d'icône, nous devons savoir comment et où est déclaré Icon()
-
en fait, c'est une macro fournie par la classe KApplication
:
#define Icon(x) kapp->getIconLoader()->loadIcon(x)
Elle utilise, d'ailleurs, la macro interne suivante pour accéder à l'objet application :
#define kapp KApplication::getKApplication()
Cela signifie que l'objet KApplication
contient déjà une instance du
chargeur d'icône - nous devons seulement y accéder ; ensuite, il chargera l'icône
correpondante. Comme nos icônes viennent toutes des bibliothèques de KDE, nous
n'avons pas à nous préoccuper de quoi que ce soit d'autre - elles sont installées
automatiquement sur le système et nous n'avons donc pas besoin de les inclure dans
le paquetage de notre application pour pouvoir les utiliser.
Après le paramètre d'icône (qui est optionnel), nous insérons le nom de l'entrée de
menu par i18n("&Open...")
. Là, nous devons signaler deux choses : premièrement,
l'entrée est insérée avec la méthode i18n()
. Comme pour Icon()
, c'est aussi
une macro définie dans kapp.h
et appelle l'objet KLocale
de
KApplication
pour traduire l'entrée dans la langue utilisée actuellement :
#define i18n(X) KApplication::getKApplication()->getLocale()->translate(X)
Il faut signaler que quelqu'un pourrait penser "Je ne veux pas utiliser de macros" - vous
pouvez le faire dans la plupart des cas. Mais ici, il est nécessaire d'utiliser i18n()
car pour l'internationalisation, les fichiers de traduction correspondants doivent être
générés. Comme ce processus de génération repose sur l'utilisation de la chaîne de
caractères i18n
, vous devez utiliser cette macro.
Comme vous l'avez peut-être déjà deviné, le symbole & (et commercial) dans les entrées
de menu est interprété ultérieurement comme une petite ligne sous la lettre correspondante
dans l'entrée de menu. Cela permet un accès rapide à la commande du menu via le clavier
quand l'utilisateur appuie simultanément sur la touche Alt
et la lettre soulignée.
Enfin, nous donnons à l'entrée de menu un identificateur (NdT : ID) qui est une valeur
entière par laquelle nous pourrons trouver l'entrée ultérieurement. Pour garder un oeil
sur les valeurs utilisées, celles-ci sont définies par des macros et sont regroupées
dans le fichier resource.h
de votre projet. Par souci de cohérence, ces macros sont
écrites en majuscules, commencent par ID_ et sont suivies du nom du menu et de celui
de l'entrée. Cela aide énormément à se remémorer le sens de chaque entrée n'importe où
dans le code ; il n'est donc plus nécessaire d'aller systématiquement dans l'implantation
de la barre de menus pour chercher les entrées.
Le deuxième exemple d'entrée montre une autre variante de la méthode insertItem()
.
Ici, nous ajoutons le menu popup recent_files_menu comme un élément de menu. Cela signifie
que l'entrée s'affiche elle-même avec la chaîne donnée "Open recent", suivie par une flèche
vers la droite. Lors d'une sélection, le menu popup des fichiers récemment ouverts apparaît
et l'utilisateur peut choisir un des derniers fichiers.
Enfin, il y a beaucoup d'autres manières d'insérer des éléments de menu - l'architecture
rend cela aussi simple que possible. Plus d'informations sur la classe QMenuData
peuvent être trouvées dans la documentation de Qt.
Maintenant, après avoir créé les menus popup file_menu, edit_menu
et view_menu
,
nous devons insérer aussi un menu "Aide". Nous pourrions le faire comme pour les autres
menus mais la classe KApplication
fournit une méthode simple et rapide pour le
faire :
help_menu = kapp->getHelpMenu(true, i18n("KScribble\n" VERSION ));
C'est tout ce que nous avons à faire pour obtenir un menu d'aide qui contient une entrée
pour le contenu de l'aide accessible avec le raccourci clavier
F1, une
boîte de dialogue "À propos" pour l'application et une boîte de dialogue
"À propos" pour KDE (qui peut être
désactivée en appelant getHelpMenu(false,...);
). Le contenu de la boîte de dialogue
"À propos" de notre application est à nouveau défini avec la chaîne i18n()
- VERSION
prend la macro qui est définie dans le fichier config.h
pour le numéro de version
du projet donc nous n'avons pas besoin de le changer manuellement à chaque fois que nous
voulons diffuser une nouvelle version. N'hésitez pas à ajouter ici des informations sur
votre application, par exemple votre nom, votre adresse électronique, le copyright, etc.
Maintenant, nous n'avons plus qu'à insérer les popups dans la barre de menus.
Comme KTMainWindow
construit déjà une barre de menus pour nous, il suffit
de les insérer en appelant menuBar()->insertItem();
.
Ce qu'il reste à faire est de connecter les entrées de menu avec les méthodes
qu'elles exécuteront. C'est pourquoi, nous connectons chaque menu popup par son signal
activated( int )
à une méthode commandCallback( int )
qui contient un switch
qui appelle les méthodes correspondantes pour les entrées
de menu. En plus, nous connectons le signal highlighted( int )
des popups
pour fournir de l'aide sur chaque entrée dans la barre d'état. Lorsque l'utilisateur
déplace sa souris ou le focus du clavier sur une entrée, la barre d'état affiche
alors le message d'aide correspondant.
Après avoir terminé avec la barre de menus, nous pouvons passer à la barre d'outils
dans la section suivante. Remarquez qu'une instance de KTMainWindow
peut
avoir seulement une seule barre de menus visible à la fois ; c'est pourquoi, si vous
voulez construire plusieurs barres de menus, vous devez les créer séparément avec des
instances de KMenuBar
et définir l'une d'elles comme la barre de menus
courante avec la méthode appropriée de KTMainWindow
. Consultez la
documentation de la classe KMenuBar
pour plus de détails sur ses
fonctionnalités étendues, voir aussi
Configuration des Barres de Menus et des Barres d'Outils.
La création de barres d'outils est bien plus simple que pour les barres de menus.
Comme KTMainWindow
fournit déjà des barres d'outils qui sont créées
dès leur première insertion, vous êtes libre d'en créer plusieurs. Ajoutez juste les
boutons pour les fonctions que vous voulez fournir :
toolBar()->insertButton(Icon("filenew.xpm"), ID_FILE_NEW, true, i18n("New File") );
Ceci ajoute un bouton aligné à gauche avec l'icône "filenew.xpm" et l'identificateur
(NdT : ID) correspondant dans la barre d'outils. Le troisième paramètre décide si
le bouton doit être activé ou non ; par défaut, nous le définissons à true
car nos
méthodes disableCommand()
à la fin du constructeur le font automatiquement pour
nous, à la fois pour les entrées du menu et de la barre d'outils. Enfin,
le dernier paramètre est utilisé pour la "bulle d'aide" - quand l'utilisateur
place le pointeur de la souris sur le bouton pour le mettre en surbrillance,
une petite fenêtre, qui contient un court message d'aide dont le contenu est
défini ici, apparaît.
Enfin, les boutons de la barre d'outils sont connectés à notre méthode
commandCallback()
par leur signal clicked()
. Lors du signal pressed()
,
nous permettons à l'utilisateur de recevoir le message d'aide correspondant dans la
barre d'état.
Informations supplémentaires :
Comme les barres d'outils sont créées en utilisant la classe KToolBar
,
vous devriez consulter la documentation correspondante. Avec KToolBar
,
beaucoup de choses nécessaires pour une barre d'outils peuvent être réalisées,
comme un popup retardé si votre bouton veut afficher un menu quand le bouton reste
enfoncé ou même l'utilisation d'autres widgets comme par exemple une liste déroulante.
Par défaut, la barre d'outils remplit complètement la largeur de la fenêtre ce
qui est sympathique pour l'utilisation d'une seule barre. Lorsque vous en avez plus
d'une, vous devriez penser à définir la taille de la barre à l'extrémité du bouton le
plus à droite, ainsi les autres barres peuvent s'afficher dans la même ligne, sous
la barre de menus. Nous évoquerons certaines techniques de conception et d'extension
des barres d'outils dans la section
Configuration des Barres de Menus et des Barres d'Outils.
La barre d'état est, comme les autres barres, déjà fournie par l'instance de
KTMainWindow
donc nous avons juste à insérer nos éléments dedans
comme nous le souhaitons. Par défaut, l'architecture contient seulement une
entrée qui affiche l'aide de la barre d'état. Pour beaucoup d'applications,
ce n'est pas suffisant, vous pourrez donc ajouter les entrées dont vous avez
besoin pour afficher, par exemple, des coordonnées ou autre chose.
De plus, une application ne peut avoir qu'une seule barre d'état, comme pour
la barre de menus. Si vous voulez en construire plusieurs, vous devrez les
créer séparément et définir la barre courante avec la méthode appropriée de
KTMainWindow
. La barre d'état permet aussi d'insérer des widgets
qui peuvent être utilisés pour créer des zones pour afficher des barres de
progression, comme KDevelop le fait. Référez-vous à la documentation de
la classe KStatusBar
.
Une fois rendu à la méthode initKeyAccel()
, nous avons déjà construit les
éléments standards de la fenêtre principale d'une application - la barre de
menus, la barre d'outils et la barre d'état.
Cependant, nous n'avons pas encore défini les raccourcis clavier
par lesquels l'utilisateur expérimenté qui veut uniquement travailler avec son
clavier peut accéder rapidement aux commandes qui sont le plus souvent utilisées
pendant une session de travail de notre programme. Pour cela, nous aurions pu insérer
les touches de raccourci
, par exemple, lors de l'insertion des
éléments du menu mais KDE offre une bonne solution pour construire et maintenir
les raccourcis clavier
. Beaucoup d'utilisateurs veulent d'un côté
qu'ils soient configurables et d'un autre côté les raccourcis
standards doivent être les mêmes pour toutes les applications. C'est pourquoi,
le Centre de Contrôle de KDE permet de configurer les raccourcis
clavier standards en utilisant la classe KAccel
. En plus, les
bibliothèques de KDE contiennent un widget qui permet aux utilisateurs de
configurer facilement les raccourcis
clavier spécifiques à
l'application. Comme l'architecture d'application utilise seulement des éléments
de menus qui sont des actions standards comme "Nouveau" ou "Quitter", celles-ci
sont définies par la méthode initKeyAccel()
. Les actions standards doivent
juste être connectées, pour la configuration du clavier spécifique à votre
application, vous devez les insérer d'abord en spécifiant le nom du raccourci
clavier et ensuite les connecter. Comme nos raccourcis
sont tous
présents dans la barre de menus, nous devons changer le raccourci
pour les entrées du popup. Enfin, nous appelons readSettings()
qui lit la
configuration courante depuis la fenêtre du bureau de KDE (NdT : KDE rootwindow) où est
stockée la configuration
des raccourcis
standards, puis les paramètres des
raccourcis
spécifié dans le fichier de configuration de l'application.
Quand nous aurons progressé dans notre projet d'exemple, nous vous dirons aussi comment
modifier avec une boîte de dialogue de configuration les raccourcis
spécifiques à notre application, voir
Configuration des Barres de Menus et des Barres d'Outils pour cette partie du
processus de développement.
Les deux appels de fonctions membres suivants, initDocument()
et initView()
,
permettent enfin de construire la partie que les fenêtres de l'application sont
supposées fournir à l'utilisateur : une interface pour travailler avec les données
que l'application est sensée manipuler ; et c'est aussi la raison pour laquelle
l'architecture d'application contient trois classes *App
, *View
et *Doc
. Pour comprendre pourquoi cette structure est utile, nous allons regarder
un peu au-delà du code actuel et introduire un peu de théorie, ensuite nous reviendrons
au programme pour voir comment l'architecture de KDevelop supporte ce modèle.
Typiquement, tout ce qui a été expliqué sur cette architecture est que nous avons besoin d'une instance de l'application qui contient une fenêtre principale. Cette fenêtre est chargée de fournir l'interface basique pour l'utilisateur - elle contient la barre de menus, les barres d'outils, la barre d'état et le contrôleur d'événements pour les interactions avec l'utilisateur. En plus, elle contient la zone qui est appelée la "Vue". Le but d'une vue est généralement d'afficher les données que l'utilisateur peut manipuler, par exemple un morceau de fichier texte. Cependant, le fichier texte, bien que probablement plus grand que la vue, est capable de s'afficher à l'écran, il permet à l'utilisateur d'aller dans la partie qu'il veut voir (c'est pourquoi c'est une vue) et l'utilisateur peut alors changer les données du contenu du fichier. Pour donner au programmeur une meilleure façon de séparer les parties du code de l'application, le Modèle Document-Vue a été inventé. Bien que n'étant pas un standard, il fournit la structure de fonctionnement d'une application :
Revenons à notre exemple de travail avec un fichier texte - là, le modèle s'applique de la façon suivante : le Document lit le contenu du fichier et fournit des méthodes aussi bien pour modifier les données que pour enregistrer à nouveau le fichier. La Vue, elle, traite les événements que l'utilisateur produit avec le clavier et la souris et utilise les méthodes de l'objet document pour manipuler les données du document.
Enfin, l'objet contrôleur est responsable de l'interaction avec l'utilisateur en fournissant les objets document et vue, ainsi que les interfaces pour envoyer des commandes comme l'ouverture et l'enregistrement. En plus, certaines méthodes de l'objet vue peuvent être fournies par des commandes accessibles par des accélérateurs clavier ou la souris sur les barres de menus et les barres d'outils.
Le modèle Document-Vue a des avantages - il sépare le code du programme à la mode "orientée objet" et par là offre plus de flexibilité ; par exemple, le même objet document peut être affiché simultanément par deux vues, soit avec une nouvelle vue dans une nouvelle fenêtre, soit en séparant la fenêtre courante qui contient alors deux objets vue qui forment la zone de vue de la fenêtre.
Si vous êtes issu des systèmes MS-Windows, vous devez être familier avec tout cela - les MFC fournissent déjà un modèle de document prêt à être utilisé. Pour les applications KDE et Qt, les choses sont un peu différentes. Qt est une boîte à outils puissante car elle fournit la majorité des classes, widgets, etc nécessaires. Mais, il n'y a eu aucune intention de gérer le modèle document-vue et comme KDE hérite de Qt, ce modèle n'a pas été non plus introduit. En fait, cela s'explique aussi par le fait que les applications X ne travaillent généralement pas en MDI (Multiple Document Interface). Chaque fenêtre principale est responsable de ses propres données et cela réduit le besoin d'un modèle de document au fait que les méthodes pour travailler sur le document sont toujours écrites dans les widgets. Actuellement, la seule exception est le projet KOffice qui fournit une suite de bureautique complète comprenant un traitement de texte, un tableur, etc. Techniquement, cela est réalisé par deux changements dans l'utilisation normale de Qt et KDE :
Mais, comme l'objectif de KDevelop est d'utiliser les bibliothèques actuelles de KDE 1.1.x et Qt 1.4x, nous ne pouvons pas utiliser ce modèle par défaut - cela apparaîtra dans les prochaines versions de KDE 2 qui contiendra (probablement) deux changements majeurs par rapport à la situation actuelle :
C'est pourquoi, pour l'instant, la façon de travailler des développeurs d'applications est soit d'implanter toutes les méthodes de documents dans leur vue, soit d'essayer de reproduire eux-mêmes un modèle de document. KDevelop souscrit à cette tentative en fournissant les classes requises et les méthodes de base qui sont généralement utilisées pour un modèle Document-Vue avec les architectures d'application de Qt et KDE.
Revenons au code, vous pouvez maintenant imaginer le but des deux méthodes que nous
avons mentionnées au début de cette section : les fonctions initDocument()
et
initView()
. initDocument()
construit l'objet document qui représente les
données de la fenêtre de l'application et initialise les attributs de base comme
le bit de modification qui indique si les données utilisées ont été modifiées par
l'utilisateur. Ensuite, la méthode initView()
construit le widget *View
,
le connecte au document et appelle la méthode setView()
de KTMainWindow
pour dire à la fenêtre *App
d'utiliser le widget *View
comme vue centrale.
Pour le développeur, il est important de savoir que durant le processus de développement, il doit :
*View
les méthodes virtuelles de QWidget
pour les événements du clavier et de la souris afin de pouvoir manipuler les donnéespaintEvent()
de QWidget
dans l'objet *View
pour redessiner (Ndt : repaint()) la vue après des modifications*View
*Doc
de charger et
enregistrer le fichier *Doc
qui représente logiquement en mémoire les données du document
Maintenant, après avoir créé toutes les instances de l'instance de
KTMainWindow
de notre application pour créer la fenêtre principale,
nous devons initialiser certaines valeurs qui influencent l'apparence du programme.
Pour cela, nous appelons readOptions()
qui récupère toutes les valeurs et
appelle les méthodes nécessaires pour définir les attributs correspondants. La
bibliothèque KDE-Core contient la classe KConfig
qui fournit une bonne
façon de stocker les valeurs dans des fichiers de configuration et permet
aussi de les relire. De plus, comme chaque instance de KApplication
crée déjà son
fichier de ressources, nous devons seulement accéder à ce fichier et créer nos
valeurs. Comme KConfig
nous donne l'objet fichier, nous devons utiliser
la classe KConfigBase
pour lire et écrire toutes les entrées. L'écriture
est très facile avec les méthodes writeEntry()
mais la lecture dépend du type
d'attribut que nous voulons initialiser. Généralement, une entrée dans le fichier
de configuration contient un nom de valeur et une valeur. Les valeurs qui
appartiennent au même contexte peuvent être regroupées dans des groupes, c'est
pourquoi nous devons définir le nom du groupe afin d'accéder ensuite à ses
valeurs : le groupe doit être défini seulement une seule fois pour lire les
attributs qui sont dans le même groupe. Regardons ce que nous voulons lire :
1 void KScribbleApp::readOptions()
2 {
3
4 config->setGroup("General Options");
5
6 // bar status settings
7 bool bViewToolbar = config->readBoolEntry("Show Toolbar", true);
8 view_menu->setItemChecked(ID_VIEW_TOOLBAR, bViewToolbar);
9 if(!bViewToolbar)
10 enableToolBar(KToolBar::Hide);
11
12 bool bViewStatusbar = config->readBoolEntry("Show Statusbar", true);
13 view_menu->setItemChecked(ID_VIEW_STATUSBAR, bViewStatusbar);
14 if(!bViewStatusbar)
15 enableStatusBar(KStatusBar::Hide);
16
17 // bar position settings
18 KMenuBar::menuPosition menu_bar_pos;
19 menu_bar_pos=(KMenuBar::menuPosition)config->readNumEntry("MenuBar Position", KMenuBar::Top);
20
21 KToolBar::BarPosition tool_bar_pos;
22 tool_bar_pos=(KToolBar::BarPosition)config->readNumEntry("ToolBar Position", KToolBar::Top);
23
24 menuBar()->setMenuBarPos(menu_bar_pos);
25 toolBar()->setBarPos(tool_bar_pos);
26
27 // initialize the recent file list
28 recent_files.setAutoDelete(TRUE);
29 config->readListEntry("Recent Files",recent_files);
30
31 uint i;
32 for ( i =0 ; i < recent_files.count(); i++){
33 recent_files_menu->insertItem(recent_files.at(i));
34 }
35
36 QSize size=config->readSizeEntry("Geometry");
37 if(!size.isEmpty())
38 resize(size);
39 }
Comme nous l'avons vu dans un des morceaux de code précédents, la première action réalisée par notre constructeur était :
config=kapp->getConfig();
qui positionne le pointeur config
de type KConfig
sur la configuration
de l'application. Nous n'avons donc pas besoin de nous préoccuper de l'emplacement
de ce fichier de configuration. En fait, ce fichier est, conformément
au Système de Fichiers Standard de KDE (KDE FSS) (NdT : KDE FSS signifie KDE File
System Standard), situé dans $HOME/.kde/share/config/
; nous regarderons
plus précisément le KDE FSS dans une autre section quand nous définirons l'emplacement
pour l'installation des fichiers du projet. Comme le fichier de configuration est
placé dans le répertoire utilisateur (NdT : user's home directory), chaque utilisateur
possède sa propre apparence de l'application, excepté les valeurs qui sont situées
dans le fichier de configuration global
du système qui peut optionnellement être créé et installé par le programmeur dans
le dossier de KDE. Mais, bien que cela puisse être utile dans certains cas, nous
devrions éviter toute dépendance de l'application envers l'existence d'entrées de fichier.
C'est pourquoi toutes les méthodes de lecture fournies par KConfigBase
permettent d'ajouter une valeur par défaut à utiliser lorsque l'entrée n'existe pas.
Une autre chose importante pour le programmeur est que le fichier de configuration est
stocké sous la forme d'un fichier texte, et, pour cette raison, vous devez vous souvenir que :
Maintenant que nous connaissons les bases, nous allons analyser le code. Comme
cela a été dit, nous avons juste à utiliser notre pointeur de configuration pour
accéder aux valeurs. D'abord, à la ligne 4, nous définissons le groupe courant à
"General Options". Cela indique que les valeurs utilisées sont des attributs
relativement globaux pour l'application. Ensuite, nous lisons les valeurs pour
la barre d'outils et la barre d'état - elles doivent être enregistrées lorsque
l'application est fermée afin de pouvoir restaurer leur état quand l'utilisateur
redémarre le programme. Comme les barres peuvent seulement être actives ou inactives,
nous utilisons une valeur booléenne, c'est pourquoi notre méthode est readBoolEntry()
.
Le processus est identique pour les deux barres donc nous considérerons seulement
les lignes 7-10 pour regarder ce qui se passe avec la barre d'outils. D'abord,
nous lisons la valeur dans une variable temporaire bViewToolbar
à la ligne 7.
Dans le fichier, le nom de la valeur est "Show Toolbar" et, si la valeur n'est pas
présente (ce qui peut être le cas lors du premier démarrage de l'application), la
valeur par défaut est définie à true
. Ensuite, nous positionnons la coche de
l'entrée de menu pour (dés)activer la barre d'outils suivant sa valeur : nous
appelons setItemChecked()
pour le menu de la vue, avec l'entrée ID_VIEW_TOOLBAR
et notre attribut. Enfin, nous faisons en sorte que la barre d'outils utilise cette
valeur. Par défaut, la barre d'outils est visible donc nous devons faire quelque
chose seulement si bViewToolbar
vaut false
. Avec enableToolBar()
(ligne 10),
nous forçons la barre à se cacher si elle est désactivée.
Ensuite, nous devons lire la position de la barre. Comme l'utilisateur peut avoir
changé la position de la barre en glissant la barre avec la souris vers une autre
zone de la vue, ceci doit aussi être enregistré afin de pouvoir restaurer son état.
En regardant les classes KToolBar
et KMenuBar
, nous voyons
que la position des barres peut valoir :
enum BarPosition {Top, Left, Bottom, Right, Floating, Flat}
Comme cette valeur doit être écrite sous forme numérique, nous devons la lire avec
readNumEntry()
et la convertir en une valeur de position. Avec setMenuBarPos()
et setBarPos()
, nous disons aux barres de s'afficher.
Vous avez aussi probablement noté que le menu "Fichier" contient un menu pour les
fichiers récemment utilisés. Les noms de ces fichiers sont stockés dans une liste de
chaînes de caractères qui doit être enregistrée lors de la fermeture de l'application
et maintenant, nous devons les lire pour restaurer le menu. D'abord, nous initialisons
la liste avec les entrées enregistrées en utilisant readListEntry()
. Ensuite, dans
une boucle for
, nous créons une entrée de menu pour chaque élément de la liste.
Enfin, nous devons juste prendre en compte la géométrie de notre fenêtre. Nous lisons
son apparence avec une variable QSize
contenant une valeur x et y pour la largeur
et la hauteur de la fenêtre. Comme la fenêtre est initialisée par KTMainWindow
,
nous n'avons pas besoin de nous soucier de la valeur par défaut et nous utiliserons
resize()
seulement si l'entrée n'est pas vide.
Ce qui reste à expliquer dans la construction de l'application est que nous devons initialement désactiver les commandes utilisateur qui ne seraient pas disponibles si certaines instances ne correspondent pas aux critères requis. Ce sont l'enregistrement de fichier et les opérations qui utilisent le presse-papiers. Pendant la vie de l'application, nous devons y faire attention à plusieurs reprises mais cela reste vraiment simple. L'architecture nous donne seulement deux méthodes pour activer/désactiver la barre de menus et les éléments de la barre d'outils avec un seul appel à la méthode à la fois.
Au long de la section précédente, nous avons seulement surveillé ce qui se passe pendant
l'appel au constructeur de notre instance de KScribbleApp
qui nous donne la fenêtre
principale. Après le retour à la fonction main()
, nous devons appeler show()
pour afficher la fenêtre. Ici, ce qui est différent d'une KApplication
ou
d'une QApplication
, c'est que nous utilisons KTMainWindow
comme
instance de notre widget principal ; nous n'avons pas besoin de le définir avec
setMainWidget()
. Cela est fait par KTMainWindow
lui-même et nous
n'avons pas besoin de nous en soucier.
La seule chose restante est d'interpréter la ligne de commande. Nous lisons la ligne
de commande et testons si int argc
est > 1, ce qui indique que l'utilisateur a
lancé notre application avec kscribble nom_de_fichier_a_ouvrir
. Notre fenêtre
est alors sensée ouvrir le fichier ayant ce nom et appeler openDocumentFile()
avec le nom du fichier.
La dernière ligne de la fonction main()
fait le travail attendu : elle exécute
l'instance de l'application et le programme entre dans la boucle d'événements.
Dans la section
La Fonction main(), nous avons
commencé à séparer le processus d'exécution par if( app.isRestored() )
et décrit
le processus de lancement habituel. La suite vous donne maintenant une introduction à
la gestion de sessions et comment notre application l'utilise.
Comme nous l'avons dit, la fonction main()
teste si l'application a été lancée
par le gestionnaire de sessions. Le gestionnaire de sessions est responsable de
l'enregistrement de l'état actuel de toutes les fenêtres ouvertes de l'application
sur le bureau de l'utilisateur et doit les restaurer quand l'utilisateur se
connecte à nouveau, ce qui signifie que l'application n'est pas lancée par
l'utilisateur mais automatiquement exécutée. La partie du code qui est exécutée était :
6 if (app.isRestored())
7 {
8 RESTORE(KScribbleApp);
9 }
Dans
La Fonction main(), nous avons indiqué que
nous testons le type de lancement en interrogeant app.isRestored()
. Ensuite, la
ligne 8 est exécutée. Cela ressemble à quelque chose de simple mais, en fait, il en
résulte un processus d'exécution complexe que nous allons suivre dans cette section.
RESTORE(), quant à elle, est une macro fournie par KTMainWindow
. Elle est
remplacée par le code suivant :
if (app.isRestored()){
int n = 1;
while (KTMainWindow::canBeRestored(n)){
(new KScribbleApp)->restore(n);
n++;
}
}
Cela restaurera toutes les fenêtres de l'application de la classe KScribbleApp
en créant les instances et en appelant restore()
pour la nouvelle fenêtre. Il est
important de comprendre que si votre application utilise plusieurs widgets différents
qui héritent de KTMainWindow
, vous devez remplacer la macro et déterminer le
type des widgets principaux (NdT : top widgets) en utilisant
KTMainWindow::classNameOfToplevel(n)
au lieu de la classe KScribbleApp
.
La méthode restore()
lit ensuite la partie du fichier de session qui
contient les informations concernant la fenêtre. Comme KTMainWindow
enregistre tout cela pour nous, nous n'avons rien de spécial à faire. Ensuite, seules
les informations spécifiques à notre instance de KScribbleApp
doivent être retrouvées.
Souvent, c'est un fichier temporaire que nous avons créé pour enregistrer le document ou
une autre initialisation qui est requise. Pour obtenir ces informations de restauration,
nous devons seulement réécrire deux méthodes virtuelles de KTMainWindow
,
saveProperties()
et readProperties()
. Les informations que nous devons
enregistrer pour la session sont si le fichier actuellement ouvert est modifié ou non
et le nom du fichier. Si le fichier est modifié, nous obtiendrons un fichier
temporaire pour l'enregistrer. Au début de la session, ces informations sont utilisées
pour restaurer le contenu du document :
void KScribbleApp::readProperties(KConfig*)
{
QString filename = config->readEntry("filename","");
bool modified = config->readBoolEntry("modified",false);
if( modified ){
bool b_canRecover;
QString tempname = kapp->checkRecoverFile(filename,b_canRecover);
if(b_canRecover){
doc->openDocument(tempname);
doc->setModified();
QFileInfo info(filename);
doc->pathName(info.absFilePath());
doc->title(info.fileName());
QFile::remove(tempname);
}
}
else if(!filename.isEmpty()){
doc->openDocument(filename);
}
setCaption(kapp->appName()+": "+doc->getTitle());
}
Ici, la ligne kapp->checkRecoverFile()
paraît un peu étrange car
b_canRecover
n'est pas initialisé. Cela est fait par la méthode qui le
met à true
, s'il y a un fichier de restauration.
Comme nous avons seulement enregistré un document dans un fichier de restauration (NdT : recover file) s'il était modifié, nous positionnons le bit de modification pour indiquer que les informations n'ont pas été enregistrées dans le fichier original. Nous devons aussi faire attention au fait que le fichier de restauration possède un nom de fichier différent du fichier original qui était ouvert. C'est pourquoi, nous devons réinitialiser le nom de fichier et le chemin à l'ancien nom de fichier. Enfin, nous avons les informations que nous voulions restaurer et nous pouvons supprimer le fichier temporaire du gestionnaire de sessions.
Résumé :
Tout au long de ce chapitre, vous avez appris comment l'application est lancée, soit par un appel normal de l'utilisateur, soit par le gestionnaire de sessions. Nous avons parcouru le code pour apprendre comment les parties de l'interface visuelle de l'application sont construites et comment initialiser les attributs grâce aux entrées du fichier de configuration. Maintenant, vous pouvez exécuter l'application pour tester ces fonctions et voir comment la fenêtre du programme réagit.
Au-delà du code source fourni, les projets KDevelop contiennent beaucoup de choses supplémentaires qui intéresseront le développeur. Parmi elles, on trouve :
Mise à part la documentation de l'API, ces éléments du projet seront
installés ensemble avec le binaire de l'application. Comme l'architecture de projet
doit être aussi ouverte que possible, vous devrez adapter ces éléments aux objectifs
de votre projet. Premièrement, vous devez éditer les icônes fournies. Cela donnera à
votre application un indentifiant unique par lequel l'utilisateur peut déterminer
visuellement votre application dans les menus du gestionnaire de fenêtres. Le fichier
.kdelnk est un fichier qui installe votre application dans le menu
Applications
de kpanel
(NdT : le tableau de bord de KDE). Il devra être
édité pour définir le chemin d'installation que nous détaillerons ultérieurement
dans ce manuel. Enfin, la documentation que vous voudrez fournir à l'utilisateur
est écrite en SGML. Cela permet de créer très facilement des formats de
sortie différents à partir de la même source. Par défaut, KDevelop propose de
créer un ensemble de fichiers HTML à partir de cette source ; pour les projets
KDE, il utilisera automatiquement le programme ksgml2html
pour donner
une apparence homogène, dans le style de KDE, à la documentation. Dans une section
ultérieure, nous verrons comment éditer les sources SGML et ce qu'il faut
faire pour l'installation vers l'utilisateur final.
Enfin, la documentation de l'API (Application Programming Interface)
vous permet, ainsi qu'aux autres développeurs, d'aller rapidement dans le code
et d'utiliser les classes sans avoir à deviner la finalité de chacune d'elles.
Nous apprendrons comment étendre la documentation de l'API dans une étape
ultérieure ; pour l'instant, il suffit de savoir que la documentation est générée
par le programme KDoc
qui traite les fichiers d'en-tête et crée les
fichiers HTML, c'est pourquoi toute la documentation est placée dans les en-têtes.
Page suivante Page précédente Table des matières