1. Padrão de codificação do QGIS
Esses padrões devem ser seguidos por todos os desenvolvedores do QGIS
1.1. Classes
1.1.1. Nomes
A classe em QGIS começa com Qgs e é formada usando camel case.
Exemplos:
QgsPoint
QgsMapCanvas
QgsRasterLayer
1.1.2. Membros
Os nomes dos membros da classe começam com um m minúsculo e são formados usando maiúsculas e minúsculas.
mMapCanvas
mCurrentExtent
Todos os membros da classe devem ser privados. Membros públicos na classe são FORTEMENTE desencorajados. Os membros protegidos devem ser evitados quando o membro pode precisar ser acessado a partir de subclasses Python, uma vez que os membros protegidos não podem ser usados nas ligações Python.
Os nomes dos membros da classe estática mutável devem começar com s
minúsculos, mas os nomes constantes dos membros da classe estática devem ser todos em maiúsculas:
sRefCounter
DEFAULT_QUEUE_SIZE
1.1.3. Funções do acessório
Os valores dos membros da classe devem ser obtidos através das funções do acessório. A função deve ser nomeada sem um prefixo de obtenção. As funções de acessório para os dois membros privados acima seriam.
mapCanvas()
currentExtent()
Certifique-se de que os acessadores estejam corretamente marcados com `` const``. Quando apropriado, isso pode exigir que as variáveis de membro do tipo de valor em cache sejam marcadas com `` mutable``.
1.1.4. Funções
Os nomes das funções começam com uma letra minúscula e são formados usando maiúsculas e minúsculas. O nome da função deve transmitir algo sobre o propósito da função.
updateMapExtent()
setUserOptions()
Por consistência com a API QGIS existente e com a API Qt, abreviações devem ser evitadas. Por exemplo. SetDestinationSize
ao invés de setDestSize
, setMaximumValue
ao invés de setMaxVal
.
Os acrônimos também devem utilizar camel case para consistência. Por exemplo. SetXml
ao invés de setXML
.
1.1.5. Argumentos de função
Argumentos de função devem usar nomes descritivos. Não use argumentos de uma única letra (setColor( const QColor& color )
ao invés de setColor( const QColor& c )
).
Preste muita atenção quando os argumentos devem ser passados por referência. A menos que os objetos dos argumentos sejam pequenos e copiados trivialmente (como objetos QPoint), eles devem ser passados por referência em uma constante. Por consistência com a API Qt, mesmo os objetos compartilhados implicitamente são passados por referência em uma constante (por exemplo, setTitle (const QString & title)
ao invés de setTitle (QString title)
.
1.1.6. Valores de retorno da função
Retorna objetos pequenos e copiados trivialmente como valores. Objetos maiores devem ser retornados por referência const. A única exceção a isso são os objetos implicitamente compartilhados, que sempre são retornados por valor. Retorna QObject
ou objetos de subclasse como ponteiros.
int maximumValue() const
const LayerSet& layers() const
QString title() const
(QString
é compartilhado implicitamente)QList< QgsMapLayer* > layers() const
(QList
é compartilhado implicitamente)QgsVectorLayer *layer() const;
(QgsVectorLayer
herdaQObject
)QgsAbstractGeometry *geometry () const;
(QgsAbstractGeometry
é abstrato e provavelmente precisará ser moldado)
1.2. Documentação de API
É necessário escrever a documentação de API para cada classe, método, enumeração e outro código disponível na API pública.
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étodos
As descrições dos métodos devem ser escritas de forma descritiva, usando a terceira pessoa. Os métodos requerem uma tag \since
que define quando eles foram introduzidos. Você deve adicionar tags \since
adicionais para alterações importantes que foram introduzidas posteriormente.
/**
* 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. Variáveis Internas
Variáveis de membro normalmente devem estar na seção private
e disponibilizadas via getters e setters. Uma exceção a isso é para contêineres de dados, como relatórios de erros. Nesses casos, não prefixe o membro com um 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
Classes QGIS geradas a partir dos arquivos Qt Designer (ui) devem ter o sufixo Base. Isto identifica a classe como uma classe base gerada.
Exemplos:
QgsPluginManagerBase
QgsUserOptionsBase
1.3.2. Diálogos
Todos os diálogos devem implementar dicas de contexto para todos os ícones da barra de ferramentas e outros widgets relevantes. Dicas de contexto auxiliam muito na descoberta de funcionalidade tanto para usuários novos quanto experientes.
Garanta que a ordem das tabulações para os widgets seja atualizada sempre que o layout de um diálogo for alterado.
1.4. Arquivos C++
1.4.1. Nomes
Arquivos C++ de código e cabeçalhos devem ter extensão .cpp e .h, respectivamente. Nomes de arquivos devem ser todos em minúsculas e, no caso de representar uma classe, ter o mesmo nome da classe.
Exemplo: os arquivos de origem da Classe QgsFeatureAttribute
são qgsfeatureattribute.cpp
e qgsfeatureattribute.h
Nota
No caso de não ter ficado claro na declaração acima, o nome do arquivo combinar com o nome da classe significa, implicitamente, que cada classe deve ser declarada e implementada em seu próprio arquivo. isto torna muito mais fácil para recém-chegados identificar onde o código relativo para uma classe específica está localizado.
1.4.2. Cabeçalho Padrão e Licença
Cada arquivo de código fonte deve conter uma seção de cabeçalho padronizado conforme o exemplo a seguir:
/***************************************************************************
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
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. Nomes de Variáveis
Nomes de variáveis locais devem começar com uma letra minúscula e serem formadas por maiúsculas e minúsculas. Não use prefixos como my
ou the
.
Exemplos:
mapCanvas
currentExtent
1.6. Tipos Enumerados
Tipos enumerados devem ser nomeados usando CamelCase iniciando com uma maiúscula. Exemplo:
enum UnitType
{
Meters,
Feet,
Degrees,
UnknownUnit
};
Não use nomes de tipos genéricos que causarão conflito com outros tipos. Exemplo. Use UnknownUnit
ao invés de Unknown
1.7. Constantes Globais & Macros
Constantes globais e macros devem ser escritas em maiúsculas e separadas por sublinha. ex.:
const long GEOCRS_ID = 3344;
1.9. Qt Signals e Slots
Todos as conexões de signal/slot devem ser feitas utilizando as conexões “new style” disponíveis no Qt5. Mais informações sobre este requisito está disponível em QEP #77.
Evite utilizar a auto conexão de slots do Qt (ex. aquelas nomeadas com void on_mSpinBox_valueChanged
). Conexões automáticas são frágeis e tendem a se quebrar sem aviso se os diálogos são alterados.
1.10. Editando
Qualquer editor de texto/IDE pode ser utilizada para editar o código do QGIS desde que os seguintes requisitos sejam satisfeitos.
1.10.1. Tabulações
Ajuste seu editor para emular tabulações com espaços. As tabulações devem ser ajustadas para 2 espaços.
Nota
No vim isto é feito com set expandtab ts=2
1.10.2. Indentação
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.
Como versões mais recentes de astyle recuam de forma diferente da versão usada para fazer uma reindentação completa da fonte, o script usa uma versão antiga de estilo, que incluímos em nosso repositório (ative WITH_ASTYLE
no cmake para incluí-lo na compilação) .
1.10.3. Parênteses
Parênteses devem iniciar na linha seguindo a expressão:
if( foo == 1 )
{
// do stuff
...
}
else
{
// do something else
...
}
1.11. Compatibilidade da API
Existe API documentation para 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. Ligações SIP
Alguns dos arquivos SIP são gerados automaticamente usando um script dedicado.
1.12.1. Pré-processamento de cabeçalho
Todas as informações para construir corretamente o arquivo SIP devem ser encontradas no arquivo de cabeçalho C++. Algumas macros estão disponíveis para tal definição:
Use
#ifdef SIP_RUN
para gerar código apenas em arquivos SIP ou#ifndef SIP_RUN
apenas para código C++. As instruções#else
são tratadas em ambos os casos.Use ``SIP_SKIP `` para descartar uma linha
As seguintes anotações são tratadas:
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/
As seções
private
não são exibidas, exceto se você usar uma instrução#ifdef SIP_RUN
neste bloco.SIP_PYDEFAULTVALUE(value)
pode ser usado para definir um valor padrão alternativo do método python. Se o valor padrão contém uma vírgula,
, o valor deve estar entre aspas simples'
SIP_PYTYPE(type)
pode ser usado para definir um tipo alternativo para um argumento do método python. Se o tipo contém uma vírgula,
, o tipo deve estar entre aspas simples'
A demo file, sipifyheader.h, is also available.
1.12.2. Gerando o arquivo SIP
O arquivo SIP pode ser gerado usando um script dedicado. Por exemplo:
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. Melhorando o 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. Configurações
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. Estilo de Codificação
Aqui são descritas algumas dicas de programação que, esperamos, reduzirão erros, tempo de desenvolvimento e manutenção.
1.14.1. Sempre que possível, generalize o código
Se fizer cópia-cola do código, ou escrevendo a mesma coisa mais de uma vez, considere consolidar o código em uma função.
Isso vai:
permitir que alterações sejam feitas em apenas um local ao invés de vários
ajuda a prevenir inchaço no código
tornar mais difícil para várias cópias irem se diferenciando longo do tempo, tornando mais difícil a compreensão e a manutenção para os outros
1.14.2. Prefira Ter Constantes Antes nos Predicados
Prefira colocar as constantes primeiro nos predicados.
0 == value
ao invés de value == 0
Isso ajudará a impedir que os programadores acidentalmente usem `` = `` quando eles pretendem usar `` == ``, o que pode introduzir erros de lógica muito sutis. O compilador gerará um erro se você usar acidentalmente `` = `` em vez de `` == `` para comparações, uma vez que as constantes não podem ser atribuídas valores inerentes.
1.14.3. Espaços Podem Ser Seus Amigos
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
prepare_commit.sh script will take care of this.
1.14.4. Coloque comandos em linhas separadas
Ao ler o código, é fácil perder os comandos, se não estiverem no início da linha. Ao ler rapidamente o código, é comum ignorar linhas se não se parecem com o que você procura nos primeiros caracteres. Também é comum esperar um comando após um condicional como `` if``.
Considere:
if (foo) bar();
baz(); bar();
É muito fácil perder parte do fluxo de controle. Em vez disso use
if (foo)
bar();
baz();
bar();
1.14.5. Indente modificadores de acesso
Os modificadores de acesso estruturam uma classe em seções de API pública, API protegida e API privada. Os próprios modificadores de acesso agrupam o código nesta estrutura. Indente o modificador de acesso e as declarações.
class QgsStructure
{
public:
/**
* Constructor
*/
explicit QgsStructure();
}
1.14.6. Recomendações de Livros
Effective Modern C++, Scott Meyers
C++ mais eficaz, Scott Meyers
STL eficaz, Scott Meyers
Padrões de design, GoF
Você também deve realmente ler este artigo do Qt Quarterly sobre designing Qt style (APIs)
1.15. Créditos para as contribuições
Colaboradores de novas funções são encorajados a deixar as pessoas saberem sobre suas contribuições por:
Adicionando uma nota ao changelog na primeira versão em que o código for incorporado, do tipo:
This feature was funded by: Olmiomland https://olmiomland.ol This feature was developed by: Chuck Norris https://chucknorris.kr
escrever um artigo sobre o novo recurso em um blog e adicioná-lo ao planeta QGIS https://plugins.qgis.org/planet/
Adicionando seu nome em:
1.8. Comentários
Comentários dos métodos de classe devem usar a terceira pessoa do indicativo ao invés do estilo imperativo: