## Comment écrire une extension pour Scribus

### Préface

La présente section vous montre comment écrire une extension pour Scribus. Les extensions sont des librairies qui sont chargées dans l'application principale au moment de l'exécution. Les extensions peuvent étendre, voire modifier le comportement de l'application sans nécessiter de réécriture ni de recompilation. Elles permettent d'ajouter des outils supplémentaires, de nouvelles fonctions d'importation et d'exportation, et plusieurs autres fonctionnalités évoluées.

Ce document présuppose une connaissance de base du langage C++. Vous devez savoir ce qu'est un fichier d'en-tête et comment fonctionne l'inclusion de fichier;aussi, vous devez posséder des connaissance sur l'héritage des classes et une certaine maîtrise du langage C++. La connaissance de Qt - principalement QString et QObject - sera également utile. Des questions comme les fonctions virtuelles et purement virtuelles, les déclarations "extern C", les détails de la gestion de mémoire, etc. sont éludées dans ce document. Vous n'avez pas à les connaître, mais elles pourraient vous aider à mieux suivre ce qui ce passe.

Nous n'allons pas tenter d'expliquer ici les détails du fonctionnement du système d'extensions de Scribus. Le présent document explique seulement comment écrire une extension. La documentation des texte d'aide `scplugin.h` et `pluginmanager.h` explique le fonctionnement du système.

### Où puis-je trouver les extensions Scribus ?

Scribus est livré avec un certain nombre d'extensions standard. Celles-ci seront installées en même temps que le programme Scribus et ses autres fichiers. Sous UNIX, les extensions seront installées sous le même préfixe que l'application principale. Sous Mac OS X elles sont incluses avec l'application. Si vous voulez savoir ce que font ces extensions, le meilleur moyen de le découvrir est de démarrer Scribus et d'aller dans `Fichier->Préférences` puis de cliquer sur l'icône "extensions". À partir de là, vous obtiendrez une liste des extensions installées, des types d'extensions associés et des emplacements des fichiers.

En plus des extensions livrées en standard avec Scribus, il est possible de compiler et d'installer des extensions obtenues ailleurs, ou d'écrire et d'ajouter la vôtre.

### Avant de commencer à coder

Supposons que vous avez eu une bonne idée pour améliorer Scribus et que vous êtes impatient d'écrire un code C++ de qualité. Patientez quelques minutes et lisez la présente section; vous pourriez gagner du temps et vous éviter des problèmes.

#### Important

Peut-être que vous êtes sur le point de "réinventer la roue", c'est-à-dire de ré-écrire ce que quelqu'un d'autre a déjà fait. Vous devriez vous joindre à la liste de diffusion et afficher votre idée, ou vous connecter au canal `#scribus` sur `irc.libera.chat`. Votre sujet sera soumis à l'étude, et vous obtiendrez probablement de l'aide et des idées des développeurs et des utilisateurs. Comme Scribus est distribué sous licence libre, vous pouvez travailler en solitaire, mais vous devriez au moins avoir une conversation d'introduction sur IRC ou envoyer un courriel à la liste de diffusion, ce qui pourrait vous éviter des heures de travail et des maux de tête. Nous voulons faciliter l'écriture d'extensions le plus possible pour les personnes intéressées.

#### Compatibilité

Scribus n'a pas une API fixe en C++ pour accommoder les extensions. Les versions ne sont pas compatibles en binaire, et les versions instables enfreignent souvent la compatibilité avec le code source. La compatibilité source n'est pas garantie actuellement, même entre des versions stables, lorsque des changements sont requis pour corriger un problème. Nous espérons redresser la situation dans l'avenir et fournir une API C++ stable pour le code externe. Pour l'instant, vous devez tenter d'intégrer l'essentiel de vos fonctionnalités dans un module séparé qui dépend le moins possible des rouages internes de Scribus.

Ce document traite de la mise en oeuvre d'une extension pour Scribus 1.3.1cvs. Les exigences sont radicalement différentes de celles des versions 1.2.x. Les changements futurs devraient être moins importants.

Il est peu pratique de prévoir l'écriture d'une extension pouvant fonctionner sous les versions 1.2.x et 1.3.x de Scribus.

### Démarrage rapide

