/*
* Stellarium
* Copyright (C) 2008 Fabien Chereau
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*!
@page codingStyle Coding Style Conventions in Stellarium
@tableofcontents
The increasing number of contributors require that we clearly define coding rules and guidelines. Although for historical reasons the current code of Stellarium does not always comply to these rules, they should now be respected for any addition or modification of the code.
Settings for QtCreator IDE you can get here (or TGZ archive for it).
@section stylistic_conventions_sec Stylistic Conventions
- Source code should use the ASCII character set. Characters such as 'è'
or 'ö' are not portable when hard-coded. Gettext translated strings should
be used for text using such characters.
- Variable names and comments should be in English.
- Class names are nouns, in mixed-case, with an initial upper-case letter and
the first letter of each subsequent word capitalized (e.g. @c CoreFactory).
- Method names are verbs or nouns in mixed-case, starting with a lower-case
letter (e.g. @c update() or @c addElement()).
- Names of methods that return a value should start with a suitable verb,
such as @c getSize().
- For methods, only names of Qt signals should be in passive voice
(@c valueChanged()). Names of Qt slots should use active verbs to avoid
confusion with signals:
@code
// BAD:
void buttonBoomClicked(); // Causes an explosion.
// BETTER:
void handleButtonBoom(); // Connected to buttonBoom::clicked().
// EVEN BETTER:
void explode(); // Connected to buttonBoom::clicked().
@endcode
The only exception is names of slots that use Qt's automatic connections to
controls in .ui files. (See @c QMetaObject::connectSlotsByName().)
- The names of local variables should be in mixed case, starting with
a lower-case letter (e.g. @c packetSize). This also applies to the formal
parameters of methods. Do not use names starting with underscore.
- The names of macro or static const should be all upper-case words, separated by underscore:
@code
#define MIN_WIDTH 3
static const QString VERSION = "0.10.1";
@endcode
- Indentation should be done with tabs, not spaces. This allows developers
to use their favorite indent size without changing the code.
- When wrapping lines from long function calls, where the wrapped line does not start at the same level of indentation as the start of the function call, tab up to the start of the function call, and then use spaces to the opening parenthesis.
@verbatim
[--tab-][--tab-][--tab-]someFunction(param, ...
[--tab-][--tab-][--tab-][ spaces ]moreparams, ...);
@endverbatim
This method will handle different tab widths gracefully.
- Use the following layout for braces:
@verbatim
void MyClass::myMethod(int x)
{
if (x>10)
{
cout << "You won." << endl;
}
}
@endverbatim
- Use blank lines as follows:
- 1 between methods, before (block or single line) comment
- 1 between logical sections of a method
- 2 between sections of a source file
- @c enums should follow the %Qt conventions. i.e. CamelCase with First letter capitalization for both enum type and enum values. Document with doxygen. The //!\< tag can be used to add descriptions on the same line as an enum value, e.g.
@verbatim
//! @enum EnumName Here is a description of the enum
enum EnumName
{
EnumValueOne, //!< Some doxygen description of EnumValueOne
EnumValueTwo, //!< Some doxygen description of EnumValueTwo
EnumValueThree //!< Some doxygen description of EnumValueThree
};
@endverbatim
- You can use the astyle program
to format your code according to these conventions. Use the following options:
@verbatim
astyle --style=ansi -tU source.cpp
@endverbatim
Note that this command will replace the file source.cpp with the re-formatted one, and create a backup of the original with the .orig suffix. Also note that the -U option (used to un-pad
parenthesis) may not be available in older versions of @c astyle.
@section file_names_sec File Names
The extensions are .hpp/.cpp for C++ headers/code, .h/.c for C headers/code.
C++ files should have the same name and case than the class they contain. For example class StelFontMgr should be declared in file StelFontMgr.hpp and implemented in StelFontMgr.cpp.
@section comments_sec Doxygen Comments
Stellarium source code should be documented with Doxygen. From Doxygen webpage:
"Doxygen is a documentation system for C++, C, Java, [...] It can generate an on-line documentation browser (in HTML) and/or an off-line reference manual (in LaTeX) from a set of documented source files. [...] The documentation is extracted directly from the sources, which makes it much easier to keep the documentation consistent with the source code. [...] You can also visualize the relations between the various elements by means of include dependency graphs, inheritance diagrams, and collaboration diagrams, which are all generated automatically.
All public and protected classes and methods from Stellarium should be fully documented in the headers (.hpp).
There are different ways to comment C++ code with Doxygen, in Stellarium use the following for headers files:
@verbatim
//! Find and return the list of at most maxNbItem objects auto-completing the passed object I18n name.
//! @param objPrefix the case insensitive first letters of the searched object.
//! @param maxNbItem the maximum number of returned object names.
//! @return a vector of matching object name by order of relevance, or an empty vector if nothing match.
QList listMatchingObjectsI18n(const QString& objPrefix, unsigned int maxNbItem=5) const;
@endverbatim
Brief descriptions are single line only, and stop at the first full stop (period). Any subsequent sentences which occur before \@param or a similar tag are considered to be part of a detailed description.
For methods definitions in .cpp files, a simpler comment for each method is sufficient:
@code
// Find and return the list of at most maxNbItem objects auto-completing the
// passed object I18n name.
QList listMatchingObjectsI18n(const QString& objPrefix, unsigned int maxNbItem=5) const
{
etc..
@endcode
@section cpp_code C/C++ Code
Use C++ replacement for C functions and %Qt replacements for C++ functions/STL wherever possible.
- Use QString
instead of @c std::string or char *
- Use QIODevice
instead of C file managment with @c fopen()
- Pass objects as references when needed instead of using pointers.
- Include standard headers the C++ way, it is more portable:
@code
#include // Bad
#include // Good
#include // Good
@endcode
- Use Qt containers instead of STL ones. They are easier to use, allow for the foreach keyword. Only if speed is really critical, use STL containers such as @c std::vector or @c std::map, they are extremely efficient. Documentation is there.
- Avoid public global functions and variables. Encapsulate them in classes or namespaces as static members/variables.
- Avoid using C macros, use static const variables instead.
It is safer because it is type safe.
@code
#define RADIUS 12 // Bad
static const int RADIUS = 12; // Good
@endcode
- Use stdc++ math functions instead of C ones. There are more portable and are also overrided for float, thus may be faster.
@code
double cosLat = cos(lat); // Bad
double cosLat = std::cos(lat); // Good
@endcode
@section translation_sec Translatable Strings and Console Output
Translatable strings are translated using the StelTranslator class, which is
a C++ wrapper around gettext.
A string literal can be marked for translation in with two different macros,
@c q_() or @c N_() , and you need to pick one for the appropriate purpose:
- The @c q_() macro takes a string in English and returns the translation as
a QString using the current global language. This also allows calling @c q_()
with a QString parameter to return a translation.
- When a string literal needs to be marked for translation without returning
a translation, use the @c N_() macro. It returns the original string.
Several guidelines:
- Translatable text in sources or data files should be written in English, encoded in ASCII or UTF-8 if needed.
- Translatable strings should be modified only if really necessary. Any modification to one of them means that all the translators for all the langages will have to re-translate the new string.
This also means that new strings should be chosen carefully, to avoid the need to modify them later.
- Do not concatenate strings, use @c QString::arg() instead. Concatenated strings are very hard (or even impossible) to translate.
@code
text << q_("Distance: ") << distance << q_("AU"); // Bad
text = q_("Distance: %1AU").arg(distance); // Good
@endcode
- Translatable text should obey English typographic conventions. For example, there should be no space before the colon:
@code
QString myTranslatedText(q_("Distance of the planet :")); // Bad
QString myTranslatedText(q_("Distance of the planet:")); // Good
@endcode
- In general no translated text should be output on the console because there are problems when string and wstring are output on the same console. This means that you should never use wcout, wcerr or wprintf(). Console output should be used for informations, errors and warnings which are not required by the user in nominal use.
- Errors and warnings should be output in the stderr file, not stdout. [OBSOLETE? We use qDebug() and qWarning() now.]
@code
std::cout << "Error while opening file " << qPrintable(myFileName) << "." << std::endl; // Bad
std::cerr << "Error while opening file " << qPrintable(myFileName) << "." << std::endl; // Good
@endcode
Further technical notes and tips:
- @b Important: When using %Qt format strings, if a letter follows a digit immediately, xgettext might erroneously mark the extracted string as a C format string. Depending on the actual translation, this might cause errors when uploading the message catalog to Rosetta, or when compiling it to binary format. To prevent this, add an xgettext:no-c-format comment to the line preceding the format string:
@code
// xgettext:no-c-format
text = q_("Distance: %1AU").arg(distance);
@endcode
- You can add clarifying remarks for the translators by adding a special comment before the line marking the string. They will be automatically extracted and visible in the .po files and in the web interface:
@code
// TRANSLATORS: Message displayed when an error occurs.
QString errorMessage(q_("Loading failed."));
@endcode
- User-visible strings in %Qt .ui files (used for GUI windows) are marked for translation, unless the "translate" flag is unchecked. Note that these strings are actually extracted from the files generated by the .ui file compiler (@c uic) during compilation, and not from the .ui files themselves, so translation comments in the .ui files will be ignored.
- When creating a .ui file with a new QWidget, %Qt Designer/Qt Creator sets the widget's @c windowTitle property to "Form", which then appears in translation templates and puzzles translators. It needs to be manually reset to an empty string.
- Stellarium also supports gettext contexts for the cases when identical English strings are used in different places with different meanings and therefore need to have different translations. Contexts are short strings used to indicate the difference both to the program and the people making the translations.
- In .ui files, for every property that holds a user-visible string, there's a "disambiguation" sub-property that can be used to indicate the context. It will be extracted together with the message (see above).
- The qc_() macro can be used in the cases when context needs to be handled in the code itself. It is analogous to the q_() macro, but with two parameters - the second parameter is the context string.
*/