1. QGIS コーディング基準
これらの基準は、すべての QGIS 開発者が守るべきです。
1.1. クラス
1.1.1. 名前
QGISのクラスは、Qgsで始まり、キャメルケースを使用して形成します。
例:
QgsPoint
QgsMapCanvas
QgsRasterLayer
1.1.2. メンバー
クラスメンバー名は小文字のmで始まり、大文字と小文字を使用して形成されています。
mMapCanvas
mCurrentExtent
すべてのクラスメンバはprivateにしましょう。publicクラスメンバは極力避けるようにしてください。protectedメンバは Python バインディングから使用できないため、メンバが Python のサブクラスからアクセスする必要がある場合は、protectedメンバを使用しないでください。
静的メンバの命名は、変数の場合は小文字の "s" で始め、定数の場合はすべての文字を大文字としてください。
sRefCounter
DEFAULT_QUEUE_SIZE
1.1.3. アクセサ関数
クラスのメンバ値はアクセサ関数を通じて取得しましょう。関数は、 get 接頭辞なしの名前を付ける必要があります。上記2つの私的メンバのためのアクセサ関数は次のようになります。
mapCanvas()
currentExtent()
アクセサが正しく const
でマークされていることを確認してください。適切な場合には、これはキャッシュされた値型のメンバー変数が mutable
でマークされていることを要求することができます。
1.1.4. 関数
関数名は小文字で始まり、大文字と小文字を使用して形成されています。関数名は、その関数の目的について何かを伝える必要があります。
updateMapExtent()
setUserOptions()
既存の QGIS の API と Qt の API との一貫性を保つために、略語は避けましょう。例えば setDestSize
でなく setDestinationSize
、 setMaxVal
でなく setMaximumValue
といった形で書くようにしてください。
頭字語についても同様に、一貫性を保つためにキャメルケースにする必要があります。例えば、 setXML
でなく setXml
と書くようにしてください 。
1.1.5. 関数の引数
関数の引数は説明的な名前を使用してください。1文字の引数名を使用しないでください (例:``setColor( const QColor& c )``ではなく、``setColor( const QColor& color )``とする)。
引数を参照渡しするべき場合に注意してください。オブジェクトの引数は小さくてコピーが簡単なもの (QPoint オブジェクトなど) でない限り、 const 参照で渡しましょう。 Qt の API との一貫性を保つために、暗黙的に共有されるオブジェクトは const 参照によって渡されます。 (例えば、 setTitle( QString title )
ではなく setTitle( const QString& title )
)。
1.1.6. 関数の戻り値
小さくコピーが簡単なオブジェクトは値として返してください。より大きなオブジェクトは const 参照で返しましょう。この例外の一つは暗黙的に共有されるオブジェクトで、常に値で返します。 QObject
またはそのサブクラスは、ポインタとして返してください。
int maximumValue() const
const LayerSet& layers() const
QString title() const
(QString
は暗黙的に共有される)QList< QgsMapLayer* > layers() const
(QList
は暗黙的に共有される)QgsVectorLayer *layer() const;
(QgsVectorLayer
はQObject
を継承)QgsAbstractGeometry *geometry() const;
(QgsAbstractGeometry
は抽象クラスであり、おそらくキャストする必要がある)
1.2. APIドキュメント
公開 API で利用可能なすべてのクラス、メソッド、列挙型などのコードについては、 API ドキュメントを書く必要があります。
QGISは Doxygen またはドキュメントを使用します。説明的で意味のあるコメントを書き、読者に何を期待するか、エッジケースで何が起こるか、読者が探しているかもしれない他のインターフェース、ベストプラクティス、コードサンプルについてのヒントを与える情報を提供します。
1.2.1. メソッド
メソッドの説明は三人称を使用した説明的な形で書いてください。メソッドにはいつ導入されたかを定義する \since
タグが必要です。導入以降に重要な変更が行われたものについては、追加の \since
タグを追加してください。
/**
* 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. メンバ変数
メンバ変数はふつう private
セクションに入れ、ゲッタやセッタを利用できるようにしてください。エラー報告などのためのデータコンテナはこの例外です。このような場合はメンバに 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 デザイナ
1.3.1. 生成されたクラス
Qt デザイナ(UI)ファイルから生成される QGIS クラスは Base という接尾辞を持つ必要があります。これは、そのクラスを生成された基本クラスとして識別します。
例:
QgsPluginManagerBase
QgsUserOptionsBase
1.3.2. ダイアログ
すべてのダイアログには、すべてのツールバーアイコンおよびその他の関連するウィジェットのツールチップヘルプを実装する必要があります。ツールチップは、新規および経験豊富なユーザーのために機能の見つけやすさを大きく追加します。
ウィジェットのタブ順序は、ダイアログの変更のたびレイアウトを更新していることを確認します。
1.4. C ++ファイル
1.4.1. 名前
C ++の実装とヘッダーファイルは、それぞれ拡張子.cppと.hを持つ必要があります。ファイル名はすべて小文字で、クラスの場合、クラス名と一致する必要があります。
例: クラス QgsFeatureAttribute
ソースファイルは qgsfeatureattribute.cpp
と qgsfeatureattribute.h
に置く
注釈
上記の文が暗黙的に意味していることをより明確にいえば、ファイル名をクラス名と一致させるために、それぞれのクラスはそのクラス固有のファイルで宣言され、実装されねばならないということです。これによって、あるクラスに関連したコードがどこにあるのかを探すのが、新規参加者にとってもはるかに容易になります。
1.4.2. 標準ヘッダとライセンス
各ソースファイルには以下の例に従ってパターン化されたヘッダセクションがあるようにしてください:
/***************************************************************************
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.
*
***************************************************************************/
注釈
gitリポジトリにはQt Creatorのためのテンプレートがあります。それを使用するには、 それを qt_creator_license_template からローカルの場所にコピーし、メールアドレスと(必要ならば)名前を修正し、それを使用するようにQtCreatorを設定します: 。
1.5. 変数名
ローカル変数名は小文字で始まり、大文字と小文字を使用して形成されています。my
あるいは the
といった文字列を前に付けないでください。
例:
mapCanvas
currentExtent
1.6. 列挙型
列挙型は、最初が大文字のキャメルケースで命名する必要があります、例えば:
enum UnitType
{
Meters,
Feet,
Degrees,
UnknownUnit
};
他のタイプと競合するジェネリック型の名前を使用しないでください。例えば Unknown
よりむしろ UnkownUnit
を使用してください
1.7. グローバル定数&マクロ
グローバル定数とマクロは大文字のアンダースコア区切りなどで書かれる必要があります。
const long GEOCRS_ID = 3344;
1.9. Qt のシグナルとスロット
すべてのシグナルとスロットの接続は、Qt5から利用可能になった「新しいスタイル」の接続を使用して行われるべきです。この要件についてのより詳しい情報は、 QEP #77 で読むことができます。
Qt自動接続スロット(すなわち void on_mSpinBox_valueChanged
と名前付けされたもの)の使用を避けてください。自動接続スロットはダイアログがリファクタリングされている場合は、警告なしに破損し、脆弱となりやすいです。
1.10. 編集
任意のテキストエディタ/IDEは、次の要件が満たされているとすれば、QGISコードを編集するために使用できます。
1.10.1. タブ
スペースでタブを代替するようにエディタを設定します。タブ間隔はスペース2つに設定する必要があります。
注釈
vim では、 set expandtab ts=2
でこれを実行できます
1.10.2. 字下げ
ソースコードは読みやすくするために字下げされるべきです。変更されたファイルを検索し、 astyle を使用してそれらを字下げし直す prepare_commit.sh ファイルがあります。これは、コミットする前に実行すべきです。また、個々のファイルを字下げするために astyle.sh を使用できます。
astyle字下げのより新しいバージョンは、ソースコード全体を字下げし直す時に使用するバージョンとは異なっているので、スクリプトでは古いastyleバージョンを使用しており、これをリポジトリに含めています(これを含めるにはビルドの際にcmakeで WITH_ASTYLE
を有効にします)。
1.10.3. 中括弧
中括弧は式の次の行で始めてください。
if( foo == 1 )
{
// do stuff
...
}
else
{
// do something else
...
}
1.11. API の互換性
C++用の API documentation があります。
私たちは、APIを安定させ、後方互換性を保つように努めています。APIのクリーンアップは、Qtのソースコードと同じような方法で行ってください。例
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 バインド
SIP ファイルの一部は、特定のスクリプトを使用して自動的に生成されます。
1.12.1. ヘッダの前処理
正しく SIP を構築するためのすべての情報は C++ のヘッダファイル内になければなりません。そのような定義のためにいくつかのマクロを利用することができます。
#ifdef SIP_RUN
で SIP ファイル内でのみ使用するコードを生成し、#ifndef SIP_RUN
で C++ コード内でのみ使用するコードを生成してください。#else
文を使えばこの両方を扱うことができます。SIP_SKIP
を使用すると、行が無効になります。以下の表記法を扱うことができます。
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
セクションは、ブロック内で#ifdef SIP_RUN
文を使用した場合を除いて表示されません。SIP_PYDEFAULTVALUE(value)
は、Pythonのメソッドのための別のデフォルト値を定義するために使用することができます。デフォルト値がコンマ,
を含む場合は、値はシングルクォート'
で囲まなければなりません。SIP_PYTYPE(type)
は、Pythonのメソッドの引数のための別の型を定義するために使用することができます。型がコンマ,
を含む場合は、型はシングルクォート'
で囲まなければなりません。
デモファイル、sipifyheader.h も利用できます。
1.12.2. SIP ファイルを生成する
SIP ファイルはそのための専用スクリプトを使って生成することができます。例えば次のようにします。
scripts/sipify.pl src/core/qgsvectorlayer.h > python/core/qgsvectorlayer.sip
新しく追加されたC++ファイルのSIPファイルを自動生成するには、 sip_include.sh を実行する必要があります。
SIP ファイルがソースファイル (core_auto.sip, gui_auto.sip または analysis_auto.sip) のいずれかに追加されると同時に自動的に生成されたと見なされます。テストオンは、このファイルが対応するヘッダと更新されたことを確認します。
SIPファイルを強制的に再生成するためには、 sipify_all.sh を実行しなければなりません。
1.12.3. sipify スクリプトを改善する
もし、sipifyスクリプトに何らかの改良が必要であれば、デモファイルに足りない部分を追加してください sipifyheader.h そして、期待されるヘッダー sipifyheader.expected.sip を作成します。これは、スクリプト自体のユニットテストとしても自動的にテストされることになります。
1.13. 設定
QGISのコードベースには、設定を宣言、登録、利用するための仕組みが用意されています。
設定は、利用可能な実装(QgsSettingsEntryString, QgsSettingsEntryInteger, ...)のいずれかを使用して定義しなければいけません。
それらは、専用のクラスかレジストリ(core、gui、app、...)で直接
const static
として宣言されます。QgsSettingsRegistry の
addSettingsEntry
メソッドを使用してレジストリに追加する必要があります。設定キーは、
kebab-case
を使用する必要があります。
1.14. コーディングスタイル
ここでは、うまくいけばエラーや開発時間、メンテナンスを減らすことが期待できる、プログラミングのヒントやコツを説明します。
1.14.1. 可能なかぎりコードを一般化しましょう
コードをカット&ペーストしている、あるいは複数回同じことを書いている場合は、単一の関数にコードを統合することを検討してください。
これにより:
変更は複数の場所ではなく一箇所で行うことを可能にします
コードの膨張を防ぐのを助けます
複数のコピーが時間につれて違いを進化させること、したがって他人が理解して維持管理するのを難しくすること、がより起こりにくくします
1.14.2. 述語中で定数は最初にしましょう
述語中では最初に定数を置くことを好みます。
value == 0
の代わりに 0 == value
これにより、プログラマが ==
を使用するつもりで誤って =
を使用することを防げます、それは非常に微妙な論理的バグになる。比較のための ==
の代わりに誤って =
を使用している場合、 定数には本質的に値を割り当てできませんから、コンパイラでエラーが発生します。
1.14.3. 空白は友達になりえます
演算子、ステートメント、および関数の間にスペースを追加すると、人間がコードを簡単に解析できるようになります。
より読みやすいのは、こちら:
if (!a&&b)
またはこちら:
if ( ! a && b )
注釈
prepare_commit.sh スクリプトがこの処理を行います。
1.14.4. コマンドは別々の行に入れましょう
コードを読み取るとき、行の先頭にない場合は、コマンドを見逃しやすくなります。すぐにコードを読むとき、それらは最初の数文字で探しているもののように見えない場合、行を読み飛ばすのが一般的です。 if
のような条件の後にコマンドを期待することも一般的です。
考えてみましょう:
if (foo) bar();
baz(); bar();
制御のどのような流れの一部を見逃すのは非常に簡単です。代わりに使用します
if (foo)
bar();
baz();
bar();
1.14.5. アクセス修飾子を字下げしましょう
アクセス修飾子は、公開API、保護されたAPIとプライベートAPIのセクションにクラスを構造化します。アクセス修飾子自体はこのような構造にコードをグループ化します。アクセス修飾子と宣言を字下げしてください。
class QgsStructure
{
public:
/**
* Constructor
*/
explicit QgsStructure();
}
1.14.6. お奨めの読み物
Effective Modern C++, Scott Meyers
More Effective C++, Scott Meyers
Effective STL, Scott Meyers
Design Patterns, GoF
Qt Quarterly の記事 designing Qt style (APIs) も絶対に読むべきです。
1.15. 貢献のためのクレジット
新機能の貢献者は、以下の手段によりその貢献について人々に知らせることをお勧めします:
コードが組み込まれた最初のバージョンの更新履歴にメモを追加すること、以下のタイプで:
This feature was funded by: Olmiomland https://olmiomland.ol This feature was developed by: Chuck Norris https://chucknorris.kr
新機能についてのブログ記事を執筆し、それを QGIS planet https://plugins.qgis.org/planet/ に追加してください。
以下に自分の名前を追加すること:
1.8. コメント
クラスのメソッドのコメントには、命令形ではなく三人称の終止形を使用してください。