1. QGIS コーディング基準

これらの基準は、すべての QGIS 開発者が守るべきです。

1.1. クラス

1.1.1. 名前

QGISのクラスは、Qgsで始まり、キャメルケースを使用して形成します。

例:

  • QgsPoint

  • QgsMapCanvas

  • QgsRasterLayer

1.1.2. メンバー

クラスメンバー名は小文字のmで始まり、大文字と小文字を使用して形成されています。

  • mMapCanvas

  • mCurrentExtent

すべてのクラスメンバはプライベートにしましょう。公開クラスメンバは極力避けるようにしてください。保護メンバーは Python バインディングから使用できないため、メンバーが Python のサブクラスからアクセスする必要がある場合は、保護メンバを使用しないでください。

静的メンバの命名は、変数の場合は小文字の "s" で始め、定数の場合はすべての文字を大文字としてください。

  • sRefCounter

  • DEFAULT_QUEUE_SIZE

1.1.3. アクセサ関数

クラスのメンバ値はアクセサ関数を通じて取得しましょう。関数は、 get 接頭辞なしの名前を付ける必要があります。上記2つの私的メンバのためのアクセサ関数は次のようになります。

  • mapCanvas()

  • currentExtent()

アクセサが正しく const でマークされていることを確認してください。適切な場合には、これはキャッシュされた値型のメンバー変数が mutable でマークされていることを要求することができます。

1.1.4. 関数

関数名は小文字で始まり、大文字と小文字を使用して形成されています。関数名は、その関数の目的について何かを伝える必要があります。

  • updateMapExtent()

  • setUserOptions()

既存の QGIS の API と Qt の API との一貫性を保つために、略語は避けましょう。例えば setDestSize でなく setDestinationSizesetMaxVal でなく 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; (QgsVectorLayerQObject を継承)

  • QgsAbstractGeometry *geometry() const; (QgsAbstractGeometry は抽象クラスであり、おそらくキャストする必要がある)

1.2. APIドキュメント

公開 API で利用可能なすべてのクラス、メソッド、列挙型などのコードについては、 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. メソッド

メソッドの説明は三人称を使用した説明的な形で書いてください。メソッドにはいつ導入されたかを定義する \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.cppqgsfeatureattribute.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のためのテンプレートがあります。それを使用するには、 doc/qt_creator_license_template からそれをローカルの場所にコピーし、メールアドレスと名前を(必要ならば)修正し、それを使用するようにQtCreatorを設定します ツール ► オプション ► C++ ► ファイル命名

1.5. 変数名

ローカル変数名は小文字で始まり、大文字と小文字を使用して形成されています。my あるいは the といった文字列を前に付けないでください。

例:

  • mapCanvas

  • currentExtent

1.6. 列挙型

列挙型は、最初が大文字のキャメルケースで命名する必要があります、例えば:

enum UnitType
{
  Meters,
  Feet,
  Degrees,
  UnknownUnit
};

他のタイプと競合するジェネリック型の名前を使用しないでください。例えば Unknown よりむしろ UnkownUnit を使用してください

1.7. グローバル定数&マクロ

グローバル定数とマクロは大文字のアンダースコア区切りなどで書かれる必要があります。

const long GEOCRS_ID = 3344;

1.8. コメント

クラスのメソッドのコメントには、命令形ではなく三人称の終止形を使用してください。

/**
 * Creates a new QgsFeatureFilterModel, optionally specifying a \a parent.
 */
explicit QgsFeatureFilterModel( QObject *parent = nullptr );
~QgsFeatureFilterModel() override;

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 を使用してそれらを字下げし直す scripts/prepare-commit.sh があります。これは、コミットする前に実行する必要があります。また、個々のファイルを字下げするために scripts/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のメソッドの引数のための別の型を定義するために使用することができます。型がコンマ , を含む場合は、型はシングルクォート ' で囲まなければなりません。

A demo file can be found in tests/code_layout/sipifyheader.h.

1.12.2. SIP ファイルを生成する

SIP ファイルはそのための専用スクリプトを使って生成することができます。例えば次のようにします。

scripts/sipify.pl src/core/qgsvectorlayer.h > python/core/qgsvectorlayer.sip

To automatically generate the SIP file of a newly added C++ file scripts/sip_include.sh needs to be executed.

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.

To force recreation of SIP files, scripts/sipify_all.sh shall be executed.

1.12.3. sipify スクリプトを改善する

If some improvements are required for sipify script, please add the missing bits to the demo file tests/code_layout/sipifyheader.h and create the expected header tests/code_layout/sipifyheader.expected.sip. This will also be automatically tested on Travis as a unit test of the script itself.

1.13. コーディングスタイル

ここでは、うまくいけばエラーや開発時間、メンテナンスを減らすことが期待できる、プログラミングのヒントやコツを説明します。

1.13.1. 可能なかぎりコードを一般化しましょう

コードをカット&ペーストしている、あるいは複数回同じことを書いている場合は、単一の関数にコードを統合することを検討してください。

これにより:

  • 変更は複数の場所ではなく一箇所で行うことを可能にします

  • コードの膨張を防ぐのを助けます

  • 複数のコピーが時間につれて違いを進化させること、したがって他人が理解して維持管理するのを難しくすること、がより起こりにくくします

1.13.2. 述語中で定数は最初にしましょう

述語中では最初に定数を置くことを好みます。

value == 0 の代わりに 0 == value

これにより、プログラマが == を使用するつもりで誤って = を使用することを防げます、それは非常に微妙な論理的バグになる。比較のための == の代わりに誤って = を使用している場合、 定数には本質的に値を割り当てできませんから、コンパイラでエラーが発生します。

1.13.3. 空白は友達になりえます

演算子、ステートメント、および関数の間にスペースを追加すると、人間がコードを簡単に解析できるようになります。

より読みやすいのは、こちら:

if (!a&&b)

またはこちら:

if ( ! a && b )

注釈

scripts/prepare-commit.sh はこれを行います。

1.13.4. コマンドは別々の行に入れましょう

コードを読み取るとき、行の先頭にない場合は、コマンドを見逃しやすくなります。すぐにコードを読むとき、それらは最初の数文字で探しているもののように見えない場合、行を読み飛ばすのが一般的です。 if のような条件の後にコマンドを期待することも一般的です。

考えてみましょう:

if (foo) bar();

baz(); bar();

制御のどのような流れの一部を見逃すのは非常に簡単です。代わりに使用します

if (foo)
  bar();

baz();
bar();

1.13.5. アクセス修飾子を字下げしましょう

アクセス修飾子は、公開API、保護されたAPIとプライベートAPIのセクションにクラスを構造化します。アクセス修飾子自体はこのような構造にコードをグループ化します。アクセス修飾子と宣言を字下げしてください。

class QgsStructure
{
  public:
    /**
     * Constructor
     */
     explicit QgsStructure();
}

1.13.6. お奨めの読み物

Qt Quarterly の記事 designing Qt style (APIs) も絶対に読むべきです。

1.14. 貢献のためのクレジット

新機能の貢献者は、以下の手段によりその貢献について人々に知らせることをお勧めします: