% vim: set textwidth=78 autoindent:

% \section{Writing a QGIS Plugin in Python}
\section{Écrire une extension en Python pour QGIS}

% when the revision of a section has been finalized,
% comment out the following line:
% \updatedisclaimer

% In this section you find a beginner's tutorial for writing a QGIS Python
% plugins. It is based on the workshop "Extending the Functionality of QGIS
% with Python Plugins" held at FOSS4G 2008 by Dr. Marco Hugentobler, Dr. Horst
% Düster and Tim Sutton.
Dans cette section vous trouverez un cours pour débutant pour écrire des
extensions Python Pour QGIS. Il est basé sur le workshop "Étendre les
fonctionnalités de QGIS avec des extensions en Python" réalisé lors du FOSS4G 2008
par  Dr. Marco Hugentobler, Dr. Horst Düster et Tim Sutton.

% Apart from writing a QGIS Python plugin, it is also possible to use PyQGIS
% from a python command line console which is mainly interesting for debugging
% or to write standalone applications in Python with their own user interfaces
% using the functionality of the QGIS core library.
En plus d'écrire des extensions en python pour QGIS, il est également possible
d'utiliser PyQGIS dans une console de ligne de commande python qui est
principalement utilisée pour déboguer ou pour écrire des applications
indépendantes en Python avec leurs propres interfaces en utilisant la
bibliothèque principale de QGIS.

% \subsection{Why Python and what about licensing}
\subsection{Pourquoi Python et à propos de la licence}

% Python is a scripting language which was designed with the goal of being easy
% to program. It has a mechanism that automatically releases memory that is no
% longer used (garbagge collector). A further advantage is that many programs
% that are written in C++ or Java offer the possibility to write extensions in
% Python, e.g. OpenOffice or Gimp. Therefore it is a good investment of time to
% learn the Python language.
Python est un langage de script qui a été conçu afin d'être facile à écrire. Il
a un mécanisme qui nettoie automatiquement la mémoire qui n'est plus utilisée
(collecteur de déchet). Un avantage supplémentaire est que plusieurs programmes
écrits en C++ ou Java offrent la possibilité d'écrire des extensions en Python,
comme OpenOffice.org ou GIMP. C'est donc un bon investissement d'apprendre le
langage Python.

% PyQGIS plugins use functionality of libqgis\_core.so and libqgis\_gui.so. As
% both are licensed under GNU GPL, QGIS Python plugins must be licenced under
% the GPL, too. This means you may use your plugins for any purpose and you are
% not forced to publish them. If you do publish them however, they must be
% published under the conditions of the GPL license. 
Les extensions PyGQIS utilisent les fonctionnalités de libqgis\_core.so et
libqgis\_gui.so. Comme les deux sont publiés sous licence GPL, les extensions
Python pour QGIS doivent être publiés sous licence GPL également. Cela signifie
que vous pouvez utiliser votre extension dans n'importe quel but et vous n'êtes pas
obligé de les publier. Toutefois, si vous voulez les publier, ils doivent l'être
dans les conditions de la licence GPL.

