Initiation à la programmation KDE - 2e partie

Nous avons vu la dernière fois les mécanismes de base nécessaires pour réaliser notre première application KDE (un visualiseur de texte simplifié) : création d'une fenêtre, d'un menu, d'une barre d'outils, internationalisation du programme et enfin, gestion des sessions. Dans cette deuxième partie, nous poursuivrons l'amélioration de notre visualiseur de texte en lui ajoutant : des raccourcis claviers standards et configurables, un fichier de configuration, la transparence réseau, le « drag and drop » et la portabilité.

Avant de commencer

Une petite note sur l'exemple choisi : certes, un visualiseur de texte a peu d'intérêt en soi, mais c'est un bon exemple pour se familiariser avec les mécanismes proposés par les bibliothèques du KDE, car ces mécanismes ne dépendent pas de la finalité du programme.

Cette deuxième partie du didacticiel part du principe que vous avez lu et éventuellement testé la première partie. Cependant, si vous n'avez pas les sources du visualiseur à portée de main, vous pouvez trouver les sources (comprenant cette deuxième partie) sur http://www.insa-lyon.fr/People/AEDI/dfaure/my prog/

Raccourcis clavier Standards

Si vous utilisez déjà KDE, vous avez remarqué que les raccourcis clavier standards ("Nouveau", "Ouvrir", "Quitter", "Copier", "Coller"...) peuvent être configurés de manière globale, pour toutes les applications KDE. Cependant, notre programme minimal de la première partie ne respecte pas ces raccourcis standards. Il nous faut donc le modifier légèrement. Dans myprog.cpp, ajoutons

#include <kstdaccel.h>

et, au début du constructeur MyWin::MyWin(),

KStdAccel stdAccel;

afin de créer une instance de la classe KStdAccel.

Pour utiliser les raccourcis standards, il nous suffit ensuite de remplacer

CTRL+Key_N par stdAccel.openNew()

CTRL+Key_O par stdAccel.open()

CTRL+Key_Q par stdAccel.quit()

C'est aussi simple que cela.

La liste complète des raccourcis standards est bien sûr disponible dans

kstdaccel.h.

Lancez "kcmkeys standard" pour changer les raccourcis standards (il faut relancer le visualiseur pour que les changements soient pris en compte).

Fichiers de configuration

Afin de permettre à l'utilisateur de tout programme de sauvegarder ses préférences, KDE fournit la classe KConfig, qui gère la sauvegarde et la restauration de la configuration. Par exemple, tous les modules du centre de contrôle KDE utilisent KConfig pour enregistrer les changements de configuration.

Le format des fichiers de configuration est un format simple, lisible et éditable manuellement, similaire à celui des fichiers INI de Windows 3.x et désormais standard sous Unix aussi. Ce format définit des "groupes" et des "entrées" dans les groupes. Par exemple, un fichier de configuration comportant les entrées "Width" et "Height" dans le groupe "Options" ressemblera à :

# KDE Config File

[Options]

Width=430

Height=350

La première ligne est un commentaire qui sert à la détection automatique du type de fichier.

Les répertoires contenant les fichiers de configuration ont une organisation à deux niveaux : le niveau global et le niveau utilisateur. Ainsi, au moment de la lecture d'une entrée de configuration, KConfig regarde d'abord dans le fichier $KDEDIR/share/config/<appname>rc, qui contient les options par défaut pour l'application, puis dans ~/.kde/share/config/<appname>rc, qui contient les options propres à l'utilisateur. Cette organisation permet à l'auteur de l'application de fournir des options par défaut, éventuellement configurables par l'administrateur système.

En écriture, c'est bien sûr toujours dans le fichier utilisateur que les options sont enregistrées.

Comme exemple d'options à sauvegarder, nous pourrions permettre d'enregistrer la taille de la fenêtre. Afin que l'option soit disponible dans le menu Options, ajoutons, après l'insertion du menu Fichier :

// Le menu "options"

p = new QPopupMenu;

p->insertItem(i18n("&Save window size"), this, SLOT(slotSaveSize()));

menuBar()->insertItem(i18n("&Options"), p);

La méthode slotSaveSize() (à déclarer dans mywin.h !) enregistre la taille de la fenêtre :

KConfig * config = kapp->getConfig();

config->setGroup( "Options" ); // choix du groupe : "Options"

config->writeEntry( "Width", width() ); // largeur de la fenêtre

config->writeEntry( "Height", height() ); // hauteur de la fenêtre