Il n'est pas trop difficile de se mettre à écrire une extension. La documentation ci-dessous décrit l'implantation d'une extension et vous renvoie à des compléments d'information au besoin. Un "modèle d'extension" vous est fourni, et vous pouvez en faire une copie au moment de débuter la programmation. Des instructions de base sont incluses dans le fichier et, en cas doute, vous pouvez consulter ce document.

Nous allons bâtir l'extension comme un composant de Scribus. C'est la manière la plus simple de commencer, même si vous prévoyez de la distribuer séparément plus tard (voir plus loin). Pour commencer à travailler sur une extension (de type Action) :

- Copiez `scribus/plugins/myplugin` dans `scribus/plugins/pluginname` (où "pluginname" est le nom que vous voulez donner à votre extension). pluginname doit être un identifiant C valide - je suggère d'utiliser seulement les caractères minuscules.
- Éditez `scribus/plugins/Makefile.am` et ajoutez "pluginname" à Makefile.am. Cela indique au système d'intégration de Scribus de compiler votre extension.
- Renommez tous les fichiers dans `scribus/plugins/pluginname/` de `myplugin` en `pluginname`, par exemple `myplugin.h` en `pluginname.h`. Ne renommez pas Makefile.am.
- Renommez `myplugin` là où il figure dans les fichiers en `pluginname`, par exemple `myplugin_getPluginAPIVersion()` en `pluginname_getPluginAPIVersion()`. Faites de même pour `MyPlugin` et `MYPLUGIN`. Sous UNIX, vous pouvez utiliser cette commande :
  `sed -i -e "s/myplugin/pluginname/g" -e "s/MyPlugin/PluginName/g" -e "s/MYPLUGIN/PLUGINNAME/g" myplugin*`
  (tout sur une ligne, exécuté à partir de `scribus/plugins/pluginname/`).

Vous êtes maintenant prêt à commencer à travailler sur votre extension. Premièrement, vous devez entrer des renseignements à propos de votre extension dans `pluginname.cpp` :

- Dans `PluginName::languageChange()` :
  - Changez `m_actionInfo.text` pour le texte de l'élément de menu qui doit lancer votre extension.
  - Changez `m_actionInfo.menu` pour le nom du menu qui doit afficher cet élément. Voir FIXME where???? FIXME pour une liste de noms de menu.
  - Pour activer un raccourci clavier, décommentez `m_actionInfo.keySequence` et inscrivez-y votre raccourci préféré. L'exemple ci-dessousdevrait vous montrer comment cela fonctionne.
- Changez le nom inscrit dans `PluginName::fullTrName()` pour le nom de votre extension tel que vous voulez qu'il figure à l'écran Aide->À propos des extensions et dans le panneau de gestion des extensions (dans les préférences).
- Si vous souhaitez afficher de l'information (p. ex. l'auteur et la description) à l'utilisateur qui clique sur Aide->À propos des extensions, remplissez les zones prévues à cet effet en assignant les membres de la section `À propos`. Pour connaître l'information possible, consultez la définition de `AboutData` dans `scplugin.h`.

Vous avez terminé la mise en place de l'extension et vous pouvez maintenant commencer à programmer. Votre code doit être placé dans `pluginnameimpl.cpp` et `pluginnameimpl.h`. Le code existant devrait afficher une boîte de dialogue contenant un message.

Pour compiler l'extension, il suffit d'exécuter une nouvelle fois `make -f Makefile.cvs`, `./configure`, et `make` dans le répertoire supérieur de Scribus. Une fois la compilation terminée, exécutez `make install` et démarrez Scribus. Votre extension doit maintenant figurer dans le gestionnaire d'extensions (dans les préférences) et doit être associée à un élément de menu. Si vous appuyez sur l'élément de menu, vous devriez obtenir une boîte de dialogue.

### Bâtir les extension en dehors de la hiérarchie de Scribus

#### Utilisation rapide et directe de QMake

Avertissement

Attention, il est facile d'utiliser un projet qmake, mais il ne s'agit pas nécessairement de la méthode standard pour distribuer un logiciel sur une plateforme Linux. Le processus sert à titre d'exemple seulement, pour le développement. Quand vous créerez votre progiciel opérationnel, sans bogues, prenez le temps de préparer la distribution complète automagic (autoconf, automake) tel que décrit dans la prochaine section.