% \subsection{What needs to be installed to get started}
\subsection{ce que vous avez besoin d'installer pour démarrer}

% On the lab computers, everything for the workshop is already installed. If
% you program Python plugins at home, you will need the following libraries and
% programs:
Sur les ordinateurs du labs, tout ce qui est nécessaire est déjà installé. Si
vous programmez chez vous, vous aurez besoin des bibliothèques et programmes
suivants :

\begin{itemize}
\item QGIS ;
\item Python ;
\item Qt ;
\item PyQT ;
% \item PyQt development tools
\item Outils de développement PyQt.
\end{itemize}

% If you use Linux, there are binary packages for all major distributions. For
% Windows, the PyQt installer already contains Qt, PyQt and the PyQt
% development tools.
Si vous utilisez un système Linux ou équivalent, il existe des binaires pour
toutes les distributions majeures. Pour les utilisateurs de Windows,
l'installateur PyQT contient déjà Qt, PyQT et les outils de développement de
PyQT.

%\subsection{Programming a simple PyQGIS Plugin in four steps}\label{subsec:pyfoursteps}
\subsection{Programmer une extension PyQGIS en quatre étapes}\label{subsec:pyfoursteps}

% The example plugin is intentionally kept simple. It adds a button to the menu
% bar of QGIS. If the button is clicked, a file dialog appears where the user
% may load a shape file.
Notre exemple d'extension restera intentionnellement simple. Il ajoute un bouton à
la barre de menu de QGIS. Si le bouton est cliqué, une boîte de dialogue
apparait dans laquelle un utilisateur peut charger un fichier shape.

% For each python plugin, a dedicated folder that contains the plugin files
% needs to be created. By default, QGIS looks for plugins in
% two locations: \$QGIS\_DIR/share/qgis/python/plugins and
% \$HOME/.qgis/python/plugins. Note that plugins installed in the latter
% location are only visible for one user.
Pour chaque extension Python, un répertoire dédié qui contient les fichiers du
extensions est nécessaire. Par défaut, QGIS cherche des extensions dans
\$QGIS\_DIR/share/qgis/python/plugins et \$HOME/.qgis/python/plugins.
Remarquez que les extensions installés dans ce dernier  sont seulement visible
par l'utilisateur.

% \minisec{Step 1: Make the plugin manager recognise the plugin}
\minisec{Étape 1 : reconnaissance d'une extension par le gestionnaire d'extension}

% Each Python plugin is contained in its own directory. When QGIS starts up it
% will scan each OS specific subdirectory and initialize any plugins it finds.
Chaque extension Python est contenu dans son propre répertoire. Lors de démarrage
de QGIS celui-ci parcourra chaque sous-répertoire spécifique au système et
initialisera toutes les extensions qu'il trouvera.

\begin{itemize}
% \item \nix{Linux and other unices}:\\
\item \nix{Linux et autre UNIX} : \\
./share/qgis/python/plugins \\
/home/\$USERNAME/.qgis/python/plugins
\item \osx{Mac OS X}:\\
./Contents/MacOS/share/qgis/python/plugins \\
/Users/\$USERNAME/.qgis/python/plugins
\item \win{Windows}:\\
C:\textbackslash Program Files\textbackslash QGIS\textbackslash python\textbackslash plugins \\
C:\textbackslash Documents and Settings\textbackslash\$USERNAME\textbackslash .qgis\textbackslash python\textbackslash plugins

\end{itemize}

% Once that's done, the plugin will show up in the
% \dropmenuopttwo{mActionShowPluginManager}{Plugin Manager...}
Une fois réalisé, le plugin s'affichera dans
\dropmenuopttwo{mActionShowPluginManager}{gestionnaire de plugin...}

% \begin{Tip}\caption{\textsc{Two QGIS Python Plugin folders}}
\begin{Astuce}\caption{\textsc{Deux répertoires de plugins Python}}
% \qgistip{There are two directories containing the python plugins.
% \$QGIS\_DIR/share/qgis/python/plugins
% is designed mainly for the core plugins while \$HOME/.qgis/python/plugins for
% easy installation of the external plugins. Plugins in the home location are
% only visible for one user but also mask the core plugins with the same name,
% what can be used to provide main plugin updates
\qgistip{Il y a deux répertoires contenant les extensions en python.
\$QGIS\_DIR/share/qgis/python/plugins a été conçu principalement pour les
extensions principales tandis que \$HOME/.qgis/python/plugins pour les extensions
seulement visibles par l'utilisateur, mais aussi masque les extensions principales de
même nom, ce qui peut être pratique pour les mettre à jour.
}
\end{Astuce}

% To provide the neccessary information for QGIS, the plugin needs to implement
% the methods \method{name()}, \method{description()}, \method{version()},
% \method{qgisMinimumVersion()} and \method{authorName()} which return
% descriptive strings. The \method{qgisMinimumVersion()} should return a simple
% form, for example ``1.0``. A plugin also needs a method
% \method{classFactory(QgisInterface)} which is called by the plugin manager to
% create an instance of the plugin. The argument of type QGisInterface is used
% by the plugin to access functions of the QGIS instance. We are going to work
% with this object in step 2.
Pour fournir les informations nécessaires pour QGIS, le plugin nécessite
d'implémenter les méthodes \method{name()}, \method{description()} et
\method{version()} qui renvoient les chaînes descriptives.
\method{qgisMinimumVersion()} doit renvoyer une forme simple, par exemple
``1.0``. Une extension nécessite également une méthode
\method{classFactory(QgisInterface)} qui est appelée par le gestionnaire d'extension
 pour créer une instance de l'extension. L'argument de type QGisInterface est
utilisé par l'extension pour accéder aux fonctions de l'instance QGIS. Nous allons
travailler avec cet objet à l'étape 2.

% Note that, in contrast to other programing languages, indention is very
% important. The Python interpreter throws an error if it is not correct.
Notez que, contrairement aux autres langages de programmation, l'indentation est
très importante. L'interpréteur Python renvoie une erreur si elle n'est pas
correcte.

% For our plugin we create the plugin folder 'foss4g\_plugin' in
% \filename{\$HOME/.qgis/python/plugins}. Then we add two new textfiles into
% this folder, \filename{foss4gplugin.py} and \filename{\_\_init\_\_.py}.
Pour nos plugins nous  créons un répertoire de plugin 'foss4g\_plugin' dans
\filename{\$HOME/.qgis/python/plugins}. Puis nous ajoutons deux nouveaux
fichiers textes dans ce répertoire \filename{foss4gplugin.py} et
\filename{\_\_init\_\_.py}.

% The file \filename{foss4gplugin.py} contains the plugin class:
Le fichier \filename{foss4gplugin.py} contient la classe de l'extension :

\begin{verbatim}
# -*- coding: utf-8 -*-
# Import des bibliothèques PyQt et QGIS
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
# Initialisation des ressources Qt à partir du fichier resources.py
import resources

class FOSS4GPlugin:

def __init__(self, iface):
# Sauve la référence à l'interface QGIS
  self.iface = iface

def initGui(self):
  print 'Initialising GUI'

def unload(self):
  print 'Unloading plugin'
\end{verbatim}

% The file \filename{\_\_init\_\_.py} contains the methods \method{name()},
% \method{description()}, \method{version()}, \method{qgisMinimumVersion()}
% and \method{authorName()} and \method{classFactory}. As
% we are creating a new instance of the plugin class, we need to import the
% code of this class:
Le fichier \filename{\_\_init\_\_.py} contient les méthodes \method{name()},
\method{description()}, \method{version()}, \method{qgisMinimumVersion()}
et \method{authorName()} évoqués plus haut. Comme nous somme en train de créer
une nouvelle instance de la classe plugin (extension)s, nous devons importer le code de cette
classe :

\begin{verbatim}
# -*- coding: utf-8 -*-
from foss4gplugin import FOSS4GPlugin
def name():
  return "FOSS4G example"
def description():
  return "A simple example plugin to load shapefiles"
def version():
  return "0.1"
def qgisMinimumVersion():
  return "1.0"
def authorName():
  return "John Developer"
def classFactory(iface):
  return FOSS4GPlugin(iface)
\end{verbatim}

% At this point the plugin already the neccessary infrastructure to appear in
% the QGIS \dropmenuopttwo{mActionShowPluginManager}{Plugin Manager...} to be
% loaded or unloaded.
Maintenant l'extension possède l'infrastructure nécessaire pour apparaître dans le
\dropmenuopttwo{mActionShowPluginManager}{gestionnaire d'extension} QGIS et être
chargé/déchargé.

% \minisec{Step 2: Create an Icon for the plugin}
\minisec{Étape 2 : Créer un icône pour le plugin}

% To make the icon graphic available for our program, we need a so-called
% resource file. In the resource file, the graphic is contained in hexadecimal
% notation. Fortunately, we don't need to care about its representation because
% we use the pyrcc compiler, a tool that reads the file
% \filename{resources.qrc} and creates a resource file. 
Pour que votre icône graphique soit disponible dans votre programme, nous avons
besoin d'un fichier ressource. Dans ce fichier ressource, le graphique est
contenu sous forme hexadécimale. Heureusement, nous n'avons pas à nous occuper de
sa représentation parce que nous utilisons le compilateur pyrcc, un outil qui
lit le fichier \filename{resources.qrc} et créé un fichier ressource.

% The file \filename{foss4g.png} and the \filename{resources.qrc} we use in
% this little workshop can be downloaded from
% \url{http://karlinapp.ethz.ch/python\_foss4g}. Move these 2 files into the
% directory of the example plugin
% \filename{\$HOME/.qgis/python/plugins/foss4g\_plugin} and enter there: pyrcc4
% -o resources.py resources.qrc.
Le fichier \filename{foss4g.png} et le ficher \filename{resources.qrc} peuvent
être téléchargé à partir de \url{http://karlinapp.ethz.ch/python\_foss4g}.
Déplacez ces fichiers dans le répertoire de l'extension exemple
\filename{\$HOME/.qgis/python/plugins/foss4g\_plugin} et entrez : pyrcc4 -o
ressources.py ressources.qrc.

% \minisec{Step 3: Add a button and a menu}
\minisec{Étape 3 : ajouter un bouton au menu}

% In this section, we implement the content of the methods \method{initGui()}
% and \method{unload()}. We need an instance of the class \classname{QAction}
% that executes the \method{run()} method of the plugin. With the action object,
% we are then able to generate the menu entry and the button:
Dans cette partie, nous allons implémenter le contenu des méthodes
\method{initGui()} et \method{unload()}. Nous avons besoins d'une instance de la
classe \classname{QAction} qui exécute la méthode \method{run()} de l'extension. Avec
l'objet action, nous somme alors capable de générer l'entrée du menu et le
bouton :

\begin{verbatim}
import resources

  def initGui(self):
    # Créer une action qui démmarera la configuration du plugin
    self.action = QAction(QIcon(":/plugins/foss4g_plugin/foss4g.png"), "FOSS4G
plugin",self.iface.getMainWindow())
    # Connecter l'action à la méthode run
    QObject.connect(self.action, SIGNAL("activated()"), self.run)

    # Ajoutez le bouton de la barre d'outil et l'entrée du menu
    self.iface.addToolBarIcon(self.action)
    self.iface.addPluginMenu("FOSS-GIS plugin...", self.action)

    def unload(self):
    # Supprime les entrées des menu et de l'icône
    self.iface.removePluginMenu("FOSSGIS Plugin...", self.action)
    self.iface.removeToolBarIcon(self.action)
\end{verbatim}

% \minisec{Step 4: Load a layer from a shape file}
\minisec{Étape 4 : charger une couche à partir d'un shapefile}

% In this step we implement the real functionality of the plugin in the
% \method{run()} method. The Qt4 method \method{QFileDialog::getOpenFileName}
% opens a file dialog and returns the path to the chosen file. If the user
% cancels the dialog, the path is a null object, which we test for. We then
% call the method \method{addVectorLayer} of the interface object which loads
% the layer. The method only needs three arguments: the file path, the name of
% the layer that will be shown in the legend and the data provider name. For
% shapefiles, this is 'ogr' because QGIS internally uses the OGR library to
% access shapefiles:
Dans cette étape nous allons implémenter les fonctionnalités réelles de l'extension
dans la méthode method{run()} La méthode Qt4
\method{QFileDialog::getOpenFileName} ouvre une boîte de dialogue et renvoie le
chemin du fichier choisit. Si l'utilisateur annule la boîte de dialogue, le
chemin est un objet null, que nous allons tester. Puis nous appelons la méthode
\method{addVectorLayer} de l'objet interface qui charge la couche. La méthode
possède seulement trois arguments : le chemin du fichier, le nom de la couche
qui sera affichée dans la légende et le nom du fournisseur de données. Pour les
Shapefiles, c'est 'ogr' car QGIS utilise en interne la bibliothèque OGR pour
accéder aux shapefiles :

\begin{verbatim}
    def run(self):
    fileName = QFileDialog.getOpenFileName(None,QString.fromLocal8Bit("Select a file:"),
 "", "*.shp *.gml")
    if fileName.isNull():
      QMessageBox.information(None, "Cancel", "File selection canceled")
      else:
      vlayer = self.iface.addVectorLayer(fileName, "myLayer", "ogr")
\end{verbatim}


% \subsection{Committing the plugin to repository}
\subsection{Comiter l'extension dans un dépôt}

% If you have written a plugin you consider to be useful and you want to share
% with other users you're welcome to upload it to the QGIS User-Contributed
% Repository.
Si vous avez écrit une extension vous pouvez trouver utile et vouloir le partager
avec d'autres utilisateurs, vous êtes invité à le télécharger sur le dépôt de
contribution des utilisateurs de QGIS.
\begin{itemize}
% \item Prepare a plugin directory containing only necessary files (ensure that
% there is no compiled .pyc files, Subversion .svn directories etc).
\item Préparer un répertoire d'extensions contenant les fichiers nécessaires
(assurez-vous qu'il n'y ait pas de fichiers .pyc compilés, de répertoires .svn
de subversion, etc.)
% \item Make a zip archive of it, including the directory. Be sure the zip file
% name is exactly the same as the directory inside (except the .zip extension of
% course). In other case the Plugin Installer won't be able to relate the
% available plugin with its locally installed instance.
\item Faîtes une archive zip, incluant le répertoire. Assurez-vous que le nom du
fichier zip est exactement le même que le répertoire à l'intérieur (sauf bien
sur avec l'extension .zip). Sinon l'installateur d'extension ne sera pas capable
de relier l'extension disponible avec celui installé localement.
% \item Upload it to the repository: \url{http://pyqgis.org/admin/contributed}
% (you will need to register at first time). Please pay attention when filling
% the form. Especially the Version Number field is often filled wrongly what
% confuses the Plugin Installer and causes false notifications of available
% updates.
\item Téléchargez le dans le dépôt : \url{http://pyqgis.org/admin/contributed}
(vous devez vous enregistrer la première fois). S'il vous plait, ayez une
attention particulière lors du remplissage du formulaire. Spécialement le champ
du numéro de version qui est souvent remplie incorrectement ce qui pose
problème à l'installateur d'extension et cause de fausse notification de mise à
jour disponible.
\end{itemize}

% \subsection{Further information}
\subsection{Plus d'informations}

% As you can see, you need information from different sources to write PyQGIS
% plugins. Plugin writers need to know Python and the QGIS plugin interface as
% well as the Qt4 classes and tools. At the beginning it is best to learn from
% examples and copy the mechanism of existing plugins. Using the QGIS plugin
% installer, which itself is a Python plugin, it is possible to download a lot
% of existing Python plugins and to study their behaviour.
Comme vous pouvez voir, vous avez besoin d'informations de différentes sources
pour écrire des extensions PyQGIS. Les développeurs de plugins doivent connaître
Python et l'interface d'extension de QGIS ainsi que les classes et outils de Qt4.
Au début il est important d'apprendre à partir des exemples et de copier les
mécanismes d'extensions existants. En utilisant l'installateur d'extensionns de QGIS,
qui est lui même une extension Python, il est possible de télécharger plusieurs
extensions et de les étudier.

% There is a a collection of online documentation that may be usefull for
% PyQGIS programers:
Il y a de nombreuses documentations qui peuvent être utile pour les programmeurs de
PyQGIS :

\begin{itemize}
\item wiki de QGIS : \url{http://wiki.qgis.org/qgiswiki/PythonBindings}
\item Documentation de l'API QGIS :
\url{http://doc.qgis.org/index.html}
\item Documentation Qt : \url{http://doc.trolltech.com/4.3/index.html}
\item PyQt : \url{http://www.riverbankcomputing.co.uk/pyqt/}
\item Cours sur Python : \url{http://docs.python.org/}
\item Un livre sur les SIG bureautiques et QGIS. Il contient un chapitre sur la
programmation d'extension PyQGIS :
\url{http://www.pragprog.com/titles/gsdgis/desktop-gis} 
\end{itemize}

% You can also write plugins for QGIS in C++. See Section \ref{cpp_plugin} for
% more information about that.
Vous pouvez également écrire des extensions pour QGIS en C++. Lisez la section
\ref{cpp_plugin} pour plus d'information là dessus.

