Doxygen: Difference between revisions

From FreeCAD Documentation
(→‎Second style: documentation block elsewhere: Small changes to the first example)
Line 69: Line 69:
<div class="mw-collapsible mw-collapsed toccolours">
<div class="mw-collapsible mw-collapsed toccolours">
For example, in FreeCAD's source tree, the file {{incode|src/Base/core-base.dox}} gives a short explanation of the {{incode|Base}} namespace.
For example, in FreeCAD's source tree, the file {{incode|src/Base/core-base.dox}} gives a short explanation of the {{incode|Base}} namespace.

<div class="mw-collapsible-content">
<div class="mw-collapsible-content">
{{Code|code=
{{Code|code=
Line 97: Line 98:
</div>
</div>


Another example is the file {{incode|src/Gui/Command.cpp}}. Before the implementation details of the {{incode|Gui::Command}} methods, it has a block of text which explains some details of the command framework of FreeCAD. It even includes example code which is introduced with the special command {{incode|\code}}; when the file is processed by Doxygen this code example will be specially formatted to stand out.
Another example is the file {{incode|src/Gui/Command.cpp}}. Before the implementation details of the {{incode|Gui::Command}} methods, there is a documentation block that explains some details of the command framework of FreeCAD. It has various {{incode|\section}} commands to structure the documentation. It even includes example code enclosed in a pair of {{incode|\code}} and {{incode|\endcode}} keywords; when the file is processed by Doxygen this code example will be specially formatted to stand out. The {{incode|\ref}} keyword is used in several places to create links to named sections, subsections, pages or anchors elsewhere in the documentation. Similarly, the {{incode|\see}} or {{incode|\sa}} commands print "See also" and provide a link to other classes, functions, methods, variables, files or URLs.
<div class="mw-collapsible mw-collapsed toccolours">
<div class="mw-collapsible mw-collapsed toccolours">
Example {{incode|src/Gui/Command.cpp}}
See the following code:

<div class="mw-collapsible-content">
<div class="mw-collapsible-content">
{{Code|code=
{{Code|code=

Revision as of 01:02, 16 July 2019

Future home of tutorial how to write doxygen for FreeCAD Source_documentation#How_to_integrate_doxygen_in_to_the_FreeCAD_source_code

Doxygen is a popular tool for generating documentation from annotated C++ sources, but it also supports other popular programming languages such as C#, PHP, Java, and Python. Visit Doxygen website to learn more about the system.

This document gives a brief introduction to Doxygen, in particular how it is used with FreeCAD to document its sources. See the Doxygen Manual for the full information on its usage.

Introduction

The Getting started (Step 3) section of the Doxygen manual mentions the basic ways of documenting the sources.

For members, classes and namespaces there are basically two options:

  1. Place a special "documentation block" in front of the declaration or definition of the function, member, class or namespace. For file, class and namespace members it is also allowed to place the documentation directly after the member. See section Special comment blocks to learn more about these blocks.
  2. Place a special documentation block somewhere else (another file or another location) and put a "structural command" in the documentation block. A structural command links a documentation block to a certain entity that can be documented (e.g. a function, member, class, namespace or file). See section Documentation at other places to learn more about structural commands.

Note:

  • The advantage of the first option is that you do not have to repeat the name of the entity (function, member, class, or namespace), as Doxygen will analyze the code and extract the relevant information.
  • Files can only be documented using the second option, since there is no way to put a documentation block before a file. Of course, file members (functions, variables, typedefs, defines) do not need an explicit structural command; just putting a special documentation block before or after them will work fine.

First style: documentation block before the code

Usually you'd want to document the code in the header file, just before the class declaration or function prototype. This keeps the declaration and documentation close to each other, so it's easy to update the latter one if the first one changes.

The special documentation block starts like a C-style comment /* but has an additional asterisk, so /**. The block ends with a matching */.

/**
 * Returns the name of the workbench object.
 */
std::string name() const;

/**
 * Set the name to the workbench object.
 */
void setName(const std::string&);

Second style: documentation block elsewhere

Alternatively, the documentation can be placed in another file (or in the same file at the top or bottom, or wherever), away from the class declaration or function prototype. In this case, you will have duplicated information, once in the actual source file, and once in the documentation file.

First file, source.h:

std::string name() const;
void setName(const std::string&);

Second file, source.h.dox:

/** \file source.h
 *  \brief The documentation of source.h
 *   
 *   The details of this file go here.
 */

/** \fn std::string name() const;
 *  \brief Returns the name of the workbench object.
 */
/** \fn void setName(const std::string&);
 *  \brief Set the name to the workbench object.
 */

In this case the structural command \file is used to indicate which source file is being documented; a structural command \fn indicates that the following code is a function, and the command \brief is used to give a small description of this function.

This way of documenting a source file is useful if you just want to add documentation to your project without adding real code. When you place a comment block in a file with one of the following extensions .dox, .txt, or .doc then Doxygen will parse the comments and build the appropriate documentation, but it will hide this auxiliary file from the file list.

The FreeCAD project adds several files ending in .dox in many directories in order to provide a description, or examples, of the code there. It is important that such files are correctly categorized in a group or namespace, for which Doxygen provides some auxiliary commands like \defgroup, \ingroup, and \namespace.

For example, in FreeCAD's source tree, the file src/Base/core-base.dox gives a short explanation of the Base namespace.

/** \defgroup BASE Base
 *  \ingroup CORE
    \brief Basic structures used by other FreeCAD components
    
    The Base module includes most of the basic functions of FreeCAD, such as:
    - Console services: printing different kinds of messages to the FreeCAD report view or the terminal
    - Python interpreter: handles the execution of Python code in FreeCAD
    - Parameter handling: Management, saving and restoring of user preferences settings
    - Units: Management and conversion of different units

*/

/*! \namespace Base
    \ingroup BASE
    \brief Basic structures used by other FreeCAD components

    The Base module includes most of the basic functions of FreeCAD, such as:
    - Console services: printing different kinds of messages to the FreeCAD report view or the terminal
    - Python interpreter: handles the execution of Python code in FreeCAD
    - Parameter handling: Management, saving and restoring of user preferences settings
    - Units: Management and conversion of different units
*/

Another example is the file src/Gui/Command.cpp. Before the implementation details of the Gui::Command methods, there is a documentation block that explains some details of the command framework of FreeCAD. It has various \section commands to structure the documentation. It even includes example code enclosed in a pair of \code and \endcode keywords; when the file is processed by Doxygen this code example will be specially formatted to stand out. The \ref keyword is used in several places to create links to named sections, subsections, pages or anchors elsewhere in the documentation. Similarly, the \see or \sa commands print "See also" and provide a link to other classes, functions, methods, variables, files or URLs.

Example src/Gui/Command.cpp

/** \defgroup commands Command Framework
    \ingroup GUI
    \brief Structure for registering commands to the FreeCAD system
 * \section Overview
 * In GUI applications many commands can be invoked via a menu item, a toolbar button or an accelerator key. The answer of Qt to master this
 * challenge is the class \a QAction. A QAction object can be added to a popup menu or a toolbar and keep the state of the menu item and
 * the toolbar button synchronized.
 *
 * For example, if the user clicks the menu item of a toggle action then the toolbar button gets also pressed
 * and vice versa. For more details refer to your Qt documentation.
 *
 * \section Drawbacks
 * Since QAction inherits QObject and emits the \a triggered() signal or \a toggled() signal for toggle actions it is very convenient to connect
 * these signals e.g. with slots of your MainWindow class. But this means that for every action an appropriate slot of MainWindow is necessary
 * and leads to an inflated MainWindow class. Furthermore, it's simply impossible to provide plugins that may also need special slots -- without
 * changing the MainWindow class.
 *
 * \section wayout Way out
 * To solve these problems we have introduced the command framework to decouple QAction and MainWindow. The base classes of the framework are
 * \a Gui::CommandBase and \a Gui::Action that represent the link between Qt's QAction world and the FreeCAD's command world. 
 *
 * The Action class holds a pointer to QAction and CommandBase and acts as a mediator and -- to save memory -- that gets created 
 * (@ref Gui::CommandBase::createAction()) not before it is added (@ref Gui::Command::addTo()) to a menu or toolbar.
 *
 * Now, the implementation of the slots of MainWindow can be done in the method \a activated() of subclasses of Command instead.
 *
 * For example, the implementation of the "Open file" command can be done as follows.
 * \code
 * class OpenCommand : public Command
 * {
 * public:
 *   OpenCommand() : Command("Std_Open")
 *   {
 *     // set up menu text, status tip, ...
 *     sMenuText     = "&Open";
 *     sToolTipText  = "Open a file";
 *     sWhatsThis    = "Open a file";
 *     sStatusTip    = "Open a file";
 *     sPixmap       = "Open"; // name of a registered pixmap
 *     sAccel        = "Shift+P"; // or "P" or "P, L" or "Ctrl+X, Ctrl+C" for a sequence
 *   }
 * protected:
 *   void activated(int)
 *   {
 *     QString filter ... // make a filter of all supported file formats
 *     QStringList FileList = QFileDialog::getOpenFileNames( filter,QString::null, getMainWindow() );
 *     for ( QStringList::Iterator it = FileList.begin(); it != FileList.end(); ++it ) {
 *       getGuiApplication()->open((*it).latin1());
 *     }
 *   }
 * };
 * \endcode
 * An instance of \a OpenCommand must be created and added to the \ref Gui::CommandManager to make the class known to FreeCAD.
 * To see how menus and toolbars can be built go to the @ref workbench.
 *
 * @see Gui::Command, Gui::CommandManager
 */

Doxygen markup

All Doxygen documentation commands start with a backslash \ or an at-sign @, at your preference. In FreeCAD, C style comments are normally used, that is, a pair of /* and */ to delimit the comment. In this case, the @-sign is used in Doxygen commands to improve readability.

Some commands can have one or more arguments.

  • If <sharp> braces are used the argument is a single word.
  • If (round) braces are used the argument extends until the end of the line on which the command was found.
  • If {curly} braces are used the argument extends until the next paragraph. Paragraphs are delimited by a blank line or by a section indicator.
  • If [square] brackets are used the argument is optional.

Some of the most common keywords used in the FreeCAD documentation are

  • \addtogroup <name> [(title)], see \addtogroup
  • \brief { brief description }, see \brief
  • \param <parameter-name> { parameter description }, see \param
  • \return { description of the return value }, see \return
  • \note { text }, see \note

Example with the FreeCAD source code

The code in the file src/Gui/Workbench.h defines the Gui::Workbench class.

Example code from src/Gui/Workbench.h

/**
 * This is the base class for the workbench facility. Each FreeCAD module can provide its own 
 * workbench implementation. The workbench defines which GUI elements (such as toolbars, menus, 
 * dockable windows, ...) are added to the mainwindow and which gets removed or hidden. 
 * When a workbench object gets activated the first time the module - it stands for - gets 
 * loaded into RAM.
 * @author Werner Mayer
 */
class GuiExport Workbench : public Base::BaseClass
{
    TYPESYSTEM_HEADER();

public:
    /** Constructs a workbench object. */
    Workbench();
    virtual ~Workbench();
    /**
     * Returns the name of the workbench object.
     */
    std::string name() const;
    /**
     * Set the name to the workbench object.
     */
    void setName(const std::string&);
    /**
     * The default implementation returns an instance of @ref WorkbenchPy.
     */
    PyObject* getPyObject();
    /** Sets up the contextmenu for this workbench. 
     * The default implementation does nothing.
     */
    virtual void setupContextMenu(const char* recipient,MenuItem*) const;
    /** Sets up the contextmenu for the main window for this workbench. 
     * The default implementation does nothing.
     */
    virtual void createMainWindowPopupMenu(MenuItem*) const;
    /** 
     * Activates the workbench and adds/removes GUI elements.
     */
    bool activate();
    /**
     * Translates the window titles of all menus, toolbars and dock windows.
     */
    void retranslate() const;
    /** Run some actions when the workbench gets activated. */
    virtual void activated();
    /** Run some actions when the workbench gets deactivated. */
    virtual void deactivated();

    /// helper to add TaskWatcher to the TaskView
    void addTaskWatcher(const std::vector<Gui::TaskView::TaskWatcher*> &Watcher);
    /// remove the added TaskWatcher
    void removeTaskWatcher(void);

protected:
    /** Returns a MenuItem tree structure of menus for this workbench. */
    virtual MenuItem* setupMenuBar() const=0;
    /** Returns a ToolBarItem tree structure of toolbars for this workbench. */
    virtual ToolBarItem* setupToolBars() const=0;
    /** Returns a ToolBarItem tree structure of command bars for this workbench. */
    virtual ToolBarItem* setupCommandBars() const=0;
    /** Returns a DockWindowItems structure of dock windows this workbench. */
    virtual DockWindowItems* setupDockWindows() const=0;

private:
    /**
     * The method imports the user defined toolbars or toolbox bars and creates
     * a ToolBarItem tree structure.
     */
    void setupCustomToolbars(ToolBarItem* root, const char* toolbar) const;
    void setupCustomToolbars(ToolBarItem* root, const Base::Reference<ParameterGrp>& hGrp) const;
    void setupCustomShortcuts() const;

private:
    std::string _name;
};

Doxygen with Python code

Doxygen works best for statically typed languages like C++. However, it can also create documentation for Python files.

There are two ways to comment Python:

  1. The Pythonic way, using docstrings immediately after the class or function definition.
  2. The Doxygen way, putting comments before the class or function definition.

The first option is preferred to comply with PEP8 and most style guidelines for Python. However, in this way Doxygen doesn't recognize special commands.

The second option isn't the traditional Python style, but it allows you to use Doxygen's special commands.

Parsing of documentation blocks

The text inside a special documentation block is parsed before it is written to the HTML and LaTeX output files. During parsing the following steps take place:

  • Markdown formatting is replaced by corresponding HTML or special commands.
  • The special commands inside the documentation are executed. See section Special Commands for an overview of all commands.
  • If a line starts with some whitespace followed by one or more asterisks (*) and then optionally more whitespace, then all whitespace and asterisks are removed.
  • All resulting blank lines are treated as a paragraph separators. This saves you from placing new-paragraph commands yourself in order to make the generated documentation readable.
  • Links are created for words corresponding to documented classes. If the word is preceded by a %-sign, then sign will be removed and the word won't be linked.
  • Links to members are created when certain patterns are found in the text. See section Automatic link generation for more information.
  • HTML tags that are in the documentation are interpreted and converted to \LaTeX equivalents for the \LaTeX output. See section HTML Commands for an overview of all supported HTML tags.

FreeCAD doxygen

FC doxygen formatting

The FC project has chosen the following method for it's doxygen comment blocks: As it's special char of choice

  • \note ex. \note added in FreeCAD 0.17

Note: Please also read: https://github.com/FreeCAD/FreeCAD/blob/master/src/Doc/doctips.dox