Compilons maintenant l'extension (ce n'est pas aussi simple que de taper `gcc myplugin.cpp` ;). Voici un procédé simple : qmake de Qt (parce que certaines personnes hésitent à utiliser autoconf et automake en raison de leur complexité). Nota : vous devrez créer un fichier vide `config.h` avant d'exécuter ces étapes.

>     #qmake -project

Maintenant que le fichier projet est créé, nous allons y apporter quelques petits changements.

>     ######################################################################
>     # Automatically generated by qmake (1.06c) Sun Dec 14 13:32:11 2003
>     ######################################################################

>     #change TEMPLATE = app. Nous ne travaillons pas sur l'application, seulement sur l'extension
>     TEMPLATE = lib
>     INCLUDEPATH += .
>     #Comme nous travaillons avec Scribus, nous avons besoin des inclusions de Scribus aussi.
>     INCLUDEPATH += /home/subzero/devel/Scribus/include/Scribus/
>     #Et Scribus doit utiliser freetype2.
>     #Donc nous devons le lier aussi. Utilisez les chemins retournés par
>     ##freetype-config --cflags and --libs
>     INCLUDEPATH += /usr/include/freetype2
>     LIBS += -lfreetype -lz

>     # Entrée
>     #crée un fichier config.h vide
>     HEADERS += myplugin.h config.h
>     SOURCES += myplugin.cpp

Après ces changements, vous êtes prêt à compiler

>     #qmake
>     #make

Exécuter Qmake crée le Makefile et, en l'exécutant, vous compilez votre extension.

Ensuite : Copiez seulement les fichiers *so* dans le répertoire d'extensions de Scribus et lancez Scribus. Vous lirez "Do Nothing Plugin" dans le menu Extra.

Il est clair que vous devez utiliser une autre méthode pour distribuer votre code aux autres utilisateurs - certains utilisent les fichiers autogénérés qmake pro, d'autres, la combinaison autoconf/automake.

#### Distribuez-le! (autrement dit compilez-le! 2e édition)

Qmake est facile à utiliser et convient bien à un développement rapide, mais il y a une manière standard de compiler ou de distribuer un logiciel pour Linux, *BSD, etc. : autoconf et automake. Nous désignerons ces deux programmes sous l'acronyme automagic dans le texte qui suit.

Pour utiliser automagic avec succès, vous aurez besoin d'un pentagramme dessiné à la craie sur le sol et orienté au nord (Carrefour, 2€), d'un costume de diablotin rouge et noir (Hugo Boss, 2000€) et d'un pingouin sacrifié sur l'autel domestique (une heure de frayeur au zoo le plus proche). Ce n'était qu'une blague... ne faites pas de mal aux mignons pingouins, ce n'est pas nécessaire!!

Téléchargez l'exemple `donothingplugin-1.0.tar.gz` à partir de http://docs.scribus.net, décomprimez-le et parcourez son contenu.

Quand vous accédez au répertoire principal, vous apercevez beaucoup de fichiers et de répertoires. Attention : Ne changez rien dans le répertoire admin. Ce contenu vous est INTERDIT!

Puisque vous avez lu la documentation d'automagic (sûrement), vous savez que chaque répertoire de votre projet contient un fichier important appelé `Makefile.am`. Voici un court exemple commenté :

>     # indique où l'extension sera installée
>     pluginsdir = $(prefix)/lib/scribus/plugins
>     # spécifie les inclusions additionnelles pour la compilation
>     AM_CPPFLAGS = -I$(prefix)/include/scribus
>     # spécifie les répertoires à parcourir (avec les sous-niveaux)
>     SUBDIRS = translation doc
>     # nom de l'extension = librairie
>     plugins_LTLIBRARIES = libscribusvlna.la
>     # join toutes les inclusions
>     INCLUDES = $(LIBFREETYPE_CFLAGS) $(all_includes)
>     # divers relatifs à la librairie - symlinks, etc.
>     libscribusvlna_la_LDFLAGS = -version-info 0:0:0
>     libscribusvlna_la_METASOURCES = AUTO
>     #
>     # liste des fichiers source de votre projet
>     libscribusvlna_la_SOURCES = frame.cpp selection.cpp vlnadialog.cpp vlnapage.cpp svlna.cpp
>     EXTRA_DIST = frame.cpp selection.cpp svlna.cpp vlnadialog.cpp vlnapage.cpp frame.h /
>       selection.h svlna.h vlnadialog.h vlnapage$
>     # comment compiler
>     KDE_OPTIONS = qtonly
>     AM_LDFLAGS =    -s $(LIBFREETYPE_LIBS)

Pour récapituler : Si vous prenez le fichier `donothingplugin-1.0.tar.gz` (si vous le renommez, bien sûr) et si vous analysez le contenu des fichiers `Makefile.am`, vous obtiendrez un progiciel opérationnel.

Il reste une dernière chose à faire. Vous devez aussi spécifier la structure de répertoire dans le fichier `configure.in` du répertoire racine du projet :

>     AC_CONFIG_FILES([Makefile])
>     AC_CONFIG_FILES([svlna/Makefile])
>     AC_CONFIG_FILES([svlna/translation/Makefile])
>     AC_CONFIG_FILES([svlna/doc/Makefile])

Et maintenant, comment ça marche?

Premièrement lancez `make -f Makefile.dist` dans le répertoire racine. Les modèles de `Makefile.in` sont créés (comme par magie).

Ensuite, `./configure ; make ; make install` devrait fonctionnner pour vous. Profitez-en.

### Complément d'information

À ce stade, vous devriez lire `scplugin.h` et comprendre le texte d'aide. Pour des précisions sur le fonctionnement du système d'extensions ici. Surtout, vous apprendrez la procédure en lisant les autres extensions et le code central de Scribus.

#### Comment conserver les préférences de votre extension :

Scribus fournit une API de préférences pour les développeurs d'extensions qui permet de conserver les données entre les démarrages de Scribus. Il y a deux types de formats disponibles : Paires "clé-valeur" et Tables.

Tout d'abord, vous devrez obtenir l'objet `PrefsContext` pour votre extension. Ensuite, vous pouvez extraire de `PrefsContext` une valeur de clé spécifique ou vous pouvez solliciter `PrefsTable` par son nom. Voici un court exemple qui utilise les paires clé-valeur.

    #include <prefsfile.h>
    #include <prefscontext.h>

    extern PrefsFile* prefsFile;

    PrefsContext *myPluginPrefs = prefsFile->getPluginContext("MyPlugin");

    // la valeur par défaut 1 sera utilisée si "i" n'existe pas déjà
    int i = myPluginPrefs->getInt("i");

    // la valeur par défaut "chien" sera utilisée si "s" n'existe pas
    QString s = myPluginPrefs->get("s", "chien");

    myPluginPrefs->set("i", 221);
    myPluginPrefs->set("s", "chat");

#### Modèle objet de Scribus

Le code source de Scribus n'est pas documenté en détail. Beaucoup d'efforts sont déployés pour corriger la situation, mais étant donné la taille du code, cela prend du temps. Essayez de suivre l'évolution en vous basant sur les fichiers d'en-tête et sur le code. En cas de doute, n'hésitez pas à consulter le canal IRC ou à poser des questions via la liste de diffusion, et vous obtiendrez probablement une réponse. Soyezpatient, car nous ne sommes pas toujours disponibles ou présents sur IRC.

Si vous souhaitez améliorer la documentation ou corriger l'API de génération doxygen api, nous vous en saurons gré.

Il est important de noter que l'accès au coeur de l'application Scribus passe par l'aide du pointeur statique global `ScApp`, déclaré dans `scribus.h`. Attention à la confusion : c'est aussi une sous-classe de QMainWindow. Vous pouvez également aller à la sous-classe QApplication utilisée comme `ScQApp` à partir de `scribusapp.h`.

Certains sous-systèmes majeurs sont des classes uniques qui sont accessibles via ClassName::instance() . Il y a par exemple `PluginManager`, `ScPaths`, ainsi qu'un nombre croissant d'autres classes. L'avantage de cette approche est de vous permettre d'interagir avec ces classes sans pénétrer dans les rouages de ScApp.

### Liens associés aux extensions

Documentation de Qt par Trolltech
Documentation de QMake par Trolltech
Exemple automake/autoconf
o