config->sync();

A la première ligne, nous obtenons la référence à l'objet KConfig créé par l'application - il sera automatiquement nommé <appname>rc, c'est-à-dire myprogrc dans notre exemple.

Après choix du groupe et écriture des options, nous devons appeler la méthode sync() pour que l'enregistrement ait effectivement lieu. En effet, KConfig constitue un cache mémoire par rapport au fichier réel. Ceci permet d'optimiser les accès disques : le fichier est lu au lancement de l'application et toute lecture d'une entrée de configuration par la suite ne nécessite pas d'autre accès disque. C'est pourquoi il nous faut forcer la synchronisation du fichier disque après avoir modifié la configuration.

Pour restaurer la taille de la fenêtre, au lancement de notre application, il nous suffit de lire ces valeurs et de les appliquer à la fenêtre :

KConfig * config = kapp->getConfig();

config->setGroup( "Options" ); // choix du groupe : "Op tions"

int w = config->readNumEntry( "Width", 0 ); // largeur de la fenêtre

int h = config->readNumEntry( "Height", 0 ); // hauteur de la fenêtre

Ceci lit les valeurs dans le fichier de configuration, s'il existe (et affecte 0 dans le cas contraire). Bien qu'au moment de l'écriture, il nous suffise d'appeler writeEntry quel que soit le type de la valeur à écrire, à la lecture, il faut explicitement spécifier le type de valeur (la surcharge de méthode en C++ ne fonctionne qu'avec les paramètres, pas avec le type de retour de la méthode).

Il nous reste plus qu'à redimensionner la fenêtre, si w et h sont différents de 0 (nous ne voulons pas une fenêtre de taille (0,0) au premier lancement du programme !).

if (w != 0 && h != 0)

resize( w, h );

Afin de tester la restauration de la taille de la fenêtre, il faut inclure le code ci-dessus (y compris la lecture du fichier de configuration) à la fin du constructeur MyWin::MyWin().

Transparence du réseau

Jusqu'à présent, notre application ne gère que des fichiers présents sur un disque dur local. Nous pouvons facilement l'étendre pour qu'elle puisse ouvrir un fichier n'importe où sur le réseau, à partir de son URL.

Cette fonctionnalité est fournie par la bibliothèque kfmlib, dont le fichier d'en-tête est kfm.h, mais nécessite kfm pour son exécution (cette limitation disparaîtra dans KDE 2). Tel qu'indiqué par kfm.h, le chargement d'un fichier distant se fait de la manière suivante :

void MyWin::loadURL( QString url ) // méthode à défi nir comme publique

{

if ( KFM::download( url, fileName ) ) // télécharge le fichier

{

loadFile(); // ouvre le fichier temporaire local

KFM::removeTempFile( fileName ); // efface le fichier temporaire

setCaption( url ); // barre de titre = URL

}

}

Il nous reste à appeler cette méthode. Vous pouvez ajouter un élément de menu "Ouvrir l'URL..." dans le menu Fichier (aucune difficulté), le connecter à slotOpenURL() et définir cette méthode comme suit :

DlgLocation dlg ( i18n("URL :"), "" ); // défini dans kfm.h

dlg.show();

QString url = dlg.getText();

if (!url.isEmpty()) loadURL( url ); // ouvre l'URL

Ainsi, une boîte de dialogue apparaîtra pour demander l'URL à ouvrir. Un autre moyen d'ouvrir une URL est de la passer en ligne de commande. Pour cela, il suffit d'ajouter dans le main(), après mywin = new MyWin,

if ( argc==2 ) mywin->loadURL( argv[1] );

Vous pouvez tester ceci en appelant par exemple :

"./myprog http://www.kde.org/index.html" (fichier distant) et

"./myprog file:$PWD/Makefile" (fichier local).

L'ouverture depuis la ligne de commande permet aussi d'intégrer notre application dans kfm. Pour cela, créer un fichier .kdelnk pour notre application (Edition/Applications puis dans Utilities, Fichier/Nouveau/Application), le configurer en l'associant avec les types MIME désirés (text/plain et text/english par exemple) et en définissant comme ligne de commande à exécuter : "myprog %U". Après installation de myprog dans $KDEDIR/bin, ceci permet, en utilisant le menu contextuel sur un fichier texte local ou distant, de l'ouvrir avec notre application. (Notez que si on enlève le %U, kfm se charge du téléchargement et lance myprog avec le fichier temporaire. La seule différence est que, dans ce cas, myprog ne connaît pas l'URL initiale et ne peut donc pas l'afficher dans la barre de titre.)

Drag and drop

Un autre moyen d'ouvrir un fichier avec notre application est de le déposer depuis le gestionnaire de fichiers dans une fenêtre préalablement ouverte (mécanisme appelé "drag and drop"). Pour que ceci fonctionne, il va nous falloir créer, à la fin du constructeur, une zone de "dépôt", définie par KDNDDropZone (inclure <drag.h> dans mywin.h) :

KDNDDropZone * dropZone = new KDNDDropZone( this, DndURL );

La zone de dépôt est associée au widget "this", donc à toute la fenêtre. Le paramètre DndURL indique que nous attendons des URLs comme type d'objet déposé (seul type supporté dans KDE 1.x).

Ensuite, nous connectons l'action de dépôt dans cette zone avec une méthode de MyWin, toujours en utilisant les signaux et les slots :

connect( dropZone, SIGNAL( dropAction( KDNDDropZone *) ),

this, SLOT( slotDropAction( KDNDDropZone *) ) );

La zone de dépôt est passée comme argument à la méthode, c'est pourquoi nous n'avons pas besoin de garder la valeur de dropZone pour usage futur.

La méthode slotDropAction peut être définie de la manière suivante :

void MyWin::slotDropAction( KDNDDropZone * _dropZone )

{

// obtenir la liste des URLs déposées

QStrList urls = _dropZone->getURLList();

// ouvrir la première URL

if ( urls.first() ) loadURL( urls.first() );

}

Ceci ne permet pas de déposer plusieurs fichiers texte à la fois en créant une fenêtre par URL. Cette fonctionnalité est laissée au lecteur en guise d'exercice. D'ailleurs, ce comportement de l'application risque de troubler un peu l'utilisateur...

En revanche, vous pouvez constater que l'ajout du drag and drop s'est fait de manière très simple. Déposez un fichier depuis kfm vers myprog : le fichier est affiché dans la fenêtre.

La portabilité (autoconf/automake)

Vous l'avez remarqué, de nombreux programmes libres nécessitent l'exécution d'un script appelé "configure" avant qu'il soit possible de les compiler. Bien que ce mécanisme ne soit pas spécifique à KDE, nous allons nous y intéresser car il est important de le maîtriser si l'on veut distribuer son premier programme KDE. En effet, ce mécanisme permet non seulement la portabilité vers de nombreux Unix, il permet aussi à la phase de compilation de s'adapter à la configuration de la machine sur laquelle le programme est compilé (présence ou absence de certaines bibliothèques, répertoires d'installation différents...)

Pour créer votre application KDE, vous devez disposer des programmes autoconf et automake, soit en installant les paquetages correspondant à votre distribution, soit en les compilant depuis ftp://prep.ai.mit.edu/pub/gnu/.

Le mécanisme général est le suivant : le script configure est généré par le programme autoconf, à partir du fichier configure.in, qui donne les grandes lignes du script et de acinclude.m4.in, qui définit les actions précises que le script effectue. De plus, avant l'exécution d'autoconf, il faut préparer les fichiers Makefile.in, qui seront transformés en Makefile par configure. Plutôt que de les préparer à la main, nous utilisons automake, qui les génère à partir des fichiers Makefile.am, beaucoup plus simples à écrire.

Il est hors de question de créer tous les fichiers nécessaires à la main. Il est conseillé de partir d'une application KDE indépendante, par exemple trouvée sur ftp.kde.org, ou d'utiliser kapptemplate, qui génère les fichiers nécessaires et est donc plus facile à utiliser. kapptemplate est disponible à l'adresse ftp://ftp.kde.org/pub/kde/devel/helpers/kapptemplate.tar.gz

Après exécution du script kapptemplate, nous disposons de toute l'architecture nécessaire. Il nous suffit d'effacer tous les fichiers .cpp et .h du répertoire myprog/ et d'y copier nos fichiers sources, puis de modifier Makefile.am en enlevant tout ce qui concerne myprogwidget.* et main.* Il nous faut aussi récupérer LDADD de notre précédent Makefile.

Comme le montre Makefile.am, l'utilisation de kapptemplate nous a aussi procuré toute l'infrastructure pour l'installation d'un kdelnk dans le menu "K", d'une icône et d'une mini-icône pour l'application (à modifier bien sûr) et même de la documentation, dont un squelette est disponible dans doc/en/.

Pour générer configure et les Makefile.in, il faut exécuter les commandes suivantes :

aclocal

autoheader

automake

autoconf

Ensuite, nous pouvons tester la compilation avec "./configure" puis "make". Il est très important de générer le script configure avant de distribuer l'application, car tout le monde n'a pas automake et autoconf installés.

L'utilisation d'autoconf et automake permet donc de générer des Makefiles adaptés à la configuration locale, mais aussi de générer le fichier config.h, qui contient les résultats des divers tests effectués par configure. Ainsi, si le programme désire utiliser la macro _PATH_TMP, qui contient normalement "/tmp/", il doit faire attention à l'existence de cette macro et du fichier qui la contient (/usr/include/paths.h sur la plupart des systèmes Linux), sans quoi le programme ne compilera pas sur un système qui ne définit pas _PATH_TMP ou ne possède pas de fichier paths.h.

Pour que configure.in teste la présence de paths.h, il suffit d'ajouter paths.h à la liste des fichiers testés par la commande AC_CHECK_HEADERS dans configure.in. Après le lancement des 4 commandes ci-dessus, ceci ajoutera dans config.h le symbole HAVE_PATHS_H, défini si le fichier existe, indéfini sinon.

Le code correspondant dans le fichier source sera donc :

#include <config.h> // inclure les résultats de configure

#ifdef HAVE_PATHS_H // si le fichier existe

#include <paths.h> // alors l'inclure

#endif

#ifndef _PATH_TMP // si _PATH_TMP n'existe pas

#define _PATH_TMP "/tmp/" // alors le définir

#endif

Après cela, il est possible d'utiliser _PATH_TMP sans problème. Le cas du test d'un fichier d'en-tête est un cas typique mais simple - dans certains cas, il peut s'avérer nécessaire d'écrire soi-même un test dans acinclude.m4.in, ce qui nécessite de connaître de langage m4.

Documentation

Ainsi que l'a montré ce didacticiel, la plupart des informations nécessaires pour programmer une application KDE se trouvent dans les fichiers d'entêtes de kdelibs. Il est bien sûr possible de les lire directement, mais on peut préférer disposer d'une documentation formatée et arborescente, plus facile à utiliser. Le programme kdoc permet de générer une telle documentation, au format HTML, à partir des fichiers d'entête eux-mêmes.

La première étape est de se procurer kdoc : il est lui aussi disponible dans le CVS (module kdesdk pour kdoc v1, module kdoc pour kdoc v2) ou en tar.gz sur http://www.ph.uni melb.edu .au/~ssk/kde/kdoc/.

Pour générer la documentation, installer kdoc, puis lancer, depuis le répertoire kdelibs,

(pour kdoc v1) kdoc -d ~/src/kde/doc/ kdelibs */*.h

(pour kdoc v2) makekdedoc --outputdir=~/src/kde/doc/ --rule-file=kdoc.rules

Dans le cas de kdoc v2, il faut au préalable créer le fichier kdelibs/kdoc.rules contenant :

kde_MODULES = kdecore kdeui

kdecore_FILES= *.h

kdecore_LIBS= -lqt

kdeui_FILES= *.h

kdeui_LIBS= -lkdecore -lqt

Contrairement aux apparences, il est fortement conseillé d'utiliser kdoc v2, qui génère une documentation de bien meilleure qualité (et conserve l'indépendance des bibliothèques).

La documentation générée étant en HTML, on peut facilement la lire avec kfm : pour gagner du temps, on peut créer un alias pour "kfmclient exec ~/src/kde/doc/".

Outil de developpement

kdevelop est l'outil de développement (ou IDE - Integrated Development Environment) pour le KDE le plus avancé.

Il comporte une interface similaire à Visual Studio de Microsoft et résout la plupart des problèmes présentés ci-dessus : la génération du squelette de l'application (avec fichiers pour autoconf et automake), la génération de la documentation (en utilisant kdoc).

La page web de kdevelop se trouve à http://www.cs.uni-potsdam.de/~smeier/kdevelop/index.html

 

David Faure, étudiant INSA, développeur et

représentant officiel de KDE

Contact : faure@kde.org

Remerciements à Francois-Xavier Duranceau

pour la relecture.

 


© Copyright 2000 Diamond Editions/Linux magazine France. - Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1or any later version published by the Free Software Foundation; A copy of the license is included in the section entitled "GNU Free Documentation License".