1. Standards de développement QGIS
Ces standards doivent être suivis par tous les développeurs de QGIS.
1.1. Classes
1.1.1. Noms
Les classes dans QGIS commencent par Qgs et sont nommées en utilisant le camel case.
Exemples:
QgsPoint
QgsMapCanvas
QgsRasterLayer
1.1.2. Membres
Les noms des membres de classe commencent par un m minuscule et sont composés de majuscules et de minuscules.
mMapCanvas
mCurrentExtent
Tous les membres d’une classe doivent être privés. Il est FORTEMENT déconseillé de déclarer des membres publics. Les membres protégés doivent être évités pour que le membre soit accessible depuis des sous-classes Python, car les membres protégés ne peuvent pas être utilisés à partir des liaisons Python.
Les noms des membres mutables des classes statiques doivent commencer par un s
minuscule, mais les noms des membres constants des classes statiques doivent être en majuscules :
sRefCounter
DEFAULT_QUEUE_SIZE
1.1.3. Fonctions d’accesseurs
Les valeurs des membres de la classe doivent être obtenues via les fonctions d’accesseur. La fonction doit être nommée sans préfixe « get ». Les fonctions d’accesseur pour les deux membres privés ci-dessus seraient:
mapCanvas()
currentExtent()
Assurez-vous que les accesseurs sont correctement marqués avec const
. Le cas échéant, cela peut nécessiter que les variables membres du type de valeur en cache soient marquées avec mutable
.
1.1.4. Fonctions
Les noms de fonction commencent par une minuscule et se composent de minuscules/majuscules. Le nom de fonction devrait évoquer sa fonctionnalité.
updateMapExtent()
setUserOptions()
Par souci de cohérence avec l’API QGIS existante et avec l’API Qt, les abréviations doivent être évitées. Par exemple, setDestinationSize
au lieu de setDestSize
, setMaximumValue
au lieu de setMaxVal
.
Les acronymes devraient également être nommés en utilisant le camel case pour la cohérence. Par exemple, setXml
au lieu de setXML
.
1.1.5. Arguments de la fonction
Les noms des arguments de fonctions doivent être descriptifs. Ne pas utiliser de noms à une seule lettre (p. ex. setColor( const QColor& color )
plutôt que setColor( const QColor& c )
).
Portez une attention particulière à quand les arguments devraient être passés par référence. À moins que les objets argument soient petits et trivialement copiés (tels que les objets QPoint), ils doivent être passés par une référence const. Par souci de cohérence avec l’API Qt, même les objets partagés implicitement sont passés par une référence const (p. ex. setTitle( const QString& title )
au lieu de setTitle( QString title )
.
1.1.6. Valeurs de retour de la fonction
Renvoie les objets petits et trivialement copiés en tant que valeurs. Les objets plus grands doivent être renvoyés par une référence const. La seule exception à cela porte sur les objets implicitement partagés, qui sont toujours renvoyés par valeur. Renvoie QObject
ou les objets sous-classes en tant que pointeurs.
int maximumValue() const
const LayerSet& layers() const
QString title() const
(QString
est implicitement partagée)QList< QgsMapLayer* > layers() const
(QList
est implicitement partagé)QgsVectorLayer *layer() const;
(QgsVectorLayer
hérite deQObject
)QgsAbstractGeometry *geometry() const;
(QgsAbstractGeometry
est abastrait et nécessitera probablement d’être typé)
1.2. Documentation de l’API
Il est requis d’écrire la documentation API pour chaque classe, méthode, enumération et autres codes disponible dans l’API publique.
QGIS uses Doxygen or documentation. Write descriptive and meaningful comments that give a reader information about what to expect, what happens in edge cases and give hints about other interfaces he could be looking for, best practices and code samples.
1.2.1. Méthode
La description des méthodes doit être écrite sous forme descriptive en utilisant la 3ème personne. Les méthodes nécessitent le mot-clé \since
qui définit quand elles ont été introduites. Vous devrez en outre ajouter les tags \since
aux changements importants introduits ultérieurement.
/**
* Cleans the laundry by using water and fast rotation.
* It will use the provided \a detergent during the washing programme.
*
* \returns True if everything was successful. If false is returned, use
* \link error() \endlink to get more information.
*
* \note Make sure to manually call dry() after this method.
*
* \since QGIS 3.0
* \see dry()
*/
1.2.2. Variables membres
Les variables membres devraient normalement être dans la section private
et rendues accessibles via les getters et les setters. Une exception à cela existe pour les conteneurs de données comme pour la remontée d’erreurs. Dans ces cas, ne préfixez pas les membres par un m
.
/**
* \ingroup core
* Represents points on the way along the journey to a destination.
*
* \since QGIS 2.20
*/
class QgsWaypoint
{
/**
* Holds information about results of an operation on a QgsWaypoint.
*
* \since QGIS 3.0
*/
struct OperationResult
{
QgsWaypoint::ResultCode resultCode; //!< Indicates if the operation completed successfully.
QString message; //!< A human readable localized error message. Only set if the resultCode is not QgsWaypoint::Success.
QVariant result; //!< The result of the operation. The content depends on the method that returned it. \since QGIS 3.2
};
};
1.3. Qt Designer
1.3.1. Les classes générées
Les classes QGIS générées depuis des fichiers Qt Designer (.ui) doivent avoir comme suffixe -Base. Cela permet d’identifier la classe comme étant une classe générée.
Exemples:
QgsPluginManagerBase
QgsUserOptionsBase
1.3.2. Dialogues
Toutes les boîtes de dialogue doivent intégrer des info-bulles d’aide pour toutes les icônes de la barre d’outils ainsi que pour les autres widgets appropriés. Ces info-bulles apportent beaucoup à la découverte des fonctionnalités pour les utilisateurs débutants et confirmés.
Assurez-vous que l’ordre des onglets pour les widgets est bien mis à jour à chaque fois que la boîte de dialogue de la couche change.
1.4. Fichiers C++
1.4.1. Noms
L’intégration du C++ et des fichiers en-têtes doivent respectivement avoir une extension en .cpp et en .h. Les fichiers doivent être nommés intégralement en minuscule et, dans le cas des classes, doivent correspondre avec le nom des classes.
Exemple : Pour la classe QgsFeatureAttribute
, les fichiers sources sont qgsfeatureattribute.cpp
et qgsfeatureattribute.h
Note
Si le cas précédent n’est pas assez claire, pour qu’un nom de fichier corresponde au nom d’une classe, il est implicite que chaque classe soit déclarée et implémentée par son propre fichier. Cela permet aux nouveaux développeurs d’identifier plus rapidement le code lié à une classe donnée.
1.4.2. En-tête standard et licence
Chaque fichier source doit contenir une en-tête calquée sur l’exemple qui suit:
/***************************************************************************
qgsfield.cpp - Describes a field in a layer or table
--------------------------------------
Date : 01-Jan-2004
Copyright: (C) 2004 by Gary E.Sherman
Email: sherman at mrcc.com
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
Note
There is a template for Qt Creator in git repository. To use it, copy it from qt_creator_license_template to a local location, adjust the mail address and - if required - the name and configure QtCreator to use it: .
1.5. Noms de variable
Les noms des variables locales commencent par une minuscule et sont formés en utilisant des minuscules et majuscules. Ne pas utiliser de préfixes comme my
ou the
.
Exemples:
mapCanvas
currentExtent
1.6. Énumérations
Les énumérations doivent être nommés en CamelCase avec une première lettre en majuscule, ex:
enum UnitType
{
Meters,
Feet,
Degrees,
UnknownUnit
};
N’utilisez pas de noms génériques qui peuvent entrer en conflit avec d’autres types. Par exemple, utilisez UnkownUnit
plutôt que Unknown
1.7. Constantes globales et Macros
Les constantes globales et les macros doivent être écrites en majuscules avec des séparateurs en tirets bas, ex:
const long GEOCRS_ID = 3344;
1.9. Signaux Qt et emplacements
Toutes les connections de signaux ou emplacements doivent être faites en utilisant les connections « new style » disponibles dans Qt5. De plus amples informations sur cette exigence sont disponibles dans`QEP #77 <https://github.com/qgis/QGIS-Enhancement-Proposals/issues/77>`_.
Évitez d’utiliser l’emplacement de connexion automatique de Qt (c’est-à-dire ceux nommés void on_mSpinBox_valueChanged
). Les emplacements à connexion automatique sont fragiles et sujets à des ruptures sans avertissement si les boîtes de dialogue sont remaniées.
1.10. Edition
N’importe quel éditeur ou EDI peut être utilisé pour éditer le code de QGIS, sous réserve qu’il respecte les pré-requis suivants:
1.10.1. Tabulations
Paramétrez votre éditeur pour remplacer les tabulations par des espaces. L’espacement d’une tabulation doit être paramétrée pour occuper deux espaces.
Note
Sous Vim, vous pouvez utiliser set expandtab ts=2
1.10.2. Indentation
Source code should be indented to improve readability. There is a prepare_commit.sh file that looks up the changed files and reindents them using astyle. This should be run before committing. You can also use astyle.sh to indent individual files.
Les nouvelles version de astyle indentent différemment que la version utilisée pour ré-indenter l’intégralité des sources, nous avons inclus une veille version du script astyle dans notre dépôt (activez la variable WITH_ASTYLE
dans le cmake pour l’inclure dans votre build).
1.10.3. Accolades
Les accolades doivent commencer sur la ligne suivant l’expression:
if( foo == 1 )
{
// do stuff
...
}
else
{
// do something else
...
}
1.11. Compatibilité API
Il y a la Documentation de l’API pour C ++.
We try to keep the API stable and backwards compatible. Cleanups to the API should be done in a manner similar to the Qt source code e.g.
class Foo
{
public:
/**
* This method will be deprecated, you are encouraged to use
* doSomethingBetter() rather.
* \deprecated use doSomethingBetter()
*/
Q_DECL_DEPRECATED bool doSomething();
/**
* Does something a better way.
* \note added in 1.1
*/
bool doSomethingBetter();
signals:
/**
* This signal will be deprecated, you are encouraged to
* connect to somethingHappenedBetter() rather.
* \deprecated use somethingHappenedBetter()
*/
#ifndef Q_MOC_RUN
Q_DECL_DEPRECATED
#endif
bool somethingHappened();
/**
* Something happened
* \note added in 1.1
*/
bool somethingHappenedBetter();
}
1.12. Liaisons SIP
Certain fichiers SIP sont automatiquement générés en utilisant un script dédié.
1.12.1. Pré-traitement d’en-tête
Toutes les informations pour construire proprement le fichier SIP doivent être présentes dans le fichier d’en-tête C++. Quelques macros sont disponibles pour ces définitions:
Utilisez
#ifdef SIP_RUN
pour générer du code uniquement dans les fichiers SIP ou#ifndef SIP_RUN
pour le code C ++ uniquement. Les instructions#else
sont gérées dans les deux cas.Utilisez
SIP_SKIP
pour sauter une ligneLes annotations suivante sont traitées:
SIP_FACTORY
:/Factory/
SIP_OUT
:/Out/
SIP_INOUT
:/In,Out/
SIP_TRANSFER
:/Transfer/
SIP_PYNAME(name)
:/PyName=name/
SIP_KEEPREFERENCE
:/KeepReference/
SIP_TRANSFERTHIS
:/TransferThis/
SIP_TRANSFERBACK
:/TransferBack/
Les sections
private
ne sont pas affichées, sauf si vous utilisez une instruction#ifdef SIP_RUN
dans ce bloc.SIP_PYDEFAULTVALUE(valeur)
peut être utilisé pour définir une valeur par défaut alternative à la méthode par python. Si la valeur par défaut contient une virgule,
, la valeur doit être entourée par des simples guillements'
.SIP_PYTYPE(type)
peut-être utilisé pour définir une type alternatif d’un argument à la méthode par python. Si le type contient une virgule,
, le type doit être entouré de simples guillemets'
.
A demo file, sipifyheader.h, is also available.
1.12.2. Générer le fichier SIP
Le fichier SIP peut être généré en utilisant un script dédié. Par exemple :
scripts/sipify.pl src/core/qgsvectorlayer.h > python/core/qgsvectorlayer.sip
To automatically generate the SIP file of a newly added C++ file sip_include.sh needs to be executed.
As soon as a SIP file is added to one of the source file (core_auto.sip, gui_auto.sip or analysis_auto.sip), it will be considered as generated automatically. A test on will ensure that this file is up to date with its corresponding header.
To force recreation of SIP files, sipify_all.sh shall be executed.
1.12.3. Améliorer le script sipify
If some improvements are required for sipify script, please add the missing bits to the demo file sipifyheader.h and create the expected header sipifyheader.expected.sip. This will also be automatically tested as a unit test of the script itself.
1.13. Préférences
QGIS code base offers a mechanism to declare, register and use settings.
settings should be defined using one of the available implementations (QgsSettingsEntryString, QgsSettingsEntryInteger, …).
they are declared as
const static
either in a dedicated class or in the registry directly (core, gui, app, …).they always must be added to the registry using
addSettingsEntry
method of QgsSettingsRegistry.the setting key should be using a
kebab-case
.
1.14. Style de code
Voici quelques trucs et astuces de programmation qui, nous l’espérons, vous aideront à réduire les erreurs, le temps de développement et la maintenance.
1.14.1. Lorsque c’est possible, utiliser du code générique
Si vous copiez-collez du code, ou si vous écrivez la même chose plusieurs fois, pensez à consolider le code en une seule fonction.
Cela permettra:
Autorisez les changements à s’effectuer à un seul endroit plutôt qu’en de multiples emplacements.
de prévenir le code pourri
de rendre plus difficile l’évolution différenciée de plusieurs copies au fil du temps, phénomène qui rend plus difficile la compréhension et la maintenance pour les autres développeurs
1.14.2. Placez les constantes en premier dans les expressions
Placez les constantes en premier dans les expressions
0 == value
à la place de value == 0
Cela empêchera les développeurs d’utiliser accidentellement =
au lieu de ==
, ce qui peut introduire des bogues logiques et subtils. Le compilateur générera une erreur si vous utilisez accidentellement =
à la place de ==
pour les comparaisons puisque les constantes ne peuvent pas se voir assigner des valeurs.
1.14.3. Le caractère espace peut être votre ami
Ajouter des espaces entre les opérateurs, les instructions et les fonctions rendent le code plus lisible.
Ce qui est plus facile à lire, ceci:
if (!a&&b)
ou ceci:
if ( ! a && b )
Note
prepare_commit.sh script will take care of this.
1.14.4. Placer les commandes sur des lignes séparées
Lors de la lecture du code il est facile de rater des commandes, si elles ne sont pas en début de ligne. Lors d’une lecture rapide, il est courant de sauter des lignes si elles ne semblent pas correspondre avec ce que l’on cherche dans les premiers caractères. Il est aussi commun de s’attendre à une commande après un conditionnel comme if
.
Considérez ceci:
if (foo) bar();
baz(); bar();
Il est très facile de rater des extraits dans le flux de contrôle. Au lieu de cela, utiliser
if (foo)
bar();
baz();
bar();
1.14.5. Indenter les modificateurs d’accès
Les modificateurs d’accès structurent une classe en sections publique, protégée et privée de l’API. Les modificateurs d’accès eux-mêmes groupent le code dans cette structure. Indentez les modificateurs d’accès et les déclarations.
class QgsStructure
{
public:
/**
* Constructor
*/
explicit QgsStructure();
}
1.14.6. Recommandation de lecture
Effective Modern C++, Scott Meyers
More Effective C++, Scott Meyers
Effective STL, Scott Meyers
Design Patterns, GoF
You should also really read this article from Qt Quarterly on designing Qt style (APIs)
1.15. Crédits pour les contributions
Les contributeurs aux nouvelles fonctionnalités sont encouragés à faire connaître aux gens leur contribution via:
l’ajout d’une note au fichier de changement lors de la première incorporation du code auquel ils ont contribué, du type:
This feature was funded by: Olmiomland https://olmiomland.ol This feature was developed by: Chuck Norris https://chucknorris.kr
Écrivant un article à propos de cette nouvelle fonctionnalité sur un blog, et en l’ajoutant à l’agrégateur https://plugins.qgis.org/planet/
Ajout de leur nom à:
1.8. Commentaires
Les commentaires des méthodes de classes devraient utiliser un style indicatif à la troisième personne plus qu’un style impératif: