1. Normas de Codificação QGIS¶
Estas normas devem ser seguidas por todos os programadores de QGIS
1.1. Classes¶
1.1.1. Nomes¶
A classe em QGIS começa com Qgs e são formadas usando a inicial em letra maiúscula.
Exemplos:
QgsPoint
QgsMapCanvas
QgsRasterLayer
1.1.2. Membros¶
Os nomes do membro da classe começam pela letra minúscula m e são formados usando um misto de letras minúsculas e maiúsculas..
mMapCanvas
mCurrentExtent
Todos os membros da classe devem ser privados. NÃO recomendamos membros da classe públicos. Devem ser evitados os membros protegidos quando o membro tiver de ser acedido a partir de subclasses do Python, uma vez que membros protegidos não podem ser utilizados a parting de ligações do Python.
Os nomes de membro da classe estática mutáveis devem começar com a letra minúscula s
, mas os nomes de membro da classe devem estar todos em letra maiúscula:
sRefCounter
DEFAULT_QUEUE_SIZE
1.1.3. Funções de Acessor¶
Os valores do membro da classe devem ser obtidos através de funções de acessor. O nome da função não deve ser atribuído sem um prefixo. As funções de acessor para os dois membros privados acima referidos serão:
mapCanvas()
currentExtent()
Assegure-se que os acessores são corretamente marcados com const
. Onde apropriado, isto poderá necessitar que as variáveis de membro tipo valor em cache são marcados com mutable
.
1.1.4. Funções¶
Os nomes das funções começam com uma letra minúscula e são formados usando um misto de letras minúsculas e maiúsculas. O nome da função deve transmitir algo sobre o propósito da função.
updateMapExtent()
setUserOptions()
Para a consistência entre o QGIS API e o Qt API existente, as abreviaturas devem ser evitadas. Por exemplo: `` setDestinationSize`` em vez de `` setDestSize``, `` setMaximumValue`` em vez de `` setMaxVal``.
Os acrónimos também devem começar por letra maiúscula por questões de consistência. Por exemplo, setXml
em vez de setXML
.
1.1.5. Argumentos da função¶
Os argumentos da função devem usar nomes descritivos. Não use argumentos com uma só letra (por exemplo``setColor( const QColor& color )`` em vez de setColor( const QColor& c )
).
Tenha atenção sempre que os argumentos sejam passados através de referência. A não ser que os argumentos sejam pequenos e copiados (tais como objetos QPoint), devem ser passados através da referência const. Por questões de consistência com o Qt API, mesmo os objetos implicitamente partilhados são passados através da referência const (por exemplo, setTitle( const QString& title )
em vez de setTitle( QString title )
.
1.1.6. Valores de Retorno da Função¶
Devolva os objetos pequenos e trivialmente copiados como valores. Os objetos maiores devem ser devolvidos através da referência const. A única exceção a isto são os objetos implicitamente partilhados, que são sempre devolvidos por valor. Devolva objetos QObject
ou atribuídos como subclasse como ponteiros.
int maximumValue() const
const LayerSet& layers() const
QString title() const
(QString
is implicitly shared)QList< QgsMapLayer* > layers() const
(QList
is implicitly shared)QgsVectorLayer *layer() const;
(QgsVectorLayer
inheritsQObject
)QgsAbstractGeometry *geometry() const;
(QgsAbstractGeometry
is abstract and will probably need to be casted)
1.2. API Documentation¶
It is required to write API documentation for every class, method, enum and other code that is available in the public API.
QGIS uses Doxygen for 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. Methods¶
Method descriptions should be written in a descriptive form, using the 3rd
person. Methods require a \since
tag that defines when they have been
introduced. You should add additional \since
tags for important changes
that were introduced later on.
/**
* 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. Members Variables¶
Member variables should normally be in the private
section and made
available via getters and setters. One exception to this is for data
containers like for error reporting. In such cases do not prefix the member
with an 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. Classes geradas¶
QGIS classes that are generated from Qt Designer (ui) files should have a Base suffix. This identifies the class as a generated base class.
Exemplos:
QgsPluginManagerBase
QgsUserOptionsBase
1.3.2. Diálogos¶
Todos os diálogos devem implementar dicas de ajuda para todos os ícones das barras de ferramentas e outros componentes relevantes. As dicas de ajuda são um grande auxílio para utilizadores novos ou experientes conhecerem as funcionalidades.
Certifique que a ordem das abas para os widgets é atualizada toda vez que a composição de uma janela mudar.
1.4. Ficheiros C++¶
1.4.1. Nomes¶
a implementação de C++ e os cabeçalhos dos ficheiros devem ter uma extensão .cpp e .h, respetivamente. O nome do arquivo deve ser todo em minúsculas e, no caso das classes, corresponder ao nome da classe.
Example:
Class QgsFeatureAttribute
source files are
qgsfeatureattribute.cpp
and qgsfeatureattribute.h
Nota
In case it is not clear from the statement above, for a filename to match a class name it implicitly means that each class should be declared and implemented in its own file. This makes it much easier for newcomers to identify where the code is relating to specific class.
1.4.2. Cabeçalho padrão e licença¶
Cada arquivo de código fonte deve conter um cabeçalho de acordo com o seguinte exemplo:
/***************************************************************************
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.
*
***************************************************************************/
Nota
Há um template para o Qt Creator no git. Para use-lo, copie-no do arquivo doc/qt_creator_license_template
para uma pasta local, ajuste o endereço de e-mail e - caso necessário - o nome e configure o QtCreator para usá-lo: menuselection:Tools –> Options –> C++ –> File Naming.
1.5. Nome das variáveis¶
Os nomes de variáveis locais começam com uma letra minúscula e são formados usando um misto de letras minúsculas e maiúsculas. Não usar prefixos como my
ou the
.
Exemplos:
mapCanvas
mapCanvas
1.6. Enumerated Types¶
Enumerated types should be named in CamelCase with a leading capital e.g.:
enum UnitType
{
Meters,
Feet,
Degrees,
UnknownUnit
};
Do not use generic type names that will conflict with other types. e.g. use
UnkownUnit
rather than Unknown
1.7. Constantes Globais & Macros¶
Constantes globais e macros devem ser escritas em caixa alta e linha (_) por exemplo.:
const long GEOCRS_ID = 3344;
1.8. Comments¶
Comments to class methods should use a third person indicative style instead of the imperative style:
/**
* Creates a new QgsFeatureFilterModel, optionally specifying a \a parent.
*/
explicit QgsFeatureFilterModel( QObject *parent = nullptr );
~QgsFeatureFilterModel() override;
1.9. Sinais e Slots da Qt¶
All signal/slot connects should be made using the «new style» connects available in Qt5. Futher information on this requirement is available in QEP #77.
Avoid use of Qt auto connect slots (i.e. those named
void on_mSpinBox_valueChanged
). Auto connect slots are fragile and
prone to breakage without warning if dialogs are refactored.
1.10. Editando¶
Qualquer editor de texto/ambiente de desenvolvimento (IDE) pode ser usado para editar códigos do QGIS, contanto que os seguintes requisitos sejam atendidos.
1.10.1. Separadores¶
Set your editor to emulate tabs with spaces. Tab spacing should be set to 2 spaces.
Nota
In vim this is done with set expandtab ts=2
1.10.2. Indentation¶
Source code should be indented to improve readability. There is a
scripts/prepare-commit.sh
that looks up the changed files and reindents
them using astyle. This should be run before committing. You can also use
scripts/astyle.sh
to indent individual files.
As newer versions of astyle indent differently than the version used to do a
complete reindentation of the source, the script uses an old astyle version,
that we include in our repository (enable WITH_ASTYLE
in cmake to include
it in the build).
1.10.3. Braces¶
Braces should start on the line following the expression:
if( foo == 1 )
{
// do stuff
...
}
else
{
// do something else
...
}
1.11. Compatibilidade da Interface de Programação da Aplicação¶
There is API documentation for 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 sourcecode 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. SIP Bindings¶
Some of the SIP files are automatically generated using a dedicated script.
1.12.1. Header pre-processing¶
All the information to properly build the SIP file must be found in the C++ header file. Some macros are available for such definition:
Use
#ifdef SIP_RUN
to generate code only in SIP files or#ifndef SIP_RUN
for C++ code only.#else
statements are handled in both cases.Use
SIP_SKIP
to discard a lineThe following annotations are handled:
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/
private
sections are not displayed, except if you use a#ifdef SIP_RUN
statement in this block.SIP_PYDEFAULTVALUE(value)
can be used to define an alternative default value of the python method. If the default value contains a comma,
, the value should be surrounded by single quotes'
SIP_PYTYPE(type)
can be used to define an alternative type for an argument of the python method. If the type contains a comma,
, the type should be surrounded by single quotes'
A demo file can be found in tests/scripts/sipifyheader.h
.
1.12.2. Generating the SIP file¶
The SIP file can be generated using a dedicated script. For instance:
scripts/sipify.pl src/core/qgsvectorlayer.h > python/core/qgsvectorlayer.sip
As soon as a SIP file is added to one of the source file
(python/core/core.sip
, python/gui/gui.sip
or
python/analysis/analysis.sip
), it will be considered as generated
automatically. A test on Travis will ensure that this file is up to date with
its corresponding header.
Older files for which the automatic creation is not enabled yet are listed in
python/auto_sip.blacklist
.
1.12.3. Improving sipify script¶
If some improvements are required for sipify script, please add the missing bits
to the demo file tests/scripts/sipifyheader.h
and create the expected
header tests/scripts/sipifyheader.expected.si
. This will also be
automatically tested on Travis as a unit test of the script itself.
1.13. Coding Style¶
Here are described some programming hints and tips that will hopefully reduce errors, development time and maintenance.
1.13.1. Where-ever Possible Generalize Code¶
If you are cut-n-pasting code, or otherwise writing the same thing more than once, consider consolidating the code into a single function.
Isto irá:
permitir que as alterações sejam feitas num só local em vez de em vários lugares
help prevent code bloat
make it more difficult for multiple copies to evolve differences over time, thus making it harder to understand and maintain for others
1.13.2. Prefer Having Constants First in Predicates¶
Prefer to put constants first in predicates.
0 == value
em vez de value == 0
This will help prevent programmers from accidentally using =
when they meant
to use ==
, which can introduce very subtle logic bugs. The compiler will
generate an error if you accidentally use =
instead of ==
for comparisons
since constants inherently cannot be assigned values.
1.13.3. Whitespace Can Be Your Friend¶
Adicionar espaços entre operadores, declarações e funções torna mais fácil para os humanos analisar o código.
O que é mais fácil de ler, isto:
if (!a&&b)
ou isto:
if ( ! a && b )
Nota
scripts/prepare-commit.sh
will take care of this.
1.13.4. Colocar os comandos em linhas separadas¶
When reading code it’s easy to miss commands, if they are not at the beginning
of the line. When quickly reading through code, it’s common to skip lines
if they don’t look like what you are looking for in the first few characters.
It’s also common to expect a command after a conditional like if
.
Considere:
if (foo) bar();
baz(); bar();
It’s very easy to miss part of what the flow of control. Instead use
if (foo)
bar();
baz();
bar();
1.13.5. Indent access modifiers¶
Access modifiers structure a class into sections of public API, protected API and private API. Access modifiers themselves group the code into this structure. Indent the access modifier and declarations.
class QgsStructure
{
public:
/**
* Constructor
*/
explicit QgsStructure();
}
1.13.6. Book recommendations¶
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.14. Créditos de contribuições¶
Os contribuidores de novas funções são encorajados a informar as pessoas sobre sua contribuição:
adicionar uma nota ao registo de alterações para a primeira versão onde o código foi incorporado, do tipo
This feature was funded by: Olmiomland https://olmiomland.ol This feature was developed by: Chuck Norris https://chucknorris.kr
writing an article about the new feature on a blog, and add it to the QGIS planet https://plugins.qgis.org/planet/
adding their name to: